##// END OF EJS Templates
revert: support reverting to hidden cset if directaccess config is set...
Pulkit Goyal -
r35537:31fe397f default
parent child Browse files
Show More
@@ -1,5614 +1,5617 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import sys
14 import sys
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 short,
21 short,
22 )
22 )
23 from . import (
23 from . import (
24 archival,
24 archival,
25 bookmarks,
25 bookmarks,
26 bundle2,
26 bundle2,
27 changegroup,
27 changegroup,
28 cmdutil,
28 cmdutil,
29 copies,
29 copies,
30 debugcommands as debugcommandsmod,
30 debugcommands as debugcommandsmod,
31 destutil,
31 destutil,
32 dirstateguard,
32 dirstateguard,
33 discovery,
33 discovery,
34 encoding,
34 encoding,
35 error,
35 error,
36 exchange,
36 exchange,
37 extensions,
37 extensions,
38 formatter,
38 formatter,
39 graphmod,
39 graphmod,
40 hbisect,
40 hbisect,
41 help,
41 help,
42 hg,
42 hg,
43 lock as lockmod,
43 lock as lockmod,
44 merge as mergemod,
44 merge as mergemod,
45 obsolete,
45 obsolete,
46 patch,
46 patch,
47 phases,
47 phases,
48 pycompat,
48 pycompat,
49 rcutil,
49 rcutil,
50 registrar,
50 registrar,
51 revsetlang,
51 revsetlang,
52 rewriteutil,
52 rewriteutil,
53 scmutil,
53 scmutil,
54 server,
54 server,
55 sshserver,
55 sshserver,
56 streamclone,
56 streamclone,
57 tags as tagsmod,
57 tags as tagsmod,
58 templatekw,
58 templatekw,
59 ui as uimod,
59 ui as uimod,
60 util,
60 util,
61 )
61 )
62
62
63 release = lockmod.release
63 release = lockmod.release
64
64
65 table = {}
65 table = {}
66 table.update(debugcommandsmod.command._table)
66 table.update(debugcommandsmod.command._table)
67
67
68 command = registrar.command(table)
68 command = registrar.command(table)
69 readonly = registrar.command.readonly
69 readonly = registrar.command.readonly
70
70
71 # common command options
71 # common command options
72
72
73 globalopts = [
73 globalopts = [
74 ('R', 'repository', '',
74 ('R', 'repository', '',
75 _('repository root directory or name of overlay bundle file'),
75 _('repository root directory or name of overlay bundle file'),
76 _('REPO')),
76 _('REPO')),
77 ('', 'cwd', '',
77 ('', 'cwd', '',
78 _('change working directory'), _('DIR')),
78 _('change working directory'), _('DIR')),
79 ('y', 'noninteractive', None,
79 ('y', 'noninteractive', None,
80 _('do not prompt, automatically pick the first choice for all prompts')),
80 _('do not prompt, automatically pick the first choice for all prompts')),
81 ('q', 'quiet', None, _('suppress output')),
81 ('q', 'quiet', None, _('suppress output')),
82 ('v', 'verbose', None, _('enable additional output')),
82 ('v', 'verbose', None, _('enable additional output')),
83 ('', 'color', '',
83 ('', 'color', '',
84 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
84 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
85 # and should not be translated
85 # and should not be translated
86 _("when to colorize (boolean, always, auto, never, or debug)"),
86 _("when to colorize (boolean, always, auto, never, or debug)"),
87 _('TYPE')),
87 _('TYPE')),
88 ('', 'config', [],
88 ('', 'config', [],
89 _('set/override config option (use \'section.name=value\')'),
89 _('set/override config option (use \'section.name=value\')'),
90 _('CONFIG')),
90 _('CONFIG')),
91 ('', 'debug', None, _('enable debugging output')),
91 ('', 'debug', None, _('enable debugging output')),
92 ('', 'debugger', None, _('start debugger')),
92 ('', 'debugger', None, _('start debugger')),
93 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
93 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
94 _('ENCODE')),
94 _('ENCODE')),
95 ('', 'encodingmode', encoding.encodingmode,
95 ('', 'encodingmode', encoding.encodingmode,
96 _('set the charset encoding mode'), _('MODE')),
96 _('set the charset encoding mode'), _('MODE')),
97 ('', 'traceback', None, _('always print a traceback on exception')),
97 ('', 'traceback', None, _('always print a traceback on exception')),
98 ('', 'time', None, _('time how long the command takes')),
98 ('', 'time', None, _('time how long the command takes')),
99 ('', 'profile', None, _('print command execution profile')),
99 ('', 'profile', None, _('print command execution profile')),
100 ('', 'version', None, _('output version information and exit')),
100 ('', 'version', None, _('output version information and exit')),
101 ('h', 'help', None, _('display help and exit')),
101 ('h', 'help', None, _('display help and exit')),
102 ('', 'hidden', False, _('consider hidden changesets')),
102 ('', 'hidden', False, _('consider hidden changesets')),
103 ('', 'pager', 'auto',
103 ('', 'pager', 'auto',
104 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
104 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
105 ]
105 ]
106
106
107 dryrunopts = cmdutil.dryrunopts
107 dryrunopts = cmdutil.dryrunopts
108 remoteopts = cmdutil.remoteopts
108 remoteopts = cmdutil.remoteopts
109 walkopts = cmdutil.walkopts
109 walkopts = cmdutil.walkopts
110 commitopts = cmdutil.commitopts
110 commitopts = cmdutil.commitopts
111 commitopts2 = cmdutil.commitopts2
111 commitopts2 = cmdutil.commitopts2
112 formatteropts = cmdutil.formatteropts
112 formatteropts = cmdutil.formatteropts
113 templateopts = cmdutil.templateopts
113 templateopts = cmdutil.templateopts
114 logopts = cmdutil.logopts
114 logopts = cmdutil.logopts
115 diffopts = cmdutil.diffopts
115 diffopts = cmdutil.diffopts
116 diffwsopts = cmdutil.diffwsopts
116 diffwsopts = cmdutil.diffwsopts
117 diffopts2 = cmdutil.diffopts2
117 diffopts2 = cmdutil.diffopts2
118 mergetoolopts = cmdutil.mergetoolopts
118 mergetoolopts = cmdutil.mergetoolopts
119 similarityopts = cmdutil.similarityopts
119 similarityopts = cmdutil.similarityopts
120 subrepoopts = cmdutil.subrepoopts
120 subrepoopts = cmdutil.subrepoopts
121 debugrevlogopts = cmdutil.debugrevlogopts
121 debugrevlogopts = cmdutil.debugrevlogopts
122
122
123 # Commands start here, listed alphabetically
123 # Commands start here, listed alphabetically
124
124
125 @command('^add',
125 @command('^add',
126 walkopts + subrepoopts + dryrunopts,
126 walkopts + subrepoopts + dryrunopts,
127 _('[OPTION]... [FILE]...'),
127 _('[OPTION]... [FILE]...'),
128 inferrepo=True)
128 inferrepo=True)
129 def add(ui, repo, *pats, **opts):
129 def add(ui, repo, *pats, **opts):
130 """add the specified files on the next commit
130 """add the specified files on the next commit
131
131
132 Schedule files to be version controlled and added to the
132 Schedule files to be version controlled and added to the
133 repository.
133 repository.
134
134
135 The files will be added to the repository at the next commit. To
135 The files will be added to the repository at the next commit. To
136 undo an add before that, see :hg:`forget`.
136 undo an add before that, see :hg:`forget`.
137
137
138 If no names are given, add all files to the repository (except
138 If no names are given, add all files to the repository (except
139 files matching ``.hgignore``).
139 files matching ``.hgignore``).
140
140
141 .. container:: verbose
141 .. container:: verbose
142
142
143 Examples:
143 Examples:
144
144
145 - New (unknown) files are added
145 - New (unknown) files are added
146 automatically by :hg:`add`::
146 automatically by :hg:`add`::
147
147
148 $ ls
148 $ ls
149 foo.c
149 foo.c
150 $ hg status
150 $ hg status
151 ? foo.c
151 ? foo.c
152 $ hg add
152 $ hg add
153 adding foo.c
153 adding foo.c
154 $ hg status
154 $ hg status
155 A foo.c
155 A foo.c
156
156
157 - Specific files to be added can be specified::
157 - Specific files to be added can be specified::
158
158
159 $ ls
159 $ ls
160 bar.c foo.c
160 bar.c foo.c
161 $ hg status
161 $ hg status
162 ? bar.c
162 ? bar.c
163 ? foo.c
163 ? foo.c
164 $ hg add bar.c
164 $ hg add bar.c
165 $ hg status
165 $ hg status
166 A bar.c
166 A bar.c
167 ? foo.c
167 ? foo.c
168
168
169 Returns 0 if all files are successfully added.
169 Returns 0 if all files are successfully added.
170 """
170 """
171
171
172 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
172 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
173 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
173 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
174 return rejected and 1 or 0
174 return rejected and 1 or 0
175
175
176 @command('addremove',
176 @command('addremove',
177 similarityopts + subrepoopts + walkopts + dryrunopts,
177 similarityopts + subrepoopts + walkopts + dryrunopts,
178 _('[OPTION]... [FILE]...'),
178 _('[OPTION]... [FILE]...'),
179 inferrepo=True)
179 inferrepo=True)
180 def addremove(ui, repo, *pats, **opts):
180 def addremove(ui, repo, *pats, **opts):
181 """add all new files, delete all missing files
181 """add all new files, delete all missing files
182
182
183 Add all new files and remove all missing files from the
183 Add all new files and remove all missing files from the
184 repository.
184 repository.
185
185
186 Unless names are given, new files are ignored if they match any of
186 Unless names are given, new files are ignored if they match any of
187 the patterns in ``.hgignore``. As with add, these changes take
187 the patterns in ``.hgignore``. As with add, these changes take
188 effect at the next commit.
188 effect at the next commit.
189
189
190 Use the -s/--similarity option to detect renamed files. This
190 Use the -s/--similarity option to detect renamed files. This
191 option takes a percentage between 0 (disabled) and 100 (files must
191 option takes a percentage between 0 (disabled) and 100 (files must
192 be identical) as its parameter. With a parameter greater than 0,
192 be identical) as its parameter. With a parameter greater than 0,
193 this compares every removed file with every added file and records
193 this compares every removed file with every added file and records
194 those similar enough as renames. Detecting renamed files this way
194 those similar enough as renames. Detecting renamed files this way
195 can be expensive. After using this option, :hg:`status -C` can be
195 can be expensive. After using this option, :hg:`status -C` can be
196 used to check which files were identified as moved or renamed. If
196 used to check which files were identified as moved or renamed. If
197 not specified, -s/--similarity defaults to 100 and only renames of
197 not specified, -s/--similarity defaults to 100 and only renames of
198 identical files are detected.
198 identical files are detected.
199
199
200 .. container:: verbose
200 .. container:: verbose
201
201
202 Examples:
202 Examples:
203
203
204 - A number of files (bar.c and foo.c) are new,
204 - A number of files (bar.c and foo.c) are new,
205 while foobar.c has been removed (without using :hg:`remove`)
205 while foobar.c has been removed (without using :hg:`remove`)
206 from the repository::
206 from the repository::
207
207
208 $ ls
208 $ ls
209 bar.c foo.c
209 bar.c foo.c
210 $ hg status
210 $ hg status
211 ! foobar.c
211 ! foobar.c
212 ? bar.c
212 ? bar.c
213 ? foo.c
213 ? foo.c
214 $ hg addremove
214 $ hg addremove
215 adding bar.c
215 adding bar.c
216 adding foo.c
216 adding foo.c
217 removing foobar.c
217 removing foobar.c
218 $ hg status
218 $ hg status
219 A bar.c
219 A bar.c
220 A foo.c
220 A foo.c
221 R foobar.c
221 R foobar.c
222
222
223 - A file foobar.c was moved to foo.c without using :hg:`rename`.
223 - A file foobar.c was moved to foo.c without using :hg:`rename`.
224 Afterwards, it was edited slightly::
224 Afterwards, it was edited slightly::
225
225
226 $ ls
226 $ ls
227 foo.c
227 foo.c
228 $ hg status
228 $ hg status
229 ! foobar.c
229 ! foobar.c
230 ? foo.c
230 ? foo.c
231 $ hg addremove --similarity 90
231 $ hg addremove --similarity 90
232 removing foobar.c
232 removing foobar.c
233 adding foo.c
233 adding foo.c
234 recording removal of foobar.c as rename to foo.c (94% similar)
234 recording removal of foobar.c as rename to foo.c (94% similar)
235 $ hg status -C
235 $ hg status -C
236 A foo.c
236 A foo.c
237 foobar.c
237 foobar.c
238 R foobar.c
238 R foobar.c
239
239
240 Returns 0 if all files are successfully added.
240 Returns 0 if all files are successfully added.
241 """
241 """
242 opts = pycompat.byteskwargs(opts)
242 opts = pycompat.byteskwargs(opts)
243 try:
243 try:
244 sim = float(opts.get('similarity') or 100)
244 sim = float(opts.get('similarity') or 100)
245 except ValueError:
245 except ValueError:
246 raise error.Abort(_('similarity must be a number'))
246 raise error.Abort(_('similarity must be a number'))
247 if sim < 0 or sim > 100:
247 if sim < 0 or sim > 100:
248 raise error.Abort(_('similarity must be between 0 and 100'))
248 raise error.Abort(_('similarity must be between 0 and 100'))
249 matcher = scmutil.match(repo[None], pats, opts)
249 matcher = scmutil.match(repo[None], pats, opts)
250 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
250 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
251
251
252 @command('^annotate|blame',
252 @command('^annotate|blame',
253 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
253 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
254 ('', 'follow', None,
254 ('', 'follow', None,
255 _('follow copies/renames and list the filename (DEPRECATED)')),
255 _('follow copies/renames and list the filename (DEPRECATED)')),
256 ('', 'no-follow', None, _("don't follow copies and renames")),
256 ('', 'no-follow', None, _("don't follow copies and renames")),
257 ('a', 'text', None, _('treat all files as text')),
257 ('a', 'text', None, _('treat all files as text')),
258 ('u', 'user', None, _('list the author (long with -v)')),
258 ('u', 'user', None, _('list the author (long with -v)')),
259 ('f', 'file', None, _('list the filename')),
259 ('f', 'file', None, _('list the filename')),
260 ('d', 'date', None, _('list the date (short with -q)')),
260 ('d', 'date', None, _('list the date (short with -q)')),
261 ('n', 'number', None, _('list the revision number (default)')),
261 ('n', 'number', None, _('list the revision number (default)')),
262 ('c', 'changeset', None, _('list the changeset')),
262 ('c', 'changeset', None, _('list the changeset')),
263 ('l', 'line-number', None, _('show line number at the first appearance')),
263 ('l', 'line-number', None, _('show line number at the first appearance')),
264 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
264 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
265 ] + diffwsopts + walkopts + formatteropts,
265 ] + diffwsopts + walkopts + formatteropts,
266 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
266 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
267 inferrepo=True)
267 inferrepo=True)
268 def annotate(ui, repo, *pats, **opts):
268 def annotate(ui, repo, *pats, **opts):
269 """show changeset information by line for each file
269 """show changeset information by line for each file
270
270
271 List changes in files, showing the revision id responsible for
271 List changes in files, showing the revision id responsible for
272 each line.
272 each line.
273
273
274 This command is useful for discovering when a change was made and
274 This command is useful for discovering when a change was made and
275 by whom.
275 by whom.
276
276
277 If you include --file, --user, or --date, the revision number is
277 If you include --file, --user, or --date, the revision number is
278 suppressed unless you also include --number.
278 suppressed unless you also include --number.
279
279
280 Without the -a/--text option, annotate will avoid processing files
280 Without the -a/--text option, annotate will avoid processing files
281 it detects as binary. With -a, annotate will annotate the file
281 it detects as binary. With -a, annotate will annotate the file
282 anyway, although the results will probably be neither useful
282 anyway, although the results will probably be neither useful
283 nor desirable.
283 nor desirable.
284
284
285 Returns 0 on success.
285 Returns 0 on success.
286 """
286 """
287 opts = pycompat.byteskwargs(opts)
287 opts = pycompat.byteskwargs(opts)
288 if not pats:
288 if not pats:
289 raise error.Abort(_('at least one filename or pattern is required'))
289 raise error.Abort(_('at least one filename or pattern is required'))
290
290
291 if opts.get('follow'):
291 if opts.get('follow'):
292 # --follow is deprecated and now just an alias for -f/--file
292 # --follow is deprecated and now just an alias for -f/--file
293 # to mimic the behavior of Mercurial before version 1.5
293 # to mimic the behavior of Mercurial before version 1.5
294 opts['file'] = True
294 opts['file'] = True
295
295
296 ctx = scmutil.revsingle(repo, opts.get('rev'))
296 ctx = scmutil.revsingle(repo, opts.get('rev'))
297
297
298 rootfm = ui.formatter('annotate', opts)
298 rootfm = ui.formatter('annotate', opts)
299 if ui.quiet:
299 if ui.quiet:
300 datefunc = util.shortdate
300 datefunc = util.shortdate
301 else:
301 else:
302 datefunc = util.datestr
302 datefunc = util.datestr
303 if ctx.rev() is None:
303 if ctx.rev() is None:
304 def hexfn(node):
304 def hexfn(node):
305 if node is None:
305 if node is None:
306 return None
306 return None
307 else:
307 else:
308 return rootfm.hexfunc(node)
308 return rootfm.hexfunc(node)
309 if opts.get('changeset'):
309 if opts.get('changeset'):
310 # omit "+" suffix which is appended to node hex
310 # omit "+" suffix which is appended to node hex
311 def formatrev(rev):
311 def formatrev(rev):
312 if rev is None:
312 if rev is None:
313 return '%d' % ctx.p1().rev()
313 return '%d' % ctx.p1().rev()
314 else:
314 else:
315 return '%d' % rev
315 return '%d' % rev
316 else:
316 else:
317 def formatrev(rev):
317 def formatrev(rev):
318 if rev is None:
318 if rev is None:
319 return '%d+' % ctx.p1().rev()
319 return '%d+' % ctx.p1().rev()
320 else:
320 else:
321 return '%d ' % rev
321 return '%d ' % rev
322 def formathex(hex):
322 def formathex(hex):
323 if hex is None:
323 if hex is None:
324 return '%s+' % rootfm.hexfunc(ctx.p1().node())
324 return '%s+' % rootfm.hexfunc(ctx.p1().node())
325 else:
325 else:
326 return '%s ' % hex
326 return '%s ' % hex
327 else:
327 else:
328 hexfn = rootfm.hexfunc
328 hexfn = rootfm.hexfunc
329 formatrev = formathex = pycompat.bytestr
329 formatrev = formathex = pycompat.bytestr
330
330
331 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
331 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
332 ('number', ' ', lambda x: x.fctx.rev(), formatrev),
332 ('number', ' ', lambda x: x.fctx.rev(), formatrev),
333 ('changeset', ' ', lambda x: hexfn(x.fctx.node()), formathex),
333 ('changeset', ' ', lambda x: hexfn(x.fctx.node()), formathex),
334 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
334 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
335 ('file', ' ', lambda x: x.fctx.path(), str),
335 ('file', ' ', lambda x: x.fctx.path(), str),
336 ('line_number', ':', lambda x: x.lineno, str),
336 ('line_number', ':', lambda x: x.lineno, str),
337 ]
337 ]
338 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
338 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
339
339
340 if (not opts.get('user') and not opts.get('changeset')
340 if (not opts.get('user') and not opts.get('changeset')
341 and not opts.get('date') and not opts.get('file')):
341 and not opts.get('date') and not opts.get('file')):
342 opts['number'] = True
342 opts['number'] = True
343
343
344 linenumber = opts.get('line_number') is not None
344 linenumber = opts.get('line_number') is not None
345 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
345 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
346 raise error.Abort(_('at least one of -n/-c is required for -l'))
346 raise error.Abort(_('at least one of -n/-c is required for -l'))
347
347
348 ui.pager('annotate')
348 ui.pager('annotate')
349
349
350 if rootfm.isplain():
350 if rootfm.isplain():
351 def makefunc(get, fmt):
351 def makefunc(get, fmt):
352 return lambda x: fmt(get(x))
352 return lambda x: fmt(get(x))
353 else:
353 else:
354 def makefunc(get, fmt):
354 def makefunc(get, fmt):
355 return get
355 return get
356 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
356 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
357 if opts.get(op)]
357 if opts.get(op)]
358 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
358 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
359 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
359 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
360 if opts.get(op))
360 if opts.get(op))
361
361
362 def bad(x, y):
362 def bad(x, y):
363 raise error.Abort("%s: %s" % (x, y))
363 raise error.Abort("%s: %s" % (x, y))
364
364
365 m = scmutil.match(ctx, pats, opts, badfn=bad)
365 m = scmutil.match(ctx, pats, opts, badfn=bad)
366
366
367 follow = not opts.get('no_follow')
367 follow = not opts.get('no_follow')
368 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
368 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
369 whitespace=True)
369 whitespace=True)
370 skiprevs = opts.get('skip')
370 skiprevs = opts.get('skip')
371 if skiprevs:
371 if skiprevs:
372 skiprevs = scmutil.revrange(repo, skiprevs)
372 skiprevs = scmutil.revrange(repo, skiprevs)
373
373
374 for abs in ctx.walk(m):
374 for abs in ctx.walk(m):
375 fctx = ctx[abs]
375 fctx = ctx[abs]
376 rootfm.startitem()
376 rootfm.startitem()
377 rootfm.data(abspath=abs, path=m.rel(abs))
377 rootfm.data(abspath=abs, path=m.rel(abs))
378 if not opts.get('text') and fctx.isbinary():
378 if not opts.get('text') and fctx.isbinary():
379 rootfm.plain(_("%s: binary file\n")
379 rootfm.plain(_("%s: binary file\n")
380 % ((pats and m.rel(abs)) or abs))
380 % ((pats and m.rel(abs)) or abs))
381 continue
381 continue
382
382
383 fm = rootfm.nested('lines')
383 fm = rootfm.nested('lines')
384 lines = fctx.annotate(follow=follow, linenumber=linenumber,
384 lines = fctx.annotate(follow=follow, linenumber=linenumber,
385 skiprevs=skiprevs, diffopts=diffopts)
385 skiprevs=skiprevs, diffopts=diffopts)
386 if not lines:
386 if not lines:
387 fm.end()
387 fm.end()
388 continue
388 continue
389 formats = []
389 formats = []
390 pieces = []
390 pieces = []
391
391
392 for f, sep in funcmap:
392 for f, sep in funcmap:
393 l = [f(n) for n, dummy in lines]
393 l = [f(n) for n, dummy in lines]
394 if fm.isplain():
394 if fm.isplain():
395 sizes = [encoding.colwidth(x) for x in l]
395 sizes = [encoding.colwidth(x) for x in l]
396 ml = max(sizes)
396 ml = max(sizes)
397 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
397 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
398 else:
398 else:
399 formats.append(['%s' for x in l])
399 formats.append(['%s' for x in l])
400 pieces.append(l)
400 pieces.append(l)
401
401
402 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
402 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
403 fm.startitem()
403 fm.startitem()
404 fm.write(fields, "".join(f), *p)
404 fm.write(fields, "".join(f), *p)
405 if l[0].skip:
405 if l[0].skip:
406 fmt = "* %s"
406 fmt = "* %s"
407 else:
407 else:
408 fmt = ": %s"
408 fmt = ": %s"
409 fm.write('line', fmt, l[1])
409 fm.write('line', fmt, l[1])
410
410
411 if not lines[-1][1].endswith('\n'):
411 if not lines[-1][1].endswith('\n'):
412 fm.plain('\n')
412 fm.plain('\n')
413 fm.end()
413 fm.end()
414
414
415 rootfm.end()
415 rootfm.end()
416
416
417 @command('archive',
417 @command('archive',
418 [('', 'no-decode', None, _('do not pass files through decoders')),
418 [('', 'no-decode', None, _('do not pass files through decoders')),
419 ('p', 'prefix', '', _('directory prefix for files in archive'),
419 ('p', 'prefix', '', _('directory prefix for files in archive'),
420 _('PREFIX')),
420 _('PREFIX')),
421 ('r', 'rev', '', _('revision to distribute'), _('REV')),
421 ('r', 'rev', '', _('revision to distribute'), _('REV')),
422 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
422 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
423 ] + subrepoopts + walkopts,
423 ] + subrepoopts + walkopts,
424 _('[OPTION]... DEST'))
424 _('[OPTION]... DEST'))
425 def archive(ui, repo, dest, **opts):
425 def archive(ui, repo, dest, **opts):
426 '''create an unversioned archive of a repository revision
426 '''create an unversioned archive of a repository revision
427
427
428 By default, the revision used is the parent of the working
428 By default, the revision used is the parent of the working
429 directory; use -r/--rev to specify a different revision.
429 directory; use -r/--rev to specify a different revision.
430
430
431 The archive type is automatically detected based on file
431 The archive type is automatically detected based on file
432 extension (to override, use -t/--type).
432 extension (to override, use -t/--type).
433
433
434 .. container:: verbose
434 .. container:: verbose
435
435
436 Examples:
436 Examples:
437
437
438 - create a zip file containing the 1.0 release::
438 - create a zip file containing the 1.0 release::
439
439
440 hg archive -r 1.0 project-1.0.zip
440 hg archive -r 1.0 project-1.0.zip
441
441
442 - create a tarball excluding .hg files::
442 - create a tarball excluding .hg files::
443
443
444 hg archive project.tar.gz -X ".hg*"
444 hg archive project.tar.gz -X ".hg*"
445
445
446 Valid types are:
446 Valid types are:
447
447
448 :``files``: a directory full of files (default)
448 :``files``: a directory full of files (default)
449 :``tar``: tar archive, uncompressed
449 :``tar``: tar archive, uncompressed
450 :``tbz2``: tar archive, compressed using bzip2
450 :``tbz2``: tar archive, compressed using bzip2
451 :``tgz``: tar archive, compressed using gzip
451 :``tgz``: tar archive, compressed using gzip
452 :``uzip``: zip archive, uncompressed
452 :``uzip``: zip archive, uncompressed
453 :``zip``: zip archive, compressed using deflate
453 :``zip``: zip archive, compressed using deflate
454
454
455 The exact name of the destination archive or directory is given
455 The exact name of the destination archive or directory is given
456 using a format string; see :hg:`help export` for details.
456 using a format string; see :hg:`help export` for details.
457
457
458 Each member added to an archive file has a directory prefix
458 Each member added to an archive file has a directory prefix
459 prepended. Use -p/--prefix to specify a format string for the
459 prepended. Use -p/--prefix to specify a format string for the
460 prefix. The default is the basename of the archive, with suffixes
460 prefix. The default is the basename of the archive, with suffixes
461 removed.
461 removed.
462
462
463 Returns 0 on success.
463 Returns 0 on success.
464 '''
464 '''
465
465
466 opts = pycompat.byteskwargs(opts)
466 opts = pycompat.byteskwargs(opts)
467 ctx = scmutil.revsingle(repo, opts.get('rev'))
467 ctx = scmutil.revsingle(repo, opts.get('rev'))
468 if not ctx:
468 if not ctx:
469 raise error.Abort(_('no working directory: please specify a revision'))
469 raise error.Abort(_('no working directory: please specify a revision'))
470 node = ctx.node()
470 node = ctx.node()
471 dest = cmdutil.makefilename(repo, dest, node)
471 dest = cmdutil.makefilename(repo, dest, node)
472 if os.path.realpath(dest) == repo.root:
472 if os.path.realpath(dest) == repo.root:
473 raise error.Abort(_('repository root cannot be destination'))
473 raise error.Abort(_('repository root cannot be destination'))
474
474
475 kind = opts.get('type') or archival.guesskind(dest) or 'files'
475 kind = opts.get('type') or archival.guesskind(dest) or 'files'
476 prefix = opts.get('prefix')
476 prefix = opts.get('prefix')
477
477
478 if dest == '-':
478 if dest == '-':
479 if kind == 'files':
479 if kind == 'files':
480 raise error.Abort(_('cannot archive plain files to stdout'))
480 raise error.Abort(_('cannot archive plain files to stdout'))
481 dest = cmdutil.makefileobj(repo, dest)
481 dest = cmdutil.makefileobj(repo, dest)
482 if not prefix:
482 if not prefix:
483 prefix = os.path.basename(repo.root) + '-%h'
483 prefix = os.path.basename(repo.root) + '-%h'
484
484
485 prefix = cmdutil.makefilename(repo, prefix, node)
485 prefix = cmdutil.makefilename(repo, prefix, node)
486 match = scmutil.match(ctx, [], opts)
486 match = scmutil.match(ctx, [], opts)
487 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
487 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
488 match, prefix, subrepos=opts.get('subrepos'))
488 match, prefix, subrepos=opts.get('subrepos'))
489
489
490 @command('backout',
490 @command('backout',
491 [('', 'merge', None, _('merge with old dirstate parent after backout')),
491 [('', 'merge', None, _('merge with old dirstate parent after backout')),
492 ('', 'commit', None,
492 ('', 'commit', None,
493 _('commit if no conflicts were encountered (DEPRECATED)')),
493 _('commit if no conflicts were encountered (DEPRECATED)')),
494 ('', 'no-commit', None, _('do not commit')),
494 ('', 'no-commit', None, _('do not commit')),
495 ('', 'parent', '',
495 ('', 'parent', '',
496 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
496 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
497 ('r', 'rev', '', _('revision to backout'), _('REV')),
497 ('r', 'rev', '', _('revision to backout'), _('REV')),
498 ('e', 'edit', False, _('invoke editor on commit messages')),
498 ('e', 'edit', False, _('invoke editor on commit messages')),
499 ] + mergetoolopts + walkopts + commitopts + commitopts2,
499 ] + mergetoolopts + walkopts + commitopts + commitopts2,
500 _('[OPTION]... [-r] REV'))
500 _('[OPTION]... [-r] REV'))
501 def backout(ui, repo, node=None, rev=None, **opts):
501 def backout(ui, repo, node=None, rev=None, **opts):
502 '''reverse effect of earlier changeset
502 '''reverse effect of earlier changeset
503
503
504 Prepare a new changeset with the effect of REV undone in the
504 Prepare a new changeset with the effect of REV undone in the
505 current working directory. If no conflicts were encountered,
505 current working directory. If no conflicts were encountered,
506 it will be committed immediately.
506 it will be committed immediately.
507
507
508 If REV is the parent of the working directory, then this new changeset
508 If REV is the parent of the working directory, then this new changeset
509 is committed automatically (unless --no-commit is specified).
509 is committed automatically (unless --no-commit is specified).
510
510
511 .. note::
511 .. note::
512
512
513 :hg:`backout` cannot be used to fix either an unwanted or
513 :hg:`backout` cannot be used to fix either an unwanted or
514 incorrect merge.
514 incorrect merge.
515
515
516 .. container:: verbose
516 .. container:: verbose
517
517
518 Examples:
518 Examples:
519
519
520 - Reverse the effect of the parent of the working directory.
520 - Reverse the effect of the parent of the working directory.
521 This backout will be committed immediately::
521 This backout will be committed immediately::
522
522
523 hg backout -r .
523 hg backout -r .
524
524
525 - Reverse the effect of previous bad revision 23::
525 - Reverse the effect of previous bad revision 23::
526
526
527 hg backout -r 23
527 hg backout -r 23
528
528
529 - Reverse the effect of previous bad revision 23 and
529 - Reverse the effect of previous bad revision 23 and
530 leave changes uncommitted::
530 leave changes uncommitted::
531
531
532 hg backout -r 23 --no-commit
532 hg backout -r 23 --no-commit
533 hg commit -m "Backout revision 23"
533 hg commit -m "Backout revision 23"
534
534
535 By default, the pending changeset will have one parent,
535 By default, the pending changeset will have one parent,
536 maintaining a linear history. With --merge, the pending
536 maintaining a linear history. With --merge, the pending
537 changeset will instead have two parents: the old parent of the
537 changeset will instead have two parents: the old parent of the
538 working directory and a new child of REV that simply undoes REV.
538 working directory and a new child of REV that simply undoes REV.
539
539
540 Before version 1.7, the behavior without --merge was equivalent
540 Before version 1.7, the behavior without --merge was equivalent
541 to specifying --merge followed by :hg:`update --clean .` to
541 to specifying --merge followed by :hg:`update --clean .` to
542 cancel the merge and leave the child of REV as a head to be
542 cancel the merge and leave the child of REV as a head to be
543 merged separately.
543 merged separately.
544
544
545 See :hg:`help dates` for a list of formats valid for -d/--date.
545 See :hg:`help dates` for a list of formats valid for -d/--date.
546
546
547 See :hg:`help revert` for a way to restore files to the state
547 See :hg:`help revert` for a way to restore files to the state
548 of another revision.
548 of another revision.
549
549
550 Returns 0 on success, 1 if nothing to backout or there are unresolved
550 Returns 0 on success, 1 if nothing to backout or there are unresolved
551 files.
551 files.
552 '''
552 '''
553 wlock = lock = None
553 wlock = lock = None
554 try:
554 try:
555 wlock = repo.wlock()
555 wlock = repo.wlock()
556 lock = repo.lock()
556 lock = repo.lock()
557 return _dobackout(ui, repo, node, rev, **opts)
557 return _dobackout(ui, repo, node, rev, **opts)
558 finally:
558 finally:
559 release(lock, wlock)
559 release(lock, wlock)
560
560
561 def _dobackout(ui, repo, node=None, rev=None, **opts):
561 def _dobackout(ui, repo, node=None, rev=None, **opts):
562 opts = pycompat.byteskwargs(opts)
562 opts = pycompat.byteskwargs(opts)
563 if opts.get('commit') and opts.get('no_commit'):
563 if opts.get('commit') and opts.get('no_commit'):
564 raise error.Abort(_("cannot use --commit with --no-commit"))
564 raise error.Abort(_("cannot use --commit with --no-commit"))
565 if opts.get('merge') and opts.get('no_commit'):
565 if opts.get('merge') and opts.get('no_commit'):
566 raise error.Abort(_("cannot use --merge with --no-commit"))
566 raise error.Abort(_("cannot use --merge with --no-commit"))
567
567
568 if rev and node:
568 if rev and node:
569 raise error.Abort(_("please specify just one revision"))
569 raise error.Abort(_("please specify just one revision"))
570
570
571 if not rev:
571 if not rev:
572 rev = node
572 rev = node
573
573
574 if not rev:
574 if not rev:
575 raise error.Abort(_("please specify a revision to backout"))
575 raise error.Abort(_("please specify a revision to backout"))
576
576
577 date = opts.get('date')
577 date = opts.get('date')
578 if date:
578 if date:
579 opts['date'] = util.parsedate(date)
579 opts['date'] = util.parsedate(date)
580
580
581 cmdutil.checkunfinished(repo)
581 cmdutil.checkunfinished(repo)
582 cmdutil.bailifchanged(repo)
582 cmdutil.bailifchanged(repo)
583 node = scmutil.revsingle(repo, rev).node()
583 node = scmutil.revsingle(repo, rev).node()
584
584
585 op1, op2 = repo.dirstate.parents()
585 op1, op2 = repo.dirstate.parents()
586 if not repo.changelog.isancestor(node, op1):
586 if not repo.changelog.isancestor(node, op1):
587 raise error.Abort(_('cannot backout change that is not an ancestor'))
587 raise error.Abort(_('cannot backout change that is not an ancestor'))
588
588
589 p1, p2 = repo.changelog.parents(node)
589 p1, p2 = repo.changelog.parents(node)
590 if p1 == nullid:
590 if p1 == nullid:
591 raise error.Abort(_('cannot backout a change with no parents'))
591 raise error.Abort(_('cannot backout a change with no parents'))
592 if p2 != nullid:
592 if p2 != nullid:
593 if not opts.get('parent'):
593 if not opts.get('parent'):
594 raise error.Abort(_('cannot backout a merge changeset'))
594 raise error.Abort(_('cannot backout a merge changeset'))
595 p = repo.lookup(opts['parent'])
595 p = repo.lookup(opts['parent'])
596 if p not in (p1, p2):
596 if p not in (p1, p2):
597 raise error.Abort(_('%s is not a parent of %s') %
597 raise error.Abort(_('%s is not a parent of %s') %
598 (short(p), short(node)))
598 (short(p), short(node)))
599 parent = p
599 parent = p
600 else:
600 else:
601 if opts.get('parent'):
601 if opts.get('parent'):
602 raise error.Abort(_('cannot use --parent on non-merge changeset'))
602 raise error.Abort(_('cannot use --parent on non-merge changeset'))
603 parent = p1
603 parent = p1
604
604
605 # the backout should appear on the same branch
605 # the backout should appear on the same branch
606 branch = repo.dirstate.branch()
606 branch = repo.dirstate.branch()
607 bheads = repo.branchheads(branch)
607 bheads = repo.branchheads(branch)
608 rctx = scmutil.revsingle(repo, hex(parent))
608 rctx = scmutil.revsingle(repo, hex(parent))
609 if not opts.get('merge') and op1 != node:
609 if not opts.get('merge') and op1 != node:
610 dsguard = dirstateguard.dirstateguard(repo, 'backout')
610 dsguard = dirstateguard.dirstateguard(repo, 'backout')
611 try:
611 try:
612 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
612 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
613 'backout')
613 'backout')
614 stats = mergemod.update(repo, parent, True, True, node, False)
614 stats = mergemod.update(repo, parent, True, True, node, False)
615 repo.setparents(op1, op2)
615 repo.setparents(op1, op2)
616 dsguard.close()
616 dsguard.close()
617 hg._showstats(repo, stats)
617 hg._showstats(repo, stats)
618 if stats[3]:
618 if stats[3]:
619 repo.ui.status(_("use 'hg resolve' to retry unresolved "
619 repo.ui.status(_("use 'hg resolve' to retry unresolved "
620 "file merges\n"))
620 "file merges\n"))
621 return 1
621 return 1
622 finally:
622 finally:
623 ui.setconfig('ui', 'forcemerge', '', '')
623 ui.setconfig('ui', 'forcemerge', '', '')
624 lockmod.release(dsguard)
624 lockmod.release(dsguard)
625 else:
625 else:
626 hg.clean(repo, node, show_stats=False)
626 hg.clean(repo, node, show_stats=False)
627 repo.dirstate.setbranch(branch)
627 repo.dirstate.setbranch(branch)
628 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
628 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
629
629
630 if opts.get('no_commit'):
630 if opts.get('no_commit'):
631 msg = _("changeset %s backed out, "
631 msg = _("changeset %s backed out, "
632 "don't forget to commit.\n")
632 "don't forget to commit.\n")
633 ui.status(msg % short(node))
633 ui.status(msg % short(node))
634 return 0
634 return 0
635
635
636 def commitfunc(ui, repo, message, match, opts):
636 def commitfunc(ui, repo, message, match, opts):
637 editform = 'backout'
637 editform = 'backout'
638 e = cmdutil.getcommiteditor(editform=editform,
638 e = cmdutil.getcommiteditor(editform=editform,
639 **pycompat.strkwargs(opts))
639 **pycompat.strkwargs(opts))
640 if not message:
640 if not message:
641 # we don't translate commit messages
641 # we don't translate commit messages
642 message = "Backed out changeset %s" % short(node)
642 message = "Backed out changeset %s" % short(node)
643 e = cmdutil.getcommiteditor(edit=True, editform=editform)
643 e = cmdutil.getcommiteditor(edit=True, editform=editform)
644 return repo.commit(message, opts.get('user'), opts.get('date'),
644 return repo.commit(message, opts.get('user'), opts.get('date'),
645 match, editor=e)
645 match, editor=e)
646 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
646 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
647 if not newnode:
647 if not newnode:
648 ui.status(_("nothing changed\n"))
648 ui.status(_("nothing changed\n"))
649 return 1
649 return 1
650 cmdutil.commitstatus(repo, newnode, branch, bheads)
650 cmdutil.commitstatus(repo, newnode, branch, bheads)
651
651
652 def nice(node):
652 def nice(node):
653 return '%d:%s' % (repo.changelog.rev(node), short(node))
653 return '%d:%s' % (repo.changelog.rev(node), short(node))
654 ui.status(_('changeset %s backs out changeset %s\n') %
654 ui.status(_('changeset %s backs out changeset %s\n') %
655 (nice(repo.changelog.tip()), nice(node)))
655 (nice(repo.changelog.tip()), nice(node)))
656 if opts.get('merge') and op1 != node:
656 if opts.get('merge') and op1 != node:
657 hg.clean(repo, op1, show_stats=False)
657 hg.clean(repo, op1, show_stats=False)
658 ui.status(_('merging with changeset %s\n')
658 ui.status(_('merging with changeset %s\n')
659 % nice(repo.changelog.tip()))
659 % nice(repo.changelog.tip()))
660 try:
660 try:
661 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
661 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
662 'backout')
662 'backout')
663 return hg.merge(repo, hex(repo.changelog.tip()))
663 return hg.merge(repo, hex(repo.changelog.tip()))
664 finally:
664 finally:
665 ui.setconfig('ui', 'forcemerge', '', '')
665 ui.setconfig('ui', 'forcemerge', '', '')
666 return 0
666 return 0
667
667
668 @command('bisect',
668 @command('bisect',
669 [('r', 'reset', False, _('reset bisect state')),
669 [('r', 'reset', False, _('reset bisect state')),
670 ('g', 'good', False, _('mark changeset good')),
670 ('g', 'good', False, _('mark changeset good')),
671 ('b', 'bad', False, _('mark changeset bad')),
671 ('b', 'bad', False, _('mark changeset bad')),
672 ('s', 'skip', False, _('skip testing changeset')),
672 ('s', 'skip', False, _('skip testing changeset')),
673 ('e', 'extend', False, _('extend the bisect range')),
673 ('e', 'extend', False, _('extend the bisect range')),
674 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
674 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
675 ('U', 'noupdate', False, _('do not update to target'))],
675 ('U', 'noupdate', False, _('do not update to target'))],
676 _("[-gbsr] [-U] [-c CMD] [REV]"))
676 _("[-gbsr] [-U] [-c CMD] [REV]"))
677 def bisect(ui, repo, rev=None, extra=None, command=None,
677 def bisect(ui, repo, rev=None, extra=None, command=None,
678 reset=None, good=None, bad=None, skip=None, extend=None,
678 reset=None, good=None, bad=None, skip=None, extend=None,
679 noupdate=None):
679 noupdate=None):
680 """subdivision search of changesets
680 """subdivision search of changesets
681
681
682 This command helps to find changesets which introduce problems. To
682 This command helps to find changesets which introduce problems. To
683 use, mark the earliest changeset you know exhibits the problem as
683 use, mark the earliest changeset you know exhibits the problem as
684 bad, then mark the latest changeset which is free from the problem
684 bad, then mark the latest changeset which is free from the problem
685 as good. Bisect will update your working directory to a revision
685 as good. Bisect will update your working directory to a revision
686 for testing (unless the -U/--noupdate option is specified). Once
686 for testing (unless the -U/--noupdate option is specified). Once
687 you have performed tests, mark the working directory as good or
687 you have performed tests, mark the working directory as good or
688 bad, and bisect will either update to another candidate changeset
688 bad, and bisect will either update to another candidate changeset
689 or announce that it has found the bad revision.
689 or announce that it has found the bad revision.
690
690
691 As a shortcut, you can also use the revision argument to mark a
691 As a shortcut, you can also use the revision argument to mark a
692 revision as good or bad without checking it out first.
692 revision as good or bad without checking it out first.
693
693
694 If you supply a command, it will be used for automatic bisection.
694 If you supply a command, it will be used for automatic bisection.
695 The environment variable HG_NODE will contain the ID of the
695 The environment variable HG_NODE will contain the ID of the
696 changeset being tested. The exit status of the command will be
696 changeset being tested. The exit status of the command will be
697 used to mark revisions as good or bad: status 0 means good, 125
697 used to mark revisions as good or bad: status 0 means good, 125
698 means to skip the revision, 127 (command not found) will abort the
698 means to skip the revision, 127 (command not found) will abort the
699 bisection, and any other non-zero exit status means the revision
699 bisection, and any other non-zero exit status means the revision
700 is bad.
700 is bad.
701
701
702 .. container:: verbose
702 .. container:: verbose
703
703
704 Some examples:
704 Some examples:
705
705
706 - start a bisection with known bad revision 34, and good revision 12::
706 - start a bisection with known bad revision 34, and good revision 12::
707
707
708 hg bisect --bad 34
708 hg bisect --bad 34
709 hg bisect --good 12
709 hg bisect --good 12
710
710
711 - advance the current bisection by marking current revision as good or
711 - advance the current bisection by marking current revision as good or
712 bad::
712 bad::
713
713
714 hg bisect --good
714 hg bisect --good
715 hg bisect --bad
715 hg bisect --bad
716
716
717 - mark the current revision, or a known revision, to be skipped (e.g. if
717 - mark the current revision, or a known revision, to be skipped (e.g. if
718 that revision is not usable because of another issue)::
718 that revision is not usable because of another issue)::
719
719
720 hg bisect --skip
720 hg bisect --skip
721 hg bisect --skip 23
721 hg bisect --skip 23
722
722
723 - skip all revisions that do not touch directories ``foo`` or ``bar``::
723 - skip all revisions that do not touch directories ``foo`` or ``bar``::
724
724
725 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
725 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
726
726
727 - forget the current bisection::
727 - forget the current bisection::
728
728
729 hg bisect --reset
729 hg bisect --reset
730
730
731 - use 'make && make tests' to automatically find the first broken
731 - use 'make && make tests' to automatically find the first broken
732 revision::
732 revision::
733
733
734 hg bisect --reset
734 hg bisect --reset
735 hg bisect --bad 34
735 hg bisect --bad 34
736 hg bisect --good 12
736 hg bisect --good 12
737 hg bisect --command "make && make tests"
737 hg bisect --command "make && make tests"
738
738
739 - see all changesets whose states are already known in the current
739 - see all changesets whose states are already known in the current
740 bisection::
740 bisection::
741
741
742 hg log -r "bisect(pruned)"
742 hg log -r "bisect(pruned)"
743
743
744 - see the changeset currently being bisected (especially useful
744 - see the changeset currently being bisected (especially useful
745 if running with -U/--noupdate)::
745 if running with -U/--noupdate)::
746
746
747 hg log -r "bisect(current)"
747 hg log -r "bisect(current)"
748
748
749 - see all changesets that took part in the current bisection::
749 - see all changesets that took part in the current bisection::
750
750
751 hg log -r "bisect(range)"
751 hg log -r "bisect(range)"
752
752
753 - you can even get a nice graph::
753 - you can even get a nice graph::
754
754
755 hg log --graph -r "bisect(range)"
755 hg log --graph -r "bisect(range)"
756
756
757 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
757 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
758
758
759 Returns 0 on success.
759 Returns 0 on success.
760 """
760 """
761 # backward compatibility
761 # backward compatibility
762 if rev in "good bad reset init".split():
762 if rev in "good bad reset init".split():
763 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
763 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
764 cmd, rev, extra = rev, extra, None
764 cmd, rev, extra = rev, extra, None
765 if cmd == "good":
765 if cmd == "good":
766 good = True
766 good = True
767 elif cmd == "bad":
767 elif cmd == "bad":
768 bad = True
768 bad = True
769 else:
769 else:
770 reset = True
770 reset = True
771 elif extra:
771 elif extra:
772 raise error.Abort(_('incompatible arguments'))
772 raise error.Abort(_('incompatible arguments'))
773
773
774 incompatibles = {
774 incompatibles = {
775 '--bad': bad,
775 '--bad': bad,
776 '--command': bool(command),
776 '--command': bool(command),
777 '--extend': extend,
777 '--extend': extend,
778 '--good': good,
778 '--good': good,
779 '--reset': reset,
779 '--reset': reset,
780 '--skip': skip,
780 '--skip': skip,
781 }
781 }
782
782
783 enabled = [x for x in incompatibles if incompatibles[x]]
783 enabled = [x for x in incompatibles if incompatibles[x]]
784
784
785 if len(enabled) > 1:
785 if len(enabled) > 1:
786 raise error.Abort(_('%s and %s are incompatible') %
786 raise error.Abort(_('%s and %s are incompatible') %
787 tuple(sorted(enabled)[0:2]))
787 tuple(sorted(enabled)[0:2]))
788
788
789 if reset:
789 if reset:
790 hbisect.resetstate(repo)
790 hbisect.resetstate(repo)
791 return
791 return
792
792
793 state = hbisect.load_state(repo)
793 state = hbisect.load_state(repo)
794
794
795 # update state
795 # update state
796 if good or bad or skip:
796 if good or bad or skip:
797 if rev:
797 if rev:
798 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
798 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
799 else:
799 else:
800 nodes = [repo.lookup('.')]
800 nodes = [repo.lookup('.')]
801 if good:
801 if good:
802 state['good'] += nodes
802 state['good'] += nodes
803 elif bad:
803 elif bad:
804 state['bad'] += nodes
804 state['bad'] += nodes
805 elif skip:
805 elif skip:
806 state['skip'] += nodes
806 state['skip'] += nodes
807 hbisect.save_state(repo, state)
807 hbisect.save_state(repo, state)
808 if not (state['good'] and state['bad']):
808 if not (state['good'] and state['bad']):
809 return
809 return
810
810
811 def mayupdate(repo, node, show_stats=True):
811 def mayupdate(repo, node, show_stats=True):
812 """common used update sequence"""
812 """common used update sequence"""
813 if noupdate:
813 if noupdate:
814 return
814 return
815 cmdutil.checkunfinished(repo)
815 cmdutil.checkunfinished(repo)
816 cmdutil.bailifchanged(repo)
816 cmdutil.bailifchanged(repo)
817 return hg.clean(repo, node, show_stats=show_stats)
817 return hg.clean(repo, node, show_stats=show_stats)
818
818
819 displayer = cmdutil.show_changeset(ui, repo, {})
819 displayer = cmdutil.show_changeset(ui, repo, {})
820
820
821 if command:
821 if command:
822 changesets = 1
822 changesets = 1
823 if noupdate:
823 if noupdate:
824 try:
824 try:
825 node = state['current'][0]
825 node = state['current'][0]
826 except LookupError:
826 except LookupError:
827 raise error.Abort(_('current bisect revision is unknown - '
827 raise error.Abort(_('current bisect revision is unknown - '
828 'start a new bisect to fix'))
828 'start a new bisect to fix'))
829 else:
829 else:
830 node, p2 = repo.dirstate.parents()
830 node, p2 = repo.dirstate.parents()
831 if p2 != nullid:
831 if p2 != nullid:
832 raise error.Abort(_('current bisect revision is a merge'))
832 raise error.Abort(_('current bisect revision is a merge'))
833 if rev:
833 if rev:
834 node = repo[scmutil.revsingle(repo, rev, node)].node()
834 node = repo[scmutil.revsingle(repo, rev, node)].node()
835 try:
835 try:
836 while changesets:
836 while changesets:
837 # update state
837 # update state
838 state['current'] = [node]
838 state['current'] = [node]
839 hbisect.save_state(repo, state)
839 hbisect.save_state(repo, state)
840 status = ui.system(command, environ={'HG_NODE': hex(node)},
840 status = ui.system(command, environ={'HG_NODE': hex(node)},
841 blockedtag='bisect_check')
841 blockedtag='bisect_check')
842 if status == 125:
842 if status == 125:
843 transition = "skip"
843 transition = "skip"
844 elif status == 0:
844 elif status == 0:
845 transition = "good"
845 transition = "good"
846 # status < 0 means process was killed
846 # status < 0 means process was killed
847 elif status == 127:
847 elif status == 127:
848 raise error.Abort(_("failed to execute %s") % command)
848 raise error.Abort(_("failed to execute %s") % command)
849 elif status < 0:
849 elif status < 0:
850 raise error.Abort(_("%s killed") % command)
850 raise error.Abort(_("%s killed") % command)
851 else:
851 else:
852 transition = "bad"
852 transition = "bad"
853 state[transition].append(node)
853 state[transition].append(node)
854 ctx = repo[node]
854 ctx = repo[node]
855 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
855 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
856 hbisect.checkstate(state)
856 hbisect.checkstate(state)
857 # bisect
857 # bisect
858 nodes, changesets, bgood = hbisect.bisect(repo, state)
858 nodes, changesets, bgood = hbisect.bisect(repo, state)
859 # update to next check
859 # update to next check
860 node = nodes[0]
860 node = nodes[0]
861 mayupdate(repo, node, show_stats=False)
861 mayupdate(repo, node, show_stats=False)
862 finally:
862 finally:
863 state['current'] = [node]
863 state['current'] = [node]
864 hbisect.save_state(repo, state)
864 hbisect.save_state(repo, state)
865 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
865 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
866 return
866 return
867
867
868 hbisect.checkstate(state)
868 hbisect.checkstate(state)
869
869
870 # actually bisect
870 # actually bisect
871 nodes, changesets, good = hbisect.bisect(repo, state)
871 nodes, changesets, good = hbisect.bisect(repo, state)
872 if extend:
872 if extend:
873 if not changesets:
873 if not changesets:
874 extendnode = hbisect.extendrange(repo, state, nodes, good)
874 extendnode = hbisect.extendrange(repo, state, nodes, good)
875 if extendnode is not None:
875 if extendnode is not None:
876 ui.write(_("Extending search to changeset %d:%s\n")
876 ui.write(_("Extending search to changeset %d:%s\n")
877 % (extendnode.rev(), extendnode))
877 % (extendnode.rev(), extendnode))
878 state['current'] = [extendnode.node()]
878 state['current'] = [extendnode.node()]
879 hbisect.save_state(repo, state)
879 hbisect.save_state(repo, state)
880 return mayupdate(repo, extendnode.node())
880 return mayupdate(repo, extendnode.node())
881 raise error.Abort(_("nothing to extend"))
881 raise error.Abort(_("nothing to extend"))
882
882
883 if changesets == 0:
883 if changesets == 0:
884 hbisect.printresult(ui, repo, state, displayer, nodes, good)
884 hbisect.printresult(ui, repo, state, displayer, nodes, good)
885 else:
885 else:
886 assert len(nodes) == 1 # only a single node can be tested next
886 assert len(nodes) == 1 # only a single node can be tested next
887 node = nodes[0]
887 node = nodes[0]
888 # compute the approximate number of remaining tests
888 # compute the approximate number of remaining tests
889 tests, size = 0, 2
889 tests, size = 0, 2
890 while size <= changesets:
890 while size <= changesets:
891 tests, size = tests + 1, size * 2
891 tests, size = tests + 1, size * 2
892 rev = repo.changelog.rev(node)
892 rev = repo.changelog.rev(node)
893 ui.write(_("Testing changeset %d:%s "
893 ui.write(_("Testing changeset %d:%s "
894 "(%d changesets remaining, ~%d tests)\n")
894 "(%d changesets remaining, ~%d tests)\n")
895 % (rev, short(node), changesets, tests))
895 % (rev, short(node), changesets, tests))
896 state['current'] = [node]
896 state['current'] = [node]
897 hbisect.save_state(repo, state)
897 hbisect.save_state(repo, state)
898 return mayupdate(repo, node)
898 return mayupdate(repo, node)
899
899
900 @command('bookmarks|bookmark',
900 @command('bookmarks|bookmark',
901 [('f', 'force', False, _('force')),
901 [('f', 'force', False, _('force')),
902 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
902 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
903 ('d', 'delete', False, _('delete a given bookmark')),
903 ('d', 'delete', False, _('delete a given bookmark')),
904 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
904 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
905 ('i', 'inactive', False, _('mark a bookmark inactive')),
905 ('i', 'inactive', False, _('mark a bookmark inactive')),
906 ] + formatteropts,
906 ] + formatteropts,
907 _('hg bookmarks [OPTIONS]... [NAME]...'))
907 _('hg bookmarks [OPTIONS]... [NAME]...'))
908 def bookmark(ui, repo, *names, **opts):
908 def bookmark(ui, repo, *names, **opts):
909 '''create a new bookmark or list existing bookmarks
909 '''create a new bookmark or list existing bookmarks
910
910
911 Bookmarks are labels on changesets to help track lines of development.
911 Bookmarks are labels on changesets to help track lines of development.
912 Bookmarks are unversioned and can be moved, renamed and deleted.
912 Bookmarks are unversioned and can be moved, renamed and deleted.
913 Deleting or moving a bookmark has no effect on the associated changesets.
913 Deleting or moving a bookmark has no effect on the associated changesets.
914
914
915 Creating or updating to a bookmark causes it to be marked as 'active'.
915 Creating or updating to a bookmark causes it to be marked as 'active'.
916 The active bookmark is indicated with a '*'.
916 The active bookmark is indicated with a '*'.
917 When a commit is made, the active bookmark will advance to the new commit.
917 When a commit is made, the active bookmark will advance to the new commit.
918 A plain :hg:`update` will also advance an active bookmark, if possible.
918 A plain :hg:`update` will also advance an active bookmark, if possible.
919 Updating away from a bookmark will cause it to be deactivated.
919 Updating away from a bookmark will cause it to be deactivated.
920
920
921 Bookmarks can be pushed and pulled between repositories (see
921 Bookmarks can be pushed and pulled between repositories (see
922 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
922 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
923 diverged, a new 'divergent bookmark' of the form 'name@path' will
923 diverged, a new 'divergent bookmark' of the form 'name@path' will
924 be created. Using :hg:`merge` will resolve the divergence.
924 be created. Using :hg:`merge` will resolve the divergence.
925
925
926 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
926 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
927 the active bookmark's name.
927 the active bookmark's name.
928
928
929 A bookmark named '@' has the special property that :hg:`clone` will
929 A bookmark named '@' has the special property that :hg:`clone` will
930 check it out by default if it exists.
930 check it out by default if it exists.
931
931
932 .. container:: verbose
932 .. container:: verbose
933
933
934 Examples:
934 Examples:
935
935
936 - create an active bookmark for a new line of development::
936 - create an active bookmark for a new line of development::
937
937
938 hg book new-feature
938 hg book new-feature
939
939
940 - create an inactive bookmark as a place marker::
940 - create an inactive bookmark as a place marker::
941
941
942 hg book -i reviewed
942 hg book -i reviewed
943
943
944 - create an inactive bookmark on another changeset::
944 - create an inactive bookmark on another changeset::
945
945
946 hg book -r .^ tested
946 hg book -r .^ tested
947
947
948 - rename bookmark turkey to dinner::
948 - rename bookmark turkey to dinner::
949
949
950 hg book -m turkey dinner
950 hg book -m turkey dinner
951
951
952 - move the '@' bookmark from another branch::
952 - move the '@' bookmark from another branch::
953
953
954 hg book -f @
954 hg book -f @
955 '''
955 '''
956 force = opts.get(r'force')
956 force = opts.get(r'force')
957 rev = opts.get(r'rev')
957 rev = opts.get(r'rev')
958 delete = opts.get(r'delete')
958 delete = opts.get(r'delete')
959 rename = opts.get(r'rename')
959 rename = opts.get(r'rename')
960 inactive = opts.get(r'inactive')
960 inactive = opts.get(r'inactive')
961
961
962 if delete and rename:
962 if delete and rename:
963 raise error.Abort(_("--delete and --rename are incompatible"))
963 raise error.Abort(_("--delete and --rename are incompatible"))
964 if delete and rev:
964 if delete and rev:
965 raise error.Abort(_("--rev is incompatible with --delete"))
965 raise error.Abort(_("--rev is incompatible with --delete"))
966 if rename and rev:
966 if rename and rev:
967 raise error.Abort(_("--rev is incompatible with --rename"))
967 raise error.Abort(_("--rev is incompatible with --rename"))
968 if not names and (delete or rev):
968 if not names and (delete or rev):
969 raise error.Abort(_("bookmark name required"))
969 raise error.Abort(_("bookmark name required"))
970
970
971 if delete or rename or names or inactive:
971 if delete or rename or names or inactive:
972 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
972 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
973 if delete:
973 if delete:
974 names = pycompat.maplist(repo._bookmarks.expandname, names)
974 names = pycompat.maplist(repo._bookmarks.expandname, names)
975 bookmarks.delete(repo, tr, names)
975 bookmarks.delete(repo, tr, names)
976 elif rename:
976 elif rename:
977 if not names:
977 if not names:
978 raise error.Abort(_("new bookmark name required"))
978 raise error.Abort(_("new bookmark name required"))
979 elif len(names) > 1:
979 elif len(names) > 1:
980 raise error.Abort(_("only one new bookmark name allowed"))
980 raise error.Abort(_("only one new bookmark name allowed"))
981 rename = repo._bookmarks.expandname(rename)
981 rename = repo._bookmarks.expandname(rename)
982 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
982 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
983 elif names:
983 elif names:
984 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
984 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
985 elif inactive:
985 elif inactive:
986 if len(repo._bookmarks) == 0:
986 if len(repo._bookmarks) == 0:
987 ui.status(_("no bookmarks set\n"))
987 ui.status(_("no bookmarks set\n"))
988 elif not repo._activebookmark:
988 elif not repo._activebookmark:
989 ui.status(_("no active bookmark\n"))
989 ui.status(_("no active bookmark\n"))
990 else:
990 else:
991 bookmarks.deactivate(repo)
991 bookmarks.deactivate(repo)
992 else: # show bookmarks
992 else: # show bookmarks
993 bookmarks.printbookmarks(ui, repo, **opts)
993 bookmarks.printbookmarks(ui, repo, **opts)
994
994
995 @command('branch',
995 @command('branch',
996 [('f', 'force', None,
996 [('f', 'force', None,
997 _('set branch name even if it shadows an existing branch')),
997 _('set branch name even if it shadows an existing branch')),
998 ('C', 'clean', None, _('reset branch name to parent branch name'))],
998 ('C', 'clean', None, _('reset branch name to parent branch name'))],
999 _('[-fC] [NAME]'))
999 _('[-fC] [NAME]'))
1000 def branch(ui, repo, label=None, **opts):
1000 def branch(ui, repo, label=None, **opts):
1001 """set or show the current branch name
1001 """set or show the current branch name
1002
1002
1003 .. note::
1003 .. note::
1004
1004
1005 Branch names are permanent and global. Use :hg:`bookmark` to create a
1005 Branch names are permanent and global. Use :hg:`bookmark` to create a
1006 light-weight bookmark instead. See :hg:`help glossary` for more
1006 light-weight bookmark instead. See :hg:`help glossary` for more
1007 information about named branches and bookmarks.
1007 information about named branches and bookmarks.
1008
1008
1009 With no argument, show the current branch name. With one argument,
1009 With no argument, show the current branch name. With one argument,
1010 set the working directory branch name (the branch will not exist
1010 set the working directory branch name (the branch will not exist
1011 in the repository until the next commit). Standard practice
1011 in the repository until the next commit). Standard practice
1012 recommends that primary development take place on the 'default'
1012 recommends that primary development take place on the 'default'
1013 branch.
1013 branch.
1014
1014
1015 Unless -f/--force is specified, branch will not let you set a
1015 Unless -f/--force is specified, branch will not let you set a
1016 branch name that already exists.
1016 branch name that already exists.
1017
1017
1018 Use -C/--clean to reset the working directory branch to that of
1018 Use -C/--clean to reset the working directory branch to that of
1019 the parent of the working directory, negating a previous branch
1019 the parent of the working directory, negating a previous branch
1020 change.
1020 change.
1021
1021
1022 Use the command :hg:`update` to switch to an existing branch. Use
1022 Use the command :hg:`update` to switch to an existing branch. Use
1023 :hg:`commit --close-branch` to mark this branch head as closed.
1023 :hg:`commit --close-branch` to mark this branch head as closed.
1024 When all heads of a branch are closed, the branch will be
1024 When all heads of a branch are closed, the branch will be
1025 considered closed.
1025 considered closed.
1026
1026
1027 Returns 0 on success.
1027 Returns 0 on success.
1028 """
1028 """
1029 opts = pycompat.byteskwargs(opts)
1029 opts = pycompat.byteskwargs(opts)
1030 if label:
1030 if label:
1031 label = label.strip()
1031 label = label.strip()
1032
1032
1033 if not opts.get('clean') and not label:
1033 if not opts.get('clean') and not label:
1034 ui.write("%s\n" % repo.dirstate.branch())
1034 ui.write("%s\n" % repo.dirstate.branch())
1035 return
1035 return
1036
1036
1037 with repo.wlock():
1037 with repo.wlock():
1038 if opts.get('clean'):
1038 if opts.get('clean'):
1039 label = repo[None].p1().branch()
1039 label = repo[None].p1().branch()
1040 repo.dirstate.setbranch(label)
1040 repo.dirstate.setbranch(label)
1041 ui.status(_('reset working directory to branch %s\n') % label)
1041 ui.status(_('reset working directory to branch %s\n') % label)
1042 elif label:
1042 elif label:
1043 if not opts.get('force') and label in repo.branchmap():
1043 if not opts.get('force') and label in repo.branchmap():
1044 if label not in [p.branch() for p in repo[None].parents()]:
1044 if label not in [p.branch() for p in repo[None].parents()]:
1045 raise error.Abort(_('a branch of the same name already'
1045 raise error.Abort(_('a branch of the same name already'
1046 ' exists'),
1046 ' exists'),
1047 # i18n: "it" refers to an existing branch
1047 # i18n: "it" refers to an existing branch
1048 hint=_("use 'hg update' to switch to it"))
1048 hint=_("use 'hg update' to switch to it"))
1049 scmutil.checknewlabel(repo, label, 'branch')
1049 scmutil.checknewlabel(repo, label, 'branch')
1050 repo.dirstate.setbranch(label)
1050 repo.dirstate.setbranch(label)
1051 ui.status(_('marked working directory as branch %s\n') % label)
1051 ui.status(_('marked working directory as branch %s\n') % label)
1052
1052
1053 # find any open named branches aside from default
1053 # find any open named branches aside from default
1054 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1054 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1055 if n != "default" and not c]
1055 if n != "default" and not c]
1056 if not others:
1056 if not others:
1057 ui.status(_('(branches are permanent and global, '
1057 ui.status(_('(branches are permanent and global, '
1058 'did you want a bookmark?)\n'))
1058 'did you want a bookmark?)\n'))
1059
1059
1060 @command('branches',
1060 @command('branches',
1061 [('a', 'active', False,
1061 [('a', 'active', False,
1062 _('show only branches that have unmerged heads (DEPRECATED)')),
1062 _('show only branches that have unmerged heads (DEPRECATED)')),
1063 ('c', 'closed', False, _('show normal and closed branches')),
1063 ('c', 'closed', False, _('show normal and closed branches')),
1064 ] + formatteropts,
1064 ] + formatteropts,
1065 _('[-c]'), cmdtype=readonly)
1065 _('[-c]'), cmdtype=readonly)
1066 def branches(ui, repo, active=False, closed=False, **opts):
1066 def branches(ui, repo, active=False, closed=False, **opts):
1067 """list repository named branches
1067 """list repository named branches
1068
1068
1069 List the repository's named branches, indicating which ones are
1069 List the repository's named branches, indicating which ones are
1070 inactive. If -c/--closed is specified, also list branches which have
1070 inactive. If -c/--closed is specified, also list branches which have
1071 been marked closed (see :hg:`commit --close-branch`).
1071 been marked closed (see :hg:`commit --close-branch`).
1072
1072
1073 Use the command :hg:`update` to switch to an existing branch.
1073 Use the command :hg:`update` to switch to an existing branch.
1074
1074
1075 Returns 0.
1075 Returns 0.
1076 """
1076 """
1077
1077
1078 opts = pycompat.byteskwargs(opts)
1078 opts = pycompat.byteskwargs(opts)
1079 ui.pager('branches')
1079 ui.pager('branches')
1080 fm = ui.formatter('branches', opts)
1080 fm = ui.formatter('branches', opts)
1081 hexfunc = fm.hexfunc
1081 hexfunc = fm.hexfunc
1082
1082
1083 allheads = set(repo.heads())
1083 allheads = set(repo.heads())
1084 branches = []
1084 branches = []
1085 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1085 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1086 isactive = False
1086 isactive = False
1087 if not isclosed:
1087 if not isclosed:
1088 openheads = set(repo.branchmap().iteropen(heads))
1088 openheads = set(repo.branchmap().iteropen(heads))
1089 isactive = bool(openheads & allheads)
1089 isactive = bool(openheads & allheads)
1090 branches.append((tag, repo[tip], isactive, not isclosed))
1090 branches.append((tag, repo[tip], isactive, not isclosed))
1091 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1091 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1092 reverse=True)
1092 reverse=True)
1093
1093
1094 for tag, ctx, isactive, isopen in branches:
1094 for tag, ctx, isactive, isopen in branches:
1095 if active and not isactive:
1095 if active and not isactive:
1096 continue
1096 continue
1097 if isactive:
1097 if isactive:
1098 label = 'branches.active'
1098 label = 'branches.active'
1099 notice = ''
1099 notice = ''
1100 elif not isopen:
1100 elif not isopen:
1101 if not closed:
1101 if not closed:
1102 continue
1102 continue
1103 label = 'branches.closed'
1103 label = 'branches.closed'
1104 notice = _(' (closed)')
1104 notice = _(' (closed)')
1105 else:
1105 else:
1106 label = 'branches.inactive'
1106 label = 'branches.inactive'
1107 notice = _(' (inactive)')
1107 notice = _(' (inactive)')
1108 current = (tag == repo.dirstate.branch())
1108 current = (tag == repo.dirstate.branch())
1109 if current:
1109 if current:
1110 label = 'branches.current'
1110 label = 'branches.current'
1111
1111
1112 fm.startitem()
1112 fm.startitem()
1113 fm.write('branch', '%s', tag, label=label)
1113 fm.write('branch', '%s', tag, label=label)
1114 rev = ctx.rev()
1114 rev = ctx.rev()
1115 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1115 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1116 fmt = ' ' * padsize + ' %d:%s'
1116 fmt = ' ' * padsize + ' %d:%s'
1117 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1117 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1118 label='log.changeset changeset.%s' % ctx.phasestr())
1118 label='log.changeset changeset.%s' % ctx.phasestr())
1119 fm.context(ctx=ctx)
1119 fm.context(ctx=ctx)
1120 fm.data(active=isactive, closed=not isopen, current=current)
1120 fm.data(active=isactive, closed=not isopen, current=current)
1121 if not ui.quiet:
1121 if not ui.quiet:
1122 fm.plain(notice)
1122 fm.plain(notice)
1123 fm.plain('\n')
1123 fm.plain('\n')
1124 fm.end()
1124 fm.end()
1125
1125
1126 @command('bundle',
1126 @command('bundle',
1127 [('f', 'force', None, _('run even when the destination is unrelated')),
1127 [('f', 'force', None, _('run even when the destination is unrelated')),
1128 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1128 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1129 _('REV')),
1129 _('REV')),
1130 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1130 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1131 _('BRANCH')),
1131 _('BRANCH')),
1132 ('', 'base', [],
1132 ('', 'base', [],
1133 _('a base changeset assumed to be available at the destination'),
1133 _('a base changeset assumed to be available at the destination'),
1134 _('REV')),
1134 _('REV')),
1135 ('a', 'all', None, _('bundle all changesets in the repository')),
1135 ('a', 'all', None, _('bundle all changesets in the repository')),
1136 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1136 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1137 ] + remoteopts,
1137 ] + remoteopts,
1138 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1138 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1139 def bundle(ui, repo, fname, dest=None, **opts):
1139 def bundle(ui, repo, fname, dest=None, **opts):
1140 """create a bundle file
1140 """create a bundle file
1141
1141
1142 Generate a bundle file containing data to be added to a repository.
1142 Generate a bundle file containing data to be added to a repository.
1143
1143
1144 To create a bundle containing all changesets, use -a/--all
1144 To create a bundle containing all changesets, use -a/--all
1145 (or --base null). Otherwise, hg assumes the destination will have
1145 (or --base null). Otherwise, hg assumes the destination will have
1146 all the nodes you specify with --base parameters. Otherwise, hg
1146 all the nodes you specify with --base parameters. Otherwise, hg
1147 will assume the repository has all the nodes in destination, or
1147 will assume the repository has all the nodes in destination, or
1148 default-push/default if no destination is specified.
1148 default-push/default if no destination is specified.
1149
1149
1150 You can change bundle format with the -t/--type option. See
1150 You can change bundle format with the -t/--type option. See
1151 :hg:`help bundlespec` for documentation on this format. By default,
1151 :hg:`help bundlespec` for documentation on this format. By default,
1152 the most appropriate format is used and compression defaults to
1152 the most appropriate format is used and compression defaults to
1153 bzip2.
1153 bzip2.
1154
1154
1155 The bundle file can then be transferred using conventional means
1155 The bundle file can then be transferred using conventional means
1156 and applied to another repository with the unbundle or pull
1156 and applied to another repository with the unbundle or pull
1157 command. This is useful when direct push and pull are not
1157 command. This is useful when direct push and pull are not
1158 available or when exporting an entire repository is undesirable.
1158 available or when exporting an entire repository is undesirable.
1159
1159
1160 Applying bundles preserves all changeset contents including
1160 Applying bundles preserves all changeset contents including
1161 permissions, copy/rename information, and revision history.
1161 permissions, copy/rename information, and revision history.
1162
1162
1163 Returns 0 on success, 1 if no changes found.
1163 Returns 0 on success, 1 if no changes found.
1164 """
1164 """
1165 opts = pycompat.byteskwargs(opts)
1165 opts = pycompat.byteskwargs(opts)
1166 revs = None
1166 revs = None
1167 if 'rev' in opts:
1167 if 'rev' in opts:
1168 revstrings = opts['rev']
1168 revstrings = opts['rev']
1169 revs = scmutil.revrange(repo, revstrings)
1169 revs = scmutil.revrange(repo, revstrings)
1170 if revstrings and not revs:
1170 if revstrings and not revs:
1171 raise error.Abort(_('no commits to bundle'))
1171 raise error.Abort(_('no commits to bundle'))
1172
1172
1173 bundletype = opts.get('type', 'bzip2').lower()
1173 bundletype = opts.get('type', 'bzip2').lower()
1174 try:
1174 try:
1175 bcompression, cgversion, params = exchange.parsebundlespec(
1175 bcompression, cgversion, params = exchange.parsebundlespec(
1176 repo, bundletype, strict=False)
1176 repo, bundletype, strict=False)
1177 except error.UnsupportedBundleSpecification as e:
1177 except error.UnsupportedBundleSpecification as e:
1178 raise error.Abort(str(e),
1178 raise error.Abort(str(e),
1179 hint=_("see 'hg help bundlespec' for supported "
1179 hint=_("see 'hg help bundlespec' for supported "
1180 "values for --type"))
1180 "values for --type"))
1181
1181
1182 # Packed bundles are a pseudo bundle format for now.
1182 # Packed bundles are a pseudo bundle format for now.
1183 if cgversion == 's1':
1183 if cgversion == 's1':
1184 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1184 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1185 hint=_("use 'hg debugcreatestreamclonebundle'"))
1185 hint=_("use 'hg debugcreatestreamclonebundle'"))
1186
1186
1187 if opts.get('all'):
1187 if opts.get('all'):
1188 if dest:
1188 if dest:
1189 raise error.Abort(_("--all is incompatible with specifying "
1189 raise error.Abort(_("--all is incompatible with specifying "
1190 "a destination"))
1190 "a destination"))
1191 if opts.get('base'):
1191 if opts.get('base'):
1192 ui.warn(_("ignoring --base because --all was specified\n"))
1192 ui.warn(_("ignoring --base because --all was specified\n"))
1193 base = ['null']
1193 base = ['null']
1194 else:
1194 else:
1195 base = scmutil.revrange(repo, opts.get('base'))
1195 base = scmutil.revrange(repo, opts.get('base'))
1196 if cgversion not in changegroup.supportedoutgoingversions(repo):
1196 if cgversion not in changegroup.supportedoutgoingversions(repo):
1197 raise error.Abort(_("repository does not support bundle version %s") %
1197 raise error.Abort(_("repository does not support bundle version %s") %
1198 cgversion)
1198 cgversion)
1199
1199
1200 if base:
1200 if base:
1201 if dest:
1201 if dest:
1202 raise error.Abort(_("--base is incompatible with specifying "
1202 raise error.Abort(_("--base is incompatible with specifying "
1203 "a destination"))
1203 "a destination"))
1204 common = [repo.lookup(rev) for rev in base]
1204 common = [repo.lookup(rev) for rev in base]
1205 heads = revs and map(repo.lookup, revs) or None
1205 heads = revs and map(repo.lookup, revs) or None
1206 outgoing = discovery.outgoing(repo, common, heads)
1206 outgoing = discovery.outgoing(repo, common, heads)
1207 else:
1207 else:
1208 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1208 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1209 dest, branches = hg.parseurl(dest, opts.get('branch'))
1209 dest, branches = hg.parseurl(dest, opts.get('branch'))
1210 other = hg.peer(repo, opts, dest)
1210 other = hg.peer(repo, opts, dest)
1211 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1211 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1212 heads = revs and map(repo.lookup, revs) or revs
1212 heads = revs and map(repo.lookup, revs) or revs
1213 outgoing = discovery.findcommonoutgoing(repo, other,
1213 outgoing = discovery.findcommonoutgoing(repo, other,
1214 onlyheads=heads,
1214 onlyheads=heads,
1215 force=opts.get('force'),
1215 force=opts.get('force'),
1216 portable=True)
1216 portable=True)
1217
1217
1218 if not outgoing.missing:
1218 if not outgoing.missing:
1219 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1219 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1220 return 1
1220 return 1
1221
1221
1222 if cgversion == '01': #bundle1
1222 if cgversion == '01': #bundle1
1223 if bcompression is None:
1223 if bcompression is None:
1224 bcompression = 'UN'
1224 bcompression = 'UN'
1225 bversion = 'HG10' + bcompression
1225 bversion = 'HG10' + bcompression
1226 bcompression = None
1226 bcompression = None
1227 elif cgversion in ('02', '03'):
1227 elif cgversion in ('02', '03'):
1228 bversion = 'HG20'
1228 bversion = 'HG20'
1229 else:
1229 else:
1230 raise error.ProgrammingError(
1230 raise error.ProgrammingError(
1231 'bundle: unexpected changegroup version %s' % cgversion)
1231 'bundle: unexpected changegroup version %s' % cgversion)
1232
1232
1233 # TODO compression options should be derived from bundlespec parsing.
1233 # TODO compression options should be derived from bundlespec parsing.
1234 # This is a temporary hack to allow adjusting bundle compression
1234 # This is a temporary hack to allow adjusting bundle compression
1235 # level without a) formalizing the bundlespec changes to declare it
1235 # level without a) formalizing the bundlespec changes to declare it
1236 # b) introducing a command flag.
1236 # b) introducing a command flag.
1237 compopts = {}
1237 compopts = {}
1238 complevel = ui.configint('experimental', 'bundlecomplevel')
1238 complevel = ui.configint('experimental', 'bundlecomplevel')
1239 if complevel is not None:
1239 if complevel is not None:
1240 compopts['level'] = complevel
1240 compopts['level'] = complevel
1241
1241
1242
1242
1243 contentopts = {'cg.version': cgversion}
1243 contentopts = {'cg.version': cgversion}
1244 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1244 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1245 contentopts['obsolescence'] = True
1245 contentopts['obsolescence'] = True
1246 if repo.ui.configbool('experimental', 'bundle-phases'):
1246 if repo.ui.configbool('experimental', 'bundle-phases'):
1247 contentopts['phases'] = True
1247 contentopts['phases'] = True
1248 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1248 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1249 contentopts, compression=bcompression,
1249 contentopts, compression=bcompression,
1250 compopts=compopts)
1250 compopts=compopts)
1251
1251
1252 @command('cat',
1252 @command('cat',
1253 [('o', 'output', '',
1253 [('o', 'output', '',
1254 _('print output to file with formatted name'), _('FORMAT')),
1254 _('print output to file with formatted name'), _('FORMAT')),
1255 ('r', 'rev', '', _('print the given revision'), _('REV')),
1255 ('r', 'rev', '', _('print the given revision'), _('REV')),
1256 ('', 'decode', None, _('apply any matching decode filter')),
1256 ('', 'decode', None, _('apply any matching decode filter')),
1257 ] + walkopts + formatteropts,
1257 ] + walkopts + formatteropts,
1258 _('[OPTION]... FILE...'),
1258 _('[OPTION]... FILE...'),
1259 inferrepo=True, cmdtype=readonly)
1259 inferrepo=True, cmdtype=readonly)
1260 def cat(ui, repo, file1, *pats, **opts):
1260 def cat(ui, repo, file1, *pats, **opts):
1261 """output the current or given revision of files
1261 """output the current or given revision of files
1262
1262
1263 Print the specified files as they were at the given revision. If
1263 Print the specified files as they were at the given revision. If
1264 no revision is given, the parent of the working directory is used.
1264 no revision is given, the parent of the working directory is used.
1265
1265
1266 Output may be to a file, in which case the name of the file is
1266 Output may be to a file, in which case the name of the file is
1267 given using a format string. The formatting rules as follows:
1267 given using a format string. The formatting rules as follows:
1268
1268
1269 :``%%``: literal "%" character
1269 :``%%``: literal "%" character
1270 :``%s``: basename of file being printed
1270 :``%s``: basename of file being printed
1271 :``%d``: dirname of file being printed, or '.' if in repository root
1271 :``%d``: dirname of file being printed, or '.' if in repository root
1272 :``%p``: root-relative path name of file being printed
1272 :``%p``: root-relative path name of file being printed
1273 :``%H``: changeset hash (40 hexadecimal digits)
1273 :``%H``: changeset hash (40 hexadecimal digits)
1274 :``%R``: changeset revision number
1274 :``%R``: changeset revision number
1275 :``%h``: short-form changeset hash (12 hexadecimal digits)
1275 :``%h``: short-form changeset hash (12 hexadecimal digits)
1276 :``%r``: zero-padded changeset revision number
1276 :``%r``: zero-padded changeset revision number
1277 :``%b``: basename of the exporting repository
1277 :``%b``: basename of the exporting repository
1278
1278
1279 Returns 0 on success.
1279 Returns 0 on success.
1280 """
1280 """
1281 opts = pycompat.byteskwargs(opts)
1281 opts = pycompat.byteskwargs(opts)
1282 rev = opts.get('rev')
1282 rev = opts.get('rev')
1283 if rev:
1283 if rev:
1284 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1284 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1285 ctx = scmutil.revsingle(repo, rev)
1285 ctx = scmutil.revsingle(repo, rev)
1286 m = scmutil.match(ctx, (file1,) + pats, opts)
1286 m = scmutil.match(ctx, (file1,) + pats, opts)
1287 fntemplate = opts.pop('output', '')
1287 fntemplate = opts.pop('output', '')
1288 if cmdutil.isstdiofilename(fntemplate):
1288 if cmdutil.isstdiofilename(fntemplate):
1289 fntemplate = ''
1289 fntemplate = ''
1290
1290
1291 if fntemplate:
1291 if fntemplate:
1292 fm = formatter.nullformatter(ui, 'cat')
1292 fm = formatter.nullformatter(ui, 'cat')
1293 else:
1293 else:
1294 ui.pager('cat')
1294 ui.pager('cat')
1295 fm = ui.formatter('cat', opts)
1295 fm = ui.formatter('cat', opts)
1296 with fm:
1296 with fm:
1297 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1297 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1298 **pycompat.strkwargs(opts))
1298 **pycompat.strkwargs(opts))
1299
1299
1300 @command('^clone',
1300 @command('^clone',
1301 [('U', 'noupdate', None, _('the clone will include an empty working '
1301 [('U', 'noupdate', None, _('the clone will include an empty working '
1302 'directory (only a repository)')),
1302 'directory (only a repository)')),
1303 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1303 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1304 _('REV')),
1304 _('REV')),
1305 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1305 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1306 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1306 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1307 ('', 'pull', None, _('use pull protocol to copy metadata')),
1307 ('', 'pull', None, _('use pull protocol to copy metadata')),
1308 ('', 'uncompressed', None,
1308 ('', 'uncompressed', None,
1309 _('an alias to --stream (DEPRECATED)')),
1309 _('an alias to --stream (DEPRECATED)')),
1310 ('', 'stream', None,
1310 ('', 'stream', None,
1311 _('clone with minimal data processing')),
1311 _('clone with minimal data processing')),
1312 ] + remoteopts,
1312 ] + remoteopts,
1313 _('[OPTION]... SOURCE [DEST]'),
1313 _('[OPTION]... SOURCE [DEST]'),
1314 norepo=True)
1314 norepo=True)
1315 def clone(ui, source, dest=None, **opts):
1315 def clone(ui, source, dest=None, **opts):
1316 """make a copy of an existing repository
1316 """make a copy of an existing repository
1317
1317
1318 Create a copy of an existing repository in a new directory.
1318 Create a copy of an existing repository in a new directory.
1319
1319
1320 If no destination directory name is specified, it defaults to the
1320 If no destination directory name is specified, it defaults to the
1321 basename of the source.
1321 basename of the source.
1322
1322
1323 The location of the source is added to the new repository's
1323 The location of the source is added to the new repository's
1324 ``.hg/hgrc`` file, as the default to be used for future pulls.
1324 ``.hg/hgrc`` file, as the default to be used for future pulls.
1325
1325
1326 Only local paths and ``ssh://`` URLs are supported as
1326 Only local paths and ``ssh://`` URLs are supported as
1327 destinations. For ``ssh://`` destinations, no working directory or
1327 destinations. For ``ssh://`` destinations, no working directory or
1328 ``.hg/hgrc`` will be created on the remote side.
1328 ``.hg/hgrc`` will be created on the remote side.
1329
1329
1330 If the source repository has a bookmark called '@' set, that
1330 If the source repository has a bookmark called '@' set, that
1331 revision will be checked out in the new repository by default.
1331 revision will be checked out in the new repository by default.
1332
1332
1333 To check out a particular version, use -u/--update, or
1333 To check out a particular version, use -u/--update, or
1334 -U/--noupdate to create a clone with no working directory.
1334 -U/--noupdate to create a clone with no working directory.
1335
1335
1336 To pull only a subset of changesets, specify one or more revisions
1336 To pull only a subset of changesets, specify one or more revisions
1337 identifiers with -r/--rev or branches with -b/--branch. The
1337 identifiers with -r/--rev or branches with -b/--branch. The
1338 resulting clone will contain only the specified changesets and
1338 resulting clone will contain only the specified changesets and
1339 their ancestors. These options (or 'clone src#rev dest') imply
1339 their ancestors. These options (or 'clone src#rev dest') imply
1340 --pull, even for local source repositories.
1340 --pull, even for local source repositories.
1341
1341
1342 In normal clone mode, the remote normalizes repository data into a common
1342 In normal clone mode, the remote normalizes repository data into a common
1343 exchange format and the receiving end translates this data into its local
1343 exchange format and the receiving end translates this data into its local
1344 storage format. --stream activates a different clone mode that essentially
1344 storage format. --stream activates a different clone mode that essentially
1345 copies repository files from the remote with minimal data processing. This
1345 copies repository files from the remote with minimal data processing. This
1346 significantly reduces the CPU cost of a clone both remotely and locally.
1346 significantly reduces the CPU cost of a clone both remotely and locally.
1347 However, it often increases the transferred data size by 30-40%. This can
1347 However, it often increases the transferred data size by 30-40%. This can
1348 result in substantially faster clones where I/O throughput is plentiful,
1348 result in substantially faster clones where I/O throughput is plentiful,
1349 especially for larger repositories. A side-effect of --stream clones is
1349 especially for larger repositories. A side-effect of --stream clones is
1350 that storage settings and requirements on the remote are applied locally:
1350 that storage settings and requirements on the remote are applied locally:
1351 a modern client may inherit legacy or inefficient storage used by the
1351 a modern client may inherit legacy or inefficient storage used by the
1352 remote or a legacy Mercurial client may not be able to clone from a
1352 remote or a legacy Mercurial client may not be able to clone from a
1353 modern Mercurial remote.
1353 modern Mercurial remote.
1354
1354
1355 .. note::
1355 .. note::
1356
1356
1357 Specifying a tag will include the tagged changeset but not the
1357 Specifying a tag will include the tagged changeset but not the
1358 changeset containing the tag.
1358 changeset containing the tag.
1359
1359
1360 .. container:: verbose
1360 .. container:: verbose
1361
1361
1362 For efficiency, hardlinks are used for cloning whenever the
1362 For efficiency, hardlinks are used for cloning whenever the
1363 source and destination are on the same filesystem (note this
1363 source and destination are on the same filesystem (note this
1364 applies only to the repository data, not to the working
1364 applies only to the repository data, not to the working
1365 directory). Some filesystems, such as AFS, implement hardlinking
1365 directory). Some filesystems, such as AFS, implement hardlinking
1366 incorrectly, but do not report errors. In these cases, use the
1366 incorrectly, but do not report errors. In these cases, use the
1367 --pull option to avoid hardlinking.
1367 --pull option to avoid hardlinking.
1368
1368
1369 Mercurial will update the working directory to the first applicable
1369 Mercurial will update the working directory to the first applicable
1370 revision from this list:
1370 revision from this list:
1371
1371
1372 a) null if -U or the source repository has no changesets
1372 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
1373 b) if -u . and the source repository is local, the first parent of
1374 the source repository's working directory
1374 the source repository's working directory
1375 c) the changeset specified with -u (if a branch name, this means the
1375 c) the changeset specified with -u (if a branch name, this means the
1376 latest head of that branch)
1376 latest head of that branch)
1377 d) the changeset specified with -r
1377 d) the changeset specified with -r
1378 e) the tipmost head specified with -b
1378 e) the tipmost head specified with -b
1379 f) the tipmost head specified with the url#branch source syntax
1379 f) the tipmost head specified with the url#branch source syntax
1380 g) the revision marked with the '@' bookmark, if present
1380 g) the revision marked with the '@' bookmark, if present
1381 h) the tipmost head of the default branch
1381 h) the tipmost head of the default branch
1382 i) tip
1382 i) tip
1383
1383
1384 When cloning from servers that support it, Mercurial may fetch
1384 When cloning from servers that support it, Mercurial may fetch
1385 pre-generated data from a server-advertised URL. When this is done,
1385 pre-generated data from a server-advertised URL. When this is done,
1386 hooks operating on incoming changesets and changegroups may fire twice,
1386 hooks operating on incoming changesets and changegroups may fire twice,
1387 once for the bundle fetched from the URL and another for any additional
1387 once for the bundle fetched from the URL and another for any additional
1388 data not fetched from this URL. In addition, if an error occurs, the
1388 data not fetched from this URL. In addition, if an error occurs, the
1389 repository may be rolled back to a partial clone. This behavior may
1389 repository may be rolled back to a partial clone. This behavior may
1390 change in future releases. See :hg:`help -e clonebundles` for more.
1390 change in future releases. See :hg:`help -e clonebundles` for more.
1391
1391
1392 Examples:
1392 Examples:
1393
1393
1394 - clone a remote repository to a new directory named hg/::
1394 - clone a remote repository to a new directory named hg/::
1395
1395
1396 hg clone https://www.mercurial-scm.org/repo/hg/
1396 hg clone https://www.mercurial-scm.org/repo/hg/
1397
1397
1398 - create a lightweight local clone::
1398 - create a lightweight local clone::
1399
1399
1400 hg clone project/ project-feature/
1400 hg clone project/ project-feature/
1401
1401
1402 - clone from an absolute path on an ssh server (note double-slash)::
1402 - clone from an absolute path on an ssh server (note double-slash)::
1403
1403
1404 hg clone ssh://user@server//home/projects/alpha/
1404 hg clone ssh://user@server//home/projects/alpha/
1405
1405
1406 - do a streaming clone while checking out a specified version::
1406 - do a streaming clone while checking out a specified version::
1407
1407
1408 hg clone --stream http://server/repo -u 1.5
1408 hg clone --stream http://server/repo -u 1.5
1409
1409
1410 - create a repository without changesets after a particular revision::
1410 - create a repository without changesets after a particular revision::
1411
1411
1412 hg clone -r 04e544 experimental/ good/
1412 hg clone -r 04e544 experimental/ good/
1413
1413
1414 - clone (and track) a particular named branch::
1414 - clone (and track) a particular named branch::
1415
1415
1416 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1416 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1417
1417
1418 See :hg:`help urls` for details on specifying URLs.
1418 See :hg:`help urls` for details on specifying URLs.
1419
1419
1420 Returns 0 on success.
1420 Returns 0 on success.
1421 """
1421 """
1422 opts = pycompat.byteskwargs(opts)
1422 opts = pycompat.byteskwargs(opts)
1423 if opts.get('noupdate') and opts.get('updaterev'):
1423 if opts.get('noupdate') and opts.get('updaterev'):
1424 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1424 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1425
1425
1426 r = hg.clone(ui, opts, source, dest,
1426 r = hg.clone(ui, opts, source, dest,
1427 pull=opts.get('pull'),
1427 pull=opts.get('pull'),
1428 stream=opts.get('stream') or opts.get('uncompressed'),
1428 stream=opts.get('stream') or opts.get('uncompressed'),
1429 rev=opts.get('rev'),
1429 rev=opts.get('rev'),
1430 update=opts.get('updaterev') or not opts.get('noupdate'),
1430 update=opts.get('updaterev') or not opts.get('noupdate'),
1431 branch=opts.get('branch'),
1431 branch=opts.get('branch'),
1432 shareopts=opts.get('shareopts'))
1432 shareopts=opts.get('shareopts'))
1433
1433
1434 return r is None
1434 return r is None
1435
1435
1436 @command('^commit|ci',
1436 @command('^commit|ci',
1437 [('A', 'addremove', None,
1437 [('A', 'addremove', None,
1438 _('mark new/missing files as added/removed before committing')),
1438 _('mark new/missing files as added/removed before committing')),
1439 ('', 'close-branch', None,
1439 ('', 'close-branch', None,
1440 _('mark a branch head as closed')),
1440 _('mark a branch head as closed')),
1441 ('', 'amend', None, _('amend the parent of the working directory')),
1441 ('', 'amend', None, _('amend the parent of the working directory')),
1442 ('s', 'secret', None, _('use the secret phase for committing')),
1442 ('s', 'secret', None, _('use the secret phase for committing')),
1443 ('e', 'edit', None, _('invoke editor on commit messages')),
1443 ('e', 'edit', None, _('invoke editor on commit messages')),
1444 ('i', 'interactive', None, _('use interactive mode')),
1444 ('i', 'interactive', None, _('use interactive mode')),
1445 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1445 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1446 _('[OPTION]... [FILE]...'),
1446 _('[OPTION]... [FILE]...'),
1447 inferrepo=True)
1447 inferrepo=True)
1448 def commit(ui, repo, *pats, **opts):
1448 def commit(ui, repo, *pats, **opts):
1449 """commit the specified files or all outstanding changes
1449 """commit the specified files or all outstanding changes
1450
1450
1451 Commit changes to the given files into the repository. Unlike a
1451 Commit changes to the given files into the repository. Unlike a
1452 centralized SCM, this operation is a local operation. See
1452 centralized SCM, this operation is a local operation. See
1453 :hg:`push` for a way to actively distribute your changes.
1453 :hg:`push` for a way to actively distribute your changes.
1454
1454
1455 If a list of files is omitted, all changes reported by :hg:`status`
1455 If a list of files is omitted, all changes reported by :hg:`status`
1456 will be committed.
1456 will be committed.
1457
1457
1458 If you are committing the result of a merge, do not provide any
1458 If you are committing the result of a merge, do not provide any
1459 filenames or -I/-X filters.
1459 filenames or -I/-X filters.
1460
1460
1461 If no commit message is specified, Mercurial starts your
1461 If no commit message is specified, Mercurial starts your
1462 configured editor where you can enter a message. In case your
1462 configured editor where you can enter a message. In case your
1463 commit fails, you will find a backup of your message in
1463 commit fails, you will find a backup of your message in
1464 ``.hg/last-message.txt``.
1464 ``.hg/last-message.txt``.
1465
1465
1466 The --close-branch flag can be used to mark the current branch
1466 The --close-branch flag can be used to mark the current branch
1467 head closed. When all heads of a branch are closed, the branch
1467 head closed. When all heads of a branch are closed, the branch
1468 will be considered closed and no longer listed.
1468 will be considered closed and no longer listed.
1469
1469
1470 The --amend flag can be used to amend the parent of the
1470 The --amend flag can be used to amend the parent of the
1471 working directory with a new commit that contains the changes
1471 working directory with a new commit that contains the changes
1472 in the parent in addition to those currently reported by :hg:`status`,
1472 in the parent in addition to those currently reported by :hg:`status`,
1473 if there are any. The old commit is stored in a backup bundle in
1473 if there are any. The old commit is stored in a backup bundle in
1474 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1474 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1475 on how to restore it).
1475 on how to restore it).
1476
1476
1477 Message, user and date are taken from the amended commit unless
1477 Message, user and date are taken from the amended commit unless
1478 specified. When a message isn't specified on the command line,
1478 specified. When a message isn't specified on the command line,
1479 the editor will open with the message of the amended commit.
1479 the editor will open with the message of the amended commit.
1480
1480
1481 It is not possible to amend public changesets (see :hg:`help phases`)
1481 It is not possible to amend public changesets (see :hg:`help phases`)
1482 or changesets that have children.
1482 or changesets that have children.
1483
1483
1484 See :hg:`help dates` for a list of formats valid for -d/--date.
1484 See :hg:`help dates` for a list of formats valid for -d/--date.
1485
1485
1486 Returns 0 on success, 1 if nothing changed.
1486 Returns 0 on success, 1 if nothing changed.
1487
1487
1488 .. container:: verbose
1488 .. container:: verbose
1489
1489
1490 Examples:
1490 Examples:
1491
1491
1492 - commit all files ending in .py::
1492 - commit all files ending in .py::
1493
1493
1494 hg commit --include "set:**.py"
1494 hg commit --include "set:**.py"
1495
1495
1496 - commit all non-binary files::
1496 - commit all non-binary files::
1497
1497
1498 hg commit --exclude "set:binary()"
1498 hg commit --exclude "set:binary()"
1499
1499
1500 - amend the current commit and set the date to now::
1500 - amend the current commit and set the date to now::
1501
1501
1502 hg commit --amend --date now
1502 hg commit --amend --date now
1503 """
1503 """
1504 wlock = lock = None
1504 wlock = lock = None
1505 try:
1505 try:
1506 wlock = repo.wlock()
1506 wlock = repo.wlock()
1507 lock = repo.lock()
1507 lock = repo.lock()
1508 return _docommit(ui, repo, *pats, **opts)
1508 return _docommit(ui, repo, *pats, **opts)
1509 finally:
1509 finally:
1510 release(lock, wlock)
1510 release(lock, wlock)
1511
1511
1512 def _docommit(ui, repo, *pats, **opts):
1512 def _docommit(ui, repo, *pats, **opts):
1513 if opts.get(r'interactive'):
1513 if opts.get(r'interactive'):
1514 opts.pop(r'interactive')
1514 opts.pop(r'interactive')
1515 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1515 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1516 cmdutil.recordfilter, *pats,
1516 cmdutil.recordfilter, *pats,
1517 **opts)
1517 **opts)
1518 # ret can be 0 (no changes to record) or the value returned by
1518 # ret can be 0 (no changes to record) or the value returned by
1519 # commit(), 1 if nothing changed or None on success.
1519 # commit(), 1 if nothing changed or None on success.
1520 return 1 if ret == 0 else ret
1520 return 1 if ret == 0 else ret
1521
1521
1522 opts = pycompat.byteskwargs(opts)
1522 opts = pycompat.byteskwargs(opts)
1523 if opts.get('subrepos'):
1523 if opts.get('subrepos'):
1524 if opts.get('amend'):
1524 if opts.get('amend'):
1525 raise error.Abort(_('cannot amend with --subrepos'))
1525 raise error.Abort(_('cannot amend with --subrepos'))
1526 # Let --subrepos on the command line override config setting.
1526 # Let --subrepos on the command line override config setting.
1527 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1527 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1528
1528
1529 cmdutil.checkunfinished(repo, commit=True)
1529 cmdutil.checkunfinished(repo, commit=True)
1530
1530
1531 branch = repo[None].branch()
1531 branch = repo[None].branch()
1532 bheads = repo.branchheads(branch)
1532 bheads = repo.branchheads(branch)
1533
1533
1534 extra = {}
1534 extra = {}
1535 if opts.get('close_branch'):
1535 if opts.get('close_branch'):
1536 extra['close'] = 1
1536 extra['close'] = 1
1537
1537
1538 if not bheads:
1538 if not bheads:
1539 raise error.Abort(_('can only close branch heads'))
1539 raise error.Abort(_('can only close branch heads'))
1540 elif opts.get('amend'):
1540 elif opts.get('amend'):
1541 if repo[None].parents()[0].p1().branch() != branch and \
1541 if repo[None].parents()[0].p1().branch() != branch and \
1542 repo[None].parents()[0].p2().branch() != branch:
1542 repo[None].parents()[0].p2().branch() != branch:
1543 raise error.Abort(_('can only close branch heads'))
1543 raise error.Abort(_('can only close branch heads'))
1544
1544
1545 if opts.get('amend'):
1545 if opts.get('amend'):
1546 if ui.configbool('ui', 'commitsubrepos'):
1546 if ui.configbool('ui', 'commitsubrepos'):
1547 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1547 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1548
1548
1549 old = repo['.']
1549 old = repo['.']
1550 rewriteutil.precheck(repo, [old.rev()], 'amend')
1550 rewriteutil.precheck(repo, [old.rev()], 'amend')
1551
1551
1552 # Currently histedit gets confused if an amend happens while histedit
1552 # Currently histedit gets confused if an amend happens while histedit
1553 # is in progress. Since we have a checkunfinished command, we are
1553 # is in progress. Since we have a checkunfinished command, we are
1554 # temporarily honoring it.
1554 # temporarily honoring it.
1555 #
1555 #
1556 # Note: eventually this guard will be removed. Please do not expect
1556 # Note: eventually this guard will be removed. Please do not expect
1557 # this behavior to remain.
1557 # this behavior to remain.
1558 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1558 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1559 cmdutil.checkunfinished(repo)
1559 cmdutil.checkunfinished(repo)
1560
1560
1561 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1561 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1562 if node == old.node():
1562 if node == old.node():
1563 ui.status(_("nothing changed\n"))
1563 ui.status(_("nothing changed\n"))
1564 return 1
1564 return 1
1565 else:
1565 else:
1566 def commitfunc(ui, repo, message, match, opts):
1566 def commitfunc(ui, repo, message, match, opts):
1567 overrides = {}
1567 overrides = {}
1568 if opts.get('secret'):
1568 if opts.get('secret'):
1569 overrides[('phases', 'new-commit')] = 'secret'
1569 overrides[('phases', 'new-commit')] = 'secret'
1570
1570
1571 baseui = repo.baseui
1571 baseui = repo.baseui
1572 with baseui.configoverride(overrides, 'commit'):
1572 with baseui.configoverride(overrides, 'commit'):
1573 with ui.configoverride(overrides, 'commit'):
1573 with ui.configoverride(overrides, 'commit'):
1574 editform = cmdutil.mergeeditform(repo[None],
1574 editform = cmdutil.mergeeditform(repo[None],
1575 'commit.normal')
1575 'commit.normal')
1576 editor = cmdutil.getcommiteditor(
1576 editor = cmdutil.getcommiteditor(
1577 editform=editform, **pycompat.strkwargs(opts))
1577 editform=editform, **pycompat.strkwargs(opts))
1578 return repo.commit(message,
1578 return repo.commit(message,
1579 opts.get('user'),
1579 opts.get('user'),
1580 opts.get('date'),
1580 opts.get('date'),
1581 match,
1581 match,
1582 editor=editor,
1582 editor=editor,
1583 extra=extra)
1583 extra=extra)
1584
1584
1585 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1585 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1586
1586
1587 if not node:
1587 if not node:
1588 stat = cmdutil.postcommitstatus(repo, pats, opts)
1588 stat = cmdutil.postcommitstatus(repo, pats, opts)
1589 if stat[3]:
1589 if stat[3]:
1590 ui.status(_("nothing changed (%d missing files, see "
1590 ui.status(_("nothing changed (%d missing files, see "
1591 "'hg status')\n") % len(stat[3]))
1591 "'hg status')\n") % len(stat[3]))
1592 else:
1592 else:
1593 ui.status(_("nothing changed\n"))
1593 ui.status(_("nothing changed\n"))
1594 return 1
1594 return 1
1595
1595
1596 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1596 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1597
1597
1598 @command('config|showconfig|debugconfig',
1598 @command('config|showconfig|debugconfig',
1599 [('u', 'untrusted', None, _('show untrusted configuration options')),
1599 [('u', 'untrusted', None, _('show untrusted configuration options')),
1600 ('e', 'edit', None, _('edit user config')),
1600 ('e', 'edit', None, _('edit user config')),
1601 ('l', 'local', None, _('edit repository config')),
1601 ('l', 'local', None, _('edit repository config')),
1602 ('g', 'global', None, _('edit global config'))] + formatteropts,
1602 ('g', 'global', None, _('edit global config'))] + formatteropts,
1603 _('[-u] [NAME]...'),
1603 _('[-u] [NAME]...'),
1604 optionalrepo=True, cmdtype=readonly)
1604 optionalrepo=True, cmdtype=readonly)
1605 def config(ui, repo, *values, **opts):
1605 def config(ui, repo, *values, **opts):
1606 """show combined config settings from all hgrc files
1606 """show combined config settings from all hgrc files
1607
1607
1608 With no arguments, print names and values of all config items.
1608 With no arguments, print names and values of all config items.
1609
1609
1610 With one argument of the form section.name, print just the value
1610 With one argument of the form section.name, print just the value
1611 of that config item.
1611 of that config item.
1612
1612
1613 With multiple arguments, print names and values of all config
1613 With multiple arguments, print names and values of all config
1614 items with matching section names.
1614 items with matching section names.
1615
1615
1616 With --edit, start an editor on the user-level config file. With
1616 With --edit, start an editor on the user-level config file. With
1617 --global, edit the system-wide config file. With --local, edit the
1617 --global, edit the system-wide config file. With --local, edit the
1618 repository-level config file.
1618 repository-level config file.
1619
1619
1620 With --debug, the source (filename and line number) is printed
1620 With --debug, the source (filename and line number) is printed
1621 for each config item.
1621 for each config item.
1622
1622
1623 See :hg:`help config` for more information about config files.
1623 See :hg:`help config` for more information about config files.
1624
1624
1625 Returns 0 on success, 1 if NAME does not exist.
1625 Returns 0 on success, 1 if NAME does not exist.
1626
1626
1627 """
1627 """
1628
1628
1629 opts = pycompat.byteskwargs(opts)
1629 opts = pycompat.byteskwargs(opts)
1630 if opts.get('edit') or opts.get('local') or opts.get('global'):
1630 if opts.get('edit') or opts.get('local') or opts.get('global'):
1631 if opts.get('local') and opts.get('global'):
1631 if opts.get('local') and opts.get('global'):
1632 raise error.Abort(_("can't use --local and --global together"))
1632 raise error.Abort(_("can't use --local and --global together"))
1633
1633
1634 if opts.get('local'):
1634 if opts.get('local'):
1635 if not repo:
1635 if not repo:
1636 raise error.Abort(_("can't use --local outside a repository"))
1636 raise error.Abort(_("can't use --local outside a repository"))
1637 paths = [repo.vfs.join('hgrc')]
1637 paths = [repo.vfs.join('hgrc')]
1638 elif opts.get('global'):
1638 elif opts.get('global'):
1639 paths = rcutil.systemrcpath()
1639 paths = rcutil.systemrcpath()
1640 else:
1640 else:
1641 paths = rcutil.userrcpath()
1641 paths = rcutil.userrcpath()
1642
1642
1643 for f in paths:
1643 for f in paths:
1644 if os.path.exists(f):
1644 if os.path.exists(f):
1645 break
1645 break
1646 else:
1646 else:
1647 if opts.get('global'):
1647 if opts.get('global'):
1648 samplehgrc = uimod.samplehgrcs['global']
1648 samplehgrc = uimod.samplehgrcs['global']
1649 elif opts.get('local'):
1649 elif opts.get('local'):
1650 samplehgrc = uimod.samplehgrcs['local']
1650 samplehgrc = uimod.samplehgrcs['local']
1651 else:
1651 else:
1652 samplehgrc = uimod.samplehgrcs['user']
1652 samplehgrc = uimod.samplehgrcs['user']
1653
1653
1654 f = paths[0]
1654 f = paths[0]
1655 fp = open(f, "wb")
1655 fp = open(f, "wb")
1656 fp.write(util.tonativeeol(samplehgrc))
1656 fp.write(util.tonativeeol(samplehgrc))
1657 fp.close()
1657 fp.close()
1658
1658
1659 editor = ui.geteditor()
1659 editor = ui.geteditor()
1660 ui.system("%s \"%s\"" % (editor, f),
1660 ui.system("%s \"%s\"" % (editor, f),
1661 onerr=error.Abort, errprefix=_("edit failed"),
1661 onerr=error.Abort, errprefix=_("edit failed"),
1662 blockedtag='config_edit')
1662 blockedtag='config_edit')
1663 return
1663 return
1664 ui.pager('config')
1664 ui.pager('config')
1665 fm = ui.formatter('config', opts)
1665 fm = ui.formatter('config', opts)
1666 for t, f in rcutil.rccomponents():
1666 for t, f in rcutil.rccomponents():
1667 if t == 'path':
1667 if t == 'path':
1668 ui.debug('read config from: %s\n' % f)
1668 ui.debug('read config from: %s\n' % f)
1669 elif t == 'items':
1669 elif t == 'items':
1670 for section, name, value, source in f:
1670 for section, name, value, source in f:
1671 ui.debug('set config by: %s\n' % source)
1671 ui.debug('set config by: %s\n' % source)
1672 else:
1672 else:
1673 raise error.ProgrammingError('unknown rctype: %s' % t)
1673 raise error.ProgrammingError('unknown rctype: %s' % t)
1674 untrusted = bool(opts.get('untrusted'))
1674 untrusted = bool(opts.get('untrusted'))
1675 if values:
1675 if values:
1676 sections = [v for v in values if '.' not in v]
1676 sections = [v for v in values if '.' not in v]
1677 items = [v for v in values if '.' in v]
1677 items = [v for v in values if '.' in v]
1678 if len(items) > 1 or items and sections:
1678 if len(items) > 1 or items and sections:
1679 raise error.Abort(_('only one config item permitted'))
1679 raise error.Abort(_('only one config item permitted'))
1680 matched = False
1680 matched = False
1681 for section, name, value in ui.walkconfig(untrusted=untrusted):
1681 for section, name, value in ui.walkconfig(untrusted=untrusted):
1682 source = ui.configsource(section, name, untrusted)
1682 source = ui.configsource(section, name, untrusted)
1683 value = pycompat.bytestr(value)
1683 value = pycompat.bytestr(value)
1684 if fm.isplain():
1684 if fm.isplain():
1685 source = source or 'none'
1685 source = source or 'none'
1686 value = value.replace('\n', '\\n')
1686 value = value.replace('\n', '\\n')
1687 entryname = section + '.' + name
1687 entryname = section + '.' + name
1688 if values:
1688 if values:
1689 for v in values:
1689 for v in values:
1690 if v == section:
1690 if v == section:
1691 fm.startitem()
1691 fm.startitem()
1692 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1692 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1693 fm.write('name value', '%s=%s\n', entryname, value)
1693 fm.write('name value', '%s=%s\n', entryname, value)
1694 matched = True
1694 matched = True
1695 elif v == entryname:
1695 elif v == entryname:
1696 fm.startitem()
1696 fm.startitem()
1697 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1697 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1698 fm.write('value', '%s\n', value)
1698 fm.write('value', '%s\n', value)
1699 fm.data(name=entryname)
1699 fm.data(name=entryname)
1700 matched = True
1700 matched = True
1701 else:
1701 else:
1702 fm.startitem()
1702 fm.startitem()
1703 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1703 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1704 fm.write('name value', '%s=%s\n', entryname, value)
1704 fm.write('name value', '%s=%s\n', entryname, value)
1705 matched = True
1705 matched = True
1706 fm.end()
1706 fm.end()
1707 if matched:
1707 if matched:
1708 return 0
1708 return 0
1709 return 1
1709 return 1
1710
1710
1711 @command('copy|cp',
1711 @command('copy|cp',
1712 [('A', 'after', None, _('record a copy that has already occurred')),
1712 [('A', 'after', None, _('record a copy that has already occurred')),
1713 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1713 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1714 ] + walkopts + dryrunopts,
1714 ] + walkopts + dryrunopts,
1715 _('[OPTION]... [SOURCE]... DEST'))
1715 _('[OPTION]... [SOURCE]... DEST'))
1716 def copy(ui, repo, *pats, **opts):
1716 def copy(ui, repo, *pats, **opts):
1717 """mark files as copied for the next commit
1717 """mark files as copied for the next commit
1718
1718
1719 Mark dest as having copies of source files. If dest is a
1719 Mark dest as having copies of source files. If dest is a
1720 directory, copies are put in that directory. If dest is a file,
1720 directory, copies are put in that directory. If dest is a file,
1721 the source must be a single file.
1721 the source must be a single file.
1722
1722
1723 By default, this command copies the contents of files as they
1723 By default, this command copies the contents of files as they
1724 exist in the working directory. If invoked with -A/--after, the
1724 exist in the working directory. If invoked with -A/--after, the
1725 operation is recorded, but no copying is performed.
1725 operation is recorded, but no copying is performed.
1726
1726
1727 This command takes effect with the next commit. To undo a copy
1727 This command takes effect with the next commit. To undo a copy
1728 before that, see :hg:`revert`.
1728 before that, see :hg:`revert`.
1729
1729
1730 Returns 0 on success, 1 if errors are encountered.
1730 Returns 0 on success, 1 if errors are encountered.
1731 """
1731 """
1732 opts = pycompat.byteskwargs(opts)
1732 opts = pycompat.byteskwargs(opts)
1733 with repo.wlock(False):
1733 with repo.wlock(False):
1734 return cmdutil.copy(ui, repo, pats, opts)
1734 return cmdutil.copy(ui, repo, pats, opts)
1735
1735
1736 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1736 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1737 def debugcommands(ui, cmd='', *args):
1737 def debugcommands(ui, cmd='', *args):
1738 """list all available commands and options"""
1738 """list all available commands and options"""
1739 for cmd, vals in sorted(table.iteritems()):
1739 for cmd, vals in sorted(table.iteritems()):
1740 cmd = cmd.split('|')[0].strip('^')
1740 cmd = cmd.split('|')[0].strip('^')
1741 opts = ', '.join([i[1] for i in vals[1]])
1741 opts = ', '.join([i[1] for i in vals[1]])
1742 ui.write('%s: %s\n' % (cmd, opts))
1742 ui.write('%s: %s\n' % (cmd, opts))
1743
1743
1744 @command('debugcomplete',
1744 @command('debugcomplete',
1745 [('o', 'options', None, _('show the command options'))],
1745 [('o', 'options', None, _('show the command options'))],
1746 _('[-o] CMD'),
1746 _('[-o] CMD'),
1747 norepo=True)
1747 norepo=True)
1748 def debugcomplete(ui, cmd='', **opts):
1748 def debugcomplete(ui, cmd='', **opts):
1749 """returns the completion list associated with the given command"""
1749 """returns the completion list associated with the given command"""
1750
1750
1751 if opts.get(r'options'):
1751 if opts.get(r'options'):
1752 options = []
1752 options = []
1753 otables = [globalopts]
1753 otables = [globalopts]
1754 if cmd:
1754 if cmd:
1755 aliases, entry = cmdutil.findcmd(cmd, table, False)
1755 aliases, entry = cmdutil.findcmd(cmd, table, False)
1756 otables.append(entry[1])
1756 otables.append(entry[1])
1757 for t in otables:
1757 for t in otables:
1758 for o in t:
1758 for o in t:
1759 if "(DEPRECATED)" in o[3]:
1759 if "(DEPRECATED)" in o[3]:
1760 continue
1760 continue
1761 if o[0]:
1761 if o[0]:
1762 options.append('-%s' % o[0])
1762 options.append('-%s' % o[0])
1763 options.append('--%s' % o[1])
1763 options.append('--%s' % o[1])
1764 ui.write("%s\n" % "\n".join(options))
1764 ui.write("%s\n" % "\n".join(options))
1765 return
1765 return
1766
1766
1767 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1767 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1768 if ui.verbose:
1768 if ui.verbose:
1769 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1769 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1770 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1770 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1771
1771
1772 @command('^diff',
1772 @command('^diff',
1773 [('r', 'rev', [], _('revision'), _('REV')),
1773 [('r', 'rev', [], _('revision'), _('REV')),
1774 ('c', 'change', '', _('change made by revision'), _('REV'))
1774 ('c', 'change', '', _('change made by revision'), _('REV'))
1775 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1775 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1776 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1776 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1777 inferrepo=True, cmdtype=readonly)
1777 inferrepo=True, cmdtype=readonly)
1778 def diff(ui, repo, *pats, **opts):
1778 def diff(ui, repo, *pats, **opts):
1779 """diff repository (or selected files)
1779 """diff repository (or selected files)
1780
1780
1781 Show differences between revisions for the specified files.
1781 Show differences between revisions for the specified files.
1782
1782
1783 Differences between files are shown using the unified diff format.
1783 Differences between files are shown using the unified diff format.
1784
1784
1785 .. note::
1785 .. note::
1786
1786
1787 :hg:`diff` may generate unexpected results for merges, as it will
1787 :hg:`diff` may generate unexpected results for merges, as it will
1788 default to comparing against the working directory's first
1788 default to comparing against the working directory's first
1789 parent changeset if no revisions are specified.
1789 parent changeset if no revisions are specified.
1790
1790
1791 When two revision arguments are given, then changes are shown
1791 When two revision arguments are given, then changes are shown
1792 between those revisions. If only one revision is specified then
1792 between those revisions. If only one revision is specified then
1793 that revision is compared to the working directory, and, when no
1793 that revision is compared to the working directory, and, when no
1794 revisions are specified, the working directory files are compared
1794 revisions are specified, the working directory files are compared
1795 to its first parent.
1795 to its first parent.
1796
1796
1797 Alternatively you can specify -c/--change with a revision to see
1797 Alternatively you can specify -c/--change with a revision to see
1798 the changes in that changeset relative to its first parent.
1798 the changes in that changeset relative to its first parent.
1799
1799
1800 Without the -a/--text option, diff will avoid generating diffs of
1800 Without the -a/--text option, diff will avoid generating diffs of
1801 files it detects as binary. With -a, diff will generate a diff
1801 files it detects as binary. With -a, diff will generate a diff
1802 anyway, probably with undesirable results.
1802 anyway, probably with undesirable results.
1803
1803
1804 Use the -g/--git option to generate diffs in the git extended diff
1804 Use the -g/--git option to generate diffs in the git extended diff
1805 format. For more information, read :hg:`help diffs`.
1805 format. For more information, read :hg:`help diffs`.
1806
1806
1807 .. container:: verbose
1807 .. container:: verbose
1808
1808
1809 Examples:
1809 Examples:
1810
1810
1811 - compare a file in the current working directory to its parent::
1811 - compare a file in the current working directory to its parent::
1812
1812
1813 hg diff foo.c
1813 hg diff foo.c
1814
1814
1815 - compare two historical versions of a directory, with rename info::
1815 - compare two historical versions of a directory, with rename info::
1816
1816
1817 hg diff --git -r 1.0:1.2 lib/
1817 hg diff --git -r 1.0:1.2 lib/
1818
1818
1819 - get change stats relative to the last change on some date::
1819 - get change stats relative to the last change on some date::
1820
1820
1821 hg diff --stat -r "date('may 2')"
1821 hg diff --stat -r "date('may 2')"
1822
1822
1823 - diff all newly-added files that contain a keyword::
1823 - diff all newly-added files that contain a keyword::
1824
1824
1825 hg diff "set:added() and grep(GNU)"
1825 hg diff "set:added() and grep(GNU)"
1826
1826
1827 - compare a revision and its parents::
1827 - compare a revision and its parents::
1828
1828
1829 hg diff -c 9353 # compare against first parent
1829 hg diff -c 9353 # compare against first parent
1830 hg diff -r 9353^:9353 # same using revset syntax
1830 hg diff -r 9353^:9353 # same using revset syntax
1831 hg diff -r 9353^2:9353 # compare against the second parent
1831 hg diff -r 9353^2:9353 # compare against the second parent
1832
1832
1833 Returns 0 on success.
1833 Returns 0 on success.
1834 """
1834 """
1835
1835
1836 opts = pycompat.byteskwargs(opts)
1836 opts = pycompat.byteskwargs(opts)
1837 revs = opts.get('rev')
1837 revs = opts.get('rev')
1838 change = opts.get('change')
1838 change = opts.get('change')
1839 stat = opts.get('stat')
1839 stat = opts.get('stat')
1840 reverse = opts.get('reverse')
1840 reverse = opts.get('reverse')
1841
1841
1842 if revs and change:
1842 if revs and change:
1843 msg = _('cannot specify --rev and --change at the same time')
1843 msg = _('cannot specify --rev and --change at the same time')
1844 raise error.Abort(msg)
1844 raise error.Abort(msg)
1845 elif change:
1845 elif change:
1846 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1846 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1847 node2 = scmutil.revsingle(repo, change, None).node()
1847 node2 = scmutil.revsingle(repo, change, None).node()
1848 node1 = repo[node2].p1().node()
1848 node1 = repo[node2].p1().node()
1849 else:
1849 else:
1850 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1850 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1851 node1, node2 = scmutil.revpair(repo, revs)
1851 node1, node2 = scmutil.revpair(repo, revs)
1852
1852
1853 if reverse:
1853 if reverse:
1854 node1, node2 = node2, node1
1854 node1, node2 = node2, node1
1855
1855
1856 diffopts = patch.diffallopts(ui, opts)
1856 diffopts = patch.diffallopts(ui, opts)
1857 m = scmutil.match(repo[node2], pats, opts)
1857 m = scmutil.match(repo[node2], pats, opts)
1858 ui.pager('diff')
1858 ui.pager('diff')
1859 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1859 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1860 listsubrepos=opts.get('subrepos'),
1860 listsubrepos=opts.get('subrepos'),
1861 root=opts.get('root'))
1861 root=opts.get('root'))
1862
1862
1863 @command('^export',
1863 @command('^export',
1864 [('o', 'output', '',
1864 [('o', 'output', '',
1865 _('print output to file with formatted name'), _('FORMAT')),
1865 _('print output to file with formatted name'), _('FORMAT')),
1866 ('', 'switch-parent', None, _('diff against the second parent')),
1866 ('', 'switch-parent', None, _('diff against the second parent')),
1867 ('r', 'rev', [], _('revisions to export'), _('REV')),
1867 ('r', 'rev', [], _('revisions to export'), _('REV')),
1868 ] + diffopts,
1868 ] + diffopts,
1869 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'), cmdtype=readonly)
1869 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'), cmdtype=readonly)
1870 def export(ui, repo, *changesets, **opts):
1870 def export(ui, repo, *changesets, **opts):
1871 """dump the header and diffs for one or more changesets
1871 """dump the header and diffs for one or more changesets
1872
1872
1873 Print the changeset header and diffs for one or more revisions.
1873 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.
1874 If no revision is given, the parent of the working directory is used.
1875
1875
1876 The information shown in the changeset header is: author, date,
1876 The information shown in the changeset header is: author, date,
1877 branch name (if non-default), changeset hash, parent(s) and commit
1877 branch name (if non-default), changeset hash, parent(s) and commit
1878 comment.
1878 comment.
1879
1879
1880 .. note::
1880 .. note::
1881
1881
1882 :hg:`export` may generate unexpected diff output for merge
1882 :hg:`export` may generate unexpected diff output for merge
1883 changesets, as it will compare the merge changeset against its
1883 changesets, as it will compare the merge changeset against its
1884 first parent only.
1884 first parent only.
1885
1885
1886 Output may be to a file, in which case the name of the file is
1886 Output may be to a file, in which case the name of the file is
1887 given using a format string. The formatting rules are as follows:
1887 given using a format string. The formatting rules are as follows:
1888
1888
1889 :``%%``: literal "%" character
1889 :``%%``: literal "%" character
1890 :``%H``: changeset hash (40 hexadecimal digits)
1890 :``%H``: changeset hash (40 hexadecimal digits)
1891 :``%N``: number of patches being generated
1891 :``%N``: number of patches being generated
1892 :``%R``: changeset revision number
1892 :``%R``: changeset revision number
1893 :``%b``: basename of the exporting repository
1893 :``%b``: basename of the exporting repository
1894 :``%h``: short-form changeset hash (12 hexadecimal digits)
1894 :``%h``: short-form changeset hash (12 hexadecimal digits)
1895 :``%m``: first line of the commit message (only alphanumeric characters)
1895 :``%m``: first line of the commit message (only alphanumeric characters)
1896 :``%n``: zero-padded sequence number, starting at 1
1896 :``%n``: zero-padded sequence number, starting at 1
1897 :``%r``: zero-padded changeset revision number
1897 :``%r``: zero-padded changeset revision number
1898
1898
1899 Without the -a/--text option, export will avoid generating diffs
1899 Without the -a/--text option, export will avoid generating diffs
1900 of files it detects as binary. With -a, export will generate a
1900 of files it detects as binary. With -a, export will generate a
1901 diff anyway, probably with undesirable results.
1901 diff anyway, probably with undesirable results.
1902
1902
1903 Use the -g/--git option to generate diffs in the git extended diff
1903 Use the -g/--git option to generate diffs in the git extended diff
1904 format. See :hg:`help diffs` for more information.
1904 format. See :hg:`help diffs` for more information.
1905
1905
1906 With the --switch-parent option, the diff will be against the
1906 With the --switch-parent option, the diff will be against the
1907 second parent. It can be useful to review a merge.
1907 second parent. It can be useful to review a merge.
1908
1908
1909 .. container:: verbose
1909 .. container:: verbose
1910
1910
1911 Examples:
1911 Examples:
1912
1912
1913 - use export and import to transplant a bugfix to the current
1913 - use export and import to transplant a bugfix to the current
1914 branch::
1914 branch::
1915
1915
1916 hg export -r 9353 | hg import -
1916 hg export -r 9353 | hg import -
1917
1917
1918 - export all the changesets between two revisions to a file with
1918 - export all the changesets between two revisions to a file with
1919 rename information::
1919 rename information::
1920
1920
1921 hg export --git -r 123:150 > changes.txt
1921 hg export --git -r 123:150 > changes.txt
1922
1922
1923 - split outgoing changes into a series of patches with
1923 - split outgoing changes into a series of patches with
1924 descriptive names::
1924 descriptive names::
1925
1925
1926 hg export -r "outgoing()" -o "%n-%m.patch"
1926 hg export -r "outgoing()" -o "%n-%m.patch"
1927
1927
1928 Returns 0 on success.
1928 Returns 0 on success.
1929 """
1929 """
1930 opts = pycompat.byteskwargs(opts)
1930 opts = pycompat.byteskwargs(opts)
1931 changesets += tuple(opts.get('rev', []))
1931 changesets += tuple(opts.get('rev', []))
1932 if not changesets:
1932 if not changesets:
1933 changesets = ['.']
1933 changesets = ['.']
1934 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
1934 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
1935 revs = scmutil.revrange(repo, changesets)
1935 revs = scmutil.revrange(repo, changesets)
1936 if not revs:
1936 if not revs:
1937 raise error.Abort(_("export requires at least one changeset"))
1937 raise error.Abort(_("export requires at least one changeset"))
1938 if len(revs) > 1:
1938 if len(revs) > 1:
1939 ui.note(_('exporting patches:\n'))
1939 ui.note(_('exporting patches:\n'))
1940 else:
1940 else:
1941 ui.note(_('exporting patch:\n'))
1941 ui.note(_('exporting patch:\n'))
1942 ui.pager('export')
1942 ui.pager('export')
1943 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
1943 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
1944 switch_parent=opts.get('switch_parent'),
1944 switch_parent=opts.get('switch_parent'),
1945 opts=patch.diffallopts(ui, opts))
1945 opts=patch.diffallopts(ui, opts))
1946
1946
1947 @command('files',
1947 @command('files',
1948 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1948 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1949 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1949 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1950 ] + walkopts + formatteropts + subrepoopts,
1950 ] + walkopts + formatteropts + subrepoopts,
1951 _('[OPTION]... [FILE]...'), cmdtype=readonly)
1951 _('[OPTION]... [FILE]...'), cmdtype=readonly)
1952 def files(ui, repo, *pats, **opts):
1952 def files(ui, repo, *pats, **opts):
1953 """list tracked files
1953 """list tracked files
1954
1954
1955 Print files under Mercurial control in the working directory or
1955 Print files under Mercurial control in the working directory or
1956 specified revision for given files (excluding removed files).
1956 specified revision for given files (excluding removed files).
1957 Files can be specified as filenames or filesets.
1957 Files can be specified as filenames or filesets.
1958
1958
1959 If no files are given to match, this command prints the names
1959 If no files are given to match, this command prints the names
1960 of all files under Mercurial control.
1960 of all files under Mercurial control.
1961
1961
1962 .. container:: verbose
1962 .. container:: verbose
1963
1963
1964 Examples:
1964 Examples:
1965
1965
1966 - list all files under the current directory::
1966 - list all files under the current directory::
1967
1967
1968 hg files .
1968 hg files .
1969
1969
1970 - shows sizes and flags for current revision::
1970 - shows sizes and flags for current revision::
1971
1971
1972 hg files -vr .
1972 hg files -vr .
1973
1973
1974 - list all files named README::
1974 - list all files named README::
1975
1975
1976 hg files -I "**/README"
1976 hg files -I "**/README"
1977
1977
1978 - list all binary files::
1978 - list all binary files::
1979
1979
1980 hg files "set:binary()"
1980 hg files "set:binary()"
1981
1981
1982 - find files containing a regular expression::
1982 - find files containing a regular expression::
1983
1983
1984 hg files "set:grep('bob')"
1984 hg files "set:grep('bob')"
1985
1985
1986 - search tracked file contents with xargs and grep::
1986 - search tracked file contents with xargs and grep::
1987
1987
1988 hg files -0 | xargs -0 grep foo
1988 hg files -0 | xargs -0 grep foo
1989
1989
1990 See :hg:`help patterns` and :hg:`help filesets` for more information
1990 See :hg:`help patterns` and :hg:`help filesets` for more information
1991 on specifying file patterns.
1991 on specifying file patterns.
1992
1992
1993 Returns 0 if a match is found, 1 otherwise.
1993 Returns 0 if a match is found, 1 otherwise.
1994
1994
1995 """
1995 """
1996
1996
1997 opts = pycompat.byteskwargs(opts)
1997 opts = pycompat.byteskwargs(opts)
1998 rev = opts.get('rev')
1998 rev = opts.get('rev')
1999 if rev:
1999 if rev:
2000 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2000 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2001 ctx = scmutil.revsingle(repo, rev, None)
2001 ctx = scmutil.revsingle(repo, rev, None)
2002
2002
2003 end = '\n'
2003 end = '\n'
2004 if opts.get('print0'):
2004 if opts.get('print0'):
2005 end = '\0'
2005 end = '\0'
2006 fmt = '%s' + end
2006 fmt = '%s' + end
2007
2007
2008 m = scmutil.match(ctx, pats, opts)
2008 m = scmutil.match(ctx, pats, opts)
2009 ui.pager('files')
2009 ui.pager('files')
2010 with ui.formatter('files', opts) as fm:
2010 with ui.formatter('files', opts) as fm:
2011 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2011 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2012
2012
2013 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2013 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2014 def forget(ui, repo, *pats, **opts):
2014 def forget(ui, repo, *pats, **opts):
2015 """forget the specified files on the next commit
2015 """forget the specified files on the next commit
2016
2016
2017 Mark the specified files so they will no longer be tracked
2017 Mark the specified files so they will no longer be tracked
2018 after the next commit.
2018 after the next commit.
2019
2019
2020 This only removes files from the current branch, not from the
2020 This only removes files from the current branch, not from the
2021 entire project history, and it does not delete them from the
2021 entire project history, and it does not delete them from the
2022 working directory.
2022 working directory.
2023
2023
2024 To delete the file from the working directory, see :hg:`remove`.
2024 To delete the file from the working directory, see :hg:`remove`.
2025
2025
2026 To undo a forget before the next commit, see :hg:`add`.
2026 To undo a forget before the next commit, see :hg:`add`.
2027
2027
2028 .. container:: verbose
2028 .. container:: verbose
2029
2029
2030 Examples:
2030 Examples:
2031
2031
2032 - forget newly-added binary files::
2032 - forget newly-added binary files::
2033
2033
2034 hg forget "set:added() and binary()"
2034 hg forget "set:added() and binary()"
2035
2035
2036 - forget files that would be excluded by .hgignore::
2036 - forget files that would be excluded by .hgignore::
2037
2037
2038 hg forget "set:hgignore()"
2038 hg forget "set:hgignore()"
2039
2039
2040 Returns 0 on success.
2040 Returns 0 on success.
2041 """
2041 """
2042
2042
2043 opts = pycompat.byteskwargs(opts)
2043 opts = pycompat.byteskwargs(opts)
2044 if not pats:
2044 if not pats:
2045 raise error.Abort(_('no files specified'))
2045 raise error.Abort(_('no files specified'))
2046
2046
2047 m = scmutil.match(repo[None], pats, opts)
2047 m = scmutil.match(repo[None], pats, opts)
2048 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2048 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2049 return rejected and 1 or 0
2049 return rejected and 1 or 0
2050
2050
2051 @command(
2051 @command(
2052 'graft',
2052 'graft',
2053 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2053 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2054 ('c', 'continue', False, _('resume interrupted graft')),
2054 ('c', 'continue', False, _('resume interrupted graft')),
2055 ('e', 'edit', False, _('invoke editor on commit messages')),
2055 ('e', 'edit', False, _('invoke editor on commit messages')),
2056 ('', 'log', None, _('append graft info to log message')),
2056 ('', 'log', None, _('append graft info to log message')),
2057 ('f', 'force', False, _('force graft')),
2057 ('f', 'force', False, _('force graft')),
2058 ('D', 'currentdate', False,
2058 ('D', 'currentdate', False,
2059 _('record the current date as commit date')),
2059 _('record the current date as commit date')),
2060 ('U', 'currentuser', False,
2060 ('U', 'currentuser', False,
2061 _('record the current user as committer'), _('DATE'))]
2061 _('record the current user as committer'), _('DATE'))]
2062 + commitopts2 + mergetoolopts + dryrunopts,
2062 + commitopts2 + mergetoolopts + dryrunopts,
2063 _('[OPTION]... [-r REV]... REV...'))
2063 _('[OPTION]... [-r REV]... REV...'))
2064 def graft(ui, repo, *revs, **opts):
2064 def graft(ui, repo, *revs, **opts):
2065 '''copy changes from other branches onto the current branch
2065 '''copy changes from other branches onto the current branch
2066
2066
2067 This command uses Mercurial's merge logic to copy individual
2067 This command uses Mercurial's merge logic to copy individual
2068 changes from other branches without merging branches in the
2068 changes from other branches without merging branches in the
2069 history graph. This is sometimes known as 'backporting' or
2069 history graph. This is sometimes known as 'backporting' or
2070 'cherry-picking'. By default, graft will copy user, date, and
2070 'cherry-picking'. By default, graft will copy user, date, and
2071 description from the source changesets.
2071 description from the source changesets.
2072
2072
2073 Changesets that are ancestors of the current revision, that have
2073 Changesets that are ancestors of the current revision, that have
2074 already been grafted, or that are merges will be skipped.
2074 already been grafted, or that are merges will be skipped.
2075
2075
2076 If --log is specified, log messages will have a comment appended
2076 If --log is specified, log messages will have a comment appended
2077 of the form::
2077 of the form::
2078
2078
2079 (grafted from CHANGESETHASH)
2079 (grafted from CHANGESETHASH)
2080
2080
2081 If --force is specified, revisions will be grafted even if they
2081 If --force is specified, revisions will be grafted even if they
2082 are already ancestors of, or have been grafted to, the destination.
2082 are already ancestors of, or have been grafted to, the destination.
2083 This is useful when the revisions have since been backed out.
2083 This is useful when the revisions have since been backed out.
2084
2084
2085 If a graft merge results in conflicts, the graft process is
2085 If a graft merge results in conflicts, the graft process is
2086 interrupted so that the current merge can be manually resolved.
2086 interrupted so that the current merge can be manually resolved.
2087 Once all conflicts are addressed, the graft process can be
2087 Once all conflicts are addressed, the graft process can be
2088 continued with the -c/--continue option.
2088 continued with the -c/--continue option.
2089
2089
2090 .. note::
2090 .. note::
2091
2091
2092 The -c/--continue option does not reapply earlier options, except
2092 The -c/--continue option does not reapply earlier options, except
2093 for --force.
2093 for --force.
2094
2094
2095 .. container:: verbose
2095 .. container:: verbose
2096
2096
2097 Examples:
2097 Examples:
2098
2098
2099 - copy a single change to the stable branch and edit its description::
2099 - copy a single change to the stable branch and edit its description::
2100
2100
2101 hg update stable
2101 hg update stable
2102 hg graft --edit 9393
2102 hg graft --edit 9393
2103
2103
2104 - graft a range of changesets with one exception, updating dates::
2104 - graft a range of changesets with one exception, updating dates::
2105
2105
2106 hg graft -D "2085::2093 and not 2091"
2106 hg graft -D "2085::2093 and not 2091"
2107
2107
2108 - continue a graft after resolving conflicts::
2108 - continue a graft after resolving conflicts::
2109
2109
2110 hg graft -c
2110 hg graft -c
2111
2111
2112 - show the source of a grafted changeset::
2112 - show the source of a grafted changeset::
2113
2113
2114 hg log --debug -r .
2114 hg log --debug -r .
2115
2115
2116 - show revisions sorted by date::
2116 - show revisions sorted by date::
2117
2117
2118 hg log -r "sort(all(), date)"
2118 hg log -r "sort(all(), date)"
2119
2119
2120 See :hg:`help revisions` for more about specifying revisions.
2120 See :hg:`help revisions` for more about specifying revisions.
2121
2121
2122 Returns 0 on successful completion.
2122 Returns 0 on successful completion.
2123 '''
2123 '''
2124 with repo.wlock():
2124 with repo.wlock():
2125 return _dograft(ui, repo, *revs, **opts)
2125 return _dograft(ui, repo, *revs, **opts)
2126
2126
2127 def _dograft(ui, repo, *revs, **opts):
2127 def _dograft(ui, repo, *revs, **opts):
2128 opts = pycompat.byteskwargs(opts)
2128 opts = pycompat.byteskwargs(opts)
2129 if revs and opts.get('rev'):
2129 if revs and opts.get('rev'):
2130 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2130 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2131 'revision ordering!\n'))
2131 'revision ordering!\n'))
2132
2132
2133 revs = list(revs)
2133 revs = list(revs)
2134 revs.extend(opts.get('rev'))
2134 revs.extend(opts.get('rev'))
2135
2135
2136 if not opts.get('user') and opts.get('currentuser'):
2136 if not opts.get('user') and opts.get('currentuser'):
2137 opts['user'] = ui.username()
2137 opts['user'] = ui.username()
2138 if not opts.get('date') and opts.get('currentdate'):
2138 if not opts.get('date') and opts.get('currentdate'):
2139 opts['date'] = "%d %d" % util.makedate()
2139 opts['date'] = "%d %d" % util.makedate()
2140
2140
2141 editor = cmdutil.getcommiteditor(editform='graft',
2141 editor = cmdutil.getcommiteditor(editform='graft',
2142 **pycompat.strkwargs(opts))
2142 **pycompat.strkwargs(opts))
2143
2143
2144 cont = False
2144 cont = False
2145 if opts.get('continue'):
2145 if opts.get('continue'):
2146 cont = True
2146 cont = True
2147 if revs:
2147 if revs:
2148 raise error.Abort(_("can't specify --continue and revisions"))
2148 raise error.Abort(_("can't specify --continue and revisions"))
2149 # read in unfinished revisions
2149 # read in unfinished revisions
2150 try:
2150 try:
2151 nodes = repo.vfs.read('graftstate').splitlines()
2151 nodes = repo.vfs.read('graftstate').splitlines()
2152 revs = [repo[node].rev() for node in nodes]
2152 revs = [repo[node].rev() for node in nodes]
2153 except IOError as inst:
2153 except IOError as inst:
2154 if inst.errno != errno.ENOENT:
2154 if inst.errno != errno.ENOENT:
2155 raise
2155 raise
2156 cmdutil.wrongtooltocontinue(repo, _('graft'))
2156 cmdutil.wrongtooltocontinue(repo, _('graft'))
2157 else:
2157 else:
2158 cmdutil.checkunfinished(repo)
2158 cmdutil.checkunfinished(repo)
2159 cmdutil.bailifchanged(repo)
2159 cmdutil.bailifchanged(repo)
2160 if not revs:
2160 if not revs:
2161 raise error.Abort(_('no revisions specified'))
2161 raise error.Abort(_('no revisions specified'))
2162 revs = scmutil.revrange(repo, revs)
2162 revs = scmutil.revrange(repo, revs)
2163
2163
2164 skipped = set()
2164 skipped = set()
2165 # check for merges
2165 # check for merges
2166 for rev in repo.revs('%ld and merge()', revs):
2166 for rev in repo.revs('%ld and merge()', revs):
2167 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2167 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2168 skipped.add(rev)
2168 skipped.add(rev)
2169 revs = [r for r in revs if r not in skipped]
2169 revs = [r for r in revs if r not in skipped]
2170 if not revs:
2170 if not revs:
2171 return -1
2171 return -1
2172
2172
2173 # Don't check in the --continue case, in effect retaining --force across
2173 # Don't check in the --continue case, in effect retaining --force across
2174 # --continues. That's because without --force, any revisions we decided to
2174 # --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
2175 # 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
2176 # 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
2177 # skipped would not have been filtered out, and if they hadn't been applied
2178 # already, they'd have been in the graftstate.
2178 # already, they'd have been in the graftstate.
2179 if not (cont or opts.get('force')):
2179 if not (cont or opts.get('force')):
2180 # check for ancestors of dest branch
2180 # check for ancestors of dest branch
2181 crev = repo['.'].rev()
2181 crev = repo['.'].rev()
2182 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2182 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2183 # XXX make this lazy in the future
2183 # XXX make this lazy in the future
2184 # don't mutate while iterating, create a copy
2184 # don't mutate while iterating, create a copy
2185 for rev in list(revs):
2185 for rev in list(revs):
2186 if rev in ancestors:
2186 if rev in ancestors:
2187 ui.warn(_('skipping ancestor revision %d:%s\n') %
2187 ui.warn(_('skipping ancestor revision %d:%s\n') %
2188 (rev, repo[rev]))
2188 (rev, repo[rev]))
2189 # XXX remove on list is slow
2189 # XXX remove on list is slow
2190 revs.remove(rev)
2190 revs.remove(rev)
2191 if not revs:
2191 if not revs:
2192 return -1
2192 return -1
2193
2193
2194 # analyze revs for earlier grafts
2194 # analyze revs for earlier grafts
2195 ids = {}
2195 ids = {}
2196 for ctx in repo.set("%ld", revs):
2196 for ctx in repo.set("%ld", revs):
2197 ids[ctx.hex()] = ctx.rev()
2197 ids[ctx.hex()] = ctx.rev()
2198 n = ctx.extra().get('source')
2198 n = ctx.extra().get('source')
2199 if n:
2199 if n:
2200 ids[n] = ctx.rev()
2200 ids[n] = ctx.rev()
2201
2201
2202 # check ancestors for earlier grafts
2202 # check ancestors for earlier grafts
2203 ui.debug('scanning for duplicate grafts\n')
2203 ui.debug('scanning for duplicate grafts\n')
2204
2204
2205 # The only changesets we can be sure doesn't contain grafts of any
2205 # The only changesets we can be sure doesn't contain grafts of any
2206 # revs, are the ones that are common ancestors of *all* revs:
2206 # revs, are the ones that are common ancestors of *all* revs:
2207 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2207 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2208 ctx = repo[rev]
2208 ctx = repo[rev]
2209 n = ctx.extra().get('source')
2209 n = ctx.extra().get('source')
2210 if n in ids:
2210 if n in ids:
2211 try:
2211 try:
2212 r = repo[n].rev()
2212 r = repo[n].rev()
2213 except error.RepoLookupError:
2213 except error.RepoLookupError:
2214 r = None
2214 r = None
2215 if r in revs:
2215 if r in revs:
2216 ui.warn(_('skipping revision %d:%s '
2216 ui.warn(_('skipping revision %d:%s '
2217 '(already grafted to %d:%s)\n')
2217 '(already grafted to %d:%s)\n')
2218 % (r, repo[r], rev, ctx))
2218 % (r, repo[r], rev, ctx))
2219 revs.remove(r)
2219 revs.remove(r)
2220 elif ids[n] in revs:
2220 elif ids[n] in revs:
2221 if r is None:
2221 if r is None:
2222 ui.warn(_('skipping already grafted revision %d:%s '
2222 ui.warn(_('skipping already grafted revision %d:%s '
2223 '(%d:%s also has unknown origin %s)\n')
2223 '(%d:%s also has unknown origin %s)\n')
2224 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2224 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2225 else:
2225 else:
2226 ui.warn(_('skipping already grafted revision %d:%s '
2226 ui.warn(_('skipping already grafted revision %d:%s '
2227 '(%d:%s also has origin %d:%s)\n')
2227 '(%d:%s also has origin %d:%s)\n')
2228 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2228 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2229 revs.remove(ids[n])
2229 revs.remove(ids[n])
2230 elif ctx.hex() in ids:
2230 elif ctx.hex() in ids:
2231 r = ids[ctx.hex()]
2231 r = ids[ctx.hex()]
2232 ui.warn(_('skipping already grafted revision %d:%s '
2232 ui.warn(_('skipping already grafted revision %d:%s '
2233 '(was grafted from %d:%s)\n') %
2233 '(was grafted from %d:%s)\n') %
2234 (r, repo[r], rev, ctx))
2234 (r, repo[r], rev, ctx))
2235 revs.remove(r)
2235 revs.remove(r)
2236 if not revs:
2236 if not revs:
2237 return -1
2237 return -1
2238
2238
2239 for pos, ctx in enumerate(repo.set("%ld", revs)):
2239 for pos, ctx in enumerate(repo.set("%ld", revs)):
2240 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2240 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2241 ctx.description().split('\n', 1)[0])
2241 ctx.description().split('\n', 1)[0])
2242 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2242 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2243 if names:
2243 if names:
2244 desc += ' (%s)' % ' '.join(names)
2244 desc += ' (%s)' % ' '.join(names)
2245 ui.status(_('grafting %s\n') % desc)
2245 ui.status(_('grafting %s\n') % desc)
2246 if opts.get('dry_run'):
2246 if opts.get('dry_run'):
2247 continue
2247 continue
2248
2248
2249 source = ctx.extra().get('source')
2249 source = ctx.extra().get('source')
2250 extra = {}
2250 extra = {}
2251 if source:
2251 if source:
2252 extra['source'] = source
2252 extra['source'] = source
2253 extra['intermediate-source'] = ctx.hex()
2253 extra['intermediate-source'] = ctx.hex()
2254 else:
2254 else:
2255 extra['source'] = ctx.hex()
2255 extra['source'] = ctx.hex()
2256 user = ctx.user()
2256 user = ctx.user()
2257 if opts.get('user'):
2257 if opts.get('user'):
2258 user = opts['user']
2258 user = opts['user']
2259 date = ctx.date()
2259 date = ctx.date()
2260 if opts.get('date'):
2260 if opts.get('date'):
2261 date = opts['date']
2261 date = opts['date']
2262 message = ctx.description()
2262 message = ctx.description()
2263 if opts.get('log'):
2263 if opts.get('log'):
2264 message += '\n(grafted from %s)' % ctx.hex()
2264 message += '\n(grafted from %s)' % ctx.hex()
2265
2265
2266 # we don't merge the first commit when continuing
2266 # we don't merge the first commit when continuing
2267 if not cont:
2267 if not cont:
2268 # perform the graft merge with p1(rev) as 'ancestor'
2268 # perform the graft merge with p1(rev) as 'ancestor'
2269 try:
2269 try:
2270 # ui.forcemerge is an internal variable, do not document
2270 # ui.forcemerge is an internal variable, do not document
2271 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2271 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2272 'graft')
2272 'graft')
2273 stats = mergemod.graft(repo, ctx, ctx.p1(),
2273 stats = mergemod.graft(repo, ctx, ctx.p1(),
2274 ['local', 'graft'])
2274 ['local', 'graft'])
2275 finally:
2275 finally:
2276 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2276 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2277 # report any conflicts
2277 # report any conflicts
2278 if stats and stats[3] > 0:
2278 if stats and stats[3] > 0:
2279 # write out state for --continue
2279 # write out state for --continue
2280 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2280 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2281 repo.vfs.write('graftstate', ''.join(nodelines))
2281 repo.vfs.write('graftstate', ''.join(nodelines))
2282 extra = ''
2282 extra = ''
2283 if opts.get('user'):
2283 if opts.get('user'):
2284 extra += ' --user %s' % util.shellquote(opts['user'])
2284 extra += ' --user %s' % util.shellquote(opts['user'])
2285 if opts.get('date'):
2285 if opts.get('date'):
2286 extra += ' --date %s' % util.shellquote(opts['date'])
2286 extra += ' --date %s' % util.shellquote(opts['date'])
2287 if opts.get('log'):
2287 if opts.get('log'):
2288 extra += ' --log'
2288 extra += ' --log'
2289 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2289 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2290 raise error.Abort(
2290 raise error.Abort(
2291 _("unresolved conflicts, can't continue"),
2291 _("unresolved conflicts, can't continue"),
2292 hint=hint)
2292 hint=hint)
2293 else:
2293 else:
2294 cont = False
2294 cont = False
2295
2295
2296 # commit
2296 # commit
2297 node = repo.commit(text=message, user=user,
2297 node = repo.commit(text=message, user=user,
2298 date=date, extra=extra, editor=editor)
2298 date=date, extra=extra, editor=editor)
2299 if node is None:
2299 if node is None:
2300 ui.warn(
2300 ui.warn(
2301 _('note: graft of %d:%s created no changes to commit\n') %
2301 _('note: graft of %d:%s created no changes to commit\n') %
2302 (ctx.rev(), ctx))
2302 (ctx.rev(), ctx))
2303
2303
2304 # remove state when we complete successfully
2304 # remove state when we complete successfully
2305 if not opts.get('dry_run'):
2305 if not opts.get('dry_run'):
2306 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2306 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2307
2307
2308 return 0
2308 return 0
2309
2309
2310 @command('grep',
2310 @command('grep',
2311 [('0', 'print0', None, _('end fields with NUL')),
2311 [('0', 'print0', None, _('end fields with NUL')),
2312 ('', 'all', None, _('print all revisions that match')),
2312 ('', 'all', None, _('print all revisions that match')),
2313 ('a', 'text', None, _('treat all files as text')),
2313 ('a', 'text', None, _('treat all files as text')),
2314 ('f', 'follow', None,
2314 ('f', 'follow', None,
2315 _('follow changeset history,'
2315 _('follow changeset history,'
2316 ' or file history across copies and renames')),
2316 ' or file history across copies and renames')),
2317 ('i', 'ignore-case', None, _('ignore case when matching')),
2317 ('i', 'ignore-case', None, _('ignore case when matching')),
2318 ('l', 'files-with-matches', None,
2318 ('l', 'files-with-matches', None,
2319 _('print only filenames and revisions that match')),
2319 _('print only filenames and revisions that match')),
2320 ('n', 'line-number', None, _('print matching line numbers')),
2320 ('n', 'line-number', None, _('print matching line numbers')),
2321 ('r', 'rev', [],
2321 ('r', 'rev', [],
2322 _('only search files changed within revision range'), _('REV')),
2322 _('only search files changed within revision range'), _('REV')),
2323 ('u', 'user', None, _('list the author (long with -v)')),
2323 ('u', 'user', None, _('list the author (long with -v)')),
2324 ('d', 'date', None, _('list the date (short with -q)')),
2324 ('d', 'date', None, _('list the date (short with -q)')),
2325 ] + formatteropts + walkopts,
2325 ] + formatteropts + walkopts,
2326 _('[OPTION]... PATTERN [FILE]...'),
2326 _('[OPTION]... PATTERN [FILE]...'),
2327 inferrepo=True, cmdtype=readonly)
2327 inferrepo=True, cmdtype=readonly)
2328 def grep(ui, repo, pattern, *pats, **opts):
2328 def grep(ui, repo, pattern, *pats, **opts):
2329 """search revision history for a pattern in specified files
2329 """search revision history for a pattern in specified files
2330
2330
2331 Search revision history for a regular expression in the specified
2331 Search revision history for a regular expression in the specified
2332 files or the entire project.
2332 files or the entire project.
2333
2333
2334 By default, grep prints the most recent revision number for each
2334 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
2335 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
2336 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
2337 a non-match, or "+" for a non-match that becomes a match), use the
2338 --all flag.
2338 --all flag.
2339
2339
2340 PATTERN can be any Python (roughly Perl-compatible) regular
2340 PATTERN can be any Python (roughly Perl-compatible) regular
2341 expression.
2341 expression.
2342
2342
2343 If no FILEs are specified (and -f/--follow isn't set), all files in
2343 If no FILEs are specified (and -f/--follow isn't set), all files in
2344 the repository are searched, including those that don't exist in the
2344 the repository are searched, including those that don't exist in the
2345 current branch or have been deleted in a prior changeset.
2345 current branch or have been deleted in a prior changeset.
2346
2346
2347 Returns 0 if a match is found, 1 otherwise.
2347 Returns 0 if a match is found, 1 otherwise.
2348 """
2348 """
2349 opts = pycompat.byteskwargs(opts)
2349 opts = pycompat.byteskwargs(opts)
2350 reflags = re.M
2350 reflags = re.M
2351 if opts.get('ignore_case'):
2351 if opts.get('ignore_case'):
2352 reflags |= re.I
2352 reflags |= re.I
2353 try:
2353 try:
2354 regexp = util.re.compile(pattern, reflags)
2354 regexp = util.re.compile(pattern, reflags)
2355 except re.error as inst:
2355 except re.error as inst:
2356 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2356 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2357 return 1
2357 return 1
2358 sep, eol = ':', '\n'
2358 sep, eol = ':', '\n'
2359 if opts.get('print0'):
2359 if opts.get('print0'):
2360 sep = eol = '\0'
2360 sep = eol = '\0'
2361
2361
2362 getfile = util.lrucachefunc(repo.file)
2362 getfile = util.lrucachefunc(repo.file)
2363
2363
2364 def matchlines(body):
2364 def matchlines(body):
2365 begin = 0
2365 begin = 0
2366 linenum = 0
2366 linenum = 0
2367 while begin < len(body):
2367 while begin < len(body):
2368 match = regexp.search(body, begin)
2368 match = regexp.search(body, begin)
2369 if not match:
2369 if not match:
2370 break
2370 break
2371 mstart, mend = match.span()
2371 mstart, mend = match.span()
2372 linenum += body.count('\n', begin, mstart) + 1
2372 linenum += body.count('\n', begin, mstart) + 1
2373 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2373 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2374 begin = body.find('\n', mend) + 1 or len(body) + 1
2374 begin = body.find('\n', mend) + 1 or len(body) + 1
2375 lend = begin - 1
2375 lend = begin - 1
2376 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2376 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2377
2377
2378 class linestate(object):
2378 class linestate(object):
2379 def __init__(self, line, linenum, colstart, colend):
2379 def __init__(self, line, linenum, colstart, colend):
2380 self.line = line
2380 self.line = line
2381 self.linenum = linenum
2381 self.linenum = linenum
2382 self.colstart = colstart
2382 self.colstart = colstart
2383 self.colend = colend
2383 self.colend = colend
2384
2384
2385 def __hash__(self):
2385 def __hash__(self):
2386 return hash((self.linenum, self.line))
2386 return hash((self.linenum, self.line))
2387
2387
2388 def __eq__(self, other):
2388 def __eq__(self, other):
2389 return self.line == other.line
2389 return self.line == other.line
2390
2390
2391 def findpos(self):
2391 def findpos(self):
2392 """Iterate all (start, end) indices of matches"""
2392 """Iterate all (start, end) indices of matches"""
2393 yield self.colstart, self.colend
2393 yield self.colstart, self.colend
2394 p = self.colend
2394 p = self.colend
2395 while p < len(self.line):
2395 while p < len(self.line):
2396 m = regexp.search(self.line, p)
2396 m = regexp.search(self.line, p)
2397 if not m:
2397 if not m:
2398 break
2398 break
2399 yield m.span()
2399 yield m.span()
2400 p = m.end()
2400 p = m.end()
2401
2401
2402 matches = {}
2402 matches = {}
2403 copies = {}
2403 copies = {}
2404 def grepbody(fn, rev, body):
2404 def grepbody(fn, rev, body):
2405 matches[rev].setdefault(fn, [])
2405 matches[rev].setdefault(fn, [])
2406 m = matches[rev][fn]
2406 m = matches[rev][fn]
2407 for lnum, cstart, cend, line in matchlines(body):
2407 for lnum, cstart, cend, line in matchlines(body):
2408 s = linestate(line, lnum, cstart, cend)
2408 s = linestate(line, lnum, cstart, cend)
2409 m.append(s)
2409 m.append(s)
2410
2410
2411 def difflinestates(a, b):
2411 def difflinestates(a, b):
2412 sm = difflib.SequenceMatcher(None, a, b)
2412 sm = difflib.SequenceMatcher(None, a, b)
2413 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2413 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2414 if tag == 'insert':
2414 if tag == 'insert':
2415 for i in xrange(blo, bhi):
2415 for i in xrange(blo, bhi):
2416 yield ('+', b[i])
2416 yield ('+', b[i])
2417 elif tag == 'delete':
2417 elif tag == 'delete':
2418 for i in xrange(alo, ahi):
2418 for i in xrange(alo, ahi):
2419 yield ('-', a[i])
2419 yield ('-', a[i])
2420 elif tag == 'replace':
2420 elif tag == 'replace':
2421 for i in xrange(alo, ahi):
2421 for i in xrange(alo, ahi):
2422 yield ('-', a[i])
2422 yield ('-', a[i])
2423 for i in xrange(blo, bhi):
2423 for i in xrange(blo, bhi):
2424 yield ('+', b[i])
2424 yield ('+', b[i])
2425
2425
2426 def display(fm, fn, ctx, pstates, states):
2426 def display(fm, fn, ctx, pstates, states):
2427 rev = ctx.rev()
2427 rev = ctx.rev()
2428 if fm.isplain():
2428 if fm.isplain():
2429 formatuser = ui.shortuser
2429 formatuser = ui.shortuser
2430 else:
2430 else:
2431 formatuser = str
2431 formatuser = str
2432 if ui.quiet:
2432 if ui.quiet:
2433 datefmt = '%Y-%m-%d'
2433 datefmt = '%Y-%m-%d'
2434 else:
2434 else:
2435 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2435 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2436 found = False
2436 found = False
2437 @util.cachefunc
2437 @util.cachefunc
2438 def binary():
2438 def binary():
2439 flog = getfile(fn)
2439 flog = getfile(fn)
2440 return util.binary(flog.read(ctx.filenode(fn)))
2440 return util.binary(flog.read(ctx.filenode(fn)))
2441
2441
2442 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2442 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2443 if opts.get('all'):
2443 if opts.get('all'):
2444 iter = difflinestates(pstates, states)
2444 iter = difflinestates(pstates, states)
2445 else:
2445 else:
2446 iter = [('', l) for l in states]
2446 iter = [('', l) for l in states]
2447 for change, l in iter:
2447 for change, l in iter:
2448 fm.startitem()
2448 fm.startitem()
2449 fm.data(node=fm.hexfunc(ctx.node()))
2449 fm.data(node=fm.hexfunc(ctx.node()))
2450 cols = [
2450 cols = [
2451 ('filename', fn, True),
2451 ('filename', fn, True),
2452 ('rev', rev, True),
2452 ('rev', rev, True),
2453 ('linenumber', l.linenum, opts.get('line_number')),
2453 ('linenumber', l.linenum, opts.get('line_number')),
2454 ]
2454 ]
2455 if opts.get('all'):
2455 if opts.get('all'):
2456 cols.append(('change', change, True))
2456 cols.append(('change', change, True))
2457 cols.extend([
2457 cols.extend([
2458 ('user', formatuser(ctx.user()), opts.get('user')),
2458 ('user', formatuser(ctx.user()), opts.get('user')),
2459 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2459 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2460 ])
2460 ])
2461 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2461 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2462 for name, data, cond in cols:
2462 for name, data, cond in cols:
2463 field = fieldnamemap.get(name, name)
2463 field = fieldnamemap.get(name, name)
2464 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2464 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2465 if cond and name != lastcol:
2465 if cond and name != lastcol:
2466 fm.plain(sep, label='grep.sep')
2466 fm.plain(sep, label='grep.sep')
2467 if not opts.get('files_with_matches'):
2467 if not opts.get('files_with_matches'):
2468 fm.plain(sep, label='grep.sep')
2468 fm.plain(sep, label='grep.sep')
2469 if not opts.get('text') and binary():
2469 if not opts.get('text') and binary():
2470 fm.plain(_(" Binary file matches"))
2470 fm.plain(_(" Binary file matches"))
2471 else:
2471 else:
2472 displaymatches(fm.nested('texts'), l)
2472 displaymatches(fm.nested('texts'), l)
2473 fm.plain(eol)
2473 fm.plain(eol)
2474 found = True
2474 found = True
2475 if opts.get('files_with_matches'):
2475 if opts.get('files_with_matches'):
2476 break
2476 break
2477 return found
2477 return found
2478
2478
2479 def displaymatches(fm, l):
2479 def displaymatches(fm, l):
2480 p = 0
2480 p = 0
2481 for s, e in l.findpos():
2481 for s, e in l.findpos():
2482 if p < s:
2482 if p < s:
2483 fm.startitem()
2483 fm.startitem()
2484 fm.write('text', '%s', l.line[p:s])
2484 fm.write('text', '%s', l.line[p:s])
2485 fm.data(matched=False)
2485 fm.data(matched=False)
2486 fm.startitem()
2486 fm.startitem()
2487 fm.write('text', '%s', l.line[s:e], label='grep.match')
2487 fm.write('text', '%s', l.line[s:e], label='grep.match')
2488 fm.data(matched=True)
2488 fm.data(matched=True)
2489 p = e
2489 p = e
2490 if p < len(l.line):
2490 if p < len(l.line):
2491 fm.startitem()
2491 fm.startitem()
2492 fm.write('text', '%s', l.line[p:])
2492 fm.write('text', '%s', l.line[p:])
2493 fm.data(matched=False)
2493 fm.data(matched=False)
2494 fm.end()
2494 fm.end()
2495
2495
2496 skip = {}
2496 skip = {}
2497 revfiles = {}
2497 revfiles = {}
2498 match = scmutil.match(repo[None], pats, opts)
2498 match = scmutil.match(repo[None], pats, opts)
2499 found = False
2499 found = False
2500 follow = opts.get('follow')
2500 follow = opts.get('follow')
2501
2501
2502 def prep(ctx, fns):
2502 def prep(ctx, fns):
2503 rev = ctx.rev()
2503 rev = ctx.rev()
2504 pctx = ctx.p1()
2504 pctx = ctx.p1()
2505 parent = pctx.rev()
2505 parent = pctx.rev()
2506 matches.setdefault(rev, {})
2506 matches.setdefault(rev, {})
2507 matches.setdefault(parent, {})
2507 matches.setdefault(parent, {})
2508 files = revfiles.setdefault(rev, [])
2508 files = revfiles.setdefault(rev, [])
2509 for fn in fns:
2509 for fn in fns:
2510 flog = getfile(fn)
2510 flog = getfile(fn)
2511 try:
2511 try:
2512 fnode = ctx.filenode(fn)
2512 fnode = ctx.filenode(fn)
2513 except error.LookupError:
2513 except error.LookupError:
2514 continue
2514 continue
2515
2515
2516 copied = flog.renamed(fnode)
2516 copied = flog.renamed(fnode)
2517 copy = follow and copied and copied[0]
2517 copy = follow and copied and copied[0]
2518 if copy:
2518 if copy:
2519 copies.setdefault(rev, {})[fn] = copy
2519 copies.setdefault(rev, {})[fn] = copy
2520 if fn in skip:
2520 if fn in skip:
2521 if copy:
2521 if copy:
2522 skip[copy] = True
2522 skip[copy] = True
2523 continue
2523 continue
2524 files.append(fn)
2524 files.append(fn)
2525
2525
2526 if fn not in matches[rev]:
2526 if fn not in matches[rev]:
2527 grepbody(fn, rev, flog.read(fnode))
2527 grepbody(fn, rev, flog.read(fnode))
2528
2528
2529 pfn = copy or fn
2529 pfn = copy or fn
2530 if pfn not in matches[parent]:
2530 if pfn not in matches[parent]:
2531 try:
2531 try:
2532 fnode = pctx.filenode(pfn)
2532 fnode = pctx.filenode(pfn)
2533 grepbody(pfn, parent, flog.read(fnode))
2533 grepbody(pfn, parent, flog.read(fnode))
2534 except error.LookupError:
2534 except error.LookupError:
2535 pass
2535 pass
2536
2536
2537 ui.pager('grep')
2537 ui.pager('grep')
2538 fm = ui.formatter('grep', opts)
2538 fm = ui.formatter('grep', opts)
2539 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2539 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2540 rev = ctx.rev()
2540 rev = ctx.rev()
2541 parent = ctx.p1().rev()
2541 parent = ctx.p1().rev()
2542 for fn in sorted(revfiles.get(rev, [])):
2542 for fn in sorted(revfiles.get(rev, [])):
2543 states = matches[rev][fn]
2543 states = matches[rev][fn]
2544 copy = copies.get(rev, {}).get(fn)
2544 copy = copies.get(rev, {}).get(fn)
2545 if fn in skip:
2545 if fn in skip:
2546 if copy:
2546 if copy:
2547 skip[copy] = True
2547 skip[copy] = True
2548 continue
2548 continue
2549 pstates = matches.get(parent, {}).get(copy or fn, [])
2549 pstates = matches.get(parent, {}).get(copy or fn, [])
2550 if pstates or states:
2550 if pstates or states:
2551 r = display(fm, fn, ctx, pstates, states)
2551 r = display(fm, fn, ctx, pstates, states)
2552 found = found or r
2552 found = found or r
2553 if r and not opts.get('all'):
2553 if r and not opts.get('all'):
2554 skip[fn] = True
2554 skip[fn] = True
2555 if copy:
2555 if copy:
2556 skip[copy] = True
2556 skip[copy] = True
2557 del matches[rev]
2557 del matches[rev]
2558 del revfiles[rev]
2558 del revfiles[rev]
2559 fm.end()
2559 fm.end()
2560
2560
2561 return not found
2561 return not found
2562
2562
2563 @command('heads',
2563 @command('heads',
2564 [('r', 'rev', '',
2564 [('r', 'rev', '',
2565 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2565 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2566 ('t', 'topo', False, _('show topological heads only')),
2566 ('t', 'topo', False, _('show topological heads only')),
2567 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2567 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2568 ('c', 'closed', False, _('show normal and closed branch heads')),
2568 ('c', 'closed', False, _('show normal and closed branch heads')),
2569 ] + templateopts,
2569 ] + templateopts,
2570 _('[-ct] [-r STARTREV] [REV]...'), cmdtype=readonly)
2570 _('[-ct] [-r STARTREV] [REV]...'), cmdtype=readonly)
2571 def heads(ui, repo, *branchrevs, **opts):
2571 def heads(ui, repo, *branchrevs, **opts):
2572 """show branch heads
2572 """show branch heads
2573
2573
2574 With no arguments, show all open branch heads in the repository.
2574 With no arguments, show all open branch heads in the repository.
2575 Branch heads are changesets that have no descendants on the
2575 Branch heads are changesets that have no descendants on the
2576 same branch. They are where development generally takes place and
2576 same branch. They are where development generally takes place and
2577 are the usual targets for update and merge operations.
2577 are the usual targets for update and merge operations.
2578
2578
2579 If one or more REVs are given, only open branch heads on the
2579 If one or more REVs are given, only open branch heads on the
2580 branches associated with the specified changesets are shown. This
2580 branches associated with the specified changesets are shown. This
2581 means that you can use :hg:`heads .` to see the heads on the
2581 means that you can use :hg:`heads .` to see the heads on the
2582 currently checked-out branch.
2582 currently checked-out branch.
2583
2583
2584 If -c/--closed is specified, also show branch heads marked closed
2584 If -c/--closed is specified, also show branch heads marked closed
2585 (see :hg:`commit --close-branch`).
2585 (see :hg:`commit --close-branch`).
2586
2586
2587 If STARTREV is specified, only those heads that are descendants of
2587 If STARTREV is specified, only those heads that are descendants of
2588 STARTREV will be displayed.
2588 STARTREV will be displayed.
2589
2589
2590 If -t/--topo is specified, named branch mechanics will be ignored and only
2590 If -t/--topo is specified, named branch mechanics will be ignored and only
2591 topological heads (changesets with no children) will be shown.
2591 topological heads (changesets with no children) will be shown.
2592
2592
2593 Returns 0 if matching heads are found, 1 if not.
2593 Returns 0 if matching heads are found, 1 if not.
2594 """
2594 """
2595
2595
2596 opts = pycompat.byteskwargs(opts)
2596 opts = pycompat.byteskwargs(opts)
2597 start = None
2597 start = None
2598 rev = opts.get('rev')
2598 rev = opts.get('rev')
2599 if rev:
2599 if rev:
2600 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2600 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2601 start = scmutil.revsingle(repo, rev, None).node()
2601 start = scmutil.revsingle(repo, rev, None).node()
2602
2602
2603 if opts.get('topo'):
2603 if opts.get('topo'):
2604 heads = [repo[h] for h in repo.heads(start)]
2604 heads = [repo[h] for h in repo.heads(start)]
2605 else:
2605 else:
2606 heads = []
2606 heads = []
2607 for branch in repo.branchmap():
2607 for branch in repo.branchmap():
2608 heads += repo.branchheads(branch, start, opts.get('closed'))
2608 heads += repo.branchheads(branch, start, opts.get('closed'))
2609 heads = [repo[h] for h in heads]
2609 heads = [repo[h] for h in heads]
2610
2610
2611 if branchrevs:
2611 if branchrevs:
2612 branches = set(repo[br].branch() for br in branchrevs)
2612 branches = set(repo[br].branch() for br in branchrevs)
2613 heads = [h for h in heads if h.branch() in branches]
2613 heads = [h for h in heads if h.branch() in branches]
2614
2614
2615 if opts.get('active') and branchrevs:
2615 if opts.get('active') and branchrevs:
2616 dagheads = repo.heads(start)
2616 dagheads = repo.heads(start)
2617 heads = [h for h in heads if h.node() in dagheads]
2617 heads = [h for h in heads if h.node() in dagheads]
2618
2618
2619 if branchrevs:
2619 if branchrevs:
2620 haveheads = set(h.branch() for h in heads)
2620 haveheads = set(h.branch() for h in heads)
2621 if branches - haveheads:
2621 if branches - haveheads:
2622 headless = ', '.join(b for b in branches - haveheads)
2622 headless = ', '.join(b for b in branches - haveheads)
2623 msg = _('no open branch heads found on branches %s')
2623 msg = _('no open branch heads found on branches %s')
2624 if opts.get('rev'):
2624 if opts.get('rev'):
2625 msg += _(' (started at %s)') % opts['rev']
2625 msg += _(' (started at %s)') % opts['rev']
2626 ui.warn((msg + '\n') % headless)
2626 ui.warn((msg + '\n') % headless)
2627
2627
2628 if not heads:
2628 if not heads:
2629 return 1
2629 return 1
2630
2630
2631 ui.pager('heads')
2631 ui.pager('heads')
2632 heads = sorted(heads, key=lambda x: -x.rev())
2632 heads = sorted(heads, key=lambda x: -x.rev())
2633 displayer = cmdutil.show_changeset(ui, repo, opts)
2633 displayer = cmdutil.show_changeset(ui, repo, opts)
2634 for ctx in heads:
2634 for ctx in heads:
2635 displayer.show(ctx)
2635 displayer.show(ctx)
2636 displayer.close()
2636 displayer.close()
2637
2637
2638 @command('help',
2638 @command('help',
2639 [('e', 'extension', None, _('show only help for extensions')),
2639 [('e', 'extension', None, _('show only help for extensions')),
2640 ('c', 'command', None, _('show only help for commands')),
2640 ('c', 'command', None, _('show only help for commands')),
2641 ('k', 'keyword', None, _('show topics matching keyword')),
2641 ('k', 'keyword', None, _('show topics matching keyword')),
2642 ('s', 'system', [], _('show help for specific platform(s)')),
2642 ('s', 'system', [], _('show help for specific platform(s)')),
2643 ],
2643 ],
2644 _('[-ecks] [TOPIC]'),
2644 _('[-ecks] [TOPIC]'),
2645 norepo=True, cmdtype=readonly)
2645 norepo=True, cmdtype=readonly)
2646 def help_(ui, name=None, **opts):
2646 def help_(ui, name=None, **opts):
2647 """show help for a given topic or a help overview
2647 """show help for a given topic or a help overview
2648
2648
2649 With no arguments, print a list of commands with short help messages.
2649 With no arguments, print a list of commands with short help messages.
2650
2650
2651 Given a topic, extension, or command name, print help for that
2651 Given a topic, extension, or command name, print help for that
2652 topic.
2652 topic.
2653
2653
2654 Returns 0 if successful.
2654 Returns 0 if successful.
2655 """
2655 """
2656
2656
2657 keep = opts.get(r'system') or []
2657 keep = opts.get(r'system') or []
2658 if len(keep) == 0:
2658 if len(keep) == 0:
2659 if pycompat.sysplatform.startswith('win'):
2659 if pycompat.sysplatform.startswith('win'):
2660 keep.append('windows')
2660 keep.append('windows')
2661 elif pycompat.sysplatform == 'OpenVMS':
2661 elif pycompat.sysplatform == 'OpenVMS':
2662 keep.append('vms')
2662 keep.append('vms')
2663 elif pycompat.sysplatform == 'plan9':
2663 elif pycompat.sysplatform == 'plan9':
2664 keep.append('plan9')
2664 keep.append('plan9')
2665 else:
2665 else:
2666 keep.append('unix')
2666 keep.append('unix')
2667 keep.append(pycompat.sysplatform.lower())
2667 keep.append(pycompat.sysplatform.lower())
2668 if ui.verbose:
2668 if ui.verbose:
2669 keep.append('verbose')
2669 keep.append('verbose')
2670
2670
2671 commands = sys.modules[__name__]
2671 commands = sys.modules[__name__]
2672 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2672 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2673 ui.pager('help')
2673 ui.pager('help')
2674 ui.write(formatted)
2674 ui.write(formatted)
2675
2675
2676
2676
2677 @command('identify|id',
2677 @command('identify|id',
2678 [('r', 'rev', '',
2678 [('r', 'rev', '',
2679 _('identify the specified revision'), _('REV')),
2679 _('identify the specified revision'), _('REV')),
2680 ('n', 'num', None, _('show local revision number')),
2680 ('n', 'num', None, _('show local revision number')),
2681 ('i', 'id', None, _('show global revision id')),
2681 ('i', 'id', None, _('show global revision id')),
2682 ('b', 'branch', None, _('show branch')),
2682 ('b', 'branch', None, _('show branch')),
2683 ('t', 'tags', None, _('show tags')),
2683 ('t', 'tags', None, _('show tags')),
2684 ('B', 'bookmarks', None, _('show bookmarks')),
2684 ('B', 'bookmarks', None, _('show bookmarks')),
2685 ] + remoteopts + formatteropts,
2685 ] + remoteopts + formatteropts,
2686 _('[-nibtB] [-r REV] [SOURCE]'),
2686 _('[-nibtB] [-r REV] [SOURCE]'),
2687 optionalrepo=True, cmdtype=readonly)
2687 optionalrepo=True, cmdtype=readonly)
2688 def identify(ui, repo, source=None, rev=None,
2688 def identify(ui, repo, source=None, rev=None,
2689 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2689 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2690 """identify the working directory or specified revision
2690 """identify the working directory or specified revision
2691
2691
2692 Print a summary identifying the repository state at REV using one or
2692 Print a summary identifying the repository state at REV using one or
2693 two parent hash identifiers, followed by a "+" if the working
2693 two parent hash identifiers, followed by a "+" if the working
2694 directory has uncommitted changes, the branch name (if not default),
2694 directory has uncommitted changes, the branch name (if not default),
2695 a list of tags, and a list of bookmarks.
2695 a list of tags, and a list of bookmarks.
2696
2696
2697 When REV is not given, print a summary of the current state of the
2697 When REV is not given, print a summary of the current state of the
2698 repository.
2698 repository.
2699
2699
2700 Specifying a path to a repository root or Mercurial bundle will
2700 Specifying a path to a repository root or Mercurial bundle will
2701 cause lookup to operate on that repository/bundle.
2701 cause lookup to operate on that repository/bundle.
2702
2702
2703 .. container:: verbose
2703 .. container:: verbose
2704
2704
2705 Examples:
2705 Examples:
2706
2706
2707 - generate a build identifier for the working directory::
2707 - generate a build identifier for the working directory::
2708
2708
2709 hg id --id > build-id.dat
2709 hg id --id > build-id.dat
2710
2710
2711 - find the revision corresponding to a tag::
2711 - find the revision corresponding to a tag::
2712
2712
2713 hg id -n -r 1.3
2713 hg id -n -r 1.3
2714
2714
2715 - check the most recent revision of a remote repository::
2715 - check the most recent revision of a remote repository::
2716
2716
2717 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2717 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2718
2718
2719 See :hg:`log` for generating more information about specific revisions,
2719 See :hg:`log` for generating more information about specific revisions,
2720 including full hash identifiers.
2720 including full hash identifiers.
2721
2721
2722 Returns 0 if successful.
2722 Returns 0 if successful.
2723 """
2723 """
2724
2724
2725 opts = pycompat.byteskwargs(opts)
2725 opts = pycompat.byteskwargs(opts)
2726 if not repo and not source:
2726 if not repo and not source:
2727 raise error.Abort(_("there is no Mercurial repository here "
2727 raise error.Abort(_("there is no Mercurial repository here "
2728 "(.hg not found)"))
2728 "(.hg not found)"))
2729
2729
2730 if ui.debugflag:
2730 if ui.debugflag:
2731 hexfunc = hex
2731 hexfunc = hex
2732 else:
2732 else:
2733 hexfunc = short
2733 hexfunc = short
2734 default = not (num or id or branch or tags or bookmarks)
2734 default = not (num or id or branch or tags or bookmarks)
2735 output = []
2735 output = []
2736 revs = []
2736 revs = []
2737
2737
2738 if source:
2738 if source:
2739 source, branches = hg.parseurl(ui.expandpath(source))
2739 source, branches = hg.parseurl(ui.expandpath(source))
2740 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2740 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2741 repo = peer.local()
2741 repo = peer.local()
2742 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2742 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2743
2743
2744 fm = ui.formatter('identify', opts)
2744 fm = ui.formatter('identify', opts)
2745 fm.startitem()
2745 fm.startitem()
2746
2746
2747 if not repo:
2747 if not repo:
2748 if num or branch or tags:
2748 if num or branch or tags:
2749 raise error.Abort(
2749 raise error.Abort(
2750 _("can't query remote revision number, branch, or tags"))
2750 _("can't query remote revision number, branch, or tags"))
2751 if not rev and revs:
2751 if not rev and revs:
2752 rev = revs[0]
2752 rev = revs[0]
2753 if not rev:
2753 if not rev:
2754 rev = "tip"
2754 rev = "tip"
2755
2755
2756 remoterev = peer.lookup(rev)
2756 remoterev = peer.lookup(rev)
2757 hexrev = hexfunc(remoterev)
2757 hexrev = hexfunc(remoterev)
2758 if default or id:
2758 if default or id:
2759 output = [hexrev]
2759 output = [hexrev]
2760 fm.data(id=hexrev)
2760 fm.data(id=hexrev)
2761
2761
2762 def getbms():
2762 def getbms():
2763 bms = []
2763 bms = []
2764
2764
2765 if 'bookmarks' in peer.listkeys('namespaces'):
2765 if 'bookmarks' in peer.listkeys('namespaces'):
2766 hexremoterev = hex(remoterev)
2766 hexremoterev = hex(remoterev)
2767 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2767 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2768 if bmr == hexremoterev]
2768 if bmr == hexremoterev]
2769
2769
2770 return sorted(bms)
2770 return sorted(bms)
2771
2771
2772 bms = getbms()
2772 bms = getbms()
2773 if bookmarks:
2773 if bookmarks:
2774 output.extend(bms)
2774 output.extend(bms)
2775 elif default and not ui.quiet:
2775 elif default and not ui.quiet:
2776 # multiple bookmarks for a single parent separated by '/'
2776 # multiple bookmarks for a single parent separated by '/'
2777 bm = '/'.join(bms)
2777 bm = '/'.join(bms)
2778 if bm:
2778 if bm:
2779 output.append(bm)
2779 output.append(bm)
2780
2780
2781 fm.data(node=hex(remoterev))
2781 fm.data(node=hex(remoterev))
2782 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
2782 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
2783 else:
2783 else:
2784 if rev:
2784 if rev:
2785 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2785 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2786 ctx = scmutil.revsingle(repo, rev, None)
2786 ctx = scmutil.revsingle(repo, rev, None)
2787
2787
2788 if ctx.rev() is None:
2788 if ctx.rev() is None:
2789 ctx = repo[None]
2789 ctx = repo[None]
2790 parents = ctx.parents()
2790 parents = ctx.parents()
2791 taglist = []
2791 taglist = []
2792 for p in parents:
2792 for p in parents:
2793 taglist.extend(p.tags())
2793 taglist.extend(p.tags())
2794
2794
2795 dirty = ""
2795 dirty = ""
2796 if ctx.dirty(missing=True, merge=False, branch=False):
2796 if ctx.dirty(missing=True, merge=False, branch=False):
2797 dirty = '+'
2797 dirty = '+'
2798 fm.data(dirty=dirty)
2798 fm.data(dirty=dirty)
2799
2799
2800 hexoutput = [hexfunc(p.node()) for p in parents]
2800 hexoutput = [hexfunc(p.node()) for p in parents]
2801 if default or id:
2801 if default or id:
2802 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
2802 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
2803 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
2803 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
2804
2804
2805 if num:
2805 if num:
2806 numoutput = ["%d" % p.rev() for p in parents]
2806 numoutput = ["%d" % p.rev() for p in parents]
2807 output.append("%s%s" % ('+'.join(numoutput), dirty))
2807 output.append("%s%s" % ('+'.join(numoutput), dirty))
2808
2808
2809 fn = fm.nested('parents')
2809 fn = fm.nested('parents')
2810 for p in parents:
2810 for p in parents:
2811 fn.startitem()
2811 fn.startitem()
2812 fn.data(rev=p.rev())
2812 fn.data(rev=p.rev())
2813 fn.data(node=p.hex())
2813 fn.data(node=p.hex())
2814 fn.context(ctx=p)
2814 fn.context(ctx=p)
2815 fn.end()
2815 fn.end()
2816 else:
2816 else:
2817 hexoutput = hexfunc(ctx.node())
2817 hexoutput = hexfunc(ctx.node())
2818 if default or id:
2818 if default or id:
2819 output = [hexoutput]
2819 output = [hexoutput]
2820 fm.data(id=hexoutput)
2820 fm.data(id=hexoutput)
2821
2821
2822 if num:
2822 if num:
2823 output.append(pycompat.bytestr(ctx.rev()))
2823 output.append(pycompat.bytestr(ctx.rev()))
2824 taglist = ctx.tags()
2824 taglist = ctx.tags()
2825
2825
2826 if default and not ui.quiet:
2826 if default and not ui.quiet:
2827 b = ctx.branch()
2827 b = ctx.branch()
2828 if b != 'default':
2828 if b != 'default':
2829 output.append("(%s)" % b)
2829 output.append("(%s)" % b)
2830
2830
2831 # multiple tags for a single parent separated by '/'
2831 # multiple tags for a single parent separated by '/'
2832 t = '/'.join(taglist)
2832 t = '/'.join(taglist)
2833 if t:
2833 if t:
2834 output.append(t)
2834 output.append(t)
2835
2835
2836 # multiple bookmarks for a single parent separated by '/'
2836 # multiple bookmarks for a single parent separated by '/'
2837 bm = '/'.join(ctx.bookmarks())
2837 bm = '/'.join(ctx.bookmarks())
2838 if bm:
2838 if bm:
2839 output.append(bm)
2839 output.append(bm)
2840 else:
2840 else:
2841 if branch:
2841 if branch:
2842 output.append(ctx.branch())
2842 output.append(ctx.branch())
2843
2843
2844 if tags:
2844 if tags:
2845 output.extend(taglist)
2845 output.extend(taglist)
2846
2846
2847 if bookmarks:
2847 if bookmarks:
2848 output.extend(ctx.bookmarks())
2848 output.extend(ctx.bookmarks())
2849
2849
2850 fm.data(node=ctx.hex())
2850 fm.data(node=ctx.hex())
2851 fm.data(branch=ctx.branch())
2851 fm.data(branch=ctx.branch())
2852 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
2852 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
2853 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
2853 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
2854 fm.context(ctx=ctx)
2854 fm.context(ctx=ctx)
2855
2855
2856 fm.plain("%s\n" % ' '.join(output))
2856 fm.plain("%s\n" % ' '.join(output))
2857 fm.end()
2857 fm.end()
2858
2858
2859 @command('import|patch',
2859 @command('import|patch',
2860 [('p', 'strip', 1,
2860 [('p', 'strip', 1,
2861 _('directory strip option for patch. This has the same '
2861 _('directory strip option for patch. This has the same '
2862 'meaning as the corresponding patch option'), _('NUM')),
2862 'meaning as the corresponding patch option'), _('NUM')),
2863 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2863 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2864 ('e', 'edit', False, _('invoke editor on commit messages')),
2864 ('e', 'edit', False, _('invoke editor on commit messages')),
2865 ('f', 'force', None,
2865 ('f', 'force', None,
2866 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2866 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2867 ('', 'no-commit', None,
2867 ('', 'no-commit', None,
2868 _("don't commit, just update the working directory")),
2868 _("don't commit, just update the working directory")),
2869 ('', 'bypass', None,
2869 ('', 'bypass', None,
2870 _("apply patch without touching the working directory")),
2870 _("apply patch without touching the working directory")),
2871 ('', 'partial', None,
2871 ('', 'partial', None,
2872 _('commit even if some hunks fail')),
2872 _('commit even if some hunks fail')),
2873 ('', 'exact', None,
2873 ('', 'exact', None,
2874 _('abort if patch would apply lossily')),
2874 _('abort if patch would apply lossily')),
2875 ('', 'prefix', '',
2875 ('', 'prefix', '',
2876 _('apply patch to subdirectory'), _('DIR')),
2876 _('apply patch to subdirectory'), _('DIR')),
2877 ('', 'import-branch', None,
2877 ('', 'import-branch', None,
2878 _('use any branch information in patch (implied by --exact)'))] +
2878 _('use any branch information in patch (implied by --exact)'))] +
2879 commitopts + commitopts2 + similarityopts,
2879 commitopts + commitopts2 + similarityopts,
2880 _('[OPTION]... PATCH...'))
2880 _('[OPTION]... PATCH...'))
2881 def import_(ui, repo, patch1=None, *patches, **opts):
2881 def import_(ui, repo, patch1=None, *patches, **opts):
2882 """import an ordered set of patches
2882 """import an ordered set of patches
2883
2883
2884 Import a list of patches and commit them individually (unless
2884 Import a list of patches and commit them individually (unless
2885 --no-commit is specified).
2885 --no-commit is specified).
2886
2886
2887 To read a patch from standard input (stdin), use "-" as the patch
2887 To read a patch from standard input (stdin), use "-" as the patch
2888 name. If a URL is specified, the patch will be downloaded from
2888 name. If a URL is specified, the patch will be downloaded from
2889 there.
2889 there.
2890
2890
2891 Import first applies changes to the working directory (unless
2891 Import first applies changes to the working directory (unless
2892 --bypass is specified), import will abort if there are outstanding
2892 --bypass is specified), import will abort if there are outstanding
2893 changes.
2893 changes.
2894
2894
2895 Use --bypass to apply and commit patches directly to the
2895 Use --bypass to apply and commit patches directly to the
2896 repository, without affecting the working directory. Without
2896 repository, without affecting the working directory. Without
2897 --exact, patches will be applied on top of the working directory
2897 --exact, patches will be applied on top of the working directory
2898 parent revision.
2898 parent revision.
2899
2899
2900 You can import a patch straight from a mail message. Even patches
2900 You can import a patch straight from a mail message. Even patches
2901 as attachments work (to use the body part, it must have type
2901 as attachments work (to use the body part, it must have type
2902 text/plain or text/x-patch). From and Subject headers of email
2902 text/plain or text/x-patch). From and Subject headers of email
2903 message are used as default committer and commit message. All
2903 message are used as default committer and commit message. All
2904 text/plain body parts before first diff are added to the commit
2904 text/plain body parts before first diff are added to the commit
2905 message.
2905 message.
2906
2906
2907 If the imported patch was generated by :hg:`export`, user and
2907 If the imported patch was generated by :hg:`export`, user and
2908 description from patch override values from message headers and
2908 description from patch override values from message headers and
2909 body. Values given on command line with -m/--message and -u/--user
2909 body. Values given on command line with -m/--message and -u/--user
2910 override these.
2910 override these.
2911
2911
2912 If --exact is specified, import will set the working directory to
2912 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
2913 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
2914 resulting changeset has a different ID than the one recorded in
2915 the patch. This will guard against various ways that portable
2915 the patch. This will guard against various ways that portable
2916 patch formats and mail systems might fail to transfer Mercurial
2916 patch formats and mail systems might fail to transfer Mercurial
2917 data or metadata. See :hg:`bundle` for lossless transmission.
2917 data or metadata. See :hg:`bundle` for lossless transmission.
2918
2918
2919 Use --partial to ensure a changeset will be created from the patch
2919 Use --partial to ensure a changeset will be created from the patch
2920 even if some hunks fail to apply. Hunks that fail to apply will be
2920 even if some hunks fail to apply. Hunks that fail to apply will be
2921 written to a <target-file>.rej file. Conflicts can then be resolved
2921 written to a <target-file>.rej file. Conflicts can then be resolved
2922 by hand before :hg:`commit --amend` is run to update the created
2922 by hand before :hg:`commit --amend` is run to update the created
2923 changeset. This flag exists to let people import patches that
2923 changeset. This flag exists to let people import patches that
2924 partially apply without losing the associated metadata (author,
2924 partially apply without losing the associated metadata (author,
2925 date, description, ...).
2925 date, description, ...).
2926
2926
2927 .. note::
2927 .. note::
2928
2928
2929 When no hunks apply cleanly, :hg:`import --partial` will create
2929 When no hunks apply cleanly, :hg:`import --partial` will create
2930 an empty changeset, importing only the patch metadata.
2930 an empty changeset, importing only the patch metadata.
2931
2931
2932 With -s/--similarity, hg will attempt to discover renames and
2932 With -s/--similarity, hg will attempt to discover renames and
2933 copies in the patch in the same way as :hg:`addremove`.
2933 copies in the patch in the same way as :hg:`addremove`.
2934
2934
2935 It is possible to use external patch programs to perform the patch
2935 It is possible to use external patch programs to perform the patch
2936 by setting the ``ui.patch`` configuration option. For the default
2936 by setting the ``ui.patch`` configuration option. For the default
2937 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2937 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2938 See :hg:`help config` for more information about configuration
2938 See :hg:`help config` for more information about configuration
2939 files and how to use these options.
2939 files and how to use these options.
2940
2940
2941 See :hg:`help dates` for a list of formats valid for -d/--date.
2941 See :hg:`help dates` for a list of formats valid for -d/--date.
2942
2942
2943 .. container:: verbose
2943 .. container:: verbose
2944
2944
2945 Examples:
2945 Examples:
2946
2946
2947 - import a traditional patch from a website and detect renames::
2947 - import a traditional patch from a website and detect renames::
2948
2948
2949 hg import -s 80 http://example.com/bugfix.patch
2949 hg import -s 80 http://example.com/bugfix.patch
2950
2950
2951 - import a changeset from an hgweb server::
2951 - import a changeset from an hgweb server::
2952
2952
2953 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2953 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2954
2954
2955 - import all the patches in an Unix-style mbox::
2955 - import all the patches in an Unix-style mbox::
2956
2956
2957 hg import incoming-patches.mbox
2957 hg import incoming-patches.mbox
2958
2958
2959 - import patches from stdin::
2959 - import patches from stdin::
2960
2960
2961 hg import -
2961 hg import -
2962
2962
2963 - attempt to exactly restore an exported changeset (not always
2963 - attempt to exactly restore an exported changeset (not always
2964 possible)::
2964 possible)::
2965
2965
2966 hg import --exact proposed-fix.patch
2966 hg import --exact proposed-fix.patch
2967
2967
2968 - use an external tool to apply a patch which is too fuzzy for
2968 - use an external tool to apply a patch which is too fuzzy for
2969 the default internal tool.
2969 the default internal tool.
2970
2970
2971 hg import --config ui.patch="patch --merge" fuzzy.patch
2971 hg import --config ui.patch="patch --merge" fuzzy.patch
2972
2972
2973 - change the default fuzzing from 2 to a less strict 7
2973 - change the default fuzzing from 2 to a less strict 7
2974
2974
2975 hg import --config ui.fuzz=7 fuzz.patch
2975 hg import --config ui.fuzz=7 fuzz.patch
2976
2976
2977 Returns 0 on success, 1 on partial success (see --partial).
2977 Returns 0 on success, 1 on partial success (see --partial).
2978 """
2978 """
2979
2979
2980 opts = pycompat.byteskwargs(opts)
2980 opts = pycompat.byteskwargs(opts)
2981 if not patch1:
2981 if not patch1:
2982 raise error.Abort(_('need at least one patch to import'))
2982 raise error.Abort(_('need at least one patch to import'))
2983
2983
2984 patches = (patch1,) + patches
2984 patches = (patch1,) + patches
2985
2985
2986 date = opts.get('date')
2986 date = opts.get('date')
2987 if date:
2987 if date:
2988 opts['date'] = util.parsedate(date)
2988 opts['date'] = util.parsedate(date)
2989
2989
2990 exact = opts.get('exact')
2990 exact = opts.get('exact')
2991 update = not opts.get('bypass')
2991 update = not opts.get('bypass')
2992 if not update and opts.get('no_commit'):
2992 if not update and opts.get('no_commit'):
2993 raise error.Abort(_('cannot use --no-commit with --bypass'))
2993 raise error.Abort(_('cannot use --no-commit with --bypass'))
2994 try:
2994 try:
2995 sim = float(opts.get('similarity') or 0)
2995 sim = float(opts.get('similarity') or 0)
2996 except ValueError:
2996 except ValueError:
2997 raise error.Abort(_('similarity must be a number'))
2997 raise error.Abort(_('similarity must be a number'))
2998 if sim < 0 or sim > 100:
2998 if sim < 0 or sim > 100:
2999 raise error.Abort(_('similarity must be between 0 and 100'))
2999 raise error.Abort(_('similarity must be between 0 and 100'))
3000 if sim and not update:
3000 if sim and not update:
3001 raise error.Abort(_('cannot use --similarity with --bypass'))
3001 raise error.Abort(_('cannot use --similarity with --bypass'))
3002 if exact:
3002 if exact:
3003 if opts.get('edit'):
3003 if opts.get('edit'):
3004 raise error.Abort(_('cannot use --exact with --edit'))
3004 raise error.Abort(_('cannot use --exact with --edit'))
3005 if opts.get('prefix'):
3005 if opts.get('prefix'):
3006 raise error.Abort(_('cannot use --exact with --prefix'))
3006 raise error.Abort(_('cannot use --exact with --prefix'))
3007
3007
3008 base = opts["base"]
3008 base = opts["base"]
3009 wlock = dsguard = lock = tr = None
3009 wlock = dsguard = lock = tr = None
3010 msgs = []
3010 msgs = []
3011 ret = 0
3011 ret = 0
3012
3012
3013
3013
3014 try:
3014 try:
3015 wlock = repo.wlock()
3015 wlock = repo.wlock()
3016
3016
3017 if update:
3017 if update:
3018 cmdutil.checkunfinished(repo)
3018 cmdutil.checkunfinished(repo)
3019 if (exact or not opts.get('force')):
3019 if (exact or not opts.get('force')):
3020 cmdutil.bailifchanged(repo)
3020 cmdutil.bailifchanged(repo)
3021
3021
3022 if not opts.get('no_commit'):
3022 if not opts.get('no_commit'):
3023 lock = repo.lock()
3023 lock = repo.lock()
3024 tr = repo.transaction('import')
3024 tr = repo.transaction('import')
3025 else:
3025 else:
3026 dsguard = dirstateguard.dirstateguard(repo, 'import')
3026 dsguard = dirstateguard.dirstateguard(repo, 'import')
3027 parents = repo[None].parents()
3027 parents = repo[None].parents()
3028 for patchurl in patches:
3028 for patchurl in patches:
3029 if patchurl == '-':
3029 if patchurl == '-':
3030 ui.status(_('applying patch from stdin\n'))
3030 ui.status(_('applying patch from stdin\n'))
3031 patchfile = ui.fin
3031 patchfile = ui.fin
3032 patchurl = 'stdin' # for error message
3032 patchurl = 'stdin' # for error message
3033 else:
3033 else:
3034 patchurl = os.path.join(base, patchurl)
3034 patchurl = os.path.join(base, patchurl)
3035 ui.status(_('applying %s\n') % patchurl)
3035 ui.status(_('applying %s\n') % patchurl)
3036 patchfile = hg.openpath(ui, patchurl)
3036 patchfile = hg.openpath(ui, patchurl)
3037
3037
3038 haspatch = False
3038 haspatch = False
3039 for hunk in patch.split(patchfile):
3039 for hunk in patch.split(patchfile):
3040 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3040 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3041 parents, opts,
3041 parents, opts,
3042 msgs, hg.clean)
3042 msgs, hg.clean)
3043 if msg:
3043 if msg:
3044 haspatch = True
3044 haspatch = True
3045 ui.note(msg + '\n')
3045 ui.note(msg + '\n')
3046 if update or exact:
3046 if update or exact:
3047 parents = repo[None].parents()
3047 parents = repo[None].parents()
3048 else:
3048 else:
3049 parents = [repo[node]]
3049 parents = [repo[node]]
3050 if rej:
3050 if rej:
3051 ui.write_err(_("patch applied partially\n"))
3051 ui.write_err(_("patch applied partially\n"))
3052 ui.write_err(_("(fix the .rej files and run "
3052 ui.write_err(_("(fix the .rej files and run "
3053 "`hg commit --amend`)\n"))
3053 "`hg commit --amend`)\n"))
3054 ret = 1
3054 ret = 1
3055 break
3055 break
3056
3056
3057 if not haspatch:
3057 if not haspatch:
3058 raise error.Abort(_('%s: no diffs found') % patchurl)
3058 raise error.Abort(_('%s: no diffs found') % patchurl)
3059
3059
3060 if tr:
3060 if tr:
3061 tr.close()
3061 tr.close()
3062 if msgs:
3062 if msgs:
3063 repo.savecommitmessage('\n* * *\n'.join(msgs))
3063 repo.savecommitmessage('\n* * *\n'.join(msgs))
3064 if dsguard:
3064 if dsguard:
3065 dsguard.close()
3065 dsguard.close()
3066 return ret
3066 return ret
3067 finally:
3067 finally:
3068 if tr:
3068 if tr:
3069 tr.release()
3069 tr.release()
3070 release(lock, dsguard, wlock)
3070 release(lock, dsguard, wlock)
3071
3071
3072 @command('incoming|in',
3072 @command('incoming|in',
3073 [('f', 'force', None,
3073 [('f', 'force', None,
3074 _('run even if remote repository is unrelated')),
3074 _('run even if remote repository is unrelated')),
3075 ('n', 'newest-first', None, _('show newest record first')),
3075 ('n', 'newest-first', None, _('show newest record first')),
3076 ('', 'bundle', '',
3076 ('', 'bundle', '',
3077 _('file to store the bundles into'), _('FILE')),
3077 _('file to store the bundles into'), _('FILE')),
3078 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3078 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3079 ('B', 'bookmarks', False, _("compare bookmarks")),
3079 ('B', 'bookmarks', False, _("compare bookmarks")),
3080 ('b', 'branch', [],
3080 ('b', 'branch', [],
3081 _('a specific branch you would like to pull'), _('BRANCH')),
3081 _('a specific branch you would like to pull'), _('BRANCH')),
3082 ] + logopts + remoteopts + subrepoopts,
3082 ] + logopts + remoteopts + subrepoopts,
3083 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3083 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3084 def incoming(ui, repo, source="default", **opts):
3084 def incoming(ui, repo, source="default", **opts):
3085 """show new changesets found in source
3085 """show new changesets found in source
3086
3086
3087 Show new changesets found in the specified path/URL or the default
3087 Show new changesets found in the specified path/URL or the default
3088 pull location. These are the changesets that would have been pulled
3088 pull location. These are the changesets that would have been pulled
3089 by :hg:`pull` at the time you issued this command.
3089 by :hg:`pull` at the time you issued this command.
3090
3090
3091 See pull for valid source format details.
3091 See pull for valid source format details.
3092
3092
3093 .. container:: verbose
3093 .. container:: verbose
3094
3094
3095 With -B/--bookmarks, the result of bookmark comparison between
3095 With -B/--bookmarks, the result of bookmark comparison between
3096 local and remote repositories is displayed. With -v/--verbose,
3096 local and remote repositories is displayed. With -v/--verbose,
3097 status is also displayed for each bookmark like below::
3097 status is also displayed for each bookmark like below::
3098
3098
3099 BM1 01234567890a added
3099 BM1 01234567890a added
3100 BM2 1234567890ab advanced
3100 BM2 1234567890ab advanced
3101 BM3 234567890abc diverged
3101 BM3 234567890abc diverged
3102 BM4 34567890abcd changed
3102 BM4 34567890abcd changed
3103
3103
3104 The action taken locally when pulling depends on the
3104 The action taken locally when pulling depends on the
3105 status of each bookmark:
3105 status of each bookmark:
3106
3106
3107 :``added``: pull will create it
3107 :``added``: pull will create it
3108 :``advanced``: pull will update it
3108 :``advanced``: pull will update it
3109 :``diverged``: pull will create a divergent bookmark
3109 :``diverged``: pull will create a divergent bookmark
3110 :``changed``: result depends on remote changesets
3110 :``changed``: result depends on remote changesets
3111
3111
3112 From the point of view of pulling behavior, bookmark
3112 From the point of view of pulling behavior, bookmark
3113 existing only in the remote repository are treated as ``added``,
3113 existing only in the remote repository are treated as ``added``,
3114 even if it is in fact locally deleted.
3114 even if it is in fact locally deleted.
3115
3115
3116 .. container:: verbose
3116 .. container:: verbose
3117
3117
3118 For remote repository, using --bundle avoids downloading the
3118 For remote repository, using --bundle avoids downloading the
3119 changesets twice if the incoming is followed by a pull.
3119 changesets twice if the incoming is followed by a pull.
3120
3120
3121 Examples:
3121 Examples:
3122
3122
3123 - show incoming changes with patches and full description::
3123 - show incoming changes with patches and full description::
3124
3124
3125 hg incoming -vp
3125 hg incoming -vp
3126
3126
3127 - show incoming changes excluding merges, store a bundle::
3127 - show incoming changes excluding merges, store a bundle::
3128
3128
3129 hg in -vpM --bundle incoming.hg
3129 hg in -vpM --bundle incoming.hg
3130 hg pull incoming.hg
3130 hg pull incoming.hg
3131
3131
3132 - briefly list changes inside a bundle::
3132 - briefly list changes inside a bundle::
3133
3133
3134 hg in changes.hg -T "{desc|firstline}\\n"
3134 hg in changes.hg -T "{desc|firstline}\\n"
3135
3135
3136 Returns 0 if there are incoming changes, 1 otherwise.
3136 Returns 0 if there are incoming changes, 1 otherwise.
3137 """
3137 """
3138 opts = pycompat.byteskwargs(opts)
3138 opts = pycompat.byteskwargs(opts)
3139 if opts.get('graph'):
3139 if opts.get('graph'):
3140 cmdutil.checkunsupportedgraphflags([], opts)
3140 cmdutil.checkunsupportedgraphflags([], opts)
3141 def display(other, chlist, displayer):
3141 def display(other, chlist, displayer):
3142 revdag = cmdutil.graphrevs(other, chlist, opts)
3142 revdag = cmdutil.graphrevs(other, chlist, opts)
3143 cmdutil.displaygraph(ui, repo, revdag, displayer,
3143 cmdutil.displaygraph(ui, repo, revdag, displayer,
3144 graphmod.asciiedges)
3144 graphmod.asciiedges)
3145
3145
3146 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3146 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3147 return 0
3147 return 0
3148
3148
3149 if opts.get('bundle') and opts.get('subrepos'):
3149 if opts.get('bundle') and opts.get('subrepos'):
3150 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3150 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3151
3151
3152 if opts.get('bookmarks'):
3152 if opts.get('bookmarks'):
3153 source, branches = hg.parseurl(ui.expandpath(source),
3153 source, branches = hg.parseurl(ui.expandpath(source),
3154 opts.get('branch'))
3154 opts.get('branch'))
3155 other = hg.peer(repo, opts, source)
3155 other = hg.peer(repo, opts, source)
3156 if 'bookmarks' not in other.listkeys('namespaces'):
3156 if 'bookmarks' not in other.listkeys('namespaces'):
3157 ui.warn(_("remote doesn't support bookmarks\n"))
3157 ui.warn(_("remote doesn't support bookmarks\n"))
3158 return 0
3158 return 0
3159 ui.pager('incoming')
3159 ui.pager('incoming')
3160 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3160 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3161 return bookmarks.incoming(ui, repo, other)
3161 return bookmarks.incoming(ui, repo, other)
3162
3162
3163 repo._subtoppath = ui.expandpath(source)
3163 repo._subtoppath = ui.expandpath(source)
3164 try:
3164 try:
3165 return hg.incoming(ui, repo, source, opts)
3165 return hg.incoming(ui, repo, source, opts)
3166 finally:
3166 finally:
3167 del repo._subtoppath
3167 del repo._subtoppath
3168
3168
3169
3169
3170 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3170 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3171 norepo=True)
3171 norepo=True)
3172 def init(ui, dest=".", **opts):
3172 def init(ui, dest=".", **opts):
3173 """create a new repository in the given directory
3173 """create a new repository in the given directory
3174
3174
3175 Initialize a new repository in the given directory. If the given
3175 Initialize a new repository in the given directory. If the given
3176 directory does not exist, it will be created.
3176 directory does not exist, it will be created.
3177
3177
3178 If no directory is given, the current directory is used.
3178 If no directory is given, the current directory is used.
3179
3179
3180 It is possible to specify an ``ssh://`` URL as the destination.
3180 It is possible to specify an ``ssh://`` URL as the destination.
3181 See :hg:`help urls` for more information.
3181 See :hg:`help urls` for more information.
3182
3182
3183 Returns 0 on success.
3183 Returns 0 on success.
3184 """
3184 """
3185 opts = pycompat.byteskwargs(opts)
3185 opts = pycompat.byteskwargs(opts)
3186 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3186 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3187
3187
3188 @command('locate',
3188 @command('locate',
3189 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3189 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3190 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3190 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3191 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3191 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3192 ] + walkopts,
3192 ] + walkopts,
3193 _('[OPTION]... [PATTERN]...'))
3193 _('[OPTION]... [PATTERN]...'))
3194 def locate(ui, repo, *pats, **opts):
3194 def locate(ui, repo, *pats, **opts):
3195 """locate files matching specific patterns (DEPRECATED)
3195 """locate files matching specific patterns (DEPRECATED)
3196
3196
3197 Print files under Mercurial control in the working directory whose
3197 Print files under Mercurial control in the working directory whose
3198 names match the given patterns.
3198 names match the given patterns.
3199
3199
3200 By default, this command searches all directories in the working
3200 By default, this command searches all directories in the working
3201 directory. To search just the current directory and its
3201 directory. To search just the current directory and its
3202 subdirectories, use "--include .".
3202 subdirectories, use "--include .".
3203
3203
3204 If no patterns are given to match, this command prints the names
3204 If no patterns are given to match, this command prints the names
3205 of all files under Mercurial control in the working directory.
3205 of all files under Mercurial control in the working directory.
3206
3206
3207 If you want to feed the output of this command into the "xargs"
3207 If you want to feed the output of this command into the "xargs"
3208 command, use the -0 option to both this command and "xargs". This
3208 command, use the -0 option to both this command and "xargs". This
3209 will avoid the problem of "xargs" treating single filenames that
3209 will avoid the problem of "xargs" treating single filenames that
3210 contain whitespace as multiple filenames.
3210 contain whitespace as multiple filenames.
3211
3211
3212 See :hg:`help files` for a more versatile command.
3212 See :hg:`help files` for a more versatile command.
3213
3213
3214 Returns 0 if a match is found, 1 otherwise.
3214 Returns 0 if a match is found, 1 otherwise.
3215 """
3215 """
3216 opts = pycompat.byteskwargs(opts)
3216 opts = pycompat.byteskwargs(opts)
3217 if opts.get('print0'):
3217 if opts.get('print0'):
3218 end = '\0'
3218 end = '\0'
3219 else:
3219 else:
3220 end = '\n'
3220 end = '\n'
3221 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3221 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3222
3222
3223 ret = 1
3223 ret = 1
3224 ctx = repo[rev]
3224 ctx = repo[rev]
3225 m = scmutil.match(ctx, pats, opts, default='relglob',
3225 m = scmutil.match(ctx, pats, opts, default='relglob',
3226 badfn=lambda x, y: False)
3226 badfn=lambda x, y: False)
3227
3227
3228 ui.pager('locate')
3228 ui.pager('locate')
3229 for abs in ctx.matches(m):
3229 for abs in ctx.matches(m):
3230 if opts.get('fullpath'):
3230 if opts.get('fullpath'):
3231 ui.write(repo.wjoin(abs), end)
3231 ui.write(repo.wjoin(abs), end)
3232 else:
3232 else:
3233 ui.write(((pats and m.rel(abs)) or abs), end)
3233 ui.write(((pats and m.rel(abs)) or abs), end)
3234 ret = 0
3234 ret = 0
3235
3235
3236 return ret
3236 return ret
3237
3237
3238 @command('^log|history',
3238 @command('^log|history',
3239 [('f', 'follow', None,
3239 [('f', 'follow', None,
3240 _('follow changeset history, or file history across copies and renames')),
3240 _('follow changeset history, or file history across copies and renames')),
3241 ('', 'follow-first', None,
3241 ('', 'follow-first', None,
3242 _('only follow the first parent of merge changesets (DEPRECATED)')),
3242 _('only follow the first parent of merge changesets (DEPRECATED)')),
3243 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3243 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3244 ('C', 'copies', None, _('show copied files')),
3244 ('C', 'copies', None, _('show copied files')),
3245 ('k', 'keyword', [],
3245 ('k', 'keyword', [],
3246 _('do case-insensitive search for a given text'), _('TEXT')),
3246 _('do case-insensitive search for a given text'), _('TEXT')),
3247 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3247 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3248 ('L', 'line-range', [],
3248 ('L', 'line-range', [],
3249 _('follow line range of specified file (EXPERIMENTAL)'),
3249 _('follow line range of specified file (EXPERIMENTAL)'),
3250 _('FILE,RANGE')),
3250 _('FILE,RANGE')),
3251 ('', 'removed', None, _('include revisions where files were removed')),
3251 ('', 'removed', None, _('include revisions where files were removed')),
3252 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3252 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3253 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3253 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3254 ('', 'only-branch', [],
3254 ('', 'only-branch', [],
3255 _('show only changesets within the given named branch (DEPRECATED)'),
3255 _('show only changesets within the given named branch (DEPRECATED)'),
3256 _('BRANCH')),
3256 _('BRANCH')),
3257 ('b', 'branch', [],
3257 ('b', 'branch', [],
3258 _('show changesets within the given named branch'), _('BRANCH')),
3258 _('show changesets within the given named branch'), _('BRANCH')),
3259 ('P', 'prune', [],
3259 ('P', 'prune', [],
3260 _('do not display revision or any of its ancestors'), _('REV')),
3260 _('do not display revision or any of its ancestors'), _('REV')),
3261 ] + logopts + walkopts,
3261 ] + logopts + walkopts,
3262 _('[OPTION]... [FILE]'),
3262 _('[OPTION]... [FILE]'),
3263 inferrepo=True, cmdtype=readonly)
3263 inferrepo=True, cmdtype=readonly)
3264 def log(ui, repo, *pats, **opts):
3264 def log(ui, repo, *pats, **opts):
3265 """show revision history of entire repository or files
3265 """show revision history of entire repository or files
3266
3266
3267 Print the revision history of the specified files or the entire
3267 Print the revision history of the specified files or the entire
3268 project.
3268 project.
3269
3269
3270 If no revision range is specified, the default is ``tip:0`` unless
3270 If no revision range is specified, the default is ``tip:0`` unless
3271 --follow is set, in which case the working directory parent is
3271 --follow is set, in which case the working directory parent is
3272 used as the starting revision.
3272 used as the starting revision.
3273
3273
3274 File history is shown without following rename or copy history of
3274 File history is shown without following rename or copy history of
3275 files. Use -f/--follow with a filename to follow history across
3275 files. Use -f/--follow with a filename to follow history across
3276 renames and copies. --follow without a filename will only show
3276 renames and copies. --follow without a filename will only show
3277 ancestors or descendants of the starting revision.
3277 ancestors or descendants of the starting revision.
3278
3278
3279 By default this command prints revision number and changeset id,
3279 By default this command prints revision number and changeset id,
3280 tags, non-trivial parents, user, date and time, and a summary for
3280 tags, non-trivial parents, user, date and time, and a summary for
3281 each commit. When the -v/--verbose switch is used, the list of
3281 each commit. When the -v/--verbose switch is used, the list of
3282 changed files and full commit message are shown.
3282 changed files and full commit message are shown.
3283
3283
3284 With --graph the revisions are shown as an ASCII art DAG with the most
3284 With --graph the revisions are shown as an ASCII art DAG with the most
3285 recent changeset at the top.
3285 recent changeset at the top.
3286 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3286 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3287 and '+' represents a fork where the changeset from the lines below is a
3287 and '+' represents a fork where the changeset from the lines below is a
3288 parent of the 'o' merge on the same line.
3288 parent of the 'o' merge on the same line.
3289 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3289 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3290 of a '|' indicates one or more revisions in a path are omitted.
3290 of a '|' indicates one or more revisions in a path are omitted.
3291
3291
3292 .. container:: verbose
3292 .. container:: verbose
3293
3293
3294 Use -L/--line-range FILE,M:N options to follow the history of lines
3294 Use -L/--line-range FILE,M:N options to follow the history of lines
3295 from M to N in FILE. With -p/--patch only diff hunks affecting
3295 from M to N in FILE. With -p/--patch only diff hunks affecting
3296 specified line range will be shown. This option requires --follow;
3296 specified line range will be shown. This option requires --follow;
3297 it can be specified multiple times. Currently, this option is not
3297 it can be specified multiple times. Currently, this option is not
3298 compatible with --graph. This option is experimental.
3298 compatible with --graph. This option is experimental.
3299
3299
3300 .. note::
3300 .. note::
3301
3301
3302 :hg:`log --patch` may generate unexpected diff output for merge
3302 :hg:`log --patch` may generate unexpected diff output for merge
3303 changesets, as it will only compare the merge changeset against
3303 changesets, as it will only compare the merge changeset against
3304 its first parent. Also, only files different from BOTH parents
3304 its first parent. Also, only files different from BOTH parents
3305 will appear in files:.
3305 will appear in files:.
3306
3306
3307 .. note::
3307 .. note::
3308
3308
3309 For performance reasons, :hg:`log FILE` may omit duplicate changes
3309 For performance reasons, :hg:`log FILE` may omit duplicate changes
3310 made on branches and will not show removals or mode changes. To
3310 made on branches and will not show removals or mode changes. To
3311 see all such changes, use the --removed switch.
3311 see all such changes, use the --removed switch.
3312
3312
3313 .. container:: verbose
3313 .. container:: verbose
3314
3314
3315 .. note::
3315 .. note::
3316
3316
3317 The history resulting from -L/--line-range options depends on diff
3317 The history resulting from -L/--line-range options depends on diff
3318 options; for instance if white-spaces are ignored, respective changes
3318 options; for instance if white-spaces are ignored, respective changes
3319 with only white-spaces in specified line range will not be listed.
3319 with only white-spaces in specified line range will not be listed.
3320
3320
3321 .. container:: verbose
3321 .. container:: verbose
3322
3322
3323 Some examples:
3323 Some examples:
3324
3324
3325 - changesets with full descriptions and file lists::
3325 - changesets with full descriptions and file lists::
3326
3326
3327 hg log -v
3327 hg log -v
3328
3328
3329 - changesets ancestral to the working directory::
3329 - changesets ancestral to the working directory::
3330
3330
3331 hg log -f
3331 hg log -f
3332
3332
3333 - last 10 commits on the current branch::
3333 - last 10 commits on the current branch::
3334
3334
3335 hg log -l 10 -b .
3335 hg log -l 10 -b .
3336
3336
3337 - changesets showing all modifications of a file, including removals::
3337 - changesets showing all modifications of a file, including removals::
3338
3338
3339 hg log --removed file.c
3339 hg log --removed file.c
3340
3340
3341 - all changesets that touch a directory, with diffs, excluding merges::
3341 - all changesets that touch a directory, with diffs, excluding merges::
3342
3342
3343 hg log -Mp lib/
3343 hg log -Mp lib/
3344
3344
3345 - all revision numbers that match a keyword::
3345 - all revision numbers that match a keyword::
3346
3346
3347 hg log -k bug --template "{rev}\\n"
3347 hg log -k bug --template "{rev}\\n"
3348
3348
3349 - the full hash identifier of the working directory parent::
3349 - the full hash identifier of the working directory parent::
3350
3350
3351 hg log -r . --template "{node}\\n"
3351 hg log -r . --template "{node}\\n"
3352
3352
3353 - list available log templates::
3353 - list available log templates::
3354
3354
3355 hg log -T list
3355 hg log -T list
3356
3356
3357 - check if a given changeset is included in a tagged release::
3357 - check if a given changeset is included in a tagged release::
3358
3358
3359 hg log -r "a21ccf and ancestor(1.9)"
3359 hg log -r "a21ccf and ancestor(1.9)"
3360
3360
3361 - find all changesets by some user in a date range::
3361 - find all changesets by some user in a date range::
3362
3362
3363 hg log -k alice -d "may 2008 to jul 2008"
3363 hg log -k alice -d "may 2008 to jul 2008"
3364
3364
3365 - summary of all changesets after the last tag::
3365 - summary of all changesets after the last tag::
3366
3366
3367 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3367 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3368
3368
3369 - changesets touching lines 13 to 23 for file.c::
3369 - changesets touching lines 13 to 23 for file.c::
3370
3370
3371 hg log -L file.c,13:23
3371 hg log -L file.c,13:23
3372
3372
3373 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3373 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3374 main.c with patch::
3374 main.c with patch::
3375
3375
3376 hg log -L file.c,13:23 -L main.c,2:6 -p
3376 hg log -L file.c,13:23 -L main.c,2:6 -p
3377
3377
3378 See :hg:`help dates` for a list of formats valid for -d/--date.
3378 See :hg:`help dates` for a list of formats valid for -d/--date.
3379
3379
3380 See :hg:`help revisions` for more about specifying and ordering
3380 See :hg:`help revisions` for more about specifying and ordering
3381 revisions.
3381 revisions.
3382
3382
3383 See :hg:`help templates` for more about pre-packaged styles and
3383 See :hg:`help templates` for more about pre-packaged styles and
3384 specifying custom templates. The default template used by the log
3384 specifying custom templates. The default template used by the log
3385 command can be customized via the ``ui.logtemplate`` configuration
3385 command can be customized via the ``ui.logtemplate`` configuration
3386 setting.
3386 setting.
3387
3387
3388 Returns 0 on success.
3388 Returns 0 on success.
3389
3389
3390 """
3390 """
3391 opts = pycompat.byteskwargs(opts)
3391 opts = pycompat.byteskwargs(opts)
3392 linerange = opts.get('line_range')
3392 linerange = opts.get('line_range')
3393
3393
3394 if linerange and not opts.get('follow'):
3394 if linerange and not opts.get('follow'):
3395 raise error.Abort(_('--line-range requires --follow'))
3395 raise error.Abort(_('--line-range requires --follow'))
3396
3396
3397 if linerange and pats:
3397 if linerange and pats:
3398 raise error.Abort(
3398 raise error.Abort(
3399 _('FILE arguments are not compatible with --line-range option')
3399 _('FILE arguments are not compatible with --line-range option')
3400 )
3400 )
3401
3401
3402 if opts.get('follow') and opts.get('rev'):
3402 if opts.get('follow') and opts.get('rev'):
3403 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3403 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3404 del opts['follow']
3404 del opts['follow']
3405
3405
3406 if opts.get('graph'):
3406 if opts.get('graph'):
3407 if linerange:
3407 if linerange:
3408 raise error.Abort(_('graph not supported with line range patterns'))
3408 raise error.Abort(_('graph not supported with line range patterns'))
3409 return cmdutil.graphlog(ui, repo, pats, opts)
3409 return cmdutil.graphlog(ui, repo, pats, opts)
3410
3410
3411 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3411 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3412 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3412 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3413 hunksfilter = None
3413 hunksfilter = None
3414
3414
3415 if linerange:
3415 if linerange:
3416 revs, lrfilematcher, hunksfilter = cmdutil.getloglinerangerevs(
3416 revs, lrfilematcher, hunksfilter = cmdutil.getloglinerangerevs(
3417 repo, revs, opts)
3417 repo, revs, opts)
3418
3418
3419 if filematcher is not None and lrfilematcher is not None:
3419 if filematcher is not None and lrfilematcher is not None:
3420 basefilematcher = filematcher
3420 basefilematcher = filematcher
3421
3421
3422 def filematcher(rev):
3422 def filematcher(rev):
3423 files = (basefilematcher(rev).files()
3423 files = (basefilematcher(rev).files()
3424 + lrfilematcher(rev).files())
3424 + lrfilematcher(rev).files())
3425 return scmutil.matchfiles(repo, files)
3425 return scmutil.matchfiles(repo, files)
3426
3426
3427 elif filematcher is None:
3427 elif filematcher is None:
3428 filematcher = lrfilematcher
3428 filematcher = lrfilematcher
3429
3429
3430 limit = cmdutil.loglimit(opts)
3430 limit = cmdutil.loglimit(opts)
3431 count = 0
3431 count = 0
3432
3432
3433 getrenamed = None
3433 getrenamed = None
3434 if opts.get('copies'):
3434 if opts.get('copies'):
3435 endrev = None
3435 endrev = None
3436 if opts.get('rev'):
3436 if opts.get('rev'):
3437 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3437 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3438 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3438 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3439
3439
3440 ui.pager('log')
3440 ui.pager('log')
3441 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3441 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3442 for rev in revs:
3442 for rev in revs:
3443 if count == limit:
3443 if count == limit:
3444 break
3444 break
3445 ctx = repo[rev]
3445 ctx = repo[rev]
3446 copies = None
3446 copies = None
3447 if getrenamed is not None and rev:
3447 if getrenamed is not None and rev:
3448 copies = []
3448 copies = []
3449 for fn in ctx.files():
3449 for fn in ctx.files():
3450 rename = getrenamed(fn, rev)
3450 rename = getrenamed(fn, rev)
3451 if rename:
3451 if rename:
3452 copies.append((fn, rename[0]))
3452 copies.append((fn, rename[0]))
3453 if filematcher:
3453 if filematcher:
3454 revmatchfn = filematcher(ctx.rev())
3454 revmatchfn = filematcher(ctx.rev())
3455 else:
3455 else:
3456 revmatchfn = None
3456 revmatchfn = None
3457 if hunksfilter:
3457 if hunksfilter:
3458 revhunksfilter = hunksfilter(rev)
3458 revhunksfilter = hunksfilter(rev)
3459 else:
3459 else:
3460 revhunksfilter = None
3460 revhunksfilter = None
3461 displayer.show(ctx, copies=copies, matchfn=revmatchfn,
3461 displayer.show(ctx, copies=copies, matchfn=revmatchfn,
3462 hunksfilterfn=revhunksfilter)
3462 hunksfilterfn=revhunksfilter)
3463 if displayer.flush(ctx):
3463 if displayer.flush(ctx):
3464 count += 1
3464 count += 1
3465
3465
3466 displayer.close()
3466 displayer.close()
3467
3467
3468 @command('manifest',
3468 @command('manifest',
3469 [('r', 'rev', '', _('revision to display'), _('REV')),
3469 [('r', 'rev', '', _('revision to display'), _('REV')),
3470 ('', 'all', False, _("list files from all revisions"))]
3470 ('', 'all', False, _("list files from all revisions"))]
3471 + formatteropts,
3471 + formatteropts,
3472 _('[-r REV]'), cmdtype=readonly)
3472 _('[-r REV]'), cmdtype=readonly)
3473 def manifest(ui, repo, node=None, rev=None, **opts):
3473 def manifest(ui, repo, node=None, rev=None, **opts):
3474 """output the current or given revision of the project manifest
3474 """output the current or given revision of the project manifest
3475
3475
3476 Print a list of version controlled files for the given revision.
3476 Print a list of version controlled files for the given revision.
3477 If no revision is given, the first parent of the working directory
3477 If no revision is given, the first parent of the working directory
3478 is used, or the null revision if no revision is checked out.
3478 is used, or the null revision if no revision is checked out.
3479
3479
3480 With -v, print file permissions, symlink and executable bits.
3480 With -v, print file permissions, symlink and executable bits.
3481 With --debug, print file revision hashes.
3481 With --debug, print file revision hashes.
3482
3482
3483 If option --all is specified, the list of all files from all revisions
3483 If option --all is specified, the list of all files from all revisions
3484 is printed. This includes deleted and renamed files.
3484 is printed. This includes deleted and renamed files.
3485
3485
3486 Returns 0 on success.
3486 Returns 0 on success.
3487 """
3487 """
3488 opts = pycompat.byteskwargs(opts)
3488 opts = pycompat.byteskwargs(opts)
3489 fm = ui.formatter('manifest', opts)
3489 fm = ui.formatter('manifest', opts)
3490
3490
3491 if opts.get('all'):
3491 if opts.get('all'):
3492 if rev or node:
3492 if rev or node:
3493 raise error.Abort(_("can't specify a revision with --all"))
3493 raise error.Abort(_("can't specify a revision with --all"))
3494
3494
3495 res = []
3495 res = []
3496 prefix = "data/"
3496 prefix = "data/"
3497 suffix = ".i"
3497 suffix = ".i"
3498 plen = len(prefix)
3498 plen = len(prefix)
3499 slen = len(suffix)
3499 slen = len(suffix)
3500 with repo.lock():
3500 with repo.lock():
3501 for fn, b, size in repo.store.datafiles():
3501 for fn, b, size in repo.store.datafiles():
3502 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3502 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3503 res.append(fn[plen:-slen])
3503 res.append(fn[plen:-slen])
3504 ui.pager('manifest')
3504 ui.pager('manifest')
3505 for f in res:
3505 for f in res:
3506 fm.startitem()
3506 fm.startitem()
3507 fm.write("path", '%s\n', f)
3507 fm.write("path", '%s\n', f)
3508 fm.end()
3508 fm.end()
3509 return
3509 return
3510
3510
3511 if rev and node:
3511 if rev and node:
3512 raise error.Abort(_("please specify just one revision"))
3512 raise error.Abort(_("please specify just one revision"))
3513
3513
3514 if not node:
3514 if not node:
3515 node = rev
3515 node = rev
3516
3516
3517 char = {'l': '@', 'x': '*', '': ''}
3517 char = {'l': '@', 'x': '*', '': ''}
3518 mode = {'l': '644', 'x': '755', '': '644'}
3518 mode = {'l': '644', 'x': '755', '': '644'}
3519 if node:
3519 if node:
3520 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3520 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3521 ctx = scmutil.revsingle(repo, node)
3521 ctx = scmutil.revsingle(repo, node)
3522 mf = ctx.manifest()
3522 mf = ctx.manifest()
3523 ui.pager('manifest')
3523 ui.pager('manifest')
3524 for f in ctx:
3524 for f in ctx:
3525 fm.startitem()
3525 fm.startitem()
3526 fl = ctx[f].flags()
3526 fl = ctx[f].flags()
3527 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3527 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3528 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3528 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3529 fm.write('path', '%s\n', f)
3529 fm.write('path', '%s\n', f)
3530 fm.end()
3530 fm.end()
3531
3531
3532 @command('^merge',
3532 @command('^merge',
3533 [('f', 'force', None,
3533 [('f', 'force', None,
3534 _('force a merge including outstanding changes (DEPRECATED)')),
3534 _('force a merge including outstanding changes (DEPRECATED)')),
3535 ('r', 'rev', '', _('revision to merge'), _('REV')),
3535 ('r', 'rev', '', _('revision to merge'), _('REV')),
3536 ('P', 'preview', None,
3536 ('P', 'preview', None,
3537 _('review revisions to merge (no merge is performed)'))
3537 _('review revisions to merge (no merge is performed)'))
3538 ] + mergetoolopts,
3538 ] + mergetoolopts,
3539 _('[-P] [[-r] REV]'))
3539 _('[-P] [[-r] REV]'))
3540 def merge(ui, repo, node=None, **opts):
3540 def merge(ui, repo, node=None, **opts):
3541 """merge another revision into working directory
3541 """merge another revision into working directory
3542
3542
3543 The current working directory is updated with all changes made in
3543 The current working directory is updated with all changes made in
3544 the requested revision since the last common predecessor revision.
3544 the requested revision since the last common predecessor revision.
3545
3545
3546 Files that changed between either parent are marked as changed for
3546 Files that changed between either parent are marked as changed for
3547 the next commit and a commit must be performed before any further
3547 the next commit and a commit must be performed before any further
3548 updates to the repository are allowed. The next commit will have
3548 updates to the repository are allowed. The next commit will have
3549 two parents.
3549 two parents.
3550
3550
3551 ``--tool`` can be used to specify the merge tool used for file
3551 ``--tool`` can be used to specify the merge tool used for file
3552 merges. It overrides the HGMERGE environment variable and your
3552 merges. It overrides the HGMERGE environment variable and your
3553 configuration files. See :hg:`help merge-tools` for options.
3553 configuration files. See :hg:`help merge-tools` for options.
3554
3554
3555 If no revision is specified, the working directory's parent is a
3555 If no revision is specified, the working directory's parent is a
3556 head revision, and the current branch contains exactly one other
3556 head revision, and the current branch contains exactly one other
3557 head, the other head is merged with by default. Otherwise, an
3557 head, the other head is merged with by default. Otherwise, an
3558 explicit revision with which to merge with must be provided.
3558 explicit revision with which to merge with must be provided.
3559
3559
3560 See :hg:`help resolve` for information on handling file conflicts.
3560 See :hg:`help resolve` for information on handling file conflicts.
3561
3561
3562 To undo an uncommitted merge, use :hg:`update --clean .` which
3562 To undo an uncommitted merge, use :hg:`update --clean .` which
3563 will check out a clean copy of the original merge parent, losing
3563 will check out a clean copy of the original merge parent, losing
3564 all changes.
3564 all changes.
3565
3565
3566 Returns 0 on success, 1 if there are unresolved files.
3566 Returns 0 on success, 1 if there are unresolved files.
3567 """
3567 """
3568
3568
3569 opts = pycompat.byteskwargs(opts)
3569 opts = pycompat.byteskwargs(opts)
3570 if opts.get('rev') and node:
3570 if opts.get('rev') and node:
3571 raise error.Abort(_("please specify just one revision"))
3571 raise error.Abort(_("please specify just one revision"))
3572 if not node:
3572 if not node:
3573 node = opts.get('rev')
3573 node = opts.get('rev')
3574
3574
3575 if node:
3575 if node:
3576 node = scmutil.revsingle(repo, node).node()
3576 node = scmutil.revsingle(repo, node).node()
3577
3577
3578 if not node:
3578 if not node:
3579 node = repo[destutil.destmerge(repo)].node()
3579 node = repo[destutil.destmerge(repo)].node()
3580
3580
3581 if opts.get('preview'):
3581 if opts.get('preview'):
3582 # find nodes that are ancestors of p2 but not of p1
3582 # find nodes that are ancestors of p2 but not of p1
3583 p1 = repo.lookup('.')
3583 p1 = repo.lookup('.')
3584 p2 = repo.lookup(node)
3584 p2 = repo.lookup(node)
3585 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3585 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3586
3586
3587 displayer = cmdutil.show_changeset(ui, repo, opts)
3587 displayer = cmdutil.show_changeset(ui, repo, opts)
3588 for node in nodes:
3588 for node in nodes:
3589 displayer.show(repo[node])
3589 displayer.show(repo[node])
3590 displayer.close()
3590 displayer.close()
3591 return 0
3591 return 0
3592
3592
3593 try:
3593 try:
3594 # ui.forcemerge is an internal variable, do not document
3594 # ui.forcemerge is an internal variable, do not document
3595 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3595 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3596 force = opts.get('force')
3596 force = opts.get('force')
3597 labels = ['working copy', 'merge rev']
3597 labels = ['working copy', 'merge rev']
3598 return hg.merge(repo, node, force=force, mergeforce=force,
3598 return hg.merge(repo, node, force=force, mergeforce=force,
3599 labels=labels)
3599 labels=labels)
3600 finally:
3600 finally:
3601 ui.setconfig('ui', 'forcemerge', '', 'merge')
3601 ui.setconfig('ui', 'forcemerge', '', 'merge')
3602
3602
3603 @command('outgoing|out',
3603 @command('outgoing|out',
3604 [('f', 'force', None, _('run even when the destination is unrelated')),
3604 [('f', 'force', None, _('run even when the destination is unrelated')),
3605 ('r', 'rev', [],
3605 ('r', 'rev', [],
3606 _('a changeset intended to be included in the destination'), _('REV')),
3606 _('a changeset intended to be included in the destination'), _('REV')),
3607 ('n', 'newest-first', None, _('show newest record first')),
3607 ('n', 'newest-first', None, _('show newest record first')),
3608 ('B', 'bookmarks', False, _('compare bookmarks')),
3608 ('B', 'bookmarks', False, _('compare bookmarks')),
3609 ('b', 'branch', [], _('a specific branch you would like to push'),
3609 ('b', 'branch', [], _('a specific branch you would like to push'),
3610 _('BRANCH')),
3610 _('BRANCH')),
3611 ] + logopts + remoteopts + subrepoopts,
3611 ] + logopts + remoteopts + subrepoopts,
3612 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3612 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3613 def outgoing(ui, repo, dest=None, **opts):
3613 def outgoing(ui, repo, dest=None, **opts):
3614 """show changesets not found in the destination
3614 """show changesets not found in the destination
3615
3615
3616 Show changesets not found in the specified destination repository
3616 Show changesets not found in the specified destination repository
3617 or the default push location. These are the changesets that would
3617 or the default push location. These are the changesets that would
3618 be pushed if a push was requested.
3618 be pushed if a push was requested.
3619
3619
3620 See pull for details of valid destination formats.
3620 See pull for details of valid destination formats.
3621
3621
3622 .. container:: verbose
3622 .. container:: verbose
3623
3623
3624 With -B/--bookmarks, the result of bookmark comparison between
3624 With -B/--bookmarks, the result of bookmark comparison between
3625 local and remote repositories is displayed. With -v/--verbose,
3625 local and remote repositories is displayed. With -v/--verbose,
3626 status is also displayed for each bookmark like below::
3626 status is also displayed for each bookmark like below::
3627
3627
3628 BM1 01234567890a added
3628 BM1 01234567890a added
3629 BM2 deleted
3629 BM2 deleted
3630 BM3 234567890abc advanced
3630 BM3 234567890abc advanced
3631 BM4 34567890abcd diverged
3631 BM4 34567890abcd diverged
3632 BM5 4567890abcde changed
3632 BM5 4567890abcde changed
3633
3633
3634 The action taken when pushing depends on the
3634 The action taken when pushing depends on the
3635 status of each bookmark:
3635 status of each bookmark:
3636
3636
3637 :``added``: push with ``-B`` will create it
3637 :``added``: push with ``-B`` will create it
3638 :``deleted``: push with ``-B`` will delete it
3638 :``deleted``: push with ``-B`` will delete it
3639 :``advanced``: push will update it
3639 :``advanced``: push will update it
3640 :``diverged``: push with ``-B`` will update it
3640 :``diverged``: push with ``-B`` will update it
3641 :``changed``: push with ``-B`` will update it
3641 :``changed``: push with ``-B`` will update it
3642
3642
3643 From the point of view of pushing behavior, bookmarks
3643 From the point of view of pushing behavior, bookmarks
3644 existing only in the remote repository are treated as
3644 existing only in the remote repository are treated as
3645 ``deleted``, even if it is in fact added remotely.
3645 ``deleted``, even if it is in fact added remotely.
3646
3646
3647 Returns 0 if there are outgoing changes, 1 otherwise.
3647 Returns 0 if there are outgoing changes, 1 otherwise.
3648 """
3648 """
3649 opts = pycompat.byteskwargs(opts)
3649 opts = pycompat.byteskwargs(opts)
3650 if opts.get('graph'):
3650 if opts.get('graph'):
3651 cmdutil.checkunsupportedgraphflags([], opts)
3651 cmdutil.checkunsupportedgraphflags([], opts)
3652 o, other = hg._outgoing(ui, repo, dest, opts)
3652 o, other = hg._outgoing(ui, repo, dest, opts)
3653 if not o:
3653 if not o:
3654 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3654 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3655 return
3655 return
3656
3656
3657 revdag = cmdutil.graphrevs(repo, o, opts)
3657 revdag = cmdutil.graphrevs(repo, o, opts)
3658 ui.pager('outgoing')
3658 ui.pager('outgoing')
3659 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3659 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3660 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3660 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3661 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3661 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3662 return 0
3662 return 0
3663
3663
3664 if opts.get('bookmarks'):
3664 if opts.get('bookmarks'):
3665 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3665 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3666 dest, branches = hg.parseurl(dest, opts.get('branch'))
3666 dest, branches = hg.parseurl(dest, opts.get('branch'))
3667 other = hg.peer(repo, opts, dest)
3667 other = hg.peer(repo, opts, dest)
3668 if 'bookmarks' not in other.listkeys('namespaces'):
3668 if 'bookmarks' not in other.listkeys('namespaces'):
3669 ui.warn(_("remote doesn't support bookmarks\n"))
3669 ui.warn(_("remote doesn't support bookmarks\n"))
3670 return 0
3670 return 0
3671 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3671 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3672 ui.pager('outgoing')
3672 ui.pager('outgoing')
3673 return bookmarks.outgoing(ui, repo, other)
3673 return bookmarks.outgoing(ui, repo, other)
3674
3674
3675 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3675 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3676 try:
3676 try:
3677 return hg.outgoing(ui, repo, dest, opts)
3677 return hg.outgoing(ui, repo, dest, opts)
3678 finally:
3678 finally:
3679 del repo._subtoppath
3679 del repo._subtoppath
3680
3680
3681 @command('parents',
3681 @command('parents',
3682 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3682 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3683 ] + templateopts,
3683 ] + templateopts,
3684 _('[-r REV] [FILE]'),
3684 _('[-r REV] [FILE]'),
3685 inferrepo=True)
3685 inferrepo=True)
3686 def parents(ui, repo, file_=None, **opts):
3686 def parents(ui, repo, file_=None, **opts):
3687 """show the parents of the working directory or revision (DEPRECATED)
3687 """show the parents of the working directory or revision (DEPRECATED)
3688
3688
3689 Print the working directory's parent revisions. If a revision is
3689 Print the working directory's parent revisions. If a revision is
3690 given via -r/--rev, the parent of that revision will be printed.
3690 given via -r/--rev, the parent of that revision will be printed.
3691 If a file argument is given, the revision in which the file was
3691 If a file argument is given, the revision in which the file was
3692 last changed (before the working directory revision or the
3692 last changed (before the working directory revision or the
3693 argument to --rev if given) is printed.
3693 argument to --rev if given) is printed.
3694
3694
3695 This command is equivalent to::
3695 This command is equivalent to::
3696
3696
3697 hg log -r "p1()+p2()" or
3697 hg log -r "p1()+p2()" or
3698 hg log -r "p1(REV)+p2(REV)" or
3698 hg log -r "p1(REV)+p2(REV)" or
3699 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3699 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3700 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3700 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3701
3701
3702 See :hg:`summary` and :hg:`help revsets` for related information.
3702 See :hg:`summary` and :hg:`help revsets` for related information.
3703
3703
3704 Returns 0 on success.
3704 Returns 0 on success.
3705 """
3705 """
3706
3706
3707 opts = pycompat.byteskwargs(opts)
3707 opts = pycompat.byteskwargs(opts)
3708 rev = opts.get('rev')
3708 rev = opts.get('rev')
3709 if rev:
3709 if rev:
3710 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3710 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3711 ctx = scmutil.revsingle(repo, rev, None)
3711 ctx = scmutil.revsingle(repo, rev, None)
3712
3712
3713 if file_:
3713 if file_:
3714 m = scmutil.match(ctx, (file_,), opts)
3714 m = scmutil.match(ctx, (file_,), opts)
3715 if m.anypats() or len(m.files()) != 1:
3715 if m.anypats() or len(m.files()) != 1:
3716 raise error.Abort(_('can only specify an explicit filename'))
3716 raise error.Abort(_('can only specify an explicit filename'))
3717 file_ = m.files()[0]
3717 file_ = m.files()[0]
3718 filenodes = []
3718 filenodes = []
3719 for cp in ctx.parents():
3719 for cp in ctx.parents():
3720 if not cp:
3720 if not cp:
3721 continue
3721 continue
3722 try:
3722 try:
3723 filenodes.append(cp.filenode(file_))
3723 filenodes.append(cp.filenode(file_))
3724 except error.LookupError:
3724 except error.LookupError:
3725 pass
3725 pass
3726 if not filenodes:
3726 if not filenodes:
3727 raise error.Abort(_("'%s' not found in manifest!") % file_)
3727 raise error.Abort(_("'%s' not found in manifest!") % file_)
3728 p = []
3728 p = []
3729 for fn in filenodes:
3729 for fn in filenodes:
3730 fctx = repo.filectx(file_, fileid=fn)
3730 fctx = repo.filectx(file_, fileid=fn)
3731 p.append(fctx.node())
3731 p.append(fctx.node())
3732 else:
3732 else:
3733 p = [cp.node() for cp in ctx.parents()]
3733 p = [cp.node() for cp in ctx.parents()]
3734
3734
3735 displayer = cmdutil.show_changeset(ui, repo, opts)
3735 displayer = cmdutil.show_changeset(ui, repo, opts)
3736 for n in p:
3736 for n in p:
3737 if n != nullid:
3737 if n != nullid:
3738 displayer.show(repo[n])
3738 displayer.show(repo[n])
3739 displayer.close()
3739 displayer.close()
3740
3740
3741 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3741 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3742 cmdtype=readonly)
3742 cmdtype=readonly)
3743 def paths(ui, repo, search=None, **opts):
3743 def paths(ui, repo, search=None, **opts):
3744 """show aliases for remote repositories
3744 """show aliases for remote repositories
3745
3745
3746 Show definition of symbolic path name NAME. If no name is given,
3746 Show definition of symbolic path name NAME. If no name is given,
3747 show definition of all available names.
3747 show definition of all available names.
3748
3748
3749 Option -q/--quiet suppresses all output when searching for NAME
3749 Option -q/--quiet suppresses all output when searching for NAME
3750 and shows only the path names when listing all definitions.
3750 and shows only the path names when listing all definitions.
3751
3751
3752 Path names are defined in the [paths] section of your
3752 Path names are defined in the [paths] section of your
3753 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3753 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3754 repository, ``.hg/hgrc`` is used, too.
3754 repository, ``.hg/hgrc`` is used, too.
3755
3755
3756 The path names ``default`` and ``default-push`` have a special
3756 The path names ``default`` and ``default-push`` have a special
3757 meaning. When performing a push or pull operation, they are used
3757 meaning. When performing a push or pull operation, they are used
3758 as fallbacks if no location is specified on the command-line.
3758 as fallbacks if no location is specified on the command-line.
3759 When ``default-push`` is set, it will be used for push and
3759 When ``default-push`` is set, it will be used for push and
3760 ``default`` will be used for pull; otherwise ``default`` is used
3760 ``default`` will be used for pull; otherwise ``default`` is used
3761 as the fallback for both. When cloning a repository, the clone
3761 as the fallback for both. When cloning a repository, the clone
3762 source is written as ``default`` in ``.hg/hgrc``.
3762 source is written as ``default`` in ``.hg/hgrc``.
3763
3763
3764 .. note::
3764 .. note::
3765
3765
3766 ``default`` and ``default-push`` apply to all inbound (e.g.
3766 ``default`` and ``default-push`` apply to all inbound (e.g.
3767 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3767 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3768 and :hg:`bundle`) operations.
3768 and :hg:`bundle`) operations.
3769
3769
3770 See :hg:`help urls` for more information.
3770 See :hg:`help urls` for more information.
3771
3771
3772 Returns 0 on success.
3772 Returns 0 on success.
3773 """
3773 """
3774
3774
3775 opts = pycompat.byteskwargs(opts)
3775 opts = pycompat.byteskwargs(opts)
3776 ui.pager('paths')
3776 ui.pager('paths')
3777 if search:
3777 if search:
3778 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3778 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3779 if name == search]
3779 if name == search]
3780 else:
3780 else:
3781 pathitems = sorted(ui.paths.iteritems())
3781 pathitems = sorted(ui.paths.iteritems())
3782
3782
3783 fm = ui.formatter('paths', opts)
3783 fm = ui.formatter('paths', opts)
3784 if fm.isplain():
3784 if fm.isplain():
3785 hidepassword = util.hidepassword
3785 hidepassword = util.hidepassword
3786 else:
3786 else:
3787 hidepassword = str
3787 hidepassword = str
3788 if ui.quiet:
3788 if ui.quiet:
3789 namefmt = '%s\n'
3789 namefmt = '%s\n'
3790 else:
3790 else:
3791 namefmt = '%s = '
3791 namefmt = '%s = '
3792 showsubopts = not search and not ui.quiet
3792 showsubopts = not search and not ui.quiet
3793
3793
3794 for name, path in pathitems:
3794 for name, path in pathitems:
3795 fm.startitem()
3795 fm.startitem()
3796 fm.condwrite(not search, 'name', namefmt, name)
3796 fm.condwrite(not search, 'name', namefmt, name)
3797 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3797 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3798 for subopt, value in sorted(path.suboptions.items()):
3798 for subopt, value in sorted(path.suboptions.items()):
3799 assert subopt not in ('name', 'url')
3799 assert subopt not in ('name', 'url')
3800 if showsubopts:
3800 if showsubopts:
3801 fm.plain('%s:%s = ' % (name, subopt))
3801 fm.plain('%s:%s = ' % (name, subopt))
3802 fm.condwrite(showsubopts, subopt, '%s\n', value)
3802 fm.condwrite(showsubopts, subopt, '%s\n', value)
3803
3803
3804 fm.end()
3804 fm.end()
3805
3805
3806 if search and not pathitems:
3806 if search and not pathitems:
3807 if not ui.quiet:
3807 if not ui.quiet:
3808 ui.warn(_("not found!\n"))
3808 ui.warn(_("not found!\n"))
3809 return 1
3809 return 1
3810 else:
3810 else:
3811 return 0
3811 return 0
3812
3812
3813 @command('phase',
3813 @command('phase',
3814 [('p', 'public', False, _('set changeset phase to public')),
3814 [('p', 'public', False, _('set changeset phase to public')),
3815 ('d', 'draft', False, _('set changeset phase to draft')),
3815 ('d', 'draft', False, _('set changeset phase to draft')),
3816 ('s', 'secret', False, _('set changeset phase to secret')),
3816 ('s', 'secret', False, _('set changeset phase to secret')),
3817 ('f', 'force', False, _('allow to move boundary backward')),
3817 ('f', 'force', False, _('allow to move boundary backward')),
3818 ('r', 'rev', [], _('target revision'), _('REV')),
3818 ('r', 'rev', [], _('target revision'), _('REV')),
3819 ],
3819 ],
3820 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3820 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3821 def phase(ui, repo, *revs, **opts):
3821 def phase(ui, repo, *revs, **opts):
3822 """set or show the current phase name
3822 """set or show the current phase name
3823
3823
3824 With no argument, show the phase name of the current revision(s).
3824 With no argument, show the phase name of the current revision(s).
3825
3825
3826 With one of -p/--public, -d/--draft or -s/--secret, change the
3826 With one of -p/--public, -d/--draft or -s/--secret, change the
3827 phase value of the specified revisions.
3827 phase value of the specified revisions.
3828
3828
3829 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
3829 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
3830 lower phase to a higher phase. Phases are ordered as follows::
3830 lower phase to a higher phase. Phases are ordered as follows::
3831
3831
3832 public < draft < secret
3832 public < draft < secret
3833
3833
3834 Returns 0 on success, 1 if some phases could not be changed.
3834 Returns 0 on success, 1 if some phases could not be changed.
3835
3835
3836 (For more information about the phases concept, see :hg:`help phases`.)
3836 (For more information about the phases concept, see :hg:`help phases`.)
3837 """
3837 """
3838 opts = pycompat.byteskwargs(opts)
3838 opts = pycompat.byteskwargs(opts)
3839 # search for a unique phase argument
3839 # search for a unique phase argument
3840 targetphase = None
3840 targetphase = None
3841 for idx, name in enumerate(phases.phasenames):
3841 for idx, name in enumerate(phases.phasenames):
3842 if opts[name]:
3842 if opts[name]:
3843 if targetphase is not None:
3843 if targetphase is not None:
3844 raise error.Abort(_('only one phase can be specified'))
3844 raise error.Abort(_('only one phase can be specified'))
3845 targetphase = idx
3845 targetphase = idx
3846
3846
3847 # look for specified revision
3847 # look for specified revision
3848 revs = list(revs)
3848 revs = list(revs)
3849 revs.extend(opts['rev'])
3849 revs.extend(opts['rev'])
3850 if not revs:
3850 if not revs:
3851 # display both parents as the second parent phase can influence
3851 # display both parents as the second parent phase can influence
3852 # the phase of a merge commit
3852 # the phase of a merge commit
3853 revs = [c.rev() for c in repo[None].parents()]
3853 revs = [c.rev() for c in repo[None].parents()]
3854
3854
3855 revs = scmutil.revrange(repo, revs)
3855 revs = scmutil.revrange(repo, revs)
3856
3856
3857 lock = None
3857 lock = None
3858 ret = 0
3858 ret = 0
3859 if targetphase is None:
3859 if targetphase is None:
3860 # display
3860 # display
3861 for r in revs:
3861 for r in revs:
3862 ctx = repo[r]
3862 ctx = repo[r]
3863 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3863 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3864 else:
3864 else:
3865 tr = None
3865 tr = None
3866 lock = repo.lock()
3866 lock = repo.lock()
3867 try:
3867 try:
3868 tr = repo.transaction("phase")
3868 tr = repo.transaction("phase")
3869 # set phase
3869 # set phase
3870 if not revs:
3870 if not revs:
3871 raise error.Abort(_('empty revision set'))
3871 raise error.Abort(_('empty revision set'))
3872 nodes = [repo[r].node() for r in revs]
3872 nodes = [repo[r].node() for r in revs]
3873 # moving revision from public to draft may hide them
3873 # moving revision from public to draft may hide them
3874 # We have to check result on an unfiltered repository
3874 # We have to check result on an unfiltered repository
3875 unfi = repo.unfiltered()
3875 unfi = repo.unfiltered()
3876 getphase = unfi._phasecache.phase
3876 getphase = unfi._phasecache.phase
3877 olddata = [getphase(unfi, r) for r in unfi]
3877 olddata = [getphase(unfi, r) for r in unfi]
3878 phases.advanceboundary(repo, tr, targetphase, nodes)
3878 phases.advanceboundary(repo, tr, targetphase, nodes)
3879 if opts['force']:
3879 if opts['force']:
3880 phases.retractboundary(repo, tr, targetphase, nodes)
3880 phases.retractboundary(repo, tr, targetphase, nodes)
3881 tr.close()
3881 tr.close()
3882 finally:
3882 finally:
3883 if tr is not None:
3883 if tr is not None:
3884 tr.release()
3884 tr.release()
3885 lock.release()
3885 lock.release()
3886 getphase = unfi._phasecache.phase
3886 getphase = unfi._phasecache.phase
3887 newdata = [getphase(unfi, r) for r in unfi]
3887 newdata = [getphase(unfi, r) for r in unfi]
3888 changes = sum(newdata[r] != olddata[r] for r in unfi)
3888 changes = sum(newdata[r] != olddata[r] for r in unfi)
3889 cl = unfi.changelog
3889 cl = unfi.changelog
3890 rejected = [n for n in nodes
3890 rejected = [n for n in nodes
3891 if newdata[cl.rev(n)] < targetphase]
3891 if newdata[cl.rev(n)] < targetphase]
3892 if rejected:
3892 if rejected:
3893 ui.warn(_('cannot move %i changesets to a higher '
3893 ui.warn(_('cannot move %i changesets to a higher '
3894 'phase, use --force\n') % len(rejected))
3894 'phase, use --force\n') % len(rejected))
3895 ret = 1
3895 ret = 1
3896 if changes:
3896 if changes:
3897 msg = _('phase changed for %i changesets\n') % changes
3897 msg = _('phase changed for %i changesets\n') % changes
3898 if ret:
3898 if ret:
3899 ui.status(msg)
3899 ui.status(msg)
3900 else:
3900 else:
3901 ui.note(msg)
3901 ui.note(msg)
3902 else:
3902 else:
3903 ui.warn(_('no phases changed\n'))
3903 ui.warn(_('no phases changed\n'))
3904 return ret
3904 return ret
3905
3905
3906 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3906 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3907 """Run after a changegroup has been added via pull/unbundle
3907 """Run after a changegroup has been added via pull/unbundle
3908
3908
3909 This takes arguments below:
3909 This takes arguments below:
3910
3910
3911 :modheads: change of heads by pull/unbundle
3911 :modheads: change of heads by pull/unbundle
3912 :optupdate: updating working directory is needed or not
3912 :optupdate: updating working directory is needed or not
3913 :checkout: update destination revision (or None to default destination)
3913 :checkout: update destination revision (or None to default destination)
3914 :brev: a name, which might be a bookmark to be activated after updating
3914 :brev: a name, which might be a bookmark to be activated after updating
3915 """
3915 """
3916 if modheads == 0:
3916 if modheads == 0:
3917 return
3917 return
3918 if optupdate:
3918 if optupdate:
3919 try:
3919 try:
3920 return hg.updatetotally(ui, repo, checkout, brev)
3920 return hg.updatetotally(ui, repo, checkout, brev)
3921 except error.UpdateAbort as inst:
3921 except error.UpdateAbort as inst:
3922 msg = _("not updating: %s") % str(inst)
3922 msg = _("not updating: %s") % str(inst)
3923 hint = inst.hint
3923 hint = inst.hint
3924 raise error.UpdateAbort(msg, hint=hint)
3924 raise error.UpdateAbort(msg, hint=hint)
3925 if modheads > 1:
3925 if modheads > 1:
3926 currentbranchheads = len(repo.branchheads())
3926 currentbranchheads = len(repo.branchheads())
3927 if currentbranchheads == modheads:
3927 if currentbranchheads == modheads:
3928 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3928 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3929 elif currentbranchheads > 1:
3929 elif currentbranchheads > 1:
3930 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3930 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3931 "merge)\n"))
3931 "merge)\n"))
3932 else:
3932 else:
3933 ui.status(_("(run 'hg heads' to see heads)\n"))
3933 ui.status(_("(run 'hg heads' to see heads)\n"))
3934 elif not ui.configbool('commands', 'update.requiredest'):
3934 elif not ui.configbool('commands', 'update.requiredest'):
3935 ui.status(_("(run 'hg update' to get a working copy)\n"))
3935 ui.status(_("(run 'hg update' to get a working copy)\n"))
3936
3936
3937 @command('^pull',
3937 @command('^pull',
3938 [('u', 'update', None,
3938 [('u', 'update', None,
3939 _('update to new branch head if new descendants were pulled')),
3939 _('update to new branch head if new descendants were pulled')),
3940 ('f', 'force', None, _('run even when remote repository is unrelated')),
3940 ('f', 'force', None, _('run even when remote repository is unrelated')),
3941 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3941 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3942 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3942 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3943 ('b', 'branch', [], _('a specific branch you would like to pull'),
3943 ('b', 'branch', [], _('a specific branch you would like to pull'),
3944 _('BRANCH')),
3944 _('BRANCH')),
3945 ] + remoteopts,
3945 ] + remoteopts,
3946 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3946 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3947 def pull(ui, repo, source="default", **opts):
3947 def pull(ui, repo, source="default", **opts):
3948 """pull changes from the specified source
3948 """pull changes from the specified source
3949
3949
3950 Pull changes from a remote repository to a local one.
3950 Pull changes from a remote repository to a local one.
3951
3951
3952 This finds all changes from the repository at the specified path
3952 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
3953 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
3954 -R is specified). By default, this does not update the copy of the
3955 project in the working directory.
3955 project in the working directory.
3956
3956
3957 Use :hg:`incoming` if you want to see what would have been added
3957 Use :hg:`incoming` if you want to see what would have been added
3958 by a pull at the time you issued this command. If you then decide
3958 by a pull at the time you issued this command. If you then decide
3959 to add those changes to the repository, you should use :hg:`pull
3959 to add those changes to the repository, you should use :hg:`pull
3960 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3960 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3961
3961
3962 If SOURCE is omitted, the 'default' path will be used.
3962 If SOURCE is omitted, the 'default' path will be used.
3963 See :hg:`help urls` for more information.
3963 See :hg:`help urls` for more information.
3964
3964
3965 Specifying bookmark as ``.`` is equivalent to specifying the active
3965 Specifying bookmark as ``.`` is equivalent to specifying the active
3966 bookmark's name.
3966 bookmark's name.
3967
3967
3968 Returns 0 on success, 1 if an update had unresolved files.
3968 Returns 0 on success, 1 if an update had unresolved files.
3969 """
3969 """
3970
3970
3971 opts = pycompat.byteskwargs(opts)
3971 opts = pycompat.byteskwargs(opts)
3972 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3972 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3973 msg = _('update destination required by configuration')
3973 msg = _('update destination required by configuration')
3974 hint = _('use hg pull followed by hg update DEST')
3974 hint = _('use hg pull followed by hg update DEST')
3975 raise error.Abort(msg, hint=hint)
3975 raise error.Abort(msg, hint=hint)
3976
3976
3977 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3977 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3978 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3978 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3979 other = hg.peer(repo, opts, source)
3979 other = hg.peer(repo, opts, source)
3980 try:
3980 try:
3981 revs, checkout = hg.addbranchrevs(repo, other, branches,
3981 revs, checkout = hg.addbranchrevs(repo, other, branches,
3982 opts.get('rev'))
3982 opts.get('rev'))
3983
3983
3984
3984
3985 pullopargs = {}
3985 pullopargs = {}
3986 if opts.get('bookmark'):
3986 if opts.get('bookmark'):
3987 if not revs:
3987 if not revs:
3988 revs = []
3988 revs = []
3989 # The list of bookmark used here is not the one used to actually
3989 # The list of bookmark used here is not the one used to actually
3990 # update the bookmark name. This can result in the revision pulled
3990 # 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
3991 # not ending up with the name of the bookmark because of a race
3992 # condition on the server. (See issue 4689 for details)
3992 # condition on the server. (See issue 4689 for details)
3993 remotebookmarks = other.listkeys('bookmarks')
3993 remotebookmarks = other.listkeys('bookmarks')
3994 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
3994 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
3995 pullopargs['remotebookmarks'] = remotebookmarks
3995 pullopargs['remotebookmarks'] = remotebookmarks
3996 for b in opts['bookmark']:
3996 for b in opts['bookmark']:
3997 b = repo._bookmarks.expandname(b)
3997 b = repo._bookmarks.expandname(b)
3998 if b not in remotebookmarks:
3998 if b not in remotebookmarks:
3999 raise error.Abort(_('remote bookmark %s not found!') % b)
3999 raise error.Abort(_('remote bookmark %s not found!') % b)
4000 revs.append(hex(remotebookmarks[b]))
4000 revs.append(hex(remotebookmarks[b]))
4001
4001
4002 if revs:
4002 if revs:
4003 try:
4003 try:
4004 # When 'rev' is a bookmark name, we cannot guarantee that it
4004 # When 'rev' is a bookmark name, we cannot guarantee that it
4005 # will be updated with that name because of a race condition
4005 # will be updated with that name because of a race condition
4006 # server side. (See issue 4689 for details)
4006 # server side. (See issue 4689 for details)
4007 oldrevs = revs
4007 oldrevs = revs
4008 revs = [] # actually, nodes
4008 revs = [] # actually, nodes
4009 for r in oldrevs:
4009 for r in oldrevs:
4010 node = other.lookup(r)
4010 node = other.lookup(r)
4011 revs.append(node)
4011 revs.append(node)
4012 if r == checkout:
4012 if r == checkout:
4013 checkout = node
4013 checkout = node
4014 except error.CapabilityError:
4014 except error.CapabilityError:
4015 err = _("other repository doesn't support revision lookup, "
4015 err = _("other repository doesn't support revision lookup, "
4016 "so a rev cannot be specified.")
4016 "so a rev cannot be specified.")
4017 raise error.Abort(err)
4017 raise error.Abort(err)
4018
4018
4019 pullopargs.update(opts.get('opargs', {}))
4019 pullopargs.update(opts.get('opargs', {}))
4020 modheads = exchange.pull(repo, other, heads=revs,
4020 modheads = exchange.pull(repo, other, heads=revs,
4021 force=opts.get('force'),
4021 force=opts.get('force'),
4022 bookmarks=opts.get('bookmark', ()),
4022 bookmarks=opts.get('bookmark', ()),
4023 opargs=pullopargs).cgresult
4023 opargs=pullopargs).cgresult
4024
4024
4025 # brev is a name, which might be a bookmark to be activated at
4025 # brev is a name, which might be a bookmark to be activated at
4026 # the end of the update. In other words, it is an explicit
4026 # the end of the update. In other words, it is an explicit
4027 # destination of the update
4027 # destination of the update
4028 brev = None
4028 brev = None
4029
4029
4030 if checkout:
4030 if checkout:
4031 checkout = str(repo.changelog.rev(checkout))
4031 checkout = str(repo.changelog.rev(checkout))
4032
4032
4033 # order below depends on implementation of
4033 # order below depends on implementation of
4034 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4034 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4035 # because 'checkout' is determined without it.
4035 # because 'checkout' is determined without it.
4036 if opts.get('rev'):
4036 if opts.get('rev'):
4037 brev = opts['rev'][0]
4037 brev = opts['rev'][0]
4038 elif opts.get('branch'):
4038 elif opts.get('branch'):
4039 brev = opts['branch'][0]
4039 brev = opts['branch'][0]
4040 else:
4040 else:
4041 brev = branches[0]
4041 brev = branches[0]
4042 repo._subtoppath = source
4042 repo._subtoppath = source
4043 try:
4043 try:
4044 ret = postincoming(ui, repo, modheads, opts.get('update'),
4044 ret = postincoming(ui, repo, modheads, opts.get('update'),
4045 checkout, brev)
4045 checkout, brev)
4046
4046
4047 finally:
4047 finally:
4048 del repo._subtoppath
4048 del repo._subtoppath
4049
4049
4050 finally:
4050 finally:
4051 other.close()
4051 other.close()
4052 return ret
4052 return ret
4053
4053
4054 @command('^push',
4054 @command('^push',
4055 [('f', 'force', None, _('force push')),
4055 [('f', 'force', None, _('force push')),
4056 ('r', 'rev', [],
4056 ('r', 'rev', [],
4057 _('a changeset intended to be included in the destination'),
4057 _('a changeset intended to be included in the destination'),
4058 _('REV')),
4058 _('REV')),
4059 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4059 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4060 ('b', 'branch', [],
4060 ('b', 'branch', [],
4061 _('a specific branch you would like to push'), _('BRANCH')),
4061 _('a specific branch you would like to push'), _('BRANCH')),
4062 ('', 'new-branch', False, _('allow pushing a new branch')),
4062 ('', 'new-branch', False, _('allow pushing a new branch')),
4063 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4063 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4064 ] + remoteopts,
4064 ] + remoteopts,
4065 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4065 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4066 def push(ui, repo, dest=None, **opts):
4066 def push(ui, repo, dest=None, **opts):
4067 """push changes to the specified destination
4067 """push changes to the specified destination
4068
4068
4069 Push changesets from the local repository to the specified
4069 Push changesets from the local repository to the specified
4070 destination.
4070 destination.
4071
4071
4072 This operation is symmetrical to pull: it is identical to a pull
4072 This operation is symmetrical to pull: it is identical to a pull
4073 in the destination repository from the current one.
4073 in the destination repository from the current one.
4074
4074
4075 By default, push will not allow creation of new heads at the
4075 By default, push will not allow creation of new heads at the
4076 destination, since multiple heads would make it unclear which head
4076 destination, since multiple heads would make it unclear which head
4077 to use. In this situation, it is recommended to pull and merge
4077 to use. In this situation, it is recommended to pull and merge
4078 before pushing.
4078 before pushing.
4079
4079
4080 Use --new-branch if you want to allow push to create a new named
4080 Use --new-branch if you want to allow push to create a new named
4081 branch that is not present at the destination. This allows you to
4081 branch that is not present at the destination. This allows you to
4082 only create a new branch without forcing other changes.
4082 only create a new branch without forcing other changes.
4083
4083
4084 .. note::
4084 .. note::
4085
4085
4086 Extra care should be taken with the -f/--force option,
4086 Extra care should be taken with the -f/--force option,
4087 which will push all new heads on all branches, an action which will
4087 which will push all new heads on all branches, an action which will
4088 almost always cause confusion for collaborators.
4088 almost always cause confusion for collaborators.
4089
4089
4090 If -r/--rev is used, the specified revision and all its ancestors
4090 If -r/--rev is used, the specified revision and all its ancestors
4091 will be pushed to the remote repository.
4091 will be pushed to the remote repository.
4092
4092
4093 If -B/--bookmark is used, the specified bookmarked revision, its
4093 If -B/--bookmark is used, the specified bookmarked revision, its
4094 ancestors, and the bookmark will be pushed to the remote
4094 ancestors, and the bookmark will be pushed to the remote
4095 repository. Specifying ``.`` is equivalent to specifying the active
4095 repository. Specifying ``.`` is equivalent to specifying the active
4096 bookmark's name.
4096 bookmark's name.
4097
4097
4098 Please see :hg:`help urls` for important details about ``ssh://``
4098 Please see :hg:`help urls` for important details about ``ssh://``
4099 URLs. If DESTINATION is omitted, a default path will be used.
4099 URLs. If DESTINATION is omitted, a default path will be used.
4100
4100
4101 .. container:: verbose
4101 .. container:: verbose
4102
4102
4103 The --pushvars option sends strings to the server that become
4103 The --pushvars option sends strings to the server that become
4104 environment variables prepended with ``HG_USERVAR_``. For example,
4104 environment variables prepended with ``HG_USERVAR_``. For example,
4105 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4105 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4106 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4106 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4107
4107
4108 pushvars can provide for user-overridable hooks as well as set debug
4108 pushvars can provide for user-overridable hooks as well as set debug
4109 levels. One example is having a hook that blocks commits containing
4109 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
4110 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
4111 is using conflict markers for testing purposes or the file format has
4112 strings that look like conflict markers.
4112 strings that look like conflict markers.
4113
4113
4114 By default, servers will ignore `--pushvars`. To enable it add the
4114 By default, servers will ignore `--pushvars`. To enable it add the
4115 following to your configuration file::
4115 following to your configuration file::
4116
4116
4117 [push]
4117 [push]
4118 pushvars.server = true
4118 pushvars.server = true
4119
4119
4120 Returns 0 if push was successful, 1 if nothing to push.
4120 Returns 0 if push was successful, 1 if nothing to push.
4121 """
4121 """
4122
4122
4123 opts = pycompat.byteskwargs(opts)
4123 opts = pycompat.byteskwargs(opts)
4124 if opts.get('bookmark'):
4124 if opts.get('bookmark'):
4125 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4125 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4126 for b in opts['bookmark']:
4126 for b in opts['bookmark']:
4127 # translate -B options to -r so changesets get pushed
4127 # translate -B options to -r so changesets get pushed
4128 b = repo._bookmarks.expandname(b)
4128 b = repo._bookmarks.expandname(b)
4129 if b in repo._bookmarks:
4129 if b in repo._bookmarks:
4130 opts.setdefault('rev', []).append(b)
4130 opts.setdefault('rev', []).append(b)
4131 else:
4131 else:
4132 # if we try to push a deleted bookmark, translate it to null
4132 # if we try to push a deleted bookmark, translate it to null
4133 # this lets simultaneous -r, -b options continue working
4133 # this lets simultaneous -r, -b options continue working
4134 opts.setdefault('rev', []).append("null")
4134 opts.setdefault('rev', []).append("null")
4135
4135
4136 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4136 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4137 if not path:
4137 if not path:
4138 raise error.Abort(_('default repository not configured!'),
4138 raise error.Abort(_('default repository not configured!'),
4139 hint=_("see 'hg help config.paths'"))
4139 hint=_("see 'hg help config.paths'"))
4140 dest = path.pushloc or path.loc
4140 dest = path.pushloc or path.loc
4141 branches = (path.branch, opts.get('branch') or [])
4141 branches = (path.branch, opts.get('branch') or [])
4142 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4142 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4143 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4143 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4144 other = hg.peer(repo, opts, dest)
4144 other = hg.peer(repo, opts, dest)
4145
4145
4146 if revs:
4146 if revs:
4147 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4147 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4148 if not revs:
4148 if not revs:
4149 raise error.Abort(_("specified revisions evaluate to an empty set"),
4149 raise error.Abort(_("specified revisions evaluate to an empty set"),
4150 hint=_("use different revision arguments"))
4150 hint=_("use different revision arguments"))
4151 elif path.pushrev:
4151 elif path.pushrev:
4152 # It doesn't make any sense to specify ancestor revisions. So limit
4152 # It doesn't make any sense to specify ancestor revisions. So limit
4153 # to DAG heads to make discovery simpler.
4153 # to DAG heads to make discovery simpler.
4154 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4154 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4155 revs = scmutil.revrange(repo, [expr])
4155 revs = scmutil.revrange(repo, [expr])
4156 revs = [repo[rev].node() for rev in revs]
4156 revs = [repo[rev].node() for rev in revs]
4157 if not revs:
4157 if not revs:
4158 raise error.Abort(_('default push revset for path evaluates to an '
4158 raise error.Abort(_('default push revset for path evaluates to an '
4159 'empty set'))
4159 'empty set'))
4160
4160
4161 repo._subtoppath = dest
4161 repo._subtoppath = dest
4162 try:
4162 try:
4163 # push subrepos depth-first for coherent ordering
4163 # push subrepos depth-first for coherent ordering
4164 c = repo['']
4164 c = repo['']
4165 subs = c.substate # only repos that are committed
4165 subs = c.substate # only repos that are committed
4166 for s in sorted(subs):
4166 for s in sorted(subs):
4167 result = c.sub(s).push(opts)
4167 result = c.sub(s).push(opts)
4168 if result == 0:
4168 if result == 0:
4169 return not result
4169 return not result
4170 finally:
4170 finally:
4171 del repo._subtoppath
4171 del repo._subtoppath
4172
4172
4173 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4173 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4174 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4174 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4175
4175
4176 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4176 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4177 newbranch=opts.get('new_branch'),
4177 newbranch=opts.get('new_branch'),
4178 bookmarks=opts.get('bookmark', ()),
4178 bookmarks=opts.get('bookmark', ()),
4179 opargs=opargs)
4179 opargs=opargs)
4180
4180
4181 result = not pushop.cgresult
4181 result = not pushop.cgresult
4182
4182
4183 if pushop.bkresult is not None:
4183 if pushop.bkresult is not None:
4184 if pushop.bkresult == 2:
4184 if pushop.bkresult == 2:
4185 result = 2
4185 result = 2
4186 elif not result and pushop.bkresult:
4186 elif not result and pushop.bkresult:
4187 result = 2
4187 result = 2
4188
4188
4189 return result
4189 return result
4190
4190
4191 @command('recover', [])
4191 @command('recover', [])
4192 def recover(ui, repo):
4192 def recover(ui, repo):
4193 """roll back an interrupted transaction
4193 """roll back an interrupted transaction
4194
4194
4195 Recover from an interrupted commit or pull.
4195 Recover from an interrupted commit or pull.
4196
4196
4197 This command tries to fix the repository status after an
4197 This command tries to fix the repository status after an
4198 interrupted operation. It should only be necessary when Mercurial
4198 interrupted operation. It should only be necessary when Mercurial
4199 suggests it.
4199 suggests it.
4200
4200
4201 Returns 0 if successful, 1 if nothing to recover or verify fails.
4201 Returns 0 if successful, 1 if nothing to recover or verify fails.
4202 """
4202 """
4203 if repo.recover():
4203 if repo.recover():
4204 return hg.verify(repo)
4204 return hg.verify(repo)
4205 return 1
4205 return 1
4206
4206
4207 @command('^remove|rm',
4207 @command('^remove|rm',
4208 [('A', 'after', None, _('record delete for missing files')),
4208 [('A', 'after', None, _('record delete for missing files')),
4209 ('f', 'force', None,
4209 ('f', 'force', None,
4210 _('forget added files, delete modified files')),
4210 _('forget added files, delete modified files')),
4211 ] + subrepoopts + walkopts,
4211 ] + subrepoopts + walkopts,
4212 _('[OPTION]... FILE...'),
4212 _('[OPTION]... FILE...'),
4213 inferrepo=True)
4213 inferrepo=True)
4214 def remove(ui, repo, *pats, **opts):
4214 def remove(ui, repo, *pats, **opts):
4215 """remove the specified files on the next commit
4215 """remove the specified files on the next commit
4216
4216
4217 Schedule the indicated files for removal from the current branch.
4217 Schedule the indicated files for removal from the current branch.
4218
4218
4219 This command schedules the files to be removed at the next commit.
4219 This command schedules the files to be removed at the next commit.
4220 To undo a remove before that, see :hg:`revert`. To undo added
4220 To undo a remove before that, see :hg:`revert`. To undo added
4221 files, see :hg:`forget`.
4221 files, see :hg:`forget`.
4222
4222
4223 .. container:: verbose
4223 .. container:: verbose
4224
4224
4225 -A/--after can be used to remove only files that have already
4225 -A/--after can be used to remove only files that have already
4226 been deleted, -f/--force can be used to force deletion, and -Af
4226 been deleted, -f/--force can be used to force deletion, and -Af
4227 can be used to remove files from the next revision without
4227 can be used to remove files from the next revision without
4228 deleting them from the working directory.
4228 deleting them from the working directory.
4229
4229
4230 The following table details the behavior of remove for different
4230 The following table details the behavior of remove for different
4231 file states (columns) and option combinations (rows). The file
4231 file states (columns) and option combinations (rows). The file
4232 states are Added [A], Clean [C], Modified [M] and Missing [!]
4232 states are Added [A], Clean [C], Modified [M] and Missing [!]
4233 (as reported by :hg:`status`). The actions are Warn, Remove
4233 (as reported by :hg:`status`). The actions are Warn, Remove
4234 (from branch) and Delete (from disk):
4234 (from branch) and Delete (from disk):
4235
4235
4236 ========= == == == ==
4236 ========= == == == ==
4237 opt/state A C M !
4237 opt/state A C M !
4238 ========= == == == ==
4238 ========= == == == ==
4239 none W RD W R
4239 none W RD W R
4240 -f R RD RD R
4240 -f R RD RD R
4241 -A W W W R
4241 -A W W W R
4242 -Af R R R R
4242 -Af R R R R
4243 ========= == == == ==
4243 ========= == == == ==
4244
4244
4245 .. note::
4245 .. note::
4246
4246
4247 :hg:`remove` never deletes files in Added [A] state from the
4247 :hg:`remove` never deletes files in Added [A] state from the
4248 working directory, not even if ``--force`` is specified.
4248 working directory, not even if ``--force`` is specified.
4249
4249
4250 Returns 0 on success, 1 if any warnings encountered.
4250 Returns 0 on success, 1 if any warnings encountered.
4251 """
4251 """
4252
4252
4253 opts = pycompat.byteskwargs(opts)
4253 opts = pycompat.byteskwargs(opts)
4254 after, force = opts.get('after'), opts.get('force')
4254 after, force = opts.get('after'), opts.get('force')
4255 if not pats and not after:
4255 if not pats and not after:
4256 raise error.Abort(_('no files specified'))
4256 raise error.Abort(_('no files specified'))
4257
4257
4258 m = scmutil.match(repo[None], pats, opts)
4258 m = scmutil.match(repo[None], pats, opts)
4259 subrepos = opts.get('subrepos')
4259 subrepos = opts.get('subrepos')
4260 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4260 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4261
4261
4262 @command('rename|move|mv',
4262 @command('rename|move|mv',
4263 [('A', 'after', None, _('record a rename that has already occurred')),
4263 [('A', 'after', None, _('record a rename that has already occurred')),
4264 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4264 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4265 ] + walkopts + dryrunopts,
4265 ] + walkopts + dryrunopts,
4266 _('[OPTION]... SOURCE... DEST'))
4266 _('[OPTION]... SOURCE... DEST'))
4267 def rename(ui, repo, *pats, **opts):
4267 def rename(ui, repo, *pats, **opts):
4268 """rename files; equivalent of copy + remove
4268 """rename files; equivalent of copy + remove
4269
4269
4270 Mark dest as copies of sources; mark sources for deletion. If dest
4270 Mark dest as copies of sources; mark sources for deletion. If dest
4271 is a directory, copies are put in that directory. If dest is a
4271 is a directory, copies are put in that directory. If dest is a
4272 file, there can only be one source.
4272 file, there can only be one source.
4273
4273
4274 By default, this command copies the contents of files as they
4274 By default, this command copies the contents of files as they
4275 exist in the working directory. If invoked with -A/--after, the
4275 exist in the working directory. If invoked with -A/--after, the
4276 operation is recorded, but no copying is performed.
4276 operation is recorded, but no copying is performed.
4277
4277
4278 This command takes effect at the next commit. To undo a rename
4278 This command takes effect at the next commit. To undo a rename
4279 before that, see :hg:`revert`.
4279 before that, see :hg:`revert`.
4280
4280
4281 Returns 0 on success, 1 if errors are encountered.
4281 Returns 0 on success, 1 if errors are encountered.
4282 """
4282 """
4283 opts = pycompat.byteskwargs(opts)
4283 opts = pycompat.byteskwargs(opts)
4284 with repo.wlock(False):
4284 with repo.wlock(False):
4285 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4285 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4286
4286
4287 @command('resolve',
4287 @command('resolve',
4288 [('a', 'all', None, _('select all unresolved files')),
4288 [('a', 'all', None, _('select all unresolved files')),
4289 ('l', 'list', None, _('list state of files needing merge')),
4289 ('l', 'list', None, _('list state of files needing merge')),
4290 ('m', 'mark', None, _('mark files as resolved')),
4290 ('m', 'mark', None, _('mark files as resolved')),
4291 ('u', 'unmark', None, _('mark files as unresolved')),
4291 ('u', 'unmark', None, _('mark files as unresolved')),
4292 ('n', 'no-status', None, _('hide status prefix'))]
4292 ('n', 'no-status', None, _('hide status prefix'))]
4293 + mergetoolopts + walkopts + formatteropts,
4293 + mergetoolopts + walkopts + formatteropts,
4294 _('[OPTION]... [FILE]...'),
4294 _('[OPTION]... [FILE]...'),
4295 inferrepo=True)
4295 inferrepo=True)
4296 def resolve(ui, repo, *pats, **opts):
4296 def resolve(ui, repo, *pats, **opts):
4297 """redo merges or set/view the merge status of files
4297 """redo merges or set/view the merge status of files
4298
4298
4299 Merges with unresolved conflicts are often the result of
4299 Merges with unresolved conflicts are often the result of
4300 non-interactive merging using the ``internal:merge`` configuration
4300 non-interactive merging using the ``internal:merge`` configuration
4301 setting, or a command-line merge tool like ``diff3``. The resolve
4301 setting, or a command-line merge tool like ``diff3``. The resolve
4302 command is used to manage the files involved in a merge, after
4302 command is used to manage the files involved in a merge, after
4303 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4303 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4304 working directory must have two parents). See :hg:`help
4304 working directory must have two parents). See :hg:`help
4305 merge-tools` for information on configuring merge tools.
4305 merge-tools` for information on configuring merge tools.
4306
4306
4307 The resolve command can be used in the following ways:
4307 The resolve command can be used in the following ways:
4308
4308
4309 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4309 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4310 files, discarding any previous merge attempts. Re-merging is not
4310 files, discarding any previous merge attempts. Re-merging is not
4311 performed for files already marked as resolved. Use ``--all/-a``
4311 performed for files already marked as resolved. Use ``--all/-a``
4312 to select all unresolved files. ``--tool`` can be used to specify
4312 to select all unresolved files. ``--tool`` can be used to specify
4313 the merge tool used for the given files. It overrides the HGMERGE
4313 the merge tool used for the given files. It overrides the HGMERGE
4314 environment variable and your configuration files. Previous file
4314 environment variable and your configuration files. Previous file
4315 contents are saved with a ``.orig`` suffix.
4315 contents are saved with a ``.orig`` suffix.
4316
4316
4317 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4317 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4318 (e.g. after having manually fixed-up the files). The default is
4318 (e.g. after having manually fixed-up the files). The default is
4319 to mark all unresolved files.
4319 to mark all unresolved files.
4320
4320
4321 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4321 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4322 default is to mark all resolved files.
4322 default is to mark all resolved files.
4323
4323
4324 - :hg:`resolve -l`: list files which had or still have conflicts.
4324 - :hg:`resolve -l`: list files which had or still have conflicts.
4325 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4325 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4326 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4326 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4327 the list. See :hg:`help filesets` for details.
4327 the list. See :hg:`help filesets` for details.
4328
4328
4329 .. note::
4329 .. note::
4330
4330
4331 Mercurial will not let you commit files with unresolved merge
4331 Mercurial will not let you commit files with unresolved merge
4332 conflicts. You must use :hg:`resolve -m ...` before you can
4332 conflicts. You must use :hg:`resolve -m ...` before you can
4333 commit after a conflicting merge.
4333 commit after a conflicting merge.
4334
4334
4335 Returns 0 on success, 1 if any files fail a resolve attempt.
4335 Returns 0 on success, 1 if any files fail a resolve attempt.
4336 """
4336 """
4337
4337
4338 opts = pycompat.byteskwargs(opts)
4338 opts = pycompat.byteskwargs(opts)
4339 flaglist = 'all mark unmark list no_status'.split()
4339 flaglist = 'all mark unmark list no_status'.split()
4340 all, mark, unmark, show, nostatus = \
4340 all, mark, unmark, show, nostatus = \
4341 [opts.get(o) for o in flaglist]
4341 [opts.get(o) for o in flaglist]
4342
4342
4343 if (show and (mark or unmark)) or (mark and unmark):
4343 if (show and (mark or unmark)) or (mark and unmark):
4344 raise error.Abort(_("too many options specified"))
4344 raise error.Abort(_("too many options specified"))
4345 if pats and all:
4345 if pats and all:
4346 raise error.Abort(_("can't specify --all and patterns"))
4346 raise error.Abort(_("can't specify --all and patterns"))
4347 if not (all or pats or show or mark or unmark):
4347 if not (all or pats or show or mark or unmark):
4348 raise error.Abort(_('no files or directories specified'),
4348 raise error.Abort(_('no files or directories specified'),
4349 hint=('use --all to re-merge all unresolved files'))
4349 hint=('use --all to re-merge all unresolved files'))
4350
4350
4351 if show:
4351 if show:
4352 ui.pager('resolve')
4352 ui.pager('resolve')
4353 fm = ui.formatter('resolve', opts)
4353 fm = ui.formatter('resolve', opts)
4354 ms = mergemod.mergestate.read(repo)
4354 ms = mergemod.mergestate.read(repo)
4355 m = scmutil.match(repo[None], pats, opts)
4355 m = scmutil.match(repo[None], pats, opts)
4356
4356
4357 # Labels and keys based on merge state. Unresolved path conflicts show
4357 # Labels and keys based on merge state. Unresolved path conflicts show
4358 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4358 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4359 # resolved conflicts.
4359 # resolved conflicts.
4360 mergestateinfo = {
4360 mergestateinfo = {
4361 'u': ('resolve.unresolved', 'U'),
4361 'u': ('resolve.unresolved', 'U'),
4362 'r': ('resolve.resolved', 'R'),
4362 'r': ('resolve.resolved', 'R'),
4363 'pu': ('resolve.unresolved', 'P'),
4363 'pu': ('resolve.unresolved', 'P'),
4364 'pr': ('resolve.resolved', 'R'),
4364 'pr': ('resolve.resolved', 'R'),
4365 'd': ('resolve.driverresolved', 'D'),
4365 'd': ('resolve.driverresolved', 'D'),
4366 }
4366 }
4367
4367
4368 for f in ms:
4368 for f in ms:
4369 if not m(f):
4369 if not m(f):
4370 continue
4370 continue
4371
4371
4372 label, key = mergestateinfo[ms[f]]
4372 label, key = mergestateinfo[ms[f]]
4373 fm.startitem()
4373 fm.startitem()
4374 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4374 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4375 fm.write('path', '%s\n', f, label=label)
4375 fm.write('path', '%s\n', f, label=label)
4376 fm.end()
4376 fm.end()
4377 return 0
4377 return 0
4378
4378
4379 with repo.wlock():
4379 with repo.wlock():
4380 ms = mergemod.mergestate.read(repo)
4380 ms = mergemod.mergestate.read(repo)
4381
4381
4382 if not (ms.active() or repo.dirstate.p2() != nullid):
4382 if not (ms.active() or repo.dirstate.p2() != nullid):
4383 raise error.Abort(
4383 raise error.Abort(
4384 _('resolve command not applicable when not merging'))
4384 _('resolve command not applicable when not merging'))
4385
4385
4386 wctx = repo[None]
4386 wctx = repo[None]
4387
4387
4388 if ms.mergedriver and ms.mdstate() == 'u':
4388 if ms.mergedriver and ms.mdstate() == 'u':
4389 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4389 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4390 ms.commit()
4390 ms.commit()
4391 # allow mark and unmark to go through
4391 # allow mark and unmark to go through
4392 if not mark and not unmark and not proceed:
4392 if not mark and not unmark and not proceed:
4393 return 1
4393 return 1
4394
4394
4395 m = scmutil.match(wctx, pats, opts)
4395 m = scmutil.match(wctx, pats, opts)
4396 ret = 0
4396 ret = 0
4397 didwork = False
4397 didwork = False
4398 runconclude = False
4398 runconclude = False
4399
4399
4400 tocomplete = []
4400 tocomplete = []
4401 for f in ms:
4401 for f in ms:
4402 if not m(f):
4402 if not m(f):
4403 continue
4403 continue
4404
4404
4405 didwork = True
4405 didwork = True
4406
4406
4407 # don't let driver-resolved files be marked, and run the conclude
4407 # don't let driver-resolved files be marked, and run the conclude
4408 # step if asked to resolve
4408 # step if asked to resolve
4409 if ms[f] == "d":
4409 if ms[f] == "d":
4410 exact = m.exact(f)
4410 exact = m.exact(f)
4411 if mark:
4411 if mark:
4412 if exact:
4412 if exact:
4413 ui.warn(_('not marking %s as it is driver-resolved\n')
4413 ui.warn(_('not marking %s as it is driver-resolved\n')
4414 % f)
4414 % f)
4415 elif unmark:
4415 elif unmark:
4416 if exact:
4416 if exact:
4417 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4417 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4418 % f)
4418 % f)
4419 else:
4419 else:
4420 runconclude = True
4420 runconclude = True
4421 continue
4421 continue
4422
4422
4423 # path conflicts must be resolved manually
4423 # path conflicts must be resolved manually
4424 if ms[f] in ("pu", "pr"):
4424 if ms[f] in ("pu", "pr"):
4425 if mark:
4425 if mark:
4426 ms.mark(f, "pr")
4426 ms.mark(f, "pr")
4427 elif unmark:
4427 elif unmark:
4428 ms.mark(f, "pu")
4428 ms.mark(f, "pu")
4429 elif ms[f] == "pu":
4429 elif ms[f] == "pu":
4430 ui.warn(_('%s: path conflict must be resolved manually\n')
4430 ui.warn(_('%s: path conflict must be resolved manually\n')
4431 % f)
4431 % f)
4432 continue
4432 continue
4433
4433
4434 if mark:
4434 if mark:
4435 ms.mark(f, "r")
4435 ms.mark(f, "r")
4436 elif unmark:
4436 elif unmark:
4437 ms.mark(f, "u")
4437 ms.mark(f, "u")
4438 else:
4438 else:
4439 # backup pre-resolve (merge uses .orig for its own purposes)
4439 # backup pre-resolve (merge uses .orig for its own purposes)
4440 a = repo.wjoin(f)
4440 a = repo.wjoin(f)
4441 try:
4441 try:
4442 util.copyfile(a, a + ".resolve")
4442 util.copyfile(a, a + ".resolve")
4443 except (IOError, OSError) as inst:
4443 except (IOError, OSError) as inst:
4444 if inst.errno != errno.ENOENT:
4444 if inst.errno != errno.ENOENT:
4445 raise
4445 raise
4446
4446
4447 try:
4447 try:
4448 # preresolve file
4448 # preresolve file
4449 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4449 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4450 'resolve')
4450 'resolve')
4451 complete, r = ms.preresolve(f, wctx)
4451 complete, r = ms.preresolve(f, wctx)
4452 if not complete:
4452 if not complete:
4453 tocomplete.append(f)
4453 tocomplete.append(f)
4454 elif r:
4454 elif r:
4455 ret = 1
4455 ret = 1
4456 finally:
4456 finally:
4457 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4457 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4458 ms.commit()
4458 ms.commit()
4459
4459
4460 # replace filemerge's .orig file with our resolve file, but only
4460 # replace filemerge's .orig file with our resolve file, but only
4461 # for merges that are complete
4461 # for merges that are complete
4462 if complete:
4462 if complete:
4463 try:
4463 try:
4464 util.rename(a + ".resolve",
4464 util.rename(a + ".resolve",
4465 scmutil.origpath(ui, repo, a))
4465 scmutil.origpath(ui, repo, a))
4466 except OSError as inst:
4466 except OSError as inst:
4467 if inst.errno != errno.ENOENT:
4467 if inst.errno != errno.ENOENT:
4468 raise
4468 raise
4469
4469
4470 for f in tocomplete:
4470 for f in tocomplete:
4471 try:
4471 try:
4472 # resolve file
4472 # resolve file
4473 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4473 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4474 'resolve')
4474 'resolve')
4475 r = ms.resolve(f, wctx)
4475 r = ms.resolve(f, wctx)
4476 if r:
4476 if r:
4477 ret = 1
4477 ret = 1
4478 finally:
4478 finally:
4479 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4479 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4480 ms.commit()
4480 ms.commit()
4481
4481
4482 # replace filemerge's .orig file with our resolve file
4482 # replace filemerge's .orig file with our resolve file
4483 a = repo.wjoin(f)
4483 a = repo.wjoin(f)
4484 try:
4484 try:
4485 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4485 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4486 except OSError as inst:
4486 except OSError as inst:
4487 if inst.errno != errno.ENOENT:
4487 if inst.errno != errno.ENOENT:
4488 raise
4488 raise
4489
4489
4490 ms.commit()
4490 ms.commit()
4491 ms.recordactions()
4491 ms.recordactions()
4492
4492
4493 if not didwork and pats:
4493 if not didwork and pats:
4494 hint = None
4494 hint = None
4495 if not any([p for p in pats if p.find(':') >= 0]):
4495 if not any([p for p in pats if p.find(':') >= 0]):
4496 pats = ['path:%s' % p for p in pats]
4496 pats = ['path:%s' % p for p in pats]
4497 m = scmutil.match(wctx, pats, opts)
4497 m = scmutil.match(wctx, pats, opts)
4498 for f in ms:
4498 for f in ms:
4499 if not m(f):
4499 if not m(f):
4500 continue
4500 continue
4501 flags = ''.join(['-%s ' % o[0] for o in flaglist
4501 flags = ''.join(['-%s ' % o[0] for o in flaglist
4502 if opts.get(o)])
4502 if opts.get(o)])
4503 hint = _("(try: hg resolve %s%s)\n") % (
4503 hint = _("(try: hg resolve %s%s)\n") % (
4504 flags,
4504 flags,
4505 ' '.join(pats))
4505 ' '.join(pats))
4506 break
4506 break
4507 ui.warn(_("arguments do not match paths that need resolving\n"))
4507 ui.warn(_("arguments do not match paths that need resolving\n"))
4508 if hint:
4508 if hint:
4509 ui.warn(hint)
4509 ui.warn(hint)
4510 elif ms.mergedriver and ms.mdstate() != 's':
4510 elif ms.mergedriver and ms.mdstate() != 's':
4511 # run conclude step when either a driver-resolved file is requested
4511 # run conclude step when either a driver-resolved file is requested
4512 # or there are no driver-resolved files
4512 # or there are no driver-resolved files
4513 # we can't use 'ret' to determine whether any files are unresolved
4513 # we can't use 'ret' to determine whether any files are unresolved
4514 # because we might not have tried to resolve some
4514 # because we might not have tried to resolve some
4515 if ((runconclude or not list(ms.driverresolved()))
4515 if ((runconclude or not list(ms.driverresolved()))
4516 and not list(ms.unresolved())):
4516 and not list(ms.unresolved())):
4517 proceed = mergemod.driverconclude(repo, ms, wctx)
4517 proceed = mergemod.driverconclude(repo, ms, wctx)
4518 ms.commit()
4518 ms.commit()
4519 if not proceed:
4519 if not proceed:
4520 return 1
4520 return 1
4521
4521
4522 # Nudge users into finishing an unfinished operation
4522 # Nudge users into finishing an unfinished operation
4523 unresolvedf = list(ms.unresolved())
4523 unresolvedf = list(ms.unresolved())
4524 driverresolvedf = list(ms.driverresolved())
4524 driverresolvedf = list(ms.driverresolved())
4525 if not unresolvedf and not driverresolvedf:
4525 if not unresolvedf and not driverresolvedf:
4526 ui.status(_('(no more unresolved files)\n'))
4526 ui.status(_('(no more unresolved files)\n'))
4527 cmdutil.checkafterresolved(repo)
4527 cmdutil.checkafterresolved(repo)
4528 elif not unresolvedf:
4528 elif not unresolvedf:
4529 ui.status(_('(no more unresolved files -- '
4529 ui.status(_('(no more unresolved files -- '
4530 'run "hg resolve --all" to conclude)\n'))
4530 'run "hg resolve --all" to conclude)\n'))
4531
4531
4532 return ret
4532 return ret
4533
4533
4534 @command('revert',
4534 @command('revert',
4535 [('a', 'all', None, _('revert all changes when no arguments given')),
4535 [('a', 'all', None, _('revert all changes when no arguments given')),
4536 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4536 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4537 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4537 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4538 ('C', 'no-backup', None, _('do not save backup copies of files')),
4538 ('C', 'no-backup', None, _('do not save backup copies of files')),
4539 ('i', 'interactive', None, _('interactively select the changes')),
4539 ('i', 'interactive', None, _('interactively select the changes')),
4540 ] + walkopts + dryrunopts,
4540 ] + walkopts + dryrunopts,
4541 _('[OPTION]... [-r REV] [NAME]...'))
4541 _('[OPTION]... [-r REV] [NAME]...'))
4542 def revert(ui, repo, *pats, **opts):
4542 def revert(ui, repo, *pats, **opts):
4543 """restore files to their checkout state
4543 """restore files to their checkout state
4544
4544
4545 .. note::
4545 .. note::
4546
4546
4547 To check out earlier revisions, you should use :hg:`update REV`.
4547 To check out earlier revisions, you should use :hg:`update REV`.
4548 To cancel an uncommitted merge (and lose your changes),
4548 To cancel an uncommitted merge (and lose your changes),
4549 use :hg:`update --clean .`.
4549 use :hg:`update --clean .`.
4550
4550
4551 With no revision specified, revert the specified files or directories
4551 With no revision specified, revert the specified files or directories
4552 to the contents they had in the parent of the working directory.
4552 to the contents they had in the parent of the working directory.
4553 This restores the contents of files to an unmodified
4553 This restores the contents of files to an unmodified
4554 state and unschedules adds, removes, copies, and renames. If the
4554 state and unschedules adds, removes, copies, and renames. If the
4555 working directory has two parents, you must explicitly specify a
4555 working directory has two parents, you must explicitly specify a
4556 revision.
4556 revision.
4557
4557
4558 Using the -r/--rev or -d/--date options, revert the given files or
4558 Using the -r/--rev or -d/--date options, revert the given files or
4559 directories to their states as of a specific revision. Because
4559 directories to their states as of a specific revision. Because
4560 revert does not change the working directory parents, this will
4560 revert does not change the working directory parents, this will
4561 cause these files to appear modified. This can be helpful to "back
4561 cause these files to appear modified. This can be helpful to "back
4562 out" some or all of an earlier change. See :hg:`backout` for a
4562 out" some or all of an earlier change. See :hg:`backout` for a
4563 related method.
4563 related method.
4564
4564
4565 Modified files are saved with a .orig suffix before reverting.
4565 Modified files are saved with a .orig suffix before reverting.
4566 To disable these backups, use --no-backup. It is possible to store
4566 To disable these backups, use --no-backup. It is possible to store
4567 the backup files in a custom directory relative to the root of the
4567 the backup files in a custom directory relative to the root of the
4568 repository by setting the ``ui.origbackuppath`` configuration
4568 repository by setting the ``ui.origbackuppath`` configuration
4569 option.
4569 option.
4570
4570
4571 See :hg:`help dates` for a list of formats valid for -d/--date.
4571 See :hg:`help dates` for a list of formats valid for -d/--date.
4572
4572
4573 See :hg:`help backout` for a way to reverse the effect of an
4573 See :hg:`help backout` for a way to reverse the effect of an
4574 earlier changeset.
4574 earlier changeset.
4575
4575
4576 Returns 0 on success.
4576 Returns 0 on success.
4577 """
4577 """
4578
4578
4579 opts = pycompat.byteskwargs(opts)
4579 opts = pycompat.byteskwargs(opts)
4580 if opts.get("date"):
4580 if opts.get("date"):
4581 if opts.get("rev"):
4581 if opts.get("rev"):
4582 raise error.Abort(_("you can't specify a revision and a date"))
4582 raise error.Abort(_("you can't specify a revision and a date"))
4583 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4583 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4584
4584
4585 parent, p2 = repo.dirstate.parents()
4585 parent, p2 = repo.dirstate.parents()
4586 if not opts.get('rev') and p2 != nullid:
4586 if not opts.get('rev') and p2 != nullid:
4587 # revert after merge is a trap for new users (issue2915)
4587 # revert after merge is a trap for new users (issue2915)
4588 raise error.Abort(_('uncommitted merge with no revision specified'),
4588 raise error.Abort(_('uncommitted merge with no revision specified'),
4589 hint=_("use 'hg update' or see 'hg help revert'"))
4589 hint=_("use 'hg update' or see 'hg help revert'"))
4590
4590
4591 ctx = scmutil.revsingle(repo, opts.get('rev'))
4591 rev = opts.get('rev')
4592 if rev:
4593 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4594 ctx = scmutil.revsingle(repo, rev)
4592
4595
4593 if (not (pats or opts.get('include') or opts.get('exclude') or
4596 if (not (pats or opts.get('include') or opts.get('exclude') or
4594 opts.get('all') or opts.get('interactive'))):
4597 opts.get('all') or opts.get('interactive'))):
4595 msg = _("no files or directories specified")
4598 msg = _("no files or directories specified")
4596 if p2 != nullid:
4599 if p2 != nullid:
4597 hint = _("uncommitted merge, use --all to discard all changes,"
4600 hint = _("uncommitted merge, use --all to discard all changes,"
4598 " or 'hg update -C .' to abort the merge")
4601 " or 'hg update -C .' to abort the merge")
4599 raise error.Abort(msg, hint=hint)
4602 raise error.Abort(msg, hint=hint)
4600 dirty = any(repo.status())
4603 dirty = any(repo.status())
4601 node = ctx.node()
4604 node = ctx.node()
4602 if node != parent:
4605 if node != parent:
4603 if dirty:
4606 if dirty:
4604 hint = _("uncommitted changes, use --all to discard all"
4607 hint = _("uncommitted changes, use --all to discard all"
4605 " changes, or 'hg update %s' to update") % ctx.rev()
4608 " changes, or 'hg update %s' to update") % ctx.rev()
4606 else:
4609 else:
4607 hint = _("use --all to revert all files,"
4610 hint = _("use --all to revert all files,"
4608 " or 'hg update %s' to update") % ctx.rev()
4611 " or 'hg update %s' to update") % ctx.rev()
4609 elif dirty:
4612 elif dirty:
4610 hint = _("uncommitted changes, use --all to discard all changes")
4613 hint = _("uncommitted changes, use --all to discard all changes")
4611 else:
4614 else:
4612 hint = _("use --all to revert all files")
4615 hint = _("use --all to revert all files")
4613 raise error.Abort(msg, hint=hint)
4616 raise error.Abort(msg, hint=hint)
4614
4617
4615 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4618 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4616 **pycompat.strkwargs(opts))
4619 **pycompat.strkwargs(opts))
4617
4620
4618 @command('rollback', dryrunopts +
4621 @command('rollback', dryrunopts +
4619 [('f', 'force', False, _('ignore safety measures'))])
4622 [('f', 'force', False, _('ignore safety measures'))])
4620 def rollback(ui, repo, **opts):
4623 def rollback(ui, repo, **opts):
4621 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4624 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4622
4625
4623 Please use :hg:`commit --amend` instead of rollback to correct
4626 Please use :hg:`commit --amend` instead of rollback to correct
4624 mistakes in the last commit.
4627 mistakes in the last commit.
4625
4628
4626 This command should be used with care. There is only one level of
4629 This command should be used with care. There is only one level of
4627 rollback, and there is no way to undo a rollback. It will also
4630 rollback, and there is no way to undo a rollback. It will also
4628 restore the dirstate at the time of the last transaction, losing
4631 restore the dirstate at the time of the last transaction, losing
4629 any dirstate changes since that time. This command does not alter
4632 any dirstate changes since that time. This command does not alter
4630 the working directory.
4633 the working directory.
4631
4634
4632 Transactions are used to encapsulate the effects of all commands
4635 Transactions are used to encapsulate the effects of all commands
4633 that create new changesets or propagate existing changesets into a
4636 that create new changesets or propagate existing changesets into a
4634 repository.
4637 repository.
4635
4638
4636 .. container:: verbose
4639 .. container:: verbose
4637
4640
4638 For example, the following commands are transactional, and their
4641 For example, the following commands are transactional, and their
4639 effects can be rolled back:
4642 effects can be rolled back:
4640
4643
4641 - commit
4644 - commit
4642 - import
4645 - import
4643 - pull
4646 - pull
4644 - push (with this repository as the destination)
4647 - push (with this repository as the destination)
4645 - unbundle
4648 - unbundle
4646
4649
4647 To avoid permanent data loss, rollback will refuse to rollback a
4650 To avoid permanent data loss, rollback will refuse to rollback a
4648 commit transaction if it isn't checked out. Use --force to
4651 commit transaction if it isn't checked out. Use --force to
4649 override this protection.
4652 override this protection.
4650
4653
4651 The rollback command can be entirely disabled by setting the
4654 The rollback command can be entirely disabled by setting the
4652 ``ui.rollback`` configuration setting to false. If you're here
4655 ``ui.rollback`` configuration setting to false. If you're here
4653 because you want to use rollback and it's disabled, you can
4656 because you want to use rollback and it's disabled, you can
4654 re-enable the command by setting ``ui.rollback`` to true.
4657 re-enable the command by setting ``ui.rollback`` to true.
4655
4658
4656 This command is not intended for use on public repositories. Once
4659 This command is not intended for use on public repositories. Once
4657 changes are visible for pull by other users, rolling a transaction
4660 changes are visible for pull by other users, rolling a transaction
4658 back locally is ineffective (someone else may already have pulled
4661 back locally is ineffective (someone else may already have pulled
4659 the changes). Furthermore, a race is possible with readers of the
4662 the changes). Furthermore, a race is possible with readers of the
4660 repository; for example an in-progress pull from the repository
4663 repository; for example an in-progress pull from the repository
4661 may fail if a rollback is performed.
4664 may fail if a rollback is performed.
4662
4665
4663 Returns 0 on success, 1 if no rollback data is available.
4666 Returns 0 on success, 1 if no rollback data is available.
4664 """
4667 """
4665 if not ui.configbool('ui', 'rollback'):
4668 if not ui.configbool('ui', 'rollback'):
4666 raise error.Abort(_('rollback is disabled because it is unsafe'),
4669 raise error.Abort(_('rollback is disabled because it is unsafe'),
4667 hint=('see `hg help -v rollback` for information'))
4670 hint=('see `hg help -v rollback` for information'))
4668 return repo.rollback(dryrun=opts.get(r'dry_run'),
4671 return repo.rollback(dryrun=opts.get(r'dry_run'),
4669 force=opts.get(r'force'))
4672 force=opts.get(r'force'))
4670
4673
4671 @command('root', [], cmdtype=readonly)
4674 @command('root', [], cmdtype=readonly)
4672 def root(ui, repo):
4675 def root(ui, repo):
4673 """print the root (top) of the current working directory
4676 """print the root (top) of the current working directory
4674
4677
4675 Print the root directory of the current repository.
4678 Print the root directory of the current repository.
4676
4679
4677 Returns 0 on success.
4680 Returns 0 on success.
4678 """
4681 """
4679 ui.write(repo.root + "\n")
4682 ui.write(repo.root + "\n")
4680
4683
4681 @command('^serve',
4684 @command('^serve',
4682 [('A', 'accesslog', '', _('name of access log file to write to'),
4685 [('A', 'accesslog', '', _('name of access log file to write to'),
4683 _('FILE')),
4686 _('FILE')),
4684 ('d', 'daemon', None, _('run server in background')),
4687 ('d', 'daemon', None, _('run server in background')),
4685 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4688 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4686 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4689 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4687 # use string type, then we can check if something was passed
4690 # use string type, then we can check if something was passed
4688 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4691 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4689 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4692 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4690 _('ADDR')),
4693 _('ADDR')),
4691 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4694 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4692 _('PREFIX')),
4695 _('PREFIX')),
4693 ('n', 'name', '',
4696 ('n', 'name', '',
4694 _('name to show in web pages (default: working directory)'), _('NAME')),
4697 _('name to show in web pages (default: working directory)'), _('NAME')),
4695 ('', 'web-conf', '',
4698 ('', 'web-conf', '',
4696 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4699 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4697 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4700 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4698 _('FILE')),
4701 _('FILE')),
4699 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4702 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4700 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4703 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4701 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4704 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4702 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4705 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4703 ('', 'style', '', _('template style to use'), _('STYLE')),
4706 ('', 'style', '', _('template style to use'), _('STYLE')),
4704 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4707 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4705 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4708 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4706 + subrepoopts,
4709 + subrepoopts,
4707 _('[OPTION]...'),
4710 _('[OPTION]...'),
4708 optionalrepo=True)
4711 optionalrepo=True)
4709 def serve(ui, repo, **opts):
4712 def serve(ui, repo, **opts):
4710 """start stand-alone webserver
4713 """start stand-alone webserver
4711
4714
4712 Start a local HTTP repository browser and pull server. You can use
4715 Start a local HTTP repository browser and pull server. You can use
4713 this for ad-hoc sharing and browsing of repositories. It is
4716 this for ad-hoc sharing and browsing of repositories. It is
4714 recommended to use a real web server to serve a repository for
4717 recommended to use a real web server to serve a repository for
4715 longer periods of time.
4718 longer periods of time.
4716
4719
4717 Please note that the server does not implement access control.
4720 Please note that the server does not implement access control.
4718 This means that, by default, anybody can read from the server and
4721 This means that, by default, anybody can read from the server and
4719 nobody can write to it by default. Set the ``web.allow-push``
4722 nobody can write to it by default. Set the ``web.allow-push``
4720 option to ``*`` to allow everybody to push to the server. You
4723 option to ``*`` to allow everybody to push to the server. You
4721 should use a real web server if you need to authenticate users.
4724 should use a real web server if you need to authenticate users.
4722
4725
4723 By default, the server logs accesses to stdout and errors to
4726 By default, the server logs accesses to stdout and errors to
4724 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4727 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4725 files.
4728 files.
4726
4729
4727 To have the server choose a free port number to listen on, specify
4730 To have the server choose a free port number to listen on, specify
4728 a port number of 0; in this case, the server will print the port
4731 a port number of 0; in this case, the server will print the port
4729 number it uses.
4732 number it uses.
4730
4733
4731 Returns 0 on success.
4734 Returns 0 on success.
4732 """
4735 """
4733
4736
4734 opts = pycompat.byteskwargs(opts)
4737 opts = pycompat.byteskwargs(opts)
4735 if opts["stdio"] and opts["cmdserver"]:
4738 if opts["stdio"] and opts["cmdserver"]:
4736 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4739 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4737
4740
4738 if opts["stdio"]:
4741 if opts["stdio"]:
4739 if repo is None:
4742 if repo is None:
4740 raise error.RepoError(_("there is no Mercurial repository here"
4743 raise error.RepoError(_("there is no Mercurial repository here"
4741 " (.hg not found)"))
4744 " (.hg not found)"))
4742 s = sshserver.sshserver(ui, repo)
4745 s = sshserver.sshserver(ui, repo)
4743 s.serve_forever()
4746 s.serve_forever()
4744
4747
4745 service = server.createservice(ui, repo, opts)
4748 service = server.createservice(ui, repo, opts)
4746 return server.runservice(opts, initfn=service.init, runfn=service.run)
4749 return server.runservice(opts, initfn=service.init, runfn=service.run)
4747
4750
4748 @command('^status|st',
4751 @command('^status|st',
4749 [('A', 'all', None, _('show status of all files')),
4752 [('A', 'all', None, _('show status of all files')),
4750 ('m', 'modified', None, _('show only modified files')),
4753 ('m', 'modified', None, _('show only modified files')),
4751 ('a', 'added', None, _('show only added files')),
4754 ('a', 'added', None, _('show only added files')),
4752 ('r', 'removed', None, _('show only removed files')),
4755 ('r', 'removed', None, _('show only removed files')),
4753 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4756 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4754 ('c', 'clean', None, _('show only files without changes')),
4757 ('c', 'clean', None, _('show only files without changes')),
4755 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4758 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4756 ('i', 'ignored', None, _('show only ignored files')),
4759 ('i', 'ignored', None, _('show only ignored files')),
4757 ('n', 'no-status', None, _('hide status prefix')),
4760 ('n', 'no-status', None, _('hide status prefix')),
4758 ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')),
4761 ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')),
4759 ('C', 'copies', None, _('show source of copied files')),
4762 ('C', 'copies', None, _('show source of copied files')),
4760 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4763 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4761 ('', 'rev', [], _('show difference from revision'), _('REV')),
4764 ('', 'rev', [], _('show difference from revision'), _('REV')),
4762 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4765 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4763 ] + walkopts + subrepoopts + formatteropts,
4766 ] + walkopts + subrepoopts + formatteropts,
4764 _('[OPTION]... [FILE]...'),
4767 _('[OPTION]... [FILE]...'),
4765 inferrepo=True, cmdtype=readonly)
4768 inferrepo=True, cmdtype=readonly)
4766 def status(ui, repo, *pats, **opts):
4769 def status(ui, repo, *pats, **opts):
4767 """show changed files in the working directory
4770 """show changed files in the working directory
4768
4771
4769 Show status of files in the repository. If names are given, only
4772 Show status of files in the repository. If names are given, only
4770 files that match are shown. Files that are clean or ignored or
4773 files that match are shown. Files that are clean or ignored or
4771 the source of a copy/move operation, are not listed unless
4774 the source of a copy/move operation, are not listed unless
4772 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4775 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4773 Unless options described with "show only ..." are given, the
4776 Unless options described with "show only ..." are given, the
4774 options -mardu are used.
4777 options -mardu are used.
4775
4778
4776 Option -q/--quiet hides untracked (unknown and ignored) files
4779 Option -q/--quiet hides untracked (unknown and ignored) files
4777 unless explicitly requested with -u/--unknown or -i/--ignored.
4780 unless explicitly requested with -u/--unknown or -i/--ignored.
4778
4781
4779 .. note::
4782 .. note::
4780
4783
4781 :hg:`status` may appear to disagree with diff if permissions have
4784 :hg:`status` may appear to disagree with diff if permissions have
4782 changed or a merge has occurred. The standard diff format does
4785 changed or a merge has occurred. The standard diff format does
4783 not report permission changes and diff only reports changes
4786 not report permission changes and diff only reports changes
4784 relative to one merge parent.
4787 relative to one merge parent.
4785
4788
4786 If one revision is given, it is used as the base revision.
4789 If one revision is given, it is used as the base revision.
4787 If two revisions are given, the differences between them are
4790 If two revisions are given, the differences between them are
4788 shown. The --change option can also be used as a shortcut to list
4791 shown. The --change option can also be used as a shortcut to list
4789 the changed files of a revision from its first parent.
4792 the changed files of a revision from its first parent.
4790
4793
4791 The codes used to show the status of files are::
4794 The codes used to show the status of files are::
4792
4795
4793 M = modified
4796 M = modified
4794 A = added
4797 A = added
4795 R = removed
4798 R = removed
4796 C = clean
4799 C = clean
4797 ! = missing (deleted by non-hg command, but still tracked)
4800 ! = missing (deleted by non-hg command, but still tracked)
4798 ? = not tracked
4801 ? = not tracked
4799 I = ignored
4802 I = ignored
4800 = origin of the previous file (with --copies)
4803 = origin of the previous file (with --copies)
4801
4804
4802 .. container:: verbose
4805 .. container:: verbose
4803
4806
4804 The -t/--terse option abbreviates the output by showing only the directory
4807 The -t/--terse option abbreviates the output by showing only the directory
4805 name if all the files in it share the same status. The option takes an
4808 name if all the files in it share the same status. The option takes an
4806 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
4809 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
4807 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
4810 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
4808 for 'ignored' and 'c' for clean.
4811 for 'ignored' and 'c' for clean.
4809
4812
4810 It abbreviates only those statuses which are passed. Note that clean and
4813 It abbreviates only those statuses which are passed. Note that clean and
4811 ignored files are not displayed with '--terse ic' unless the -c/--clean
4814 ignored files are not displayed with '--terse ic' unless the -c/--clean
4812 and -i/--ignored options are also used.
4815 and -i/--ignored options are also used.
4813
4816
4814 The -v/--verbose option shows information when the repository is in an
4817 The -v/--verbose option shows information when the repository is in an
4815 unfinished merge, shelve, rebase state etc. You can have this behavior
4818 unfinished merge, shelve, rebase state etc. You can have this behavior
4816 turned on by default by enabling the ``commands.status.verbose`` option.
4819 turned on by default by enabling the ``commands.status.verbose`` option.
4817
4820
4818 You can skip displaying some of these states by setting
4821 You can skip displaying some of these states by setting
4819 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
4822 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
4820 'histedit', 'merge', 'rebase', or 'unshelve'.
4823 'histedit', 'merge', 'rebase', or 'unshelve'.
4821
4824
4822 Examples:
4825 Examples:
4823
4826
4824 - show changes in the working directory relative to a
4827 - show changes in the working directory relative to a
4825 changeset::
4828 changeset::
4826
4829
4827 hg status --rev 9353
4830 hg status --rev 9353
4828
4831
4829 - show changes in the working directory relative to the
4832 - show changes in the working directory relative to the
4830 current directory (see :hg:`help patterns` for more information)::
4833 current directory (see :hg:`help patterns` for more information)::
4831
4834
4832 hg status re:
4835 hg status re:
4833
4836
4834 - show all changes including copies in an existing changeset::
4837 - show all changes including copies in an existing changeset::
4835
4838
4836 hg status --copies --change 9353
4839 hg status --copies --change 9353
4837
4840
4838 - get a NUL separated list of added files, suitable for xargs::
4841 - get a NUL separated list of added files, suitable for xargs::
4839
4842
4840 hg status -an0
4843 hg status -an0
4841
4844
4842 - show more information about the repository status, abbreviating
4845 - show more information about the repository status, abbreviating
4843 added, removed, modified, deleted, and untracked paths::
4846 added, removed, modified, deleted, and untracked paths::
4844
4847
4845 hg status -v -t mardu
4848 hg status -v -t mardu
4846
4849
4847 Returns 0 on success.
4850 Returns 0 on success.
4848
4851
4849 """
4852 """
4850
4853
4851 opts = pycompat.byteskwargs(opts)
4854 opts = pycompat.byteskwargs(opts)
4852 revs = opts.get('rev')
4855 revs = opts.get('rev')
4853 change = opts.get('change')
4856 change = opts.get('change')
4854 terse = opts.get('terse')
4857 terse = opts.get('terse')
4855
4858
4856 if revs and change:
4859 if revs and change:
4857 msg = _('cannot specify --rev and --change at the same time')
4860 msg = _('cannot specify --rev and --change at the same time')
4858 raise error.Abort(msg)
4861 raise error.Abort(msg)
4859 elif revs and terse:
4862 elif revs and terse:
4860 msg = _('cannot use --terse with --rev')
4863 msg = _('cannot use --terse with --rev')
4861 raise error.Abort(msg)
4864 raise error.Abort(msg)
4862 elif change:
4865 elif change:
4863 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
4866 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
4864 node2 = scmutil.revsingle(repo, change, None).node()
4867 node2 = scmutil.revsingle(repo, change, None).node()
4865 node1 = repo[node2].p1().node()
4868 node1 = repo[node2].p1().node()
4866 else:
4869 else:
4867 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
4870 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
4868 node1, node2 = scmutil.revpair(repo, revs)
4871 node1, node2 = scmutil.revpair(repo, revs)
4869
4872
4870 if pats or ui.configbool('commands', 'status.relative'):
4873 if pats or ui.configbool('commands', 'status.relative'):
4871 cwd = repo.getcwd()
4874 cwd = repo.getcwd()
4872 else:
4875 else:
4873 cwd = ''
4876 cwd = ''
4874
4877
4875 if opts.get('print0'):
4878 if opts.get('print0'):
4876 end = '\0'
4879 end = '\0'
4877 else:
4880 else:
4878 end = '\n'
4881 end = '\n'
4879 copy = {}
4882 copy = {}
4880 states = 'modified added removed deleted unknown ignored clean'.split()
4883 states = 'modified added removed deleted unknown ignored clean'.split()
4881 show = [k for k in states if opts.get(k)]
4884 show = [k for k in states if opts.get(k)]
4882 if opts.get('all'):
4885 if opts.get('all'):
4883 show += ui.quiet and (states[:4] + ['clean']) or states
4886 show += ui.quiet and (states[:4] + ['clean']) or states
4884
4887
4885 if not show:
4888 if not show:
4886 if ui.quiet:
4889 if ui.quiet:
4887 show = states[:4]
4890 show = states[:4]
4888 else:
4891 else:
4889 show = states[:5]
4892 show = states[:5]
4890
4893
4891 m = scmutil.match(repo[node2], pats, opts)
4894 m = scmutil.match(repo[node2], pats, opts)
4892 if terse:
4895 if terse:
4893 # we need to compute clean and unknown to terse
4896 # we need to compute clean and unknown to terse
4894 stat = repo.status(node1, node2, m,
4897 stat = repo.status(node1, node2, m,
4895 'ignored' in show or 'i' in terse,
4898 'ignored' in show or 'i' in terse,
4896 True, True, opts.get('subrepos'))
4899 True, True, opts.get('subrepos'))
4897
4900
4898 stat = cmdutil.tersedir(stat, terse)
4901 stat = cmdutil.tersedir(stat, terse)
4899 else:
4902 else:
4900 stat = repo.status(node1, node2, m,
4903 stat = repo.status(node1, node2, m,
4901 'ignored' in show, 'clean' in show,
4904 'ignored' in show, 'clean' in show,
4902 'unknown' in show, opts.get('subrepos'))
4905 'unknown' in show, opts.get('subrepos'))
4903
4906
4904 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4907 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4905
4908
4906 if (opts.get('all') or opts.get('copies')
4909 if (opts.get('all') or opts.get('copies')
4907 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4910 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4908 copy = copies.pathcopies(repo[node1], repo[node2], m)
4911 copy = copies.pathcopies(repo[node1], repo[node2], m)
4909
4912
4910 ui.pager('status')
4913 ui.pager('status')
4911 fm = ui.formatter('status', opts)
4914 fm = ui.formatter('status', opts)
4912 fmt = '%s' + end
4915 fmt = '%s' + end
4913 showchar = not opts.get('no_status')
4916 showchar = not opts.get('no_status')
4914
4917
4915 for state, char, files in changestates:
4918 for state, char, files in changestates:
4916 if state in show:
4919 if state in show:
4917 label = 'status.' + state
4920 label = 'status.' + state
4918 for f in files:
4921 for f in files:
4919 fm.startitem()
4922 fm.startitem()
4920 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4923 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4921 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4924 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4922 if f in copy:
4925 if f in copy:
4923 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4926 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4924 label='status.copied')
4927 label='status.copied')
4925
4928
4926 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
4929 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
4927 and not ui.plain()):
4930 and not ui.plain()):
4928 cmdutil.morestatus(repo, fm)
4931 cmdutil.morestatus(repo, fm)
4929 fm.end()
4932 fm.end()
4930
4933
4931 @command('^summary|sum',
4934 @command('^summary|sum',
4932 [('', 'remote', None, _('check for push and pull'))],
4935 [('', 'remote', None, _('check for push and pull'))],
4933 '[--remote]', cmdtype=readonly)
4936 '[--remote]', cmdtype=readonly)
4934 def summary(ui, repo, **opts):
4937 def summary(ui, repo, **opts):
4935 """summarize working directory state
4938 """summarize working directory state
4936
4939
4937 This generates a brief summary of the working directory state,
4940 This generates a brief summary of the working directory state,
4938 including parents, branch, commit status, phase and available updates.
4941 including parents, branch, commit status, phase and available updates.
4939
4942
4940 With the --remote option, this will check the default paths for
4943 With the --remote option, this will check the default paths for
4941 incoming and outgoing changes. This can be time-consuming.
4944 incoming and outgoing changes. This can be time-consuming.
4942
4945
4943 Returns 0 on success.
4946 Returns 0 on success.
4944 """
4947 """
4945
4948
4946 opts = pycompat.byteskwargs(opts)
4949 opts = pycompat.byteskwargs(opts)
4947 ui.pager('summary')
4950 ui.pager('summary')
4948 ctx = repo[None]
4951 ctx = repo[None]
4949 parents = ctx.parents()
4952 parents = ctx.parents()
4950 pnode = parents[0].node()
4953 pnode = parents[0].node()
4951 marks = []
4954 marks = []
4952
4955
4953 ms = None
4956 ms = None
4954 try:
4957 try:
4955 ms = mergemod.mergestate.read(repo)
4958 ms = mergemod.mergestate.read(repo)
4956 except error.UnsupportedMergeRecords as e:
4959 except error.UnsupportedMergeRecords as e:
4957 s = ' '.join(e.recordtypes)
4960 s = ' '.join(e.recordtypes)
4958 ui.warn(
4961 ui.warn(
4959 _('warning: merge state has unsupported record types: %s\n') % s)
4962 _('warning: merge state has unsupported record types: %s\n') % s)
4960 unresolved = []
4963 unresolved = []
4961 else:
4964 else:
4962 unresolved = list(ms.unresolved())
4965 unresolved = list(ms.unresolved())
4963
4966
4964 for p in parents:
4967 for p in parents:
4965 # label with log.changeset (instead of log.parent) since this
4968 # label with log.changeset (instead of log.parent) since this
4966 # shows a working directory parent *changeset*:
4969 # shows a working directory parent *changeset*:
4967 # i18n: column positioning for "hg summary"
4970 # i18n: column positioning for "hg summary"
4968 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4971 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4969 label=cmdutil._changesetlabels(p))
4972 label=cmdutil._changesetlabels(p))
4970 ui.write(' '.join(p.tags()), label='log.tag')
4973 ui.write(' '.join(p.tags()), label='log.tag')
4971 if p.bookmarks():
4974 if p.bookmarks():
4972 marks.extend(p.bookmarks())
4975 marks.extend(p.bookmarks())
4973 if p.rev() == -1:
4976 if p.rev() == -1:
4974 if not len(repo):
4977 if not len(repo):
4975 ui.write(_(' (empty repository)'))
4978 ui.write(_(' (empty repository)'))
4976 else:
4979 else:
4977 ui.write(_(' (no revision checked out)'))
4980 ui.write(_(' (no revision checked out)'))
4978 if p.obsolete():
4981 if p.obsolete():
4979 ui.write(_(' (obsolete)'))
4982 ui.write(_(' (obsolete)'))
4980 if p.isunstable():
4983 if p.isunstable():
4981 instabilities = (ui.label(instability, 'trouble.%s' % instability)
4984 instabilities = (ui.label(instability, 'trouble.%s' % instability)
4982 for instability in p.instabilities())
4985 for instability in p.instabilities())
4983 ui.write(' ('
4986 ui.write(' ('
4984 + ', '.join(instabilities)
4987 + ', '.join(instabilities)
4985 + ')')
4988 + ')')
4986 ui.write('\n')
4989 ui.write('\n')
4987 if p.description():
4990 if p.description():
4988 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4991 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4989 label='log.summary')
4992 label='log.summary')
4990
4993
4991 branch = ctx.branch()
4994 branch = ctx.branch()
4992 bheads = repo.branchheads(branch)
4995 bheads = repo.branchheads(branch)
4993 # i18n: column positioning for "hg summary"
4996 # i18n: column positioning for "hg summary"
4994 m = _('branch: %s\n') % branch
4997 m = _('branch: %s\n') % branch
4995 if branch != 'default':
4998 if branch != 'default':
4996 ui.write(m, label='log.branch')
4999 ui.write(m, label='log.branch')
4997 else:
5000 else:
4998 ui.status(m, label='log.branch')
5001 ui.status(m, label='log.branch')
4999
5002
5000 if marks:
5003 if marks:
5001 active = repo._activebookmark
5004 active = repo._activebookmark
5002 # i18n: column positioning for "hg summary"
5005 # i18n: column positioning for "hg summary"
5003 ui.write(_('bookmarks:'), label='log.bookmark')
5006 ui.write(_('bookmarks:'), label='log.bookmark')
5004 if active is not None:
5007 if active is not None:
5005 if active in marks:
5008 if active in marks:
5006 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5009 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5007 marks.remove(active)
5010 marks.remove(active)
5008 else:
5011 else:
5009 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5012 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5010 for m in marks:
5013 for m in marks:
5011 ui.write(' ' + m, label='log.bookmark')
5014 ui.write(' ' + m, label='log.bookmark')
5012 ui.write('\n', label='log.bookmark')
5015 ui.write('\n', label='log.bookmark')
5013
5016
5014 status = repo.status(unknown=True)
5017 status = repo.status(unknown=True)
5015
5018
5016 c = repo.dirstate.copies()
5019 c = repo.dirstate.copies()
5017 copied, renamed = [], []
5020 copied, renamed = [], []
5018 for d, s in c.iteritems():
5021 for d, s in c.iteritems():
5019 if s in status.removed:
5022 if s in status.removed:
5020 status.removed.remove(s)
5023 status.removed.remove(s)
5021 renamed.append(d)
5024 renamed.append(d)
5022 else:
5025 else:
5023 copied.append(d)
5026 copied.append(d)
5024 if d in status.added:
5027 if d in status.added:
5025 status.added.remove(d)
5028 status.added.remove(d)
5026
5029
5027 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5030 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5028
5031
5029 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5032 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5030 (ui.label(_('%d added'), 'status.added'), status.added),
5033 (ui.label(_('%d added'), 'status.added'), status.added),
5031 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5034 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5032 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5035 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5033 (ui.label(_('%d copied'), 'status.copied'), copied),
5036 (ui.label(_('%d copied'), 'status.copied'), copied),
5034 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5037 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5035 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5038 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5036 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5039 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5037 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5040 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5038 t = []
5041 t = []
5039 for l, s in labels:
5042 for l, s in labels:
5040 if s:
5043 if s:
5041 t.append(l % len(s))
5044 t.append(l % len(s))
5042
5045
5043 t = ', '.join(t)
5046 t = ', '.join(t)
5044 cleanworkdir = False
5047 cleanworkdir = False
5045
5048
5046 if repo.vfs.exists('graftstate'):
5049 if repo.vfs.exists('graftstate'):
5047 t += _(' (graft in progress)')
5050 t += _(' (graft in progress)')
5048 if repo.vfs.exists('updatestate'):
5051 if repo.vfs.exists('updatestate'):
5049 t += _(' (interrupted update)')
5052 t += _(' (interrupted update)')
5050 elif len(parents) > 1:
5053 elif len(parents) > 1:
5051 t += _(' (merge)')
5054 t += _(' (merge)')
5052 elif branch != parents[0].branch():
5055 elif branch != parents[0].branch():
5053 t += _(' (new branch)')
5056 t += _(' (new branch)')
5054 elif (parents[0].closesbranch() and
5057 elif (parents[0].closesbranch() and
5055 pnode in repo.branchheads(branch, closed=True)):
5058 pnode in repo.branchheads(branch, closed=True)):
5056 t += _(' (head closed)')
5059 t += _(' (head closed)')
5057 elif not (status.modified or status.added or status.removed or renamed or
5060 elif not (status.modified or status.added or status.removed or renamed or
5058 copied or subs):
5061 copied or subs):
5059 t += _(' (clean)')
5062 t += _(' (clean)')
5060 cleanworkdir = True
5063 cleanworkdir = True
5061 elif pnode not in bheads:
5064 elif pnode not in bheads:
5062 t += _(' (new branch head)')
5065 t += _(' (new branch head)')
5063
5066
5064 if parents:
5067 if parents:
5065 pendingphase = max(p.phase() for p in parents)
5068 pendingphase = max(p.phase() for p in parents)
5066 else:
5069 else:
5067 pendingphase = phases.public
5070 pendingphase = phases.public
5068
5071
5069 if pendingphase > phases.newcommitphase(ui):
5072 if pendingphase > phases.newcommitphase(ui):
5070 t += ' (%s)' % phases.phasenames[pendingphase]
5073 t += ' (%s)' % phases.phasenames[pendingphase]
5071
5074
5072 if cleanworkdir:
5075 if cleanworkdir:
5073 # i18n: column positioning for "hg summary"
5076 # i18n: column positioning for "hg summary"
5074 ui.status(_('commit: %s\n') % t.strip())
5077 ui.status(_('commit: %s\n') % t.strip())
5075 else:
5078 else:
5076 # i18n: column positioning for "hg summary"
5079 # i18n: column positioning for "hg summary"
5077 ui.write(_('commit: %s\n') % t.strip())
5080 ui.write(_('commit: %s\n') % t.strip())
5078
5081
5079 # all ancestors of branch heads - all ancestors of parent = new csets
5082 # all ancestors of branch heads - all ancestors of parent = new csets
5080 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5083 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5081 bheads))
5084 bheads))
5082
5085
5083 if new == 0:
5086 if new == 0:
5084 # i18n: column positioning for "hg summary"
5087 # i18n: column positioning for "hg summary"
5085 ui.status(_('update: (current)\n'))
5088 ui.status(_('update: (current)\n'))
5086 elif pnode not in bheads:
5089 elif pnode not in bheads:
5087 # i18n: column positioning for "hg summary"
5090 # i18n: column positioning for "hg summary"
5088 ui.write(_('update: %d new changesets (update)\n') % new)
5091 ui.write(_('update: %d new changesets (update)\n') % new)
5089 else:
5092 else:
5090 # i18n: column positioning for "hg summary"
5093 # i18n: column positioning for "hg summary"
5091 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5094 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5092 (new, len(bheads)))
5095 (new, len(bheads)))
5093
5096
5094 t = []
5097 t = []
5095 draft = len(repo.revs('draft()'))
5098 draft = len(repo.revs('draft()'))
5096 if draft:
5099 if draft:
5097 t.append(_('%d draft') % draft)
5100 t.append(_('%d draft') % draft)
5098 secret = len(repo.revs('secret()'))
5101 secret = len(repo.revs('secret()'))
5099 if secret:
5102 if secret:
5100 t.append(_('%d secret') % secret)
5103 t.append(_('%d secret') % secret)
5101
5104
5102 if draft or secret:
5105 if draft or secret:
5103 ui.status(_('phases: %s\n') % ', '.join(t))
5106 ui.status(_('phases: %s\n') % ', '.join(t))
5104
5107
5105 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5108 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5106 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5109 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5107 numtrouble = len(repo.revs(trouble + "()"))
5110 numtrouble = len(repo.revs(trouble + "()"))
5108 # We write all the possibilities to ease translation
5111 # We write all the possibilities to ease translation
5109 troublemsg = {
5112 troublemsg = {
5110 "orphan": _("orphan: %d changesets"),
5113 "orphan": _("orphan: %d changesets"),
5111 "contentdivergent": _("content-divergent: %d changesets"),
5114 "contentdivergent": _("content-divergent: %d changesets"),
5112 "phasedivergent": _("phase-divergent: %d changesets"),
5115 "phasedivergent": _("phase-divergent: %d changesets"),
5113 }
5116 }
5114 if numtrouble > 0:
5117 if numtrouble > 0:
5115 ui.status(troublemsg[trouble] % numtrouble + "\n")
5118 ui.status(troublemsg[trouble] % numtrouble + "\n")
5116
5119
5117 cmdutil.summaryhooks(ui, repo)
5120 cmdutil.summaryhooks(ui, repo)
5118
5121
5119 if opts.get('remote'):
5122 if opts.get('remote'):
5120 needsincoming, needsoutgoing = True, True
5123 needsincoming, needsoutgoing = True, True
5121 else:
5124 else:
5122 needsincoming, needsoutgoing = False, False
5125 needsincoming, needsoutgoing = False, False
5123 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5126 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5124 if i:
5127 if i:
5125 needsincoming = True
5128 needsincoming = True
5126 if o:
5129 if o:
5127 needsoutgoing = True
5130 needsoutgoing = True
5128 if not needsincoming and not needsoutgoing:
5131 if not needsincoming and not needsoutgoing:
5129 return
5132 return
5130
5133
5131 def getincoming():
5134 def getincoming():
5132 source, branches = hg.parseurl(ui.expandpath('default'))
5135 source, branches = hg.parseurl(ui.expandpath('default'))
5133 sbranch = branches[0]
5136 sbranch = branches[0]
5134 try:
5137 try:
5135 other = hg.peer(repo, {}, source)
5138 other = hg.peer(repo, {}, source)
5136 except error.RepoError:
5139 except error.RepoError:
5137 if opts.get('remote'):
5140 if opts.get('remote'):
5138 raise
5141 raise
5139 return source, sbranch, None, None, None
5142 return source, sbranch, None, None, None
5140 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5143 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5141 if revs:
5144 if revs:
5142 revs = [other.lookup(rev) for rev in revs]
5145 revs = [other.lookup(rev) for rev in revs]
5143 ui.debug('comparing with %s\n' % util.hidepassword(source))
5146 ui.debug('comparing with %s\n' % util.hidepassword(source))
5144 repo.ui.pushbuffer()
5147 repo.ui.pushbuffer()
5145 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5148 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5146 repo.ui.popbuffer()
5149 repo.ui.popbuffer()
5147 return source, sbranch, other, commoninc, commoninc[1]
5150 return source, sbranch, other, commoninc, commoninc[1]
5148
5151
5149 if needsincoming:
5152 if needsincoming:
5150 source, sbranch, sother, commoninc, incoming = getincoming()
5153 source, sbranch, sother, commoninc, incoming = getincoming()
5151 else:
5154 else:
5152 source = sbranch = sother = commoninc = incoming = None
5155 source = sbranch = sother = commoninc = incoming = None
5153
5156
5154 def getoutgoing():
5157 def getoutgoing():
5155 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5158 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5156 dbranch = branches[0]
5159 dbranch = branches[0]
5157 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5160 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5158 if source != dest:
5161 if source != dest:
5159 try:
5162 try:
5160 dother = hg.peer(repo, {}, dest)
5163 dother = hg.peer(repo, {}, dest)
5161 except error.RepoError:
5164 except error.RepoError:
5162 if opts.get('remote'):
5165 if opts.get('remote'):
5163 raise
5166 raise
5164 return dest, dbranch, None, None
5167 return dest, dbranch, None, None
5165 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5168 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5166 elif sother is None:
5169 elif sother is None:
5167 # there is no explicit destination peer, but source one is invalid
5170 # there is no explicit destination peer, but source one is invalid
5168 return dest, dbranch, None, None
5171 return dest, dbranch, None, None
5169 else:
5172 else:
5170 dother = sother
5173 dother = sother
5171 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5174 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5172 common = None
5175 common = None
5173 else:
5176 else:
5174 common = commoninc
5177 common = commoninc
5175 if revs:
5178 if revs:
5176 revs = [repo.lookup(rev) for rev in revs]
5179 revs = [repo.lookup(rev) for rev in revs]
5177 repo.ui.pushbuffer()
5180 repo.ui.pushbuffer()
5178 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5181 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5179 commoninc=common)
5182 commoninc=common)
5180 repo.ui.popbuffer()
5183 repo.ui.popbuffer()
5181 return dest, dbranch, dother, outgoing
5184 return dest, dbranch, dother, outgoing
5182
5185
5183 if needsoutgoing:
5186 if needsoutgoing:
5184 dest, dbranch, dother, outgoing = getoutgoing()
5187 dest, dbranch, dother, outgoing = getoutgoing()
5185 else:
5188 else:
5186 dest = dbranch = dother = outgoing = None
5189 dest = dbranch = dother = outgoing = None
5187
5190
5188 if opts.get('remote'):
5191 if opts.get('remote'):
5189 t = []
5192 t = []
5190 if incoming:
5193 if incoming:
5191 t.append(_('1 or more incoming'))
5194 t.append(_('1 or more incoming'))
5192 o = outgoing.missing
5195 o = outgoing.missing
5193 if o:
5196 if o:
5194 t.append(_('%d outgoing') % len(o))
5197 t.append(_('%d outgoing') % len(o))
5195 other = dother or sother
5198 other = dother or sother
5196 if 'bookmarks' in other.listkeys('namespaces'):
5199 if 'bookmarks' in other.listkeys('namespaces'):
5197 counts = bookmarks.summary(repo, other)
5200 counts = bookmarks.summary(repo, other)
5198 if counts[0] > 0:
5201 if counts[0] > 0:
5199 t.append(_('%d incoming bookmarks') % counts[0])
5202 t.append(_('%d incoming bookmarks') % counts[0])
5200 if counts[1] > 0:
5203 if counts[1] > 0:
5201 t.append(_('%d outgoing bookmarks') % counts[1])
5204 t.append(_('%d outgoing bookmarks') % counts[1])
5202
5205
5203 if t:
5206 if t:
5204 # i18n: column positioning for "hg summary"
5207 # i18n: column positioning for "hg summary"
5205 ui.write(_('remote: %s\n') % (', '.join(t)))
5208 ui.write(_('remote: %s\n') % (', '.join(t)))
5206 else:
5209 else:
5207 # i18n: column positioning for "hg summary"
5210 # i18n: column positioning for "hg summary"
5208 ui.status(_('remote: (synced)\n'))
5211 ui.status(_('remote: (synced)\n'))
5209
5212
5210 cmdutil.summaryremotehooks(ui, repo, opts,
5213 cmdutil.summaryremotehooks(ui, repo, opts,
5211 ((source, sbranch, sother, commoninc),
5214 ((source, sbranch, sother, commoninc),
5212 (dest, dbranch, dother, outgoing)))
5215 (dest, dbranch, dother, outgoing)))
5213
5216
5214 @command('tag',
5217 @command('tag',
5215 [('f', 'force', None, _('force tag')),
5218 [('f', 'force', None, _('force tag')),
5216 ('l', 'local', None, _('make the tag local')),
5219 ('l', 'local', None, _('make the tag local')),
5217 ('r', 'rev', '', _('revision to tag'), _('REV')),
5220 ('r', 'rev', '', _('revision to tag'), _('REV')),
5218 ('', 'remove', None, _('remove a tag')),
5221 ('', 'remove', None, _('remove a tag')),
5219 # -l/--local is already there, commitopts cannot be used
5222 # -l/--local is already there, commitopts cannot be used
5220 ('e', 'edit', None, _('invoke editor on commit messages')),
5223 ('e', 'edit', None, _('invoke editor on commit messages')),
5221 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5224 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5222 ] + commitopts2,
5225 ] + commitopts2,
5223 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5226 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5224 def tag(ui, repo, name1, *names, **opts):
5227 def tag(ui, repo, name1, *names, **opts):
5225 """add one or more tags for the current or given revision
5228 """add one or more tags for the current or given revision
5226
5229
5227 Name a particular revision using <name>.
5230 Name a particular revision using <name>.
5228
5231
5229 Tags are used to name particular revisions of the repository and are
5232 Tags are used to name particular revisions of the repository and are
5230 very useful to compare different revisions, to go back to significant
5233 very useful to compare different revisions, to go back to significant
5231 earlier versions or to mark branch points as releases, etc. Changing
5234 earlier versions or to mark branch points as releases, etc. Changing
5232 an existing tag is normally disallowed; use -f/--force to override.
5235 an existing tag is normally disallowed; use -f/--force to override.
5233
5236
5234 If no revision is given, the parent of the working directory is
5237 If no revision is given, the parent of the working directory is
5235 used.
5238 used.
5236
5239
5237 To facilitate version control, distribution, and merging of tags,
5240 To facilitate version control, distribution, and merging of tags,
5238 they are stored as a file named ".hgtags" which is managed similarly
5241 they are stored as a file named ".hgtags" which is managed similarly
5239 to other project files and can be hand-edited if necessary. This
5242 to other project files and can be hand-edited if necessary. This
5240 also means that tagging creates a new commit. The file
5243 also means that tagging creates a new commit. The file
5241 ".hg/localtags" is used for local tags (not shared among
5244 ".hg/localtags" is used for local tags (not shared among
5242 repositories).
5245 repositories).
5243
5246
5244 Tag commits are usually made at the head of a branch. If the parent
5247 Tag commits are usually made at the head of a branch. If the parent
5245 of the working directory is not a branch head, :hg:`tag` aborts; use
5248 of the working directory is not a branch head, :hg:`tag` aborts; use
5246 -f/--force to force the tag commit to be based on a non-head
5249 -f/--force to force the tag commit to be based on a non-head
5247 changeset.
5250 changeset.
5248
5251
5249 See :hg:`help dates` for a list of formats valid for -d/--date.
5252 See :hg:`help dates` for a list of formats valid for -d/--date.
5250
5253
5251 Since tag names have priority over branch names during revision
5254 Since tag names have priority over branch names during revision
5252 lookup, using an existing branch name as a tag name is discouraged.
5255 lookup, using an existing branch name as a tag name is discouraged.
5253
5256
5254 Returns 0 on success.
5257 Returns 0 on success.
5255 """
5258 """
5256 opts = pycompat.byteskwargs(opts)
5259 opts = pycompat.byteskwargs(opts)
5257 wlock = lock = None
5260 wlock = lock = None
5258 try:
5261 try:
5259 wlock = repo.wlock()
5262 wlock = repo.wlock()
5260 lock = repo.lock()
5263 lock = repo.lock()
5261 rev_ = "."
5264 rev_ = "."
5262 names = [t.strip() for t in (name1,) + names]
5265 names = [t.strip() for t in (name1,) + names]
5263 if len(names) != len(set(names)):
5266 if len(names) != len(set(names)):
5264 raise error.Abort(_('tag names must be unique'))
5267 raise error.Abort(_('tag names must be unique'))
5265 for n in names:
5268 for n in names:
5266 scmutil.checknewlabel(repo, n, 'tag')
5269 scmutil.checknewlabel(repo, n, 'tag')
5267 if not n:
5270 if not n:
5268 raise error.Abort(_('tag names cannot consist entirely of '
5271 raise error.Abort(_('tag names cannot consist entirely of '
5269 'whitespace'))
5272 'whitespace'))
5270 if opts.get('rev') and opts.get('remove'):
5273 if opts.get('rev') and opts.get('remove'):
5271 raise error.Abort(_("--rev and --remove are incompatible"))
5274 raise error.Abort(_("--rev and --remove are incompatible"))
5272 if opts.get('rev'):
5275 if opts.get('rev'):
5273 rev_ = opts['rev']
5276 rev_ = opts['rev']
5274 message = opts.get('message')
5277 message = opts.get('message')
5275 if opts.get('remove'):
5278 if opts.get('remove'):
5276 if opts.get('local'):
5279 if opts.get('local'):
5277 expectedtype = 'local'
5280 expectedtype = 'local'
5278 else:
5281 else:
5279 expectedtype = 'global'
5282 expectedtype = 'global'
5280
5283
5281 for n in names:
5284 for n in names:
5282 if not repo.tagtype(n):
5285 if not repo.tagtype(n):
5283 raise error.Abort(_("tag '%s' does not exist") % n)
5286 raise error.Abort(_("tag '%s' does not exist") % n)
5284 if repo.tagtype(n) != expectedtype:
5287 if repo.tagtype(n) != expectedtype:
5285 if expectedtype == 'global':
5288 if expectedtype == 'global':
5286 raise error.Abort(_("tag '%s' is not a global tag") % n)
5289 raise error.Abort(_("tag '%s' is not a global tag") % n)
5287 else:
5290 else:
5288 raise error.Abort(_("tag '%s' is not a local tag") % n)
5291 raise error.Abort(_("tag '%s' is not a local tag") % n)
5289 rev_ = 'null'
5292 rev_ = 'null'
5290 if not message:
5293 if not message:
5291 # we don't translate commit messages
5294 # we don't translate commit messages
5292 message = 'Removed tag %s' % ', '.join(names)
5295 message = 'Removed tag %s' % ', '.join(names)
5293 elif not opts.get('force'):
5296 elif not opts.get('force'):
5294 for n in names:
5297 for n in names:
5295 if n in repo.tags():
5298 if n in repo.tags():
5296 raise error.Abort(_("tag '%s' already exists "
5299 raise error.Abort(_("tag '%s' already exists "
5297 "(use -f to force)") % n)
5300 "(use -f to force)") % n)
5298 if not opts.get('local'):
5301 if not opts.get('local'):
5299 p1, p2 = repo.dirstate.parents()
5302 p1, p2 = repo.dirstate.parents()
5300 if p2 != nullid:
5303 if p2 != nullid:
5301 raise error.Abort(_('uncommitted merge'))
5304 raise error.Abort(_('uncommitted merge'))
5302 bheads = repo.branchheads()
5305 bheads = repo.branchheads()
5303 if not opts.get('force') and bheads and p1 not in bheads:
5306 if not opts.get('force') and bheads and p1 not in bheads:
5304 raise error.Abort(_('working directory is not at a branch head '
5307 raise error.Abort(_('working directory is not at a branch head '
5305 '(use -f to force)'))
5308 '(use -f to force)'))
5306 r = scmutil.revsingle(repo, rev_).node()
5309 r = scmutil.revsingle(repo, rev_).node()
5307
5310
5308 if not message:
5311 if not message:
5309 # we don't translate commit messages
5312 # we don't translate commit messages
5310 message = ('Added tag %s for changeset %s' %
5313 message = ('Added tag %s for changeset %s' %
5311 (', '.join(names), short(r)))
5314 (', '.join(names), short(r)))
5312
5315
5313 date = opts.get('date')
5316 date = opts.get('date')
5314 if date:
5317 if date:
5315 date = util.parsedate(date)
5318 date = util.parsedate(date)
5316
5319
5317 if opts.get('remove'):
5320 if opts.get('remove'):
5318 editform = 'tag.remove'
5321 editform = 'tag.remove'
5319 else:
5322 else:
5320 editform = 'tag.add'
5323 editform = 'tag.add'
5321 editor = cmdutil.getcommiteditor(editform=editform,
5324 editor = cmdutil.getcommiteditor(editform=editform,
5322 **pycompat.strkwargs(opts))
5325 **pycompat.strkwargs(opts))
5323
5326
5324 # don't allow tagging the null rev
5327 # don't allow tagging the null rev
5325 if (not opts.get('remove') and
5328 if (not opts.get('remove') and
5326 scmutil.revsingle(repo, rev_).rev() == nullrev):
5329 scmutil.revsingle(repo, rev_).rev() == nullrev):
5327 raise error.Abort(_("cannot tag null revision"))
5330 raise error.Abort(_("cannot tag null revision"))
5328
5331
5329 tagsmod.tag(repo, names, r, message, opts.get('local'),
5332 tagsmod.tag(repo, names, r, message, opts.get('local'),
5330 opts.get('user'), date, editor=editor)
5333 opts.get('user'), date, editor=editor)
5331 finally:
5334 finally:
5332 release(lock, wlock)
5335 release(lock, wlock)
5333
5336
5334 @command('tags', formatteropts, '', cmdtype=readonly)
5337 @command('tags', formatteropts, '', cmdtype=readonly)
5335 def tags(ui, repo, **opts):
5338 def tags(ui, repo, **opts):
5336 """list repository tags
5339 """list repository tags
5337
5340
5338 This lists both regular and local tags. When the -v/--verbose
5341 This lists both regular and local tags. When the -v/--verbose
5339 switch is used, a third column "local" is printed for local tags.
5342 switch is used, a third column "local" is printed for local tags.
5340 When the -q/--quiet switch is used, only the tag name is printed.
5343 When the -q/--quiet switch is used, only the tag name is printed.
5341
5344
5342 Returns 0 on success.
5345 Returns 0 on success.
5343 """
5346 """
5344
5347
5345 opts = pycompat.byteskwargs(opts)
5348 opts = pycompat.byteskwargs(opts)
5346 ui.pager('tags')
5349 ui.pager('tags')
5347 fm = ui.formatter('tags', opts)
5350 fm = ui.formatter('tags', opts)
5348 hexfunc = fm.hexfunc
5351 hexfunc = fm.hexfunc
5349 tagtype = ""
5352 tagtype = ""
5350
5353
5351 for t, n in reversed(repo.tagslist()):
5354 for t, n in reversed(repo.tagslist()):
5352 hn = hexfunc(n)
5355 hn = hexfunc(n)
5353 label = 'tags.normal'
5356 label = 'tags.normal'
5354 tagtype = ''
5357 tagtype = ''
5355 if repo.tagtype(t) == 'local':
5358 if repo.tagtype(t) == 'local':
5356 label = 'tags.local'
5359 label = 'tags.local'
5357 tagtype = 'local'
5360 tagtype = 'local'
5358
5361
5359 fm.startitem()
5362 fm.startitem()
5360 fm.write('tag', '%s', t, label=label)
5363 fm.write('tag', '%s', t, label=label)
5361 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5364 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5362 fm.condwrite(not ui.quiet, 'rev node', fmt,
5365 fm.condwrite(not ui.quiet, 'rev node', fmt,
5363 repo.changelog.rev(n), hn, label=label)
5366 repo.changelog.rev(n), hn, label=label)
5364 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5367 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5365 tagtype, label=label)
5368 tagtype, label=label)
5366 fm.plain('\n')
5369 fm.plain('\n')
5367 fm.end()
5370 fm.end()
5368
5371
5369 @command('tip',
5372 @command('tip',
5370 [('p', 'patch', None, _('show patch')),
5373 [('p', 'patch', None, _('show patch')),
5371 ('g', 'git', None, _('use git extended diff format')),
5374 ('g', 'git', None, _('use git extended diff format')),
5372 ] + templateopts,
5375 ] + templateopts,
5373 _('[-p] [-g]'))
5376 _('[-p] [-g]'))
5374 def tip(ui, repo, **opts):
5377 def tip(ui, repo, **opts):
5375 """show the tip revision (DEPRECATED)
5378 """show the tip revision (DEPRECATED)
5376
5379
5377 The tip revision (usually just called the tip) is the changeset
5380 The tip revision (usually just called the tip) is the changeset
5378 most recently added to the repository (and therefore the most
5381 most recently added to the repository (and therefore the most
5379 recently changed head).
5382 recently changed head).
5380
5383
5381 If you have just made a commit, that commit will be the tip. If
5384 If you have just made a commit, that commit will be the tip. If
5382 you have just pulled changes from another repository, the tip of
5385 you have just pulled changes from another repository, the tip of
5383 that repository becomes the current tip. The "tip" tag is special
5386 that repository becomes the current tip. The "tip" tag is special
5384 and cannot be renamed or assigned to a different changeset.
5387 and cannot be renamed or assigned to a different changeset.
5385
5388
5386 This command is deprecated, please use :hg:`heads` instead.
5389 This command is deprecated, please use :hg:`heads` instead.
5387
5390
5388 Returns 0 on success.
5391 Returns 0 on success.
5389 """
5392 """
5390 opts = pycompat.byteskwargs(opts)
5393 opts = pycompat.byteskwargs(opts)
5391 displayer = cmdutil.show_changeset(ui, repo, opts)
5394 displayer = cmdutil.show_changeset(ui, repo, opts)
5392 displayer.show(repo['tip'])
5395 displayer.show(repo['tip'])
5393 displayer.close()
5396 displayer.close()
5394
5397
5395 @command('unbundle',
5398 @command('unbundle',
5396 [('u', 'update', None,
5399 [('u', 'update', None,
5397 _('update to new branch head if changesets were unbundled'))],
5400 _('update to new branch head if changesets were unbundled'))],
5398 _('[-u] FILE...'))
5401 _('[-u] FILE...'))
5399 def unbundle(ui, repo, fname1, *fnames, **opts):
5402 def unbundle(ui, repo, fname1, *fnames, **opts):
5400 """apply one or more bundle files
5403 """apply one or more bundle files
5401
5404
5402 Apply one or more bundle files generated by :hg:`bundle`.
5405 Apply one or more bundle files generated by :hg:`bundle`.
5403
5406
5404 Returns 0 on success, 1 if an update has unresolved files.
5407 Returns 0 on success, 1 if an update has unresolved files.
5405 """
5408 """
5406 fnames = (fname1,) + fnames
5409 fnames = (fname1,) + fnames
5407
5410
5408 with repo.lock():
5411 with repo.lock():
5409 for fname in fnames:
5412 for fname in fnames:
5410 f = hg.openpath(ui, fname)
5413 f = hg.openpath(ui, fname)
5411 gen = exchange.readbundle(ui, f, fname)
5414 gen = exchange.readbundle(ui, f, fname)
5412 if isinstance(gen, streamclone.streamcloneapplier):
5415 if isinstance(gen, streamclone.streamcloneapplier):
5413 raise error.Abort(
5416 raise error.Abort(
5414 _('packed bundles cannot be applied with '
5417 _('packed bundles cannot be applied with '
5415 '"hg unbundle"'),
5418 '"hg unbundle"'),
5416 hint=_('use "hg debugapplystreamclonebundle"'))
5419 hint=_('use "hg debugapplystreamclonebundle"'))
5417 url = 'bundle:' + fname
5420 url = 'bundle:' + fname
5418 try:
5421 try:
5419 txnname = 'unbundle'
5422 txnname = 'unbundle'
5420 if not isinstance(gen, bundle2.unbundle20):
5423 if not isinstance(gen, bundle2.unbundle20):
5421 txnname = 'unbundle\n%s' % util.hidepassword(url)
5424 txnname = 'unbundle\n%s' % util.hidepassword(url)
5422 with repo.transaction(txnname) as tr:
5425 with repo.transaction(txnname) as tr:
5423 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5426 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5424 url=url)
5427 url=url)
5425 except error.BundleUnknownFeatureError as exc:
5428 except error.BundleUnknownFeatureError as exc:
5426 raise error.Abort(
5429 raise error.Abort(
5427 _('%s: unknown bundle feature, %s') % (fname, exc),
5430 _('%s: unknown bundle feature, %s') % (fname, exc),
5428 hint=_("see https://mercurial-scm.org/"
5431 hint=_("see https://mercurial-scm.org/"
5429 "wiki/BundleFeature for more "
5432 "wiki/BundleFeature for more "
5430 "information"))
5433 "information"))
5431 modheads = bundle2.combinechangegroupresults(op)
5434 modheads = bundle2.combinechangegroupresults(op)
5432
5435
5433 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5436 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5434
5437
5435 @command('^update|up|checkout|co',
5438 @command('^update|up|checkout|co',
5436 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5439 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5437 ('c', 'check', None, _('require clean working directory')),
5440 ('c', 'check', None, _('require clean working directory')),
5438 ('m', 'merge', None, _('merge uncommitted changes')),
5441 ('m', 'merge', None, _('merge uncommitted changes')),
5439 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5442 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5440 ('r', 'rev', '', _('revision'), _('REV'))
5443 ('r', 'rev', '', _('revision'), _('REV'))
5441 ] + mergetoolopts,
5444 ] + mergetoolopts,
5442 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5445 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5443 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5446 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5444 merge=None, tool=None):
5447 merge=None, tool=None):
5445 """update working directory (or switch revisions)
5448 """update working directory (or switch revisions)
5446
5449
5447 Update the repository's working directory to the specified
5450 Update the repository's working directory to the specified
5448 changeset. If no changeset is specified, update to the tip of the
5451 changeset. If no changeset is specified, update to the tip of the
5449 current named branch and move the active bookmark (see :hg:`help
5452 current named branch and move the active bookmark (see :hg:`help
5450 bookmarks`).
5453 bookmarks`).
5451
5454
5452 Update sets the working directory's parent revision to the specified
5455 Update sets the working directory's parent revision to the specified
5453 changeset (see :hg:`help parents`).
5456 changeset (see :hg:`help parents`).
5454
5457
5455 If the changeset is not a descendant or ancestor of the working
5458 If the changeset is not a descendant or ancestor of the working
5456 directory's parent and there are uncommitted changes, the update is
5459 directory's parent and there are uncommitted changes, the update is
5457 aborted. With the -c/--check option, the working directory is checked
5460 aborted. With the -c/--check option, the working directory is checked
5458 for uncommitted changes; if none are found, the working directory is
5461 for uncommitted changes; if none are found, the working directory is
5459 updated to the specified changeset.
5462 updated to the specified changeset.
5460
5463
5461 .. container:: verbose
5464 .. container:: verbose
5462
5465
5463 The -C/--clean, -c/--check, and -m/--merge options control what
5466 The -C/--clean, -c/--check, and -m/--merge options control what
5464 happens if the working directory contains uncommitted changes.
5467 happens if the working directory contains uncommitted changes.
5465 At most of one of them can be specified.
5468 At most of one of them can be specified.
5466
5469
5467 1. If no option is specified, and if
5470 1. If no option is specified, and if
5468 the requested changeset is an ancestor or descendant of
5471 the requested changeset is an ancestor or descendant of
5469 the working directory's parent, the uncommitted changes
5472 the working directory's parent, the uncommitted changes
5470 are merged into the requested changeset and the merged
5473 are merged into the requested changeset and the merged
5471 result is left uncommitted. If the requested changeset is
5474 result is left uncommitted. If the requested changeset is
5472 not an ancestor or descendant (that is, it is on another
5475 not an ancestor or descendant (that is, it is on another
5473 branch), the update is aborted and the uncommitted changes
5476 branch), the update is aborted and the uncommitted changes
5474 are preserved.
5477 are preserved.
5475
5478
5476 2. With the -m/--merge option, the update is allowed even if the
5479 2. With the -m/--merge option, the update is allowed even if the
5477 requested changeset is not an ancestor or descendant of
5480 requested changeset is not an ancestor or descendant of
5478 the working directory's parent.
5481 the working directory's parent.
5479
5482
5480 3. With the -c/--check option, the update is aborted and the
5483 3. With the -c/--check option, the update is aborted and the
5481 uncommitted changes are preserved.
5484 uncommitted changes are preserved.
5482
5485
5483 4. With the -C/--clean option, uncommitted changes are discarded and
5486 4. With the -C/--clean option, uncommitted changes are discarded and
5484 the working directory is updated to the requested changeset.
5487 the working directory is updated to the requested changeset.
5485
5488
5486 To cancel an uncommitted merge (and lose your changes), use
5489 To cancel an uncommitted merge (and lose your changes), use
5487 :hg:`update --clean .`.
5490 :hg:`update --clean .`.
5488
5491
5489 Use null as the changeset to remove the working directory (like
5492 Use null as the changeset to remove the working directory (like
5490 :hg:`clone -U`).
5493 :hg:`clone -U`).
5491
5494
5492 If you want to revert just one file to an older revision, use
5495 If you want to revert just one file to an older revision, use
5493 :hg:`revert [-r REV] NAME`.
5496 :hg:`revert [-r REV] NAME`.
5494
5497
5495 See :hg:`help dates` for a list of formats valid for -d/--date.
5498 See :hg:`help dates` for a list of formats valid for -d/--date.
5496
5499
5497 Returns 0 on success, 1 if there are unresolved files.
5500 Returns 0 on success, 1 if there are unresolved files.
5498 """
5501 """
5499 if rev and node:
5502 if rev and node:
5500 raise error.Abort(_("please specify just one revision"))
5503 raise error.Abort(_("please specify just one revision"))
5501
5504
5502 if ui.configbool('commands', 'update.requiredest'):
5505 if ui.configbool('commands', 'update.requiredest'):
5503 if not node and not rev and not date:
5506 if not node and not rev and not date:
5504 raise error.Abort(_('you must specify a destination'),
5507 raise error.Abort(_('you must specify a destination'),
5505 hint=_('for example: hg update ".::"'))
5508 hint=_('for example: hg update ".::"'))
5506
5509
5507 if rev is None or rev == '':
5510 if rev is None or rev == '':
5508 rev = node
5511 rev = node
5509
5512
5510 if date and rev is not None:
5513 if date and rev is not None:
5511 raise error.Abort(_("you can't specify a revision and a date"))
5514 raise error.Abort(_("you can't specify a revision and a date"))
5512
5515
5513 if len([x for x in (clean, check, merge) if x]) > 1:
5516 if len([x for x in (clean, check, merge) if x]) > 1:
5514 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5517 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5515 "or -m/--merge"))
5518 "or -m/--merge"))
5516
5519
5517 updatecheck = None
5520 updatecheck = None
5518 if check:
5521 if check:
5519 updatecheck = 'abort'
5522 updatecheck = 'abort'
5520 elif merge:
5523 elif merge:
5521 updatecheck = 'none'
5524 updatecheck = 'none'
5522
5525
5523 with repo.wlock():
5526 with repo.wlock():
5524 cmdutil.clearunfinished(repo)
5527 cmdutil.clearunfinished(repo)
5525
5528
5526 if date:
5529 if date:
5527 rev = cmdutil.finddate(ui, repo, date)
5530 rev = cmdutil.finddate(ui, repo, date)
5528
5531
5529 # if we defined a bookmark, we have to remember the original name
5532 # if we defined a bookmark, we have to remember the original name
5530 brev = rev
5533 brev = rev
5531 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5534 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5532 ctx = scmutil.revsingle(repo, rev, rev)
5535 ctx = scmutil.revsingle(repo, rev, rev)
5533 rev = ctx.rev()
5536 rev = ctx.rev()
5534 if ctx.hidden():
5537 if ctx.hidden():
5535 ui.warn(_("updating to a hidden changeset %s\n") % ctx.hex()[:12])
5538 ui.warn(_("updating to a hidden changeset %s\n") % ctx.hex()[:12])
5536
5539
5537 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5540 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5538
5541
5539 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5542 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5540 updatecheck=updatecheck)
5543 updatecheck=updatecheck)
5541
5544
5542 @command('verify', [])
5545 @command('verify', [])
5543 def verify(ui, repo):
5546 def verify(ui, repo):
5544 """verify the integrity of the repository
5547 """verify the integrity of the repository
5545
5548
5546 Verify the integrity of the current repository.
5549 Verify the integrity of the current repository.
5547
5550
5548 This will perform an extensive check of the repository's
5551 This will perform an extensive check of the repository's
5549 integrity, validating the hashes and checksums of each entry in
5552 integrity, validating the hashes and checksums of each entry in
5550 the changelog, manifest, and tracked files, as well as the
5553 the changelog, manifest, and tracked files, as well as the
5551 integrity of their crosslinks and indices.
5554 integrity of their crosslinks and indices.
5552
5555
5553 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5556 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5554 for more information about recovery from corruption of the
5557 for more information about recovery from corruption of the
5555 repository.
5558 repository.
5556
5559
5557 Returns 0 on success, 1 if errors are encountered.
5560 Returns 0 on success, 1 if errors are encountered.
5558 """
5561 """
5559 return hg.verify(repo)
5562 return hg.verify(repo)
5560
5563
5561 @command('version', [] + formatteropts, norepo=True, cmdtype=readonly)
5564 @command('version', [] + formatteropts, norepo=True, cmdtype=readonly)
5562 def version_(ui, **opts):
5565 def version_(ui, **opts):
5563 """output version and copyright information"""
5566 """output version and copyright information"""
5564 opts = pycompat.byteskwargs(opts)
5567 opts = pycompat.byteskwargs(opts)
5565 if ui.verbose:
5568 if ui.verbose:
5566 ui.pager('version')
5569 ui.pager('version')
5567 fm = ui.formatter("version", opts)
5570 fm = ui.formatter("version", opts)
5568 fm.startitem()
5571 fm.startitem()
5569 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5572 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5570 util.version())
5573 util.version())
5571 license = _(
5574 license = _(
5572 "(see https://mercurial-scm.org for more information)\n"
5575 "(see https://mercurial-scm.org for more information)\n"
5573 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5576 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5574 "This is free software; see the source for copying conditions. "
5577 "This is free software; see the source for copying conditions. "
5575 "There is NO\nwarranty; "
5578 "There is NO\nwarranty; "
5576 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5579 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5577 )
5580 )
5578 if not ui.quiet:
5581 if not ui.quiet:
5579 fm.plain(license)
5582 fm.plain(license)
5580
5583
5581 if ui.verbose:
5584 if ui.verbose:
5582 fm.plain(_("\nEnabled extensions:\n\n"))
5585 fm.plain(_("\nEnabled extensions:\n\n"))
5583 # format names and versions into columns
5586 # format names and versions into columns
5584 names = []
5587 names = []
5585 vers = []
5588 vers = []
5586 isinternals = []
5589 isinternals = []
5587 for name, module in extensions.extensions():
5590 for name, module in extensions.extensions():
5588 names.append(name)
5591 names.append(name)
5589 vers.append(extensions.moduleversion(module) or None)
5592 vers.append(extensions.moduleversion(module) or None)
5590 isinternals.append(extensions.ismoduleinternal(module))
5593 isinternals.append(extensions.ismoduleinternal(module))
5591 fn = fm.nested("extensions")
5594 fn = fm.nested("extensions")
5592 if names:
5595 if names:
5593 namefmt = " %%-%ds " % max(len(n) for n in names)
5596 namefmt = " %%-%ds " % max(len(n) for n in names)
5594 places = [_("external"), _("internal")]
5597 places = [_("external"), _("internal")]
5595 for n, v, p in zip(names, vers, isinternals):
5598 for n, v, p in zip(names, vers, isinternals):
5596 fn.startitem()
5599 fn.startitem()
5597 fn.condwrite(ui.verbose, "name", namefmt, n)
5600 fn.condwrite(ui.verbose, "name", namefmt, n)
5598 if ui.verbose:
5601 if ui.verbose:
5599 fn.plain("%s " % places[p])
5602 fn.plain("%s " % places[p])
5600 fn.data(bundled=p)
5603 fn.data(bundled=p)
5601 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5604 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5602 if ui.verbose:
5605 if ui.verbose:
5603 fn.plain("\n")
5606 fn.plain("\n")
5604 fn.end()
5607 fn.end()
5605 fm.end()
5608 fm.end()
5606
5609
5607 def loadcmdtable(ui, name, cmdtable):
5610 def loadcmdtable(ui, name, cmdtable):
5608 """Load command functions from specified cmdtable
5611 """Load command functions from specified cmdtable
5609 """
5612 """
5610 overrides = [cmd for cmd in cmdtable if cmd in table]
5613 overrides = [cmd for cmd in cmdtable if cmd in table]
5611 if overrides:
5614 if overrides:
5612 ui.warn(_("extension '%s' overrides commands: %s\n")
5615 ui.warn(_("extension '%s' overrides commands: %s\n")
5613 % (name, " ".join(overrides)))
5616 % (name, " ".join(overrides)))
5614 table.update(cmdtable)
5617 table.update(cmdtable)
@@ -1,165 +1,178 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 status`
141 `hg status`
142
142
143 $ hg status --change 28ad74
143 $ hg status --change 28ad74
144 A c
144 A c
145
145
146 `hg update`
146 `hg update`
147
147
148 $ hg up 28ad74
148 $ hg up 28ad74
149 updating to a hidden changeset 28ad74487de9
149 updating to a hidden changeset 28ad74487de9
150 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
150 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
151
151
152 $ hg up 3
152 $ hg up 3
153 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
153 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
154
154
155 `hg revert`
156
157 $ hg revert -r 28ad74 --all
158 reverting c
159
160 $ hg diff
161 diff -r 2443a0e66469 c
162 --- a/c Thu Jan 01 00:00:00 1970 +0000
163 +++ b/c Thu Jan 01 00:00:00 1970 +0000
164 @@ -1,2 +1,1 @@
165 foo
166 -bar
167
155 Commands with undefined cmdtype should not work right now
168 Commands with undefined cmdtype should not work right now
156
169
157 $ hg phase -r 28ad74
170 $ hg phase -r 28ad74
158 abort: hidden revision '28ad74'!
171 abort: hidden revision '28ad74'!
159 (use --hidden to access hidden revisions)
172 (use --hidden to access hidden revisions)
160 [255]
173 [255]
161
174
162 $ hg phase -r 2
175 $ hg phase -r 2
163 abort: hidden revision '2'!
176 abort: hidden revision '2'!
164 (use --hidden to access hidden revisions)
177 (use --hidden to access hidden revisions)
165 [255]
178 [255]
General Comments 0
You need to be logged in to leave comments. Login now