##// END OF EJS Templates
commands: use dirstateguard instead of begin/end-parentchange for backout...
FUJIWARA Katsunori -
r26581:6e715040 default
parent child Browse files
Show More
@@ -1,6651 +1,6652 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 node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _
10 from i18n import _
11 import os, re, difflib, time, tempfile, errno, shlex
11 import os, re, difflib, time, tempfile, errno, shlex
12 import sys, socket
12 import sys, socket
13 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import hg, scmutil, util, revlog, copies, error, bookmarks
14 import patch, help, encoding, templatekw, discovery
14 import patch, help, encoding, templatekw, discovery
15 import archival, changegroup, cmdutil, hbisect
15 import archival, changegroup, cmdutil, hbisect
16 import sshserver, hgweb
16 import sshserver, hgweb
17 import extensions
17 import extensions
18 from hgweb import server as hgweb_server
18 from hgweb import server as hgweb_server
19 import merge as mergemod
19 import merge as mergemod
20 import minirst, revset, fileset
20 import minirst, revset, fileset
21 import dagparser, context, simplemerge, graphmod, copies
21 import dagparser, context, simplemerge, graphmod, copies
22 import random, operator
22 import random, operator
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
24 import phases, obsolete, exchange, bundle2, repair, lock as lockmod
24 import phases, obsolete, exchange, bundle2, repair, lock as lockmod
25 import ui as uimod
25 import ui as uimod
26
26
27 table = {}
27 table = {}
28
28
29 command = cmdutil.command(table)
29 command = cmdutil.command(table)
30
30
31 # Space delimited list of commands that don't require local repositories.
31 # Space delimited list of commands that don't require local repositories.
32 # This should be populated by passing norepo=True into the @command decorator.
32 # This should be populated by passing norepo=True into the @command decorator.
33 norepo = ''
33 norepo = ''
34 # Space delimited list of commands that optionally require local repositories.
34 # Space delimited list of commands that optionally require local repositories.
35 # This should be populated by passing optionalrepo=True into the @command
35 # This should be populated by passing optionalrepo=True into the @command
36 # decorator.
36 # decorator.
37 optionalrepo = ''
37 optionalrepo = ''
38 # Space delimited list of commands that will examine arguments looking for
38 # Space delimited list of commands that will examine arguments looking for
39 # a repository. This should be populated by passing inferrepo=True into the
39 # a repository. This should be populated by passing inferrepo=True into the
40 # @command decorator.
40 # @command decorator.
41 inferrepo = ''
41 inferrepo = ''
42
42
43 # label constants
43 # label constants
44 # until 3.5, bookmarks.current was the advertised name, not
44 # until 3.5, bookmarks.current was the advertised name, not
45 # bookmarks.active, so we must use both to avoid breaking old
45 # bookmarks.active, so we must use both to avoid breaking old
46 # custom styles
46 # custom styles
47 activebookmarklabel = 'bookmarks.active bookmarks.current'
47 activebookmarklabel = 'bookmarks.active bookmarks.current'
48
48
49 # common command options
49 # common command options
50
50
51 globalopts = [
51 globalopts = [
52 ('R', 'repository', '',
52 ('R', 'repository', '',
53 _('repository root directory or name of overlay bundle file'),
53 _('repository root directory or name of overlay bundle file'),
54 _('REPO')),
54 _('REPO')),
55 ('', 'cwd', '',
55 ('', 'cwd', '',
56 _('change working directory'), _('DIR')),
56 _('change working directory'), _('DIR')),
57 ('y', 'noninteractive', None,
57 ('y', 'noninteractive', None,
58 _('do not prompt, automatically pick the first choice for all prompts')),
58 _('do not prompt, automatically pick the first choice for all prompts')),
59 ('q', 'quiet', None, _('suppress output')),
59 ('q', 'quiet', None, _('suppress output')),
60 ('v', 'verbose', None, _('enable additional output')),
60 ('v', 'verbose', None, _('enable additional output')),
61 ('', 'config', [],
61 ('', 'config', [],
62 _('set/override config option (use \'section.name=value\')'),
62 _('set/override config option (use \'section.name=value\')'),
63 _('CONFIG')),
63 _('CONFIG')),
64 ('', 'debug', None, _('enable debugging output')),
64 ('', 'debug', None, _('enable debugging output')),
65 ('', 'debugger', None, _('start debugger')),
65 ('', 'debugger', None, _('start debugger')),
66 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
66 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
67 _('ENCODE')),
67 _('ENCODE')),
68 ('', 'encodingmode', encoding.encodingmode,
68 ('', 'encodingmode', encoding.encodingmode,
69 _('set the charset encoding mode'), _('MODE')),
69 _('set the charset encoding mode'), _('MODE')),
70 ('', 'traceback', None, _('always print a traceback on exception')),
70 ('', 'traceback', None, _('always print a traceback on exception')),
71 ('', 'time', None, _('time how long the command takes')),
71 ('', 'time', None, _('time how long the command takes')),
72 ('', 'profile', None, _('print command execution profile')),
72 ('', 'profile', None, _('print command execution profile')),
73 ('', 'version', None, _('output version information and exit')),
73 ('', 'version', None, _('output version information and exit')),
74 ('h', 'help', None, _('display help and exit')),
74 ('h', 'help', None, _('display help and exit')),
75 ('', 'hidden', False, _('consider hidden changesets')),
75 ('', 'hidden', False, _('consider hidden changesets')),
76 ]
76 ]
77
77
78 dryrunopts = [('n', 'dry-run', None,
78 dryrunopts = [('n', 'dry-run', None,
79 _('do not perform actions, just print output'))]
79 _('do not perform actions, just print output'))]
80
80
81 remoteopts = [
81 remoteopts = [
82 ('e', 'ssh', '',
82 ('e', 'ssh', '',
83 _('specify ssh command to use'), _('CMD')),
83 _('specify ssh command to use'), _('CMD')),
84 ('', 'remotecmd', '',
84 ('', 'remotecmd', '',
85 _('specify hg command to run on the remote side'), _('CMD')),
85 _('specify hg command to run on the remote side'), _('CMD')),
86 ('', 'insecure', None,
86 ('', 'insecure', None,
87 _('do not verify server certificate (ignoring web.cacerts config)')),
87 _('do not verify server certificate (ignoring web.cacerts config)')),
88 ]
88 ]
89
89
90 walkopts = [
90 walkopts = [
91 ('I', 'include', [],
91 ('I', 'include', [],
92 _('include names matching the given patterns'), _('PATTERN')),
92 _('include names matching the given patterns'), _('PATTERN')),
93 ('X', 'exclude', [],
93 ('X', 'exclude', [],
94 _('exclude names matching the given patterns'), _('PATTERN')),
94 _('exclude names matching the given patterns'), _('PATTERN')),
95 ]
95 ]
96
96
97 commitopts = [
97 commitopts = [
98 ('m', 'message', '',
98 ('m', 'message', '',
99 _('use text as commit message'), _('TEXT')),
99 _('use text as commit message'), _('TEXT')),
100 ('l', 'logfile', '',
100 ('l', 'logfile', '',
101 _('read commit message from file'), _('FILE')),
101 _('read commit message from file'), _('FILE')),
102 ]
102 ]
103
103
104 commitopts2 = [
104 commitopts2 = [
105 ('d', 'date', '',
105 ('d', 'date', '',
106 _('record the specified date as commit date'), _('DATE')),
106 _('record the specified date as commit date'), _('DATE')),
107 ('u', 'user', '',
107 ('u', 'user', '',
108 _('record the specified user as committer'), _('USER')),
108 _('record the specified user as committer'), _('USER')),
109 ]
109 ]
110
110
111 # hidden for now
111 # hidden for now
112 formatteropts = [
112 formatteropts = [
113 ('T', 'template', '',
113 ('T', 'template', '',
114 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
114 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
115 ]
115 ]
116
116
117 templateopts = [
117 templateopts = [
118 ('', 'style', '',
118 ('', 'style', '',
119 _('display using template map file (DEPRECATED)'), _('STYLE')),
119 _('display using template map file (DEPRECATED)'), _('STYLE')),
120 ('T', 'template', '',
120 ('T', 'template', '',
121 _('display with template'), _('TEMPLATE')),
121 _('display with template'), _('TEMPLATE')),
122 ]
122 ]
123
123
124 logopts = [
124 logopts = [
125 ('p', 'patch', None, _('show patch')),
125 ('p', 'patch', None, _('show patch')),
126 ('g', 'git', None, _('use git extended diff format')),
126 ('g', 'git', None, _('use git extended diff format')),
127 ('l', 'limit', '',
127 ('l', 'limit', '',
128 _('limit number of changes displayed'), _('NUM')),
128 _('limit number of changes displayed'), _('NUM')),
129 ('M', 'no-merges', None, _('do not show merges')),
129 ('M', 'no-merges', None, _('do not show merges')),
130 ('', 'stat', None, _('output diffstat-style summary of changes')),
130 ('', 'stat', None, _('output diffstat-style summary of changes')),
131 ('G', 'graph', None, _("show the revision DAG")),
131 ('G', 'graph', None, _("show the revision DAG")),
132 ] + templateopts
132 ] + templateopts
133
133
134 diffopts = [
134 diffopts = [
135 ('a', 'text', None, _('treat all files as text')),
135 ('a', 'text', None, _('treat all files as text')),
136 ('g', 'git', None, _('use git extended diff format')),
136 ('g', 'git', None, _('use git extended diff format')),
137 ('', 'nodates', None, _('omit dates from diff headers'))
137 ('', 'nodates', None, _('omit dates from diff headers'))
138 ]
138 ]
139
139
140 diffwsopts = [
140 diffwsopts = [
141 ('w', 'ignore-all-space', None,
141 ('w', 'ignore-all-space', None,
142 _('ignore white space when comparing lines')),
142 _('ignore white space when comparing lines')),
143 ('b', 'ignore-space-change', None,
143 ('b', 'ignore-space-change', None,
144 _('ignore changes in the amount of white space')),
144 _('ignore changes in the amount of white space')),
145 ('B', 'ignore-blank-lines', None,
145 ('B', 'ignore-blank-lines', None,
146 _('ignore changes whose lines are all blank')),
146 _('ignore changes whose lines are all blank')),
147 ]
147 ]
148
148
149 diffopts2 = [
149 diffopts2 = [
150 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
150 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
151 ('p', 'show-function', None, _('show which function each change is in')),
151 ('p', 'show-function', None, _('show which function each change is in')),
152 ('', 'reverse', None, _('produce a diff that undoes the changes')),
152 ('', 'reverse', None, _('produce a diff that undoes the changes')),
153 ] + diffwsopts + [
153 ] + diffwsopts + [
154 ('U', 'unified', '',
154 ('U', 'unified', '',
155 _('number of lines of context to show'), _('NUM')),
155 _('number of lines of context to show'), _('NUM')),
156 ('', 'stat', None, _('output diffstat-style summary of changes')),
156 ('', 'stat', None, _('output diffstat-style summary of changes')),
157 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
157 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
158 ]
158 ]
159
159
160 mergetoolopts = [
160 mergetoolopts = [
161 ('t', 'tool', '', _('specify merge tool')),
161 ('t', 'tool', '', _('specify merge tool')),
162 ]
162 ]
163
163
164 similarityopts = [
164 similarityopts = [
165 ('s', 'similarity', '',
165 ('s', 'similarity', '',
166 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
166 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
167 ]
167 ]
168
168
169 subrepoopts = [
169 subrepoopts = [
170 ('S', 'subrepos', None,
170 ('S', 'subrepos', None,
171 _('recurse into subrepositories'))
171 _('recurse into subrepositories'))
172 ]
172 ]
173
173
174 # Commands start here, listed alphabetically
174 # Commands start here, listed alphabetically
175
175
176 @command('^add',
176 @command('^add',
177 walkopts + subrepoopts + dryrunopts,
177 walkopts + subrepoopts + dryrunopts,
178 _('[OPTION]... [FILE]...'),
178 _('[OPTION]... [FILE]...'),
179 inferrepo=True)
179 inferrepo=True)
180 def add(ui, repo, *pats, **opts):
180 def add(ui, repo, *pats, **opts):
181 """add the specified files on the next commit
181 """add the specified files on the next commit
182
182
183 Schedule files to be version controlled and added to the
183 Schedule files to be version controlled and added to the
184 repository.
184 repository.
185
185
186 The files will be added to the repository at the next commit. To
186 The files will be added to the repository at the next commit. To
187 undo an add before that, see :hg:`forget`.
187 undo an add before that, see :hg:`forget`.
188
188
189 If no names are given, add all files to the repository.
189 If no names are given, add all files to the repository.
190
190
191 .. container:: verbose
191 .. container:: verbose
192
192
193 An example showing how new (unknown) files are added
193 An example showing how new (unknown) files are added
194 automatically by :hg:`add`::
194 automatically by :hg:`add`::
195
195
196 $ ls
196 $ ls
197 foo.c
197 foo.c
198 $ hg status
198 $ hg status
199 ? foo.c
199 ? foo.c
200 $ hg add
200 $ hg add
201 adding foo.c
201 adding foo.c
202 $ hg status
202 $ hg status
203 A foo.c
203 A foo.c
204
204
205 Returns 0 if all files are successfully added.
205 Returns 0 if all files are successfully added.
206 """
206 """
207
207
208 m = scmutil.match(repo[None], pats, opts)
208 m = scmutil.match(repo[None], pats, opts)
209 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
209 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
210 return rejected and 1 or 0
210 return rejected and 1 or 0
211
211
212 @command('addremove',
212 @command('addremove',
213 similarityopts + subrepoopts + walkopts + dryrunopts,
213 similarityopts + subrepoopts + walkopts + dryrunopts,
214 _('[OPTION]... [FILE]...'),
214 _('[OPTION]... [FILE]...'),
215 inferrepo=True)
215 inferrepo=True)
216 def addremove(ui, repo, *pats, **opts):
216 def addremove(ui, repo, *pats, **opts):
217 """add all new files, delete all missing files
217 """add all new files, delete all missing files
218
218
219 Add all new files and remove all missing files from the
219 Add all new files and remove all missing files from the
220 repository.
220 repository.
221
221
222 New files are ignored if they match any of the patterns in
222 New files are ignored if they match any of the patterns in
223 ``.hgignore``. As with add, these changes take effect at the next
223 ``.hgignore``. As with add, these changes take effect at the next
224 commit.
224 commit.
225
225
226 Use the -s/--similarity option to detect renamed files. This
226 Use the -s/--similarity option to detect renamed files. This
227 option takes a percentage between 0 (disabled) and 100 (files must
227 option takes a percentage between 0 (disabled) and 100 (files must
228 be identical) as its parameter. With a parameter greater than 0,
228 be identical) as its parameter. With a parameter greater than 0,
229 this compares every removed file with every added file and records
229 this compares every removed file with every added file and records
230 those similar enough as renames. Detecting renamed files this way
230 those similar enough as renames. Detecting renamed files this way
231 can be expensive. After using this option, :hg:`status -C` can be
231 can be expensive. After using this option, :hg:`status -C` can be
232 used to check which files were identified as moved or renamed. If
232 used to check which files were identified as moved or renamed. If
233 not specified, -s/--similarity defaults to 100 and only renames of
233 not specified, -s/--similarity defaults to 100 and only renames of
234 identical files are detected.
234 identical files are detected.
235
235
236 Returns 0 if all files are successfully added.
236 Returns 0 if all files are successfully added.
237 """
237 """
238 try:
238 try:
239 sim = float(opts.get('similarity') or 100)
239 sim = float(opts.get('similarity') or 100)
240 except ValueError:
240 except ValueError:
241 raise util.Abort(_('similarity must be a number'))
241 raise util.Abort(_('similarity must be a number'))
242 if sim < 0 or sim > 100:
242 if sim < 0 or sim > 100:
243 raise util.Abort(_('similarity must be between 0 and 100'))
243 raise util.Abort(_('similarity must be between 0 and 100'))
244 matcher = scmutil.match(repo[None], pats, opts)
244 matcher = scmutil.match(repo[None], pats, opts)
245 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
245 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
246
246
247 @command('^annotate|blame',
247 @command('^annotate|blame',
248 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
248 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
249 ('', 'follow', None,
249 ('', 'follow', None,
250 _('follow copies/renames and list the filename (DEPRECATED)')),
250 _('follow copies/renames and list the filename (DEPRECATED)')),
251 ('', 'no-follow', None, _("don't follow copies and renames")),
251 ('', 'no-follow', None, _("don't follow copies and renames")),
252 ('a', 'text', None, _('treat all files as text')),
252 ('a', 'text', None, _('treat all files as text')),
253 ('u', 'user', None, _('list the author (long with -v)')),
253 ('u', 'user', None, _('list the author (long with -v)')),
254 ('f', 'file', None, _('list the filename')),
254 ('f', 'file', None, _('list the filename')),
255 ('d', 'date', None, _('list the date (short with -q)')),
255 ('d', 'date', None, _('list the date (short with -q)')),
256 ('n', 'number', None, _('list the revision number (default)')),
256 ('n', 'number', None, _('list the revision number (default)')),
257 ('c', 'changeset', None, _('list the changeset')),
257 ('c', 'changeset', None, _('list the changeset')),
258 ('l', 'line-number', None, _('show line number at the first appearance'))
258 ('l', 'line-number', None, _('show line number at the first appearance'))
259 ] + diffwsopts + walkopts + formatteropts,
259 ] + diffwsopts + walkopts + formatteropts,
260 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
260 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
261 inferrepo=True)
261 inferrepo=True)
262 def annotate(ui, repo, *pats, **opts):
262 def annotate(ui, repo, *pats, **opts):
263 """show changeset information by line for each file
263 """show changeset information by line for each file
264
264
265 List changes in files, showing the revision id responsible for
265 List changes in files, showing the revision id responsible for
266 each line
266 each line
267
267
268 This command is useful for discovering when a change was made and
268 This command is useful for discovering when a change was made and
269 by whom.
269 by whom.
270
270
271 Without the -a/--text option, annotate will avoid processing files
271 Without the -a/--text option, annotate will avoid processing files
272 it detects as binary. With -a, annotate will annotate the file
272 it detects as binary. With -a, annotate will annotate the file
273 anyway, although the results will probably be neither useful
273 anyway, although the results will probably be neither useful
274 nor desirable.
274 nor desirable.
275
275
276 Returns 0 on success.
276 Returns 0 on success.
277 """
277 """
278 if not pats:
278 if not pats:
279 raise util.Abort(_('at least one filename or pattern is required'))
279 raise util.Abort(_('at least one filename or pattern is required'))
280
280
281 if opts.get('follow'):
281 if opts.get('follow'):
282 # --follow is deprecated and now just an alias for -f/--file
282 # --follow is deprecated and now just an alias for -f/--file
283 # to mimic the behavior of Mercurial before version 1.5
283 # to mimic the behavior of Mercurial before version 1.5
284 opts['file'] = True
284 opts['file'] = True
285
285
286 ctx = scmutil.revsingle(repo, opts.get('rev'))
286 ctx = scmutil.revsingle(repo, opts.get('rev'))
287
287
288 fm = ui.formatter('annotate', opts)
288 fm = ui.formatter('annotate', opts)
289 if ui.quiet:
289 if ui.quiet:
290 datefunc = util.shortdate
290 datefunc = util.shortdate
291 else:
291 else:
292 datefunc = util.datestr
292 datefunc = util.datestr
293 if ctx.rev() is None:
293 if ctx.rev() is None:
294 def hexfn(node):
294 def hexfn(node):
295 if node is None:
295 if node is None:
296 return None
296 return None
297 else:
297 else:
298 return fm.hexfunc(node)
298 return fm.hexfunc(node)
299 if opts.get('changeset'):
299 if opts.get('changeset'):
300 # omit "+" suffix which is appended to node hex
300 # omit "+" suffix which is appended to node hex
301 def formatrev(rev):
301 def formatrev(rev):
302 if rev is None:
302 if rev is None:
303 return '%d' % ctx.p1().rev()
303 return '%d' % ctx.p1().rev()
304 else:
304 else:
305 return '%d' % rev
305 return '%d' % rev
306 else:
306 else:
307 def formatrev(rev):
307 def formatrev(rev):
308 if rev is None:
308 if rev is None:
309 return '%d+' % ctx.p1().rev()
309 return '%d+' % ctx.p1().rev()
310 else:
310 else:
311 return '%d ' % rev
311 return '%d ' % rev
312 def formathex(hex):
312 def formathex(hex):
313 if hex is None:
313 if hex is None:
314 return '%s+' % fm.hexfunc(ctx.p1().node())
314 return '%s+' % fm.hexfunc(ctx.p1().node())
315 else:
315 else:
316 return '%s ' % hex
316 return '%s ' % hex
317 else:
317 else:
318 hexfn = fm.hexfunc
318 hexfn = fm.hexfunc
319 formatrev = formathex = str
319 formatrev = formathex = str
320
320
321 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
321 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
322 ('number', ' ', lambda x: x[0].rev(), formatrev),
322 ('number', ' ', lambda x: x[0].rev(), formatrev),
323 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
323 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
324 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
324 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
325 ('file', ' ', lambda x: x[0].path(), str),
325 ('file', ' ', lambda x: x[0].path(), str),
326 ('line_number', ':', lambda x: x[1], str),
326 ('line_number', ':', lambda x: x[1], str),
327 ]
327 ]
328 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
328 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
329
329
330 if (not opts.get('user') and not opts.get('changeset')
330 if (not opts.get('user') and not opts.get('changeset')
331 and not opts.get('date') and not opts.get('file')):
331 and not opts.get('date') and not opts.get('file')):
332 opts['number'] = True
332 opts['number'] = True
333
333
334 linenumber = opts.get('line_number') is not None
334 linenumber = opts.get('line_number') is not None
335 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
335 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
336 raise util.Abort(_('at least one of -n/-c is required for -l'))
336 raise util.Abort(_('at least one of -n/-c is required for -l'))
337
337
338 if fm:
338 if fm:
339 def makefunc(get, fmt):
339 def makefunc(get, fmt):
340 return get
340 return get
341 else:
341 else:
342 def makefunc(get, fmt):
342 def makefunc(get, fmt):
343 return lambda x: fmt(get(x))
343 return lambda x: fmt(get(x))
344 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
344 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
345 if opts.get(op)]
345 if opts.get(op)]
346 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
346 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
347 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
347 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
348 if opts.get(op))
348 if opts.get(op))
349
349
350 def bad(x, y):
350 def bad(x, y):
351 raise util.Abort("%s: %s" % (x, y))
351 raise util.Abort("%s: %s" % (x, y))
352
352
353 m = scmutil.match(ctx, pats, opts, badfn=bad)
353 m = scmutil.match(ctx, pats, opts, badfn=bad)
354
354
355 follow = not opts.get('no_follow')
355 follow = not opts.get('no_follow')
356 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
356 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
357 whitespace=True)
357 whitespace=True)
358 for abs in ctx.walk(m):
358 for abs in ctx.walk(m):
359 fctx = ctx[abs]
359 fctx = ctx[abs]
360 if not opts.get('text') and util.binary(fctx.data()):
360 if not opts.get('text') and util.binary(fctx.data()):
361 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
361 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
362 continue
362 continue
363
363
364 lines = fctx.annotate(follow=follow, linenumber=linenumber,
364 lines = fctx.annotate(follow=follow, linenumber=linenumber,
365 diffopts=diffopts)
365 diffopts=diffopts)
366 formats = []
366 formats = []
367 pieces = []
367 pieces = []
368
368
369 for f, sep in funcmap:
369 for f, sep in funcmap:
370 l = [f(n) for n, dummy in lines]
370 l = [f(n) for n, dummy in lines]
371 if l:
371 if l:
372 if fm:
372 if fm:
373 formats.append(['%s' for x in l])
373 formats.append(['%s' for x in l])
374 else:
374 else:
375 sizes = [encoding.colwidth(x) for x in l]
375 sizes = [encoding.colwidth(x) for x in l]
376 ml = max(sizes)
376 ml = max(sizes)
377 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
377 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
378 pieces.append(l)
378 pieces.append(l)
379
379
380 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
380 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
381 fm.startitem()
381 fm.startitem()
382 fm.write(fields, "".join(f), *p)
382 fm.write(fields, "".join(f), *p)
383 fm.write('line', ": %s", l[1])
383 fm.write('line', ": %s", l[1])
384
384
385 if lines and not lines[-1][1].endswith('\n'):
385 if lines and not lines[-1][1].endswith('\n'):
386 fm.plain('\n')
386 fm.plain('\n')
387
387
388 fm.end()
388 fm.end()
389
389
390 @command('archive',
390 @command('archive',
391 [('', 'no-decode', None, _('do not pass files through decoders')),
391 [('', 'no-decode', None, _('do not pass files through decoders')),
392 ('p', 'prefix', '', _('directory prefix for files in archive'),
392 ('p', 'prefix', '', _('directory prefix for files in archive'),
393 _('PREFIX')),
393 _('PREFIX')),
394 ('r', 'rev', '', _('revision to distribute'), _('REV')),
394 ('r', 'rev', '', _('revision to distribute'), _('REV')),
395 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
395 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
396 ] + subrepoopts + walkopts,
396 ] + subrepoopts + walkopts,
397 _('[OPTION]... DEST'))
397 _('[OPTION]... DEST'))
398 def archive(ui, repo, dest, **opts):
398 def archive(ui, repo, dest, **opts):
399 '''create an unversioned archive of a repository revision
399 '''create an unversioned archive of a repository revision
400
400
401 By default, the revision used is the parent of the working
401 By default, the revision used is the parent of the working
402 directory; use -r/--rev to specify a different revision.
402 directory; use -r/--rev to specify a different revision.
403
403
404 The archive type is automatically detected based on file
404 The archive type is automatically detected based on file
405 extension (or override using -t/--type).
405 extension (or override using -t/--type).
406
406
407 .. container:: verbose
407 .. container:: verbose
408
408
409 Examples:
409 Examples:
410
410
411 - create a zip file containing the 1.0 release::
411 - create a zip file containing the 1.0 release::
412
412
413 hg archive -r 1.0 project-1.0.zip
413 hg archive -r 1.0 project-1.0.zip
414
414
415 - create a tarball excluding .hg files::
415 - create a tarball excluding .hg files::
416
416
417 hg archive project.tar.gz -X ".hg*"
417 hg archive project.tar.gz -X ".hg*"
418
418
419 Valid types are:
419 Valid types are:
420
420
421 :``files``: a directory full of files (default)
421 :``files``: a directory full of files (default)
422 :``tar``: tar archive, uncompressed
422 :``tar``: tar archive, uncompressed
423 :``tbz2``: tar archive, compressed using bzip2
423 :``tbz2``: tar archive, compressed using bzip2
424 :``tgz``: tar archive, compressed using gzip
424 :``tgz``: tar archive, compressed using gzip
425 :``uzip``: zip archive, uncompressed
425 :``uzip``: zip archive, uncompressed
426 :``zip``: zip archive, compressed using deflate
426 :``zip``: zip archive, compressed using deflate
427
427
428 The exact name of the destination archive or directory is given
428 The exact name of the destination archive or directory is given
429 using a format string; see :hg:`help export` for details.
429 using a format string; see :hg:`help export` for details.
430
430
431 Each member added to an archive file has a directory prefix
431 Each member added to an archive file has a directory prefix
432 prepended. Use -p/--prefix to specify a format string for the
432 prepended. Use -p/--prefix to specify a format string for the
433 prefix. The default is the basename of the archive, with suffixes
433 prefix. The default is the basename of the archive, with suffixes
434 removed.
434 removed.
435
435
436 Returns 0 on success.
436 Returns 0 on success.
437 '''
437 '''
438
438
439 ctx = scmutil.revsingle(repo, opts.get('rev'))
439 ctx = scmutil.revsingle(repo, opts.get('rev'))
440 if not ctx:
440 if not ctx:
441 raise util.Abort(_('no working directory: please specify a revision'))
441 raise util.Abort(_('no working directory: please specify a revision'))
442 node = ctx.node()
442 node = ctx.node()
443 dest = cmdutil.makefilename(repo, dest, node)
443 dest = cmdutil.makefilename(repo, dest, node)
444 if os.path.realpath(dest) == repo.root:
444 if os.path.realpath(dest) == repo.root:
445 raise util.Abort(_('repository root cannot be destination'))
445 raise util.Abort(_('repository root cannot be destination'))
446
446
447 kind = opts.get('type') or archival.guesskind(dest) or 'files'
447 kind = opts.get('type') or archival.guesskind(dest) or 'files'
448 prefix = opts.get('prefix')
448 prefix = opts.get('prefix')
449
449
450 if dest == '-':
450 if dest == '-':
451 if kind == 'files':
451 if kind == 'files':
452 raise util.Abort(_('cannot archive plain files to stdout'))
452 raise util.Abort(_('cannot archive plain files to stdout'))
453 dest = cmdutil.makefileobj(repo, dest)
453 dest = cmdutil.makefileobj(repo, dest)
454 if not prefix:
454 if not prefix:
455 prefix = os.path.basename(repo.root) + '-%h'
455 prefix = os.path.basename(repo.root) + '-%h'
456
456
457 prefix = cmdutil.makefilename(repo, prefix, node)
457 prefix = cmdutil.makefilename(repo, prefix, node)
458 matchfn = scmutil.match(ctx, [], opts)
458 matchfn = scmutil.match(ctx, [], opts)
459 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
459 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
460 matchfn, prefix, subrepos=opts.get('subrepos'))
460 matchfn, prefix, subrepos=opts.get('subrepos'))
461
461
462 @command('backout',
462 @command('backout',
463 [('', 'merge', None, _('merge with old dirstate parent after backout')),
463 [('', 'merge', None, _('merge with old dirstate parent after backout')),
464 ('', 'commit', None, _('commit if no conflicts were encountered')),
464 ('', 'commit', None, _('commit if no conflicts were encountered')),
465 ('', 'parent', '',
465 ('', 'parent', '',
466 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
466 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
467 ('r', 'rev', '', _('revision to backout'), _('REV')),
467 ('r', 'rev', '', _('revision to backout'), _('REV')),
468 ('e', 'edit', False, _('invoke editor on commit messages')),
468 ('e', 'edit', False, _('invoke editor on commit messages')),
469 ] + mergetoolopts + walkopts + commitopts + commitopts2,
469 ] + mergetoolopts + walkopts + commitopts + commitopts2,
470 _('[OPTION]... [-r] REV'))
470 _('[OPTION]... [-r] REV'))
471 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
471 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
472 '''reverse effect of earlier changeset
472 '''reverse effect of earlier changeset
473
473
474 Prepare a new changeset with the effect of REV undone in the
474 Prepare a new changeset with the effect of REV undone in the
475 current working directory.
475 current working directory.
476
476
477 If REV is the parent of the working directory, then this new changeset
477 If REV is the parent of the working directory, then this new changeset
478 is committed automatically. Otherwise, hg needs to merge the
478 is committed automatically. Otherwise, hg needs to merge the
479 changes and the merged result is left uncommitted.
479 changes and the merged result is left uncommitted.
480
480
481 .. note::
481 .. note::
482
482
483 backout cannot be used to fix either an unwanted or
483 backout cannot be used to fix either an unwanted or
484 incorrect merge.
484 incorrect merge.
485
485
486 .. container:: verbose
486 .. container:: verbose
487
487
488 By default, the pending changeset will have one parent,
488 By default, the pending changeset will have one parent,
489 maintaining a linear history. With --merge, the pending
489 maintaining a linear history. With --merge, the pending
490 changeset will instead have two parents: the old parent of the
490 changeset will instead have two parents: the old parent of the
491 working directory and a new child of REV that simply undoes REV.
491 working directory and a new child of REV that simply undoes REV.
492
492
493 Before version 1.7, the behavior without --merge was equivalent
493 Before version 1.7, the behavior without --merge was equivalent
494 to specifying --merge followed by :hg:`update --clean .` to
494 to specifying --merge followed by :hg:`update --clean .` to
495 cancel the merge and leave the child of REV as a head to be
495 cancel the merge and leave the child of REV as a head to be
496 merged separately.
496 merged separately.
497
497
498 See :hg:`help dates` for a list of formats valid for -d/--date.
498 See :hg:`help dates` for a list of formats valid for -d/--date.
499
499
500 See :hg:`help revert` for a way to restore files to the state
500 See :hg:`help revert` for a way to restore files to the state
501 of another revision.
501 of another revision.
502
502
503 Returns 0 on success, 1 if nothing to backout or there are unresolved
503 Returns 0 on success, 1 if nothing to backout or there are unresolved
504 files.
504 files.
505 '''
505 '''
506 if rev and node:
506 if rev and node:
507 raise util.Abort(_("please specify just one revision"))
507 raise util.Abort(_("please specify just one revision"))
508
508
509 if not rev:
509 if not rev:
510 rev = node
510 rev = node
511
511
512 if not rev:
512 if not rev:
513 raise util.Abort(_("please specify a revision to backout"))
513 raise util.Abort(_("please specify a revision to backout"))
514
514
515 date = opts.get('date')
515 date = opts.get('date')
516 if date:
516 if date:
517 opts['date'] = util.parsedate(date)
517 opts['date'] = util.parsedate(date)
518
518
519 cmdutil.checkunfinished(repo)
519 cmdutil.checkunfinished(repo)
520 cmdutil.bailifchanged(repo)
520 cmdutil.bailifchanged(repo)
521 node = scmutil.revsingle(repo, rev).node()
521 node = scmutil.revsingle(repo, rev).node()
522
522
523 op1, op2 = repo.dirstate.parents()
523 op1, op2 = repo.dirstate.parents()
524 if not repo.changelog.isancestor(node, op1):
524 if not repo.changelog.isancestor(node, op1):
525 raise util.Abort(_('cannot backout change that is not an ancestor'))
525 raise util.Abort(_('cannot backout change that is not an ancestor'))
526
526
527 p1, p2 = repo.changelog.parents(node)
527 p1, p2 = repo.changelog.parents(node)
528 if p1 == nullid:
528 if p1 == nullid:
529 raise util.Abort(_('cannot backout a change with no parents'))
529 raise util.Abort(_('cannot backout a change with no parents'))
530 if p2 != nullid:
530 if p2 != nullid:
531 if not opts.get('parent'):
531 if not opts.get('parent'):
532 raise util.Abort(_('cannot backout a merge changeset'))
532 raise util.Abort(_('cannot backout a merge changeset'))
533 p = repo.lookup(opts['parent'])
533 p = repo.lookup(opts['parent'])
534 if p not in (p1, p2):
534 if p not in (p1, p2):
535 raise util.Abort(_('%s is not a parent of %s') %
535 raise util.Abort(_('%s is not a parent of %s') %
536 (short(p), short(node)))
536 (short(p), short(node)))
537 parent = p
537 parent = p
538 else:
538 else:
539 if opts.get('parent'):
539 if opts.get('parent'):
540 raise util.Abort(_('cannot use --parent on non-merge changeset'))
540 raise util.Abort(_('cannot use --parent on non-merge changeset'))
541 parent = p1
541 parent = p1
542
542
543 # the backout should appear on the same branch
543 # the backout should appear on the same branch
544 wlock = repo.wlock()
544 wlock = repo.wlock()
545 try:
545 try:
546 branch = repo.dirstate.branch()
546 branch = repo.dirstate.branch()
547 bheads = repo.branchheads(branch)
547 bheads = repo.branchheads(branch)
548 rctx = scmutil.revsingle(repo, hex(parent))
548 rctx = scmutil.revsingle(repo, hex(parent))
549 if not opts.get('merge') and op1 != node:
549 if not opts.get('merge') and op1 != node:
550 dsguard = cmdutil.dirstateguard(repo, 'backout')
550 try:
551 try:
551 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
552 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
552 'backout')
553 'backout')
553 repo.dirstate.beginparentchange()
554 stats = mergemod.update(repo, parent, True, True, False,
554 stats = mergemod.update(repo, parent, True, True, False,
555 node, False)
555 node, False)
556 repo.setparents(op1, op2)
556 repo.setparents(op1, op2)
557 repo.dirstate.endparentchange()
557 dsguard.close()
558 hg._showstats(repo, stats)
558 hg._showstats(repo, stats)
559 if stats[3]:
559 if stats[3]:
560 repo.ui.status(_("use 'hg resolve' to retry unresolved "
560 repo.ui.status(_("use 'hg resolve' to retry unresolved "
561 "file merges\n"))
561 "file merges\n"))
562 return 1
562 return 1
563 elif not commit:
563 elif not commit:
564 msg = _("changeset %s backed out, "
564 msg = _("changeset %s backed out, "
565 "don't forget to commit.\n")
565 "don't forget to commit.\n")
566 ui.status(msg % short(node))
566 ui.status(msg % short(node))
567 return 0
567 return 0
568 finally:
568 finally:
569 ui.setconfig('ui', 'forcemerge', '', '')
569 ui.setconfig('ui', 'forcemerge', '', '')
570 lockmod.release(dsguard)
570 else:
571 else:
571 hg.clean(repo, node, show_stats=False)
572 hg.clean(repo, node, show_stats=False)
572 repo.dirstate.setbranch(branch)
573 repo.dirstate.setbranch(branch)
573 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
574 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
574
575
575
576
576 def commitfunc(ui, repo, message, match, opts):
577 def commitfunc(ui, repo, message, match, opts):
577 editform = 'backout'
578 editform = 'backout'
578 e = cmdutil.getcommiteditor(editform=editform, **opts)
579 e = cmdutil.getcommiteditor(editform=editform, **opts)
579 if not message:
580 if not message:
580 # we don't translate commit messages
581 # we don't translate commit messages
581 message = "Backed out changeset %s" % short(node)
582 message = "Backed out changeset %s" % short(node)
582 e = cmdutil.getcommiteditor(edit=True, editform=editform)
583 e = cmdutil.getcommiteditor(edit=True, editform=editform)
583 return repo.commit(message, opts.get('user'), opts.get('date'),
584 return repo.commit(message, opts.get('user'), opts.get('date'),
584 match, editor=e)
585 match, editor=e)
585 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
586 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
586 if not newnode:
587 if not newnode:
587 ui.status(_("nothing changed\n"))
588 ui.status(_("nothing changed\n"))
588 return 1
589 return 1
589 cmdutil.commitstatus(repo, newnode, branch, bheads)
590 cmdutil.commitstatus(repo, newnode, branch, bheads)
590
591
591 def nice(node):
592 def nice(node):
592 return '%d:%s' % (repo.changelog.rev(node), short(node))
593 return '%d:%s' % (repo.changelog.rev(node), short(node))
593 ui.status(_('changeset %s backs out changeset %s\n') %
594 ui.status(_('changeset %s backs out changeset %s\n') %
594 (nice(repo.changelog.tip()), nice(node)))
595 (nice(repo.changelog.tip()), nice(node)))
595 if opts.get('merge') and op1 != node:
596 if opts.get('merge') and op1 != node:
596 hg.clean(repo, op1, show_stats=False)
597 hg.clean(repo, op1, show_stats=False)
597 ui.status(_('merging with changeset %s\n')
598 ui.status(_('merging with changeset %s\n')
598 % nice(repo.changelog.tip()))
599 % nice(repo.changelog.tip()))
599 try:
600 try:
600 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
601 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
601 'backout')
602 'backout')
602 return hg.merge(repo, hex(repo.changelog.tip()))
603 return hg.merge(repo, hex(repo.changelog.tip()))
603 finally:
604 finally:
604 ui.setconfig('ui', 'forcemerge', '', '')
605 ui.setconfig('ui', 'forcemerge', '', '')
605 finally:
606 finally:
606 wlock.release()
607 wlock.release()
607 return 0
608 return 0
608
609
609 @command('bisect',
610 @command('bisect',
610 [('r', 'reset', False, _('reset bisect state')),
611 [('r', 'reset', False, _('reset bisect state')),
611 ('g', 'good', False, _('mark changeset good')),
612 ('g', 'good', False, _('mark changeset good')),
612 ('b', 'bad', False, _('mark changeset bad')),
613 ('b', 'bad', False, _('mark changeset bad')),
613 ('s', 'skip', False, _('skip testing changeset')),
614 ('s', 'skip', False, _('skip testing changeset')),
614 ('e', 'extend', False, _('extend the bisect range')),
615 ('e', 'extend', False, _('extend the bisect range')),
615 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
616 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
616 ('U', 'noupdate', False, _('do not update to target'))],
617 ('U', 'noupdate', False, _('do not update to target'))],
617 _("[-gbsr] [-U] [-c CMD] [REV]"))
618 _("[-gbsr] [-U] [-c CMD] [REV]"))
618 def bisect(ui, repo, rev=None, extra=None, command=None,
619 def bisect(ui, repo, rev=None, extra=None, command=None,
619 reset=None, good=None, bad=None, skip=None, extend=None,
620 reset=None, good=None, bad=None, skip=None, extend=None,
620 noupdate=None):
621 noupdate=None):
621 """subdivision search of changesets
622 """subdivision search of changesets
622
623
623 This command helps to find changesets which introduce problems. To
624 This command helps to find changesets which introduce problems. To
624 use, mark the earliest changeset you know exhibits the problem as
625 use, mark the earliest changeset you know exhibits the problem as
625 bad, then mark the latest changeset which is free from the problem
626 bad, then mark the latest changeset which is free from the problem
626 as good. Bisect will update your working directory to a revision
627 as good. Bisect will update your working directory to a revision
627 for testing (unless the -U/--noupdate option is specified). Once
628 for testing (unless the -U/--noupdate option is specified). Once
628 you have performed tests, mark the working directory as good or
629 you have performed tests, mark the working directory as good or
629 bad, and bisect will either update to another candidate changeset
630 bad, and bisect will either update to another candidate changeset
630 or announce that it has found the bad revision.
631 or announce that it has found the bad revision.
631
632
632 As a shortcut, you can also use the revision argument to mark a
633 As a shortcut, you can also use the revision argument to mark a
633 revision as good or bad without checking it out first.
634 revision as good or bad without checking it out first.
634
635
635 If you supply a command, it will be used for automatic bisection.
636 If you supply a command, it will be used for automatic bisection.
636 The environment variable HG_NODE will contain the ID of the
637 The environment variable HG_NODE will contain the ID of the
637 changeset being tested. The exit status of the command will be
638 changeset being tested. The exit status of the command will be
638 used to mark revisions as good or bad: status 0 means good, 125
639 used to mark revisions as good or bad: status 0 means good, 125
639 means to skip the revision, 127 (command not found) will abort the
640 means to skip the revision, 127 (command not found) will abort the
640 bisection, and any other non-zero exit status means the revision
641 bisection, and any other non-zero exit status means the revision
641 is bad.
642 is bad.
642
643
643 .. container:: verbose
644 .. container:: verbose
644
645
645 Some examples:
646 Some examples:
646
647
647 - start a bisection with known bad revision 34, and good revision 12::
648 - start a bisection with known bad revision 34, and good revision 12::
648
649
649 hg bisect --bad 34
650 hg bisect --bad 34
650 hg bisect --good 12
651 hg bisect --good 12
651
652
652 - advance the current bisection by marking current revision as good or
653 - advance the current bisection by marking current revision as good or
653 bad::
654 bad::
654
655
655 hg bisect --good
656 hg bisect --good
656 hg bisect --bad
657 hg bisect --bad
657
658
658 - mark the current revision, or a known revision, to be skipped (e.g. if
659 - mark the current revision, or a known revision, to be skipped (e.g. if
659 that revision is not usable because of another issue)::
660 that revision is not usable because of another issue)::
660
661
661 hg bisect --skip
662 hg bisect --skip
662 hg bisect --skip 23
663 hg bisect --skip 23
663
664
664 - skip all revisions that do not touch directories ``foo`` or ``bar``::
665 - skip all revisions that do not touch directories ``foo`` or ``bar``::
665
666
666 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
667 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
667
668
668 - forget the current bisection::
669 - forget the current bisection::
669
670
670 hg bisect --reset
671 hg bisect --reset
671
672
672 - use 'make && make tests' to automatically find the first broken
673 - use 'make && make tests' to automatically find the first broken
673 revision::
674 revision::
674
675
675 hg bisect --reset
676 hg bisect --reset
676 hg bisect --bad 34
677 hg bisect --bad 34
677 hg bisect --good 12
678 hg bisect --good 12
678 hg bisect --command "make && make tests"
679 hg bisect --command "make && make tests"
679
680
680 - see all changesets whose states are already known in the current
681 - see all changesets whose states are already known in the current
681 bisection::
682 bisection::
682
683
683 hg log -r "bisect(pruned)"
684 hg log -r "bisect(pruned)"
684
685
685 - see the changeset currently being bisected (especially useful
686 - see the changeset currently being bisected (especially useful
686 if running with -U/--noupdate)::
687 if running with -U/--noupdate)::
687
688
688 hg log -r "bisect(current)"
689 hg log -r "bisect(current)"
689
690
690 - see all changesets that took part in the current bisection::
691 - see all changesets that took part in the current bisection::
691
692
692 hg log -r "bisect(range)"
693 hg log -r "bisect(range)"
693
694
694 - you can even get a nice graph::
695 - you can even get a nice graph::
695
696
696 hg log --graph -r "bisect(range)"
697 hg log --graph -r "bisect(range)"
697
698
698 See :hg:`help revsets` for more about the `bisect()` keyword.
699 See :hg:`help revsets` for more about the `bisect()` keyword.
699
700
700 Returns 0 on success.
701 Returns 0 on success.
701 """
702 """
702 def extendbisectrange(nodes, good):
703 def extendbisectrange(nodes, good):
703 # bisect is incomplete when it ends on a merge node and
704 # bisect is incomplete when it ends on a merge node and
704 # one of the parent was not checked.
705 # one of the parent was not checked.
705 parents = repo[nodes[0]].parents()
706 parents = repo[nodes[0]].parents()
706 if len(parents) > 1:
707 if len(parents) > 1:
707 if good:
708 if good:
708 side = state['bad']
709 side = state['bad']
709 else:
710 else:
710 side = state['good']
711 side = state['good']
711 num = len(set(i.node() for i in parents) & set(side))
712 num = len(set(i.node() for i in parents) & set(side))
712 if num == 1:
713 if num == 1:
713 return parents[0].ancestor(parents[1])
714 return parents[0].ancestor(parents[1])
714 return None
715 return None
715
716
716 def print_result(nodes, good):
717 def print_result(nodes, good):
717 displayer = cmdutil.show_changeset(ui, repo, {})
718 displayer = cmdutil.show_changeset(ui, repo, {})
718 if len(nodes) == 1:
719 if len(nodes) == 1:
719 # narrowed it down to a single revision
720 # narrowed it down to a single revision
720 if good:
721 if good:
721 ui.write(_("The first good revision is:\n"))
722 ui.write(_("The first good revision is:\n"))
722 else:
723 else:
723 ui.write(_("The first bad revision is:\n"))
724 ui.write(_("The first bad revision is:\n"))
724 displayer.show(repo[nodes[0]])
725 displayer.show(repo[nodes[0]])
725 extendnode = extendbisectrange(nodes, good)
726 extendnode = extendbisectrange(nodes, good)
726 if extendnode is not None:
727 if extendnode is not None:
727 ui.write(_('Not all ancestors of this changeset have been'
728 ui.write(_('Not all ancestors of this changeset have been'
728 ' checked.\nUse bisect --extend to continue the '
729 ' checked.\nUse bisect --extend to continue the '
729 'bisection from\nthe common ancestor, %s.\n')
730 'bisection from\nthe common ancestor, %s.\n')
730 % extendnode)
731 % extendnode)
731 else:
732 else:
732 # multiple possible revisions
733 # multiple possible revisions
733 if good:
734 if good:
734 ui.write(_("Due to skipped revisions, the first "
735 ui.write(_("Due to skipped revisions, the first "
735 "good revision could be any of:\n"))
736 "good revision could be any of:\n"))
736 else:
737 else:
737 ui.write(_("Due to skipped revisions, the first "
738 ui.write(_("Due to skipped revisions, the first "
738 "bad revision could be any of:\n"))
739 "bad revision could be any of:\n"))
739 for n in nodes:
740 for n in nodes:
740 displayer.show(repo[n])
741 displayer.show(repo[n])
741 displayer.close()
742 displayer.close()
742
743
743 def check_state(state, interactive=True):
744 def check_state(state, interactive=True):
744 if not state['good'] or not state['bad']:
745 if not state['good'] or not state['bad']:
745 if (good or bad or skip or reset) and interactive:
746 if (good or bad or skip or reset) and interactive:
746 return
747 return
747 if not state['good']:
748 if not state['good']:
748 raise util.Abort(_('cannot bisect (no known good revisions)'))
749 raise util.Abort(_('cannot bisect (no known good revisions)'))
749 else:
750 else:
750 raise util.Abort(_('cannot bisect (no known bad revisions)'))
751 raise util.Abort(_('cannot bisect (no known bad revisions)'))
751 return True
752 return True
752
753
753 # backward compatibility
754 # backward compatibility
754 if rev in "good bad reset init".split():
755 if rev in "good bad reset init".split():
755 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
756 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
756 cmd, rev, extra = rev, extra, None
757 cmd, rev, extra = rev, extra, None
757 if cmd == "good":
758 if cmd == "good":
758 good = True
759 good = True
759 elif cmd == "bad":
760 elif cmd == "bad":
760 bad = True
761 bad = True
761 else:
762 else:
762 reset = True
763 reset = True
763 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
764 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
764 raise util.Abort(_('incompatible arguments'))
765 raise util.Abort(_('incompatible arguments'))
765
766
766 cmdutil.checkunfinished(repo)
767 cmdutil.checkunfinished(repo)
767
768
768 if reset:
769 if reset:
769 p = repo.join("bisect.state")
770 p = repo.join("bisect.state")
770 if os.path.exists(p):
771 if os.path.exists(p):
771 os.unlink(p)
772 os.unlink(p)
772 return
773 return
773
774
774 state = hbisect.load_state(repo)
775 state = hbisect.load_state(repo)
775
776
776 if command:
777 if command:
777 changesets = 1
778 changesets = 1
778 if noupdate:
779 if noupdate:
779 try:
780 try:
780 node = state['current'][0]
781 node = state['current'][0]
781 except LookupError:
782 except LookupError:
782 raise util.Abort(_('current bisect revision is unknown - '
783 raise util.Abort(_('current bisect revision is unknown - '
783 'start a new bisect to fix'))
784 'start a new bisect to fix'))
784 else:
785 else:
785 node, p2 = repo.dirstate.parents()
786 node, p2 = repo.dirstate.parents()
786 if p2 != nullid:
787 if p2 != nullid:
787 raise util.Abort(_('current bisect revision is a merge'))
788 raise util.Abort(_('current bisect revision is a merge'))
788 try:
789 try:
789 while changesets:
790 while changesets:
790 # update state
791 # update state
791 state['current'] = [node]
792 state['current'] = [node]
792 hbisect.save_state(repo, state)
793 hbisect.save_state(repo, state)
793 status = ui.system(command, environ={'HG_NODE': hex(node)})
794 status = ui.system(command, environ={'HG_NODE': hex(node)})
794 if status == 125:
795 if status == 125:
795 transition = "skip"
796 transition = "skip"
796 elif status == 0:
797 elif status == 0:
797 transition = "good"
798 transition = "good"
798 # status < 0 means process was killed
799 # status < 0 means process was killed
799 elif status == 127:
800 elif status == 127:
800 raise util.Abort(_("failed to execute %s") % command)
801 raise util.Abort(_("failed to execute %s") % command)
801 elif status < 0:
802 elif status < 0:
802 raise util.Abort(_("%s killed") % command)
803 raise util.Abort(_("%s killed") % command)
803 else:
804 else:
804 transition = "bad"
805 transition = "bad"
805 ctx = scmutil.revsingle(repo, rev, node)
806 ctx = scmutil.revsingle(repo, rev, node)
806 rev = None # clear for future iterations
807 rev = None # clear for future iterations
807 state[transition].append(ctx.node())
808 state[transition].append(ctx.node())
808 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
809 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
809 check_state(state, interactive=False)
810 check_state(state, interactive=False)
810 # bisect
811 # bisect
811 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
812 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
812 # update to next check
813 # update to next check
813 node = nodes[0]
814 node = nodes[0]
814 if not noupdate:
815 if not noupdate:
815 cmdutil.bailifchanged(repo)
816 cmdutil.bailifchanged(repo)
816 hg.clean(repo, node, show_stats=False)
817 hg.clean(repo, node, show_stats=False)
817 finally:
818 finally:
818 state['current'] = [node]
819 state['current'] = [node]
819 hbisect.save_state(repo, state)
820 hbisect.save_state(repo, state)
820 print_result(nodes, bgood)
821 print_result(nodes, bgood)
821 return
822 return
822
823
823 # update state
824 # update state
824
825
825 if rev:
826 if rev:
826 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
827 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
827 else:
828 else:
828 nodes = [repo.lookup('.')]
829 nodes = [repo.lookup('.')]
829
830
830 if good or bad or skip:
831 if good or bad or skip:
831 if good:
832 if good:
832 state['good'] += nodes
833 state['good'] += nodes
833 elif bad:
834 elif bad:
834 state['bad'] += nodes
835 state['bad'] += nodes
835 elif skip:
836 elif skip:
836 state['skip'] += nodes
837 state['skip'] += nodes
837 hbisect.save_state(repo, state)
838 hbisect.save_state(repo, state)
838
839
839 if not check_state(state):
840 if not check_state(state):
840 return
841 return
841
842
842 # actually bisect
843 # actually bisect
843 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
844 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
844 if extend:
845 if extend:
845 if not changesets:
846 if not changesets:
846 extendnode = extendbisectrange(nodes, good)
847 extendnode = extendbisectrange(nodes, good)
847 if extendnode is not None:
848 if extendnode is not None:
848 ui.write(_("Extending search to changeset %d:%s\n")
849 ui.write(_("Extending search to changeset %d:%s\n")
849 % (extendnode.rev(), extendnode))
850 % (extendnode.rev(), extendnode))
850 state['current'] = [extendnode.node()]
851 state['current'] = [extendnode.node()]
851 hbisect.save_state(repo, state)
852 hbisect.save_state(repo, state)
852 if noupdate:
853 if noupdate:
853 return
854 return
854 cmdutil.bailifchanged(repo)
855 cmdutil.bailifchanged(repo)
855 return hg.clean(repo, extendnode.node())
856 return hg.clean(repo, extendnode.node())
856 raise util.Abort(_("nothing to extend"))
857 raise util.Abort(_("nothing to extend"))
857
858
858 if changesets == 0:
859 if changesets == 0:
859 print_result(nodes, good)
860 print_result(nodes, good)
860 else:
861 else:
861 assert len(nodes) == 1 # only a single node can be tested next
862 assert len(nodes) == 1 # only a single node can be tested next
862 node = nodes[0]
863 node = nodes[0]
863 # compute the approximate number of remaining tests
864 # compute the approximate number of remaining tests
864 tests, size = 0, 2
865 tests, size = 0, 2
865 while size <= changesets:
866 while size <= changesets:
866 tests, size = tests + 1, size * 2
867 tests, size = tests + 1, size * 2
867 rev = repo.changelog.rev(node)
868 rev = repo.changelog.rev(node)
868 ui.write(_("Testing changeset %d:%s "
869 ui.write(_("Testing changeset %d:%s "
869 "(%d changesets remaining, ~%d tests)\n")
870 "(%d changesets remaining, ~%d tests)\n")
870 % (rev, short(node), changesets, tests))
871 % (rev, short(node), changesets, tests))
871 state['current'] = [node]
872 state['current'] = [node]
872 hbisect.save_state(repo, state)
873 hbisect.save_state(repo, state)
873 if not noupdate:
874 if not noupdate:
874 cmdutil.bailifchanged(repo)
875 cmdutil.bailifchanged(repo)
875 return hg.clean(repo, node)
876 return hg.clean(repo, node)
876
877
877 @command('bookmarks|bookmark',
878 @command('bookmarks|bookmark',
878 [('f', 'force', False, _('force')),
879 [('f', 'force', False, _('force')),
879 ('r', 'rev', '', _('revision'), _('REV')),
880 ('r', 'rev', '', _('revision'), _('REV')),
880 ('d', 'delete', False, _('delete a given bookmark')),
881 ('d', 'delete', False, _('delete a given bookmark')),
881 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
882 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
882 ('i', 'inactive', False, _('mark a bookmark inactive')),
883 ('i', 'inactive', False, _('mark a bookmark inactive')),
883 ] + formatteropts,
884 ] + formatteropts,
884 _('hg bookmarks [OPTIONS]... [NAME]...'))
885 _('hg bookmarks [OPTIONS]... [NAME]...'))
885 def bookmark(ui, repo, *names, **opts):
886 def bookmark(ui, repo, *names, **opts):
886 '''create a new bookmark or list existing bookmarks
887 '''create a new bookmark or list existing bookmarks
887
888
888 Bookmarks are labels on changesets to help track lines of development.
889 Bookmarks are labels on changesets to help track lines of development.
889 Bookmarks are unversioned and can be moved, renamed and deleted.
890 Bookmarks are unversioned and can be moved, renamed and deleted.
890 Deleting or moving a bookmark has no effect on the associated changesets.
891 Deleting or moving a bookmark has no effect on the associated changesets.
891
892
892 Creating or updating to a bookmark causes it to be marked as 'active'.
893 Creating or updating to a bookmark causes it to be marked as 'active'.
893 The active bookmark is indicated with a '*'.
894 The active bookmark is indicated with a '*'.
894 When a commit is made, the active bookmark will advance to the new commit.
895 When a commit is made, the active bookmark will advance to the new commit.
895 A plain :hg:`update` will also advance an active bookmark, if possible.
896 A plain :hg:`update` will also advance an active bookmark, if possible.
896 Updating away from a bookmark will cause it to be deactivated.
897 Updating away from a bookmark will cause it to be deactivated.
897
898
898 Bookmarks can be pushed and pulled between repositories (see
899 Bookmarks can be pushed and pulled between repositories (see
899 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
900 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
900 diverged, a new 'divergent bookmark' of the form 'name@path' will
901 diverged, a new 'divergent bookmark' of the form 'name@path' will
901 be created. Using :hg:`merge` will resolve the divergence.
902 be created. Using :hg:`merge` will resolve the divergence.
902
903
903 A bookmark named '@' has the special property that :hg:`clone` will
904 A bookmark named '@' has the special property that :hg:`clone` will
904 check it out by default if it exists.
905 check it out by default if it exists.
905
906
906 .. container:: verbose
907 .. container:: verbose
907
908
908 Examples:
909 Examples:
909
910
910 - create an active bookmark for a new line of development::
911 - create an active bookmark for a new line of development::
911
912
912 hg book new-feature
913 hg book new-feature
913
914
914 - create an inactive bookmark as a place marker::
915 - create an inactive bookmark as a place marker::
915
916
916 hg book -i reviewed
917 hg book -i reviewed
917
918
918 - create an inactive bookmark on another changeset::
919 - create an inactive bookmark on another changeset::
919
920
920 hg book -r .^ tested
921 hg book -r .^ tested
921
922
922 - rename bookmark turkey to dinner::
923 - rename bookmark turkey to dinner::
923
924
924 hg book -m turkey dinner
925 hg book -m turkey dinner
925
926
926 - move the '@' bookmark from another branch::
927 - move the '@' bookmark from another branch::
927
928
928 hg book -f @
929 hg book -f @
929 '''
930 '''
930 force = opts.get('force')
931 force = opts.get('force')
931 rev = opts.get('rev')
932 rev = opts.get('rev')
932 delete = opts.get('delete')
933 delete = opts.get('delete')
933 rename = opts.get('rename')
934 rename = opts.get('rename')
934 inactive = opts.get('inactive')
935 inactive = opts.get('inactive')
935
936
936 def checkformat(mark):
937 def checkformat(mark):
937 mark = mark.strip()
938 mark = mark.strip()
938 if not mark:
939 if not mark:
939 raise util.Abort(_("bookmark names cannot consist entirely of "
940 raise util.Abort(_("bookmark names cannot consist entirely of "
940 "whitespace"))
941 "whitespace"))
941 scmutil.checknewlabel(repo, mark, 'bookmark')
942 scmutil.checknewlabel(repo, mark, 'bookmark')
942 return mark
943 return mark
943
944
944 def checkconflict(repo, mark, cur, force=False, target=None):
945 def checkconflict(repo, mark, cur, force=False, target=None):
945 if mark in marks and not force:
946 if mark in marks and not force:
946 if target:
947 if target:
947 if marks[mark] == target and target == cur:
948 if marks[mark] == target and target == cur:
948 # re-activating a bookmark
949 # re-activating a bookmark
949 return
950 return
950 anc = repo.changelog.ancestors([repo[target].rev()])
951 anc = repo.changelog.ancestors([repo[target].rev()])
951 bmctx = repo[marks[mark]]
952 bmctx = repo[marks[mark]]
952 divs = [repo[b].node() for b in marks
953 divs = [repo[b].node() for b in marks
953 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
954 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
954
955
955 # allow resolving a single divergent bookmark even if moving
956 # allow resolving a single divergent bookmark even if moving
956 # the bookmark across branches when a revision is specified
957 # the bookmark across branches when a revision is specified
957 # that contains a divergent bookmark
958 # that contains a divergent bookmark
958 if bmctx.rev() not in anc and target in divs:
959 if bmctx.rev() not in anc and target in divs:
959 bookmarks.deletedivergent(repo, [target], mark)
960 bookmarks.deletedivergent(repo, [target], mark)
960 return
961 return
961
962
962 deletefrom = [b for b in divs
963 deletefrom = [b for b in divs
963 if repo[b].rev() in anc or b == target]
964 if repo[b].rev() in anc or b == target]
964 bookmarks.deletedivergent(repo, deletefrom, mark)
965 bookmarks.deletedivergent(repo, deletefrom, mark)
965 if bookmarks.validdest(repo, bmctx, repo[target]):
966 if bookmarks.validdest(repo, bmctx, repo[target]):
966 ui.status(_("moving bookmark '%s' forward from %s\n") %
967 ui.status(_("moving bookmark '%s' forward from %s\n") %
967 (mark, short(bmctx.node())))
968 (mark, short(bmctx.node())))
968 return
969 return
969 raise util.Abort(_("bookmark '%s' already exists "
970 raise util.Abort(_("bookmark '%s' already exists "
970 "(use -f to force)") % mark)
971 "(use -f to force)") % mark)
971 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
972 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
972 and not force):
973 and not force):
973 raise util.Abort(
974 raise util.Abort(
974 _("a bookmark cannot have the name of an existing branch"))
975 _("a bookmark cannot have the name of an existing branch"))
975
976
976 if delete and rename:
977 if delete and rename:
977 raise util.Abort(_("--delete and --rename are incompatible"))
978 raise util.Abort(_("--delete and --rename are incompatible"))
978 if delete and rev:
979 if delete and rev:
979 raise util.Abort(_("--rev is incompatible with --delete"))
980 raise util.Abort(_("--rev is incompatible with --delete"))
980 if rename and rev:
981 if rename and rev:
981 raise util.Abort(_("--rev is incompatible with --rename"))
982 raise util.Abort(_("--rev is incompatible with --rename"))
982 if not names and (delete or rev):
983 if not names and (delete or rev):
983 raise util.Abort(_("bookmark name required"))
984 raise util.Abort(_("bookmark name required"))
984
985
985 if delete or rename or names or inactive:
986 if delete or rename or names or inactive:
986 wlock = lock = tr = None
987 wlock = lock = tr = None
987 try:
988 try:
988 wlock = repo.wlock()
989 wlock = repo.wlock()
989 lock = repo.lock()
990 lock = repo.lock()
990 cur = repo.changectx('.').node()
991 cur = repo.changectx('.').node()
991 marks = repo._bookmarks
992 marks = repo._bookmarks
992 if delete:
993 if delete:
993 tr = repo.transaction('bookmark')
994 tr = repo.transaction('bookmark')
994 for mark in names:
995 for mark in names:
995 if mark not in marks:
996 if mark not in marks:
996 raise util.Abort(_("bookmark '%s' does not exist") %
997 raise util.Abort(_("bookmark '%s' does not exist") %
997 mark)
998 mark)
998 if mark == repo._activebookmark:
999 if mark == repo._activebookmark:
999 bookmarks.deactivate(repo)
1000 bookmarks.deactivate(repo)
1000 del marks[mark]
1001 del marks[mark]
1001
1002
1002 elif rename:
1003 elif rename:
1003 tr = repo.transaction('bookmark')
1004 tr = repo.transaction('bookmark')
1004 if not names:
1005 if not names:
1005 raise util.Abort(_("new bookmark name required"))
1006 raise util.Abort(_("new bookmark name required"))
1006 elif len(names) > 1:
1007 elif len(names) > 1:
1007 raise util.Abort(_("only one new bookmark name allowed"))
1008 raise util.Abort(_("only one new bookmark name allowed"))
1008 mark = checkformat(names[0])
1009 mark = checkformat(names[0])
1009 if rename not in marks:
1010 if rename not in marks:
1010 raise util.Abort(_("bookmark '%s' does not exist") % rename)
1011 raise util.Abort(_("bookmark '%s' does not exist") % rename)
1011 checkconflict(repo, mark, cur, force)
1012 checkconflict(repo, mark, cur, force)
1012 marks[mark] = marks[rename]
1013 marks[mark] = marks[rename]
1013 if repo._activebookmark == rename and not inactive:
1014 if repo._activebookmark == rename and not inactive:
1014 bookmarks.activate(repo, mark)
1015 bookmarks.activate(repo, mark)
1015 del marks[rename]
1016 del marks[rename]
1016 elif names:
1017 elif names:
1017 tr = repo.transaction('bookmark')
1018 tr = repo.transaction('bookmark')
1018 newact = None
1019 newact = None
1019 for mark in names:
1020 for mark in names:
1020 mark = checkformat(mark)
1021 mark = checkformat(mark)
1021 if newact is None:
1022 if newact is None:
1022 newact = mark
1023 newact = mark
1023 if inactive and mark == repo._activebookmark:
1024 if inactive and mark == repo._activebookmark:
1024 bookmarks.deactivate(repo)
1025 bookmarks.deactivate(repo)
1025 return
1026 return
1026 tgt = cur
1027 tgt = cur
1027 if rev:
1028 if rev:
1028 tgt = scmutil.revsingle(repo, rev).node()
1029 tgt = scmutil.revsingle(repo, rev).node()
1029 checkconflict(repo, mark, cur, force, tgt)
1030 checkconflict(repo, mark, cur, force, tgt)
1030 marks[mark] = tgt
1031 marks[mark] = tgt
1031 if not inactive and cur == marks[newact] and not rev:
1032 if not inactive and cur == marks[newact] and not rev:
1032 bookmarks.activate(repo, newact)
1033 bookmarks.activate(repo, newact)
1033 elif cur != tgt and newact == repo._activebookmark:
1034 elif cur != tgt and newact == repo._activebookmark:
1034 bookmarks.deactivate(repo)
1035 bookmarks.deactivate(repo)
1035 elif inactive:
1036 elif inactive:
1036 if len(marks) == 0:
1037 if len(marks) == 0:
1037 ui.status(_("no bookmarks set\n"))
1038 ui.status(_("no bookmarks set\n"))
1038 elif not repo._activebookmark:
1039 elif not repo._activebookmark:
1039 ui.status(_("no active bookmark\n"))
1040 ui.status(_("no active bookmark\n"))
1040 else:
1041 else:
1041 bookmarks.deactivate(repo)
1042 bookmarks.deactivate(repo)
1042 if tr is not None:
1043 if tr is not None:
1043 marks.recordchange(tr)
1044 marks.recordchange(tr)
1044 tr.close()
1045 tr.close()
1045 finally:
1046 finally:
1046 lockmod.release(tr, lock, wlock)
1047 lockmod.release(tr, lock, wlock)
1047 else: # show bookmarks
1048 else: # show bookmarks
1048 fm = ui.formatter('bookmarks', opts)
1049 fm = ui.formatter('bookmarks', opts)
1049 hexfn = fm.hexfunc
1050 hexfn = fm.hexfunc
1050 marks = repo._bookmarks
1051 marks = repo._bookmarks
1051 if len(marks) == 0 and not fm:
1052 if len(marks) == 0 and not fm:
1052 ui.status(_("no bookmarks set\n"))
1053 ui.status(_("no bookmarks set\n"))
1053 for bmark, n in sorted(marks.iteritems()):
1054 for bmark, n in sorted(marks.iteritems()):
1054 active = repo._activebookmark
1055 active = repo._activebookmark
1055 if bmark == active:
1056 if bmark == active:
1056 prefix, label = '*', activebookmarklabel
1057 prefix, label = '*', activebookmarklabel
1057 else:
1058 else:
1058 prefix, label = ' ', ''
1059 prefix, label = ' ', ''
1059
1060
1060 fm.startitem()
1061 fm.startitem()
1061 if not ui.quiet:
1062 if not ui.quiet:
1062 fm.plain(' %s ' % prefix, label=label)
1063 fm.plain(' %s ' % prefix, label=label)
1063 fm.write('bookmark', '%s', bmark, label=label)
1064 fm.write('bookmark', '%s', bmark, label=label)
1064 pad = " " * (25 - encoding.colwidth(bmark))
1065 pad = " " * (25 - encoding.colwidth(bmark))
1065 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1066 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1066 repo.changelog.rev(n), hexfn(n), label=label)
1067 repo.changelog.rev(n), hexfn(n), label=label)
1067 fm.data(active=(bmark == active))
1068 fm.data(active=(bmark == active))
1068 fm.plain('\n')
1069 fm.plain('\n')
1069 fm.end()
1070 fm.end()
1070
1071
1071 @command('branch',
1072 @command('branch',
1072 [('f', 'force', None,
1073 [('f', 'force', None,
1073 _('set branch name even if it shadows an existing branch')),
1074 _('set branch name even if it shadows an existing branch')),
1074 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1075 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1075 _('[-fC] [NAME]'))
1076 _('[-fC] [NAME]'))
1076 def branch(ui, repo, label=None, **opts):
1077 def branch(ui, repo, label=None, **opts):
1077 """set or show the current branch name
1078 """set or show the current branch name
1078
1079
1079 .. note::
1080 .. note::
1080
1081
1081 Branch names are permanent and global. Use :hg:`bookmark` to create a
1082 Branch names are permanent and global. Use :hg:`bookmark` to create a
1082 light-weight bookmark instead. See :hg:`help glossary` for more
1083 light-weight bookmark instead. See :hg:`help glossary` for more
1083 information about named branches and bookmarks.
1084 information about named branches and bookmarks.
1084
1085
1085 With no argument, show the current branch name. With one argument,
1086 With no argument, show the current branch name. With one argument,
1086 set the working directory branch name (the branch will not exist
1087 set the working directory branch name (the branch will not exist
1087 in the repository until the next commit). Standard practice
1088 in the repository until the next commit). Standard practice
1088 recommends that primary development take place on the 'default'
1089 recommends that primary development take place on the 'default'
1089 branch.
1090 branch.
1090
1091
1091 Unless -f/--force is specified, branch will not let you set a
1092 Unless -f/--force is specified, branch will not let you set a
1092 branch name that already exists.
1093 branch name that already exists.
1093
1094
1094 Use -C/--clean to reset the working directory branch to that of
1095 Use -C/--clean to reset the working directory branch to that of
1095 the parent of the working directory, negating a previous branch
1096 the parent of the working directory, negating a previous branch
1096 change.
1097 change.
1097
1098
1098 Use the command :hg:`update` to switch to an existing branch. Use
1099 Use the command :hg:`update` to switch to an existing branch. Use
1099 :hg:`commit --close-branch` to mark this branch head as closed.
1100 :hg:`commit --close-branch` to mark this branch head as closed.
1100 When all heads of the branch are closed, the branch will be
1101 When all heads of the branch are closed, the branch will be
1101 considered closed.
1102 considered closed.
1102
1103
1103 Returns 0 on success.
1104 Returns 0 on success.
1104 """
1105 """
1105 if label:
1106 if label:
1106 label = label.strip()
1107 label = label.strip()
1107
1108
1108 if not opts.get('clean') and not label:
1109 if not opts.get('clean') and not label:
1109 ui.write("%s\n" % repo.dirstate.branch())
1110 ui.write("%s\n" % repo.dirstate.branch())
1110 return
1111 return
1111
1112
1112 wlock = repo.wlock()
1113 wlock = repo.wlock()
1113 try:
1114 try:
1114 if opts.get('clean'):
1115 if opts.get('clean'):
1115 label = repo[None].p1().branch()
1116 label = repo[None].p1().branch()
1116 repo.dirstate.setbranch(label)
1117 repo.dirstate.setbranch(label)
1117 ui.status(_('reset working directory to branch %s\n') % label)
1118 ui.status(_('reset working directory to branch %s\n') % label)
1118 elif label:
1119 elif label:
1119 if not opts.get('force') and label in repo.branchmap():
1120 if not opts.get('force') and label in repo.branchmap():
1120 if label not in [p.branch() for p in repo.parents()]:
1121 if label not in [p.branch() for p in repo.parents()]:
1121 raise util.Abort(_('a branch of the same name already'
1122 raise util.Abort(_('a branch of the same name already'
1122 ' exists'),
1123 ' exists'),
1123 # i18n: "it" refers to an existing branch
1124 # i18n: "it" refers to an existing branch
1124 hint=_("use 'hg update' to switch to it"))
1125 hint=_("use 'hg update' to switch to it"))
1125 scmutil.checknewlabel(repo, label, 'branch')
1126 scmutil.checknewlabel(repo, label, 'branch')
1126 repo.dirstate.setbranch(label)
1127 repo.dirstate.setbranch(label)
1127 ui.status(_('marked working directory as branch %s\n') % label)
1128 ui.status(_('marked working directory as branch %s\n') % label)
1128
1129
1129 # find any open named branches aside from default
1130 # find any open named branches aside from default
1130 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1131 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1131 if n != "default" and not c]
1132 if n != "default" and not c]
1132 if not others:
1133 if not others:
1133 ui.status(_('(branches are permanent and global, '
1134 ui.status(_('(branches are permanent and global, '
1134 'did you want a bookmark?)\n'))
1135 'did you want a bookmark?)\n'))
1135 finally:
1136 finally:
1136 wlock.release()
1137 wlock.release()
1137
1138
1138 @command('branches',
1139 @command('branches',
1139 [('a', 'active', False,
1140 [('a', 'active', False,
1140 _('show only branches that have unmerged heads (DEPRECATED)')),
1141 _('show only branches that have unmerged heads (DEPRECATED)')),
1141 ('c', 'closed', False, _('show normal and closed branches')),
1142 ('c', 'closed', False, _('show normal and closed branches')),
1142 ] + formatteropts,
1143 ] + formatteropts,
1143 _('[-ac]'))
1144 _('[-ac]'))
1144 def branches(ui, repo, active=False, closed=False, **opts):
1145 def branches(ui, repo, active=False, closed=False, **opts):
1145 """list repository named branches
1146 """list repository named branches
1146
1147
1147 List the repository's named branches, indicating which ones are
1148 List the repository's named branches, indicating which ones are
1148 inactive. If -c/--closed is specified, also list branches which have
1149 inactive. If -c/--closed is specified, also list branches which have
1149 been marked closed (see :hg:`commit --close-branch`).
1150 been marked closed (see :hg:`commit --close-branch`).
1150
1151
1151 Use the command :hg:`update` to switch to an existing branch.
1152 Use the command :hg:`update` to switch to an existing branch.
1152
1153
1153 Returns 0.
1154 Returns 0.
1154 """
1155 """
1155
1156
1156 fm = ui.formatter('branches', opts)
1157 fm = ui.formatter('branches', opts)
1157 hexfunc = fm.hexfunc
1158 hexfunc = fm.hexfunc
1158
1159
1159 allheads = set(repo.heads())
1160 allheads = set(repo.heads())
1160 branches = []
1161 branches = []
1161 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1162 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1162 isactive = not isclosed and bool(set(heads) & allheads)
1163 isactive = not isclosed and bool(set(heads) & allheads)
1163 branches.append((tag, repo[tip], isactive, not isclosed))
1164 branches.append((tag, repo[tip], isactive, not isclosed))
1164 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1165 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1165 reverse=True)
1166 reverse=True)
1166
1167
1167 for tag, ctx, isactive, isopen in branches:
1168 for tag, ctx, isactive, isopen in branches:
1168 if active and not isactive:
1169 if active and not isactive:
1169 continue
1170 continue
1170 if isactive:
1171 if isactive:
1171 label = 'branches.active'
1172 label = 'branches.active'
1172 notice = ''
1173 notice = ''
1173 elif not isopen:
1174 elif not isopen:
1174 if not closed:
1175 if not closed:
1175 continue
1176 continue
1176 label = 'branches.closed'
1177 label = 'branches.closed'
1177 notice = _(' (closed)')
1178 notice = _(' (closed)')
1178 else:
1179 else:
1179 label = 'branches.inactive'
1180 label = 'branches.inactive'
1180 notice = _(' (inactive)')
1181 notice = _(' (inactive)')
1181 current = (tag == repo.dirstate.branch())
1182 current = (tag == repo.dirstate.branch())
1182 if current:
1183 if current:
1183 label = 'branches.current'
1184 label = 'branches.current'
1184
1185
1185 fm.startitem()
1186 fm.startitem()
1186 fm.write('branch', '%s', tag, label=label)
1187 fm.write('branch', '%s', tag, label=label)
1187 rev = ctx.rev()
1188 rev = ctx.rev()
1188 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1189 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1189 fmt = ' ' * padsize + ' %d:%s'
1190 fmt = ' ' * padsize + ' %d:%s'
1190 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1191 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1191 label='log.changeset changeset.%s' % ctx.phasestr())
1192 label='log.changeset changeset.%s' % ctx.phasestr())
1192 fm.data(active=isactive, closed=not isopen, current=current)
1193 fm.data(active=isactive, closed=not isopen, current=current)
1193 if not ui.quiet:
1194 if not ui.quiet:
1194 fm.plain(notice)
1195 fm.plain(notice)
1195 fm.plain('\n')
1196 fm.plain('\n')
1196 fm.end()
1197 fm.end()
1197
1198
1198 @command('bundle',
1199 @command('bundle',
1199 [('f', 'force', None, _('run even when the destination is unrelated')),
1200 [('f', 'force', None, _('run even when the destination is unrelated')),
1200 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1201 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1201 _('REV')),
1202 _('REV')),
1202 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1203 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1203 _('BRANCH')),
1204 _('BRANCH')),
1204 ('', 'base', [],
1205 ('', 'base', [],
1205 _('a base changeset assumed to be available at the destination'),
1206 _('a base changeset assumed to be available at the destination'),
1206 _('REV')),
1207 _('REV')),
1207 ('a', 'all', None, _('bundle all changesets in the repository')),
1208 ('a', 'all', None, _('bundle all changesets in the repository')),
1208 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1209 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1209 ] + remoteopts,
1210 ] + remoteopts,
1210 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1211 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1211 def bundle(ui, repo, fname, dest=None, **opts):
1212 def bundle(ui, repo, fname, dest=None, **opts):
1212 """create a changegroup file
1213 """create a changegroup file
1213
1214
1214 Generate a compressed changegroup file collecting changesets not
1215 Generate a compressed changegroup file collecting changesets not
1215 known to be in another repository.
1216 known to be in another repository.
1216
1217
1217 If you omit the destination repository, then hg assumes the
1218 If you omit the destination repository, then hg assumes the
1218 destination will have all the nodes you specify with --base
1219 destination will have all the nodes you specify with --base
1219 parameters. To create a bundle containing all changesets, use
1220 parameters. To create a bundle containing all changesets, use
1220 -a/--all (or --base null).
1221 -a/--all (or --base null).
1221
1222
1222 You can change bundle format with the -t/--type option. You can
1223 You can change bundle format with the -t/--type option. You can
1223 specify a compression, a bundle version or both using a dash
1224 specify a compression, a bundle version or both using a dash
1224 (comp-version). The available compression methods are: none, bzip2,
1225 (comp-version). The available compression methods are: none, bzip2,
1225 and gzip (by default, bundles are compressed using bzip2). The
1226 and gzip (by default, bundles are compressed using bzip2). The
1226 available format are: v1, v2 (default to most suitable).
1227 available format are: v1, v2 (default to most suitable).
1227
1228
1228 The bundle file can then be transferred using conventional means
1229 The bundle file can then be transferred using conventional means
1229 and applied to another repository with the unbundle or pull
1230 and applied to another repository with the unbundle or pull
1230 command. This is useful when direct push and pull are not
1231 command. This is useful when direct push and pull are not
1231 available or when exporting an entire repository is undesirable.
1232 available or when exporting an entire repository is undesirable.
1232
1233
1233 Applying bundles preserves all changeset contents including
1234 Applying bundles preserves all changeset contents including
1234 permissions, copy/rename information, and revision history.
1235 permissions, copy/rename information, and revision history.
1235
1236
1236 Returns 0 on success, 1 if no changes found.
1237 Returns 0 on success, 1 if no changes found.
1237 """
1238 """
1238 revs = None
1239 revs = None
1239 if 'rev' in opts:
1240 if 'rev' in opts:
1240 revs = scmutil.revrange(repo, opts['rev'])
1241 revs = scmutil.revrange(repo, opts['rev'])
1241
1242
1242 bundletype = opts.get('type', 'bzip2').lower()
1243 bundletype = opts.get('type', 'bzip2').lower()
1243 cgversion, bcompression = cmdutil.parsebundletype(repo, bundletype)
1244 cgversion, bcompression = cmdutil.parsebundletype(repo, bundletype)
1244
1245
1245 if opts.get('all'):
1246 if opts.get('all'):
1246 base = ['null']
1247 base = ['null']
1247 else:
1248 else:
1248 base = scmutil.revrange(repo, opts.get('base'))
1249 base = scmutil.revrange(repo, opts.get('base'))
1249 # TODO: get desired bundlecaps from command line.
1250 # TODO: get desired bundlecaps from command line.
1250 bundlecaps = None
1251 bundlecaps = None
1251 if base:
1252 if base:
1252 if dest:
1253 if dest:
1253 raise util.Abort(_("--base is incompatible with specifying "
1254 raise util.Abort(_("--base is incompatible with specifying "
1254 "a destination"))
1255 "a destination"))
1255 common = [repo.lookup(rev) for rev in base]
1256 common = [repo.lookup(rev) for rev in base]
1256 heads = revs and map(repo.lookup, revs) or revs
1257 heads = revs and map(repo.lookup, revs) or revs
1257 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1258 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1258 common=common, bundlecaps=bundlecaps,
1259 common=common, bundlecaps=bundlecaps,
1259 version=cgversion)
1260 version=cgversion)
1260 outgoing = None
1261 outgoing = None
1261 else:
1262 else:
1262 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1263 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1263 dest, branches = hg.parseurl(dest, opts.get('branch'))
1264 dest, branches = hg.parseurl(dest, opts.get('branch'))
1264 other = hg.peer(repo, opts, dest)
1265 other = hg.peer(repo, opts, dest)
1265 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1266 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1266 heads = revs and map(repo.lookup, revs) or revs
1267 heads = revs and map(repo.lookup, revs) or revs
1267 outgoing = discovery.findcommonoutgoing(repo, other,
1268 outgoing = discovery.findcommonoutgoing(repo, other,
1268 onlyheads=heads,
1269 onlyheads=heads,
1269 force=opts.get('force'),
1270 force=opts.get('force'),
1270 portable=True)
1271 portable=True)
1271 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1272 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1272 bundlecaps, version=cgversion)
1273 bundlecaps, version=cgversion)
1273 if not cg:
1274 if not cg:
1274 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1275 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1275 return 1
1276 return 1
1276
1277
1277 if cgversion == '01': #bundle1
1278 if cgversion == '01': #bundle1
1278 if bcompression is None:
1279 if bcompression is None:
1279 bcompression = 'UN'
1280 bcompression = 'UN'
1280 bversion = 'HG10' + bcompression
1281 bversion = 'HG10' + bcompression
1281 bcompression = None
1282 bcompression = None
1282 else:
1283 else:
1283 assert cgversion == '02'
1284 assert cgversion == '02'
1284 bversion = 'HG20'
1285 bversion = 'HG20'
1285
1286
1286
1287
1287 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1288 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1288
1289
1289 @command('cat',
1290 @command('cat',
1290 [('o', 'output', '',
1291 [('o', 'output', '',
1291 _('print output to file with formatted name'), _('FORMAT')),
1292 _('print output to file with formatted name'), _('FORMAT')),
1292 ('r', 'rev', '', _('print the given revision'), _('REV')),
1293 ('r', 'rev', '', _('print the given revision'), _('REV')),
1293 ('', 'decode', None, _('apply any matching decode filter')),
1294 ('', 'decode', None, _('apply any matching decode filter')),
1294 ] + walkopts,
1295 ] + walkopts,
1295 _('[OPTION]... FILE...'),
1296 _('[OPTION]... FILE...'),
1296 inferrepo=True)
1297 inferrepo=True)
1297 def cat(ui, repo, file1, *pats, **opts):
1298 def cat(ui, repo, file1, *pats, **opts):
1298 """output the current or given revision of files
1299 """output the current or given revision of files
1299
1300
1300 Print the specified files as they were at the given revision. If
1301 Print the specified files as they were at the given revision. If
1301 no revision is given, the parent of the working directory is used.
1302 no revision is given, the parent of the working directory is used.
1302
1303
1303 Output may be to a file, in which case the name of the file is
1304 Output may be to a file, in which case the name of the file is
1304 given using a format string. The formatting rules as follows:
1305 given using a format string. The formatting rules as follows:
1305
1306
1306 :``%%``: literal "%" character
1307 :``%%``: literal "%" character
1307 :``%s``: basename of file being printed
1308 :``%s``: basename of file being printed
1308 :``%d``: dirname of file being printed, or '.' if in repository root
1309 :``%d``: dirname of file being printed, or '.' if in repository root
1309 :``%p``: root-relative path name of file being printed
1310 :``%p``: root-relative path name of file being printed
1310 :``%H``: changeset hash (40 hexadecimal digits)
1311 :``%H``: changeset hash (40 hexadecimal digits)
1311 :``%R``: changeset revision number
1312 :``%R``: changeset revision number
1312 :``%h``: short-form changeset hash (12 hexadecimal digits)
1313 :``%h``: short-form changeset hash (12 hexadecimal digits)
1313 :``%r``: zero-padded changeset revision number
1314 :``%r``: zero-padded changeset revision number
1314 :``%b``: basename of the exporting repository
1315 :``%b``: basename of the exporting repository
1315
1316
1316 Returns 0 on success.
1317 Returns 0 on success.
1317 """
1318 """
1318 ctx = scmutil.revsingle(repo, opts.get('rev'))
1319 ctx = scmutil.revsingle(repo, opts.get('rev'))
1319 m = scmutil.match(ctx, (file1,) + pats, opts)
1320 m = scmutil.match(ctx, (file1,) + pats, opts)
1320
1321
1321 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1322 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1322
1323
1323 @command('^clone',
1324 @command('^clone',
1324 [('U', 'noupdate', None, _('the clone will include an empty working '
1325 [('U', 'noupdate', None, _('the clone will include an empty working '
1325 'directory (only a repository)')),
1326 'directory (only a repository)')),
1326 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1327 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1327 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1328 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1328 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1329 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1329 ('', 'pull', None, _('use pull protocol to copy metadata')),
1330 ('', 'pull', None, _('use pull protocol to copy metadata')),
1330 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1331 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1331 ] + remoteopts,
1332 ] + remoteopts,
1332 _('[OPTION]... SOURCE [DEST]'),
1333 _('[OPTION]... SOURCE [DEST]'),
1333 norepo=True)
1334 norepo=True)
1334 def clone(ui, source, dest=None, **opts):
1335 def clone(ui, source, dest=None, **opts):
1335 """make a copy of an existing repository
1336 """make a copy of an existing repository
1336
1337
1337 Create a copy of an existing repository in a new directory.
1338 Create a copy of an existing repository in a new directory.
1338
1339
1339 If no destination directory name is specified, it defaults to the
1340 If no destination directory name is specified, it defaults to the
1340 basename of the source.
1341 basename of the source.
1341
1342
1342 The location of the source is added to the new repository's
1343 The location of the source is added to the new repository's
1343 ``.hg/hgrc`` file, as the default to be used for future pulls.
1344 ``.hg/hgrc`` file, as the default to be used for future pulls.
1344
1345
1345 Only local paths and ``ssh://`` URLs are supported as
1346 Only local paths and ``ssh://`` URLs are supported as
1346 destinations. For ``ssh://`` destinations, no working directory or
1347 destinations. For ``ssh://`` destinations, no working directory or
1347 ``.hg/hgrc`` will be created on the remote side.
1348 ``.hg/hgrc`` will be created on the remote side.
1348
1349
1349 To pull only a subset of changesets, specify one or more revisions
1350 To pull only a subset of changesets, specify one or more revisions
1350 identifiers with -r/--rev or branches with -b/--branch. The
1351 identifiers with -r/--rev or branches with -b/--branch. The
1351 resulting clone will contain only the specified changesets and
1352 resulting clone will contain only the specified changesets and
1352 their ancestors. These options (or 'clone src#rev dest') imply
1353 their ancestors. These options (or 'clone src#rev dest') imply
1353 --pull, even for local source repositories. Note that specifying a
1354 --pull, even for local source repositories. Note that specifying a
1354 tag will include the tagged changeset but not the changeset
1355 tag will include the tagged changeset but not the changeset
1355 containing the tag.
1356 containing the tag.
1356
1357
1357 If the source repository has a bookmark called '@' set, that
1358 If the source repository has a bookmark called '@' set, that
1358 revision will be checked out in the new repository by default.
1359 revision will be checked out in the new repository by default.
1359
1360
1360 To check out a particular version, use -u/--update, or
1361 To check out a particular version, use -u/--update, or
1361 -U/--noupdate to create a clone with no working directory.
1362 -U/--noupdate to create a clone with no working directory.
1362
1363
1363 .. container:: verbose
1364 .. container:: verbose
1364
1365
1365 For efficiency, hardlinks are used for cloning whenever the
1366 For efficiency, hardlinks are used for cloning whenever the
1366 source and destination are on the same filesystem (note this
1367 source and destination are on the same filesystem (note this
1367 applies only to the repository data, not to the working
1368 applies only to the repository data, not to the working
1368 directory). Some filesystems, such as AFS, implement hardlinking
1369 directory). Some filesystems, such as AFS, implement hardlinking
1369 incorrectly, but do not report errors. In these cases, use the
1370 incorrectly, but do not report errors. In these cases, use the
1370 --pull option to avoid hardlinking.
1371 --pull option to avoid hardlinking.
1371
1372
1372 In some cases, you can clone repositories and the working
1373 In some cases, you can clone repositories and the working
1373 directory using full hardlinks with ::
1374 directory using full hardlinks with ::
1374
1375
1375 $ cp -al REPO REPOCLONE
1376 $ cp -al REPO REPOCLONE
1376
1377
1377 This is the fastest way to clone, but it is not always safe. The
1378 This is the fastest way to clone, but it is not always safe. The
1378 operation is not atomic (making sure REPO is not modified during
1379 operation is not atomic (making sure REPO is not modified during
1379 the operation is up to you) and you have to make sure your
1380 the operation is up to you) and you have to make sure your
1380 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1381 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1381 so). Also, this is not compatible with certain extensions that
1382 so). Also, this is not compatible with certain extensions that
1382 place their metadata under the .hg directory, such as mq.
1383 place their metadata under the .hg directory, such as mq.
1383
1384
1384 Mercurial will update the working directory to the first applicable
1385 Mercurial will update the working directory to the first applicable
1385 revision from this list:
1386 revision from this list:
1386
1387
1387 a) null if -U or the source repository has no changesets
1388 a) null if -U or the source repository has no changesets
1388 b) if -u . and the source repository is local, the first parent of
1389 b) if -u . and the source repository is local, the first parent of
1389 the source repository's working directory
1390 the source repository's working directory
1390 c) the changeset specified with -u (if a branch name, this means the
1391 c) the changeset specified with -u (if a branch name, this means the
1391 latest head of that branch)
1392 latest head of that branch)
1392 d) the changeset specified with -r
1393 d) the changeset specified with -r
1393 e) the tipmost head specified with -b
1394 e) the tipmost head specified with -b
1394 f) the tipmost head specified with the url#branch source syntax
1395 f) the tipmost head specified with the url#branch source syntax
1395 g) the revision marked with the '@' bookmark, if present
1396 g) the revision marked with the '@' bookmark, if present
1396 h) the tipmost head of the default branch
1397 h) the tipmost head of the default branch
1397 i) tip
1398 i) tip
1398
1399
1399 Examples:
1400 Examples:
1400
1401
1401 - clone a remote repository to a new directory named hg/::
1402 - clone a remote repository to a new directory named hg/::
1402
1403
1403 hg clone http://selenic.com/hg
1404 hg clone http://selenic.com/hg
1404
1405
1405 - create a lightweight local clone::
1406 - create a lightweight local clone::
1406
1407
1407 hg clone project/ project-feature/
1408 hg clone project/ project-feature/
1408
1409
1409 - clone from an absolute path on an ssh server (note double-slash)::
1410 - clone from an absolute path on an ssh server (note double-slash)::
1410
1411
1411 hg clone ssh://user@server//home/projects/alpha/
1412 hg clone ssh://user@server//home/projects/alpha/
1412
1413
1413 - do a high-speed clone over a LAN while checking out a
1414 - do a high-speed clone over a LAN while checking out a
1414 specified version::
1415 specified version::
1415
1416
1416 hg clone --uncompressed http://server/repo -u 1.5
1417 hg clone --uncompressed http://server/repo -u 1.5
1417
1418
1418 - create a repository without changesets after a particular revision::
1419 - create a repository without changesets after a particular revision::
1419
1420
1420 hg clone -r 04e544 experimental/ good/
1421 hg clone -r 04e544 experimental/ good/
1421
1422
1422 - clone (and track) a particular named branch::
1423 - clone (and track) a particular named branch::
1423
1424
1424 hg clone http://selenic.com/hg#stable
1425 hg clone http://selenic.com/hg#stable
1425
1426
1426 See :hg:`help urls` for details on specifying URLs.
1427 See :hg:`help urls` for details on specifying URLs.
1427
1428
1428 Returns 0 on success.
1429 Returns 0 on success.
1429 """
1430 """
1430 if opts.get('noupdate') and opts.get('updaterev'):
1431 if opts.get('noupdate') and opts.get('updaterev'):
1431 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1432 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1432
1433
1433 r = hg.clone(ui, opts, source, dest,
1434 r = hg.clone(ui, opts, source, dest,
1434 pull=opts.get('pull'),
1435 pull=opts.get('pull'),
1435 stream=opts.get('uncompressed'),
1436 stream=opts.get('uncompressed'),
1436 rev=opts.get('rev'),
1437 rev=opts.get('rev'),
1437 update=opts.get('updaterev') or not opts.get('noupdate'),
1438 update=opts.get('updaterev') or not opts.get('noupdate'),
1438 branch=opts.get('branch'),
1439 branch=opts.get('branch'),
1439 shareopts=opts.get('shareopts'))
1440 shareopts=opts.get('shareopts'))
1440
1441
1441 return r is None
1442 return r is None
1442
1443
1443 @command('^commit|ci',
1444 @command('^commit|ci',
1444 [('A', 'addremove', None,
1445 [('A', 'addremove', None,
1445 _('mark new/missing files as added/removed before committing')),
1446 _('mark new/missing files as added/removed before committing')),
1446 ('', 'close-branch', None,
1447 ('', 'close-branch', None,
1447 _('mark a branch head as closed')),
1448 _('mark a branch head as closed')),
1448 ('', 'amend', None, _('amend the parent of the working directory')),
1449 ('', 'amend', None, _('amend the parent of the working directory')),
1449 ('s', 'secret', None, _('use the secret phase for committing')),
1450 ('s', 'secret', None, _('use the secret phase for committing')),
1450 ('e', 'edit', None, _('invoke editor on commit messages')),
1451 ('e', 'edit', None, _('invoke editor on commit messages')),
1451 ('i', 'interactive', None, _('use interactive mode')),
1452 ('i', 'interactive', None, _('use interactive mode')),
1452 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1453 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1453 _('[OPTION]... [FILE]...'),
1454 _('[OPTION]... [FILE]...'),
1454 inferrepo=True)
1455 inferrepo=True)
1455 def commit(ui, repo, *pats, **opts):
1456 def commit(ui, repo, *pats, **opts):
1456 """commit the specified files or all outstanding changes
1457 """commit the specified files or all outstanding changes
1457
1458
1458 Commit changes to the given files into the repository. Unlike a
1459 Commit changes to the given files into the repository. Unlike a
1459 centralized SCM, this operation is a local operation. See
1460 centralized SCM, this operation is a local operation. See
1460 :hg:`push` for a way to actively distribute your changes.
1461 :hg:`push` for a way to actively distribute your changes.
1461
1462
1462 If a list of files is omitted, all changes reported by :hg:`status`
1463 If a list of files is omitted, all changes reported by :hg:`status`
1463 will be committed.
1464 will be committed.
1464
1465
1465 If you are committing the result of a merge, do not provide any
1466 If you are committing the result of a merge, do not provide any
1466 filenames or -I/-X filters.
1467 filenames or -I/-X filters.
1467
1468
1468 If no commit message is specified, Mercurial starts your
1469 If no commit message is specified, Mercurial starts your
1469 configured editor where you can enter a message. In case your
1470 configured editor where you can enter a message. In case your
1470 commit fails, you will find a backup of your message in
1471 commit fails, you will find a backup of your message in
1471 ``.hg/last-message.txt``.
1472 ``.hg/last-message.txt``.
1472
1473
1473 The --close-branch flag can be used to mark the current branch
1474 The --close-branch flag can be used to mark the current branch
1474 head closed. When all heads of a branch are closed, the branch
1475 head closed. When all heads of a branch are closed, the branch
1475 will be considered closed and no longer listed.
1476 will be considered closed and no longer listed.
1476
1477
1477 The --amend flag can be used to amend the parent of the
1478 The --amend flag can be used to amend the parent of the
1478 working directory with a new commit that contains the changes
1479 working directory with a new commit that contains the changes
1479 in the parent in addition to those currently reported by :hg:`status`,
1480 in the parent in addition to those currently reported by :hg:`status`,
1480 if there are any. The old commit is stored in a backup bundle in
1481 if there are any. The old commit is stored in a backup bundle in
1481 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1482 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1482 on how to restore it).
1483 on how to restore it).
1483
1484
1484 Message, user and date are taken from the amended commit unless
1485 Message, user and date are taken from the amended commit unless
1485 specified. When a message isn't specified on the command line,
1486 specified. When a message isn't specified on the command line,
1486 the editor will open with the message of the amended commit.
1487 the editor will open with the message of the amended commit.
1487
1488
1488 It is not possible to amend public changesets (see :hg:`help phases`)
1489 It is not possible to amend public changesets (see :hg:`help phases`)
1489 or changesets that have children.
1490 or changesets that have children.
1490
1491
1491 See :hg:`help dates` for a list of formats valid for -d/--date.
1492 See :hg:`help dates` for a list of formats valid for -d/--date.
1492
1493
1493 Returns 0 on success, 1 if nothing changed.
1494 Returns 0 on success, 1 if nothing changed.
1494 """
1495 """
1495 if opts.get('interactive'):
1496 if opts.get('interactive'):
1496 opts.pop('interactive')
1497 opts.pop('interactive')
1497 cmdutil.dorecord(ui, repo, commit, None, False,
1498 cmdutil.dorecord(ui, repo, commit, None, False,
1498 cmdutil.recordfilter, *pats, **opts)
1499 cmdutil.recordfilter, *pats, **opts)
1499 return
1500 return
1500
1501
1501 if opts.get('subrepos'):
1502 if opts.get('subrepos'):
1502 if opts.get('amend'):
1503 if opts.get('amend'):
1503 raise util.Abort(_('cannot amend with --subrepos'))
1504 raise util.Abort(_('cannot amend with --subrepos'))
1504 # Let --subrepos on the command line override config setting.
1505 # Let --subrepos on the command line override config setting.
1505 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1506 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1506
1507
1507 cmdutil.checkunfinished(repo, commit=True)
1508 cmdutil.checkunfinished(repo, commit=True)
1508
1509
1509 branch = repo[None].branch()
1510 branch = repo[None].branch()
1510 bheads = repo.branchheads(branch)
1511 bheads = repo.branchheads(branch)
1511
1512
1512 extra = {}
1513 extra = {}
1513 if opts.get('close_branch'):
1514 if opts.get('close_branch'):
1514 extra['close'] = 1
1515 extra['close'] = 1
1515
1516
1516 if not bheads:
1517 if not bheads:
1517 raise util.Abort(_('can only close branch heads'))
1518 raise util.Abort(_('can only close branch heads'))
1518 elif opts.get('amend'):
1519 elif opts.get('amend'):
1519 if repo.parents()[0].p1().branch() != branch and \
1520 if repo.parents()[0].p1().branch() != branch and \
1520 repo.parents()[0].p2().branch() != branch:
1521 repo.parents()[0].p2().branch() != branch:
1521 raise util.Abort(_('can only close branch heads'))
1522 raise util.Abort(_('can only close branch heads'))
1522
1523
1523 if opts.get('amend'):
1524 if opts.get('amend'):
1524 if ui.configbool('ui', 'commitsubrepos'):
1525 if ui.configbool('ui', 'commitsubrepos'):
1525 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1526 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1526
1527
1527 old = repo['.']
1528 old = repo['.']
1528 if not old.mutable():
1529 if not old.mutable():
1529 raise util.Abort(_('cannot amend public changesets'))
1530 raise util.Abort(_('cannot amend public changesets'))
1530 if len(repo[None].parents()) > 1:
1531 if len(repo[None].parents()) > 1:
1531 raise util.Abort(_('cannot amend while merging'))
1532 raise util.Abort(_('cannot amend while merging'))
1532 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1533 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1533 if not allowunstable and old.children():
1534 if not allowunstable and old.children():
1534 raise util.Abort(_('cannot amend changeset with children'))
1535 raise util.Abort(_('cannot amend changeset with children'))
1535
1536
1536 # commitfunc is used only for temporary amend commit by cmdutil.amend
1537 # commitfunc is used only for temporary amend commit by cmdutil.amend
1537 def commitfunc(ui, repo, message, match, opts):
1538 def commitfunc(ui, repo, message, match, opts):
1538 return repo.commit(message,
1539 return repo.commit(message,
1539 opts.get('user') or old.user(),
1540 opts.get('user') or old.user(),
1540 opts.get('date') or old.date(),
1541 opts.get('date') or old.date(),
1541 match,
1542 match,
1542 extra=extra)
1543 extra=extra)
1543
1544
1544 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1545 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1545 if node == old.node():
1546 if node == old.node():
1546 ui.status(_("nothing changed\n"))
1547 ui.status(_("nothing changed\n"))
1547 return 1
1548 return 1
1548 else:
1549 else:
1549 def commitfunc(ui, repo, message, match, opts):
1550 def commitfunc(ui, repo, message, match, opts):
1550 backup = ui.backupconfig('phases', 'new-commit')
1551 backup = ui.backupconfig('phases', 'new-commit')
1551 baseui = repo.baseui
1552 baseui = repo.baseui
1552 basebackup = baseui.backupconfig('phases', 'new-commit')
1553 basebackup = baseui.backupconfig('phases', 'new-commit')
1553 try:
1554 try:
1554 if opts.get('secret'):
1555 if opts.get('secret'):
1555 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1556 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1556 # Propagate to subrepos
1557 # Propagate to subrepos
1557 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1558 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1558
1559
1559 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1560 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1560 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1561 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1561 return repo.commit(message, opts.get('user'), opts.get('date'),
1562 return repo.commit(message, opts.get('user'), opts.get('date'),
1562 match,
1563 match,
1563 editor=editor,
1564 editor=editor,
1564 extra=extra)
1565 extra=extra)
1565 finally:
1566 finally:
1566 ui.restoreconfig(backup)
1567 ui.restoreconfig(backup)
1567 repo.baseui.restoreconfig(basebackup)
1568 repo.baseui.restoreconfig(basebackup)
1568
1569
1569
1570
1570 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1571 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1571
1572
1572 if not node:
1573 if not node:
1573 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1574 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1574 if stat[3]:
1575 if stat[3]:
1575 ui.status(_("nothing changed (%d missing files, see "
1576 ui.status(_("nothing changed (%d missing files, see "
1576 "'hg status')\n") % len(stat[3]))
1577 "'hg status')\n") % len(stat[3]))
1577 else:
1578 else:
1578 ui.status(_("nothing changed\n"))
1579 ui.status(_("nothing changed\n"))
1579 return 1
1580 return 1
1580
1581
1581 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1582 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1582
1583
1583 @command('config|showconfig|debugconfig',
1584 @command('config|showconfig|debugconfig',
1584 [('u', 'untrusted', None, _('show untrusted configuration options')),
1585 [('u', 'untrusted', None, _('show untrusted configuration options')),
1585 ('e', 'edit', None, _('edit user config')),
1586 ('e', 'edit', None, _('edit user config')),
1586 ('l', 'local', None, _('edit repository config')),
1587 ('l', 'local', None, _('edit repository config')),
1587 ('g', 'global', None, _('edit global config'))],
1588 ('g', 'global', None, _('edit global config'))],
1588 _('[-u] [NAME]...'),
1589 _('[-u] [NAME]...'),
1589 optionalrepo=True)
1590 optionalrepo=True)
1590 def config(ui, repo, *values, **opts):
1591 def config(ui, repo, *values, **opts):
1591 """show combined config settings from all hgrc files
1592 """show combined config settings from all hgrc files
1592
1593
1593 With no arguments, print names and values of all config items.
1594 With no arguments, print names and values of all config items.
1594
1595
1595 With one argument of the form section.name, print just the value
1596 With one argument of the form section.name, print just the value
1596 of that config item.
1597 of that config item.
1597
1598
1598 With multiple arguments, print names and values of all config
1599 With multiple arguments, print names and values of all config
1599 items with matching section names.
1600 items with matching section names.
1600
1601
1601 With --edit, start an editor on the user-level config file. With
1602 With --edit, start an editor on the user-level config file. With
1602 --global, edit the system-wide config file. With --local, edit the
1603 --global, edit the system-wide config file. With --local, edit the
1603 repository-level config file.
1604 repository-level config file.
1604
1605
1605 With --debug, the source (filename and line number) is printed
1606 With --debug, the source (filename and line number) is printed
1606 for each config item.
1607 for each config item.
1607
1608
1608 See :hg:`help config` for more information about config files.
1609 See :hg:`help config` for more information about config files.
1609
1610
1610 Returns 0 on success, 1 if NAME does not exist.
1611 Returns 0 on success, 1 if NAME does not exist.
1611
1612
1612 """
1613 """
1613
1614
1614 if opts.get('edit') or opts.get('local') or opts.get('global'):
1615 if opts.get('edit') or opts.get('local') or opts.get('global'):
1615 if opts.get('local') and opts.get('global'):
1616 if opts.get('local') and opts.get('global'):
1616 raise util.Abort(_("can't use --local and --global together"))
1617 raise util.Abort(_("can't use --local and --global together"))
1617
1618
1618 if opts.get('local'):
1619 if opts.get('local'):
1619 if not repo:
1620 if not repo:
1620 raise util.Abort(_("can't use --local outside a repository"))
1621 raise util.Abort(_("can't use --local outside a repository"))
1621 paths = [repo.join('hgrc')]
1622 paths = [repo.join('hgrc')]
1622 elif opts.get('global'):
1623 elif opts.get('global'):
1623 paths = scmutil.systemrcpath()
1624 paths = scmutil.systemrcpath()
1624 else:
1625 else:
1625 paths = scmutil.userrcpath()
1626 paths = scmutil.userrcpath()
1626
1627
1627 for f in paths:
1628 for f in paths:
1628 if os.path.exists(f):
1629 if os.path.exists(f):
1629 break
1630 break
1630 else:
1631 else:
1631 if opts.get('global'):
1632 if opts.get('global'):
1632 samplehgrc = uimod.samplehgrcs['global']
1633 samplehgrc = uimod.samplehgrcs['global']
1633 elif opts.get('local'):
1634 elif opts.get('local'):
1634 samplehgrc = uimod.samplehgrcs['local']
1635 samplehgrc = uimod.samplehgrcs['local']
1635 else:
1636 else:
1636 samplehgrc = uimod.samplehgrcs['user']
1637 samplehgrc = uimod.samplehgrcs['user']
1637
1638
1638 f = paths[0]
1639 f = paths[0]
1639 fp = open(f, "w")
1640 fp = open(f, "w")
1640 fp.write(samplehgrc)
1641 fp.write(samplehgrc)
1641 fp.close()
1642 fp.close()
1642
1643
1643 editor = ui.geteditor()
1644 editor = ui.geteditor()
1644 ui.system("%s \"%s\"" % (editor, f),
1645 ui.system("%s \"%s\"" % (editor, f),
1645 onerr=util.Abort, errprefix=_("edit failed"))
1646 onerr=util.Abort, errprefix=_("edit failed"))
1646 return
1647 return
1647
1648
1648 for f in scmutil.rcpath():
1649 for f in scmutil.rcpath():
1649 ui.debug('read config from: %s\n' % f)
1650 ui.debug('read config from: %s\n' % f)
1650 untrusted = bool(opts.get('untrusted'))
1651 untrusted = bool(opts.get('untrusted'))
1651 if values:
1652 if values:
1652 sections = [v for v in values if '.' not in v]
1653 sections = [v for v in values if '.' not in v]
1653 items = [v for v in values if '.' in v]
1654 items = [v for v in values if '.' in v]
1654 if len(items) > 1 or items and sections:
1655 if len(items) > 1 or items and sections:
1655 raise util.Abort(_('only one config item permitted'))
1656 raise util.Abort(_('only one config item permitted'))
1656 matched = False
1657 matched = False
1657 for section, name, value in ui.walkconfig(untrusted=untrusted):
1658 for section, name, value in ui.walkconfig(untrusted=untrusted):
1658 value = str(value).replace('\n', '\\n')
1659 value = str(value).replace('\n', '\\n')
1659 sectname = section + '.' + name
1660 sectname = section + '.' + name
1660 if values:
1661 if values:
1661 for v in values:
1662 for v in values:
1662 if v == section:
1663 if v == section:
1663 ui.debug('%s: ' %
1664 ui.debug('%s: ' %
1664 ui.configsource(section, name, untrusted))
1665 ui.configsource(section, name, untrusted))
1665 ui.write('%s=%s\n' % (sectname, value))
1666 ui.write('%s=%s\n' % (sectname, value))
1666 matched = True
1667 matched = True
1667 elif v == sectname:
1668 elif v == sectname:
1668 ui.debug('%s: ' %
1669 ui.debug('%s: ' %
1669 ui.configsource(section, name, untrusted))
1670 ui.configsource(section, name, untrusted))
1670 ui.write(value, '\n')
1671 ui.write(value, '\n')
1671 matched = True
1672 matched = True
1672 else:
1673 else:
1673 ui.debug('%s: ' %
1674 ui.debug('%s: ' %
1674 ui.configsource(section, name, untrusted))
1675 ui.configsource(section, name, untrusted))
1675 ui.write('%s=%s\n' % (sectname, value))
1676 ui.write('%s=%s\n' % (sectname, value))
1676 matched = True
1677 matched = True
1677 if matched:
1678 if matched:
1678 return 0
1679 return 0
1679 return 1
1680 return 1
1680
1681
1681 @command('copy|cp',
1682 @command('copy|cp',
1682 [('A', 'after', None, _('record a copy that has already occurred')),
1683 [('A', 'after', None, _('record a copy that has already occurred')),
1683 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1684 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1684 ] + walkopts + dryrunopts,
1685 ] + walkopts + dryrunopts,
1685 _('[OPTION]... [SOURCE]... DEST'))
1686 _('[OPTION]... [SOURCE]... DEST'))
1686 def copy(ui, repo, *pats, **opts):
1687 def copy(ui, repo, *pats, **opts):
1687 """mark files as copied for the next commit
1688 """mark files as copied for the next commit
1688
1689
1689 Mark dest as having copies of source files. If dest is a
1690 Mark dest as having copies of source files. If dest is a
1690 directory, copies are put in that directory. If dest is a file,
1691 directory, copies are put in that directory. If dest is a file,
1691 the source must be a single file.
1692 the source must be a single file.
1692
1693
1693 By default, this command copies the contents of files as they
1694 By default, this command copies the contents of files as they
1694 exist in the working directory. If invoked with -A/--after, the
1695 exist in the working directory. If invoked with -A/--after, the
1695 operation is recorded, but no copying is performed.
1696 operation is recorded, but no copying is performed.
1696
1697
1697 This command takes effect with the next commit. To undo a copy
1698 This command takes effect with the next commit. To undo a copy
1698 before that, see :hg:`revert`.
1699 before that, see :hg:`revert`.
1699
1700
1700 Returns 0 on success, 1 if errors are encountered.
1701 Returns 0 on success, 1 if errors are encountered.
1701 """
1702 """
1702 wlock = repo.wlock(False)
1703 wlock = repo.wlock(False)
1703 try:
1704 try:
1704 return cmdutil.copy(ui, repo, pats, opts)
1705 return cmdutil.copy(ui, repo, pats, opts)
1705 finally:
1706 finally:
1706 wlock.release()
1707 wlock.release()
1707
1708
1708 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1709 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1709 def debugancestor(ui, repo, *args):
1710 def debugancestor(ui, repo, *args):
1710 """find the ancestor revision of two revisions in a given index"""
1711 """find the ancestor revision of two revisions in a given index"""
1711 if len(args) == 3:
1712 if len(args) == 3:
1712 index, rev1, rev2 = args
1713 index, rev1, rev2 = args
1713 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1714 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1714 lookup = r.lookup
1715 lookup = r.lookup
1715 elif len(args) == 2:
1716 elif len(args) == 2:
1716 if not repo:
1717 if not repo:
1717 raise util.Abort(_("there is no Mercurial repository here "
1718 raise util.Abort(_("there is no Mercurial repository here "
1718 "(.hg not found)"))
1719 "(.hg not found)"))
1719 rev1, rev2 = args
1720 rev1, rev2 = args
1720 r = repo.changelog
1721 r = repo.changelog
1721 lookup = repo.lookup
1722 lookup = repo.lookup
1722 else:
1723 else:
1723 raise util.Abort(_('either two or three arguments required'))
1724 raise util.Abort(_('either two or three arguments required'))
1724 a = r.ancestor(lookup(rev1), lookup(rev2))
1725 a = r.ancestor(lookup(rev1), lookup(rev2))
1725 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1726 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1726
1727
1727 @command('debugbuilddag',
1728 @command('debugbuilddag',
1728 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1729 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1729 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1730 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1730 ('n', 'new-file', None, _('add new file at each rev'))],
1731 ('n', 'new-file', None, _('add new file at each rev'))],
1731 _('[OPTION]... [TEXT]'))
1732 _('[OPTION]... [TEXT]'))
1732 def debugbuilddag(ui, repo, text=None,
1733 def debugbuilddag(ui, repo, text=None,
1733 mergeable_file=False,
1734 mergeable_file=False,
1734 overwritten_file=False,
1735 overwritten_file=False,
1735 new_file=False):
1736 new_file=False):
1736 """builds a repo with a given DAG from scratch in the current empty repo
1737 """builds a repo with a given DAG from scratch in the current empty repo
1737
1738
1738 The description of the DAG is read from stdin if not given on the
1739 The description of the DAG is read from stdin if not given on the
1739 command line.
1740 command line.
1740
1741
1741 Elements:
1742 Elements:
1742
1743
1743 - "+n" is a linear run of n nodes based on the current default parent
1744 - "+n" is a linear run of n nodes based on the current default parent
1744 - "." is a single node based on the current default parent
1745 - "." is a single node based on the current default parent
1745 - "$" resets the default parent to null (implied at the start);
1746 - "$" resets the default parent to null (implied at the start);
1746 otherwise the default parent is always the last node created
1747 otherwise the default parent is always the last node created
1747 - "<p" sets the default parent to the backref p
1748 - "<p" sets the default parent to the backref p
1748 - "*p" is a fork at parent p, which is a backref
1749 - "*p" is a fork at parent p, which is a backref
1749 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1750 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1750 - "/p2" is a merge of the preceding node and p2
1751 - "/p2" is a merge of the preceding node and p2
1751 - ":tag" defines a local tag for the preceding node
1752 - ":tag" defines a local tag for the preceding node
1752 - "@branch" sets the named branch for subsequent nodes
1753 - "@branch" sets the named branch for subsequent nodes
1753 - "#...\\n" is a comment up to the end of the line
1754 - "#...\\n" is a comment up to the end of the line
1754
1755
1755 Whitespace between the above elements is ignored.
1756 Whitespace between the above elements is ignored.
1756
1757
1757 A backref is either
1758 A backref is either
1758
1759
1759 - a number n, which references the node curr-n, where curr is the current
1760 - a number n, which references the node curr-n, where curr is the current
1760 node, or
1761 node, or
1761 - the name of a local tag you placed earlier using ":tag", or
1762 - the name of a local tag you placed earlier using ":tag", or
1762 - empty to denote the default parent.
1763 - empty to denote the default parent.
1763
1764
1764 All string valued-elements are either strictly alphanumeric, or must
1765 All string valued-elements are either strictly alphanumeric, or must
1765 be enclosed in double quotes ("..."), with "\\" as escape character.
1766 be enclosed in double quotes ("..."), with "\\" as escape character.
1766 """
1767 """
1767
1768
1768 if text is None:
1769 if text is None:
1769 ui.status(_("reading DAG from stdin\n"))
1770 ui.status(_("reading DAG from stdin\n"))
1770 text = ui.fin.read()
1771 text = ui.fin.read()
1771
1772
1772 cl = repo.changelog
1773 cl = repo.changelog
1773 if len(cl) > 0:
1774 if len(cl) > 0:
1774 raise util.Abort(_('repository is not empty'))
1775 raise util.Abort(_('repository is not empty'))
1775
1776
1776 # determine number of revs in DAG
1777 # determine number of revs in DAG
1777 total = 0
1778 total = 0
1778 for type, data in dagparser.parsedag(text):
1779 for type, data in dagparser.parsedag(text):
1779 if type == 'n':
1780 if type == 'n':
1780 total += 1
1781 total += 1
1781
1782
1782 if mergeable_file:
1783 if mergeable_file:
1783 linesperrev = 2
1784 linesperrev = 2
1784 # make a file with k lines per rev
1785 # make a file with k lines per rev
1785 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1786 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1786 initialmergedlines.append("")
1787 initialmergedlines.append("")
1787
1788
1788 tags = []
1789 tags = []
1789
1790
1790 lock = tr = None
1791 lock = tr = None
1791 try:
1792 try:
1792 lock = repo.lock()
1793 lock = repo.lock()
1793 tr = repo.transaction("builddag")
1794 tr = repo.transaction("builddag")
1794
1795
1795 at = -1
1796 at = -1
1796 atbranch = 'default'
1797 atbranch = 'default'
1797 nodeids = []
1798 nodeids = []
1798 id = 0
1799 id = 0
1799 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1800 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1800 for type, data in dagparser.parsedag(text):
1801 for type, data in dagparser.parsedag(text):
1801 if type == 'n':
1802 if type == 'n':
1802 ui.note(('node %s\n' % str(data)))
1803 ui.note(('node %s\n' % str(data)))
1803 id, ps = data
1804 id, ps = data
1804
1805
1805 files = []
1806 files = []
1806 fctxs = {}
1807 fctxs = {}
1807
1808
1808 p2 = None
1809 p2 = None
1809 if mergeable_file:
1810 if mergeable_file:
1810 fn = "mf"
1811 fn = "mf"
1811 p1 = repo[ps[0]]
1812 p1 = repo[ps[0]]
1812 if len(ps) > 1:
1813 if len(ps) > 1:
1813 p2 = repo[ps[1]]
1814 p2 = repo[ps[1]]
1814 pa = p1.ancestor(p2)
1815 pa = p1.ancestor(p2)
1815 base, local, other = [x[fn].data() for x in (pa, p1,
1816 base, local, other = [x[fn].data() for x in (pa, p1,
1816 p2)]
1817 p2)]
1817 m3 = simplemerge.Merge3Text(base, local, other)
1818 m3 = simplemerge.Merge3Text(base, local, other)
1818 ml = [l.strip() for l in m3.merge_lines()]
1819 ml = [l.strip() for l in m3.merge_lines()]
1819 ml.append("")
1820 ml.append("")
1820 elif at > 0:
1821 elif at > 0:
1821 ml = p1[fn].data().split("\n")
1822 ml = p1[fn].data().split("\n")
1822 else:
1823 else:
1823 ml = initialmergedlines
1824 ml = initialmergedlines
1824 ml[id * linesperrev] += " r%i" % id
1825 ml[id * linesperrev] += " r%i" % id
1825 mergedtext = "\n".join(ml)
1826 mergedtext = "\n".join(ml)
1826 files.append(fn)
1827 files.append(fn)
1827 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1828 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1828
1829
1829 if overwritten_file:
1830 if overwritten_file:
1830 fn = "of"
1831 fn = "of"
1831 files.append(fn)
1832 files.append(fn)
1832 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1833 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1833
1834
1834 if new_file:
1835 if new_file:
1835 fn = "nf%i" % id
1836 fn = "nf%i" % id
1836 files.append(fn)
1837 files.append(fn)
1837 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1838 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1838 if len(ps) > 1:
1839 if len(ps) > 1:
1839 if not p2:
1840 if not p2:
1840 p2 = repo[ps[1]]
1841 p2 = repo[ps[1]]
1841 for fn in p2:
1842 for fn in p2:
1842 if fn.startswith("nf"):
1843 if fn.startswith("nf"):
1843 files.append(fn)
1844 files.append(fn)
1844 fctxs[fn] = p2[fn]
1845 fctxs[fn] = p2[fn]
1845
1846
1846 def fctxfn(repo, cx, path):
1847 def fctxfn(repo, cx, path):
1847 return fctxs.get(path)
1848 return fctxs.get(path)
1848
1849
1849 if len(ps) == 0 or ps[0] < 0:
1850 if len(ps) == 0 or ps[0] < 0:
1850 pars = [None, None]
1851 pars = [None, None]
1851 elif len(ps) == 1:
1852 elif len(ps) == 1:
1852 pars = [nodeids[ps[0]], None]
1853 pars = [nodeids[ps[0]], None]
1853 else:
1854 else:
1854 pars = [nodeids[p] for p in ps]
1855 pars = [nodeids[p] for p in ps]
1855 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1856 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1856 date=(id, 0),
1857 date=(id, 0),
1857 user="debugbuilddag",
1858 user="debugbuilddag",
1858 extra={'branch': atbranch})
1859 extra={'branch': atbranch})
1859 nodeid = repo.commitctx(cx)
1860 nodeid = repo.commitctx(cx)
1860 nodeids.append(nodeid)
1861 nodeids.append(nodeid)
1861 at = id
1862 at = id
1862 elif type == 'l':
1863 elif type == 'l':
1863 id, name = data
1864 id, name = data
1864 ui.note(('tag %s\n' % name))
1865 ui.note(('tag %s\n' % name))
1865 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1866 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1866 elif type == 'a':
1867 elif type == 'a':
1867 ui.note(('branch %s\n' % data))
1868 ui.note(('branch %s\n' % data))
1868 atbranch = data
1869 atbranch = data
1869 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1870 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1870 tr.close()
1871 tr.close()
1871
1872
1872 if tags:
1873 if tags:
1873 repo.vfs.write("localtags", "".join(tags))
1874 repo.vfs.write("localtags", "".join(tags))
1874 finally:
1875 finally:
1875 ui.progress(_('building'), None)
1876 ui.progress(_('building'), None)
1876 release(tr, lock)
1877 release(tr, lock)
1877
1878
1878 @command('debugbundle',
1879 @command('debugbundle',
1879 [('a', 'all', None, _('show all details'))],
1880 [('a', 'all', None, _('show all details'))],
1880 _('FILE'),
1881 _('FILE'),
1881 norepo=True)
1882 norepo=True)
1882 def debugbundle(ui, bundlepath, all=None, **opts):
1883 def debugbundle(ui, bundlepath, all=None, **opts):
1883 """lists the contents of a bundle"""
1884 """lists the contents of a bundle"""
1884 f = hg.openpath(ui, bundlepath)
1885 f = hg.openpath(ui, bundlepath)
1885 try:
1886 try:
1886 gen = exchange.readbundle(ui, f, bundlepath)
1887 gen = exchange.readbundle(ui, f, bundlepath)
1887 if isinstance(gen, bundle2.unbundle20):
1888 if isinstance(gen, bundle2.unbundle20):
1888 return _debugbundle2(ui, gen, all=all, **opts)
1889 return _debugbundle2(ui, gen, all=all, **opts)
1889 if all:
1890 if all:
1890 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1891 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1891
1892
1892 def showchunks(named):
1893 def showchunks(named):
1893 ui.write("\n%s\n" % named)
1894 ui.write("\n%s\n" % named)
1894 chain = None
1895 chain = None
1895 while True:
1896 while True:
1896 chunkdata = gen.deltachunk(chain)
1897 chunkdata = gen.deltachunk(chain)
1897 if not chunkdata:
1898 if not chunkdata:
1898 break
1899 break
1899 node = chunkdata['node']
1900 node = chunkdata['node']
1900 p1 = chunkdata['p1']
1901 p1 = chunkdata['p1']
1901 p2 = chunkdata['p2']
1902 p2 = chunkdata['p2']
1902 cs = chunkdata['cs']
1903 cs = chunkdata['cs']
1903 deltabase = chunkdata['deltabase']
1904 deltabase = chunkdata['deltabase']
1904 delta = chunkdata['delta']
1905 delta = chunkdata['delta']
1905 ui.write("%s %s %s %s %s %s\n" %
1906 ui.write("%s %s %s %s %s %s\n" %
1906 (hex(node), hex(p1), hex(p2),
1907 (hex(node), hex(p1), hex(p2),
1907 hex(cs), hex(deltabase), len(delta)))
1908 hex(cs), hex(deltabase), len(delta)))
1908 chain = node
1909 chain = node
1909
1910
1910 chunkdata = gen.changelogheader()
1911 chunkdata = gen.changelogheader()
1911 showchunks("changelog")
1912 showchunks("changelog")
1912 chunkdata = gen.manifestheader()
1913 chunkdata = gen.manifestheader()
1913 showchunks("manifest")
1914 showchunks("manifest")
1914 while True:
1915 while True:
1915 chunkdata = gen.filelogheader()
1916 chunkdata = gen.filelogheader()
1916 if not chunkdata:
1917 if not chunkdata:
1917 break
1918 break
1918 fname = chunkdata['filename']
1919 fname = chunkdata['filename']
1919 showchunks(fname)
1920 showchunks(fname)
1920 else:
1921 else:
1921 if isinstance(gen, bundle2.unbundle20):
1922 if isinstance(gen, bundle2.unbundle20):
1922 raise util.Abort(_('use debugbundle2 for this file'))
1923 raise util.Abort(_('use debugbundle2 for this file'))
1923 chunkdata = gen.changelogheader()
1924 chunkdata = gen.changelogheader()
1924 chain = None
1925 chain = None
1925 while True:
1926 while True:
1926 chunkdata = gen.deltachunk(chain)
1927 chunkdata = gen.deltachunk(chain)
1927 if not chunkdata:
1928 if not chunkdata:
1928 break
1929 break
1929 node = chunkdata['node']
1930 node = chunkdata['node']
1930 ui.write("%s\n" % hex(node))
1931 ui.write("%s\n" % hex(node))
1931 chain = node
1932 chain = node
1932 finally:
1933 finally:
1933 f.close()
1934 f.close()
1934
1935
1935 def _debugbundle2(ui, gen, **opts):
1936 def _debugbundle2(ui, gen, **opts):
1936 """lists the contents of a bundle2"""
1937 """lists the contents of a bundle2"""
1937 if not isinstance(gen, bundle2.unbundle20):
1938 if not isinstance(gen, bundle2.unbundle20):
1938 raise util.Abort(_('not a bundle2 file'))
1939 raise util.Abort(_('not a bundle2 file'))
1939 ui.write(('Stream params: %s\n' % repr(gen.params)))
1940 ui.write(('Stream params: %s\n' % repr(gen.params)))
1940 for part in gen.iterparts():
1941 for part in gen.iterparts():
1941 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1942 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1942 if part.type == 'changegroup':
1943 if part.type == 'changegroup':
1943 version = part.params.get('version', '01')
1944 version = part.params.get('version', '01')
1944 cg = changegroup.packermap[version][1](part, 'UN')
1945 cg = changegroup.packermap[version][1](part, 'UN')
1945 chunkdata = cg.changelogheader()
1946 chunkdata = cg.changelogheader()
1946 chain = None
1947 chain = None
1947 while True:
1948 while True:
1948 chunkdata = cg.deltachunk(chain)
1949 chunkdata = cg.deltachunk(chain)
1949 if not chunkdata:
1950 if not chunkdata:
1950 break
1951 break
1951 node = chunkdata['node']
1952 node = chunkdata['node']
1952 ui.write(" %s\n" % hex(node))
1953 ui.write(" %s\n" % hex(node))
1953 chain = node
1954 chain = node
1954
1955
1955 @command('debugcheckstate', [], '')
1956 @command('debugcheckstate', [], '')
1956 def debugcheckstate(ui, repo):
1957 def debugcheckstate(ui, repo):
1957 """validate the correctness of the current dirstate"""
1958 """validate the correctness of the current dirstate"""
1958 parent1, parent2 = repo.dirstate.parents()
1959 parent1, parent2 = repo.dirstate.parents()
1959 m1 = repo[parent1].manifest()
1960 m1 = repo[parent1].manifest()
1960 m2 = repo[parent2].manifest()
1961 m2 = repo[parent2].manifest()
1961 errors = 0
1962 errors = 0
1962 for f in repo.dirstate:
1963 for f in repo.dirstate:
1963 state = repo.dirstate[f]
1964 state = repo.dirstate[f]
1964 if state in "nr" and f not in m1:
1965 if state in "nr" and f not in m1:
1965 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1966 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1966 errors += 1
1967 errors += 1
1967 if state in "a" and f in m1:
1968 if state in "a" and f in m1:
1968 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1969 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1969 errors += 1
1970 errors += 1
1970 if state in "m" and f not in m1 and f not in m2:
1971 if state in "m" and f not in m1 and f not in m2:
1971 ui.warn(_("%s in state %s, but not in either manifest\n") %
1972 ui.warn(_("%s in state %s, but not in either manifest\n") %
1972 (f, state))
1973 (f, state))
1973 errors += 1
1974 errors += 1
1974 for f in m1:
1975 for f in m1:
1975 state = repo.dirstate[f]
1976 state = repo.dirstate[f]
1976 if state not in "nrm":
1977 if state not in "nrm":
1977 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1978 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1978 errors += 1
1979 errors += 1
1979 if errors:
1980 if errors:
1980 error = _(".hg/dirstate inconsistent with current parent's manifest")
1981 error = _(".hg/dirstate inconsistent with current parent's manifest")
1981 raise util.Abort(error)
1982 raise util.Abort(error)
1982
1983
1983 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1984 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1984 def debugcommands(ui, cmd='', *args):
1985 def debugcommands(ui, cmd='', *args):
1985 """list all available commands and options"""
1986 """list all available commands and options"""
1986 for cmd, vals in sorted(table.iteritems()):
1987 for cmd, vals in sorted(table.iteritems()):
1987 cmd = cmd.split('|')[0].strip('^')
1988 cmd = cmd.split('|')[0].strip('^')
1988 opts = ', '.join([i[1] for i in vals[1]])
1989 opts = ', '.join([i[1] for i in vals[1]])
1989 ui.write('%s: %s\n' % (cmd, opts))
1990 ui.write('%s: %s\n' % (cmd, opts))
1990
1991
1991 @command('debugcomplete',
1992 @command('debugcomplete',
1992 [('o', 'options', None, _('show the command options'))],
1993 [('o', 'options', None, _('show the command options'))],
1993 _('[-o] CMD'),
1994 _('[-o] CMD'),
1994 norepo=True)
1995 norepo=True)
1995 def debugcomplete(ui, cmd='', **opts):
1996 def debugcomplete(ui, cmd='', **opts):
1996 """returns the completion list associated with the given command"""
1997 """returns the completion list associated with the given command"""
1997
1998
1998 if opts.get('options'):
1999 if opts.get('options'):
1999 options = []
2000 options = []
2000 otables = [globalopts]
2001 otables = [globalopts]
2001 if cmd:
2002 if cmd:
2002 aliases, entry = cmdutil.findcmd(cmd, table, False)
2003 aliases, entry = cmdutil.findcmd(cmd, table, False)
2003 otables.append(entry[1])
2004 otables.append(entry[1])
2004 for t in otables:
2005 for t in otables:
2005 for o in t:
2006 for o in t:
2006 if "(DEPRECATED)" in o[3]:
2007 if "(DEPRECATED)" in o[3]:
2007 continue
2008 continue
2008 if o[0]:
2009 if o[0]:
2009 options.append('-%s' % o[0])
2010 options.append('-%s' % o[0])
2010 options.append('--%s' % o[1])
2011 options.append('--%s' % o[1])
2011 ui.write("%s\n" % "\n".join(options))
2012 ui.write("%s\n" % "\n".join(options))
2012 return
2013 return
2013
2014
2014 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2015 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2015 if ui.verbose:
2016 if ui.verbose:
2016 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2017 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2017 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2018 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2018
2019
2019 @command('debugdag',
2020 @command('debugdag',
2020 [('t', 'tags', None, _('use tags as labels')),
2021 [('t', 'tags', None, _('use tags as labels')),
2021 ('b', 'branches', None, _('annotate with branch names')),
2022 ('b', 'branches', None, _('annotate with branch names')),
2022 ('', 'dots', None, _('use dots for runs')),
2023 ('', 'dots', None, _('use dots for runs')),
2023 ('s', 'spaces', None, _('separate elements by spaces'))],
2024 ('s', 'spaces', None, _('separate elements by spaces'))],
2024 _('[OPTION]... [FILE [REV]...]'),
2025 _('[OPTION]... [FILE [REV]...]'),
2025 optionalrepo=True)
2026 optionalrepo=True)
2026 def debugdag(ui, repo, file_=None, *revs, **opts):
2027 def debugdag(ui, repo, file_=None, *revs, **opts):
2027 """format the changelog or an index DAG as a concise textual description
2028 """format the changelog or an index DAG as a concise textual description
2028
2029
2029 If you pass a revlog index, the revlog's DAG is emitted. If you list
2030 If you pass a revlog index, the revlog's DAG is emitted. If you list
2030 revision numbers, they get labeled in the output as rN.
2031 revision numbers, they get labeled in the output as rN.
2031
2032
2032 Otherwise, the changelog DAG of the current repo is emitted.
2033 Otherwise, the changelog DAG of the current repo is emitted.
2033 """
2034 """
2034 spaces = opts.get('spaces')
2035 spaces = opts.get('spaces')
2035 dots = opts.get('dots')
2036 dots = opts.get('dots')
2036 if file_:
2037 if file_:
2037 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2038 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2038 revs = set((int(r) for r in revs))
2039 revs = set((int(r) for r in revs))
2039 def events():
2040 def events():
2040 for r in rlog:
2041 for r in rlog:
2041 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2042 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2042 if p != -1))
2043 if p != -1))
2043 if r in revs:
2044 if r in revs:
2044 yield 'l', (r, "r%i" % r)
2045 yield 'l', (r, "r%i" % r)
2045 elif repo:
2046 elif repo:
2046 cl = repo.changelog
2047 cl = repo.changelog
2047 tags = opts.get('tags')
2048 tags = opts.get('tags')
2048 branches = opts.get('branches')
2049 branches = opts.get('branches')
2049 if tags:
2050 if tags:
2050 labels = {}
2051 labels = {}
2051 for l, n in repo.tags().items():
2052 for l, n in repo.tags().items():
2052 labels.setdefault(cl.rev(n), []).append(l)
2053 labels.setdefault(cl.rev(n), []).append(l)
2053 def events():
2054 def events():
2054 b = "default"
2055 b = "default"
2055 for r in cl:
2056 for r in cl:
2056 if branches:
2057 if branches:
2057 newb = cl.read(cl.node(r))[5]['branch']
2058 newb = cl.read(cl.node(r))[5]['branch']
2058 if newb != b:
2059 if newb != b:
2059 yield 'a', newb
2060 yield 'a', newb
2060 b = newb
2061 b = newb
2061 yield 'n', (r, list(p for p in cl.parentrevs(r)
2062 yield 'n', (r, list(p for p in cl.parentrevs(r)
2062 if p != -1))
2063 if p != -1))
2063 if tags:
2064 if tags:
2064 ls = labels.get(r)
2065 ls = labels.get(r)
2065 if ls:
2066 if ls:
2066 for l in ls:
2067 for l in ls:
2067 yield 'l', (r, l)
2068 yield 'l', (r, l)
2068 else:
2069 else:
2069 raise util.Abort(_('need repo for changelog dag'))
2070 raise util.Abort(_('need repo for changelog dag'))
2070
2071
2071 for line in dagparser.dagtextlines(events(),
2072 for line in dagparser.dagtextlines(events(),
2072 addspaces=spaces,
2073 addspaces=spaces,
2073 wraplabels=True,
2074 wraplabels=True,
2074 wrapannotations=True,
2075 wrapannotations=True,
2075 wrapnonlinear=dots,
2076 wrapnonlinear=dots,
2076 usedots=dots,
2077 usedots=dots,
2077 maxlinewidth=70):
2078 maxlinewidth=70):
2078 ui.write(line)
2079 ui.write(line)
2079 ui.write("\n")
2080 ui.write("\n")
2080
2081
2081 @command('debugdata',
2082 @command('debugdata',
2082 [('c', 'changelog', False, _('open changelog')),
2083 [('c', 'changelog', False, _('open changelog')),
2083 ('m', 'manifest', False, _('open manifest')),
2084 ('m', 'manifest', False, _('open manifest')),
2084 ('', 'dir', False, _('open directory manifest'))],
2085 ('', 'dir', False, _('open directory manifest'))],
2085 _('-c|-m|FILE REV'))
2086 _('-c|-m|FILE REV'))
2086 def debugdata(ui, repo, file_, rev=None, **opts):
2087 def debugdata(ui, repo, file_, rev=None, **opts):
2087 """dump the contents of a data file revision"""
2088 """dump the contents of a data file revision"""
2088 if opts.get('changelog') or opts.get('manifest'):
2089 if opts.get('changelog') or opts.get('manifest'):
2089 file_, rev = None, file_
2090 file_, rev = None, file_
2090 elif rev is None:
2091 elif rev is None:
2091 raise error.CommandError('debugdata', _('invalid arguments'))
2092 raise error.CommandError('debugdata', _('invalid arguments'))
2092 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2093 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2093 try:
2094 try:
2094 ui.write(r.revision(r.lookup(rev)))
2095 ui.write(r.revision(r.lookup(rev)))
2095 except KeyError:
2096 except KeyError:
2096 raise util.Abort(_('invalid revision identifier %s') % rev)
2097 raise util.Abort(_('invalid revision identifier %s') % rev)
2097
2098
2098 @command('debugdate',
2099 @command('debugdate',
2099 [('e', 'extended', None, _('try extended date formats'))],
2100 [('e', 'extended', None, _('try extended date formats'))],
2100 _('[-e] DATE [RANGE]'),
2101 _('[-e] DATE [RANGE]'),
2101 norepo=True, optionalrepo=True)
2102 norepo=True, optionalrepo=True)
2102 def debugdate(ui, date, range=None, **opts):
2103 def debugdate(ui, date, range=None, **opts):
2103 """parse and display a date"""
2104 """parse and display a date"""
2104 if opts["extended"]:
2105 if opts["extended"]:
2105 d = util.parsedate(date, util.extendeddateformats)
2106 d = util.parsedate(date, util.extendeddateformats)
2106 else:
2107 else:
2107 d = util.parsedate(date)
2108 d = util.parsedate(date)
2108 ui.write(("internal: %s %s\n") % d)
2109 ui.write(("internal: %s %s\n") % d)
2109 ui.write(("standard: %s\n") % util.datestr(d))
2110 ui.write(("standard: %s\n") % util.datestr(d))
2110 if range:
2111 if range:
2111 m = util.matchdate(range)
2112 m = util.matchdate(range)
2112 ui.write(("match: %s\n") % m(d[0]))
2113 ui.write(("match: %s\n") % m(d[0]))
2113
2114
2114 @command('debugdiscovery',
2115 @command('debugdiscovery',
2115 [('', 'old', None, _('use old-style discovery')),
2116 [('', 'old', None, _('use old-style discovery')),
2116 ('', 'nonheads', None,
2117 ('', 'nonheads', None,
2117 _('use old-style discovery with non-heads included')),
2118 _('use old-style discovery with non-heads included')),
2118 ] + remoteopts,
2119 ] + remoteopts,
2119 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2120 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2120 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2121 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2121 """runs the changeset discovery protocol in isolation"""
2122 """runs the changeset discovery protocol in isolation"""
2122 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2123 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2123 opts.get('branch'))
2124 opts.get('branch'))
2124 remote = hg.peer(repo, opts, remoteurl)
2125 remote = hg.peer(repo, opts, remoteurl)
2125 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2126 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2126
2127
2127 # make sure tests are repeatable
2128 # make sure tests are repeatable
2128 random.seed(12323)
2129 random.seed(12323)
2129
2130
2130 def doit(localheads, remoteheads, remote=remote):
2131 def doit(localheads, remoteheads, remote=remote):
2131 if opts.get('old'):
2132 if opts.get('old'):
2132 if localheads:
2133 if localheads:
2133 raise util.Abort('cannot use localheads with old style '
2134 raise util.Abort('cannot use localheads with old style '
2134 'discovery')
2135 'discovery')
2135 if not util.safehasattr(remote, 'branches'):
2136 if not util.safehasattr(remote, 'branches'):
2136 # enable in-client legacy support
2137 # enable in-client legacy support
2137 remote = localrepo.locallegacypeer(remote.local())
2138 remote = localrepo.locallegacypeer(remote.local())
2138 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2139 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2139 force=True)
2140 force=True)
2140 common = set(common)
2141 common = set(common)
2141 if not opts.get('nonheads'):
2142 if not opts.get('nonheads'):
2142 ui.write(("unpruned common: %s\n") %
2143 ui.write(("unpruned common: %s\n") %
2143 " ".join(sorted(short(n) for n in common)))
2144 " ".join(sorted(short(n) for n in common)))
2144 dag = dagutil.revlogdag(repo.changelog)
2145 dag = dagutil.revlogdag(repo.changelog)
2145 all = dag.ancestorset(dag.internalizeall(common))
2146 all = dag.ancestorset(dag.internalizeall(common))
2146 common = dag.externalizeall(dag.headsetofconnecteds(all))
2147 common = dag.externalizeall(dag.headsetofconnecteds(all))
2147 else:
2148 else:
2148 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2149 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2149 common = set(common)
2150 common = set(common)
2150 rheads = set(hds)
2151 rheads = set(hds)
2151 lheads = set(repo.heads())
2152 lheads = set(repo.heads())
2152 ui.write(("common heads: %s\n") %
2153 ui.write(("common heads: %s\n") %
2153 " ".join(sorted(short(n) for n in common)))
2154 " ".join(sorted(short(n) for n in common)))
2154 if lheads <= common:
2155 if lheads <= common:
2155 ui.write(("local is subset\n"))
2156 ui.write(("local is subset\n"))
2156 elif rheads <= common:
2157 elif rheads <= common:
2157 ui.write(("remote is subset\n"))
2158 ui.write(("remote is subset\n"))
2158
2159
2159 serverlogs = opts.get('serverlog')
2160 serverlogs = opts.get('serverlog')
2160 if serverlogs:
2161 if serverlogs:
2161 for filename in serverlogs:
2162 for filename in serverlogs:
2162 logfile = open(filename, 'r')
2163 logfile = open(filename, 'r')
2163 try:
2164 try:
2164 line = logfile.readline()
2165 line = logfile.readline()
2165 while line:
2166 while line:
2166 parts = line.strip().split(';')
2167 parts = line.strip().split(';')
2167 op = parts[1]
2168 op = parts[1]
2168 if op == 'cg':
2169 if op == 'cg':
2169 pass
2170 pass
2170 elif op == 'cgss':
2171 elif op == 'cgss':
2171 doit(parts[2].split(' '), parts[3].split(' '))
2172 doit(parts[2].split(' '), parts[3].split(' '))
2172 elif op == 'unb':
2173 elif op == 'unb':
2173 doit(parts[3].split(' '), parts[2].split(' '))
2174 doit(parts[3].split(' '), parts[2].split(' '))
2174 line = logfile.readline()
2175 line = logfile.readline()
2175 finally:
2176 finally:
2176 logfile.close()
2177 logfile.close()
2177
2178
2178 else:
2179 else:
2179 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2180 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2180 opts.get('remote_head'))
2181 opts.get('remote_head'))
2181 localrevs = opts.get('local_head')
2182 localrevs = opts.get('local_head')
2182 doit(localrevs, remoterevs)
2183 doit(localrevs, remoterevs)
2183
2184
2184 @command('debugextensions', formatteropts, [], norepo=True)
2185 @command('debugextensions', formatteropts, [], norepo=True)
2185 def debugextensions(ui, **opts):
2186 def debugextensions(ui, **opts):
2186 '''show information about active extensions'''
2187 '''show information about active extensions'''
2187 exts = extensions.extensions(ui)
2188 exts = extensions.extensions(ui)
2188 fm = ui.formatter('debugextensions', opts)
2189 fm = ui.formatter('debugextensions', opts)
2189 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2190 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2190 extsource = extmod.__file__
2191 extsource = extmod.__file__
2191 exttestedwith = getattr(extmod, 'testedwith', None)
2192 exttestedwith = getattr(extmod, 'testedwith', None)
2192 if exttestedwith is not None:
2193 if exttestedwith is not None:
2193 exttestedwith = exttestedwith.split()
2194 exttestedwith = exttestedwith.split()
2194 extbuglink = getattr(extmod, 'buglink', None)
2195 extbuglink = getattr(extmod, 'buglink', None)
2195
2196
2196 fm.startitem()
2197 fm.startitem()
2197
2198
2198 if ui.quiet or ui.verbose:
2199 if ui.quiet or ui.verbose:
2199 fm.write('name', '%s\n', extname)
2200 fm.write('name', '%s\n', extname)
2200 else:
2201 else:
2201 fm.write('name', '%s', extname)
2202 fm.write('name', '%s', extname)
2202 if not exttestedwith:
2203 if not exttestedwith:
2203 fm.plain(_(' (untested!)\n'))
2204 fm.plain(_(' (untested!)\n'))
2204 else:
2205 else:
2205 if exttestedwith == ['internal'] or \
2206 if exttestedwith == ['internal'] or \
2206 util.version() in exttestedwith:
2207 util.version() in exttestedwith:
2207 fm.plain('\n')
2208 fm.plain('\n')
2208 else:
2209 else:
2209 lasttestedversion = exttestedwith[-1]
2210 lasttestedversion = exttestedwith[-1]
2210 fm.plain(' (%s!)\n' % lasttestedversion)
2211 fm.plain(' (%s!)\n' % lasttestedversion)
2211
2212
2212 fm.condwrite(ui.verbose and extsource, 'source',
2213 fm.condwrite(ui.verbose and extsource, 'source',
2213 _(' location: %s\n'), extsource or "")
2214 _(' location: %s\n'), extsource or "")
2214
2215
2215 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2216 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2216 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2217 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2217
2218
2218 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2219 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2219 _(' bug reporting: %s\n'), extbuglink or "")
2220 _(' bug reporting: %s\n'), extbuglink or "")
2220
2221
2221 fm.end()
2222 fm.end()
2222
2223
2223 @command('debugfileset',
2224 @command('debugfileset',
2224 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2225 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2225 _('[-r REV] FILESPEC'))
2226 _('[-r REV] FILESPEC'))
2226 def debugfileset(ui, repo, expr, **opts):
2227 def debugfileset(ui, repo, expr, **opts):
2227 '''parse and apply a fileset specification'''
2228 '''parse and apply a fileset specification'''
2228 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2229 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2229 if ui.verbose:
2230 if ui.verbose:
2230 tree = fileset.parse(expr)
2231 tree = fileset.parse(expr)
2231 ui.note(fileset.prettyformat(tree), "\n")
2232 ui.note(fileset.prettyformat(tree), "\n")
2232
2233
2233 for f in ctx.getfileset(expr):
2234 for f in ctx.getfileset(expr):
2234 ui.write("%s\n" % f)
2235 ui.write("%s\n" % f)
2235
2236
2236 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2237 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2237 def debugfsinfo(ui, path="."):
2238 def debugfsinfo(ui, path="."):
2238 """show information detected about current filesystem"""
2239 """show information detected about current filesystem"""
2239 util.writefile('.debugfsinfo', '')
2240 util.writefile('.debugfsinfo', '')
2240 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2241 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2241 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2242 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2242 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2243 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2243 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2244 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2244 and 'yes' or 'no'))
2245 and 'yes' or 'no'))
2245 os.unlink('.debugfsinfo')
2246 os.unlink('.debugfsinfo')
2246
2247
2247 @command('debuggetbundle',
2248 @command('debuggetbundle',
2248 [('H', 'head', [], _('id of head node'), _('ID')),
2249 [('H', 'head', [], _('id of head node'), _('ID')),
2249 ('C', 'common', [], _('id of common node'), _('ID')),
2250 ('C', 'common', [], _('id of common node'), _('ID')),
2250 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2251 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2251 _('REPO FILE [-H|-C ID]...'),
2252 _('REPO FILE [-H|-C ID]...'),
2252 norepo=True)
2253 norepo=True)
2253 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2254 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2254 """retrieves a bundle from a repo
2255 """retrieves a bundle from a repo
2255
2256
2256 Every ID must be a full-length hex node id string. Saves the bundle to the
2257 Every ID must be a full-length hex node id string. Saves the bundle to the
2257 given file.
2258 given file.
2258 """
2259 """
2259 repo = hg.peer(ui, opts, repopath)
2260 repo = hg.peer(ui, opts, repopath)
2260 if not repo.capable('getbundle'):
2261 if not repo.capable('getbundle'):
2261 raise util.Abort("getbundle() not supported by target repository")
2262 raise util.Abort("getbundle() not supported by target repository")
2262 args = {}
2263 args = {}
2263 if common:
2264 if common:
2264 args['common'] = [bin(s) for s in common]
2265 args['common'] = [bin(s) for s in common]
2265 if head:
2266 if head:
2266 args['heads'] = [bin(s) for s in head]
2267 args['heads'] = [bin(s) for s in head]
2267 # TODO: get desired bundlecaps from command line.
2268 # TODO: get desired bundlecaps from command line.
2268 args['bundlecaps'] = None
2269 args['bundlecaps'] = None
2269 bundle = repo.getbundle('debug', **args)
2270 bundle = repo.getbundle('debug', **args)
2270
2271
2271 bundletype = opts.get('type', 'bzip2').lower()
2272 bundletype = opts.get('type', 'bzip2').lower()
2272 btypes = {'none': 'HG10UN',
2273 btypes = {'none': 'HG10UN',
2273 'bzip2': 'HG10BZ',
2274 'bzip2': 'HG10BZ',
2274 'gzip': 'HG10GZ',
2275 'gzip': 'HG10GZ',
2275 'bundle2': 'HG20'}
2276 'bundle2': 'HG20'}
2276 bundletype = btypes.get(bundletype)
2277 bundletype = btypes.get(bundletype)
2277 if bundletype not in changegroup.bundletypes:
2278 if bundletype not in changegroup.bundletypes:
2278 raise util.Abort(_('unknown bundle type specified with --type'))
2279 raise util.Abort(_('unknown bundle type specified with --type'))
2279 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2280 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2280
2281
2281 @command('debugignore', [], '')
2282 @command('debugignore', [], '')
2282 def debugignore(ui, repo, *values, **opts):
2283 def debugignore(ui, repo, *values, **opts):
2283 """display the combined ignore pattern"""
2284 """display the combined ignore pattern"""
2284 ignore = repo.dirstate._ignore
2285 ignore = repo.dirstate._ignore
2285 includepat = getattr(ignore, 'includepat', None)
2286 includepat = getattr(ignore, 'includepat', None)
2286 if includepat is not None:
2287 if includepat is not None:
2287 ui.write("%s\n" % includepat)
2288 ui.write("%s\n" % includepat)
2288 else:
2289 else:
2289 raise util.Abort(_("no ignore patterns found"))
2290 raise util.Abort(_("no ignore patterns found"))
2290
2291
2291 @command('debugindex',
2292 @command('debugindex',
2292 [('c', 'changelog', False, _('open changelog')),
2293 [('c', 'changelog', False, _('open changelog')),
2293 ('m', 'manifest', False, _('open manifest')),
2294 ('m', 'manifest', False, _('open manifest')),
2294 ('', 'dir', False, _('open directory manifest')),
2295 ('', 'dir', False, _('open directory manifest')),
2295 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2296 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2296 _('[-f FORMAT] -c|-m|FILE'),
2297 _('[-f FORMAT] -c|-m|FILE'),
2297 optionalrepo=True)
2298 optionalrepo=True)
2298 def debugindex(ui, repo, file_=None, **opts):
2299 def debugindex(ui, repo, file_=None, **opts):
2299 """dump the contents of an index file"""
2300 """dump the contents of an index file"""
2300 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2301 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2301 format = opts.get('format', 0)
2302 format = opts.get('format', 0)
2302 if format not in (0, 1):
2303 if format not in (0, 1):
2303 raise util.Abort(_("unknown format %d") % format)
2304 raise util.Abort(_("unknown format %d") % format)
2304
2305
2305 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2306 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2306 if generaldelta:
2307 if generaldelta:
2307 basehdr = ' delta'
2308 basehdr = ' delta'
2308 else:
2309 else:
2309 basehdr = ' base'
2310 basehdr = ' base'
2310
2311
2311 if ui.debugflag:
2312 if ui.debugflag:
2312 shortfn = hex
2313 shortfn = hex
2313 else:
2314 else:
2314 shortfn = short
2315 shortfn = short
2315
2316
2316 # There might not be anything in r, so have a sane default
2317 # There might not be anything in r, so have a sane default
2317 idlen = 12
2318 idlen = 12
2318 for i in r:
2319 for i in r:
2319 idlen = len(shortfn(r.node(i)))
2320 idlen = len(shortfn(r.node(i)))
2320 break
2321 break
2321
2322
2322 if format == 0:
2323 if format == 0:
2323 ui.write(" rev offset length " + basehdr + " linkrev"
2324 ui.write(" rev offset length " + basehdr + " linkrev"
2324 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2325 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2325 elif format == 1:
2326 elif format == 1:
2326 ui.write(" rev flag offset length"
2327 ui.write(" rev flag offset length"
2327 " size " + basehdr + " link p1 p2"
2328 " size " + basehdr + " link p1 p2"
2328 " %s\n" % "nodeid".rjust(idlen))
2329 " %s\n" % "nodeid".rjust(idlen))
2329
2330
2330 for i in r:
2331 for i in r:
2331 node = r.node(i)
2332 node = r.node(i)
2332 if generaldelta:
2333 if generaldelta:
2333 base = r.deltaparent(i)
2334 base = r.deltaparent(i)
2334 else:
2335 else:
2335 base = r.chainbase(i)
2336 base = r.chainbase(i)
2336 if format == 0:
2337 if format == 0:
2337 try:
2338 try:
2338 pp = r.parents(node)
2339 pp = r.parents(node)
2339 except Exception:
2340 except Exception:
2340 pp = [nullid, nullid]
2341 pp = [nullid, nullid]
2341 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2342 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2342 i, r.start(i), r.length(i), base, r.linkrev(i),
2343 i, r.start(i), r.length(i), base, r.linkrev(i),
2343 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2344 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2344 elif format == 1:
2345 elif format == 1:
2345 pr = r.parentrevs(i)
2346 pr = r.parentrevs(i)
2346 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2347 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2347 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2348 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2348 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2349 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2349
2350
2350 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2351 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2351 def debugindexdot(ui, repo, file_):
2352 def debugindexdot(ui, repo, file_):
2352 """dump an index DAG as a graphviz dot file"""
2353 """dump an index DAG as a graphviz dot file"""
2353 r = None
2354 r = None
2354 if repo:
2355 if repo:
2355 filelog = repo.file(file_)
2356 filelog = repo.file(file_)
2356 if len(filelog):
2357 if len(filelog):
2357 r = filelog
2358 r = filelog
2358 if not r:
2359 if not r:
2359 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2360 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2360 ui.write(("digraph G {\n"))
2361 ui.write(("digraph G {\n"))
2361 for i in r:
2362 for i in r:
2362 node = r.node(i)
2363 node = r.node(i)
2363 pp = r.parents(node)
2364 pp = r.parents(node)
2364 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2365 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2365 if pp[1] != nullid:
2366 if pp[1] != nullid:
2366 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2367 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2367 ui.write("}\n")
2368 ui.write("}\n")
2368
2369
2369 @command('debuginstall', [], '', norepo=True)
2370 @command('debuginstall', [], '', norepo=True)
2370 def debuginstall(ui):
2371 def debuginstall(ui):
2371 '''test Mercurial installation
2372 '''test Mercurial installation
2372
2373
2373 Returns 0 on success.
2374 Returns 0 on success.
2374 '''
2375 '''
2375
2376
2376 def writetemp(contents):
2377 def writetemp(contents):
2377 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2378 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2378 f = os.fdopen(fd, "wb")
2379 f = os.fdopen(fd, "wb")
2379 f.write(contents)
2380 f.write(contents)
2380 f.close()
2381 f.close()
2381 return name
2382 return name
2382
2383
2383 problems = 0
2384 problems = 0
2384
2385
2385 # encoding
2386 # encoding
2386 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2387 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2387 try:
2388 try:
2388 encoding.fromlocal("test")
2389 encoding.fromlocal("test")
2389 except util.Abort as inst:
2390 except util.Abort as inst:
2390 ui.write(" %s\n" % inst)
2391 ui.write(" %s\n" % inst)
2391 ui.write(_(" (check that your locale is properly set)\n"))
2392 ui.write(_(" (check that your locale is properly set)\n"))
2392 problems += 1
2393 problems += 1
2393
2394
2394 # Python
2395 # Python
2395 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2396 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2396 ui.status(_("checking Python version (%s)\n")
2397 ui.status(_("checking Python version (%s)\n")
2397 % ("%s.%s.%s" % sys.version_info[:3]))
2398 % ("%s.%s.%s" % sys.version_info[:3]))
2398 ui.status(_("checking Python lib (%s)...\n")
2399 ui.status(_("checking Python lib (%s)...\n")
2399 % os.path.dirname(os.__file__))
2400 % os.path.dirname(os.__file__))
2400
2401
2401 # compiled modules
2402 # compiled modules
2402 ui.status(_("checking installed modules (%s)...\n")
2403 ui.status(_("checking installed modules (%s)...\n")
2403 % os.path.dirname(__file__))
2404 % os.path.dirname(__file__))
2404 try:
2405 try:
2405 import bdiff, mpatch, base85, osutil
2406 import bdiff, mpatch, base85, osutil
2406 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2407 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2407 except Exception as inst:
2408 except Exception as inst:
2408 ui.write(" %s\n" % inst)
2409 ui.write(" %s\n" % inst)
2409 ui.write(_(" One or more extensions could not be found"))
2410 ui.write(_(" One or more extensions could not be found"))
2410 ui.write(_(" (check that you compiled the extensions)\n"))
2411 ui.write(_(" (check that you compiled the extensions)\n"))
2411 problems += 1
2412 problems += 1
2412
2413
2413 # templates
2414 # templates
2414 import templater
2415 import templater
2415 p = templater.templatepaths()
2416 p = templater.templatepaths()
2416 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2417 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2417 if p:
2418 if p:
2418 m = templater.templatepath("map-cmdline.default")
2419 m = templater.templatepath("map-cmdline.default")
2419 if m:
2420 if m:
2420 # template found, check if it is working
2421 # template found, check if it is working
2421 try:
2422 try:
2422 templater.templater(m)
2423 templater.templater(m)
2423 except Exception as inst:
2424 except Exception as inst:
2424 ui.write(" %s\n" % inst)
2425 ui.write(" %s\n" % inst)
2425 p = None
2426 p = None
2426 else:
2427 else:
2427 ui.write(_(" template 'default' not found\n"))
2428 ui.write(_(" template 'default' not found\n"))
2428 p = None
2429 p = None
2429 else:
2430 else:
2430 ui.write(_(" no template directories found\n"))
2431 ui.write(_(" no template directories found\n"))
2431 if not p:
2432 if not p:
2432 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2433 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2433 problems += 1
2434 problems += 1
2434
2435
2435 # editor
2436 # editor
2436 ui.status(_("checking commit editor...\n"))
2437 ui.status(_("checking commit editor...\n"))
2437 editor = ui.geteditor()
2438 editor = ui.geteditor()
2438 editor = util.expandpath(editor)
2439 editor = util.expandpath(editor)
2439 cmdpath = util.findexe(shlex.split(editor)[0])
2440 cmdpath = util.findexe(shlex.split(editor)[0])
2440 if not cmdpath:
2441 if not cmdpath:
2441 if editor == 'vi':
2442 if editor == 'vi':
2442 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2443 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2443 ui.write(_(" (specify a commit editor in your configuration"
2444 ui.write(_(" (specify a commit editor in your configuration"
2444 " file)\n"))
2445 " file)\n"))
2445 else:
2446 else:
2446 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2447 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2447 ui.write(_(" (specify a commit editor in your configuration"
2448 ui.write(_(" (specify a commit editor in your configuration"
2448 " file)\n"))
2449 " file)\n"))
2449 problems += 1
2450 problems += 1
2450
2451
2451 # check username
2452 # check username
2452 ui.status(_("checking username...\n"))
2453 ui.status(_("checking username...\n"))
2453 try:
2454 try:
2454 ui.username()
2455 ui.username()
2455 except util.Abort as e:
2456 except util.Abort as e:
2456 ui.write(" %s\n" % e)
2457 ui.write(" %s\n" % e)
2457 ui.write(_(" (specify a username in your configuration file)\n"))
2458 ui.write(_(" (specify a username in your configuration file)\n"))
2458 problems += 1
2459 problems += 1
2459
2460
2460 if not problems:
2461 if not problems:
2461 ui.status(_("no problems detected\n"))
2462 ui.status(_("no problems detected\n"))
2462 else:
2463 else:
2463 ui.write(_("%s problems detected,"
2464 ui.write(_("%s problems detected,"
2464 " please check your install!\n") % problems)
2465 " please check your install!\n") % problems)
2465
2466
2466 return problems
2467 return problems
2467
2468
2468 @command('debugknown', [], _('REPO ID...'), norepo=True)
2469 @command('debugknown', [], _('REPO ID...'), norepo=True)
2469 def debugknown(ui, repopath, *ids, **opts):
2470 def debugknown(ui, repopath, *ids, **opts):
2470 """test whether node ids are known to a repo
2471 """test whether node ids are known to a repo
2471
2472
2472 Every ID must be a full-length hex node id string. Returns a list of 0s
2473 Every ID must be a full-length hex node id string. Returns a list of 0s
2473 and 1s indicating unknown/known.
2474 and 1s indicating unknown/known.
2474 """
2475 """
2475 repo = hg.peer(ui, opts, repopath)
2476 repo = hg.peer(ui, opts, repopath)
2476 if not repo.capable('known'):
2477 if not repo.capable('known'):
2477 raise util.Abort("known() not supported by target repository")
2478 raise util.Abort("known() not supported by target repository")
2478 flags = repo.known([bin(s) for s in ids])
2479 flags = repo.known([bin(s) for s in ids])
2479 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2480 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2480
2481
2481 @command('debuglabelcomplete', [], _('LABEL...'))
2482 @command('debuglabelcomplete', [], _('LABEL...'))
2482 def debuglabelcomplete(ui, repo, *args):
2483 def debuglabelcomplete(ui, repo, *args):
2483 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2484 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2484 debugnamecomplete(ui, repo, *args)
2485 debugnamecomplete(ui, repo, *args)
2485
2486
2486 @command('debugmergestate', [], '')
2487 @command('debugmergestate', [], '')
2487 def debugmergestate(ui, repo, *args):
2488 def debugmergestate(ui, repo, *args):
2488 """print merge state
2489 """print merge state
2489
2490
2490 Use --verbose to print out information about whether v1 or v2 merge state
2491 Use --verbose to print out information about whether v1 or v2 merge state
2491 was chosen."""
2492 was chosen."""
2492 def printrecords(version):
2493 def printrecords(version):
2493 ui.write(('* version %s records\n') % version)
2494 ui.write(('* version %s records\n') % version)
2494 if version == 1:
2495 if version == 1:
2495 records = v1records
2496 records = v1records
2496 else:
2497 else:
2497 records = v2records
2498 records = v2records
2498
2499
2499 for rtype, record in records:
2500 for rtype, record in records:
2500 # pretty print some record types
2501 # pretty print some record types
2501 if rtype == 'L':
2502 if rtype == 'L':
2502 ui.write(('local: %s\n') % record)
2503 ui.write(('local: %s\n') % record)
2503 elif rtype == 'O':
2504 elif rtype == 'O':
2504 ui.write(('other: %s\n') % record)
2505 ui.write(('other: %s\n') % record)
2505 elif rtype == 'F':
2506 elif rtype == 'F':
2506 r = record.split('\0')
2507 r = record.split('\0')
2507 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2508 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2508 if version == 1:
2509 if version == 1:
2509 onode = 'not stored in v1 format'
2510 onode = 'not stored in v1 format'
2510 flags = r[7]
2511 flags = r[7]
2511 else:
2512 else:
2512 onode, flags = r[7:9]
2513 onode, flags = r[7:9]
2513 ui.write(('file: %s (state "%s", hash %s)\n')
2514 ui.write(('file: %s (state "%s", hash %s)\n')
2514 % (f, state, hash))
2515 % (f, state, hash))
2515 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2516 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2516 ui.write((' ancestor path: %s (node %s)\n') % (afile, anode))
2517 ui.write((' ancestor path: %s (node %s)\n') % (afile, anode))
2517 ui.write((' other path: %s (node %s)\n') % (ofile, onode))
2518 ui.write((' other path: %s (node %s)\n') % (ofile, onode))
2518 else:
2519 else:
2519 ui.write(('unrecognized entry: %s\t%s\n')
2520 ui.write(('unrecognized entry: %s\t%s\n')
2520 % (rtype, record.replace('\0', '\t')))
2521 % (rtype, record.replace('\0', '\t')))
2521
2522
2522 ms = mergemod.mergestate(repo)
2523 ms = mergemod.mergestate(repo)
2523
2524
2524 # sort so that reasonable information is on top
2525 # sort so that reasonable information is on top
2525 v1records = ms._readrecordsv1()
2526 v1records = ms._readrecordsv1()
2526 v2records = ms._readrecordsv2()
2527 v2records = ms._readrecordsv2()
2527 order = 'LO'
2528 order = 'LO'
2528 def key(r):
2529 def key(r):
2529 idx = order.find(r[0])
2530 idx = order.find(r[0])
2530 if idx == -1:
2531 if idx == -1:
2531 return (1, r[1])
2532 return (1, r[1])
2532 else:
2533 else:
2533 return (0, idx)
2534 return (0, idx)
2534 v1records.sort(key=key)
2535 v1records.sort(key=key)
2535 v2records.sort(key=key)
2536 v2records.sort(key=key)
2536
2537
2537 if not v1records and not v2records:
2538 if not v1records and not v2records:
2538 ui.write(('no merge state found\n'))
2539 ui.write(('no merge state found\n'))
2539 elif not v2records:
2540 elif not v2records:
2540 ui.note(('no version 2 merge state\n'))
2541 ui.note(('no version 2 merge state\n'))
2541 printrecords(1)
2542 printrecords(1)
2542 elif ms._v1v2match(v1records, v2records):
2543 elif ms._v1v2match(v1records, v2records):
2543 ui.note(('v1 and v2 states match: using v2\n'))
2544 ui.note(('v1 and v2 states match: using v2\n'))
2544 printrecords(2)
2545 printrecords(2)
2545 else:
2546 else:
2546 ui.note(('v1 and v2 states mismatch: using v1\n'))
2547 ui.note(('v1 and v2 states mismatch: using v1\n'))
2547 printrecords(1)
2548 printrecords(1)
2548 if ui.verbose:
2549 if ui.verbose:
2549 printrecords(2)
2550 printrecords(2)
2550
2551
2551 @command('debugnamecomplete', [], _('NAME...'))
2552 @command('debugnamecomplete', [], _('NAME...'))
2552 def debugnamecomplete(ui, repo, *args):
2553 def debugnamecomplete(ui, repo, *args):
2553 '''complete "names" - tags, open branch names, bookmark names'''
2554 '''complete "names" - tags, open branch names, bookmark names'''
2554
2555
2555 names = set()
2556 names = set()
2556 # since we previously only listed open branches, we will handle that
2557 # since we previously only listed open branches, we will handle that
2557 # specially (after this for loop)
2558 # specially (after this for loop)
2558 for name, ns in repo.names.iteritems():
2559 for name, ns in repo.names.iteritems():
2559 if name != 'branches':
2560 if name != 'branches':
2560 names.update(ns.listnames(repo))
2561 names.update(ns.listnames(repo))
2561 names.update(tag for (tag, heads, tip, closed)
2562 names.update(tag for (tag, heads, tip, closed)
2562 in repo.branchmap().iterbranches() if not closed)
2563 in repo.branchmap().iterbranches() if not closed)
2563 completions = set()
2564 completions = set()
2564 if not args:
2565 if not args:
2565 args = ['']
2566 args = ['']
2566 for a in args:
2567 for a in args:
2567 completions.update(n for n in names if n.startswith(a))
2568 completions.update(n for n in names if n.startswith(a))
2568 ui.write('\n'.join(sorted(completions)))
2569 ui.write('\n'.join(sorted(completions)))
2569 ui.write('\n')
2570 ui.write('\n')
2570
2571
2571 @command('debuglocks',
2572 @command('debuglocks',
2572 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2573 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2573 ('W', 'force-wlock', None,
2574 ('W', 'force-wlock', None,
2574 _('free the working state lock (DANGEROUS)'))],
2575 _('free the working state lock (DANGEROUS)'))],
2575 _('[OPTION]...'))
2576 _('[OPTION]...'))
2576 def debuglocks(ui, repo, **opts):
2577 def debuglocks(ui, repo, **opts):
2577 """show or modify state of locks
2578 """show or modify state of locks
2578
2579
2579 By default, this command will show which locks are held. This
2580 By default, this command will show which locks are held. This
2580 includes the user and process holding the lock, the amount of time
2581 includes the user and process holding the lock, the amount of time
2581 the lock has been held, and the machine name where the process is
2582 the lock has been held, and the machine name where the process is
2582 running if it's not local.
2583 running if it's not local.
2583
2584
2584 Locks protect the integrity of Mercurial's data, so should be
2585 Locks protect the integrity of Mercurial's data, so should be
2585 treated with care. System crashes or other interruptions may cause
2586 treated with care. System crashes or other interruptions may cause
2586 locks to not be properly released, though Mercurial will usually
2587 locks to not be properly released, though Mercurial will usually
2587 detect and remove such stale locks automatically.
2588 detect and remove such stale locks automatically.
2588
2589
2589 However, detecting stale locks may not always be possible (for
2590 However, detecting stale locks may not always be possible (for
2590 instance, on a shared filesystem). Removing locks may also be
2591 instance, on a shared filesystem). Removing locks may also be
2591 blocked by filesystem permissions.
2592 blocked by filesystem permissions.
2592
2593
2593 Returns 0 if no locks are held.
2594 Returns 0 if no locks are held.
2594
2595
2595 """
2596 """
2596
2597
2597 if opts.get('force_lock'):
2598 if opts.get('force_lock'):
2598 repo.svfs.unlink('lock')
2599 repo.svfs.unlink('lock')
2599 if opts.get('force_wlock'):
2600 if opts.get('force_wlock'):
2600 repo.vfs.unlink('wlock')
2601 repo.vfs.unlink('wlock')
2601 if opts.get('force_lock') or opts.get('force_lock'):
2602 if opts.get('force_lock') or opts.get('force_lock'):
2602 return 0
2603 return 0
2603
2604
2604 now = time.time()
2605 now = time.time()
2605 held = 0
2606 held = 0
2606
2607
2607 def report(vfs, name, method):
2608 def report(vfs, name, method):
2608 # this causes stale locks to get reaped for more accurate reporting
2609 # this causes stale locks to get reaped for more accurate reporting
2609 try:
2610 try:
2610 l = method(False)
2611 l = method(False)
2611 except error.LockHeld:
2612 except error.LockHeld:
2612 l = None
2613 l = None
2613
2614
2614 if l:
2615 if l:
2615 l.release()
2616 l.release()
2616 else:
2617 else:
2617 try:
2618 try:
2618 stat = vfs.lstat(name)
2619 stat = vfs.lstat(name)
2619 age = now - stat.st_mtime
2620 age = now - stat.st_mtime
2620 user = util.username(stat.st_uid)
2621 user = util.username(stat.st_uid)
2621 locker = vfs.readlock(name)
2622 locker = vfs.readlock(name)
2622 if ":" in locker:
2623 if ":" in locker:
2623 host, pid = locker.split(':')
2624 host, pid = locker.split(':')
2624 if host == socket.gethostname():
2625 if host == socket.gethostname():
2625 locker = 'user %s, process %s' % (user, pid)
2626 locker = 'user %s, process %s' % (user, pid)
2626 else:
2627 else:
2627 locker = 'user %s, process %s, host %s' \
2628 locker = 'user %s, process %s, host %s' \
2628 % (user, pid, host)
2629 % (user, pid, host)
2629 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2630 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2630 return 1
2631 return 1
2631 except OSError as e:
2632 except OSError as e:
2632 if e.errno != errno.ENOENT:
2633 if e.errno != errno.ENOENT:
2633 raise
2634 raise
2634
2635
2635 ui.write("%-6s free\n" % (name + ":"))
2636 ui.write("%-6s free\n" % (name + ":"))
2636 return 0
2637 return 0
2637
2638
2638 held += report(repo.svfs, "lock", repo.lock)
2639 held += report(repo.svfs, "lock", repo.lock)
2639 held += report(repo.vfs, "wlock", repo.wlock)
2640 held += report(repo.vfs, "wlock", repo.wlock)
2640
2641
2641 return held
2642 return held
2642
2643
2643 @command('debugobsolete',
2644 @command('debugobsolete',
2644 [('', 'flags', 0, _('markers flag')),
2645 [('', 'flags', 0, _('markers flag')),
2645 ('', 'record-parents', False,
2646 ('', 'record-parents', False,
2646 _('record parent information for the precursor')),
2647 _('record parent information for the precursor')),
2647 ('r', 'rev', [], _('display markers relevant to REV')),
2648 ('r', 'rev', [], _('display markers relevant to REV')),
2648 ] + commitopts2,
2649 ] + commitopts2,
2649 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2650 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2650 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2651 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2651 """create arbitrary obsolete marker
2652 """create arbitrary obsolete marker
2652
2653
2653 With no arguments, displays the list of obsolescence markers."""
2654 With no arguments, displays the list of obsolescence markers."""
2654
2655
2655 def parsenodeid(s):
2656 def parsenodeid(s):
2656 try:
2657 try:
2657 # We do not use revsingle/revrange functions here to accept
2658 # We do not use revsingle/revrange functions here to accept
2658 # arbitrary node identifiers, possibly not present in the
2659 # arbitrary node identifiers, possibly not present in the
2659 # local repository.
2660 # local repository.
2660 n = bin(s)
2661 n = bin(s)
2661 if len(n) != len(nullid):
2662 if len(n) != len(nullid):
2662 raise TypeError()
2663 raise TypeError()
2663 return n
2664 return n
2664 except TypeError:
2665 except TypeError:
2665 raise util.Abort('changeset references must be full hexadecimal '
2666 raise util.Abort('changeset references must be full hexadecimal '
2666 'node identifiers')
2667 'node identifiers')
2667
2668
2668 if precursor is not None:
2669 if precursor is not None:
2669 if opts['rev']:
2670 if opts['rev']:
2670 raise util.Abort('cannot select revision when creating marker')
2671 raise util.Abort('cannot select revision when creating marker')
2671 metadata = {}
2672 metadata = {}
2672 metadata['user'] = opts['user'] or ui.username()
2673 metadata['user'] = opts['user'] or ui.username()
2673 succs = tuple(parsenodeid(succ) for succ in successors)
2674 succs = tuple(parsenodeid(succ) for succ in successors)
2674 l = repo.lock()
2675 l = repo.lock()
2675 try:
2676 try:
2676 tr = repo.transaction('debugobsolete')
2677 tr = repo.transaction('debugobsolete')
2677 try:
2678 try:
2678 date = opts.get('date')
2679 date = opts.get('date')
2679 if date:
2680 if date:
2680 date = util.parsedate(date)
2681 date = util.parsedate(date)
2681 else:
2682 else:
2682 date = None
2683 date = None
2683 prec = parsenodeid(precursor)
2684 prec = parsenodeid(precursor)
2684 parents = None
2685 parents = None
2685 if opts['record_parents']:
2686 if opts['record_parents']:
2686 if prec not in repo.unfiltered():
2687 if prec not in repo.unfiltered():
2687 raise util.Abort('cannot used --record-parents on '
2688 raise util.Abort('cannot used --record-parents on '
2688 'unknown changesets')
2689 'unknown changesets')
2689 parents = repo.unfiltered()[prec].parents()
2690 parents = repo.unfiltered()[prec].parents()
2690 parents = tuple(p.node() for p in parents)
2691 parents = tuple(p.node() for p in parents)
2691 repo.obsstore.create(tr, prec, succs, opts['flags'],
2692 repo.obsstore.create(tr, prec, succs, opts['flags'],
2692 parents=parents, date=date,
2693 parents=parents, date=date,
2693 metadata=metadata)
2694 metadata=metadata)
2694 tr.close()
2695 tr.close()
2695 except ValueError as exc:
2696 except ValueError as exc:
2696 raise util.Abort(_('bad obsmarker input: %s') % exc)
2697 raise util.Abort(_('bad obsmarker input: %s') % exc)
2697 finally:
2698 finally:
2698 tr.release()
2699 tr.release()
2699 finally:
2700 finally:
2700 l.release()
2701 l.release()
2701 else:
2702 else:
2702 if opts['rev']:
2703 if opts['rev']:
2703 revs = scmutil.revrange(repo, opts['rev'])
2704 revs = scmutil.revrange(repo, opts['rev'])
2704 nodes = [repo[r].node() for r in revs]
2705 nodes = [repo[r].node() for r in revs]
2705 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2706 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2706 markers.sort(key=lambda x: x._data)
2707 markers.sort(key=lambda x: x._data)
2707 else:
2708 else:
2708 markers = obsolete.getmarkers(repo)
2709 markers = obsolete.getmarkers(repo)
2709
2710
2710 for m in markers:
2711 for m in markers:
2711 cmdutil.showmarker(ui, m)
2712 cmdutil.showmarker(ui, m)
2712
2713
2713 @command('debugpathcomplete',
2714 @command('debugpathcomplete',
2714 [('f', 'full', None, _('complete an entire path')),
2715 [('f', 'full', None, _('complete an entire path')),
2715 ('n', 'normal', None, _('show only normal files')),
2716 ('n', 'normal', None, _('show only normal files')),
2716 ('a', 'added', None, _('show only added files')),
2717 ('a', 'added', None, _('show only added files')),
2717 ('r', 'removed', None, _('show only removed files'))],
2718 ('r', 'removed', None, _('show only removed files'))],
2718 _('FILESPEC...'))
2719 _('FILESPEC...'))
2719 def debugpathcomplete(ui, repo, *specs, **opts):
2720 def debugpathcomplete(ui, repo, *specs, **opts):
2720 '''complete part or all of a tracked path
2721 '''complete part or all of a tracked path
2721
2722
2722 This command supports shells that offer path name completion. It
2723 This command supports shells that offer path name completion. It
2723 currently completes only files already known to the dirstate.
2724 currently completes only files already known to the dirstate.
2724
2725
2725 Completion extends only to the next path segment unless
2726 Completion extends only to the next path segment unless
2726 --full is specified, in which case entire paths are used.'''
2727 --full is specified, in which case entire paths are used.'''
2727
2728
2728 def complete(path, acceptable):
2729 def complete(path, acceptable):
2729 dirstate = repo.dirstate
2730 dirstate = repo.dirstate
2730 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2731 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2731 rootdir = repo.root + os.sep
2732 rootdir = repo.root + os.sep
2732 if spec != repo.root and not spec.startswith(rootdir):
2733 if spec != repo.root and not spec.startswith(rootdir):
2733 return [], []
2734 return [], []
2734 if os.path.isdir(spec):
2735 if os.path.isdir(spec):
2735 spec += '/'
2736 spec += '/'
2736 spec = spec[len(rootdir):]
2737 spec = spec[len(rootdir):]
2737 fixpaths = os.sep != '/'
2738 fixpaths = os.sep != '/'
2738 if fixpaths:
2739 if fixpaths:
2739 spec = spec.replace(os.sep, '/')
2740 spec = spec.replace(os.sep, '/')
2740 speclen = len(spec)
2741 speclen = len(spec)
2741 fullpaths = opts['full']
2742 fullpaths = opts['full']
2742 files, dirs = set(), set()
2743 files, dirs = set(), set()
2743 adddir, addfile = dirs.add, files.add
2744 adddir, addfile = dirs.add, files.add
2744 for f, st in dirstate.iteritems():
2745 for f, st in dirstate.iteritems():
2745 if f.startswith(spec) and st[0] in acceptable:
2746 if f.startswith(spec) and st[0] in acceptable:
2746 if fixpaths:
2747 if fixpaths:
2747 f = f.replace('/', os.sep)
2748 f = f.replace('/', os.sep)
2748 if fullpaths:
2749 if fullpaths:
2749 addfile(f)
2750 addfile(f)
2750 continue
2751 continue
2751 s = f.find(os.sep, speclen)
2752 s = f.find(os.sep, speclen)
2752 if s >= 0:
2753 if s >= 0:
2753 adddir(f[:s])
2754 adddir(f[:s])
2754 else:
2755 else:
2755 addfile(f)
2756 addfile(f)
2756 return files, dirs
2757 return files, dirs
2757
2758
2758 acceptable = ''
2759 acceptable = ''
2759 if opts['normal']:
2760 if opts['normal']:
2760 acceptable += 'nm'
2761 acceptable += 'nm'
2761 if opts['added']:
2762 if opts['added']:
2762 acceptable += 'a'
2763 acceptable += 'a'
2763 if opts['removed']:
2764 if opts['removed']:
2764 acceptable += 'r'
2765 acceptable += 'r'
2765 cwd = repo.getcwd()
2766 cwd = repo.getcwd()
2766 if not specs:
2767 if not specs:
2767 specs = ['.']
2768 specs = ['.']
2768
2769
2769 files, dirs = set(), set()
2770 files, dirs = set(), set()
2770 for spec in specs:
2771 for spec in specs:
2771 f, d = complete(spec, acceptable or 'nmar')
2772 f, d = complete(spec, acceptable or 'nmar')
2772 files.update(f)
2773 files.update(f)
2773 dirs.update(d)
2774 dirs.update(d)
2774 files.update(dirs)
2775 files.update(dirs)
2775 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2776 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2776 ui.write('\n')
2777 ui.write('\n')
2777
2778
2778 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2779 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2779 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2780 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2780 '''access the pushkey key/value protocol
2781 '''access the pushkey key/value protocol
2781
2782
2782 With two args, list the keys in the given namespace.
2783 With two args, list the keys in the given namespace.
2783
2784
2784 With five args, set a key to new if it currently is set to old.
2785 With five args, set a key to new if it currently is set to old.
2785 Reports success or failure.
2786 Reports success or failure.
2786 '''
2787 '''
2787
2788
2788 target = hg.peer(ui, {}, repopath)
2789 target = hg.peer(ui, {}, repopath)
2789 if keyinfo:
2790 if keyinfo:
2790 key, old, new = keyinfo
2791 key, old, new = keyinfo
2791 r = target.pushkey(namespace, key, old, new)
2792 r = target.pushkey(namespace, key, old, new)
2792 ui.status(str(r) + '\n')
2793 ui.status(str(r) + '\n')
2793 return not r
2794 return not r
2794 else:
2795 else:
2795 for k, v in sorted(target.listkeys(namespace).iteritems()):
2796 for k, v in sorted(target.listkeys(namespace).iteritems()):
2796 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2797 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2797 v.encode('string-escape')))
2798 v.encode('string-escape')))
2798
2799
2799 @command('debugpvec', [], _('A B'))
2800 @command('debugpvec', [], _('A B'))
2800 def debugpvec(ui, repo, a, b=None):
2801 def debugpvec(ui, repo, a, b=None):
2801 ca = scmutil.revsingle(repo, a)
2802 ca = scmutil.revsingle(repo, a)
2802 cb = scmutil.revsingle(repo, b)
2803 cb = scmutil.revsingle(repo, b)
2803 pa = pvec.ctxpvec(ca)
2804 pa = pvec.ctxpvec(ca)
2804 pb = pvec.ctxpvec(cb)
2805 pb = pvec.ctxpvec(cb)
2805 if pa == pb:
2806 if pa == pb:
2806 rel = "="
2807 rel = "="
2807 elif pa > pb:
2808 elif pa > pb:
2808 rel = ">"
2809 rel = ">"
2809 elif pa < pb:
2810 elif pa < pb:
2810 rel = "<"
2811 rel = "<"
2811 elif pa | pb:
2812 elif pa | pb:
2812 rel = "|"
2813 rel = "|"
2813 ui.write(_("a: %s\n") % pa)
2814 ui.write(_("a: %s\n") % pa)
2814 ui.write(_("b: %s\n") % pb)
2815 ui.write(_("b: %s\n") % pb)
2815 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2816 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2816 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2817 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2817 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2818 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2818 pa.distance(pb), rel))
2819 pa.distance(pb), rel))
2819
2820
2820 @command('debugrebuilddirstate|debugrebuildstate',
2821 @command('debugrebuilddirstate|debugrebuildstate',
2821 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2822 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2822 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2823 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2823 'the working copy parent')),
2824 'the working copy parent')),
2824 ],
2825 ],
2825 _('[-r REV]'))
2826 _('[-r REV]'))
2826 def debugrebuilddirstate(ui, repo, rev, **opts):
2827 def debugrebuilddirstate(ui, repo, rev, **opts):
2827 """rebuild the dirstate as it would look like for the given revision
2828 """rebuild the dirstate as it would look like for the given revision
2828
2829
2829 If no revision is specified the first current parent will be used.
2830 If no revision is specified the first current parent will be used.
2830
2831
2831 The dirstate will be set to the files of the given revision.
2832 The dirstate will be set to the files of the given revision.
2832 The actual working directory content or existing dirstate
2833 The actual working directory content or existing dirstate
2833 information such as adds or removes is not considered.
2834 information such as adds or removes is not considered.
2834
2835
2835 ``minimal`` will only rebuild the dirstate status for files that claim to be
2836 ``minimal`` will only rebuild the dirstate status for files that claim to be
2836 tracked but are not in the parent manifest, or that exist in the parent
2837 tracked but are not in the parent manifest, or that exist in the parent
2837 manifest but are not in the dirstate. It will not change adds, removes, or
2838 manifest but are not in the dirstate. It will not change adds, removes, or
2838 modified files that are in the working copy parent.
2839 modified files that are in the working copy parent.
2839
2840
2840 One use of this command is to make the next :hg:`status` invocation
2841 One use of this command is to make the next :hg:`status` invocation
2841 check the actual file content.
2842 check the actual file content.
2842 """
2843 """
2843 ctx = scmutil.revsingle(repo, rev)
2844 ctx = scmutil.revsingle(repo, rev)
2844 wlock = repo.wlock()
2845 wlock = repo.wlock()
2845 try:
2846 try:
2846 dirstate = repo.dirstate
2847 dirstate = repo.dirstate
2847
2848
2848 # See command doc for what minimal does.
2849 # See command doc for what minimal does.
2849 if opts.get('minimal'):
2850 if opts.get('minimal'):
2850 dirstatefiles = set(dirstate)
2851 dirstatefiles = set(dirstate)
2851 ctxfiles = set(ctx.manifest().keys())
2852 ctxfiles = set(ctx.manifest().keys())
2852 for file in (dirstatefiles | ctxfiles):
2853 for file in (dirstatefiles | ctxfiles):
2853 indirstate = file in dirstatefiles
2854 indirstate = file in dirstatefiles
2854 inctx = file in ctxfiles
2855 inctx = file in ctxfiles
2855
2856
2856 if indirstate and not inctx and dirstate[file] != 'a':
2857 if indirstate and not inctx and dirstate[file] != 'a':
2857 dirstate.drop(file)
2858 dirstate.drop(file)
2858 elif inctx and not indirstate:
2859 elif inctx and not indirstate:
2859 dirstate.normallookup(file)
2860 dirstate.normallookup(file)
2860 else:
2861 else:
2861 dirstate.rebuild(ctx.node(), ctx.manifest())
2862 dirstate.rebuild(ctx.node(), ctx.manifest())
2862 finally:
2863 finally:
2863 wlock.release()
2864 wlock.release()
2864
2865
2865 @command('debugrebuildfncache', [], '')
2866 @command('debugrebuildfncache', [], '')
2866 def debugrebuildfncache(ui, repo):
2867 def debugrebuildfncache(ui, repo):
2867 """rebuild the fncache file"""
2868 """rebuild the fncache file"""
2868 repair.rebuildfncache(ui, repo)
2869 repair.rebuildfncache(ui, repo)
2869
2870
2870 @command('debugrename',
2871 @command('debugrename',
2871 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2872 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2872 _('[-r REV] FILE'))
2873 _('[-r REV] FILE'))
2873 def debugrename(ui, repo, file1, *pats, **opts):
2874 def debugrename(ui, repo, file1, *pats, **opts):
2874 """dump rename information"""
2875 """dump rename information"""
2875
2876
2876 ctx = scmutil.revsingle(repo, opts.get('rev'))
2877 ctx = scmutil.revsingle(repo, opts.get('rev'))
2877 m = scmutil.match(ctx, (file1,) + pats, opts)
2878 m = scmutil.match(ctx, (file1,) + pats, opts)
2878 for abs in ctx.walk(m):
2879 for abs in ctx.walk(m):
2879 fctx = ctx[abs]
2880 fctx = ctx[abs]
2880 o = fctx.filelog().renamed(fctx.filenode())
2881 o = fctx.filelog().renamed(fctx.filenode())
2881 rel = m.rel(abs)
2882 rel = m.rel(abs)
2882 if o:
2883 if o:
2883 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2884 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2884 else:
2885 else:
2885 ui.write(_("%s not renamed\n") % rel)
2886 ui.write(_("%s not renamed\n") % rel)
2886
2887
2887 @command('debugrevlog',
2888 @command('debugrevlog',
2888 [('c', 'changelog', False, _('open changelog')),
2889 [('c', 'changelog', False, _('open changelog')),
2889 ('m', 'manifest', False, _('open manifest')),
2890 ('m', 'manifest', False, _('open manifest')),
2890 ('', 'dir', False, _('open directory manifest')),
2891 ('', 'dir', False, _('open directory manifest')),
2891 ('d', 'dump', False, _('dump index data'))],
2892 ('d', 'dump', False, _('dump index data'))],
2892 _('-c|-m|FILE'),
2893 _('-c|-m|FILE'),
2893 optionalrepo=True)
2894 optionalrepo=True)
2894 def debugrevlog(ui, repo, file_=None, **opts):
2895 def debugrevlog(ui, repo, file_=None, **opts):
2895 """show data and statistics about a revlog"""
2896 """show data and statistics about a revlog"""
2896 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2897 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2897
2898
2898 if opts.get("dump"):
2899 if opts.get("dump"):
2899 numrevs = len(r)
2900 numrevs = len(r)
2900 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2901 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2901 " rawsize totalsize compression heads chainlen\n")
2902 " rawsize totalsize compression heads chainlen\n")
2902 ts = 0
2903 ts = 0
2903 heads = set()
2904 heads = set()
2904
2905
2905 for rev in xrange(numrevs):
2906 for rev in xrange(numrevs):
2906 dbase = r.deltaparent(rev)
2907 dbase = r.deltaparent(rev)
2907 if dbase == -1:
2908 if dbase == -1:
2908 dbase = rev
2909 dbase = rev
2909 cbase = r.chainbase(rev)
2910 cbase = r.chainbase(rev)
2910 clen = r.chainlen(rev)
2911 clen = r.chainlen(rev)
2911 p1, p2 = r.parentrevs(rev)
2912 p1, p2 = r.parentrevs(rev)
2912 rs = r.rawsize(rev)
2913 rs = r.rawsize(rev)
2913 ts = ts + rs
2914 ts = ts + rs
2914 heads -= set(r.parentrevs(rev))
2915 heads -= set(r.parentrevs(rev))
2915 heads.add(rev)
2916 heads.add(rev)
2916 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2917 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2917 "%11d %5d %8d\n" %
2918 "%11d %5d %8d\n" %
2918 (rev, p1, p2, r.start(rev), r.end(rev),
2919 (rev, p1, p2, r.start(rev), r.end(rev),
2919 r.start(dbase), r.start(cbase),
2920 r.start(dbase), r.start(cbase),
2920 r.start(p1), r.start(p2),
2921 r.start(p1), r.start(p2),
2921 rs, ts, ts / r.end(rev), len(heads), clen))
2922 rs, ts, ts / r.end(rev), len(heads), clen))
2922 return 0
2923 return 0
2923
2924
2924 v = r.version
2925 v = r.version
2925 format = v & 0xFFFF
2926 format = v & 0xFFFF
2926 flags = []
2927 flags = []
2927 gdelta = False
2928 gdelta = False
2928 if v & revlog.REVLOGNGINLINEDATA:
2929 if v & revlog.REVLOGNGINLINEDATA:
2929 flags.append('inline')
2930 flags.append('inline')
2930 if v & revlog.REVLOGGENERALDELTA:
2931 if v & revlog.REVLOGGENERALDELTA:
2931 gdelta = True
2932 gdelta = True
2932 flags.append('generaldelta')
2933 flags.append('generaldelta')
2933 if not flags:
2934 if not flags:
2934 flags = ['(none)']
2935 flags = ['(none)']
2935
2936
2936 nummerges = 0
2937 nummerges = 0
2937 numfull = 0
2938 numfull = 0
2938 numprev = 0
2939 numprev = 0
2939 nump1 = 0
2940 nump1 = 0
2940 nump2 = 0
2941 nump2 = 0
2941 numother = 0
2942 numother = 0
2942 nump1prev = 0
2943 nump1prev = 0
2943 nump2prev = 0
2944 nump2prev = 0
2944 chainlengths = []
2945 chainlengths = []
2945
2946
2946 datasize = [None, 0, 0L]
2947 datasize = [None, 0, 0L]
2947 fullsize = [None, 0, 0L]
2948 fullsize = [None, 0, 0L]
2948 deltasize = [None, 0, 0L]
2949 deltasize = [None, 0, 0L]
2949
2950
2950 def addsize(size, l):
2951 def addsize(size, l):
2951 if l[0] is None or size < l[0]:
2952 if l[0] is None or size < l[0]:
2952 l[0] = size
2953 l[0] = size
2953 if size > l[1]:
2954 if size > l[1]:
2954 l[1] = size
2955 l[1] = size
2955 l[2] += size
2956 l[2] += size
2956
2957
2957 numrevs = len(r)
2958 numrevs = len(r)
2958 for rev in xrange(numrevs):
2959 for rev in xrange(numrevs):
2959 p1, p2 = r.parentrevs(rev)
2960 p1, p2 = r.parentrevs(rev)
2960 delta = r.deltaparent(rev)
2961 delta = r.deltaparent(rev)
2961 if format > 0:
2962 if format > 0:
2962 addsize(r.rawsize(rev), datasize)
2963 addsize(r.rawsize(rev), datasize)
2963 if p2 != nullrev:
2964 if p2 != nullrev:
2964 nummerges += 1
2965 nummerges += 1
2965 size = r.length(rev)
2966 size = r.length(rev)
2966 if delta == nullrev:
2967 if delta == nullrev:
2967 chainlengths.append(0)
2968 chainlengths.append(0)
2968 numfull += 1
2969 numfull += 1
2969 addsize(size, fullsize)
2970 addsize(size, fullsize)
2970 else:
2971 else:
2971 chainlengths.append(chainlengths[delta] + 1)
2972 chainlengths.append(chainlengths[delta] + 1)
2972 addsize(size, deltasize)
2973 addsize(size, deltasize)
2973 if delta == rev - 1:
2974 if delta == rev - 1:
2974 numprev += 1
2975 numprev += 1
2975 if delta == p1:
2976 if delta == p1:
2976 nump1prev += 1
2977 nump1prev += 1
2977 elif delta == p2:
2978 elif delta == p2:
2978 nump2prev += 1
2979 nump2prev += 1
2979 elif delta == p1:
2980 elif delta == p1:
2980 nump1 += 1
2981 nump1 += 1
2981 elif delta == p2:
2982 elif delta == p2:
2982 nump2 += 1
2983 nump2 += 1
2983 elif delta != nullrev:
2984 elif delta != nullrev:
2984 numother += 1
2985 numother += 1
2985
2986
2986 # Adjust size min value for empty cases
2987 # Adjust size min value for empty cases
2987 for size in (datasize, fullsize, deltasize):
2988 for size in (datasize, fullsize, deltasize):
2988 if size[0] is None:
2989 if size[0] is None:
2989 size[0] = 0
2990 size[0] = 0
2990
2991
2991 numdeltas = numrevs - numfull
2992 numdeltas = numrevs - numfull
2992 numoprev = numprev - nump1prev - nump2prev
2993 numoprev = numprev - nump1prev - nump2prev
2993 totalrawsize = datasize[2]
2994 totalrawsize = datasize[2]
2994 datasize[2] /= numrevs
2995 datasize[2] /= numrevs
2995 fulltotal = fullsize[2]
2996 fulltotal = fullsize[2]
2996 fullsize[2] /= numfull
2997 fullsize[2] /= numfull
2997 deltatotal = deltasize[2]
2998 deltatotal = deltasize[2]
2998 if numrevs - numfull > 0:
2999 if numrevs - numfull > 0:
2999 deltasize[2] /= numrevs - numfull
3000 deltasize[2] /= numrevs - numfull
3000 totalsize = fulltotal + deltatotal
3001 totalsize = fulltotal + deltatotal
3001 avgchainlen = sum(chainlengths) / numrevs
3002 avgchainlen = sum(chainlengths) / numrevs
3002 maxchainlen = max(chainlengths)
3003 maxchainlen = max(chainlengths)
3003 compratio = totalrawsize / totalsize
3004 compratio = totalrawsize / totalsize
3004
3005
3005 basedfmtstr = '%%%dd\n'
3006 basedfmtstr = '%%%dd\n'
3006 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3007 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3007
3008
3008 def dfmtstr(max):
3009 def dfmtstr(max):
3009 return basedfmtstr % len(str(max))
3010 return basedfmtstr % len(str(max))
3010 def pcfmtstr(max, padding=0):
3011 def pcfmtstr(max, padding=0):
3011 return basepcfmtstr % (len(str(max)), ' ' * padding)
3012 return basepcfmtstr % (len(str(max)), ' ' * padding)
3012
3013
3013 def pcfmt(value, total):
3014 def pcfmt(value, total):
3014 return (value, 100 * float(value) / total)
3015 return (value, 100 * float(value) / total)
3015
3016
3016 ui.write(('format : %d\n') % format)
3017 ui.write(('format : %d\n') % format)
3017 ui.write(('flags : %s\n') % ', '.join(flags))
3018 ui.write(('flags : %s\n') % ', '.join(flags))
3018
3019
3019 ui.write('\n')
3020 ui.write('\n')
3020 fmt = pcfmtstr(totalsize)
3021 fmt = pcfmtstr(totalsize)
3021 fmt2 = dfmtstr(totalsize)
3022 fmt2 = dfmtstr(totalsize)
3022 ui.write(('revisions : ') + fmt2 % numrevs)
3023 ui.write(('revisions : ') + fmt2 % numrevs)
3023 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3024 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3024 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3025 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3025 ui.write(('revisions : ') + fmt2 % numrevs)
3026 ui.write(('revisions : ') + fmt2 % numrevs)
3026 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3027 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3027 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3028 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3028 ui.write(('revision size : ') + fmt2 % totalsize)
3029 ui.write(('revision size : ') + fmt2 % totalsize)
3029 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3030 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3030 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3031 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3031
3032
3032 ui.write('\n')
3033 ui.write('\n')
3033 fmt = dfmtstr(max(avgchainlen, compratio))
3034 fmt = dfmtstr(max(avgchainlen, compratio))
3034 ui.write(('avg chain length : ') + fmt % avgchainlen)
3035 ui.write(('avg chain length : ') + fmt % avgchainlen)
3035 ui.write(('max chain length : ') + fmt % maxchainlen)
3036 ui.write(('max chain length : ') + fmt % maxchainlen)
3036 ui.write(('compression ratio : ') + fmt % compratio)
3037 ui.write(('compression ratio : ') + fmt % compratio)
3037
3038
3038 if format > 0:
3039 if format > 0:
3039 ui.write('\n')
3040 ui.write('\n')
3040 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3041 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3041 % tuple(datasize))
3042 % tuple(datasize))
3042 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3043 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3043 % tuple(fullsize))
3044 % tuple(fullsize))
3044 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3045 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3045 % tuple(deltasize))
3046 % tuple(deltasize))
3046
3047
3047 if numdeltas > 0:
3048 if numdeltas > 0:
3048 ui.write('\n')
3049 ui.write('\n')
3049 fmt = pcfmtstr(numdeltas)
3050 fmt = pcfmtstr(numdeltas)
3050 fmt2 = pcfmtstr(numdeltas, 4)
3051 fmt2 = pcfmtstr(numdeltas, 4)
3051 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3052 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3052 if numprev > 0:
3053 if numprev > 0:
3053 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3054 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3054 numprev))
3055 numprev))
3055 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3056 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3056 numprev))
3057 numprev))
3057 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3058 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3058 numprev))
3059 numprev))
3059 if gdelta:
3060 if gdelta:
3060 ui.write(('deltas against p1 : ')
3061 ui.write(('deltas against p1 : ')
3061 + fmt % pcfmt(nump1, numdeltas))
3062 + fmt % pcfmt(nump1, numdeltas))
3062 ui.write(('deltas against p2 : ')
3063 ui.write(('deltas against p2 : ')
3063 + fmt % pcfmt(nump2, numdeltas))
3064 + fmt % pcfmt(nump2, numdeltas))
3064 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3065 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3065 numdeltas))
3066 numdeltas))
3066
3067
3067 @command('debugrevspec',
3068 @command('debugrevspec',
3068 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3069 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3069 ('REVSPEC'))
3070 ('REVSPEC'))
3070 def debugrevspec(ui, repo, expr, **opts):
3071 def debugrevspec(ui, repo, expr, **opts):
3071 """parse and apply a revision specification
3072 """parse and apply a revision specification
3072
3073
3073 Use --verbose to print the parsed tree before and after aliases
3074 Use --verbose to print the parsed tree before and after aliases
3074 expansion.
3075 expansion.
3075 """
3076 """
3076 if ui.verbose:
3077 if ui.verbose:
3077 tree = revset.parse(expr, lookup=repo.__contains__)
3078 tree = revset.parse(expr, lookup=repo.__contains__)
3078 ui.note(revset.prettyformat(tree), "\n")
3079 ui.note(revset.prettyformat(tree), "\n")
3079 newtree = revset.findaliases(ui, tree)
3080 newtree = revset.findaliases(ui, tree)
3080 if newtree != tree:
3081 if newtree != tree:
3081 ui.note(revset.prettyformat(newtree), "\n")
3082 ui.note(revset.prettyformat(newtree), "\n")
3082 tree = newtree
3083 tree = newtree
3083 newtree = revset.foldconcat(tree)
3084 newtree = revset.foldconcat(tree)
3084 if newtree != tree:
3085 if newtree != tree:
3085 ui.note(revset.prettyformat(newtree), "\n")
3086 ui.note(revset.prettyformat(newtree), "\n")
3086 if opts["optimize"]:
3087 if opts["optimize"]:
3087 weight, optimizedtree = revset.optimize(newtree, True)
3088 weight, optimizedtree = revset.optimize(newtree, True)
3088 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3089 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3089 func = revset.match(ui, expr, repo)
3090 func = revset.match(ui, expr, repo)
3090 revs = func(repo)
3091 revs = func(repo)
3091 if ui.verbose:
3092 if ui.verbose:
3092 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3093 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3093 for c in revs:
3094 for c in revs:
3094 ui.write("%s\n" % c)
3095 ui.write("%s\n" % c)
3095
3096
3096 @command('debugsetparents', [], _('REV1 [REV2]'))
3097 @command('debugsetparents', [], _('REV1 [REV2]'))
3097 def debugsetparents(ui, repo, rev1, rev2=None):
3098 def debugsetparents(ui, repo, rev1, rev2=None):
3098 """manually set the parents of the current working directory
3099 """manually set the parents of the current working directory
3099
3100
3100 This is useful for writing repository conversion tools, but should
3101 This is useful for writing repository conversion tools, but should
3101 be used with care. For example, neither the working directory nor the
3102 be used with care. For example, neither the working directory nor the
3102 dirstate is updated, so file status may be incorrect after running this
3103 dirstate is updated, so file status may be incorrect after running this
3103 command.
3104 command.
3104
3105
3105 Returns 0 on success.
3106 Returns 0 on success.
3106 """
3107 """
3107
3108
3108 r1 = scmutil.revsingle(repo, rev1).node()
3109 r1 = scmutil.revsingle(repo, rev1).node()
3109 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3110 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3110
3111
3111 wlock = repo.wlock()
3112 wlock = repo.wlock()
3112 try:
3113 try:
3113 repo.dirstate.beginparentchange()
3114 repo.dirstate.beginparentchange()
3114 repo.setparents(r1, r2)
3115 repo.setparents(r1, r2)
3115 repo.dirstate.endparentchange()
3116 repo.dirstate.endparentchange()
3116 finally:
3117 finally:
3117 wlock.release()
3118 wlock.release()
3118
3119
3119 @command('debugdirstate|debugstate',
3120 @command('debugdirstate|debugstate',
3120 [('', 'nodates', None, _('do not display the saved mtime')),
3121 [('', 'nodates', None, _('do not display the saved mtime')),
3121 ('', 'datesort', None, _('sort by saved mtime'))],
3122 ('', 'datesort', None, _('sort by saved mtime'))],
3122 _('[OPTION]...'))
3123 _('[OPTION]...'))
3123 def debugstate(ui, repo, nodates=None, datesort=None):
3124 def debugstate(ui, repo, nodates=None, datesort=None):
3124 """show the contents of the current dirstate"""
3125 """show the contents of the current dirstate"""
3125 timestr = ""
3126 timestr = ""
3126 if datesort:
3127 if datesort:
3127 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3128 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3128 else:
3129 else:
3129 keyfunc = None # sort by filename
3130 keyfunc = None # sort by filename
3130 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3131 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3131 if ent[3] == -1:
3132 if ent[3] == -1:
3132 timestr = 'unset '
3133 timestr = 'unset '
3133 elif nodates:
3134 elif nodates:
3134 timestr = 'set '
3135 timestr = 'set '
3135 else:
3136 else:
3136 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3137 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3137 time.localtime(ent[3]))
3138 time.localtime(ent[3]))
3138 if ent[1] & 0o20000:
3139 if ent[1] & 0o20000:
3139 mode = 'lnk'
3140 mode = 'lnk'
3140 else:
3141 else:
3141 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3142 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3142 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3143 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3143 for f in repo.dirstate.copies():
3144 for f in repo.dirstate.copies():
3144 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3145 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3145
3146
3146 @command('debugsub',
3147 @command('debugsub',
3147 [('r', 'rev', '',
3148 [('r', 'rev', '',
3148 _('revision to check'), _('REV'))],
3149 _('revision to check'), _('REV'))],
3149 _('[-r REV] [REV]'))
3150 _('[-r REV] [REV]'))
3150 def debugsub(ui, repo, rev=None):
3151 def debugsub(ui, repo, rev=None):
3151 ctx = scmutil.revsingle(repo, rev, None)
3152 ctx = scmutil.revsingle(repo, rev, None)
3152 for k, v in sorted(ctx.substate.items()):
3153 for k, v in sorted(ctx.substate.items()):
3153 ui.write(('path %s\n') % k)
3154 ui.write(('path %s\n') % k)
3154 ui.write((' source %s\n') % v[0])
3155 ui.write((' source %s\n') % v[0])
3155 ui.write((' revision %s\n') % v[1])
3156 ui.write((' revision %s\n') % v[1])
3156
3157
3157 @command('debugsuccessorssets',
3158 @command('debugsuccessorssets',
3158 [],
3159 [],
3159 _('[REV]'))
3160 _('[REV]'))
3160 def debugsuccessorssets(ui, repo, *revs):
3161 def debugsuccessorssets(ui, repo, *revs):
3161 """show set of successors for revision
3162 """show set of successors for revision
3162
3163
3163 A successors set of changeset A is a consistent group of revisions that
3164 A successors set of changeset A is a consistent group of revisions that
3164 succeed A. It contains non-obsolete changesets only.
3165 succeed A. It contains non-obsolete changesets only.
3165
3166
3166 In most cases a changeset A has a single successors set containing a single
3167 In most cases a changeset A has a single successors set containing a single
3167 successor (changeset A replaced by A').
3168 successor (changeset A replaced by A').
3168
3169
3169 A changeset that is made obsolete with no successors are called "pruned".
3170 A changeset that is made obsolete with no successors are called "pruned".
3170 Such changesets have no successors sets at all.
3171 Such changesets have no successors sets at all.
3171
3172
3172 A changeset that has been "split" will have a successors set containing
3173 A changeset that has been "split" will have a successors set containing
3173 more than one successor.
3174 more than one successor.
3174
3175
3175 A changeset that has been rewritten in multiple different ways is called
3176 A changeset that has been rewritten in multiple different ways is called
3176 "divergent". Such changesets have multiple successor sets (each of which
3177 "divergent". Such changesets have multiple successor sets (each of which
3177 may also be split, i.e. have multiple successors).
3178 may also be split, i.e. have multiple successors).
3178
3179
3179 Results are displayed as follows::
3180 Results are displayed as follows::
3180
3181
3181 <rev1>
3182 <rev1>
3182 <successors-1A>
3183 <successors-1A>
3183 <rev2>
3184 <rev2>
3184 <successors-2A>
3185 <successors-2A>
3185 <successors-2B1> <successors-2B2> <successors-2B3>
3186 <successors-2B1> <successors-2B2> <successors-2B3>
3186
3187
3187 Here rev2 has two possible (i.e. divergent) successors sets. The first
3188 Here rev2 has two possible (i.e. divergent) successors sets. The first
3188 holds one element, whereas the second holds three (i.e. the changeset has
3189 holds one element, whereas the second holds three (i.e. the changeset has
3189 been split).
3190 been split).
3190 """
3191 """
3191 # passed to successorssets caching computation from one call to another
3192 # passed to successorssets caching computation from one call to another
3192 cache = {}
3193 cache = {}
3193 ctx2str = str
3194 ctx2str = str
3194 node2str = short
3195 node2str = short
3195 if ui.debug():
3196 if ui.debug():
3196 def ctx2str(ctx):
3197 def ctx2str(ctx):
3197 return ctx.hex()
3198 return ctx.hex()
3198 node2str = hex
3199 node2str = hex
3199 for rev in scmutil.revrange(repo, revs):
3200 for rev in scmutil.revrange(repo, revs):
3200 ctx = repo[rev]
3201 ctx = repo[rev]
3201 ui.write('%s\n'% ctx2str(ctx))
3202 ui.write('%s\n'% ctx2str(ctx))
3202 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3203 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3203 if succsset:
3204 if succsset:
3204 ui.write(' ')
3205 ui.write(' ')
3205 ui.write(node2str(succsset[0]))
3206 ui.write(node2str(succsset[0]))
3206 for node in succsset[1:]:
3207 for node in succsset[1:]:
3207 ui.write(' ')
3208 ui.write(' ')
3208 ui.write(node2str(node))
3209 ui.write(node2str(node))
3209 ui.write('\n')
3210 ui.write('\n')
3210
3211
3211 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3212 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3212 def debugwalk(ui, repo, *pats, **opts):
3213 def debugwalk(ui, repo, *pats, **opts):
3213 """show how files match on given patterns"""
3214 """show how files match on given patterns"""
3214 m = scmutil.match(repo[None], pats, opts)
3215 m = scmutil.match(repo[None], pats, opts)
3215 items = list(repo.walk(m))
3216 items = list(repo.walk(m))
3216 if not items:
3217 if not items:
3217 return
3218 return
3218 f = lambda fn: fn
3219 f = lambda fn: fn
3219 if ui.configbool('ui', 'slash') and os.sep != '/':
3220 if ui.configbool('ui', 'slash') and os.sep != '/':
3220 f = lambda fn: util.normpath(fn)
3221 f = lambda fn: util.normpath(fn)
3221 fmt = 'f %%-%ds %%-%ds %%s' % (
3222 fmt = 'f %%-%ds %%-%ds %%s' % (
3222 max([len(abs) for abs in items]),
3223 max([len(abs) for abs in items]),
3223 max([len(m.rel(abs)) for abs in items]))
3224 max([len(m.rel(abs)) for abs in items]))
3224 for abs in items:
3225 for abs in items:
3225 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3226 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3226 ui.write("%s\n" % line.rstrip())
3227 ui.write("%s\n" % line.rstrip())
3227
3228
3228 @command('debugwireargs',
3229 @command('debugwireargs',
3229 [('', 'three', '', 'three'),
3230 [('', 'three', '', 'three'),
3230 ('', 'four', '', 'four'),
3231 ('', 'four', '', 'four'),
3231 ('', 'five', '', 'five'),
3232 ('', 'five', '', 'five'),
3232 ] + remoteopts,
3233 ] + remoteopts,
3233 _('REPO [OPTIONS]... [ONE [TWO]]'),
3234 _('REPO [OPTIONS]... [ONE [TWO]]'),
3234 norepo=True)
3235 norepo=True)
3235 def debugwireargs(ui, repopath, *vals, **opts):
3236 def debugwireargs(ui, repopath, *vals, **opts):
3236 repo = hg.peer(ui, opts, repopath)
3237 repo = hg.peer(ui, opts, repopath)
3237 for opt in remoteopts:
3238 for opt in remoteopts:
3238 del opts[opt[1]]
3239 del opts[opt[1]]
3239 args = {}
3240 args = {}
3240 for k, v in opts.iteritems():
3241 for k, v in opts.iteritems():
3241 if v:
3242 if v:
3242 args[k] = v
3243 args[k] = v
3243 # run twice to check that we don't mess up the stream for the next command
3244 # run twice to check that we don't mess up the stream for the next command
3244 res1 = repo.debugwireargs(*vals, **args)
3245 res1 = repo.debugwireargs(*vals, **args)
3245 res2 = repo.debugwireargs(*vals, **args)
3246 res2 = repo.debugwireargs(*vals, **args)
3246 ui.write("%s\n" % res1)
3247 ui.write("%s\n" % res1)
3247 if res1 != res2:
3248 if res1 != res2:
3248 ui.warn("%s\n" % res2)
3249 ui.warn("%s\n" % res2)
3249
3250
3250 @command('^diff',
3251 @command('^diff',
3251 [('r', 'rev', [], _('revision'), _('REV')),
3252 [('r', 'rev', [], _('revision'), _('REV')),
3252 ('c', 'change', '', _('change made by revision'), _('REV'))
3253 ('c', 'change', '', _('change made by revision'), _('REV'))
3253 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3254 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3254 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3255 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3255 inferrepo=True)
3256 inferrepo=True)
3256 def diff(ui, repo, *pats, **opts):
3257 def diff(ui, repo, *pats, **opts):
3257 """diff repository (or selected files)
3258 """diff repository (or selected files)
3258
3259
3259 Show differences between revisions for the specified files.
3260 Show differences between revisions for the specified files.
3260
3261
3261 Differences between files are shown using the unified diff format.
3262 Differences between files are shown using the unified diff format.
3262
3263
3263 .. note::
3264 .. note::
3264
3265
3265 diff may generate unexpected results for merges, as it will
3266 diff may generate unexpected results for merges, as it will
3266 default to comparing against the working directory's first
3267 default to comparing against the working directory's first
3267 parent changeset if no revisions are specified.
3268 parent changeset if no revisions are specified.
3268
3269
3269 When two revision arguments are given, then changes are shown
3270 When two revision arguments are given, then changes are shown
3270 between those revisions. If only one revision is specified then
3271 between those revisions. If only one revision is specified then
3271 that revision is compared to the working directory, and, when no
3272 that revision is compared to the working directory, and, when no
3272 revisions are specified, the working directory files are compared
3273 revisions are specified, the working directory files are compared
3273 to its parent.
3274 to its parent.
3274
3275
3275 Alternatively you can specify -c/--change with a revision to see
3276 Alternatively you can specify -c/--change with a revision to see
3276 the changes in that changeset relative to its first parent.
3277 the changes in that changeset relative to its first parent.
3277
3278
3278 Without the -a/--text option, diff will avoid generating diffs of
3279 Without the -a/--text option, diff will avoid generating diffs of
3279 files it detects as binary. With -a, diff will generate a diff
3280 files it detects as binary. With -a, diff will generate a diff
3280 anyway, probably with undesirable results.
3281 anyway, probably with undesirable results.
3281
3282
3282 Use the -g/--git option to generate diffs in the git extended diff
3283 Use the -g/--git option to generate diffs in the git extended diff
3283 format. For more information, read :hg:`help diffs`.
3284 format. For more information, read :hg:`help diffs`.
3284
3285
3285 .. container:: verbose
3286 .. container:: verbose
3286
3287
3287 Examples:
3288 Examples:
3288
3289
3289 - compare a file in the current working directory to its parent::
3290 - compare a file in the current working directory to its parent::
3290
3291
3291 hg diff foo.c
3292 hg diff foo.c
3292
3293
3293 - compare two historical versions of a directory, with rename info::
3294 - compare two historical versions of a directory, with rename info::
3294
3295
3295 hg diff --git -r 1.0:1.2 lib/
3296 hg diff --git -r 1.0:1.2 lib/
3296
3297
3297 - get change stats relative to the last change on some date::
3298 - get change stats relative to the last change on some date::
3298
3299
3299 hg diff --stat -r "date('may 2')"
3300 hg diff --stat -r "date('may 2')"
3300
3301
3301 - diff all newly-added files that contain a keyword::
3302 - diff all newly-added files that contain a keyword::
3302
3303
3303 hg diff "set:added() and grep(GNU)"
3304 hg diff "set:added() and grep(GNU)"
3304
3305
3305 - compare a revision and its parents::
3306 - compare a revision and its parents::
3306
3307
3307 hg diff -c 9353 # compare against first parent
3308 hg diff -c 9353 # compare against first parent
3308 hg diff -r 9353^:9353 # same using revset syntax
3309 hg diff -r 9353^:9353 # same using revset syntax
3309 hg diff -r 9353^2:9353 # compare against the second parent
3310 hg diff -r 9353^2:9353 # compare against the second parent
3310
3311
3311 Returns 0 on success.
3312 Returns 0 on success.
3312 """
3313 """
3313
3314
3314 revs = opts.get('rev')
3315 revs = opts.get('rev')
3315 change = opts.get('change')
3316 change = opts.get('change')
3316 stat = opts.get('stat')
3317 stat = opts.get('stat')
3317 reverse = opts.get('reverse')
3318 reverse = opts.get('reverse')
3318
3319
3319 if revs and change:
3320 if revs and change:
3320 msg = _('cannot specify --rev and --change at the same time')
3321 msg = _('cannot specify --rev and --change at the same time')
3321 raise util.Abort(msg)
3322 raise util.Abort(msg)
3322 elif change:
3323 elif change:
3323 node2 = scmutil.revsingle(repo, change, None).node()
3324 node2 = scmutil.revsingle(repo, change, None).node()
3324 node1 = repo[node2].p1().node()
3325 node1 = repo[node2].p1().node()
3325 else:
3326 else:
3326 node1, node2 = scmutil.revpair(repo, revs)
3327 node1, node2 = scmutil.revpair(repo, revs)
3327
3328
3328 if reverse:
3329 if reverse:
3329 node1, node2 = node2, node1
3330 node1, node2 = node2, node1
3330
3331
3331 diffopts = patch.diffallopts(ui, opts)
3332 diffopts = patch.diffallopts(ui, opts)
3332 m = scmutil.match(repo[node2], pats, opts)
3333 m = scmutil.match(repo[node2], pats, opts)
3333 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3334 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3334 listsubrepos=opts.get('subrepos'),
3335 listsubrepos=opts.get('subrepos'),
3335 root=opts.get('root'))
3336 root=opts.get('root'))
3336
3337
3337 @command('^export',
3338 @command('^export',
3338 [('o', 'output', '',
3339 [('o', 'output', '',
3339 _('print output to file with formatted name'), _('FORMAT')),
3340 _('print output to file with formatted name'), _('FORMAT')),
3340 ('', 'switch-parent', None, _('diff against the second parent')),
3341 ('', 'switch-parent', None, _('diff against the second parent')),
3341 ('r', 'rev', [], _('revisions to export'), _('REV')),
3342 ('r', 'rev', [], _('revisions to export'), _('REV')),
3342 ] + diffopts,
3343 ] + diffopts,
3343 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3344 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3344 def export(ui, repo, *changesets, **opts):
3345 def export(ui, repo, *changesets, **opts):
3345 """dump the header and diffs for one or more changesets
3346 """dump the header and diffs for one or more changesets
3346
3347
3347 Print the changeset header and diffs for one or more revisions.
3348 Print the changeset header and diffs for one or more revisions.
3348 If no revision is given, the parent of the working directory is used.
3349 If no revision is given, the parent of the working directory is used.
3349
3350
3350 The information shown in the changeset header is: author, date,
3351 The information shown in the changeset header is: author, date,
3351 branch name (if non-default), changeset hash, parent(s) and commit
3352 branch name (if non-default), changeset hash, parent(s) and commit
3352 comment.
3353 comment.
3353
3354
3354 .. note::
3355 .. note::
3355
3356
3356 export may generate unexpected diff output for merge
3357 export may generate unexpected diff output for merge
3357 changesets, as it will compare the merge changeset against its
3358 changesets, as it will compare the merge changeset against its
3358 first parent only.
3359 first parent only.
3359
3360
3360 Output may be to a file, in which case the name of the file is
3361 Output may be to a file, in which case the name of the file is
3361 given using a format string. The formatting rules are as follows:
3362 given using a format string. The formatting rules are as follows:
3362
3363
3363 :``%%``: literal "%" character
3364 :``%%``: literal "%" character
3364 :``%H``: changeset hash (40 hexadecimal digits)
3365 :``%H``: changeset hash (40 hexadecimal digits)
3365 :``%N``: number of patches being generated
3366 :``%N``: number of patches being generated
3366 :``%R``: changeset revision number
3367 :``%R``: changeset revision number
3367 :``%b``: basename of the exporting repository
3368 :``%b``: basename of the exporting repository
3368 :``%h``: short-form changeset hash (12 hexadecimal digits)
3369 :``%h``: short-form changeset hash (12 hexadecimal digits)
3369 :``%m``: first line of the commit message (only alphanumeric characters)
3370 :``%m``: first line of the commit message (only alphanumeric characters)
3370 :``%n``: zero-padded sequence number, starting at 1
3371 :``%n``: zero-padded sequence number, starting at 1
3371 :``%r``: zero-padded changeset revision number
3372 :``%r``: zero-padded changeset revision number
3372
3373
3373 Without the -a/--text option, export will avoid generating diffs
3374 Without the -a/--text option, export will avoid generating diffs
3374 of files it detects as binary. With -a, export will generate a
3375 of files it detects as binary. With -a, export will generate a
3375 diff anyway, probably with undesirable results.
3376 diff anyway, probably with undesirable results.
3376
3377
3377 Use the -g/--git option to generate diffs in the git extended diff
3378 Use the -g/--git option to generate diffs in the git extended diff
3378 format. See :hg:`help diffs` for more information.
3379 format. See :hg:`help diffs` for more information.
3379
3380
3380 With the --switch-parent option, the diff will be against the
3381 With the --switch-parent option, the diff will be against the
3381 second parent. It can be useful to review a merge.
3382 second parent. It can be useful to review a merge.
3382
3383
3383 .. container:: verbose
3384 .. container:: verbose
3384
3385
3385 Examples:
3386 Examples:
3386
3387
3387 - use export and import to transplant a bugfix to the current
3388 - use export and import to transplant a bugfix to the current
3388 branch::
3389 branch::
3389
3390
3390 hg export -r 9353 | hg import -
3391 hg export -r 9353 | hg import -
3391
3392
3392 - export all the changesets between two revisions to a file with
3393 - export all the changesets between two revisions to a file with
3393 rename information::
3394 rename information::
3394
3395
3395 hg export --git -r 123:150 > changes.txt
3396 hg export --git -r 123:150 > changes.txt
3396
3397
3397 - split outgoing changes into a series of patches with
3398 - split outgoing changes into a series of patches with
3398 descriptive names::
3399 descriptive names::
3399
3400
3400 hg export -r "outgoing()" -o "%n-%m.patch"
3401 hg export -r "outgoing()" -o "%n-%m.patch"
3401
3402
3402 Returns 0 on success.
3403 Returns 0 on success.
3403 """
3404 """
3404 changesets += tuple(opts.get('rev', []))
3405 changesets += tuple(opts.get('rev', []))
3405 if not changesets:
3406 if not changesets:
3406 changesets = ['.']
3407 changesets = ['.']
3407 revs = scmutil.revrange(repo, changesets)
3408 revs = scmutil.revrange(repo, changesets)
3408 if not revs:
3409 if not revs:
3409 raise util.Abort(_("export requires at least one changeset"))
3410 raise util.Abort(_("export requires at least one changeset"))
3410 if len(revs) > 1:
3411 if len(revs) > 1:
3411 ui.note(_('exporting patches:\n'))
3412 ui.note(_('exporting patches:\n'))
3412 else:
3413 else:
3413 ui.note(_('exporting patch:\n'))
3414 ui.note(_('exporting patch:\n'))
3414 cmdutil.export(repo, revs, template=opts.get('output'),
3415 cmdutil.export(repo, revs, template=opts.get('output'),
3415 switch_parent=opts.get('switch_parent'),
3416 switch_parent=opts.get('switch_parent'),
3416 opts=patch.diffallopts(ui, opts))
3417 opts=patch.diffallopts(ui, opts))
3417
3418
3418 @command('files',
3419 @command('files',
3419 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3420 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3420 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3421 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3421 ] + walkopts + formatteropts + subrepoopts,
3422 ] + walkopts + formatteropts + subrepoopts,
3422 _('[OPTION]... [PATTERN]...'))
3423 _('[OPTION]... [PATTERN]...'))
3423 def files(ui, repo, *pats, **opts):
3424 def files(ui, repo, *pats, **opts):
3424 """list tracked files
3425 """list tracked files
3425
3426
3426 Print files under Mercurial control in the working directory or
3427 Print files under Mercurial control in the working directory or
3427 specified revision whose names match the given patterns (excluding
3428 specified revision whose names match the given patterns (excluding
3428 removed files).
3429 removed files).
3429
3430
3430 If no patterns are given to match, this command prints the names
3431 If no patterns are given to match, this command prints the names
3431 of all files under Mercurial control in the working directory.
3432 of all files under Mercurial control in the working directory.
3432
3433
3433 .. container:: verbose
3434 .. container:: verbose
3434
3435
3435 Examples:
3436 Examples:
3436
3437
3437 - list all files under the current directory::
3438 - list all files under the current directory::
3438
3439
3439 hg files .
3440 hg files .
3440
3441
3441 - shows sizes and flags for current revision::
3442 - shows sizes and flags for current revision::
3442
3443
3443 hg files -vr .
3444 hg files -vr .
3444
3445
3445 - list all files named README::
3446 - list all files named README::
3446
3447
3447 hg files -I "**/README"
3448 hg files -I "**/README"
3448
3449
3449 - list all binary files::
3450 - list all binary files::
3450
3451
3451 hg files "set:binary()"
3452 hg files "set:binary()"
3452
3453
3453 - find files containing a regular expression::
3454 - find files containing a regular expression::
3454
3455
3455 hg files "set:grep('bob')"
3456 hg files "set:grep('bob')"
3456
3457
3457 - search tracked file contents with xargs and grep::
3458 - search tracked file contents with xargs and grep::
3458
3459
3459 hg files -0 | xargs -0 grep foo
3460 hg files -0 | xargs -0 grep foo
3460
3461
3461 See :hg:`help patterns` and :hg:`help filesets` for more information
3462 See :hg:`help patterns` and :hg:`help filesets` for more information
3462 on specifying file patterns.
3463 on specifying file patterns.
3463
3464
3464 Returns 0 if a match is found, 1 otherwise.
3465 Returns 0 if a match is found, 1 otherwise.
3465
3466
3466 """
3467 """
3467 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3468 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3468
3469
3469 end = '\n'
3470 end = '\n'
3470 if opts.get('print0'):
3471 if opts.get('print0'):
3471 end = '\0'
3472 end = '\0'
3472 fm = ui.formatter('files', opts)
3473 fm = ui.formatter('files', opts)
3473 fmt = '%s' + end
3474 fmt = '%s' + end
3474
3475
3475 m = scmutil.match(ctx, pats, opts)
3476 m = scmutil.match(ctx, pats, opts)
3476 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3477 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3477
3478
3478 fm.end()
3479 fm.end()
3479
3480
3480 return ret
3481 return ret
3481
3482
3482 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3483 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3483 def forget(ui, repo, *pats, **opts):
3484 def forget(ui, repo, *pats, **opts):
3484 """forget the specified files on the next commit
3485 """forget the specified files on the next commit
3485
3486
3486 Mark the specified files so they will no longer be tracked
3487 Mark the specified files so they will no longer be tracked
3487 after the next commit.
3488 after the next commit.
3488
3489
3489 This only removes files from the current branch, not from the
3490 This only removes files from the current branch, not from the
3490 entire project history, and it does not delete them from the
3491 entire project history, and it does not delete them from the
3491 working directory.
3492 working directory.
3492
3493
3493 To delete the file from the working directory, see :hg:`remove`.
3494 To delete the file from the working directory, see :hg:`remove`.
3494
3495
3495 To undo a forget before the next commit, see :hg:`add`.
3496 To undo a forget before the next commit, see :hg:`add`.
3496
3497
3497 .. container:: verbose
3498 .. container:: verbose
3498
3499
3499 Examples:
3500 Examples:
3500
3501
3501 - forget newly-added binary files::
3502 - forget newly-added binary files::
3502
3503
3503 hg forget "set:added() and binary()"
3504 hg forget "set:added() and binary()"
3504
3505
3505 - forget files that would be excluded by .hgignore::
3506 - forget files that would be excluded by .hgignore::
3506
3507
3507 hg forget "set:hgignore()"
3508 hg forget "set:hgignore()"
3508
3509
3509 Returns 0 on success.
3510 Returns 0 on success.
3510 """
3511 """
3511
3512
3512 if not pats:
3513 if not pats:
3513 raise util.Abort(_('no files specified'))
3514 raise util.Abort(_('no files specified'))
3514
3515
3515 m = scmutil.match(repo[None], pats, opts)
3516 m = scmutil.match(repo[None], pats, opts)
3516 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3517 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3517 return rejected and 1 or 0
3518 return rejected and 1 or 0
3518
3519
3519 @command(
3520 @command(
3520 'graft',
3521 'graft',
3521 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3522 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3522 ('c', 'continue', False, _('resume interrupted graft')),
3523 ('c', 'continue', False, _('resume interrupted graft')),
3523 ('e', 'edit', False, _('invoke editor on commit messages')),
3524 ('e', 'edit', False, _('invoke editor on commit messages')),
3524 ('', 'log', None, _('append graft info to log message')),
3525 ('', 'log', None, _('append graft info to log message')),
3525 ('f', 'force', False, _('force graft')),
3526 ('f', 'force', False, _('force graft')),
3526 ('D', 'currentdate', False,
3527 ('D', 'currentdate', False,
3527 _('record the current date as commit date')),
3528 _('record the current date as commit date')),
3528 ('U', 'currentuser', False,
3529 ('U', 'currentuser', False,
3529 _('record the current user as committer'), _('DATE'))]
3530 _('record the current user as committer'), _('DATE'))]
3530 + commitopts2 + mergetoolopts + dryrunopts,
3531 + commitopts2 + mergetoolopts + dryrunopts,
3531 _('[OPTION]... [-r] REV...'))
3532 _('[OPTION]... [-r] REV...'))
3532 def graft(ui, repo, *revs, **opts):
3533 def graft(ui, repo, *revs, **opts):
3533 '''copy changes from other branches onto the current branch
3534 '''copy changes from other branches onto the current branch
3534
3535
3535 This command uses Mercurial's merge logic to copy individual
3536 This command uses Mercurial's merge logic to copy individual
3536 changes from other branches without merging branches in the
3537 changes from other branches without merging branches in the
3537 history graph. This is sometimes known as 'backporting' or
3538 history graph. This is sometimes known as 'backporting' or
3538 'cherry-picking'. By default, graft will copy user, date, and
3539 'cherry-picking'. By default, graft will copy user, date, and
3539 description from the source changesets.
3540 description from the source changesets.
3540
3541
3541 Changesets that are ancestors of the current revision, that have
3542 Changesets that are ancestors of the current revision, that have
3542 already been grafted, or that are merges will be skipped.
3543 already been grafted, or that are merges will be skipped.
3543
3544
3544 If --log is specified, log messages will have a comment appended
3545 If --log is specified, log messages will have a comment appended
3545 of the form::
3546 of the form::
3546
3547
3547 (grafted from CHANGESETHASH)
3548 (grafted from CHANGESETHASH)
3548
3549
3549 If --force is specified, revisions will be grafted even if they
3550 If --force is specified, revisions will be grafted even if they
3550 are already ancestors of or have been grafted to the destination.
3551 are already ancestors of or have been grafted to the destination.
3551 This is useful when the revisions have since been backed out.
3552 This is useful when the revisions have since been backed out.
3552
3553
3553 If a graft merge results in conflicts, the graft process is
3554 If a graft merge results in conflicts, the graft process is
3554 interrupted so that the current merge can be manually resolved.
3555 interrupted so that the current merge can be manually resolved.
3555 Once all conflicts are addressed, the graft process can be
3556 Once all conflicts are addressed, the graft process can be
3556 continued with the -c/--continue option.
3557 continued with the -c/--continue option.
3557
3558
3558 .. note::
3559 .. note::
3559
3560
3560 The -c/--continue option does not reapply earlier options, except
3561 The -c/--continue option does not reapply earlier options, except
3561 for --force.
3562 for --force.
3562
3563
3563 .. container:: verbose
3564 .. container:: verbose
3564
3565
3565 Examples:
3566 Examples:
3566
3567
3567 - copy a single change to the stable branch and edit its description::
3568 - copy a single change to the stable branch and edit its description::
3568
3569
3569 hg update stable
3570 hg update stable
3570 hg graft --edit 9393
3571 hg graft --edit 9393
3571
3572
3572 - graft a range of changesets with one exception, updating dates::
3573 - graft a range of changesets with one exception, updating dates::
3573
3574
3574 hg graft -D "2085::2093 and not 2091"
3575 hg graft -D "2085::2093 and not 2091"
3575
3576
3576 - continue a graft after resolving conflicts::
3577 - continue a graft after resolving conflicts::
3577
3578
3578 hg graft -c
3579 hg graft -c
3579
3580
3580 - show the source of a grafted changeset::
3581 - show the source of a grafted changeset::
3581
3582
3582 hg log --debug -r .
3583 hg log --debug -r .
3583
3584
3584 See :hg:`help revisions` and :hg:`help revsets` for more about
3585 See :hg:`help revisions` and :hg:`help revsets` for more about
3585 specifying revisions.
3586 specifying revisions.
3586
3587
3587 Returns 0 on successful completion.
3588 Returns 0 on successful completion.
3588 '''
3589 '''
3589
3590
3590 revs = list(revs)
3591 revs = list(revs)
3591 revs.extend(opts['rev'])
3592 revs.extend(opts['rev'])
3592
3593
3593 if not opts.get('user') and opts.get('currentuser'):
3594 if not opts.get('user') and opts.get('currentuser'):
3594 opts['user'] = ui.username()
3595 opts['user'] = ui.username()
3595 if not opts.get('date') and opts.get('currentdate'):
3596 if not opts.get('date') and opts.get('currentdate'):
3596 opts['date'] = "%d %d" % util.makedate()
3597 opts['date'] = "%d %d" % util.makedate()
3597
3598
3598 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3599 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3599
3600
3600 cont = False
3601 cont = False
3601 if opts['continue']:
3602 if opts['continue']:
3602 cont = True
3603 cont = True
3603 if revs:
3604 if revs:
3604 raise util.Abort(_("can't specify --continue and revisions"))
3605 raise util.Abort(_("can't specify --continue and revisions"))
3605 # read in unfinished revisions
3606 # read in unfinished revisions
3606 try:
3607 try:
3607 nodes = repo.vfs.read('graftstate').splitlines()
3608 nodes = repo.vfs.read('graftstate').splitlines()
3608 revs = [repo[node].rev() for node in nodes]
3609 revs = [repo[node].rev() for node in nodes]
3609 except IOError as inst:
3610 except IOError as inst:
3610 if inst.errno != errno.ENOENT:
3611 if inst.errno != errno.ENOENT:
3611 raise
3612 raise
3612 raise util.Abort(_("no graft state found, can't continue"))
3613 raise util.Abort(_("no graft state found, can't continue"))
3613 else:
3614 else:
3614 cmdutil.checkunfinished(repo)
3615 cmdutil.checkunfinished(repo)
3615 cmdutil.bailifchanged(repo)
3616 cmdutil.bailifchanged(repo)
3616 if not revs:
3617 if not revs:
3617 raise util.Abort(_('no revisions specified'))
3618 raise util.Abort(_('no revisions specified'))
3618 revs = scmutil.revrange(repo, revs)
3619 revs = scmutil.revrange(repo, revs)
3619
3620
3620 skipped = set()
3621 skipped = set()
3621 # check for merges
3622 # check for merges
3622 for rev in repo.revs('%ld and merge()', revs):
3623 for rev in repo.revs('%ld and merge()', revs):
3623 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3624 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3624 skipped.add(rev)
3625 skipped.add(rev)
3625 revs = [r for r in revs if r not in skipped]
3626 revs = [r for r in revs if r not in skipped]
3626 if not revs:
3627 if not revs:
3627 return -1
3628 return -1
3628
3629
3629 # Don't check in the --continue case, in effect retaining --force across
3630 # Don't check in the --continue case, in effect retaining --force across
3630 # --continues. That's because without --force, any revisions we decided to
3631 # --continues. That's because without --force, any revisions we decided to
3631 # skip would have been filtered out here, so they wouldn't have made their
3632 # skip would have been filtered out here, so they wouldn't have made their
3632 # way to the graftstate. With --force, any revisions we would have otherwise
3633 # way to the graftstate. With --force, any revisions we would have otherwise
3633 # skipped would not have been filtered out, and if they hadn't been applied
3634 # skipped would not have been filtered out, and if they hadn't been applied
3634 # already, they'd have been in the graftstate.
3635 # already, they'd have been in the graftstate.
3635 if not (cont or opts.get('force')):
3636 if not (cont or opts.get('force')):
3636 # check for ancestors of dest branch
3637 # check for ancestors of dest branch
3637 crev = repo['.'].rev()
3638 crev = repo['.'].rev()
3638 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3639 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3639 # Cannot use x.remove(y) on smart set, this has to be a list.
3640 # Cannot use x.remove(y) on smart set, this has to be a list.
3640 # XXX make this lazy in the future
3641 # XXX make this lazy in the future
3641 revs = list(revs)
3642 revs = list(revs)
3642 # don't mutate while iterating, create a copy
3643 # don't mutate while iterating, create a copy
3643 for rev in list(revs):
3644 for rev in list(revs):
3644 if rev in ancestors:
3645 if rev in ancestors:
3645 ui.warn(_('skipping ancestor revision %d:%s\n') %
3646 ui.warn(_('skipping ancestor revision %d:%s\n') %
3646 (rev, repo[rev]))
3647 (rev, repo[rev]))
3647 # XXX remove on list is slow
3648 # XXX remove on list is slow
3648 revs.remove(rev)
3649 revs.remove(rev)
3649 if not revs:
3650 if not revs:
3650 return -1
3651 return -1
3651
3652
3652 # analyze revs for earlier grafts
3653 # analyze revs for earlier grafts
3653 ids = {}
3654 ids = {}
3654 for ctx in repo.set("%ld", revs):
3655 for ctx in repo.set("%ld", revs):
3655 ids[ctx.hex()] = ctx.rev()
3656 ids[ctx.hex()] = ctx.rev()
3656 n = ctx.extra().get('source')
3657 n = ctx.extra().get('source')
3657 if n:
3658 if n:
3658 ids[n] = ctx.rev()
3659 ids[n] = ctx.rev()
3659
3660
3660 # check ancestors for earlier grafts
3661 # check ancestors for earlier grafts
3661 ui.debug('scanning for duplicate grafts\n')
3662 ui.debug('scanning for duplicate grafts\n')
3662
3663
3663 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3664 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3664 ctx = repo[rev]
3665 ctx = repo[rev]
3665 n = ctx.extra().get('source')
3666 n = ctx.extra().get('source')
3666 if n in ids:
3667 if n in ids:
3667 try:
3668 try:
3668 r = repo[n].rev()
3669 r = repo[n].rev()
3669 except error.RepoLookupError:
3670 except error.RepoLookupError:
3670 r = None
3671 r = None
3671 if r in revs:
3672 if r in revs:
3672 ui.warn(_('skipping revision %d:%s '
3673 ui.warn(_('skipping revision %d:%s '
3673 '(already grafted to %d:%s)\n')
3674 '(already grafted to %d:%s)\n')
3674 % (r, repo[r], rev, ctx))
3675 % (r, repo[r], rev, ctx))
3675 revs.remove(r)
3676 revs.remove(r)
3676 elif ids[n] in revs:
3677 elif ids[n] in revs:
3677 if r is None:
3678 if r is None:
3678 ui.warn(_('skipping already grafted revision %d:%s '
3679 ui.warn(_('skipping already grafted revision %d:%s '
3679 '(%d:%s also has unknown origin %s)\n')
3680 '(%d:%s also has unknown origin %s)\n')
3680 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3681 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3681 else:
3682 else:
3682 ui.warn(_('skipping already grafted revision %d:%s '
3683 ui.warn(_('skipping already grafted revision %d:%s '
3683 '(%d:%s also has origin %d:%s)\n')
3684 '(%d:%s also has origin %d:%s)\n')
3684 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3685 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3685 revs.remove(ids[n])
3686 revs.remove(ids[n])
3686 elif ctx.hex() in ids:
3687 elif ctx.hex() in ids:
3687 r = ids[ctx.hex()]
3688 r = ids[ctx.hex()]
3688 ui.warn(_('skipping already grafted revision %d:%s '
3689 ui.warn(_('skipping already grafted revision %d:%s '
3689 '(was grafted from %d:%s)\n') %
3690 '(was grafted from %d:%s)\n') %
3690 (r, repo[r], rev, ctx))
3691 (r, repo[r], rev, ctx))
3691 revs.remove(r)
3692 revs.remove(r)
3692 if not revs:
3693 if not revs:
3693 return -1
3694 return -1
3694
3695
3695 wlock = repo.wlock()
3696 wlock = repo.wlock()
3696 try:
3697 try:
3697 for pos, ctx in enumerate(repo.set("%ld", revs)):
3698 for pos, ctx in enumerate(repo.set("%ld", revs)):
3698 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3699 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3699 ctx.description().split('\n', 1)[0])
3700 ctx.description().split('\n', 1)[0])
3700 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3701 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3701 if names:
3702 if names:
3702 desc += ' (%s)' % ' '.join(names)
3703 desc += ' (%s)' % ' '.join(names)
3703 ui.status(_('grafting %s\n') % desc)
3704 ui.status(_('grafting %s\n') % desc)
3704 if opts.get('dry_run'):
3705 if opts.get('dry_run'):
3705 continue
3706 continue
3706
3707
3707 source = ctx.extra().get('source')
3708 source = ctx.extra().get('source')
3708 extra = {}
3709 extra = {}
3709 if source:
3710 if source:
3710 extra['source'] = source
3711 extra['source'] = source
3711 extra['intermediate-source'] = ctx.hex()
3712 extra['intermediate-source'] = ctx.hex()
3712 else:
3713 else:
3713 extra['source'] = ctx.hex()
3714 extra['source'] = ctx.hex()
3714 user = ctx.user()
3715 user = ctx.user()
3715 if opts.get('user'):
3716 if opts.get('user'):
3716 user = opts['user']
3717 user = opts['user']
3717 date = ctx.date()
3718 date = ctx.date()
3718 if opts.get('date'):
3719 if opts.get('date'):
3719 date = opts['date']
3720 date = opts['date']
3720 message = ctx.description()
3721 message = ctx.description()
3721 if opts.get('log'):
3722 if opts.get('log'):
3722 message += '\n(grafted from %s)' % ctx.hex()
3723 message += '\n(grafted from %s)' % ctx.hex()
3723
3724
3724 # we don't merge the first commit when continuing
3725 # we don't merge the first commit when continuing
3725 if not cont:
3726 if not cont:
3726 # perform the graft merge with p1(rev) as 'ancestor'
3727 # perform the graft merge with p1(rev) as 'ancestor'
3727 try:
3728 try:
3728 # ui.forcemerge is an internal variable, do not document
3729 # ui.forcemerge is an internal variable, do not document
3729 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3730 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3730 'graft')
3731 'graft')
3731 stats = mergemod.graft(repo, ctx, ctx.p1(),
3732 stats = mergemod.graft(repo, ctx, ctx.p1(),
3732 ['local', 'graft'])
3733 ['local', 'graft'])
3733 finally:
3734 finally:
3734 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3735 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3735 # report any conflicts
3736 # report any conflicts
3736 if stats and stats[3] > 0:
3737 if stats and stats[3] > 0:
3737 # write out state for --continue
3738 # write out state for --continue
3738 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3739 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3739 repo.vfs.write('graftstate', ''.join(nodelines))
3740 repo.vfs.write('graftstate', ''.join(nodelines))
3740 raise util.Abort(
3741 raise util.Abort(
3741 _("unresolved conflicts, can't continue"),
3742 _("unresolved conflicts, can't continue"),
3742 hint=_('use hg resolve and hg graft --continue'))
3743 hint=_('use hg resolve and hg graft --continue'))
3743 else:
3744 else:
3744 cont = False
3745 cont = False
3745
3746
3746 # commit
3747 # commit
3747 node = repo.commit(text=message, user=user,
3748 node = repo.commit(text=message, user=user,
3748 date=date, extra=extra, editor=editor)
3749 date=date, extra=extra, editor=editor)
3749 if node is None:
3750 if node is None:
3750 ui.warn(
3751 ui.warn(
3751 _('note: graft of %d:%s created no changes to commit\n') %
3752 _('note: graft of %d:%s created no changes to commit\n') %
3752 (ctx.rev(), ctx))
3753 (ctx.rev(), ctx))
3753 finally:
3754 finally:
3754 wlock.release()
3755 wlock.release()
3755
3756
3756 # remove state when we complete successfully
3757 # remove state when we complete successfully
3757 if not opts.get('dry_run'):
3758 if not opts.get('dry_run'):
3758 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3759 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3759
3760
3760 return 0
3761 return 0
3761
3762
3762 @command('grep',
3763 @command('grep',
3763 [('0', 'print0', None, _('end fields with NUL')),
3764 [('0', 'print0', None, _('end fields with NUL')),
3764 ('', 'all', None, _('print all revisions that match')),
3765 ('', 'all', None, _('print all revisions that match')),
3765 ('a', 'text', None, _('treat all files as text')),
3766 ('a', 'text', None, _('treat all files as text')),
3766 ('f', 'follow', None,
3767 ('f', 'follow', None,
3767 _('follow changeset history,'
3768 _('follow changeset history,'
3768 ' or file history across copies and renames')),
3769 ' or file history across copies and renames')),
3769 ('i', 'ignore-case', None, _('ignore case when matching')),
3770 ('i', 'ignore-case', None, _('ignore case when matching')),
3770 ('l', 'files-with-matches', None,
3771 ('l', 'files-with-matches', None,
3771 _('print only filenames and revisions that match')),
3772 _('print only filenames and revisions that match')),
3772 ('n', 'line-number', None, _('print matching line numbers')),
3773 ('n', 'line-number', None, _('print matching line numbers')),
3773 ('r', 'rev', [],
3774 ('r', 'rev', [],
3774 _('only search files changed within revision range'), _('REV')),
3775 _('only search files changed within revision range'), _('REV')),
3775 ('u', 'user', None, _('list the author (long with -v)')),
3776 ('u', 'user', None, _('list the author (long with -v)')),
3776 ('d', 'date', None, _('list the date (short with -q)')),
3777 ('d', 'date', None, _('list the date (short with -q)')),
3777 ] + walkopts,
3778 ] + walkopts,
3778 _('[OPTION]... PATTERN [FILE]...'),
3779 _('[OPTION]... PATTERN [FILE]...'),
3779 inferrepo=True)
3780 inferrepo=True)
3780 def grep(ui, repo, pattern, *pats, **opts):
3781 def grep(ui, repo, pattern, *pats, **opts):
3781 """search for a pattern in specified files and revisions
3782 """search for a pattern in specified files and revisions
3782
3783
3783 Search revisions of files for a regular expression.
3784 Search revisions of files for a regular expression.
3784
3785
3785 This command behaves differently than Unix grep. It only accepts
3786 This command behaves differently than Unix grep. It only accepts
3786 Python/Perl regexps. It searches repository history, not the
3787 Python/Perl regexps. It searches repository history, not the
3787 working directory. It always prints the revision number in which a
3788 working directory. It always prints the revision number in which a
3788 match appears.
3789 match appears.
3789
3790
3790 By default, grep only prints output for the first revision of a
3791 By default, grep only prints output for the first revision of a
3791 file in which it finds a match. To get it to print every revision
3792 file in which it finds a match. To get it to print every revision
3792 that contains a change in match status ("-" for a match that
3793 that contains a change in match status ("-" for a match that
3793 becomes a non-match, or "+" for a non-match that becomes a match),
3794 becomes a non-match, or "+" for a non-match that becomes a match),
3794 use the --all flag.
3795 use the --all flag.
3795
3796
3796 Returns 0 if a match is found, 1 otherwise.
3797 Returns 0 if a match is found, 1 otherwise.
3797 """
3798 """
3798 reflags = re.M
3799 reflags = re.M
3799 if opts.get('ignore_case'):
3800 if opts.get('ignore_case'):
3800 reflags |= re.I
3801 reflags |= re.I
3801 try:
3802 try:
3802 regexp = util.re.compile(pattern, reflags)
3803 regexp = util.re.compile(pattern, reflags)
3803 except re.error as inst:
3804 except re.error as inst:
3804 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3805 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3805 return 1
3806 return 1
3806 sep, eol = ':', '\n'
3807 sep, eol = ':', '\n'
3807 if opts.get('print0'):
3808 if opts.get('print0'):
3808 sep = eol = '\0'
3809 sep = eol = '\0'
3809
3810
3810 getfile = util.lrucachefunc(repo.file)
3811 getfile = util.lrucachefunc(repo.file)
3811
3812
3812 def matchlines(body):
3813 def matchlines(body):
3813 begin = 0
3814 begin = 0
3814 linenum = 0
3815 linenum = 0
3815 while begin < len(body):
3816 while begin < len(body):
3816 match = regexp.search(body, begin)
3817 match = regexp.search(body, begin)
3817 if not match:
3818 if not match:
3818 break
3819 break
3819 mstart, mend = match.span()
3820 mstart, mend = match.span()
3820 linenum += body.count('\n', begin, mstart) + 1
3821 linenum += body.count('\n', begin, mstart) + 1
3821 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3822 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3822 begin = body.find('\n', mend) + 1 or len(body) + 1
3823 begin = body.find('\n', mend) + 1 or len(body) + 1
3823 lend = begin - 1
3824 lend = begin - 1
3824 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3825 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3825
3826
3826 class linestate(object):
3827 class linestate(object):
3827 def __init__(self, line, linenum, colstart, colend):
3828 def __init__(self, line, linenum, colstart, colend):
3828 self.line = line
3829 self.line = line
3829 self.linenum = linenum
3830 self.linenum = linenum
3830 self.colstart = colstart
3831 self.colstart = colstart
3831 self.colend = colend
3832 self.colend = colend
3832
3833
3833 def __hash__(self):
3834 def __hash__(self):
3834 return hash((self.linenum, self.line))
3835 return hash((self.linenum, self.line))
3835
3836
3836 def __eq__(self, other):
3837 def __eq__(self, other):
3837 return self.line == other.line
3838 return self.line == other.line
3838
3839
3839 def __iter__(self):
3840 def __iter__(self):
3840 yield (self.line[:self.colstart], '')
3841 yield (self.line[:self.colstart], '')
3841 yield (self.line[self.colstart:self.colend], 'grep.match')
3842 yield (self.line[self.colstart:self.colend], 'grep.match')
3842 rest = self.line[self.colend:]
3843 rest = self.line[self.colend:]
3843 while rest != '':
3844 while rest != '':
3844 match = regexp.search(rest)
3845 match = regexp.search(rest)
3845 if not match:
3846 if not match:
3846 yield (rest, '')
3847 yield (rest, '')
3847 break
3848 break
3848 mstart, mend = match.span()
3849 mstart, mend = match.span()
3849 yield (rest[:mstart], '')
3850 yield (rest[:mstart], '')
3850 yield (rest[mstart:mend], 'grep.match')
3851 yield (rest[mstart:mend], 'grep.match')
3851 rest = rest[mend:]
3852 rest = rest[mend:]
3852
3853
3853 matches = {}
3854 matches = {}
3854 copies = {}
3855 copies = {}
3855 def grepbody(fn, rev, body):
3856 def grepbody(fn, rev, body):
3856 matches[rev].setdefault(fn, [])
3857 matches[rev].setdefault(fn, [])
3857 m = matches[rev][fn]
3858 m = matches[rev][fn]
3858 for lnum, cstart, cend, line in matchlines(body):
3859 for lnum, cstart, cend, line in matchlines(body):
3859 s = linestate(line, lnum, cstart, cend)
3860 s = linestate(line, lnum, cstart, cend)
3860 m.append(s)
3861 m.append(s)
3861
3862
3862 def difflinestates(a, b):
3863 def difflinestates(a, b):
3863 sm = difflib.SequenceMatcher(None, a, b)
3864 sm = difflib.SequenceMatcher(None, a, b)
3864 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3865 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3865 if tag == 'insert':
3866 if tag == 'insert':
3866 for i in xrange(blo, bhi):
3867 for i in xrange(blo, bhi):
3867 yield ('+', b[i])
3868 yield ('+', b[i])
3868 elif tag == 'delete':
3869 elif tag == 'delete':
3869 for i in xrange(alo, ahi):
3870 for i in xrange(alo, ahi):
3870 yield ('-', a[i])
3871 yield ('-', a[i])
3871 elif tag == 'replace':
3872 elif tag == 'replace':
3872 for i in xrange(alo, ahi):
3873 for i in xrange(alo, ahi):
3873 yield ('-', a[i])
3874 yield ('-', a[i])
3874 for i in xrange(blo, bhi):
3875 for i in xrange(blo, bhi):
3875 yield ('+', b[i])
3876 yield ('+', b[i])
3876
3877
3877 def display(fn, ctx, pstates, states):
3878 def display(fn, ctx, pstates, states):
3878 rev = ctx.rev()
3879 rev = ctx.rev()
3879 if ui.quiet:
3880 if ui.quiet:
3880 datefunc = util.shortdate
3881 datefunc = util.shortdate
3881 else:
3882 else:
3882 datefunc = util.datestr
3883 datefunc = util.datestr
3883 found = False
3884 found = False
3884 @util.cachefunc
3885 @util.cachefunc
3885 def binary():
3886 def binary():
3886 flog = getfile(fn)
3887 flog = getfile(fn)
3887 return util.binary(flog.read(ctx.filenode(fn)))
3888 return util.binary(flog.read(ctx.filenode(fn)))
3888
3889
3889 if opts.get('all'):
3890 if opts.get('all'):
3890 iter = difflinestates(pstates, states)
3891 iter = difflinestates(pstates, states)
3891 else:
3892 else:
3892 iter = [('', l) for l in states]
3893 iter = [('', l) for l in states]
3893 for change, l in iter:
3894 for change, l in iter:
3894 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3895 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3895
3896
3896 if opts.get('line_number'):
3897 if opts.get('line_number'):
3897 cols.append((str(l.linenum), 'grep.linenumber'))
3898 cols.append((str(l.linenum), 'grep.linenumber'))
3898 if opts.get('all'):
3899 if opts.get('all'):
3899 cols.append((change, 'grep.change'))
3900 cols.append((change, 'grep.change'))
3900 if opts.get('user'):
3901 if opts.get('user'):
3901 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3902 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3902 if opts.get('date'):
3903 if opts.get('date'):
3903 cols.append((datefunc(ctx.date()), 'grep.date'))
3904 cols.append((datefunc(ctx.date()), 'grep.date'))
3904 for col, label in cols[:-1]:
3905 for col, label in cols[:-1]:
3905 ui.write(col, label=label)
3906 ui.write(col, label=label)
3906 ui.write(sep, label='grep.sep')
3907 ui.write(sep, label='grep.sep')
3907 ui.write(cols[-1][0], label=cols[-1][1])
3908 ui.write(cols[-1][0], label=cols[-1][1])
3908 if not opts.get('files_with_matches'):
3909 if not opts.get('files_with_matches'):
3909 ui.write(sep, label='grep.sep')
3910 ui.write(sep, label='grep.sep')
3910 if not opts.get('text') and binary():
3911 if not opts.get('text') and binary():
3911 ui.write(" Binary file matches")
3912 ui.write(" Binary file matches")
3912 else:
3913 else:
3913 for s, label in l:
3914 for s, label in l:
3914 ui.write(s, label=label)
3915 ui.write(s, label=label)
3915 ui.write(eol)
3916 ui.write(eol)
3916 found = True
3917 found = True
3917 if opts.get('files_with_matches'):
3918 if opts.get('files_with_matches'):
3918 break
3919 break
3919 return found
3920 return found
3920
3921
3921 skip = {}
3922 skip = {}
3922 revfiles = {}
3923 revfiles = {}
3923 matchfn = scmutil.match(repo[None], pats, opts)
3924 matchfn = scmutil.match(repo[None], pats, opts)
3924 found = False
3925 found = False
3925 follow = opts.get('follow')
3926 follow = opts.get('follow')
3926
3927
3927 def prep(ctx, fns):
3928 def prep(ctx, fns):
3928 rev = ctx.rev()
3929 rev = ctx.rev()
3929 pctx = ctx.p1()
3930 pctx = ctx.p1()
3930 parent = pctx.rev()
3931 parent = pctx.rev()
3931 matches.setdefault(rev, {})
3932 matches.setdefault(rev, {})
3932 matches.setdefault(parent, {})
3933 matches.setdefault(parent, {})
3933 files = revfiles.setdefault(rev, [])
3934 files = revfiles.setdefault(rev, [])
3934 for fn in fns:
3935 for fn in fns:
3935 flog = getfile(fn)
3936 flog = getfile(fn)
3936 try:
3937 try:
3937 fnode = ctx.filenode(fn)
3938 fnode = ctx.filenode(fn)
3938 except error.LookupError:
3939 except error.LookupError:
3939 continue
3940 continue
3940
3941
3941 copied = flog.renamed(fnode)
3942 copied = flog.renamed(fnode)
3942 copy = follow and copied and copied[0]
3943 copy = follow and copied and copied[0]
3943 if copy:
3944 if copy:
3944 copies.setdefault(rev, {})[fn] = copy
3945 copies.setdefault(rev, {})[fn] = copy
3945 if fn in skip:
3946 if fn in skip:
3946 if copy:
3947 if copy:
3947 skip[copy] = True
3948 skip[copy] = True
3948 continue
3949 continue
3949 files.append(fn)
3950 files.append(fn)
3950
3951
3951 if fn not in matches[rev]:
3952 if fn not in matches[rev]:
3952 grepbody(fn, rev, flog.read(fnode))
3953 grepbody(fn, rev, flog.read(fnode))
3953
3954
3954 pfn = copy or fn
3955 pfn = copy or fn
3955 if pfn not in matches[parent]:
3956 if pfn not in matches[parent]:
3956 try:
3957 try:
3957 fnode = pctx.filenode(pfn)
3958 fnode = pctx.filenode(pfn)
3958 grepbody(pfn, parent, flog.read(fnode))
3959 grepbody(pfn, parent, flog.read(fnode))
3959 except error.LookupError:
3960 except error.LookupError:
3960 pass
3961 pass
3961
3962
3962 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3963 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3963 rev = ctx.rev()
3964 rev = ctx.rev()
3964 parent = ctx.p1().rev()
3965 parent = ctx.p1().rev()
3965 for fn in sorted(revfiles.get(rev, [])):
3966 for fn in sorted(revfiles.get(rev, [])):
3966 states = matches[rev][fn]
3967 states = matches[rev][fn]
3967 copy = copies.get(rev, {}).get(fn)
3968 copy = copies.get(rev, {}).get(fn)
3968 if fn in skip:
3969 if fn in skip:
3969 if copy:
3970 if copy:
3970 skip[copy] = True
3971 skip[copy] = True
3971 continue
3972 continue
3972 pstates = matches.get(parent, {}).get(copy or fn, [])
3973 pstates = matches.get(parent, {}).get(copy or fn, [])
3973 if pstates or states:
3974 if pstates or states:
3974 r = display(fn, ctx, pstates, states)
3975 r = display(fn, ctx, pstates, states)
3975 found = found or r
3976 found = found or r
3976 if r and not opts.get('all'):
3977 if r and not opts.get('all'):
3977 skip[fn] = True
3978 skip[fn] = True
3978 if copy:
3979 if copy:
3979 skip[copy] = True
3980 skip[copy] = True
3980 del matches[rev]
3981 del matches[rev]
3981 del revfiles[rev]
3982 del revfiles[rev]
3982
3983
3983 return not found
3984 return not found
3984
3985
3985 @command('heads',
3986 @command('heads',
3986 [('r', 'rev', '',
3987 [('r', 'rev', '',
3987 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3988 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3988 ('t', 'topo', False, _('show topological heads only')),
3989 ('t', 'topo', False, _('show topological heads only')),
3989 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3990 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3990 ('c', 'closed', False, _('show normal and closed branch heads')),
3991 ('c', 'closed', False, _('show normal and closed branch heads')),
3991 ] + templateopts,
3992 ] + templateopts,
3992 _('[-ct] [-r STARTREV] [REV]...'))
3993 _('[-ct] [-r STARTREV] [REV]...'))
3993 def heads(ui, repo, *branchrevs, **opts):
3994 def heads(ui, repo, *branchrevs, **opts):
3994 """show branch heads
3995 """show branch heads
3995
3996
3996 With no arguments, show all open branch heads in the repository.
3997 With no arguments, show all open branch heads in the repository.
3997 Branch heads are changesets that have no descendants on the
3998 Branch heads are changesets that have no descendants on the
3998 same branch. They are where development generally takes place and
3999 same branch. They are where development generally takes place and
3999 are the usual targets for update and merge operations.
4000 are the usual targets for update and merge operations.
4000
4001
4001 If one or more REVs are given, only open branch heads on the
4002 If one or more REVs are given, only open branch heads on the
4002 branches associated with the specified changesets are shown. This
4003 branches associated with the specified changesets are shown. This
4003 means that you can use :hg:`heads .` to see the heads on the
4004 means that you can use :hg:`heads .` to see the heads on the
4004 currently checked-out branch.
4005 currently checked-out branch.
4005
4006
4006 If -c/--closed is specified, also show branch heads marked closed
4007 If -c/--closed is specified, also show branch heads marked closed
4007 (see :hg:`commit --close-branch`).
4008 (see :hg:`commit --close-branch`).
4008
4009
4009 If STARTREV is specified, only those heads that are descendants of
4010 If STARTREV is specified, only those heads that are descendants of
4010 STARTREV will be displayed.
4011 STARTREV will be displayed.
4011
4012
4012 If -t/--topo is specified, named branch mechanics will be ignored and only
4013 If -t/--topo is specified, named branch mechanics will be ignored and only
4013 topological heads (changesets with no children) will be shown.
4014 topological heads (changesets with no children) will be shown.
4014
4015
4015 Returns 0 if matching heads are found, 1 if not.
4016 Returns 0 if matching heads are found, 1 if not.
4016 """
4017 """
4017
4018
4018 start = None
4019 start = None
4019 if 'rev' in opts:
4020 if 'rev' in opts:
4020 start = scmutil.revsingle(repo, opts['rev'], None).node()
4021 start = scmutil.revsingle(repo, opts['rev'], None).node()
4021
4022
4022 if opts.get('topo'):
4023 if opts.get('topo'):
4023 heads = [repo[h] for h in repo.heads(start)]
4024 heads = [repo[h] for h in repo.heads(start)]
4024 else:
4025 else:
4025 heads = []
4026 heads = []
4026 for branch in repo.branchmap():
4027 for branch in repo.branchmap():
4027 heads += repo.branchheads(branch, start, opts.get('closed'))
4028 heads += repo.branchheads(branch, start, opts.get('closed'))
4028 heads = [repo[h] for h in heads]
4029 heads = [repo[h] for h in heads]
4029
4030
4030 if branchrevs:
4031 if branchrevs:
4031 branches = set(repo[br].branch() for br in branchrevs)
4032 branches = set(repo[br].branch() for br in branchrevs)
4032 heads = [h for h in heads if h.branch() in branches]
4033 heads = [h for h in heads if h.branch() in branches]
4033
4034
4034 if opts.get('active') and branchrevs:
4035 if opts.get('active') and branchrevs:
4035 dagheads = repo.heads(start)
4036 dagheads = repo.heads(start)
4036 heads = [h for h in heads if h.node() in dagheads]
4037 heads = [h for h in heads if h.node() in dagheads]
4037
4038
4038 if branchrevs:
4039 if branchrevs:
4039 haveheads = set(h.branch() for h in heads)
4040 haveheads = set(h.branch() for h in heads)
4040 if branches - haveheads:
4041 if branches - haveheads:
4041 headless = ', '.join(b for b in branches - haveheads)
4042 headless = ', '.join(b for b in branches - haveheads)
4042 msg = _('no open branch heads found on branches %s')
4043 msg = _('no open branch heads found on branches %s')
4043 if opts.get('rev'):
4044 if opts.get('rev'):
4044 msg += _(' (started at %s)') % opts['rev']
4045 msg += _(' (started at %s)') % opts['rev']
4045 ui.warn((msg + '\n') % headless)
4046 ui.warn((msg + '\n') % headless)
4046
4047
4047 if not heads:
4048 if not heads:
4048 return 1
4049 return 1
4049
4050
4050 heads = sorted(heads, key=lambda x: -x.rev())
4051 heads = sorted(heads, key=lambda x: -x.rev())
4051 displayer = cmdutil.show_changeset(ui, repo, opts)
4052 displayer = cmdutil.show_changeset(ui, repo, opts)
4052 for ctx in heads:
4053 for ctx in heads:
4053 displayer.show(ctx)
4054 displayer.show(ctx)
4054 displayer.close()
4055 displayer.close()
4055
4056
4056 @command('help',
4057 @command('help',
4057 [('e', 'extension', None, _('show only help for extensions')),
4058 [('e', 'extension', None, _('show only help for extensions')),
4058 ('c', 'command', None, _('show only help for commands')),
4059 ('c', 'command', None, _('show only help for commands')),
4059 ('k', 'keyword', None, _('show topics matching keyword')),
4060 ('k', 'keyword', None, _('show topics matching keyword')),
4060 ],
4061 ],
4061 _('[-eck] [TOPIC]'),
4062 _('[-eck] [TOPIC]'),
4062 norepo=True)
4063 norepo=True)
4063 def help_(ui, name=None, **opts):
4064 def help_(ui, name=None, **opts):
4064 """show help for a given topic or a help overview
4065 """show help for a given topic or a help overview
4065
4066
4066 With no arguments, print a list of commands with short help messages.
4067 With no arguments, print a list of commands with short help messages.
4067
4068
4068 Given a topic, extension, or command name, print help for that
4069 Given a topic, extension, or command name, print help for that
4069 topic.
4070 topic.
4070
4071
4071 Returns 0 if successful.
4072 Returns 0 if successful.
4072 """
4073 """
4073
4074
4074 textwidth = min(ui.termwidth(), 80) - 2
4075 textwidth = min(ui.termwidth(), 80) - 2
4075
4076
4076 keep = []
4077 keep = []
4077 if ui.verbose:
4078 if ui.verbose:
4078 keep.append('verbose')
4079 keep.append('verbose')
4079 if sys.platform.startswith('win'):
4080 if sys.platform.startswith('win'):
4080 keep.append('windows')
4081 keep.append('windows')
4081 elif sys.platform == 'OpenVMS':
4082 elif sys.platform == 'OpenVMS':
4082 keep.append('vms')
4083 keep.append('vms')
4083 elif sys.platform == 'plan9':
4084 elif sys.platform == 'plan9':
4084 keep.append('plan9')
4085 keep.append('plan9')
4085 else:
4086 else:
4086 keep.append('unix')
4087 keep.append('unix')
4087 keep.append(sys.platform.lower())
4088 keep.append(sys.platform.lower())
4088
4089
4089 section = None
4090 section = None
4090 if name and '.' in name:
4091 if name and '.' in name:
4091 name, section = name.split('.', 1)
4092 name, section = name.split('.', 1)
4092 section = section.lower()
4093 section = section.lower()
4093
4094
4094 text = help.help_(ui, name, **opts)
4095 text = help.help_(ui, name, **opts)
4095
4096
4096 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4097 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4097 section=section)
4098 section=section)
4098
4099
4099 # We could have been given a weird ".foo" section without a name
4100 # We could have been given a weird ".foo" section without a name
4100 # to look for, or we could have simply failed to found "foo.bar"
4101 # to look for, or we could have simply failed to found "foo.bar"
4101 # because bar isn't a section of foo
4102 # because bar isn't a section of foo
4102 if section and not (formatted and name):
4103 if section and not (formatted and name):
4103 raise util.Abort(_("help section not found"))
4104 raise util.Abort(_("help section not found"))
4104
4105
4105 if 'verbose' in pruned:
4106 if 'verbose' in pruned:
4106 keep.append('omitted')
4107 keep.append('omitted')
4107 else:
4108 else:
4108 keep.append('notomitted')
4109 keep.append('notomitted')
4109 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4110 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4110 section=section)
4111 section=section)
4111 ui.write(formatted)
4112 ui.write(formatted)
4112
4113
4113
4114
4114 @command('identify|id',
4115 @command('identify|id',
4115 [('r', 'rev', '',
4116 [('r', 'rev', '',
4116 _('identify the specified revision'), _('REV')),
4117 _('identify the specified revision'), _('REV')),
4117 ('n', 'num', None, _('show local revision number')),
4118 ('n', 'num', None, _('show local revision number')),
4118 ('i', 'id', None, _('show global revision id')),
4119 ('i', 'id', None, _('show global revision id')),
4119 ('b', 'branch', None, _('show branch')),
4120 ('b', 'branch', None, _('show branch')),
4120 ('t', 'tags', None, _('show tags')),
4121 ('t', 'tags', None, _('show tags')),
4121 ('B', 'bookmarks', None, _('show bookmarks')),
4122 ('B', 'bookmarks', None, _('show bookmarks')),
4122 ] + remoteopts,
4123 ] + remoteopts,
4123 _('[-nibtB] [-r REV] [SOURCE]'),
4124 _('[-nibtB] [-r REV] [SOURCE]'),
4124 optionalrepo=True)
4125 optionalrepo=True)
4125 def identify(ui, repo, source=None, rev=None,
4126 def identify(ui, repo, source=None, rev=None,
4126 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4127 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4127 """identify the working directory or specified revision
4128 """identify the working directory or specified revision
4128
4129
4129 Print a summary identifying the repository state at REV using one or
4130 Print a summary identifying the repository state at REV using one or
4130 two parent hash identifiers, followed by a "+" if the working
4131 two parent hash identifiers, followed by a "+" if the working
4131 directory has uncommitted changes, the branch name (if not default),
4132 directory has uncommitted changes, the branch name (if not default),
4132 a list of tags, and a list of bookmarks.
4133 a list of tags, and a list of bookmarks.
4133
4134
4134 When REV is not given, print a summary of the current state of the
4135 When REV is not given, print a summary of the current state of the
4135 repository.
4136 repository.
4136
4137
4137 Specifying a path to a repository root or Mercurial bundle will
4138 Specifying a path to a repository root or Mercurial bundle will
4138 cause lookup to operate on that repository/bundle.
4139 cause lookup to operate on that repository/bundle.
4139
4140
4140 .. container:: verbose
4141 .. container:: verbose
4141
4142
4142 Examples:
4143 Examples:
4143
4144
4144 - generate a build identifier for the working directory::
4145 - generate a build identifier for the working directory::
4145
4146
4146 hg id --id > build-id.dat
4147 hg id --id > build-id.dat
4147
4148
4148 - find the revision corresponding to a tag::
4149 - find the revision corresponding to a tag::
4149
4150
4150 hg id -n -r 1.3
4151 hg id -n -r 1.3
4151
4152
4152 - check the most recent revision of a remote repository::
4153 - check the most recent revision of a remote repository::
4153
4154
4154 hg id -r tip http://selenic.com/hg/
4155 hg id -r tip http://selenic.com/hg/
4155
4156
4156 Returns 0 if successful.
4157 Returns 0 if successful.
4157 """
4158 """
4158
4159
4159 if not repo and not source:
4160 if not repo and not source:
4160 raise util.Abort(_("there is no Mercurial repository here "
4161 raise util.Abort(_("there is no Mercurial repository here "
4161 "(.hg not found)"))
4162 "(.hg not found)"))
4162
4163
4163 if ui.debugflag:
4164 if ui.debugflag:
4164 hexfunc = hex
4165 hexfunc = hex
4165 else:
4166 else:
4166 hexfunc = short
4167 hexfunc = short
4167 default = not (num or id or branch or tags or bookmarks)
4168 default = not (num or id or branch or tags or bookmarks)
4168 output = []
4169 output = []
4169 revs = []
4170 revs = []
4170
4171
4171 if source:
4172 if source:
4172 source, branches = hg.parseurl(ui.expandpath(source))
4173 source, branches = hg.parseurl(ui.expandpath(source))
4173 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4174 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4174 repo = peer.local()
4175 repo = peer.local()
4175 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4176 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4176
4177
4177 if not repo:
4178 if not repo:
4178 if num or branch or tags:
4179 if num or branch or tags:
4179 raise util.Abort(
4180 raise util.Abort(
4180 _("can't query remote revision number, branch, or tags"))
4181 _("can't query remote revision number, branch, or tags"))
4181 if not rev and revs:
4182 if not rev and revs:
4182 rev = revs[0]
4183 rev = revs[0]
4183 if not rev:
4184 if not rev:
4184 rev = "tip"
4185 rev = "tip"
4185
4186
4186 remoterev = peer.lookup(rev)
4187 remoterev = peer.lookup(rev)
4187 if default or id:
4188 if default or id:
4188 output = [hexfunc(remoterev)]
4189 output = [hexfunc(remoterev)]
4189
4190
4190 def getbms():
4191 def getbms():
4191 bms = []
4192 bms = []
4192
4193
4193 if 'bookmarks' in peer.listkeys('namespaces'):
4194 if 'bookmarks' in peer.listkeys('namespaces'):
4194 hexremoterev = hex(remoterev)
4195 hexremoterev = hex(remoterev)
4195 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4196 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4196 if bmr == hexremoterev]
4197 if bmr == hexremoterev]
4197
4198
4198 return sorted(bms)
4199 return sorted(bms)
4199
4200
4200 if bookmarks:
4201 if bookmarks:
4201 output.extend(getbms())
4202 output.extend(getbms())
4202 elif default and not ui.quiet:
4203 elif default and not ui.quiet:
4203 # multiple bookmarks for a single parent separated by '/'
4204 # multiple bookmarks for a single parent separated by '/'
4204 bm = '/'.join(getbms())
4205 bm = '/'.join(getbms())
4205 if bm:
4206 if bm:
4206 output.append(bm)
4207 output.append(bm)
4207 else:
4208 else:
4208 ctx = scmutil.revsingle(repo, rev, None)
4209 ctx = scmutil.revsingle(repo, rev, None)
4209
4210
4210 if ctx.rev() is None:
4211 if ctx.rev() is None:
4211 ctx = repo[None]
4212 ctx = repo[None]
4212 parents = ctx.parents()
4213 parents = ctx.parents()
4213 taglist = []
4214 taglist = []
4214 for p in parents:
4215 for p in parents:
4215 taglist.extend(p.tags())
4216 taglist.extend(p.tags())
4216
4217
4217 changed = ""
4218 changed = ""
4218 if default or id or num:
4219 if default or id or num:
4219 if (any(repo.status())
4220 if (any(repo.status())
4220 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4221 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4221 changed = '+'
4222 changed = '+'
4222 if default or id:
4223 if default or id:
4223 output = ["%s%s" %
4224 output = ["%s%s" %
4224 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4225 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4225 if num:
4226 if num:
4226 output.append("%s%s" %
4227 output.append("%s%s" %
4227 ('+'.join([str(p.rev()) for p in parents]), changed))
4228 ('+'.join([str(p.rev()) for p in parents]), changed))
4228 else:
4229 else:
4229 if default or id:
4230 if default or id:
4230 output = [hexfunc(ctx.node())]
4231 output = [hexfunc(ctx.node())]
4231 if num:
4232 if num:
4232 output.append(str(ctx.rev()))
4233 output.append(str(ctx.rev()))
4233 taglist = ctx.tags()
4234 taglist = ctx.tags()
4234
4235
4235 if default and not ui.quiet:
4236 if default and not ui.quiet:
4236 b = ctx.branch()
4237 b = ctx.branch()
4237 if b != 'default':
4238 if b != 'default':
4238 output.append("(%s)" % b)
4239 output.append("(%s)" % b)
4239
4240
4240 # multiple tags for a single parent separated by '/'
4241 # multiple tags for a single parent separated by '/'
4241 t = '/'.join(taglist)
4242 t = '/'.join(taglist)
4242 if t:
4243 if t:
4243 output.append(t)
4244 output.append(t)
4244
4245
4245 # multiple bookmarks for a single parent separated by '/'
4246 # multiple bookmarks for a single parent separated by '/'
4246 bm = '/'.join(ctx.bookmarks())
4247 bm = '/'.join(ctx.bookmarks())
4247 if bm:
4248 if bm:
4248 output.append(bm)
4249 output.append(bm)
4249 else:
4250 else:
4250 if branch:
4251 if branch:
4251 output.append(ctx.branch())
4252 output.append(ctx.branch())
4252
4253
4253 if tags:
4254 if tags:
4254 output.extend(taglist)
4255 output.extend(taglist)
4255
4256
4256 if bookmarks:
4257 if bookmarks:
4257 output.extend(ctx.bookmarks())
4258 output.extend(ctx.bookmarks())
4258
4259
4259 ui.write("%s\n" % ' '.join(output))
4260 ui.write("%s\n" % ' '.join(output))
4260
4261
4261 @command('import|patch',
4262 @command('import|patch',
4262 [('p', 'strip', 1,
4263 [('p', 'strip', 1,
4263 _('directory strip option for patch. This has the same '
4264 _('directory strip option for patch. This has the same '
4264 'meaning as the corresponding patch option'), _('NUM')),
4265 'meaning as the corresponding patch option'), _('NUM')),
4265 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4266 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4266 ('e', 'edit', False, _('invoke editor on commit messages')),
4267 ('e', 'edit', False, _('invoke editor on commit messages')),
4267 ('f', 'force', None,
4268 ('f', 'force', None,
4268 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4269 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4269 ('', 'no-commit', None,
4270 ('', 'no-commit', None,
4270 _("don't commit, just update the working directory")),
4271 _("don't commit, just update the working directory")),
4271 ('', 'bypass', None,
4272 ('', 'bypass', None,
4272 _("apply patch without touching the working directory")),
4273 _("apply patch without touching the working directory")),
4273 ('', 'partial', None,
4274 ('', 'partial', None,
4274 _('commit even if some hunks fail')),
4275 _('commit even if some hunks fail')),
4275 ('', 'exact', None,
4276 ('', 'exact', None,
4276 _('apply patch to the nodes from which it was generated')),
4277 _('apply patch to the nodes from which it was generated')),
4277 ('', 'prefix', '',
4278 ('', 'prefix', '',
4278 _('apply patch to subdirectory'), _('DIR')),
4279 _('apply patch to subdirectory'), _('DIR')),
4279 ('', 'import-branch', None,
4280 ('', 'import-branch', None,
4280 _('use any branch information in patch (implied by --exact)'))] +
4281 _('use any branch information in patch (implied by --exact)'))] +
4281 commitopts + commitopts2 + similarityopts,
4282 commitopts + commitopts2 + similarityopts,
4282 _('[OPTION]... PATCH...'))
4283 _('[OPTION]... PATCH...'))
4283 def import_(ui, repo, patch1=None, *patches, **opts):
4284 def import_(ui, repo, patch1=None, *patches, **opts):
4284 """import an ordered set of patches
4285 """import an ordered set of patches
4285
4286
4286 Import a list of patches and commit them individually (unless
4287 Import a list of patches and commit them individually (unless
4287 --no-commit is specified).
4288 --no-commit is specified).
4288
4289
4289 Because import first applies changes to the working directory,
4290 Because import first applies changes to the working directory,
4290 import will abort if there are outstanding changes.
4291 import will abort if there are outstanding changes.
4291
4292
4292 You can import a patch straight from a mail message. Even patches
4293 You can import a patch straight from a mail message. Even patches
4293 as attachments work (to use the body part, it must have type
4294 as attachments work (to use the body part, it must have type
4294 text/plain or text/x-patch). From and Subject headers of email
4295 text/plain or text/x-patch). From and Subject headers of email
4295 message are used as default committer and commit message. All
4296 message are used as default committer and commit message. All
4296 text/plain body parts before first diff are added to commit
4297 text/plain body parts before first diff are added to commit
4297 message.
4298 message.
4298
4299
4299 If the imported patch was generated by :hg:`export`, user and
4300 If the imported patch was generated by :hg:`export`, user and
4300 description from patch override values from message headers and
4301 description from patch override values from message headers and
4301 body. Values given on command line with -m/--message and -u/--user
4302 body. Values given on command line with -m/--message and -u/--user
4302 override these.
4303 override these.
4303
4304
4304 If --exact is specified, import will set the working directory to
4305 If --exact is specified, import will set the working directory to
4305 the parent of each patch before applying it, and will abort if the
4306 the parent of each patch before applying it, and will abort if the
4306 resulting changeset has a different ID than the one recorded in
4307 resulting changeset has a different ID than the one recorded in
4307 the patch. This may happen due to character set problems or other
4308 the patch. This may happen due to character set problems or other
4308 deficiencies in the text patch format.
4309 deficiencies in the text patch format.
4309
4310
4310 Use --bypass to apply and commit patches directly to the
4311 Use --bypass to apply and commit patches directly to the
4311 repository, not touching the working directory. Without --exact,
4312 repository, not touching the working directory. Without --exact,
4312 patches will be applied on top of the working directory parent
4313 patches will be applied on top of the working directory parent
4313 revision.
4314 revision.
4314
4315
4315 With -s/--similarity, hg will attempt to discover renames and
4316 With -s/--similarity, hg will attempt to discover renames and
4316 copies in the patch in the same way as :hg:`addremove`.
4317 copies in the patch in the same way as :hg:`addremove`.
4317
4318
4318 Use --partial to ensure a changeset will be created from the patch
4319 Use --partial to ensure a changeset will be created from the patch
4319 even if some hunks fail to apply. Hunks that fail to apply will be
4320 even if some hunks fail to apply. Hunks that fail to apply will be
4320 written to a <target-file>.rej file. Conflicts can then be resolved
4321 written to a <target-file>.rej file. Conflicts can then be resolved
4321 by hand before :hg:`commit --amend` is run to update the created
4322 by hand before :hg:`commit --amend` is run to update the created
4322 changeset. This flag exists to let people import patches that
4323 changeset. This flag exists to let people import patches that
4323 partially apply without losing the associated metadata (author,
4324 partially apply without losing the associated metadata (author,
4324 date, description, ...). Note that when none of the hunk applies
4325 date, description, ...). Note that when none of the hunk applies
4325 cleanly, :hg:`import --partial` will create an empty changeset,
4326 cleanly, :hg:`import --partial` will create an empty changeset,
4326 importing only the patch metadata.
4327 importing only the patch metadata.
4327
4328
4328 It is possible to use external patch programs to perform the patch
4329 It is possible to use external patch programs to perform the patch
4329 by setting the ``ui.patch`` configuration option. For the default
4330 by setting the ``ui.patch`` configuration option. For the default
4330 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4331 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4331 See :hg:`help config` for more information about configuration
4332 See :hg:`help config` for more information about configuration
4332 files and how to use these options.
4333 files and how to use these options.
4333
4334
4334 To read a patch from standard input, use "-" as the patch name. If
4335 To read a patch from standard input, use "-" as the patch name. If
4335 a URL is specified, the patch will be downloaded from it.
4336 a URL is specified, the patch will be downloaded from it.
4336 See :hg:`help dates` for a list of formats valid for -d/--date.
4337 See :hg:`help dates` for a list of formats valid for -d/--date.
4337
4338
4338 .. container:: verbose
4339 .. container:: verbose
4339
4340
4340 Examples:
4341 Examples:
4341
4342
4342 - import a traditional patch from a website and detect renames::
4343 - import a traditional patch from a website and detect renames::
4343
4344
4344 hg import -s 80 http://example.com/bugfix.patch
4345 hg import -s 80 http://example.com/bugfix.patch
4345
4346
4346 - import a changeset from an hgweb server::
4347 - import a changeset from an hgweb server::
4347
4348
4348 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4349 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4349
4350
4350 - import all the patches in an Unix-style mbox::
4351 - import all the patches in an Unix-style mbox::
4351
4352
4352 hg import incoming-patches.mbox
4353 hg import incoming-patches.mbox
4353
4354
4354 - attempt to exactly restore an exported changeset (not always
4355 - attempt to exactly restore an exported changeset (not always
4355 possible)::
4356 possible)::
4356
4357
4357 hg import --exact proposed-fix.patch
4358 hg import --exact proposed-fix.patch
4358
4359
4359 - use an external tool to apply a patch which is too fuzzy for
4360 - use an external tool to apply a patch which is too fuzzy for
4360 the default internal tool.
4361 the default internal tool.
4361
4362
4362 hg import --config ui.patch="patch --merge" fuzzy.patch
4363 hg import --config ui.patch="patch --merge" fuzzy.patch
4363
4364
4364 - change the default fuzzing from 2 to a less strict 7
4365 - change the default fuzzing from 2 to a less strict 7
4365
4366
4366 hg import --config ui.fuzz=7 fuzz.patch
4367 hg import --config ui.fuzz=7 fuzz.patch
4367
4368
4368 Returns 0 on success, 1 on partial success (see --partial).
4369 Returns 0 on success, 1 on partial success (see --partial).
4369 """
4370 """
4370
4371
4371 if not patch1:
4372 if not patch1:
4372 raise util.Abort(_('need at least one patch to import'))
4373 raise util.Abort(_('need at least one patch to import'))
4373
4374
4374 patches = (patch1,) + patches
4375 patches = (patch1,) + patches
4375
4376
4376 date = opts.get('date')
4377 date = opts.get('date')
4377 if date:
4378 if date:
4378 opts['date'] = util.parsedate(date)
4379 opts['date'] = util.parsedate(date)
4379
4380
4380 update = not opts.get('bypass')
4381 update = not opts.get('bypass')
4381 if not update and opts.get('no_commit'):
4382 if not update and opts.get('no_commit'):
4382 raise util.Abort(_('cannot use --no-commit with --bypass'))
4383 raise util.Abort(_('cannot use --no-commit with --bypass'))
4383 try:
4384 try:
4384 sim = float(opts.get('similarity') or 0)
4385 sim = float(opts.get('similarity') or 0)
4385 except ValueError:
4386 except ValueError:
4386 raise util.Abort(_('similarity must be a number'))
4387 raise util.Abort(_('similarity must be a number'))
4387 if sim < 0 or sim > 100:
4388 if sim < 0 or sim > 100:
4388 raise util.Abort(_('similarity must be between 0 and 100'))
4389 raise util.Abort(_('similarity must be between 0 and 100'))
4389 if sim and not update:
4390 if sim and not update:
4390 raise util.Abort(_('cannot use --similarity with --bypass'))
4391 raise util.Abort(_('cannot use --similarity with --bypass'))
4391 if opts.get('exact') and opts.get('edit'):
4392 if opts.get('exact') and opts.get('edit'):
4392 raise util.Abort(_('cannot use --exact with --edit'))
4393 raise util.Abort(_('cannot use --exact with --edit'))
4393 if opts.get('exact') and opts.get('prefix'):
4394 if opts.get('exact') and opts.get('prefix'):
4394 raise util.Abort(_('cannot use --exact with --prefix'))
4395 raise util.Abort(_('cannot use --exact with --prefix'))
4395
4396
4396 if update:
4397 if update:
4397 cmdutil.checkunfinished(repo)
4398 cmdutil.checkunfinished(repo)
4398 if (opts.get('exact') or not opts.get('force')) and update:
4399 if (opts.get('exact') or not opts.get('force')) and update:
4399 cmdutil.bailifchanged(repo)
4400 cmdutil.bailifchanged(repo)
4400
4401
4401 base = opts["base"]
4402 base = opts["base"]
4402 wlock = dsguard = lock = tr = None
4403 wlock = dsguard = lock = tr = None
4403 msgs = []
4404 msgs = []
4404 ret = 0
4405 ret = 0
4405
4406
4406
4407
4407 try:
4408 try:
4408 try:
4409 try:
4409 wlock = repo.wlock()
4410 wlock = repo.wlock()
4410 if not opts.get('no_commit'):
4411 if not opts.get('no_commit'):
4411 lock = repo.lock()
4412 lock = repo.lock()
4412 tr = repo.transaction('import')
4413 tr = repo.transaction('import')
4413 else:
4414 else:
4414 dsguard = cmdutil.dirstateguard(repo, 'import')
4415 dsguard = cmdutil.dirstateguard(repo, 'import')
4415 parents = repo.parents()
4416 parents = repo.parents()
4416 for patchurl in patches:
4417 for patchurl in patches:
4417 if patchurl == '-':
4418 if patchurl == '-':
4418 ui.status(_('applying patch from stdin\n'))
4419 ui.status(_('applying patch from stdin\n'))
4419 patchfile = ui.fin
4420 patchfile = ui.fin
4420 patchurl = 'stdin' # for error message
4421 patchurl = 'stdin' # for error message
4421 else:
4422 else:
4422 patchurl = os.path.join(base, patchurl)
4423 patchurl = os.path.join(base, patchurl)
4423 ui.status(_('applying %s\n') % patchurl)
4424 ui.status(_('applying %s\n') % patchurl)
4424 patchfile = hg.openpath(ui, patchurl)
4425 patchfile = hg.openpath(ui, patchurl)
4425
4426
4426 haspatch = False
4427 haspatch = False
4427 for hunk in patch.split(patchfile):
4428 for hunk in patch.split(patchfile):
4428 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4429 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4429 parents, opts,
4430 parents, opts,
4430 msgs, hg.clean)
4431 msgs, hg.clean)
4431 if msg:
4432 if msg:
4432 haspatch = True
4433 haspatch = True
4433 ui.note(msg + '\n')
4434 ui.note(msg + '\n')
4434 if update or opts.get('exact'):
4435 if update or opts.get('exact'):
4435 parents = repo.parents()
4436 parents = repo.parents()
4436 else:
4437 else:
4437 parents = [repo[node]]
4438 parents = [repo[node]]
4438 if rej:
4439 if rej:
4439 ui.write_err(_("patch applied partially\n"))
4440 ui.write_err(_("patch applied partially\n"))
4440 ui.write_err(_("(fix the .rej files and run "
4441 ui.write_err(_("(fix the .rej files and run "
4441 "`hg commit --amend`)\n"))
4442 "`hg commit --amend`)\n"))
4442 ret = 1
4443 ret = 1
4443 break
4444 break
4444
4445
4445 if not haspatch:
4446 if not haspatch:
4446 raise util.Abort(_('%s: no diffs found') % patchurl)
4447 raise util.Abort(_('%s: no diffs found') % patchurl)
4447
4448
4448 if tr:
4449 if tr:
4449 tr.close()
4450 tr.close()
4450 if msgs:
4451 if msgs:
4451 repo.savecommitmessage('\n* * *\n'.join(msgs))
4452 repo.savecommitmessage('\n* * *\n'.join(msgs))
4452 if dsguard:
4453 if dsguard:
4453 dsguard.close()
4454 dsguard.close()
4454 return ret
4455 return ret
4455 finally:
4456 finally:
4456 # TODO: get rid of this meaningless try/finally enclosing.
4457 # TODO: get rid of this meaningless try/finally enclosing.
4457 # this is kept only to reduce changes in a patch.
4458 # this is kept only to reduce changes in a patch.
4458 pass
4459 pass
4459 finally:
4460 finally:
4460 if tr:
4461 if tr:
4461 tr.release()
4462 tr.release()
4462 release(lock, dsguard, wlock)
4463 release(lock, dsguard, wlock)
4463
4464
4464 @command('incoming|in',
4465 @command('incoming|in',
4465 [('f', 'force', None,
4466 [('f', 'force', None,
4466 _('run even if remote repository is unrelated')),
4467 _('run even if remote repository is unrelated')),
4467 ('n', 'newest-first', None, _('show newest record first')),
4468 ('n', 'newest-first', None, _('show newest record first')),
4468 ('', 'bundle', '',
4469 ('', 'bundle', '',
4469 _('file to store the bundles into'), _('FILE')),
4470 _('file to store the bundles into'), _('FILE')),
4470 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4471 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4471 ('B', 'bookmarks', False, _("compare bookmarks")),
4472 ('B', 'bookmarks', False, _("compare bookmarks")),
4472 ('b', 'branch', [],
4473 ('b', 'branch', [],
4473 _('a specific branch you would like to pull'), _('BRANCH')),
4474 _('a specific branch you would like to pull'), _('BRANCH')),
4474 ] + logopts + remoteopts + subrepoopts,
4475 ] + logopts + remoteopts + subrepoopts,
4475 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4476 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4476 def incoming(ui, repo, source="default", **opts):
4477 def incoming(ui, repo, source="default", **opts):
4477 """show new changesets found in source
4478 """show new changesets found in source
4478
4479
4479 Show new changesets found in the specified path/URL or the default
4480 Show new changesets found in the specified path/URL or the default
4480 pull location. These are the changesets that would have been pulled
4481 pull location. These are the changesets that would have been pulled
4481 if a pull at the time you issued this command.
4482 if a pull at the time you issued this command.
4482
4483
4483 See pull for valid source format details.
4484 See pull for valid source format details.
4484
4485
4485 .. container:: verbose
4486 .. container:: verbose
4486
4487
4487 With -B/--bookmarks, the result of bookmark comparison between
4488 With -B/--bookmarks, the result of bookmark comparison between
4488 local and remote repositories is displayed. With -v/--verbose,
4489 local and remote repositories is displayed. With -v/--verbose,
4489 status is also displayed for each bookmark like below::
4490 status is also displayed for each bookmark like below::
4490
4491
4491 BM1 01234567890a added
4492 BM1 01234567890a added
4492 BM2 1234567890ab advanced
4493 BM2 1234567890ab advanced
4493 BM3 234567890abc diverged
4494 BM3 234567890abc diverged
4494 BM4 34567890abcd changed
4495 BM4 34567890abcd changed
4495
4496
4496 The action taken locally when pulling depends on the
4497 The action taken locally when pulling depends on the
4497 status of each bookmark:
4498 status of each bookmark:
4498
4499
4499 :``added``: pull will create it
4500 :``added``: pull will create it
4500 :``advanced``: pull will update it
4501 :``advanced``: pull will update it
4501 :``diverged``: pull will create a divergent bookmark
4502 :``diverged``: pull will create a divergent bookmark
4502 :``changed``: result depends on remote changesets
4503 :``changed``: result depends on remote changesets
4503
4504
4504 From the point of view of pulling behavior, bookmark
4505 From the point of view of pulling behavior, bookmark
4505 existing only in the remote repository are treated as ``added``,
4506 existing only in the remote repository are treated as ``added``,
4506 even if it is in fact locally deleted.
4507 even if it is in fact locally deleted.
4507
4508
4508 .. container:: verbose
4509 .. container:: verbose
4509
4510
4510 For remote repository, using --bundle avoids downloading the
4511 For remote repository, using --bundle avoids downloading the
4511 changesets twice if the incoming is followed by a pull.
4512 changesets twice if the incoming is followed by a pull.
4512
4513
4513 Examples:
4514 Examples:
4514
4515
4515 - show incoming changes with patches and full description::
4516 - show incoming changes with patches and full description::
4516
4517
4517 hg incoming -vp
4518 hg incoming -vp
4518
4519
4519 - show incoming changes excluding merges, store a bundle::
4520 - show incoming changes excluding merges, store a bundle::
4520
4521
4521 hg in -vpM --bundle incoming.hg
4522 hg in -vpM --bundle incoming.hg
4522 hg pull incoming.hg
4523 hg pull incoming.hg
4523
4524
4524 - briefly list changes inside a bundle::
4525 - briefly list changes inside a bundle::
4525
4526
4526 hg in changes.hg -T "{desc|firstline}\\n"
4527 hg in changes.hg -T "{desc|firstline}\\n"
4527
4528
4528 Returns 0 if there are incoming changes, 1 otherwise.
4529 Returns 0 if there are incoming changes, 1 otherwise.
4529 """
4530 """
4530 if opts.get('graph'):
4531 if opts.get('graph'):
4531 cmdutil.checkunsupportedgraphflags([], opts)
4532 cmdutil.checkunsupportedgraphflags([], opts)
4532 def display(other, chlist, displayer):
4533 def display(other, chlist, displayer):
4533 revdag = cmdutil.graphrevs(other, chlist, opts)
4534 revdag = cmdutil.graphrevs(other, chlist, opts)
4534 showparents = [ctx.node() for ctx in repo[None].parents()]
4535 showparents = [ctx.node() for ctx in repo[None].parents()]
4535 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4536 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4536 graphmod.asciiedges)
4537 graphmod.asciiedges)
4537
4538
4538 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4539 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4539 return 0
4540 return 0
4540
4541
4541 if opts.get('bundle') and opts.get('subrepos'):
4542 if opts.get('bundle') and opts.get('subrepos'):
4542 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4543 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4543
4544
4544 if opts.get('bookmarks'):
4545 if opts.get('bookmarks'):
4545 source, branches = hg.parseurl(ui.expandpath(source),
4546 source, branches = hg.parseurl(ui.expandpath(source),
4546 opts.get('branch'))
4547 opts.get('branch'))
4547 other = hg.peer(repo, opts, source)
4548 other = hg.peer(repo, opts, source)
4548 if 'bookmarks' not in other.listkeys('namespaces'):
4549 if 'bookmarks' not in other.listkeys('namespaces'):
4549 ui.warn(_("remote doesn't support bookmarks\n"))
4550 ui.warn(_("remote doesn't support bookmarks\n"))
4550 return 0
4551 return 0
4551 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4552 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4552 return bookmarks.incoming(ui, repo, other)
4553 return bookmarks.incoming(ui, repo, other)
4553
4554
4554 repo._subtoppath = ui.expandpath(source)
4555 repo._subtoppath = ui.expandpath(source)
4555 try:
4556 try:
4556 return hg.incoming(ui, repo, source, opts)
4557 return hg.incoming(ui, repo, source, opts)
4557 finally:
4558 finally:
4558 del repo._subtoppath
4559 del repo._subtoppath
4559
4560
4560
4561
4561 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4562 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4562 norepo=True)
4563 norepo=True)
4563 def init(ui, dest=".", **opts):
4564 def init(ui, dest=".", **opts):
4564 """create a new repository in the given directory
4565 """create a new repository in the given directory
4565
4566
4566 Initialize a new repository in the given directory. If the given
4567 Initialize a new repository in the given directory. If the given
4567 directory does not exist, it will be created.
4568 directory does not exist, it will be created.
4568
4569
4569 If no directory is given, the current directory is used.
4570 If no directory is given, the current directory is used.
4570
4571
4571 It is possible to specify an ``ssh://`` URL as the destination.
4572 It is possible to specify an ``ssh://`` URL as the destination.
4572 See :hg:`help urls` for more information.
4573 See :hg:`help urls` for more information.
4573
4574
4574 Returns 0 on success.
4575 Returns 0 on success.
4575 """
4576 """
4576 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4577 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4577
4578
4578 @command('locate',
4579 @command('locate',
4579 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4580 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4580 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4581 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4581 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4582 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4582 ] + walkopts,
4583 ] + walkopts,
4583 _('[OPTION]... [PATTERN]...'))
4584 _('[OPTION]... [PATTERN]...'))
4584 def locate(ui, repo, *pats, **opts):
4585 def locate(ui, repo, *pats, **opts):
4585 """locate files matching specific patterns (DEPRECATED)
4586 """locate files matching specific patterns (DEPRECATED)
4586
4587
4587 Print files under Mercurial control in the working directory whose
4588 Print files under Mercurial control in the working directory whose
4588 names match the given patterns.
4589 names match the given patterns.
4589
4590
4590 By default, this command searches all directories in the working
4591 By default, this command searches all directories in the working
4591 directory. To search just the current directory and its
4592 directory. To search just the current directory and its
4592 subdirectories, use "--include .".
4593 subdirectories, use "--include .".
4593
4594
4594 If no patterns are given to match, this command prints the names
4595 If no patterns are given to match, this command prints the names
4595 of all files under Mercurial control in the working directory.
4596 of all files under Mercurial control in the working directory.
4596
4597
4597 If you want to feed the output of this command into the "xargs"
4598 If you want to feed the output of this command into the "xargs"
4598 command, use the -0 option to both this command and "xargs". This
4599 command, use the -0 option to both this command and "xargs". This
4599 will avoid the problem of "xargs" treating single filenames that
4600 will avoid the problem of "xargs" treating single filenames that
4600 contain whitespace as multiple filenames.
4601 contain whitespace as multiple filenames.
4601
4602
4602 See :hg:`help files` for a more versatile command.
4603 See :hg:`help files` for a more versatile command.
4603
4604
4604 Returns 0 if a match is found, 1 otherwise.
4605 Returns 0 if a match is found, 1 otherwise.
4605 """
4606 """
4606 if opts.get('print0'):
4607 if opts.get('print0'):
4607 end = '\0'
4608 end = '\0'
4608 else:
4609 else:
4609 end = '\n'
4610 end = '\n'
4610 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4611 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4611
4612
4612 ret = 1
4613 ret = 1
4613 ctx = repo[rev]
4614 ctx = repo[rev]
4614 m = scmutil.match(ctx, pats, opts, default='relglob',
4615 m = scmutil.match(ctx, pats, opts, default='relglob',
4615 badfn=lambda x, y: False)
4616 badfn=lambda x, y: False)
4616
4617
4617 for abs in ctx.matches(m):
4618 for abs in ctx.matches(m):
4618 if opts.get('fullpath'):
4619 if opts.get('fullpath'):
4619 ui.write(repo.wjoin(abs), end)
4620 ui.write(repo.wjoin(abs), end)
4620 else:
4621 else:
4621 ui.write(((pats and m.rel(abs)) or abs), end)
4622 ui.write(((pats and m.rel(abs)) or abs), end)
4622 ret = 0
4623 ret = 0
4623
4624
4624 return ret
4625 return ret
4625
4626
4626 @command('^log|history',
4627 @command('^log|history',
4627 [('f', 'follow', None,
4628 [('f', 'follow', None,
4628 _('follow changeset history, or file history across copies and renames')),
4629 _('follow changeset history, or file history across copies and renames')),
4629 ('', 'follow-first', None,
4630 ('', 'follow-first', None,
4630 _('only follow the first parent of merge changesets (DEPRECATED)')),
4631 _('only follow the first parent of merge changesets (DEPRECATED)')),
4631 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4632 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4632 ('C', 'copies', None, _('show copied files')),
4633 ('C', 'copies', None, _('show copied files')),
4633 ('k', 'keyword', [],
4634 ('k', 'keyword', [],
4634 _('do case-insensitive search for a given text'), _('TEXT')),
4635 _('do case-insensitive search for a given text'), _('TEXT')),
4635 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4636 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4636 ('', 'removed', None, _('include revisions where files were removed')),
4637 ('', 'removed', None, _('include revisions where files were removed')),
4637 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4638 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4638 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4639 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4639 ('', 'only-branch', [],
4640 ('', 'only-branch', [],
4640 _('show only changesets within the given named branch (DEPRECATED)'),
4641 _('show only changesets within the given named branch (DEPRECATED)'),
4641 _('BRANCH')),
4642 _('BRANCH')),
4642 ('b', 'branch', [],
4643 ('b', 'branch', [],
4643 _('show changesets within the given named branch'), _('BRANCH')),
4644 _('show changesets within the given named branch'), _('BRANCH')),
4644 ('P', 'prune', [],
4645 ('P', 'prune', [],
4645 _('do not display revision or any of its ancestors'), _('REV')),
4646 _('do not display revision or any of its ancestors'), _('REV')),
4646 ] + logopts + walkopts,
4647 ] + logopts + walkopts,
4647 _('[OPTION]... [FILE]'),
4648 _('[OPTION]... [FILE]'),
4648 inferrepo=True)
4649 inferrepo=True)
4649 def log(ui, repo, *pats, **opts):
4650 def log(ui, repo, *pats, **opts):
4650 """show revision history of entire repository or files
4651 """show revision history of entire repository or files
4651
4652
4652 Print the revision history of the specified files or the entire
4653 Print the revision history of the specified files or the entire
4653 project.
4654 project.
4654
4655
4655 If no revision range is specified, the default is ``tip:0`` unless
4656 If no revision range is specified, the default is ``tip:0`` unless
4656 --follow is set, in which case the working directory parent is
4657 --follow is set, in which case the working directory parent is
4657 used as the starting revision.
4658 used as the starting revision.
4658
4659
4659 File history is shown without following rename or copy history of
4660 File history is shown without following rename or copy history of
4660 files. Use -f/--follow with a filename to follow history across
4661 files. Use -f/--follow with a filename to follow history across
4661 renames and copies. --follow without a filename will only show
4662 renames and copies. --follow without a filename will only show
4662 ancestors or descendants of the starting revision.
4663 ancestors or descendants of the starting revision.
4663
4664
4664 By default this command prints revision number and changeset id,
4665 By default this command prints revision number and changeset id,
4665 tags, non-trivial parents, user, date and time, and a summary for
4666 tags, non-trivial parents, user, date and time, and a summary for
4666 each commit. When the -v/--verbose switch is used, the list of
4667 each commit. When the -v/--verbose switch is used, the list of
4667 changed files and full commit message are shown.
4668 changed files and full commit message are shown.
4668
4669
4669 With --graph the revisions are shown as an ASCII art DAG with the most
4670 With --graph the revisions are shown as an ASCII art DAG with the most
4670 recent changeset at the top.
4671 recent changeset at the top.
4671 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4672 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4672 and '+' represents a fork where the changeset from the lines below is a
4673 and '+' represents a fork where the changeset from the lines below is a
4673 parent of the 'o' merge on the same line.
4674 parent of the 'o' merge on the same line.
4674
4675
4675 .. note::
4676 .. note::
4676
4677
4677 log -p/--patch may generate unexpected diff output for merge
4678 log -p/--patch may generate unexpected diff output for merge
4678 changesets, as it will only compare the merge changeset against
4679 changesets, as it will only compare the merge changeset against
4679 its first parent. Also, only files different from BOTH parents
4680 its first parent. Also, only files different from BOTH parents
4680 will appear in files:.
4681 will appear in files:.
4681
4682
4682 .. note::
4683 .. note::
4683
4684
4684 for performance reasons, log FILE may omit duplicate changes
4685 for performance reasons, log FILE may omit duplicate changes
4685 made on branches and will not show removals or mode changes. To
4686 made on branches and will not show removals or mode changes. To
4686 see all such changes, use the --removed switch.
4687 see all such changes, use the --removed switch.
4687
4688
4688 .. container:: verbose
4689 .. container:: verbose
4689
4690
4690 Some examples:
4691 Some examples:
4691
4692
4692 - changesets with full descriptions and file lists::
4693 - changesets with full descriptions and file lists::
4693
4694
4694 hg log -v
4695 hg log -v
4695
4696
4696 - changesets ancestral to the working directory::
4697 - changesets ancestral to the working directory::
4697
4698
4698 hg log -f
4699 hg log -f
4699
4700
4700 - last 10 commits on the current branch::
4701 - last 10 commits on the current branch::
4701
4702
4702 hg log -l 10 -b .
4703 hg log -l 10 -b .
4703
4704
4704 - changesets showing all modifications of a file, including removals::
4705 - changesets showing all modifications of a file, including removals::
4705
4706
4706 hg log --removed file.c
4707 hg log --removed file.c
4707
4708
4708 - all changesets that touch a directory, with diffs, excluding merges::
4709 - all changesets that touch a directory, with diffs, excluding merges::
4709
4710
4710 hg log -Mp lib/
4711 hg log -Mp lib/
4711
4712
4712 - all revision numbers that match a keyword::
4713 - all revision numbers that match a keyword::
4713
4714
4714 hg log -k bug --template "{rev}\\n"
4715 hg log -k bug --template "{rev}\\n"
4715
4716
4716 - list available log templates::
4717 - list available log templates::
4717
4718
4718 hg log -T list
4719 hg log -T list
4719
4720
4720 - check if a given changeset is included in a tagged release::
4721 - check if a given changeset is included in a tagged release::
4721
4722
4722 hg log -r "a21ccf and ancestor(1.9)"
4723 hg log -r "a21ccf and ancestor(1.9)"
4723
4724
4724 - find all changesets by some user in a date range::
4725 - find all changesets by some user in a date range::
4725
4726
4726 hg log -k alice -d "may 2008 to jul 2008"
4727 hg log -k alice -d "may 2008 to jul 2008"
4727
4728
4728 - summary of all changesets after the last tag::
4729 - summary of all changesets after the last tag::
4729
4730
4730 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4731 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4731
4732
4732 See :hg:`help dates` for a list of formats valid for -d/--date.
4733 See :hg:`help dates` for a list of formats valid for -d/--date.
4733
4734
4734 See :hg:`help revisions` and :hg:`help revsets` for more about
4735 See :hg:`help revisions` and :hg:`help revsets` for more about
4735 specifying revisions.
4736 specifying revisions.
4736
4737
4737 See :hg:`help templates` for more about pre-packaged styles and
4738 See :hg:`help templates` for more about pre-packaged styles and
4738 specifying custom templates.
4739 specifying custom templates.
4739
4740
4740 Returns 0 on success.
4741 Returns 0 on success.
4741
4742
4742 """
4743 """
4743 if opts.get('follow') and opts.get('rev'):
4744 if opts.get('follow') and opts.get('rev'):
4744 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4745 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4745 del opts['follow']
4746 del opts['follow']
4746
4747
4747 if opts.get('graph'):
4748 if opts.get('graph'):
4748 return cmdutil.graphlog(ui, repo, *pats, **opts)
4749 return cmdutil.graphlog(ui, repo, *pats, **opts)
4749
4750
4750 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4751 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4751 limit = cmdutil.loglimit(opts)
4752 limit = cmdutil.loglimit(opts)
4752 count = 0
4753 count = 0
4753
4754
4754 getrenamed = None
4755 getrenamed = None
4755 if opts.get('copies'):
4756 if opts.get('copies'):
4756 endrev = None
4757 endrev = None
4757 if opts.get('rev'):
4758 if opts.get('rev'):
4758 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4759 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4759 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4760 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4760
4761
4761 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4762 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4762 for rev in revs:
4763 for rev in revs:
4763 if count == limit:
4764 if count == limit:
4764 break
4765 break
4765 ctx = repo[rev]
4766 ctx = repo[rev]
4766 copies = None
4767 copies = None
4767 if getrenamed is not None and rev:
4768 if getrenamed is not None and rev:
4768 copies = []
4769 copies = []
4769 for fn in ctx.files():
4770 for fn in ctx.files():
4770 rename = getrenamed(fn, rev)
4771 rename = getrenamed(fn, rev)
4771 if rename:
4772 if rename:
4772 copies.append((fn, rename[0]))
4773 copies.append((fn, rename[0]))
4773 if filematcher:
4774 if filematcher:
4774 revmatchfn = filematcher(ctx.rev())
4775 revmatchfn = filematcher(ctx.rev())
4775 else:
4776 else:
4776 revmatchfn = None
4777 revmatchfn = None
4777 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4778 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4778 if displayer.flush(ctx):
4779 if displayer.flush(ctx):
4779 count += 1
4780 count += 1
4780
4781
4781 displayer.close()
4782 displayer.close()
4782
4783
4783 @command('manifest',
4784 @command('manifest',
4784 [('r', 'rev', '', _('revision to display'), _('REV')),
4785 [('r', 'rev', '', _('revision to display'), _('REV')),
4785 ('', 'all', False, _("list files from all revisions"))]
4786 ('', 'all', False, _("list files from all revisions"))]
4786 + formatteropts,
4787 + formatteropts,
4787 _('[-r REV]'))
4788 _('[-r REV]'))
4788 def manifest(ui, repo, node=None, rev=None, **opts):
4789 def manifest(ui, repo, node=None, rev=None, **opts):
4789 """output the current or given revision of the project manifest
4790 """output the current or given revision of the project manifest
4790
4791
4791 Print a list of version controlled files for the given revision.
4792 Print a list of version controlled files for the given revision.
4792 If no revision is given, the first parent of the working directory
4793 If no revision is given, the first parent of the working directory
4793 is used, or the null revision if no revision is checked out.
4794 is used, or the null revision if no revision is checked out.
4794
4795
4795 With -v, print file permissions, symlink and executable bits.
4796 With -v, print file permissions, symlink and executable bits.
4796 With --debug, print file revision hashes.
4797 With --debug, print file revision hashes.
4797
4798
4798 If option --all is specified, the list of all files from all revisions
4799 If option --all is specified, the list of all files from all revisions
4799 is printed. This includes deleted and renamed files.
4800 is printed. This includes deleted and renamed files.
4800
4801
4801 Returns 0 on success.
4802 Returns 0 on success.
4802 """
4803 """
4803
4804
4804 fm = ui.formatter('manifest', opts)
4805 fm = ui.formatter('manifest', opts)
4805
4806
4806 if opts.get('all'):
4807 if opts.get('all'):
4807 if rev or node:
4808 if rev or node:
4808 raise util.Abort(_("can't specify a revision with --all"))
4809 raise util.Abort(_("can't specify a revision with --all"))
4809
4810
4810 res = []
4811 res = []
4811 prefix = "data/"
4812 prefix = "data/"
4812 suffix = ".i"
4813 suffix = ".i"
4813 plen = len(prefix)
4814 plen = len(prefix)
4814 slen = len(suffix)
4815 slen = len(suffix)
4815 lock = repo.lock()
4816 lock = repo.lock()
4816 try:
4817 try:
4817 for fn, b, size in repo.store.datafiles():
4818 for fn, b, size in repo.store.datafiles():
4818 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4819 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4819 res.append(fn[plen:-slen])
4820 res.append(fn[plen:-slen])
4820 finally:
4821 finally:
4821 lock.release()
4822 lock.release()
4822 for f in res:
4823 for f in res:
4823 fm.startitem()
4824 fm.startitem()
4824 fm.write("path", '%s\n', f)
4825 fm.write("path", '%s\n', f)
4825 fm.end()
4826 fm.end()
4826 return
4827 return
4827
4828
4828 if rev and node:
4829 if rev and node:
4829 raise util.Abort(_("please specify just one revision"))
4830 raise util.Abort(_("please specify just one revision"))
4830
4831
4831 if not node:
4832 if not node:
4832 node = rev
4833 node = rev
4833
4834
4834 char = {'l': '@', 'x': '*', '': ''}
4835 char = {'l': '@', 'x': '*', '': ''}
4835 mode = {'l': '644', 'x': '755', '': '644'}
4836 mode = {'l': '644', 'x': '755', '': '644'}
4836 ctx = scmutil.revsingle(repo, node)
4837 ctx = scmutil.revsingle(repo, node)
4837 mf = ctx.manifest()
4838 mf = ctx.manifest()
4838 for f in ctx:
4839 for f in ctx:
4839 fm.startitem()
4840 fm.startitem()
4840 fl = ctx[f].flags()
4841 fl = ctx[f].flags()
4841 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4842 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4842 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4843 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4843 fm.write('path', '%s\n', f)
4844 fm.write('path', '%s\n', f)
4844 fm.end()
4845 fm.end()
4845
4846
4846 @command('^merge',
4847 @command('^merge',
4847 [('f', 'force', None,
4848 [('f', 'force', None,
4848 _('force a merge including outstanding changes (DEPRECATED)')),
4849 _('force a merge including outstanding changes (DEPRECATED)')),
4849 ('r', 'rev', '', _('revision to merge'), _('REV')),
4850 ('r', 'rev', '', _('revision to merge'), _('REV')),
4850 ('P', 'preview', None,
4851 ('P', 'preview', None,
4851 _('review revisions to merge (no merge is performed)'))
4852 _('review revisions to merge (no merge is performed)'))
4852 ] + mergetoolopts,
4853 ] + mergetoolopts,
4853 _('[-P] [-f] [[-r] REV]'))
4854 _('[-P] [-f] [[-r] REV]'))
4854 def merge(ui, repo, node=None, **opts):
4855 def merge(ui, repo, node=None, **opts):
4855 """merge another revision into working directory
4856 """merge another revision into working directory
4856
4857
4857 The current working directory is updated with all changes made in
4858 The current working directory is updated with all changes made in
4858 the requested revision since the last common predecessor revision.
4859 the requested revision since the last common predecessor revision.
4859
4860
4860 Files that changed between either parent are marked as changed for
4861 Files that changed between either parent are marked as changed for
4861 the next commit and a commit must be performed before any further
4862 the next commit and a commit must be performed before any further
4862 updates to the repository are allowed. The next commit will have
4863 updates to the repository are allowed. The next commit will have
4863 two parents.
4864 two parents.
4864
4865
4865 ``--tool`` can be used to specify the merge tool used for file
4866 ``--tool`` can be used to specify the merge tool used for file
4866 merges. It overrides the HGMERGE environment variable and your
4867 merges. It overrides the HGMERGE environment variable and your
4867 configuration files. See :hg:`help merge-tools` for options.
4868 configuration files. See :hg:`help merge-tools` for options.
4868
4869
4869 If no revision is specified, the working directory's parent is a
4870 If no revision is specified, the working directory's parent is a
4870 head revision, and the current branch contains exactly one other
4871 head revision, and the current branch contains exactly one other
4871 head, the other head is merged with by default. Otherwise, an
4872 head, the other head is merged with by default. Otherwise, an
4872 explicit revision with which to merge with must be provided.
4873 explicit revision with which to merge with must be provided.
4873
4874
4874 :hg:`resolve` must be used to resolve unresolved files.
4875 :hg:`resolve` must be used to resolve unresolved files.
4875
4876
4876 To undo an uncommitted merge, use :hg:`update --clean .` which
4877 To undo an uncommitted merge, use :hg:`update --clean .` which
4877 will check out a clean copy of the original merge parent, losing
4878 will check out a clean copy of the original merge parent, losing
4878 all changes.
4879 all changes.
4879
4880
4880 Returns 0 on success, 1 if there are unresolved files.
4881 Returns 0 on success, 1 if there are unresolved files.
4881 """
4882 """
4882
4883
4883 if opts.get('rev') and node:
4884 if opts.get('rev') and node:
4884 raise util.Abort(_("please specify just one revision"))
4885 raise util.Abort(_("please specify just one revision"))
4885 if not node:
4886 if not node:
4886 node = opts.get('rev')
4887 node = opts.get('rev')
4887
4888
4888 if node:
4889 if node:
4889 node = scmutil.revsingle(repo, node).node()
4890 node = scmutil.revsingle(repo, node).node()
4890
4891
4891 if not node:
4892 if not node:
4892 node = scmutil.revsingle(repo, '_mergedefaultdest()').node()
4893 node = scmutil.revsingle(repo, '_mergedefaultdest()').node()
4893
4894
4894 if opts.get('preview'):
4895 if opts.get('preview'):
4895 # find nodes that are ancestors of p2 but not of p1
4896 # find nodes that are ancestors of p2 but not of p1
4896 p1 = repo.lookup('.')
4897 p1 = repo.lookup('.')
4897 p2 = repo.lookup(node)
4898 p2 = repo.lookup(node)
4898 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4899 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4899
4900
4900 displayer = cmdutil.show_changeset(ui, repo, opts)
4901 displayer = cmdutil.show_changeset(ui, repo, opts)
4901 for node in nodes:
4902 for node in nodes:
4902 displayer.show(repo[node])
4903 displayer.show(repo[node])
4903 displayer.close()
4904 displayer.close()
4904 return 0
4905 return 0
4905
4906
4906 try:
4907 try:
4907 # ui.forcemerge is an internal variable, do not document
4908 # ui.forcemerge is an internal variable, do not document
4908 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4909 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4909 return hg.merge(repo, node, force=opts.get('force'))
4910 return hg.merge(repo, node, force=opts.get('force'))
4910 finally:
4911 finally:
4911 ui.setconfig('ui', 'forcemerge', '', 'merge')
4912 ui.setconfig('ui', 'forcemerge', '', 'merge')
4912
4913
4913 @command('outgoing|out',
4914 @command('outgoing|out',
4914 [('f', 'force', None, _('run even when the destination is unrelated')),
4915 [('f', 'force', None, _('run even when the destination is unrelated')),
4915 ('r', 'rev', [],
4916 ('r', 'rev', [],
4916 _('a changeset intended to be included in the destination'), _('REV')),
4917 _('a changeset intended to be included in the destination'), _('REV')),
4917 ('n', 'newest-first', None, _('show newest record first')),
4918 ('n', 'newest-first', None, _('show newest record first')),
4918 ('B', 'bookmarks', False, _('compare bookmarks')),
4919 ('B', 'bookmarks', False, _('compare bookmarks')),
4919 ('b', 'branch', [], _('a specific branch you would like to push'),
4920 ('b', 'branch', [], _('a specific branch you would like to push'),
4920 _('BRANCH')),
4921 _('BRANCH')),
4921 ] + logopts + remoteopts + subrepoopts,
4922 ] + logopts + remoteopts + subrepoopts,
4922 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4923 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4923 def outgoing(ui, repo, dest=None, **opts):
4924 def outgoing(ui, repo, dest=None, **opts):
4924 """show changesets not found in the destination
4925 """show changesets not found in the destination
4925
4926
4926 Show changesets not found in the specified destination repository
4927 Show changesets not found in the specified destination repository
4927 or the default push location. These are the changesets that would
4928 or the default push location. These are the changesets that would
4928 be pushed if a push was requested.
4929 be pushed if a push was requested.
4929
4930
4930 See pull for details of valid destination formats.
4931 See pull for details of valid destination formats.
4931
4932
4932 .. container:: verbose
4933 .. container:: verbose
4933
4934
4934 With -B/--bookmarks, the result of bookmark comparison between
4935 With -B/--bookmarks, the result of bookmark comparison between
4935 local and remote repositories is displayed. With -v/--verbose,
4936 local and remote repositories is displayed. With -v/--verbose,
4936 status is also displayed for each bookmark like below::
4937 status is also displayed for each bookmark like below::
4937
4938
4938 BM1 01234567890a added
4939 BM1 01234567890a added
4939 BM2 deleted
4940 BM2 deleted
4940 BM3 234567890abc advanced
4941 BM3 234567890abc advanced
4941 BM4 34567890abcd diverged
4942 BM4 34567890abcd diverged
4942 BM5 4567890abcde changed
4943 BM5 4567890abcde changed
4943
4944
4944 The action taken when pushing depends on the
4945 The action taken when pushing depends on the
4945 status of each bookmark:
4946 status of each bookmark:
4946
4947
4947 :``added``: push with ``-B`` will create it
4948 :``added``: push with ``-B`` will create it
4948 :``deleted``: push with ``-B`` will delete it
4949 :``deleted``: push with ``-B`` will delete it
4949 :``advanced``: push will update it
4950 :``advanced``: push will update it
4950 :``diverged``: push with ``-B`` will update it
4951 :``diverged``: push with ``-B`` will update it
4951 :``changed``: push with ``-B`` will update it
4952 :``changed``: push with ``-B`` will update it
4952
4953
4953 From the point of view of pushing behavior, bookmarks
4954 From the point of view of pushing behavior, bookmarks
4954 existing only in the remote repository are treated as
4955 existing only in the remote repository are treated as
4955 ``deleted``, even if it is in fact added remotely.
4956 ``deleted``, even if it is in fact added remotely.
4956
4957
4957 Returns 0 if there are outgoing changes, 1 otherwise.
4958 Returns 0 if there are outgoing changes, 1 otherwise.
4958 """
4959 """
4959 if opts.get('graph'):
4960 if opts.get('graph'):
4960 cmdutil.checkunsupportedgraphflags([], opts)
4961 cmdutil.checkunsupportedgraphflags([], opts)
4961 o, other = hg._outgoing(ui, repo, dest, opts)
4962 o, other = hg._outgoing(ui, repo, dest, opts)
4962 if not o:
4963 if not o:
4963 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4964 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4964 return
4965 return
4965
4966
4966 revdag = cmdutil.graphrevs(repo, o, opts)
4967 revdag = cmdutil.graphrevs(repo, o, opts)
4967 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4968 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4968 showparents = [ctx.node() for ctx in repo[None].parents()]
4969 showparents = [ctx.node() for ctx in repo[None].parents()]
4969 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4970 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4970 graphmod.asciiedges)
4971 graphmod.asciiedges)
4971 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4972 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4972 return 0
4973 return 0
4973
4974
4974 if opts.get('bookmarks'):
4975 if opts.get('bookmarks'):
4975 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4976 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4976 dest, branches = hg.parseurl(dest, opts.get('branch'))
4977 dest, branches = hg.parseurl(dest, opts.get('branch'))
4977 other = hg.peer(repo, opts, dest)
4978 other = hg.peer(repo, opts, dest)
4978 if 'bookmarks' not in other.listkeys('namespaces'):
4979 if 'bookmarks' not in other.listkeys('namespaces'):
4979 ui.warn(_("remote doesn't support bookmarks\n"))
4980 ui.warn(_("remote doesn't support bookmarks\n"))
4980 return 0
4981 return 0
4981 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4982 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4982 return bookmarks.outgoing(ui, repo, other)
4983 return bookmarks.outgoing(ui, repo, other)
4983
4984
4984 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4985 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4985 try:
4986 try:
4986 return hg.outgoing(ui, repo, dest, opts)
4987 return hg.outgoing(ui, repo, dest, opts)
4987 finally:
4988 finally:
4988 del repo._subtoppath
4989 del repo._subtoppath
4989
4990
4990 @command('parents',
4991 @command('parents',
4991 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4992 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4992 ] + templateopts,
4993 ] + templateopts,
4993 _('[-r REV] [FILE]'),
4994 _('[-r REV] [FILE]'),
4994 inferrepo=True)
4995 inferrepo=True)
4995 def parents(ui, repo, file_=None, **opts):
4996 def parents(ui, repo, file_=None, **opts):
4996 """show the parents of the working directory or revision (DEPRECATED)
4997 """show the parents of the working directory or revision (DEPRECATED)
4997
4998
4998 Print the working directory's parent revisions. If a revision is
4999 Print the working directory's parent revisions. If a revision is
4999 given via -r/--rev, the parent of that revision will be printed.
5000 given via -r/--rev, the parent of that revision will be printed.
5000 If a file argument is given, the revision in which the file was
5001 If a file argument is given, the revision in which the file was
5001 last changed (before the working directory revision or the
5002 last changed (before the working directory revision or the
5002 argument to --rev if given) is printed.
5003 argument to --rev if given) is printed.
5003
5004
5004 See :hg:`summary` and :hg:`help revsets` for related information.
5005 See :hg:`summary` and :hg:`help revsets` for related information.
5005
5006
5006 Returns 0 on success.
5007 Returns 0 on success.
5007 """
5008 """
5008
5009
5009 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5010 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5010
5011
5011 if file_:
5012 if file_:
5012 m = scmutil.match(ctx, (file_,), opts)
5013 m = scmutil.match(ctx, (file_,), opts)
5013 if m.anypats() or len(m.files()) != 1:
5014 if m.anypats() or len(m.files()) != 1:
5014 raise util.Abort(_('can only specify an explicit filename'))
5015 raise util.Abort(_('can only specify an explicit filename'))
5015 file_ = m.files()[0]
5016 file_ = m.files()[0]
5016 filenodes = []
5017 filenodes = []
5017 for cp in ctx.parents():
5018 for cp in ctx.parents():
5018 if not cp:
5019 if not cp:
5019 continue
5020 continue
5020 try:
5021 try:
5021 filenodes.append(cp.filenode(file_))
5022 filenodes.append(cp.filenode(file_))
5022 except error.LookupError:
5023 except error.LookupError:
5023 pass
5024 pass
5024 if not filenodes:
5025 if not filenodes:
5025 raise util.Abort(_("'%s' not found in manifest!") % file_)
5026 raise util.Abort(_("'%s' not found in manifest!") % file_)
5026 p = []
5027 p = []
5027 for fn in filenodes:
5028 for fn in filenodes:
5028 fctx = repo.filectx(file_, fileid=fn)
5029 fctx = repo.filectx(file_, fileid=fn)
5029 p.append(fctx.node())
5030 p.append(fctx.node())
5030 else:
5031 else:
5031 p = [cp.node() for cp in ctx.parents()]
5032 p = [cp.node() for cp in ctx.parents()]
5032
5033
5033 displayer = cmdutil.show_changeset(ui, repo, opts)
5034 displayer = cmdutil.show_changeset(ui, repo, opts)
5034 for n in p:
5035 for n in p:
5035 if n != nullid:
5036 if n != nullid:
5036 displayer.show(repo[n])
5037 displayer.show(repo[n])
5037 displayer.close()
5038 displayer.close()
5038
5039
5039 @command('paths', [], _('[NAME]'), optionalrepo=True)
5040 @command('paths', [], _('[NAME]'), optionalrepo=True)
5040 def paths(ui, repo, search=None):
5041 def paths(ui, repo, search=None):
5041 """show aliases for remote repositories
5042 """show aliases for remote repositories
5042
5043
5043 Show definition of symbolic path name NAME. If no name is given,
5044 Show definition of symbolic path name NAME. If no name is given,
5044 show definition of all available names.
5045 show definition of all available names.
5045
5046
5046 Option -q/--quiet suppresses all output when searching for NAME
5047 Option -q/--quiet suppresses all output when searching for NAME
5047 and shows only the path names when listing all definitions.
5048 and shows only the path names when listing all definitions.
5048
5049
5049 Path names are defined in the [paths] section of your
5050 Path names are defined in the [paths] section of your
5050 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5051 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5051 repository, ``.hg/hgrc`` is used, too.
5052 repository, ``.hg/hgrc`` is used, too.
5052
5053
5053 The path names ``default`` and ``default-push`` have a special
5054 The path names ``default`` and ``default-push`` have a special
5054 meaning. When performing a push or pull operation, they are used
5055 meaning. When performing a push or pull operation, they are used
5055 as fallbacks if no location is specified on the command-line.
5056 as fallbacks if no location is specified on the command-line.
5056 When ``default-push`` is set, it will be used for push and
5057 When ``default-push`` is set, it will be used for push and
5057 ``default`` will be used for pull; otherwise ``default`` is used
5058 ``default`` will be used for pull; otherwise ``default`` is used
5058 as the fallback for both. When cloning a repository, the clone
5059 as the fallback for both. When cloning a repository, the clone
5059 source is written as ``default`` in ``.hg/hgrc``. Note that
5060 source is written as ``default`` in ``.hg/hgrc``. Note that
5060 ``default`` and ``default-push`` apply to all inbound (e.g.
5061 ``default`` and ``default-push`` apply to all inbound (e.g.
5061 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
5062 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
5062 :hg:`bundle`) operations.
5063 :hg:`bundle`) operations.
5063
5064
5064 See :hg:`help urls` for more information.
5065 See :hg:`help urls` for more information.
5065
5066
5066 Returns 0 on success.
5067 Returns 0 on success.
5067 """
5068 """
5068 if search:
5069 if search:
5069 for name, path in sorted(ui.paths.iteritems()):
5070 for name, path in sorted(ui.paths.iteritems()):
5070 if name == search:
5071 if name == search:
5071 ui.status("%s\n" % util.hidepassword(path.loc))
5072 ui.status("%s\n" % util.hidepassword(path.loc))
5072 return
5073 return
5073 if not ui.quiet:
5074 if not ui.quiet:
5074 ui.warn(_("not found!\n"))
5075 ui.warn(_("not found!\n"))
5075 return 1
5076 return 1
5076 else:
5077 else:
5077 for name, path in sorted(ui.paths.iteritems()):
5078 for name, path in sorted(ui.paths.iteritems()):
5078 if ui.quiet:
5079 if ui.quiet:
5079 ui.write("%s\n" % name)
5080 ui.write("%s\n" % name)
5080 else:
5081 else:
5081 ui.write("%s = %s\n" % (name,
5082 ui.write("%s = %s\n" % (name,
5082 util.hidepassword(path.loc)))
5083 util.hidepassword(path.loc)))
5083
5084
5084 @command('phase',
5085 @command('phase',
5085 [('p', 'public', False, _('set changeset phase to public')),
5086 [('p', 'public', False, _('set changeset phase to public')),
5086 ('d', 'draft', False, _('set changeset phase to draft')),
5087 ('d', 'draft', False, _('set changeset phase to draft')),
5087 ('s', 'secret', False, _('set changeset phase to secret')),
5088 ('s', 'secret', False, _('set changeset phase to secret')),
5088 ('f', 'force', False, _('allow to move boundary backward')),
5089 ('f', 'force', False, _('allow to move boundary backward')),
5089 ('r', 'rev', [], _('target revision'), _('REV')),
5090 ('r', 'rev', [], _('target revision'), _('REV')),
5090 ],
5091 ],
5091 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5092 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5092 def phase(ui, repo, *revs, **opts):
5093 def phase(ui, repo, *revs, **opts):
5093 """set or show the current phase name
5094 """set or show the current phase name
5094
5095
5095 With no argument, show the phase name of the current revision(s).
5096 With no argument, show the phase name of the current revision(s).
5096
5097
5097 With one of -p/--public, -d/--draft or -s/--secret, change the
5098 With one of -p/--public, -d/--draft or -s/--secret, change the
5098 phase value of the specified revisions.
5099 phase value of the specified revisions.
5099
5100
5100 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5101 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5101 lower phase to an higher phase. Phases are ordered as follows::
5102 lower phase to an higher phase. Phases are ordered as follows::
5102
5103
5103 public < draft < secret
5104 public < draft < secret
5104
5105
5105 Returns 0 on success, 1 if some phases could not be changed.
5106 Returns 0 on success, 1 if some phases could not be changed.
5106
5107
5107 (For more information about the phases concept, see :hg:`help phases`.)
5108 (For more information about the phases concept, see :hg:`help phases`.)
5108 """
5109 """
5109 # search for a unique phase argument
5110 # search for a unique phase argument
5110 targetphase = None
5111 targetphase = None
5111 for idx, name in enumerate(phases.phasenames):
5112 for idx, name in enumerate(phases.phasenames):
5112 if opts[name]:
5113 if opts[name]:
5113 if targetphase is not None:
5114 if targetphase is not None:
5114 raise util.Abort(_('only one phase can be specified'))
5115 raise util.Abort(_('only one phase can be specified'))
5115 targetphase = idx
5116 targetphase = idx
5116
5117
5117 # look for specified revision
5118 # look for specified revision
5118 revs = list(revs)
5119 revs = list(revs)
5119 revs.extend(opts['rev'])
5120 revs.extend(opts['rev'])
5120 if not revs:
5121 if not revs:
5121 # display both parents as the second parent phase can influence
5122 # display both parents as the second parent phase can influence
5122 # the phase of a merge commit
5123 # the phase of a merge commit
5123 revs = [c.rev() for c in repo[None].parents()]
5124 revs = [c.rev() for c in repo[None].parents()]
5124
5125
5125 revs = scmutil.revrange(repo, revs)
5126 revs = scmutil.revrange(repo, revs)
5126
5127
5127 lock = None
5128 lock = None
5128 ret = 0
5129 ret = 0
5129 if targetphase is None:
5130 if targetphase is None:
5130 # display
5131 # display
5131 for r in revs:
5132 for r in revs:
5132 ctx = repo[r]
5133 ctx = repo[r]
5133 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5134 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5134 else:
5135 else:
5135 tr = None
5136 tr = None
5136 lock = repo.lock()
5137 lock = repo.lock()
5137 try:
5138 try:
5138 tr = repo.transaction("phase")
5139 tr = repo.transaction("phase")
5139 # set phase
5140 # set phase
5140 if not revs:
5141 if not revs:
5141 raise util.Abort(_('empty revision set'))
5142 raise util.Abort(_('empty revision set'))
5142 nodes = [repo[r].node() for r in revs]
5143 nodes = [repo[r].node() for r in revs]
5143 # moving revision from public to draft may hide them
5144 # moving revision from public to draft may hide them
5144 # We have to check result on an unfiltered repository
5145 # We have to check result on an unfiltered repository
5145 unfi = repo.unfiltered()
5146 unfi = repo.unfiltered()
5146 getphase = unfi._phasecache.phase
5147 getphase = unfi._phasecache.phase
5147 olddata = [getphase(unfi, r) for r in unfi]
5148 olddata = [getphase(unfi, r) for r in unfi]
5148 phases.advanceboundary(repo, tr, targetphase, nodes)
5149 phases.advanceboundary(repo, tr, targetphase, nodes)
5149 if opts['force']:
5150 if opts['force']:
5150 phases.retractboundary(repo, tr, targetphase, nodes)
5151 phases.retractboundary(repo, tr, targetphase, nodes)
5151 tr.close()
5152 tr.close()
5152 finally:
5153 finally:
5153 if tr is not None:
5154 if tr is not None:
5154 tr.release()
5155 tr.release()
5155 lock.release()
5156 lock.release()
5156 getphase = unfi._phasecache.phase
5157 getphase = unfi._phasecache.phase
5157 newdata = [getphase(unfi, r) for r in unfi]
5158 newdata = [getphase(unfi, r) for r in unfi]
5158 changes = sum(newdata[r] != olddata[r] for r in unfi)
5159 changes = sum(newdata[r] != olddata[r] for r in unfi)
5159 cl = unfi.changelog
5160 cl = unfi.changelog
5160 rejected = [n for n in nodes
5161 rejected = [n for n in nodes
5161 if newdata[cl.rev(n)] < targetphase]
5162 if newdata[cl.rev(n)] < targetphase]
5162 if rejected:
5163 if rejected:
5163 ui.warn(_('cannot move %i changesets to a higher '
5164 ui.warn(_('cannot move %i changesets to a higher '
5164 'phase, use --force\n') % len(rejected))
5165 'phase, use --force\n') % len(rejected))
5165 ret = 1
5166 ret = 1
5166 if changes:
5167 if changes:
5167 msg = _('phase changed for %i changesets\n') % changes
5168 msg = _('phase changed for %i changesets\n') % changes
5168 if ret:
5169 if ret:
5169 ui.status(msg)
5170 ui.status(msg)
5170 else:
5171 else:
5171 ui.note(msg)
5172 ui.note(msg)
5172 else:
5173 else:
5173 ui.warn(_('no phases changed\n'))
5174 ui.warn(_('no phases changed\n'))
5174 return ret
5175 return ret
5175
5176
5176 def postincoming(ui, repo, modheads, optupdate, checkout):
5177 def postincoming(ui, repo, modheads, optupdate, checkout):
5177 if modheads == 0:
5178 if modheads == 0:
5178 return
5179 return
5179 if optupdate:
5180 if optupdate:
5180 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
5181 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
5181 try:
5182 try:
5182 ret = hg.update(repo, checkout)
5183 ret = hg.update(repo, checkout)
5183 except util.Abort as inst:
5184 except util.Abort as inst:
5184 ui.warn(_("not updating: %s\n") % str(inst))
5185 ui.warn(_("not updating: %s\n") % str(inst))
5185 if inst.hint:
5186 if inst.hint:
5186 ui.warn(_("(%s)\n") % inst.hint)
5187 ui.warn(_("(%s)\n") % inst.hint)
5187 return 0
5188 return 0
5188 if not ret and not checkout:
5189 if not ret and not checkout:
5189 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5190 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5190 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5191 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5191 return ret
5192 return ret
5192 if modheads > 1:
5193 if modheads > 1:
5193 currentbranchheads = len(repo.branchheads())
5194 currentbranchheads = len(repo.branchheads())
5194 if currentbranchheads == modheads:
5195 if currentbranchheads == modheads:
5195 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5196 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5196 elif currentbranchheads > 1:
5197 elif currentbranchheads > 1:
5197 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5198 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5198 "merge)\n"))
5199 "merge)\n"))
5199 else:
5200 else:
5200 ui.status(_("(run 'hg heads' to see heads)\n"))
5201 ui.status(_("(run 'hg heads' to see heads)\n"))
5201 else:
5202 else:
5202 ui.status(_("(run 'hg update' to get a working copy)\n"))
5203 ui.status(_("(run 'hg update' to get a working copy)\n"))
5203
5204
5204 @command('^pull',
5205 @command('^pull',
5205 [('u', 'update', None,
5206 [('u', 'update', None,
5206 _('update to new branch head if changesets were pulled')),
5207 _('update to new branch head if changesets were pulled')),
5207 ('f', 'force', None, _('run even when remote repository is unrelated')),
5208 ('f', 'force', None, _('run even when remote repository is unrelated')),
5208 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5209 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5209 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5210 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5210 ('b', 'branch', [], _('a specific branch you would like to pull'),
5211 ('b', 'branch', [], _('a specific branch you would like to pull'),
5211 _('BRANCH')),
5212 _('BRANCH')),
5212 ] + remoteopts,
5213 ] + remoteopts,
5213 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5214 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5214 def pull(ui, repo, source="default", **opts):
5215 def pull(ui, repo, source="default", **opts):
5215 """pull changes from the specified source
5216 """pull changes from the specified source
5216
5217
5217 Pull changes from a remote repository to a local one.
5218 Pull changes from a remote repository to a local one.
5218
5219
5219 This finds all changes from the repository at the specified path
5220 This finds all changes from the repository at the specified path
5220 or URL and adds them to a local repository (the current one unless
5221 or URL and adds them to a local repository (the current one unless
5221 -R is specified). By default, this does not update the copy of the
5222 -R is specified). By default, this does not update the copy of the
5222 project in the working directory.
5223 project in the working directory.
5223
5224
5224 Use :hg:`incoming` if you want to see what would have been added
5225 Use :hg:`incoming` if you want to see what would have been added
5225 by a pull at the time you issued this command. If you then decide
5226 by a pull at the time you issued this command. If you then decide
5226 to add those changes to the repository, you should use :hg:`pull
5227 to add those changes to the repository, you should use :hg:`pull
5227 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5228 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5228
5229
5229 If SOURCE is omitted, the 'default' path will be used.
5230 If SOURCE is omitted, the 'default' path will be used.
5230 See :hg:`help urls` for more information.
5231 See :hg:`help urls` for more information.
5231
5232
5232 Returns 0 on success, 1 if an update had unresolved files.
5233 Returns 0 on success, 1 if an update had unresolved files.
5233 """
5234 """
5234 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5235 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5235 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5236 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5236 other = hg.peer(repo, opts, source)
5237 other = hg.peer(repo, opts, source)
5237 try:
5238 try:
5238 revs, checkout = hg.addbranchrevs(repo, other, branches,
5239 revs, checkout = hg.addbranchrevs(repo, other, branches,
5239 opts.get('rev'))
5240 opts.get('rev'))
5240
5241
5241
5242
5242 pullopargs = {}
5243 pullopargs = {}
5243 if opts.get('bookmark'):
5244 if opts.get('bookmark'):
5244 if not revs:
5245 if not revs:
5245 revs = []
5246 revs = []
5246 # The list of bookmark used here is not the one used to actually
5247 # The list of bookmark used here is not the one used to actually
5247 # update the bookmark name. This can result in the revision pulled
5248 # update the bookmark name. This can result in the revision pulled
5248 # not ending up with the name of the bookmark because of a race
5249 # not ending up with the name of the bookmark because of a race
5249 # condition on the server. (See issue 4689 for details)
5250 # condition on the server. (See issue 4689 for details)
5250 remotebookmarks = other.listkeys('bookmarks')
5251 remotebookmarks = other.listkeys('bookmarks')
5251 pullopargs['remotebookmarks'] = remotebookmarks
5252 pullopargs['remotebookmarks'] = remotebookmarks
5252 for b in opts['bookmark']:
5253 for b in opts['bookmark']:
5253 if b not in remotebookmarks:
5254 if b not in remotebookmarks:
5254 raise util.Abort(_('remote bookmark %s not found!') % b)
5255 raise util.Abort(_('remote bookmark %s not found!') % b)
5255 revs.append(remotebookmarks[b])
5256 revs.append(remotebookmarks[b])
5256
5257
5257 if revs:
5258 if revs:
5258 try:
5259 try:
5259 # When 'rev' is a bookmark name, we cannot guarantee that it
5260 # When 'rev' is a bookmark name, we cannot guarantee that it
5260 # will be updated with that name because of a race condition
5261 # will be updated with that name because of a race condition
5261 # server side. (See issue 4689 for details)
5262 # server side. (See issue 4689 for details)
5262 oldrevs = revs
5263 oldrevs = revs
5263 revs = [] # actually, nodes
5264 revs = [] # actually, nodes
5264 for r in oldrevs:
5265 for r in oldrevs:
5265 node = other.lookup(r)
5266 node = other.lookup(r)
5266 revs.append(node)
5267 revs.append(node)
5267 if r == checkout:
5268 if r == checkout:
5268 checkout = node
5269 checkout = node
5269 except error.CapabilityError:
5270 except error.CapabilityError:
5270 err = _("other repository doesn't support revision lookup, "
5271 err = _("other repository doesn't support revision lookup, "
5271 "so a rev cannot be specified.")
5272 "so a rev cannot be specified.")
5272 raise util.Abort(err)
5273 raise util.Abort(err)
5273
5274
5274 modheads = exchange.pull(repo, other, heads=revs,
5275 modheads = exchange.pull(repo, other, heads=revs,
5275 force=opts.get('force'),
5276 force=opts.get('force'),
5276 bookmarks=opts.get('bookmark', ()),
5277 bookmarks=opts.get('bookmark', ()),
5277 opargs=pullopargs).cgresult
5278 opargs=pullopargs).cgresult
5278 if checkout:
5279 if checkout:
5279 checkout = str(repo.changelog.rev(checkout))
5280 checkout = str(repo.changelog.rev(checkout))
5280 repo._subtoppath = source
5281 repo._subtoppath = source
5281 try:
5282 try:
5282 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5283 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5283
5284
5284 finally:
5285 finally:
5285 del repo._subtoppath
5286 del repo._subtoppath
5286
5287
5287 finally:
5288 finally:
5288 other.close()
5289 other.close()
5289 return ret
5290 return ret
5290
5291
5291 @command('^push',
5292 @command('^push',
5292 [('f', 'force', None, _('force push')),
5293 [('f', 'force', None, _('force push')),
5293 ('r', 'rev', [],
5294 ('r', 'rev', [],
5294 _('a changeset intended to be included in the destination'),
5295 _('a changeset intended to be included in the destination'),
5295 _('REV')),
5296 _('REV')),
5296 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5297 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5297 ('b', 'branch', [],
5298 ('b', 'branch', [],
5298 _('a specific branch you would like to push'), _('BRANCH')),
5299 _('a specific branch you would like to push'), _('BRANCH')),
5299 ('', 'new-branch', False, _('allow pushing a new branch')),
5300 ('', 'new-branch', False, _('allow pushing a new branch')),
5300 ] + remoteopts,
5301 ] + remoteopts,
5301 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5302 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5302 def push(ui, repo, dest=None, **opts):
5303 def push(ui, repo, dest=None, **opts):
5303 """push changes to the specified destination
5304 """push changes to the specified destination
5304
5305
5305 Push changesets from the local repository to the specified
5306 Push changesets from the local repository to the specified
5306 destination.
5307 destination.
5307
5308
5308 This operation is symmetrical to pull: it is identical to a pull
5309 This operation is symmetrical to pull: it is identical to a pull
5309 in the destination repository from the current one.
5310 in the destination repository from the current one.
5310
5311
5311 By default, push will not allow creation of new heads at the
5312 By default, push will not allow creation of new heads at the
5312 destination, since multiple heads would make it unclear which head
5313 destination, since multiple heads would make it unclear which head
5313 to use. In this situation, it is recommended to pull and merge
5314 to use. In this situation, it is recommended to pull and merge
5314 before pushing.
5315 before pushing.
5315
5316
5316 Use --new-branch if you want to allow push to create a new named
5317 Use --new-branch if you want to allow push to create a new named
5317 branch that is not present at the destination. This allows you to
5318 branch that is not present at the destination. This allows you to
5318 only create a new branch without forcing other changes.
5319 only create a new branch without forcing other changes.
5319
5320
5320 .. note::
5321 .. note::
5321
5322
5322 Extra care should be taken with the -f/--force option,
5323 Extra care should be taken with the -f/--force option,
5323 which will push all new heads on all branches, an action which will
5324 which will push all new heads on all branches, an action which will
5324 almost always cause confusion for collaborators.
5325 almost always cause confusion for collaborators.
5325
5326
5326 If -r/--rev is used, the specified revision and all its ancestors
5327 If -r/--rev is used, the specified revision and all its ancestors
5327 will be pushed to the remote repository.
5328 will be pushed to the remote repository.
5328
5329
5329 If -B/--bookmark is used, the specified bookmarked revision, its
5330 If -B/--bookmark is used, the specified bookmarked revision, its
5330 ancestors, and the bookmark will be pushed to the remote
5331 ancestors, and the bookmark will be pushed to the remote
5331 repository.
5332 repository.
5332
5333
5333 Please see :hg:`help urls` for important details about ``ssh://``
5334 Please see :hg:`help urls` for important details about ``ssh://``
5334 URLs. If DESTINATION is omitted, a default path will be used.
5335 URLs. If DESTINATION is omitted, a default path will be used.
5335
5336
5336 Returns 0 if push was successful, 1 if nothing to push.
5337 Returns 0 if push was successful, 1 if nothing to push.
5337 """
5338 """
5338
5339
5339 if opts.get('bookmark'):
5340 if opts.get('bookmark'):
5340 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5341 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5341 for b in opts['bookmark']:
5342 for b in opts['bookmark']:
5342 # translate -B options to -r so changesets get pushed
5343 # translate -B options to -r so changesets get pushed
5343 if b in repo._bookmarks:
5344 if b in repo._bookmarks:
5344 opts.setdefault('rev', []).append(b)
5345 opts.setdefault('rev', []).append(b)
5345 else:
5346 else:
5346 # if we try to push a deleted bookmark, translate it to null
5347 # if we try to push a deleted bookmark, translate it to null
5347 # this lets simultaneous -r, -b options continue working
5348 # this lets simultaneous -r, -b options continue working
5348 opts.setdefault('rev', []).append("null")
5349 opts.setdefault('rev', []).append("null")
5349
5350
5350 path = ui.paths.getpath(dest, default='default')
5351 path = ui.paths.getpath(dest, default='default')
5351 if not path:
5352 if not path:
5352 raise util.Abort(_('default repository not configured!'),
5353 raise util.Abort(_('default repository not configured!'),
5353 hint=_('see the "path" section in "hg help config"'))
5354 hint=_('see the "path" section in "hg help config"'))
5354 dest, branches = path.pushloc, (path.branch, opts.get('branch') or [])
5355 dest, branches = path.pushloc, (path.branch, opts.get('branch') or [])
5355 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5356 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5356 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5357 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5357 other = hg.peer(repo, opts, dest)
5358 other = hg.peer(repo, opts, dest)
5358
5359
5359 if revs:
5360 if revs:
5360 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5361 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5361 if not revs:
5362 if not revs:
5362 raise util.Abort(_("specified revisions evaluate to an empty set"),
5363 raise util.Abort(_("specified revisions evaluate to an empty set"),
5363 hint=_("use different revision arguments"))
5364 hint=_("use different revision arguments"))
5364
5365
5365 repo._subtoppath = dest
5366 repo._subtoppath = dest
5366 try:
5367 try:
5367 # push subrepos depth-first for coherent ordering
5368 # push subrepos depth-first for coherent ordering
5368 c = repo['']
5369 c = repo['']
5369 subs = c.substate # only repos that are committed
5370 subs = c.substate # only repos that are committed
5370 for s in sorted(subs):
5371 for s in sorted(subs):
5371 result = c.sub(s).push(opts)
5372 result = c.sub(s).push(opts)
5372 if result == 0:
5373 if result == 0:
5373 return not result
5374 return not result
5374 finally:
5375 finally:
5375 del repo._subtoppath
5376 del repo._subtoppath
5376 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5377 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5377 newbranch=opts.get('new_branch'),
5378 newbranch=opts.get('new_branch'),
5378 bookmarks=opts.get('bookmark', ()))
5379 bookmarks=opts.get('bookmark', ()))
5379
5380
5380 result = not pushop.cgresult
5381 result = not pushop.cgresult
5381
5382
5382 if pushop.bkresult is not None:
5383 if pushop.bkresult is not None:
5383 if pushop.bkresult == 2:
5384 if pushop.bkresult == 2:
5384 result = 2
5385 result = 2
5385 elif not result and pushop.bkresult:
5386 elif not result and pushop.bkresult:
5386 result = 2
5387 result = 2
5387
5388
5388 return result
5389 return result
5389
5390
5390 @command('recover', [])
5391 @command('recover', [])
5391 def recover(ui, repo):
5392 def recover(ui, repo):
5392 """roll back an interrupted transaction
5393 """roll back an interrupted transaction
5393
5394
5394 Recover from an interrupted commit or pull.
5395 Recover from an interrupted commit or pull.
5395
5396
5396 This command tries to fix the repository status after an
5397 This command tries to fix the repository status after an
5397 interrupted operation. It should only be necessary when Mercurial
5398 interrupted operation. It should only be necessary when Mercurial
5398 suggests it.
5399 suggests it.
5399
5400
5400 Returns 0 if successful, 1 if nothing to recover or verify fails.
5401 Returns 0 if successful, 1 if nothing to recover or verify fails.
5401 """
5402 """
5402 if repo.recover():
5403 if repo.recover():
5403 return hg.verify(repo)
5404 return hg.verify(repo)
5404 return 1
5405 return 1
5405
5406
5406 @command('^remove|rm',
5407 @command('^remove|rm',
5407 [('A', 'after', None, _('record delete for missing files')),
5408 [('A', 'after', None, _('record delete for missing files')),
5408 ('f', 'force', None,
5409 ('f', 'force', None,
5409 _('remove (and delete) file even if added or modified')),
5410 _('remove (and delete) file even if added or modified')),
5410 ] + subrepoopts + walkopts,
5411 ] + subrepoopts + walkopts,
5411 _('[OPTION]... FILE...'),
5412 _('[OPTION]... FILE...'),
5412 inferrepo=True)
5413 inferrepo=True)
5413 def remove(ui, repo, *pats, **opts):
5414 def remove(ui, repo, *pats, **opts):
5414 """remove the specified files on the next commit
5415 """remove the specified files on the next commit
5415
5416
5416 Schedule the indicated files for removal from the current branch.
5417 Schedule the indicated files for removal from the current branch.
5417
5418
5418 This command schedules the files to be removed at the next commit.
5419 This command schedules the files to be removed at the next commit.
5419 To undo a remove before that, see :hg:`revert`. To undo added
5420 To undo a remove before that, see :hg:`revert`. To undo added
5420 files, see :hg:`forget`.
5421 files, see :hg:`forget`.
5421
5422
5422 .. container:: verbose
5423 .. container:: verbose
5423
5424
5424 -A/--after can be used to remove only files that have already
5425 -A/--after can be used to remove only files that have already
5425 been deleted, -f/--force can be used to force deletion, and -Af
5426 been deleted, -f/--force can be used to force deletion, and -Af
5426 can be used to remove files from the next revision without
5427 can be used to remove files from the next revision without
5427 deleting them from the working directory.
5428 deleting them from the working directory.
5428
5429
5429 The following table details the behavior of remove for different
5430 The following table details the behavior of remove for different
5430 file states (columns) and option combinations (rows). The file
5431 file states (columns) and option combinations (rows). The file
5431 states are Added [A], Clean [C], Modified [M] and Missing [!]
5432 states are Added [A], Clean [C], Modified [M] and Missing [!]
5432 (as reported by :hg:`status`). The actions are Warn, Remove
5433 (as reported by :hg:`status`). The actions are Warn, Remove
5433 (from branch) and Delete (from disk):
5434 (from branch) and Delete (from disk):
5434
5435
5435 ========= == == == ==
5436 ========= == == == ==
5436 opt/state A C M !
5437 opt/state A C M !
5437 ========= == == == ==
5438 ========= == == == ==
5438 none W RD W R
5439 none W RD W R
5439 -f R RD RD R
5440 -f R RD RD R
5440 -A W W W R
5441 -A W W W R
5441 -Af R R R R
5442 -Af R R R R
5442 ========= == == == ==
5443 ========= == == == ==
5443
5444
5444 Note that remove never deletes files in Added [A] state from the
5445 Note that remove never deletes files in Added [A] state from the
5445 working directory, not even if option --force is specified.
5446 working directory, not even if option --force is specified.
5446
5447
5447 Returns 0 on success, 1 if any warnings encountered.
5448 Returns 0 on success, 1 if any warnings encountered.
5448 """
5449 """
5449
5450
5450 after, force = opts.get('after'), opts.get('force')
5451 after, force = opts.get('after'), opts.get('force')
5451 if not pats and not after:
5452 if not pats and not after:
5452 raise util.Abort(_('no files specified'))
5453 raise util.Abort(_('no files specified'))
5453
5454
5454 m = scmutil.match(repo[None], pats, opts)
5455 m = scmutil.match(repo[None], pats, opts)
5455 subrepos = opts.get('subrepos')
5456 subrepos = opts.get('subrepos')
5456 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5457 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5457
5458
5458 @command('rename|move|mv',
5459 @command('rename|move|mv',
5459 [('A', 'after', None, _('record a rename that has already occurred')),
5460 [('A', 'after', None, _('record a rename that has already occurred')),
5460 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5461 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5461 ] + walkopts + dryrunopts,
5462 ] + walkopts + dryrunopts,
5462 _('[OPTION]... SOURCE... DEST'))
5463 _('[OPTION]... SOURCE... DEST'))
5463 def rename(ui, repo, *pats, **opts):
5464 def rename(ui, repo, *pats, **opts):
5464 """rename files; equivalent of copy + remove
5465 """rename files; equivalent of copy + remove
5465
5466
5466 Mark dest as copies of sources; mark sources for deletion. If dest
5467 Mark dest as copies of sources; mark sources for deletion. If dest
5467 is a directory, copies are put in that directory. If dest is a
5468 is a directory, copies are put in that directory. If dest is a
5468 file, there can only be one source.
5469 file, there can only be one source.
5469
5470
5470 By default, this command copies the contents of files as they
5471 By default, this command copies the contents of files as they
5471 exist in the working directory. If invoked with -A/--after, the
5472 exist in the working directory. If invoked with -A/--after, the
5472 operation is recorded, but no copying is performed.
5473 operation is recorded, but no copying is performed.
5473
5474
5474 This command takes effect at the next commit. To undo a rename
5475 This command takes effect at the next commit. To undo a rename
5475 before that, see :hg:`revert`.
5476 before that, see :hg:`revert`.
5476
5477
5477 Returns 0 on success, 1 if errors are encountered.
5478 Returns 0 on success, 1 if errors are encountered.
5478 """
5479 """
5479 wlock = repo.wlock(False)
5480 wlock = repo.wlock(False)
5480 try:
5481 try:
5481 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5482 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5482 finally:
5483 finally:
5483 wlock.release()
5484 wlock.release()
5484
5485
5485 @command('resolve',
5486 @command('resolve',
5486 [('a', 'all', None, _('select all unresolved files')),
5487 [('a', 'all', None, _('select all unresolved files')),
5487 ('l', 'list', None, _('list state of files needing merge')),
5488 ('l', 'list', None, _('list state of files needing merge')),
5488 ('m', 'mark', None, _('mark files as resolved')),
5489 ('m', 'mark', None, _('mark files as resolved')),
5489 ('u', 'unmark', None, _('mark files as unresolved')),
5490 ('u', 'unmark', None, _('mark files as unresolved')),
5490 ('n', 'no-status', None, _('hide status prefix'))]
5491 ('n', 'no-status', None, _('hide status prefix'))]
5491 + mergetoolopts + walkopts + formatteropts,
5492 + mergetoolopts + walkopts + formatteropts,
5492 _('[OPTION]... [FILE]...'),
5493 _('[OPTION]... [FILE]...'),
5493 inferrepo=True)
5494 inferrepo=True)
5494 def resolve(ui, repo, *pats, **opts):
5495 def resolve(ui, repo, *pats, **opts):
5495 """redo merges or set/view the merge status of files
5496 """redo merges or set/view the merge status of files
5496
5497
5497 Merges with unresolved conflicts are often the result of
5498 Merges with unresolved conflicts are often the result of
5498 non-interactive merging using the ``internal:merge`` configuration
5499 non-interactive merging using the ``internal:merge`` configuration
5499 setting, or a command-line merge tool like ``diff3``. The resolve
5500 setting, or a command-line merge tool like ``diff3``. The resolve
5500 command is used to manage the files involved in a merge, after
5501 command is used to manage the files involved in a merge, after
5501 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5502 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5502 working directory must have two parents). See :hg:`help
5503 working directory must have two parents). See :hg:`help
5503 merge-tools` for information on configuring merge tools.
5504 merge-tools` for information on configuring merge tools.
5504
5505
5505 The resolve command can be used in the following ways:
5506 The resolve command can be used in the following ways:
5506
5507
5507 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5508 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5508 files, discarding any previous merge attempts. Re-merging is not
5509 files, discarding any previous merge attempts. Re-merging is not
5509 performed for files already marked as resolved. Use ``--all/-a``
5510 performed for files already marked as resolved. Use ``--all/-a``
5510 to select all unresolved files. ``--tool`` can be used to specify
5511 to select all unresolved files. ``--tool`` can be used to specify
5511 the merge tool used for the given files. It overrides the HGMERGE
5512 the merge tool used for the given files. It overrides the HGMERGE
5512 environment variable and your configuration files. Previous file
5513 environment variable and your configuration files. Previous file
5513 contents are saved with a ``.orig`` suffix.
5514 contents are saved with a ``.orig`` suffix.
5514
5515
5515 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5516 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5516 (e.g. after having manually fixed-up the files). The default is
5517 (e.g. after having manually fixed-up the files). The default is
5517 to mark all unresolved files.
5518 to mark all unresolved files.
5518
5519
5519 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5520 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5520 default is to mark all resolved files.
5521 default is to mark all resolved files.
5521
5522
5522 - :hg:`resolve -l`: list files which had or still have conflicts.
5523 - :hg:`resolve -l`: list files which had or still have conflicts.
5523 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5524 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5524
5525
5525 Note that Mercurial will not let you commit files with unresolved
5526 Note that Mercurial will not let you commit files with unresolved
5526 merge conflicts. You must use :hg:`resolve -m ...` before you can
5527 merge conflicts. You must use :hg:`resolve -m ...` before you can
5527 commit after a conflicting merge.
5528 commit after a conflicting merge.
5528
5529
5529 Returns 0 on success, 1 if any files fail a resolve attempt.
5530 Returns 0 on success, 1 if any files fail a resolve attempt.
5530 """
5531 """
5531
5532
5532 all, mark, unmark, show, nostatus = \
5533 all, mark, unmark, show, nostatus = \
5533 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5534 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5534
5535
5535 if (show and (mark or unmark)) or (mark and unmark):
5536 if (show and (mark or unmark)) or (mark and unmark):
5536 raise util.Abort(_("too many options specified"))
5537 raise util.Abort(_("too many options specified"))
5537 if pats and all:
5538 if pats and all:
5538 raise util.Abort(_("can't specify --all and patterns"))
5539 raise util.Abort(_("can't specify --all and patterns"))
5539 if not (all or pats or show or mark or unmark):
5540 if not (all or pats or show or mark or unmark):
5540 raise util.Abort(_('no files or directories specified'),
5541 raise util.Abort(_('no files or directories specified'),
5541 hint=('use --all to re-merge all unresolved files'))
5542 hint=('use --all to re-merge all unresolved files'))
5542
5543
5543 if show:
5544 if show:
5544 fm = ui.formatter('resolve', opts)
5545 fm = ui.formatter('resolve', opts)
5545 ms = mergemod.mergestate(repo)
5546 ms = mergemod.mergestate(repo)
5546 m = scmutil.match(repo[None], pats, opts)
5547 m = scmutil.match(repo[None], pats, opts)
5547 for f in ms:
5548 for f in ms:
5548 if not m(f):
5549 if not m(f):
5549 continue
5550 continue
5550 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5551 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5551 fm.startitem()
5552 fm.startitem()
5552 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5553 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5553 fm.write('path', '%s\n', f, label=l)
5554 fm.write('path', '%s\n', f, label=l)
5554 fm.end()
5555 fm.end()
5555 return 0
5556 return 0
5556
5557
5557 wlock = repo.wlock()
5558 wlock = repo.wlock()
5558 try:
5559 try:
5559 ms = mergemod.mergestate(repo)
5560 ms = mergemod.mergestate(repo)
5560
5561
5561 if not (ms.active() or repo.dirstate.p2() != nullid):
5562 if not (ms.active() or repo.dirstate.p2() != nullid):
5562 raise util.Abort(
5563 raise util.Abort(
5563 _('resolve command not applicable when not merging'))
5564 _('resolve command not applicable when not merging'))
5564
5565
5565 m = scmutil.match(repo[None], pats, opts)
5566 m = scmutil.match(repo[None], pats, opts)
5566 ret = 0
5567 ret = 0
5567 didwork = False
5568 didwork = False
5568
5569
5569 for f in ms:
5570 for f in ms:
5570 if not m(f):
5571 if not m(f):
5571 continue
5572 continue
5572
5573
5573 didwork = True
5574 didwork = True
5574
5575
5575 if mark:
5576 if mark:
5576 ms.mark(f, "r")
5577 ms.mark(f, "r")
5577 elif unmark:
5578 elif unmark:
5578 ms.mark(f, "u")
5579 ms.mark(f, "u")
5579 else:
5580 else:
5580 wctx = repo[None]
5581 wctx = repo[None]
5581
5582
5582 # backup pre-resolve (merge uses .orig for its own purposes)
5583 # backup pre-resolve (merge uses .orig for its own purposes)
5583 a = repo.wjoin(f)
5584 a = repo.wjoin(f)
5584 util.copyfile(a, a + ".resolve")
5585 util.copyfile(a, a + ".resolve")
5585
5586
5586 try:
5587 try:
5587 # resolve file
5588 # resolve file
5588 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5589 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5589 'resolve')
5590 'resolve')
5590 if ms.resolve(f, wctx):
5591 if ms.resolve(f, wctx):
5591 ret = 1
5592 ret = 1
5592 finally:
5593 finally:
5593 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5594 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5594 ms.commit()
5595 ms.commit()
5595
5596
5596 # replace filemerge's .orig file with our resolve file
5597 # replace filemerge's .orig file with our resolve file
5597 util.rename(a + ".resolve", a + ".orig")
5598 util.rename(a + ".resolve", a + ".orig")
5598
5599
5599 ms.commit()
5600 ms.commit()
5600
5601
5601 if not didwork and pats:
5602 if not didwork and pats:
5602 ui.warn(_("arguments do not match paths that need resolving\n"))
5603 ui.warn(_("arguments do not match paths that need resolving\n"))
5603
5604
5604 finally:
5605 finally:
5605 wlock.release()
5606 wlock.release()
5606
5607
5607 # Nudge users into finishing an unfinished operation
5608 # Nudge users into finishing an unfinished operation
5608 if not list(ms.unresolved()):
5609 if not list(ms.unresolved()):
5609 ui.status(_('(no more unresolved files)\n'))
5610 ui.status(_('(no more unresolved files)\n'))
5610
5611
5611 return ret
5612 return ret
5612
5613
5613 @command('revert',
5614 @command('revert',
5614 [('a', 'all', None, _('revert all changes when no arguments given')),
5615 [('a', 'all', None, _('revert all changes when no arguments given')),
5615 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5616 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5616 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5617 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5617 ('C', 'no-backup', None, _('do not save backup copies of files')),
5618 ('C', 'no-backup', None, _('do not save backup copies of files')),
5618 ('i', 'interactive', None,
5619 ('i', 'interactive', None,
5619 _('interactively select the changes (EXPERIMENTAL)')),
5620 _('interactively select the changes (EXPERIMENTAL)')),
5620 ] + walkopts + dryrunopts,
5621 ] + walkopts + dryrunopts,
5621 _('[OPTION]... [-r REV] [NAME]...'))
5622 _('[OPTION]... [-r REV] [NAME]...'))
5622 def revert(ui, repo, *pats, **opts):
5623 def revert(ui, repo, *pats, **opts):
5623 """restore files to their checkout state
5624 """restore files to their checkout state
5624
5625
5625 .. note::
5626 .. note::
5626
5627
5627 To check out earlier revisions, you should use :hg:`update REV`.
5628 To check out earlier revisions, you should use :hg:`update REV`.
5628 To cancel an uncommitted merge (and lose your changes),
5629 To cancel an uncommitted merge (and lose your changes),
5629 use :hg:`update --clean .`.
5630 use :hg:`update --clean .`.
5630
5631
5631 With no revision specified, revert the specified files or directories
5632 With no revision specified, revert the specified files or directories
5632 to the contents they had in the parent of the working directory.
5633 to the contents they had in the parent of the working directory.
5633 This restores the contents of files to an unmodified
5634 This restores the contents of files to an unmodified
5634 state and unschedules adds, removes, copies, and renames. If the
5635 state and unschedules adds, removes, copies, and renames. If the
5635 working directory has two parents, you must explicitly specify a
5636 working directory has two parents, you must explicitly specify a
5636 revision.
5637 revision.
5637
5638
5638 Using the -r/--rev or -d/--date options, revert the given files or
5639 Using the -r/--rev or -d/--date options, revert the given files or
5639 directories to their states as of a specific revision. Because
5640 directories to their states as of a specific revision. Because
5640 revert does not change the working directory parents, this will
5641 revert does not change the working directory parents, this will
5641 cause these files to appear modified. This can be helpful to "back
5642 cause these files to appear modified. This can be helpful to "back
5642 out" some or all of an earlier change. See :hg:`backout` for a
5643 out" some or all of an earlier change. See :hg:`backout` for a
5643 related method.
5644 related method.
5644
5645
5645 Modified files are saved with a .orig suffix before reverting.
5646 Modified files are saved with a .orig suffix before reverting.
5646 To disable these backups, use --no-backup.
5647 To disable these backups, use --no-backup.
5647
5648
5648 See :hg:`help dates` for a list of formats valid for -d/--date.
5649 See :hg:`help dates` for a list of formats valid for -d/--date.
5649
5650
5650 See :hg:`help backout` for a way to reverse the effect of an
5651 See :hg:`help backout` for a way to reverse the effect of an
5651 earlier changeset.
5652 earlier changeset.
5652
5653
5653 Returns 0 on success.
5654 Returns 0 on success.
5654 """
5655 """
5655
5656
5656 if opts.get("date"):
5657 if opts.get("date"):
5657 if opts.get("rev"):
5658 if opts.get("rev"):
5658 raise util.Abort(_("you can't specify a revision and a date"))
5659 raise util.Abort(_("you can't specify a revision and a date"))
5659 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5660 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5660
5661
5661 parent, p2 = repo.dirstate.parents()
5662 parent, p2 = repo.dirstate.parents()
5662 if not opts.get('rev') and p2 != nullid:
5663 if not opts.get('rev') and p2 != nullid:
5663 # revert after merge is a trap for new users (issue2915)
5664 # revert after merge is a trap for new users (issue2915)
5664 raise util.Abort(_('uncommitted merge with no revision specified'),
5665 raise util.Abort(_('uncommitted merge with no revision specified'),
5665 hint=_('use "hg update" or see "hg help revert"'))
5666 hint=_('use "hg update" or see "hg help revert"'))
5666
5667
5667 ctx = scmutil.revsingle(repo, opts.get('rev'))
5668 ctx = scmutil.revsingle(repo, opts.get('rev'))
5668
5669
5669 if (not (pats or opts.get('include') or opts.get('exclude') or
5670 if (not (pats or opts.get('include') or opts.get('exclude') or
5670 opts.get('all') or opts.get('interactive'))):
5671 opts.get('all') or opts.get('interactive'))):
5671 msg = _("no files or directories specified")
5672 msg = _("no files or directories specified")
5672 if p2 != nullid:
5673 if p2 != nullid:
5673 hint = _("uncommitted merge, use --all to discard all changes,"
5674 hint = _("uncommitted merge, use --all to discard all changes,"
5674 " or 'hg update -C .' to abort the merge")
5675 " or 'hg update -C .' to abort the merge")
5675 raise util.Abort(msg, hint=hint)
5676 raise util.Abort(msg, hint=hint)
5676 dirty = any(repo.status())
5677 dirty = any(repo.status())
5677 node = ctx.node()
5678 node = ctx.node()
5678 if node != parent:
5679 if node != parent:
5679 if dirty:
5680 if dirty:
5680 hint = _("uncommitted changes, use --all to discard all"
5681 hint = _("uncommitted changes, use --all to discard all"
5681 " changes, or 'hg update %s' to update") % ctx.rev()
5682 " changes, or 'hg update %s' to update") % ctx.rev()
5682 else:
5683 else:
5683 hint = _("use --all to revert all files,"
5684 hint = _("use --all to revert all files,"
5684 " or 'hg update %s' to update") % ctx.rev()
5685 " or 'hg update %s' to update") % ctx.rev()
5685 elif dirty:
5686 elif dirty:
5686 hint = _("uncommitted changes, use --all to discard all changes")
5687 hint = _("uncommitted changes, use --all to discard all changes")
5687 else:
5688 else:
5688 hint = _("use --all to revert all files")
5689 hint = _("use --all to revert all files")
5689 raise util.Abort(msg, hint=hint)
5690 raise util.Abort(msg, hint=hint)
5690
5691
5691 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5692 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5692
5693
5693 @command('rollback', dryrunopts +
5694 @command('rollback', dryrunopts +
5694 [('f', 'force', False, _('ignore safety measures'))])
5695 [('f', 'force', False, _('ignore safety measures'))])
5695 def rollback(ui, repo, **opts):
5696 def rollback(ui, repo, **opts):
5696 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5697 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5697
5698
5698 Please use :hg:`commit --amend` instead of rollback to correct
5699 Please use :hg:`commit --amend` instead of rollback to correct
5699 mistakes in the last commit.
5700 mistakes in the last commit.
5700
5701
5701 This command should be used with care. There is only one level of
5702 This command should be used with care. There is only one level of
5702 rollback, and there is no way to undo a rollback. It will also
5703 rollback, and there is no way to undo a rollback. It will also
5703 restore the dirstate at the time of the last transaction, losing
5704 restore the dirstate at the time of the last transaction, losing
5704 any dirstate changes since that time. This command does not alter
5705 any dirstate changes since that time. This command does not alter
5705 the working directory.
5706 the working directory.
5706
5707
5707 Transactions are used to encapsulate the effects of all commands
5708 Transactions are used to encapsulate the effects of all commands
5708 that create new changesets or propagate existing changesets into a
5709 that create new changesets or propagate existing changesets into a
5709 repository.
5710 repository.
5710
5711
5711 .. container:: verbose
5712 .. container:: verbose
5712
5713
5713 For example, the following commands are transactional, and their
5714 For example, the following commands are transactional, and their
5714 effects can be rolled back:
5715 effects can be rolled back:
5715
5716
5716 - commit
5717 - commit
5717 - import
5718 - import
5718 - pull
5719 - pull
5719 - push (with this repository as the destination)
5720 - push (with this repository as the destination)
5720 - unbundle
5721 - unbundle
5721
5722
5722 To avoid permanent data loss, rollback will refuse to rollback a
5723 To avoid permanent data loss, rollback will refuse to rollback a
5723 commit transaction if it isn't checked out. Use --force to
5724 commit transaction if it isn't checked out. Use --force to
5724 override this protection.
5725 override this protection.
5725
5726
5726 This command is not intended for use on public repositories. Once
5727 This command is not intended for use on public repositories. Once
5727 changes are visible for pull by other users, rolling a transaction
5728 changes are visible for pull by other users, rolling a transaction
5728 back locally is ineffective (someone else may already have pulled
5729 back locally is ineffective (someone else may already have pulled
5729 the changes). Furthermore, a race is possible with readers of the
5730 the changes). Furthermore, a race is possible with readers of the
5730 repository; for example an in-progress pull from the repository
5731 repository; for example an in-progress pull from the repository
5731 may fail if a rollback is performed.
5732 may fail if a rollback is performed.
5732
5733
5733 Returns 0 on success, 1 if no rollback data is available.
5734 Returns 0 on success, 1 if no rollback data is available.
5734 """
5735 """
5735 return repo.rollback(dryrun=opts.get('dry_run'),
5736 return repo.rollback(dryrun=opts.get('dry_run'),
5736 force=opts.get('force'))
5737 force=opts.get('force'))
5737
5738
5738 @command('root', [])
5739 @command('root', [])
5739 def root(ui, repo):
5740 def root(ui, repo):
5740 """print the root (top) of the current working directory
5741 """print the root (top) of the current working directory
5741
5742
5742 Print the root directory of the current repository.
5743 Print the root directory of the current repository.
5743
5744
5744 Returns 0 on success.
5745 Returns 0 on success.
5745 """
5746 """
5746 ui.write(repo.root + "\n")
5747 ui.write(repo.root + "\n")
5747
5748
5748 @command('^serve',
5749 @command('^serve',
5749 [('A', 'accesslog', '', _('name of access log file to write to'),
5750 [('A', 'accesslog', '', _('name of access log file to write to'),
5750 _('FILE')),
5751 _('FILE')),
5751 ('d', 'daemon', None, _('run server in background')),
5752 ('d', 'daemon', None, _('run server in background')),
5752 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5753 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5753 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5754 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5754 # use string type, then we can check if something was passed
5755 # use string type, then we can check if something was passed
5755 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5756 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5756 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5757 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5757 _('ADDR')),
5758 _('ADDR')),
5758 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5759 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5759 _('PREFIX')),
5760 _('PREFIX')),
5760 ('n', 'name', '',
5761 ('n', 'name', '',
5761 _('name to show in web pages (default: working directory)'), _('NAME')),
5762 _('name to show in web pages (default: working directory)'), _('NAME')),
5762 ('', 'web-conf', '',
5763 ('', 'web-conf', '',
5763 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5764 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5764 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5765 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5765 _('FILE')),
5766 _('FILE')),
5766 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5767 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5767 ('', 'stdio', None, _('for remote clients')),
5768 ('', 'stdio', None, _('for remote clients')),
5768 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5769 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5769 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5770 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5770 ('', 'style', '', _('template style to use'), _('STYLE')),
5771 ('', 'style', '', _('template style to use'), _('STYLE')),
5771 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5772 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5772 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5773 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5773 _('[OPTION]...'),
5774 _('[OPTION]...'),
5774 optionalrepo=True)
5775 optionalrepo=True)
5775 def serve(ui, repo, **opts):
5776 def serve(ui, repo, **opts):
5776 """start stand-alone webserver
5777 """start stand-alone webserver
5777
5778
5778 Start a local HTTP repository browser and pull server. You can use
5779 Start a local HTTP repository browser and pull server. You can use
5779 this for ad-hoc sharing and browsing of repositories. It is
5780 this for ad-hoc sharing and browsing of repositories. It is
5780 recommended to use a real web server to serve a repository for
5781 recommended to use a real web server to serve a repository for
5781 longer periods of time.
5782 longer periods of time.
5782
5783
5783 Please note that the server does not implement access control.
5784 Please note that the server does not implement access control.
5784 This means that, by default, anybody can read from the server and
5785 This means that, by default, anybody can read from the server and
5785 nobody can write to it by default. Set the ``web.allow_push``
5786 nobody can write to it by default. Set the ``web.allow_push``
5786 option to ``*`` to allow everybody to push to the server. You
5787 option to ``*`` to allow everybody to push to the server. You
5787 should use a real web server if you need to authenticate users.
5788 should use a real web server if you need to authenticate users.
5788
5789
5789 By default, the server logs accesses to stdout and errors to
5790 By default, the server logs accesses to stdout and errors to
5790 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5791 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5791 files.
5792 files.
5792
5793
5793 To have the server choose a free port number to listen on, specify
5794 To have the server choose a free port number to listen on, specify
5794 a port number of 0; in this case, the server will print the port
5795 a port number of 0; in this case, the server will print the port
5795 number it uses.
5796 number it uses.
5796
5797
5797 Returns 0 on success.
5798 Returns 0 on success.
5798 """
5799 """
5799
5800
5800 if opts["stdio"] and opts["cmdserver"]:
5801 if opts["stdio"] and opts["cmdserver"]:
5801 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5802 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5802
5803
5803 if opts["stdio"]:
5804 if opts["stdio"]:
5804 if repo is None:
5805 if repo is None:
5805 raise error.RepoError(_("there is no Mercurial repository here"
5806 raise error.RepoError(_("there is no Mercurial repository here"
5806 " (.hg not found)"))
5807 " (.hg not found)"))
5807 s = sshserver.sshserver(ui, repo)
5808 s = sshserver.sshserver(ui, repo)
5808 s.serve_forever()
5809 s.serve_forever()
5809
5810
5810 if opts["cmdserver"]:
5811 if opts["cmdserver"]:
5811 import commandserver
5812 import commandserver
5812 service = commandserver.createservice(ui, repo, opts)
5813 service = commandserver.createservice(ui, repo, opts)
5813 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5814 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5814
5815
5815 # this way we can check if something was given in the command-line
5816 # this way we can check if something was given in the command-line
5816 if opts.get('port'):
5817 if opts.get('port'):
5817 opts['port'] = util.getport(opts.get('port'))
5818 opts['port'] = util.getport(opts.get('port'))
5818
5819
5819 if repo:
5820 if repo:
5820 baseui = repo.baseui
5821 baseui = repo.baseui
5821 else:
5822 else:
5822 baseui = ui
5823 baseui = ui
5823 optlist = ("name templates style address port prefix ipv6"
5824 optlist = ("name templates style address port prefix ipv6"
5824 " accesslog errorlog certificate encoding")
5825 " accesslog errorlog certificate encoding")
5825 for o in optlist.split():
5826 for o in optlist.split():
5826 val = opts.get(o, '')
5827 val = opts.get(o, '')
5827 if val in (None, ''): # should check against default options instead
5828 if val in (None, ''): # should check against default options instead
5828 continue
5829 continue
5829 baseui.setconfig("web", o, val, 'serve')
5830 baseui.setconfig("web", o, val, 'serve')
5830 if repo and repo.ui != baseui:
5831 if repo and repo.ui != baseui:
5831 repo.ui.setconfig("web", o, val, 'serve')
5832 repo.ui.setconfig("web", o, val, 'serve')
5832
5833
5833 o = opts.get('web_conf') or opts.get('webdir_conf')
5834 o = opts.get('web_conf') or opts.get('webdir_conf')
5834 if not o:
5835 if not o:
5835 if not repo:
5836 if not repo:
5836 raise error.RepoError(_("there is no Mercurial repository"
5837 raise error.RepoError(_("there is no Mercurial repository"
5837 " here (.hg not found)"))
5838 " here (.hg not found)"))
5838 o = repo
5839 o = repo
5839
5840
5840 app = hgweb.hgweb(o, baseui=baseui)
5841 app = hgweb.hgweb(o, baseui=baseui)
5841 service = httpservice(ui, app, opts)
5842 service = httpservice(ui, app, opts)
5842 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5843 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5843
5844
5844 class httpservice(object):
5845 class httpservice(object):
5845 def __init__(self, ui, app, opts):
5846 def __init__(self, ui, app, opts):
5846 self.ui = ui
5847 self.ui = ui
5847 self.app = app
5848 self.app = app
5848 self.opts = opts
5849 self.opts = opts
5849
5850
5850 def init(self):
5851 def init(self):
5851 util.setsignalhandler()
5852 util.setsignalhandler()
5852 self.httpd = hgweb_server.create_server(self.ui, self.app)
5853 self.httpd = hgweb_server.create_server(self.ui, self.app)
5853
5854
5854 if self.opts['port'] and not self.ui.verbose:
5855 if self.opts['port'] and not self.ui.verbose:
5855 return
5856 return
5856
5857
5857 if self.httpd.prefix:
5858 if self.httpd.prefix:
5858 prefix = self.httpd.prefix.strip('/') + '/'
5859 prefix = self.httpd.prefix.strip('/') + '/'
5859 else:
5860 else:
5860 prefix = ''
5861 prefix = ''
5861
5862
5862 port = ':%d' % self.httpd.port
5863 port = ':%d' % self.httpd.port
5863 if port == ':80':
5864 if port == ':80':
5864 port = ''
5865 port = ''
5865
5866
5866 bindaddr = self.httpd.addr
5867 bindaddr = self.httpd.addr
5867 if bindaddr == '0.0.0.0':
5868 if bindaddr == '0.0.0.0':
5868 bindaddr = '*'
5869 bindaddr = '*'
5869 elif ':' in bindaddr: # IPv6
5870 elif ':' in bindaddr: # IPv6
5870 bindaddr = '[%s]' % bindaddr
5871 bindaddr = '[%s]' % bindaddr
5871
5872
5872 fqaddr = self.httpd.fqaddr
5873 fqaddr = self.httpd.fqaddr
5873 if ':' in fqaddr:
5874 if ':' in fqaddr:
5874 fqaddr = '[%s]' % fqaddr
5875 fqaddr = '[%s]' % fqaddr
5875 if self.opts['port']:
5876 if self.opts['port']:
5876 write = self.ui.status
5877 write = self.ui.status
5877 else:
5878 else:
5878 write = self.ui.write
5879 write = self.ui.write
5879 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5880 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5880 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5881 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5881 self.ui.flush() # avoid buffering of status message
5882 self.ui.flush() # avoid buffering of status message
5882
5883
5883 def run(self):
5884 def run(self):
5884 self.httpd.serve_forever()
5885 self.httpd.serve_forever()
5885
5886
5886
5887
5887 @command('^status|st',
5888 @command('^status|st',
5888 [('A', 'all', None, _('show status of all files')),
5889 [('A', 'all', None, _('show status of all files')),
5889 ('m', 'modified', None, _('show only modified files')),
5890 ('m', 'modified', None, _('show only modified files')),
5890 ('a', 'added', None, _('show only added files')),
5891 ('a', 'added', None, _('show only added files')),
5891 ('r', 'removed', None, _('show only removed files')),
5892 ('r', 'removed', None, _('show only removed files')),
5892 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5893 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5893 ('c', 'clean', None, _('show only files without changes')),
5894 ('c', 'clean', None, _('show only files without changes')),
5894 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5895 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5895 ('i', 'ignored', None, _('show only ignored files')),
5896 ('i', 'ignored', None, _('show only ignored files')),
5896 ('n', 'no-status', None, _('hide status prefix')),
5897 ('n', 'no-status', None, _('hide status prefix')),
5897 ('C', 'copies', None, _('show source of copied files')),
5898 ('C', 'copies', None, _('show source of copied files')),
5898 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5899 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5899 ('', 'rev', [], _('show difference from revision'), _('REV')),
5900 ('', 'rev', [], _('show difference from revision'), _('REV')),
5900 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5901 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5901 ] + walkopts + subrepoopts + formatteropts,
5902 ] + walkopts + subrepoopts + formatteropts,
5902 _('[OPTION]... [FILE]...'),
5903 _('[OPTION]... [FILE]...'),
5903 inferrepo=True)
5904 inferrepo=True)
5904 def status(ui, repo, *pats, **opts):
5905 def status(ui, repo, *pats, **opts):
5905 """show changed files in the working directory
5906 """show changed files in the working directory
5906
5907
5907 Show status of files in the repository. If names are given, only
5908 Show status of files in the repository. If names are given, only
5908 files that match are shown. Files that are clean or ignored or
5909 files that match are shown. Files that are clean or ignored or
5909 the source of a copy/move operation, are not listed unless
5910 the source of a copy/move operation, are not listed unless
5910 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5911 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5911 Unless options described with "show only ..." are given, the
5912 Unless options described with "show only ..." are given, the
5912 options -mardu are used.
5913 options -mardu are used.
5913
5914
5914 Option -q/--quiet hides untracked (unknown and ignored) files
5915 Option -q/--quiet hides untracked (unknown and ignored) files
5915 unless explicitly requested with -u/--unknown or -i/--ignored.
5916 unless explicitly requested with -u/--unknown or -i/--ignored.
5916
5917
5917 .. note::
5918 .. note::
5918
5919
5919 status may appear to disagree with diff if permissions have
5920 status may appear to disagree with diff if permissions have
5920 changed or a merge has occurred. The standard diff format does
5921 changed or a merge has occurred. The standard diff format does
5921 not report permission changes and diff only reports changes
5922 not report permission changes and diff only reports changes
5922 relative to one merge parent.
5923 relative to one merge parent.
5923
5924
5924 If one revision is given, it is used as the base revision.
5925 If one revision is given, it is used as the base revision.
5925 If two revisions are given, the differences between them are
5926 If two revisions are given, the differences between them are
5926 shown. The --change option can also be used as a shortcut to list
5927 shown. The --change option can also be used as a shortcut to list
5927 the changed files of a revision from its first parent.
5928 the changed files of a revision from its first parent.
5928
5929
5929 The codes used to show the status of files are::
5930 The codes used to show the status of files are::
5930
5931
5931 M = modified
5932 M = modified
5932 A = added
5933 A = added
5933 R = removed
5934 R = removed
5934 C = clean
5935 C = clean
5935 ! = missing (deleted by non-hg command, but still tracked)
5936 ! = missing (deleted by non-hg command, but still tracked)
5936 ? = not tracked
5937 ? = not tracked
5937 I = ignored
5938 I = ignored
5938 = origin of the previous file (with --copies)
5939 = origin of the previous file (with --copies)
5939
5940
5940 .. container:: verbose
5941 .. container:: verbose
5941
5942
5942 Examples:
5943 Examples:
5943
5944
5944 - show changes in the working directory relative to a
5945 - show changes in the working directory relative to a
5945 changeset::
5946 changeset::
5946
5947
5947 hg status --rev 9353
5948 hg status --rev 9353
5948
5949
5949 - show changes in the working directory relative to the
5950 - show changes in the working directory relative to the
5950 current directory (see :hg:`help patterns` for more information)::
5951 current directory (see :hg:`help patterns` for more information)::
5951
5952
5952 hg status re:
5953 hg status re:
5953
5954
5954 - show all changes including copies in an existing changeset::
5955 - show all changes including copies in an existing changeset::
5955
5956
5956 hg status --copies --change 9353
5957 hg status --copies --change 9353
5957
5958
5958 - get a NUL separated list of added files, suitable for xargs::
5959 - get a NUL separated list of added files, suitable for xargs::
5959
5960
5960 hg status -an0
5961 hg status -an0
5961
5962
5962 Returns 0 on success.
5963 Returns 0 on success.
5963 """
5964 """
5964
5965
5965 revs = opts.get('rev')
5966 revs = opts.get('rev')
5966 change = opts.get('change')
5967 change = opts.get('change')
5967
5968
5968 if revs and change:
5969 if revs and change:
5969 msg = _('cannot specify --rev and --change at the same time')
5970 msg = _('cannot specify --rev and --change at the same time')
5970 raise util.Abort(msg)
5971 raise util.Abort(msg)
5971 elif change:
5972 elif change:
5972 node2 = scmutil.revsingle(repo, change, None).node()
5973 node2 = scmutil.revsingle(repo, change, None).node()
5973 node1 = repo[node2].p1().node()
5974 node1 = repo[node2].p1().node()
5974 else:
5975 else:
5975 node1, node2 = scmutil.revpair(repo, revs)
5976 node1, node2 = scmutil.revpair(repo, revs)
5976
5977
5977 if pats:
5978 if pats:
5978 cwd = repo.getcwd()
5979 cwd = repo.getcwd()
5979 else:
5980 else:
5980 cwd = ''
5981 cwd = ''
5981
5982
5982 if opts.get('print0'):
5983 if opts.get('print0'):
5983 end = '\0'
5984 end = '\0'
5984 else:
5985 else:
5985 end = '\n'
5986 end = '\n'
5986 copy = {}
5987 copy = {}
5987 states = 'modified added removed deleted unknown ignored clean'.split()
5988 states = 'modified added removed deleted unknown ignored clean'.split()
5988 show = [k for k in states if opts.get(k)]
5989 show = [k for k in states if opts.get(k)]
5989 if opts.get('all'):
5990 if opts.get('all'):
5990 show += ui.quiet and (states[:4] + ['clean']) or states
5991 show += ui.quiet and (states[:4] + ['clean']) or states
5991 if not show:
5992 if not show:
5992 if ui.quiet:
5993 if ui.quiet:
5993 show = states[:4]
5994 show = states[:4]
5994 else:
5995 else:
5995 show = states[:5]
5996 show = states[:5]
5996
5997
5997 m = scmutil.match(repo[node2], pats, opts)
5998 m = scmutil.match(repo[node2], pats, opts)
5998 stat = repo.status(node1, node2, m,
5999 stat = repo.status(node1, node2, m,
5999 'ignored' in show, 'clean' in show, 'unknown' in show,
6000 'ignored' in show, 'clean' in show, 'unknown' in show,
6000 opts.get('subrepos'))
6001 opts.get('subrepos'))
6001 changestates = zip(states, 'MAR!?IC', stat)
6002 changestates = zip(states, 'MAR!?IC', stat)
6002
6003
6003 if (opts.get('all') or opts.get('copies')
6004 if (opts.get('all') or opts.get('copies')
6004 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6005 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6005 copy = copies.pathcopies(repo[node1], repo[node2], m)
6006 copy = copies.pathcopies(repo[node1], repo[node2], m)
6006
6007
6007 fm = ui.formatter('status', opts)
6008 fm = ui.formatter('status', opts)
6008 fmt = '%s' + end
6009 fmt = '%s' + end
6009 showchar = not opts.get('no_status')
6010 showchar = not opts.get('no_status')
6010
6011
6011 for state, char, files in changestates:
6012 for state, char, files in changestates:
6012 if state in show:
6013 if state in show:
6013 label = 'status.' + state
6014 label = 'status.' + state
6014 for f in files:
6015 for f in files:
6015 fm.startitem()
6016 fm.startitem()
6016 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6017 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6017 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6018 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6018 if f in copy:
6019 if f in copy:
6019 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6020 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6020 label='status.copied')
6021 label='status.copied')
6021 fm.end()
6022 fm.end()
6022
6023
6023 @command('^summary|sum',
6024 @command('^summary|sum',
6024 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6025 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6025 def summary(ui, repo, **opts):
6026 def summary(ui, repo, **opts):
6026 """summarize working directory state
6027 """summarize working directory state
6027
6028
6028 This generates a brief summary of the working directory state,
6029 This generates a brief summary of the working directory state,
6029 including parents, branch, commit status, phase and available updates.
6030 including parents, branch, commit status, phase and available updates.
6030
6031
6031 With the --remote option, this will check the default paths for
6032 With the --remote option, this will check the default paths for
6032 incoming and outgoing changes. This can be time-consuming.
6033 incoming and outgoing changes. This can be time-consuming.
6033
6034
6034 Returns 0 on success.
6035 Returns 0 on success.
6035 """
6036 """
6036
6037
6037 ctx = repo[None]
6038 ctx = repo[None]
6038 parents = ctx.parents()
6039 parents = ctx.parents()
6039 pnode = parents[0].node()
6040 pnode = parents[0].node()
6040 marks = []
6041 marks = []
6041
6042
6042 for p in parents:
6043 for p in parents:
6043 # label with log.changeset (instead of log.parent) since this
6044 # label with log.changeset (instead of log.parent) since this
6044 # shows a working directory parent *changeset*:
6045 # shows a working directory parent *changeset*:
6045 # i18n: column positioning for "hg summary"
6046 # i18n: column positioning for "hg summary"
6046 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6047 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6047 label='log.changeset changeset.%s' % p.phasestr())
6048 label='log.changeset changeset.%s' % p.phasestr())
6048 ui.write(' '.join(p.tags()), label='log.tag')
6049 ui.write(' '.join(p.tags()), label='log.tag')
6049 if p.bookmarks():
6050 if p.bookmarks():
6050 marks.extend(p.bookmarks())
6051 marks.extend(p.bookmarks())
6051 if p.rev() == -1:
6052 if p.rev() == -1:
6052 if not len(repo):
6053 if not len(repo):
6053 ui.write(_(' (empty repository)'))
6054 ui.write(_(' (empty repository)'))
6054 else:
6055 else:
6055 ui.write(_(' (no revision checked out)'))
6056 ui.write(_(' (no revision checked out)'))
6056 ui.write('\n')
6057 ui.write('\n')
6057 if p.description():
6058 if p.description():
6058 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6059 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6059 label='log.summary')
6060 label='log.summary')
6060
6061
6061 branch = ctx.branch()
6062 branch = ctx.branch()
6062 bheads = repo.branchheads(branch)
6063 bheads = repo.branchheads(branch)
6063 # i18n: column positioning for "hg summary"
6064 # i18n: column positioning for "hg summary"
6064 m = _('branch: %s\n') % branch
6065 m = _('branch: %s\n') % branch
6065 if branch != 'default':
6066 if branch != 'default':
6066 ui.write(m, label='log.branch')
6067 ui.write(m, label='log.branch')
6067 else:
6068 else:
6068 ui.status(m, label='log.branch')
6069 ui.status(m, label='log.branch')
6069
6070
6070 if marks:
6071 if marks:
6071 active = repo._activebookmark
6072 active = repo._activebookmark
6072 # i18n: column positioning for "hg summary"
6073 # i18n: column positioning for "hg summary"
6073 ui.write(_('bookmarks:'), label='log.bookmark')
6074 ui.write(_('bookmarks:'), label='log.bookmark')
6074 if active is not None:
6075 if active is not None:
6075 if active in marks:
6076 if active in marks:
6076 ui.write(' *' + active, label=activebookmarklabel)
6077 ui.write(' *' + active, label=activebookmarklabel)
6077 marks.remove(active)
6078 marks.remove(active)
6078 else:
6079 else:
6079 ui.write(' [%s]' % active, label=activebookmarklabel)
6080 ui.write(' [%s]' % active, label=activebookmarklabel)
6080 for m in marks:
6081 for m in marks:
6081 ui.write(' ' + m, label='log.bookmark')
6082 ui.write(' ' + m, label='log.bookmark')
6082 ui.write('\n', label='log.bookmark')
6083 ui.write('\n', label='log.bookmark')
6083
6084
6084 status = repo.status(unknown=True)
6085 status = repo.status(unknown=True)
6085
6086
6086 c = repo.dirstate.copies()
6087 c = repo.dirstate.copies()
6087 copied, renamed = [], []
6088 copied, renamed = [], []
6088 for d, s in c.iteritems():
6089 for d, s in c.iteritems():
6089 if s in status.removed:
6090 if s in status.removed:
6090 status.removed.remove(s)
6091 status.removed.remove(s)
6091 renamed.append(d)
6092 renamed.append(d)
6092 else:
6093 else:
6093 copied.append(d)
6094 copied.append(d)
6094 if d in status.added:
6095 if d in status.added:
6095 status.added.remove(d)
6096 status.added.remove(d)
6096
6097
6097 ms = mergemod.mergestate(repo)
6098 ms = mergemod.mergestate(repo)
6098 unresolved = [f for f in ms if ms[f] == 'u']
6099 unresolved = [f for f in ms if ms[f] == 'u']
6099
6100
6100 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6101 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6101
6102
6102 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6103 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6103 (ui.label(_('%d added'), 'status.added'), status.added),
6104 (ui.label(_('%d added'), 'status.added'), status.added),
6104 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6105 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6105 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6106 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6106 (ui.label(_('%d copied'), 'status.copied'), copied),
6107 (ui.label(_('%d copied'), 'status.copied'), copied),
6107 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6108 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6108 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6109 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6109 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6110 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6110 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6111 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6111 t = []
6112 t = []
6112 for l, s in labels:
6113 for l, s in labels:
6113 if s:
6114 if s:
6114 t.append(l % len(s))
6115 t.append(l % len(s))
6115
6116
6116 t = ', '.join(t)
6117 t = ', '.join(t)
6117 cleanworkdir = False
6118 cleanworkdir = False
6118
6119
6119 if repo.vfs.exists('updatestate'):
6120 if repo.vfs.exists('updatestate'):
6120 t += _(' (interrupted update)')
6121 t += _(' (interrupted update)')
6121 elif len(parents) > 1:
6122 elif len(parents) > 1:
6122 t += _(' (merge)')
6123 t += _(' (merge)')
6123 elif branch != parents[0].branch():
6124 elif branch != parents[0].branch():
6124 t += _(' (new branch)')
6125 t += _(' (new branch)')
6125 elif (parents[0].closesbranch() and
6126 elif (parents[0].closesbranch() and
6126 pnode in repo.branchheads(branch, closed=True)):
6127 pnode in repo.branchheads(branch, closed=True)):
6127 t += _(' (head closed)')
6128 t += _(' (head closed)')
6128 elif not (status.modified or status.added or status.removed or renamed or
6129 elif not (status.modified or status.added or status.removed or renamed or
6129 copied or subs):
6130 copied or subs):
6130 t += _(' (clean)')
6131 t += _(' (clean)')
6131 cleanworkdir = True
6132 cleanworkdir = True
6132 elif pnode not in bheads:
6133 elif pnode not in bheads:
6133 t += _(' (new branch head)')
6134 t += _(' (new branch head)')
6134
6135
6135 if parents:
6136 if parents:
6136 pendingphase = max(p.phase() for p in parents)
6137 pendingphase = max(p.phase() for p in parents)
6137 else:
6138 else:
6138 pendingphase = phases.public
6139 pendingphase = phases.public
6139
6140
6140 if pendingphase > phases.newcommitphase(ui):
6141 if pendingphase > phases.newcommitphase(ui):
6141 t += ' (%s)' % phases.phasenames[pendingphase]
6142 t += ' (%s)' % phases.phasenames[pendingphase]
6142
6143
6143 if cleanworkdir:
6144 if cleanworkdir:
6144 # i18n: column positioning for "hg summary"
6145 # i18n: column positioning for "hg summary"
6145 ui.status(_('commit: %s\n') % t.strip())
6146 ui.status(_('commit: %s\n') % t.strip())
6146 else:
6147 else:
6147 # i18n: column positioning for "hg summary"
6148 # i18n: column positioning for "hg summary"
6148 ui.write(_('commit: %s\n') % t.strip())
6149 ui.write(_('commit: %s\n') % t.strip())
6149
6150
6150 # all ancestors of branch heads - all ancestors of parent = new csets
6151 # all ancestors of branch heads - all ancestors of parent = new csets
6151 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6152 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6152 bheads))
6153 bheads))
6153
6154
6154 if new == 0:
6155 if new == 0:
6155 # i18n: column positioning for "hg summary"
6156 # i18n: column positioning for "hg summary"
6156 ui.status(_('update: (current)\n'))
6157 ui.status(_('update: (current)\n'))
6157 elif pnode not in bheads:
6158 elif pnode not in bheads:
6158 # i18n: column positioning for "hg summary"
6159 # i18n: column positioning for "hg summary"
6159 ui.write(_('update: %d new changesets (update)\n') % new)
6160 ui.write(_('update: %d new changesets (update)\n') % new)
6160 else:
6161 else:
6161 # i18n: column positioning for "hg summary"
6162 # i18n: column positioning for "hg summary"
6162 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6163 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6163 (new, len(bheads)))
6164 (new, len(bheads)))
6164
6165
6165 t = []
6166 t = []
6166 draft = len(repo.revs('draft()'))
6167 draft = len(repo.revs('draft()'))
6167 if draft:
6168 if draft:
6168 t.append(_('%d draft') % draft)
6169 t.append(_('%d draft') % draft)
6169 secret = len(repo.revs('secret()'))
6170 secret = len(repo.revs('secret()'))
6170 if secret:
6171 if secret:
6171 t.append(_('%d secret') % secret)
6172 t.append(_('%d secret') % secret)
6172
6173
6173 if draft or secret:
6174 if draft or secret:
6174 ui.status(_('phases: %s\n') % ', '.join(t))
6175 ui.status(_('phases: %s\n') % ', '.join(t))
6175
6176
6176 cmdutil.summaryhooks(ui, repo)
6177 cmdutil.summaryhooks(ui, repo)
6177
6178
6178 if opts.get('remote'):
6179 if opts.get('remote'):
6179 needsincoming, needsoutgoing = True, True
6180 needsincoming, needsoutgoing = True, True
6180 else:
6181 else:
6181 needsincoming, needsoutgoing = False, False
6182 needsincoming, needsoutgoing = False, False
6182 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6183 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6183 if i:
6184 if i:
6184 needsincoming = True
6185 needsincoming = True
6185 if o:
6186 if o:
6186 needsoutgoing = True
6187 needsoutgoing = True
6187 if not needsincoming and not needsoutgoing:
6188 if not needsincoming and not needsoutgoing:
6188 return
6189 return
6189
6190
6190 def getincoming():
6191 def getincoming():
6191 source, branches = hg.parseurl(ui.expandpath('default'))
6192 source, branches = hg.parseurl(ui.expandpath('default'))
6192 sbranch = branches[0]
6193 sbranch = branches[0]
6193 try:
6194 try:
6194 other = hg.peer(repo, {}, source)
6195 other = hg.peer(repo, {}, source)
6195 except error.RepoError:
6196 except error.RepoError:
6196 if opts.get('remote'):
6197 if opts.get('remote'):
6197 raise
6198 raise
6198 return source, sbranch, None, None, None
6199 return source, sbranch, None, None, None
6199 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6200 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6200 if revs:
6201 if revs:
6201 revs = [other.lookup(rev) for rev in revs]
6202 revs = [other.lookup(rev) for rev in revs]
6202 ui.debug('comparing with %s\n' % util.hidepassword(source))
6203 ui.debug('comparing with %s\n' % util.hidepassword(source))
6203 repo.ui.pushbuffer()
6204 repo.ui.pushbuffer()
6204 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6205 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6205 repo.ui.popbuffer()
6206 repo.ui.popbuffer()
6206 return source, sbranch, other, commoninc, commoninc[1]
6207 return source, sbranch, other, commoninc, commoninc[1]
6207
6208
6208 if needsincoming:
6209 if needsincoming:
6209 source, sbranch, sother, commoninc, incoming = getincoming()
6210 source, sbranch, sother, commoninc, incoming = getincoming()
6210 else:
6211 else:
6211 source = sbranch = sother = commoninc = incoming = None
6212 source = sbranch = sother = commoninc = incoming = None
6212
6213
6213 def getoutgoing():
6214 def getoutgoing():
6214 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6215 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6215 dbranch = branches[0]
6216 dbranch = branches[0]
6216 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6217 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6217 if source != dest:
6218 if source != dest:
6218 try:
6219 try:
6219 dother = hg.peer(repo, {}, dest)
6220 dother = hg.peer(repo, {}, dest)
6220 except error.RepoError:
6221 except error.RepoError:
6221 if opts.get('remote'):
6222 if opts.get('remote'):
6222 raise
6223 raise
6223 return dest, dbranch, None, None
6224 return dest, dbranch, None, None
6224 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6225 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6225 elif sother is None:
6226 elif sother is None:
6226 # there is no explicit destination peer, but source one is invalid
6227 # there is no explicit destination peer, but source one is invalid
6227 return dest, dbranch, None, None
6228 return dest, dbranch, None, None
6228 else:
6229 else:
6229 dother = sother
6230 dother = sother
6230 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6231 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6231 common = None
6232 common = None
6232 else:
6233 else:
6233 common = commoninc
6234 common = commoninc
6234 if revs:
6235 if revs:
6235 revs = [repo.lookup(rev) for rev in revs]
6236 revs = [repo.lookup(rev) for rev in revs]
6236 repo.ui.pushbuffer()
6237 repo.ui.pushbuffer()
6237 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6238 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6238 commoninc=common)
6239 commoninc=common)
6239 repo.ui.popbuffer()
6240 repo.ui.popbuffer()
6240 return dest, dbranch, dother, outgoing
6241 return dest, dbranch, dother, outgoing
6241
6242
6242 if needsoutgoing:
6243 if needsoutgoing:
6243 dest, dbranch, dother, outgoing = getoutgoing()
6244 dest, dbranch, dother, outgoing = getoutgoing()
6244 else:
6245 else:
6245 dest = dbranch = dother = outgoing = None
6246 dest = dbranch = dother = outgoing = None
6246
6247
6247 if opts.get('remote'):
6248 if opts.get('remote'):
6248 t = []
6249 t = []
6249 if incoming:
6250 if incoming:
6250 t.append(_('1 or more incoming'))
6251 t.append(_('1 or more incoming'))
6251 o = outgoing.missing
6252 o = outgoing.missing
6252 if o:
6253 if o:
6253 t.append(_('%d outgoing') % len(o))
6254 t.append(_('%d outgoing') % len(o))
6254 other = dother or sother
6255 other = dother or sother
6255 if 'bookmarks' in other.listkeys('namespaces'):
6256 if 'bookmarks' in other.listkeys('namespaces'):
6256 counts = bookmarks.summary(repo, other)
6257 counts = bookmarks.summary(repo, other)
6257 if counts[0] > 0:
6258 if counts[0] > 0:
6258 t.append(_('%d incoming bookmarks') % counts[0])
6259 t.append(_('%d incoming bookmarks') % counts[0])
6259 if counts[1] > 0:
6260 if counts[1] > 0:
6260 t.append(_('%d outgoing bookmarks') % counts[1])
6261 t.append(_('%d outgoing bookmarks') % counts[1])
6261
6262
6262 if t:
6263 if t:
6263 # i18n: column positioning for "hg summary"
6264 # i18n: column positioning for "hg summary"
6264 ui.write(_('remote: %s\n') % (', '.join(t)))
6265 ui.write(_('remote: %s\n') % (', '.join(t)))
6265 else:
6266 else:
6266 # i18n: column positioning for "hg summary"
6267 # i18n: column positioning for "hg summary"
6267 ui.status(_('remote: (synced)\n'))
6268 ui.status(_('remote: (synced)\n'))
6268
6269
6269 cmdutil.summaryremotehooks(ui, repo, opts,
6270 cmdutil.summaryremotehooks(ui, repo, opts,
6270 ((source, sbranch, sother, commoninc),
6271 ((source, sbranch, sother, commoninc),
6271 (dest, dbranch, dother, outgoing)))
6272 (dest, dbranch, dother, outgoing)))
6272
6273
6273 @command('tag',
6274 @command('tag',
6274 [('f', 'force', None, _('force tag')),
6275 [('f', 'force', None, _('force tag')),
6275 ('l', 'local', None, _('make the tag local')),
6276 ('l', 'local', None, _('make the tag local')),
6276 ('r', 'rev', '', _('revision to tag'), _('REV')),
6277 ('r', 'rev', '', _('revision to tag'), _('REV')),
6277 ('', 'remove', None, _('remove a tag')),
6278 ('', 'remove', None, _('remove a tag')),
6278 # -l/--local is already there, commitopts cannot be used
6279 # -l/--local is already there, commitopts cannot be used
6279 ('e', 'edit', None, _('invoke editor on commit messages')),
6280 ('e', 'edit', None, _('invoke editor on commit messages')),
6280 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6281 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6281 ] + commitopts2,
6282 ] + commitopts2,
6282 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6283 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6283 def tag(ui, repo, name1, *names, **opts):
6284 def tag(ui, repo, name1, *names, **opts):
6284 """add one or more tags for the current or given revision
6285 """add one or more tags for the current or given revision
6285
6286
6286 Name a particular revision using <name>.
6287 Name a particular revision using <name>.
6287
6288
6288 Tags are used to name particular revisions of the repository and are
6289 Tags are used to name particular revisions of the repository and are
6289 very useful to compare different revisions, to go back to significant
6290 very useful to compare different revisions, to go back to significant
6290 earlier versions or to mark branch points as releases, etc. Changing
6291 earlier versions or to mark branch points as releases, etc. Changing
6291 an existing tag is normally disallowed; use -f/--force to override.
6292 an existing tag is normally disallowed; use -f/--force to override.
6292
6293
6293 If no revision is given, the parent of the working directory is
6294 If no revision is given, the parent of the working directory is
6294 used.
6295 used.
6295
6296
6296 To facilitate version control, distribution, and merging of tags,
6297 To facilitate version control, distribution, and merging of tags,
6297 they are stored as a file named ".hgtags" which is managed similarly
6298 they are stored as a file named ".hgtags" which is managed similarly
6298 to other project files and can be hand-edited if necessary. This
6299 to other project files and can be hand-edited if necessary. This
6299 also means that tagging creates a new commit. The file
6300 also means that tagging creates a new commit. The file
6300 ".hg/localtags" is used for local tags (not shared among
6301 ".hg/localtags" is used for local tags (not shared among
6301 repositories).
6302 repositories).
6302
6303
6303 Tag commits are usually made at the head of a branch. If the parent
6304 Tag commits are usually made at the head of a branch. If the parent
6304 of the working directory is not a branch head, :hg:`tag` aborts; use
6305 of the working directory is not a branch head, :hg:`tag` aborts; use
6305 -f/--force to force the tag commit to be based on a non-head
6306 -f/--force to force the tag commit to be based on a non-head
6306 changeset.
6307 changeset.
6307
6308
6308 See :hg:`help dates` for a list of formats valid for -d/--date.
6309 See :hg:`help dates` for a list of formats valid for -d/--date.
6309
6310
6310 Since tag names have priority over branch names during revision
6311 Since tag names have priority over branch names during revision
6311 lookup, using an existing branch name as a tag name is discouraged.
6312 lookup, using an existing branch name as a tag name is discouraged.
6312
6313
6313 Returns 0 on success.
6314 Returns 0 on success.
6314 """
6315 """
6315 wlock = lock = None
6316 wlock = lock = None
6316 try:
6317 try:
6317 wlock = repo.wlock()
6318 wlock = repo.wlock()
6318 lock = repo.lock()
6319 lock = repo.lock()
6319 rev_ = "."
6320 rev_ = "."
6320 names = [t.strip() for t in (name1,) + names]
6321 names = [t.strip() for t in (name1,) + names]
6321 if len(names) != len(set(names)):
6322 if len(names) != len(set(names)):
6322 raise util.Abort(_('tag names must be unique'))
6323 raise util.Abort(_('tag names must be unique'))
6323 for n in names:
6324 for n in names:
6324 scmutil.checknewlabel(repo, n, 'tag')
6325 scmutil.checknewlabel(repo, n, 'tag')
6325 if not n:
6326 if not n:
6326 raise util.Abort(_('tag names cannot consist entirely of '
6327 raise util.Abort(_('tag names cannot consist entirely of '
6327 'whitespace'))
6328 'whitespace'))
6328 if opts.get('rev') and opts.get('remove'):
6329 if opts.get('rev') and opts.get('remove'):
6329 raise util.Abort(_("--rev and --remove are incompatible"))
6330 raise util.Abort(_("--rev and --remove are incompatible"))
6330 if opts.get('rev'):
6331 if opts.get('rev'):
6331 rev_ = opts['rev']
6332 rev_ = opts['rev']
6332 message = opts.get('message')
6333 message = opts.get('message')
6333 if opts.get('remove'):
6334 if opts.get('remove'):
6334 if opts.get('local'):
6335 if opts.get('local'):
6335 expectedtype = 'local'
6336 expectedtype = 'local'
6336 else:
6337 else:
6337 expectedtype = 'global'
6338 expectedtype = 'global'
6338
6339
6339 for n in names:
6340 for n in names:
6340 if not repo.tagtype(n):
6341 if not repo.tagtype(n):
6341 raise util.Abort(_("tag '%s' does not exist") % n)
6342 raise util.Abort(_("tag '%s' does not exist") % n)
6342 if repo.tagtype(n) != expectedtype:
6343 if repo.tagtype(n) != expectedtype:
6343 if expectedtype == 'global':
6344 if expectedtype == 'global':
6344 raise util.Abort(_("tag '%s' is not a global tag") % n)
6345 raise util.Abort(_("tag '%s' is not a global tag") % n)
6345 else:
6346 else:
6346 raise util.Abort(_("tag '%s' is not a local tag") % n)
6347 raise util.Abort(_("tag '%s' is not a local tag") % n)
6347 rev_ = 'null'
6348 rev_ = 'null'
6348 if not message:
6349 if not message:
6349 # we don't translate commit messages
6350 # we don't translate commit messages
6350 message = 'Removed tag %s' % ', '.join(names)
6351 message = 'Removed tag %s' % ', '.join(names)
6351 elif not opts.get('force'):
6352 elif not opts.get('force'):
6352 for n in names:
6353 for n in names:
6353 if n in repo.tags():
6354 if n in repo.tags():
6354 raise util.Abort(_("tag '%s' already exists "
6355 raise util.Abort(_("tag '%s' already exists "
6355 "(use -f to force)") % n)
6356 "(use -f to force)") % n)
6356 if not opts.get('local'):
6357 if not opts.get('local'):
6357 p1, p2 = repo.dirstate.parents()
6358 p1, p2 = repo.dirstate.parents()
6358 if p2 != nullid:
6359 if p2 != nullid:
6359 raise util.Abort(_('uncommitted merge'))
6360 raise util.Abort(_('uncommitted merge'))
6360 bheads = repo.branchheads()
6361 bheads = repo.branchheads()
6361 if not opts.get('force') and bheads and p1 not in bheads:
6362 if not opts.get('force') and bheads and p1 not in bheads:
6362 raise util.Abort(_('not at a branch head (use -f to force)'))
6363 raise util.Abort(_('not at a branch head (use -f to force)'))
6363 r = scmutil.revsingle(repo, rev_).node()
6364 r = scmutil.revsingle(repo, rev_).node()
6364
6365
6365 if not message:
6366 if not message:
6366 # we don't translate commit messages
6367 # we don't translate commit messages
6367 message = ('Added tag %s for changeset %s' %
6368 message = ('Added tag %s for changeset %s' %
6368 (', '.join(names), short(r)))
6369 (', '.join(names), short(r)))
6369
6370
6370 date = opts.get('date')
6371 date = opts.get('date')
6371 if date:
6372 if date:
6372 date = util.parsedate(date)
6373 date = util.parsedate(date)
6373
6374
6374 if opts.get('remove'):
6375 if opts.get('remove'):
6375 editform = 'tag.remove'
6376 editform = 'tag.remove'
6376 else:
6377 else:
6377 editform = 'tag.add'
6378 editform = 'tag.add'
6378 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6379 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6379
6380
6380 # don't allow tagging the null rev
6381 # don't allow tagging the null rev
6381 if (not opts.get('remove') and
6382 if (not opts.get('remove') and
6382 scmutil.revsingle(repo, rev_).rev() == nullrev):
6383 scmutil.revsingle(repo, rev_).rev() == nullrev):
6383 raise util.Abort(_("cannot tag null revision"))
6384 raise util.Abort(_("cannot tag null revision"))
6384
6385
6385 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6386 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6386 editor=editor)
6387 editor=editor)
6387 finally:
6388 finally:
6388 release(lock, wlock)
6389 release(lock, wlock)
6389
6390
6390 @command('tags', formatteropts, '')
6391 @command('tags', formatteropts, '')
6391 def tags(ui, repo, **opts):
6392 def tags(ui, repo, **opts):
6392 """list repository tags
6393 """list repository tags
6393
6394
6394 This lists both regular and local tags. When the -v/--verbose
6395 This lists both regular and local tags. When the -v/--verbose
6395 switch is used, a third column "local" is printed for local tags.
6396 switch is used, a third column "local" is printed for local tags.
6396
6397
6397 Returns 0 on success.
6398 Returns 0 on success.
6398 """
6399 """
6399
6400
6400 fm = ui.formatter('tags', opts)
6401 fm = ui.formatter('tags', opts)
6401 hexfunc = fm.hexfunc
6402 hexfunc = fm.hexfunc
6402 tagtype = ""
6403 tagtype = ""
6403
6404
6404 for t, n in reversed(repo.tagslist()):
6405 for t, n in reversed(repo.tagslist()):
6405 hn = hexfunc(n)
6406 hn = hexfunc(n)
6406 label = 'tags.normal'
6407 label = 'tags.normal'
6407 tagtype = ''
6408 tagtype = ''
6408 if repo.tagtype(t) == 'local':
6409 if repo.tagtype(t) == 'local':
6409 label = 'tags.local'
6410 label = 'tags.local'
6410 tagtype = 'local'
6411 tagtype = 'local'
6411
6412
6412 fm.startitem()
6413 fm.startitem()
6413 fm.write('tag', '%s', t, label=label)
6414 fm.write('tag', '%s', t, label=label)
6414 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6415 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6415 fm.condwrite(not ui.quiet, 'rev node', fmt,
6416 fm.condwrite(not ui.quiet, 'rev node', fmt,
6416 repo.changelog.rev(n), hn, label=label)
6417 repo.changelog.rev(n), hn, label=label)
6417 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6418 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6418 tagtype, label=label)
6419 tagtype, label=label)
6419 fm.plain('\n')
6420 fm.plain('\n')
6420 fm.end()
6421 fm.end()
6421
6422
6422 @command('tip',
6423 @command('tip',
6423 [('p', 'patch', None, _('show patch')),
6424 [('p', 'patch', None, _('show patch')),
6424 ('g', 'git', None, _('use git extended diff format')),
6425 ('g', 'git', None, _('use git extended diff format')),
6425 ] + templateopts,
6426 ] + templateopts,
6426 _('[-p] [-g]'))
6427 _('[-p] [-g]'))
6427 def tip(ui, repo, **opts):
6428 def tip(ui, repo, **opts):
6428 """show the tip revision (DEPRECATED)
6429 """show the tip revision (DEPRECATED)
6429
6430
6430 The tip revision (usually just called the tip) is the changeset
6431 The tip revision (usually just called the tip) is the changeset
6431 most recently added to the repository (and therefore the most
6432 most recently added to the repository (and therefore the most
6432 recently changed head).
6433 recently changed head).
6433
6434
6434 If you have just made a commit, that commit will be the tip. If
6435 If you have just made a commit, that commit will be the tip. If
6435 you have just pulled changes from another repository, the tip of
6436 you have just pulled changes from another repository, the tip of
6436 that repository becomes the current tip. The "tip" tag is special
6437 that repository becomes the current tip. The "tip" tag is special
6437 and cannot be renamed or assigned to a different changeset.
6438 and cannot be renamed or assigned to a different changeset.
6438
6439
6439 This command is deprecated, please use :hg:`heads` instead.
6440 This command is deprecated, please use :hg:`heads` instead.
6440
6441
6441 Returns 0 on success.
6442 Returns 0 on success.
6442 """
6443 """
6443 displayer = cmdutil.show_changeset(ui, repo, opts)
6444 displayer = cmdutil.show_changeset(ui, repo, opts)
6444 displayer.show(repo['tip'])
6445 displayer.show(repo['tip'])
6445 displayer.close()
6446 displayer.close()
6446
6447
6447 @command('unbundle',
6448 @command('unbundle',
6448 [('u', 'update', None,
6449 [('u', 'update', None,
6449 _('update to new branch head if changesets were unbundled'))],
6450 _('update to new branch head if changesets were unbundled'))],
6450 _('[-u] FILE...'))
6451 _('[-u] FILE...'))
6451 def unbundle(ui, repo, fname1, *fnames, **opts):
6452 def unbundle(ui, repo, fname1, *fnames, **opts):
6452 """apply one or more changegroup files
6453 """apply one or more changegroup files
6453
6454
6454 Apply one or more compressed changegroup files generated by the
6455 Apply one or more compressed changegroup files generated by the
6455 bundle command.
6456 bundle command.
6456
6457
6457 Returns 0 on success, 1 if an update has unresolved files.
6458 Returns 0 on success, 1 if an update has unresolved files.
6458 """
6459 """
6459 fnames = (fname1,) + fnames
6460 fnames = (fname1,) + fnames
6460
6461
6461 lock = repo.lock()
6462 lock = repo.lock()
6462 try:
6463 try:
6463 for fname in fnames:
6464 for fname in fnames:
6464 f = hg.openpath(ui, fname)
6465 f = hg.openpath(ui, fname)
6465 gen = exchange.readbundle(ui, f, fname)
6466 gen = exchange.readbundle(ui, f, fname)
6466 if isinstance(gen, bundle2.unbundle20):
6467 if isinstance(gen, bundle2.unbundle20):
6467 tr = repo.transaction('unbundle')
6468 tr = repo.transaction('unbundle')
6468 try:
6469 try:
6469 op = bundle2.processbundle(repo, gen, lambda: tr)
6470 op = bundle2.processbundle(repo, gen, lambda: tr)
6470 tr.close()
6471 tr.close()
6471 except error.BundleUnknownFeatureError as exc:
6472 except error.BundleUnknownFeatureError as exc:
6472 raise util.Abort(_('%s: unknown bundle feature, %s')
6473 raise util.Abort(_('%s: unknown bundle feature, %s')
6473 % (fname, exc),
6474 % (fname, exc),
6474 hint=_("see https://mercurial-scm.org/"
6475 hint=_("see https://mercurial-scm.org/"
6475 "wiki/BundleFeature for more "
6476 "wiki/BundleFeature for more "
6476 "information"))
6477 "information"))
6477 finally:
6478 finally:
6478 if tr:
6479 if tr:
6479 tr.release()
6480 tr.release()
6480 changes = [r.get('return', 0)
6481 changes = [r.get('return', 0)
6481 for r in op.records['changegroup']]
6482 for r in op.records['changegroup']]
6482 modheads = changegroup.combineresults(changes)
6483 modheads = changegroup.combineresults(changes)
6483 else:
6484 else:
6484 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6485 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6485 'bundle:' + fname)
6486 'bundle:' + fname)
6486 finally:
6487 finally:
6487 lock.release()
6488 lock.release()
6488
6489
6489 return postincoming(ui, repo, modheads, opts.get('update'), None)
6490 return postincoming(ui, repo, modheads, opts.get('update'), None)
6490
6491
6491 @command('^update|up|checkout|co',
6492 @command('^update|up|checkout|co',
6492 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6493 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6493 ('c', 'check', None,
6494 ('c', 'check', None,
6494 _('update across branches if no uncommitted changes')),
6495 _('update across branches if no uncommitted changes')),
6495 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6496 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6496 ('r', 'rev', '', _('revision'), _('REV'))
6497 ('r', 'rev', '', _('revision'), _('REV'))
6497 ] + mergetoolopts,
6498 ] + mergetoolopts,
6498 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6499 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6499 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6500 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6500 tool=None):
6501 tool=None):
6501 """update working directory (or switch revisions)
6502 """update working directory (or switch revisions)
6502
6503
6503 Update the repository's working directory to the specified
6504 Update the repository's working directory to the specified
6504 changeset. If no changeset is specified, update to the tip of the
6505 changeset. If no changeset is specified, update to the tip of the
6505 current named branch and move the active bookmark (see :hg:`help
6506 current named branch and move the active bookmark (see :hg:`help
6506 bookmarks`).
6507 bookmarks`).
6507
6508
6508 Update sets the working directory's parent revision to the specified
6509 Update sets the working directory's parent revision to the specified
6509 changeset (see :hg:`help parents`).
6510 changeset (see :hg:`help parents`).
6510
6511
6511 If the changeset is not a descendant or ancestor of the working
6512 If the changeset is not a descendant or ancestor of the working
6512 directory's parent, the update is aborted. With the -c/--check
6513 directory's parent, the update is aborted. With the -c/--check
6513 option, the working directory is checked for uncommitted changes; if
6514 option, the working directory is checked for uncommitted changes; if
6514 none are found, the working directory is updated to the specified
6515 none are found, the working directory is updated to the specified
6515 changeset.
6516 changeset.
6516
6517
6517 .. container:: verbose
6518 .. container:: verbose
6518
6519
6519 The following rules apply when the working directory contains
6520 The following rules apply when the working directory contains
6520 uncommitted changes:
6521 uncommitted changes:
6521
6522
6522 1. If neither -c/--check nor -C/--clean is specified, and if
6523 1. If neither -c/--check nor -C/--clean is specified, and if
6523 the requested changeset is an ancestor or descendant of
6524 the requested changeset is an ancestor or descendant of
6524 the working directory's parent, the uncommitted changes
6525 the working directory's parent, the uncommitted changes
6525 are merged into the requested changeset and the merged
6526 are merged into the requested changeset and the merged
6526 result is left uncommitted. If the requested changeset is
6527 result is left uncommitted. If the requested changeset is
6527 not an ancestor or descendant (that is, it is on another
6528 not an ancestor or descendant (that is, it is on another
6528 branch), the update is aborted and the uncommitted changes
6529 branch), the update is aborted and the uncommitted changes
6529 are preserved.
6530 are preserved.
6530
6531
6531 2. With the -c/--check option, the update is aborted and the
6532 2. With the -c/--check option, the update is aborted and the
6532 uncommitted changes are preserved.
6533 uncommitted changes are preserved.
6533
6534
6534 3. With the -C/--clean option, uncommitted changes are discarded and
6535 3. With the -C/--clean option, uncommitted changes are discarded and
6535 the working directory is updated to the requested changeset.
6536 the working directory is updated to the requested changeset.
6536
6537
6537 To cancel an uncommitted merge (and lose your changes), use
6538 To cancel an uncommitted merge (and lose your changes), use
6538 :hg:`update --clean .`.
6539 :hg:`update --clean .`.
6539
6540
6540 Use null as the changeset to remove the working directory (like
6541 Use null as the changeset to remove the working directory (like
6541 :hg:`clone -U`).
6542 :hg:`clone -U`).
6542
6543
6543 If you want to revert just one file to an older revision, use
6544 If you want to revert just one file to an older revision, use
6544 :hg:`revert [-r REV] NAME`.
6545 :hg:`revert [-r REV] NAME`.
6545
6546
6546 See :hg:`help dates` for a list of formats valid for -d/--date.
6547 See :hg:`help dates` for a list of formats valid for -d/--date.
6547
6548
6548 Returns 0 on success, 1 if there are unresolved files.
6549 Returns 0 on success, 1 if there are unresolved files.
6549 """
6550 """
6550 if rev and node:
6551 if rev and node:
6551 raise util.Abort(_("please specify just one revision"))
6552 raise util.Abort(_("please specify just one revision"))
6552
6553
6553 if rev is None or rev == '':
6554 if rev is None or rev == '':
6554 rev = node
6555 rev = node
6555
6556
6556 wlock = repo.wlock()
6557 wlock = repo.wlock()
6557 try:
6558 try:
6558 cmdutil.clearunfinished(repo)
6559 cmdutil.clearunfinished(repo)
6559
6560
6560 if date:
6561 if date:
6561 if rev is not None:
6562 if rev is not None:
6562 raise util.Abort(_("you can't specify a revision and a date"))
6563 raise util.Abort(_("you can't specify a revision and a date"))
6563 rev = cmdutil.finddate(ui, repo, date)
6564 rev = cmdutil.finddate(ui, repo, date)
6564
6565
6565 # with no argument, we also move the active bookmark, if any
6566 # with no argument, we also move the active bookmark, if any
6566 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6567 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6567
6568
6568 # if we defined a bookmark, we have to remember the original name
6569 # if we defined a bookmark, we have to remember the original name
6569 brev = rev
6570 brev = rev
6570 rev = scmutil.revsingle(repo, rev, rev).rev()
6571 rev = scmutil.revsingle(repo, rev, rev).rev()
6571
6572
6572 if check and clean:
6573 if check and clean:
6573 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6574 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6574
6575
6575 if check:
6576 if check:
6576 cmdutil.bailifchanged(repo, merge=False)
6577 cmdutil.bailifchanged(repo, merge=False)
6577 if rev is None:
6578 if rev is None:
6578 rev = repo[repo[None].branch()].rev()
6579 rev = repo[repo[None].branch()].rev()
6579
6580
6580 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6581 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6581
6582
6582 if clean:
6583 if clean:
6583 ret = hg.clean(repo, rev)
6584 ret = hg.clean(repo, rev)
6584 else:
6585 else:
6585 ret = hg.update(repo, rev)
6586 ret = hg.update(repo, rev)
6586
6587
6587 if not ret and movemarkfrom:
6588 if not ret and movemarkfrom:
6588 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6589 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6589 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6590 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6590 else:
6591 else:
6591 # this can happen with a non-linear update
6592 # this can happen with a non-linear update
6592 ui.status(_("(leaving bookmark %s)\n") %
6593 ui.status(_("(leaving bookmark %s)\n") %
6593 repo._activebookmark)
6594 repo._activebookmark)
6594 bookmarks.deactivate(repo)
6595 bookmarks.deactivate(repo)
6595 elif brev in repo._bookmarks:
6596 elif brev in repo._bookmarks:
6596 bookmarks.activate(repo, brev)
6597 bookmarks.activate(repo, brev)
6597 ui.status(_("(activating bookmark %s)\n") % brev)
6598 ui.status(_("(activating bookmark %s)\n") % brev)
6598 elif brev:
6599 elif brev:
6599 if repo._activebookmark:
6600 if repo._activebookmark:
6600 ui.status(_("(leaving bookmark %s)\n") %
6601 ui.status(_("(leaving bookmark %s)\n") %
6601 repo._activebookmark)
6602 repo._activebookmark)
6602 bookmarks.deactivate(repo)
6603 bookmarks.deactivate(repo)
6603 finally:
6604 finally:
6604 wlock.release()
6605 wlock.release()
6605
6606
6606 return ret
6607 return ret
6607
6608
6608 @command('verify', [])
6609 @command('verify', [])
6609 def verify(ui, repo):
6610 def verify(ui, repo):
6610 """verify the integrity of the repository
6611 """verify the integrity of the repository
6611
6612
6612 Verify the integrity of the current repository.
6613 Verify the integrity of the current repository.
6613
6614
6614 This will perform an extensive check of the repository's
6615 This will perform an extensive check of the repository's
6615 integrity, validating the hashes and checksums of each entry in
6616 integrity, validating the hashes and checksums of each entry in
6616 the changelog, manifest, and tracked files, as well as the
6617 the changelog, manifest, and tracked files, as well as the
6617 integrity of their crosslinks and indices.
6618 integrity of their crosslinks and indices.
6618
6619
6619 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6620 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6620 for more information about recovery from corruption of the
6621 for more information about recovery from corruption of the
6621 repository.
6622 repository.
6622
6623
6623 Returns 0 on success, 1 if errors are encountered.
6624 Returns 0 on success, 1 if errors are encountered.
6624 """
6625 """
6625 return hg.verify(repo)
6626 return hg.verify(repo)
6626
6627
6627 @command('version', [], norepo=True)
6628 @command('version', [], norepo=True)
6628 def version_(ui):
6629 def version_(ui):
6629 """output version and copyright information"""
6630 """output version and copyright information"""
6630 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6631 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6631 % util.version())
6632 % util.version())
6632 ui.status(_(
6633 ui.status(_(
6633 "(see https://mercurial-scm.org for more information)\n"
6634 "(see https://mercurial-scm.org for more information)\n"
6634 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6635 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6635 "This is free software; see the source for copying conditions. "
6636 "This is free software; see the source for copying conditions. "
6636 "There is NO\nwarranty; "
6637 "There is NO\nwarranty; "
6637 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6638 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6638 ))
6639 ))
6639
6640
6640 ui.note(_("\nEnabled extensions:\n\n"))
6641 ui.note(_("\nEnabled extensions:\n\n"))
6641 if ui.verbose:
6642 if ui.verbose:
6642 # format names and versions into columns
6643 # format names and versions into columns
6643 names = []
6644 names = []
6644 vers = []
6645 vers = []
6645 for name, module in extensions.extensions():
6646 for name, module in extensions.extensions():
6646 names.append(name)
6647 names.append(name)
6647 vers.append(extensions.moduleversion(module))
6648 vers.append(extensions.moduleversion(module))
6648 if names:
6649 if names:
6649 maxnamelen = max(len(n) for n in names)
6650 maxnamelen = max(len(n) for n in names)
6650 for i, name in enumerate(names):
6651 for i, name in enumerate(names):
6651 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
6652 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
General Comments 0
You need to be logged in to leave comments. Login now