##// END OF EJS Templates
debuginstall: expand the editor path before searching for it (issue4380)...
Matt Harbison -
r24891:be491500 stable
parent child Browse files
Show More
@@ -1,6462 +1,6463
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, commandserver
16 import sshserver, hgweb, commandserver
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
22 import random
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
24 import phases, obsolete, exchange, bundle2
24 import phases, obsolete, exchange, bundle2
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 # common command options
43 # common command options
44
44
45 globalopts = [
45 globalopts = [
46 ('R', 'repository', '',
46 ('R', 'repository', '',
47 _('repository root directory or name of overlay bundle file'),
47 _('repository root directory or name of overlay bundle file'),
48 _('REPO')),
48 _('REPO')),
49 ('', 'cwd', '',
49 ('', 'cwd', '',
50 _('change working directory'), _('DIR')),
50 _('change working directory'), _('DIR')),
51 ('y', 'noninteractive', None,
51 ('y', 'noninteractive', None,
52 _('do not prompt, automatically pick the first choice for all prompts')),
52 _('do not prompt, automatically pick the first choice for all prompts')),
53 ('q', 'quiet', None, _('suppress output')),
53 ('q', 'quiet', None, _('suppress output')),
54 ('v', 'verbose', None, _('enable additional output')),
54 ('v', 'verbose', None, _('enable additional output')),
55 ('', 'config', [],
55 ('', 'config', [],
56 _('set/override config option (use \'section.name=value\')'),
56 _('set/override config option (use \'section.name=value\')'),
57 _('CONFIG')),
57 _('CONFIG')),
58 ('', 'debug', None, _('enable debugging output')),
58 ('', 'debug', None, _('enable debugging output')),
59 ('', 'debugger', None, _('start debugger')),
59 ('', 'debugger', None, _('start debugger')),
60 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
60 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
61 _('ENCODE')),
61 _('ENCODE')),
62 ('', 'encodingmode', encoding.encodingmode,
62 ('', 'encodingmode', encoding.encodingmode,
63 _('set the charset encoding mode'), _('MODE')),
63 _('set the charset encoding mode'), _('MODE')),
64 ('', 'traceback', None, _('always print a traceback on exception')),
64 ('', 'traceback', None, _('always print a traceback on exception')),
65 ('', 'time', None, _('time how long the command takes')),
65 ('', 'time', None, _('time how long the command takes')),
66 ('', 'profile', None, _('print command execution profile')),
66 ('', 'profile', None, _('print command execution profile')),
67 ('', 'version', None, _('output version information and exit')),
67 ('', 'version', None, _('output version information and exit')),
68 ('h', 'help', None, _('display help and exit')),
68 ('h', 'help', None, _('display help and exit')),
69 ('', 'hidden', False, _('consider hidden changesets')),
69 ('', 'hidden', False, _('consider hidden changesets')),
70 ]
70 ]
71
71
72 dryrunopts = [('n', 'dry-run', None,
72 dryrunopts = [('n', 'dry-run', None,
73 _('do not perform actions, just print output'))]
73 _('do not perform actions, just print output'))]
74
74
75 remoteopts = [
75 remoteopts = [
76 ('e', 'ssh', '',
76 ('e', 'ssh', '',
77 _('specify ssh command to use'), _('CMD')),
77 _('specify ssh command to use'), _('CMD')),
78 ('', 'remotecmd', '',
78 ('', 'remotecmd', '',
79 _('specify hg command to run on the remote side'), _('CMD')),
79 _('specify hg command to run on the remote side'), _('CMD')),
80 ('', 'insecure', None,
80 ('', 'insecure', None,
81 _('do not verify server certificate (ignoring web.cacerts config)')),
81 _('do not verify server certificate (ignoring web.cacerts config)')),
82 ]
82 ]
83
83
84 walkopts = [
84 walkopts = [
85 ('I', 'include', [],
85 ('I', 'include', [],
86 _('include names matching the given patterns'), _('PATTERN')),
86 _('include names matching the given patterns'), _('PATTERN')),
87 ('X', 'exclude', [],
87 ('X', 'exclude', [],
88 _('exclude names matching the given patterns'), _('PATTERN')),
88 _('exclude names matching the given patterns'), _('PATTERN')),
89 ]
89 ]
90
90
91 commitopts = [
91 commitopts = [
92 ('m', 'message', '',
92 ('m', 'message', '',
93 _('use text as commit message'), _('TEXT')),
93 _('use text as commit message'), _('TEXT')),
94 ('l', 'logfile', '',
94 ('l', 'logfile', '',
95 _('read commit message from file'), _('FILE')),
95 _('read commit message from file'), _('FILE')),
96 ]
96 ]
97
97
98 commitopts2 = [
98 commitopts2 = [
99 ('d', 'date', '',
99 ('d', 'date', '',
100 _('record the specified date as commit date'), _('DATE')),
100 _('record the specified date as commit date'), _('DATE')),
101 ('u', 'user', '',
101 ('u', 'user', '',
102 _('record the specified user as committer'), _('USER')),
102 _('record the specified user as committer'), _('USER')),
103 ]
103 ]
104
104
105 # hidden for now
105 # hidden for now
106 formatteropts = [
106 formatteropts = [
107 ('T', 'template', '',
107 ('T', 'template', '',
108 _('display with template (DEPRECATED)'), _('TEMPLATE')),
108 _('display with template (DEPRECATED)'), _('TEMPLATE')),
109 ]
109 ]
110
110
111 templateopts = [
111 templateopts = [
112 ('', 'style', '',
112 ('', 'style', '',
113 _('display using template map file (DEPRECATED)'), _('STYLE')),
113 _('display using template map file (DEPRECATED)'), _('STYLE')),
114 ('T', 'template', '',
114 ('T', 'template', '',
115 _('display with template'), _('TEMPLATE')),
115 _('display with template'), _('TEMPLATE')),
116 ]
116 ]
117
117
118 logopts = [
118 logopts = [
119 ('p', 'patch', None, _('show patch')),
119 ('p', 'patch', None, _('show patch')),
120 ('g', 'git', None, _('use git extended diff format')),
120 ('g', 'git', None, _('use git extended diff format')),
121 ('l', 'limit', '',
121 ('l', 'limit', '',
122 _('limit number of changes displayed'), _('NUM')),
122 _('limit number of changes displayed'), _('NUM')),
123 ('M', 'no-merges', None, _('do not show merges')),
123 ('M', 'no-merges', None, _('do not show merges')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ('G', 'graph', None, _("show the revision DAG")),
125 ('G', 'graph', None, _("show the revision DAG")),
126 ] + templateopts
126 ] + templateopts
127
127
128 diffopts = [
128 diffopts = [
129 ('a', 'text', None, _('treat all files as text')),
129 ('a', 'text', None, _('treat all files as text')),
130 ('g', 'git', None, _('use git extended diff format')),
130 ('g', 'git', None, _('use git extended diff format')),
131 ('', 'nodates', None, _('omit dates from diff headers'))
131 ('', 'nodates', None, _('omit dates from diff headers'))
132 ]
132 ]
133
133
134 diffwsopts = [
134 diffwsopts = [
135 ('w', 'ignore-all-space', None,
135 ('w', 'ignore-all-space', None,
136 _('ignore white space when comparing lines')),
136 _('ignore white space when comparing lines')),
137 ('b', 'ignore-space-change', None,
137 ('b', 'ignore-space-change', None,
138 _('ignore changes in the amount of white space')),
138 _('ignore changes in the amount of white space')),
139 ('B', 'ignore-blank-lines', None,
139 ('B', 'ignore-blank-lines', None,
140 _('ignore changes whose lines are all blank')),
140 _('ignore changes whose lines are all blank')),
141 ]
141 ]
142
142
143 diffopts2 = [
143 diffopts2 = [
144 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
144 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
145 ('p', 'show-function', None, _('show which function each change is in')),
145 ('p', 'show-function', None, _('show which function each change is in')),
146 ('', 'reverse', None, _('produce a diff that undoes the changes')),
146 ('', 'reverse', None, _('produce a diff that undoes the changes')),
147 ] + diffwsopts + [
147 ] + diffwsopts + [
148 ('U', 'unified', '',
148 ('U', 'unified', '',
149 _('number of lines of context to show'), _('NUM')),
149 _('number of lines of context to show'), _('NUM')),
150 ('', 'stat', None, _('output diffstat-style summary of changes')),
150 ('', 'stat', None, _('output diffstat-style summary of changes')),
151 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
151 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
152 ]
152 ]
153
153
154 mergetoolopts = [
154 mergetoolopts = [
155 ('t', 'tool', '', _('specify merge tool')),
155 ('t', 'tool', '', _('specify merge tool')),
156 ]
156 ]
157
157
158 similarityopts = [
158 similarityopts = [
159 ('s', 'similarity', '',
159 ('s', 'similarity', '',
160 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
160 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
161 ]
161 ]
162
162
163 subrepoopts = [
163 subrepoopts = [
164 ('S', 'subrepos', None,
164 ('S', 'subrepos', None,
165 _('recurse into subrepositories'))
165 _('recurse into subrepositories'))
166 ]
166 ]
167
167
168 # Commands start here, listed alphabetically
168 # Commands start here, listed alphabetically
169
169
170 @command('^add',
170 @command('^add',
171 walkopts + subrepoopts + dryrunopts,
171 walkopts + subrepoopts + dryrunopts,
172 _('[OPTION]... [FILE]...'),
172 _('[OPTION]... [FILE]...'),
173 inferrepo=True)
173 inferrepo=True)
174 def add(ui, repo, *pats, **opts):
174 def add(ui, repo, *pats, **opts):
175 """add the specified files on the next commit
175 """add the specified files on the next commit
176
176
177 Schedule files to be version controlled and added to the
177 Schedule files to be version controlled and added to the
178 repository.
178 repository.
179
179
180 The files will be added to the repository at the next commit. To
180 The files will be added to the repository at the next commit. To
181 undo an add before that, see :hg:`forget`.
181 undo an add before that, see :hg:`forget`.
182
182
183 If no names are given, add all files to the repository.
183 If no names are given, add all files to the repository.
184
184
185 .. container:: verbose
185 .. container:: verbose
186
186
187 An example showing how new (unknown) files are added
187 An example showing how new (unknown) files are added
188 automatically by :hg:`add`::
188 automatically by :hg:`add`::
189
189
190 $ ls
190 $ ls
191 foo.c
191 foo.c
192 $ hg status
192 $ hg status
193 ? foo.c
193 ? foo.c
194 $ hg add
194 $ hg add
195 adding foo.c
195 adding foo.c
196 $ hg status
196 $ hg status
197 A foo.c
197 A foo.c
198
198
199 Returns 0 if all files are successfully added.
199 Returns 0 if all files are successfully added.
200 """
200 """
201
201
202 m = scmutil.match(repo[None], pats, opts)
202 m = scmutil.match(repo[None], pats, opts)
203 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
203 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
204 return rejected and 1 or 0
204 return rejected and 1 or 0
205
205
206 @command('addremove',
206 @command('addremove',
207 similarityopts + subrepoopts + walkopts + dryrunopts,
207 similarityopts + subrepoopts + walkopts + dryrunopts,
208 _('[OPTION]... [FILE]...'),
208 _('[OPTION]... [FILE]...'),
209 inferrepo=True)
209 inferrepo=True)
210 def addremove(ui, repo, *pats, **opts):
210 def addremove(ui, repo, *pats, **opts):
211 """add all new files, delete all missing files
211 """add all new files, delete all missing files
212
212
213 Add all new files and remove all missing files from the
213 Add all new files and remove all missing files from the
214 repository.
214 repository.
215
215
216 New files are ignored if they match any of the patterns in
216 New files are ignored if they match any of the patterns in
217 ``.hgignore``. As with add, these changes take effect at the next
217 ``.hgignore``. As with add, these changes take effect at the next
218 commit.
218 commit.
219
219
220 Use the -s/--similarity option to detect renamed files. This
220 Use the -s/--similarity option to detect renamed files. This
221 option takes a percentage between 0 (disabled) and 100 (files must
221 option takes a percentage between 0 (disabled) and 100 (files must
222 be identical) as its parameter. With a parameter greater than 0,
222 be identical) as its parameter. With a parameter greater than 0,
223 this compares every removed file with every added file and records
223 this compares every removed file with every added file and records
224 those similar enough as renames. Detecting renamed files this way
224 those similar enough as renames. Detecting renamed files this way
225 can be expensive. After using this option, :hg:`status -C` can be
225 can be expensive. After using this option, :hg:`status -C` can be
226 used to check which files were identified as moved or renamed. If
226 used to check which files were identified as moved or renamed. If
227 not specified, -s/--similarity defaults to 100 and only renames of
227 not specified, -s/--similarity defaults to 100 and only renames of
228 identical files are detected.
228 identical files are detected.
229
229
230 Returns 0 if all files are successfully added.
230 Returns 0 if all files are successfully added.
231 """
231 """
232 try:
232 try:
233 sim = float(opts.get('similarity') or 100)
233 sim = float(opts.get('similarity') or 100)
234 except ValueError:
234 except ValueError:
235 raise util.Abort(_('similarity must be a number'))
235 raise util.Abort(_('similarity must be a number'))
236 if sim < 0 or sim > 100:
236 if sim < 0 or sim > 100:
237 raise util.Abort(_('similarity must be between 0 and 100'))
237 raise util.Abort(_('similarity must be between 0 and 100'))
238 matcher = scmutil.match(repo[None], pats, opts)
238 matcher = scmutil.match(repo[None], pats, opts)
239 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
239 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
240
240
241 @command('^annotate|blame',
241 @command('^annotate|blame',
242 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
242 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
243 ('', 'follow', None,
243 ('', 'follow', None,
244 _('follow copies/renames and list the filename (DEPRECATED)')),
244 _('follow copies/renames and list the filename (DEPRECATED)')),
245 ('', 'no-follow', None, _("don't follow copies and renames")),
245 ('', 'no-follow', None, _("don't follow copies and renames")),
246 ('a', 'text', None, _('treat all files as text')),
246 ('a', 'text', None, _('treat all files as text')),
247 ('u', 'user', None, _('list the author (long with -v)')),
247 ('u', 'user', None, _('list the author (long with -v)')),
248 ('f', 'file', None, _('list the filename')),
248 ('f', 'file', None, _('list the filename')),
249 ('d', 'date', None, _('list the date (short with -q)')),
249 ('d', 'date', None, _('list the date (short with -q)')),
250 ('n', 'number', None, _('list the revision number (default)')),
250 ('n', 'number', None, _('list the revision number (default)')),
251 ('c', 'changeset', None, _('list the changeset')),
251 ('c', 'changeset', None, _('list the changeset')),
252 ('l', 'line-number', None, _('show line number at the first appearance'))
252 ('l', 'line-number', None, _('show line number at the first appearance'))
253 ] + diffwsopts + walkopts + formatteropts,
253 ] + diffwsopts + walkopts + formatteropts,
254 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
254 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
255 inferrepo=True)
255 inferrepo=True)
256 def annotate(ui, repo, *pats, **opts):
256 def annotate(ui, repo, *pats, **opts):
257 """show changeset information by line for each file
257 """show changeset information by line for each file
258
258
259 List changes in files, showing the revision id responsible for
259 List changes in files, showing the revision id responsible for
260 each line
260 each line
261
261
262 This command is useful for discovering when a change was made and
262 This command is useful for discovering when a change was made and
263 by whom.
263 by whom.
264
264
265 Without the -a/--text option, annotate will avoid processing files
265 Without the -a/--text option, annotate will avoid processing files
266 it detects as binary. With -a, annotate will annotate the file
266 it detects as binary. With -a, annotate will annotate the file
267 anyway, although the results will probably be neither useful
267 anyway, although the results will probably be neither useful
268 nor desirable.
268 nor desirable.
269
269
270 Returns 0 on success.
270 Returns 0 on success.
271 """
271 """
272 if not pats:
272 if not pats:
273 raise util.Abort(_('at least one filename or pattern is required'))
273 raise util.Abort(_('at least one filename or pattern is required'))
274
274
275 if opts.get('follow'):
275 if opts.get('follow'):
276 # --follow is deprecated and now just an alias for -f/--file
276 # --follow is deprecated and now just an alias for -f/--file
277 # to mimic the behavior of Mercurial before version 1.5
277 # to mimic the behavior of Mercurial before version 1.5
278 opts['file'] = True
278 opts['file'] = True
279
279
280 ctx = scmutil.revsingle(repo, opts.get('rev'))
280 ctx = scmutil.revsingle(repo, opts.get('rev'))
281
281
282 fm = ui.formatter('annotate', opts)
282 fm = ui.formatter('annotate', opts)
283 if ui.quiet:
283 if ui.quiet:
284 datefunc = util.shortdate
284 datefunc = util.shortdate
285 else:
285 else:
286 datefunc = util.datestr
286 datefunc = util.datestr
287 if ctx.rev() is None:
287 if ctx.rev() is None:
288 def hexfn(node):
288 def hexfn(node):
289 if node is None:
289 if node is None:
290 return None
290 return None
291 else:
291 else:
292 return fm.hexfunc(node)
292 return fm.hexfunc(node)
293 if opts.get('changeset'):
293 if opts.get('changeset'):
294 # omit "+" suffix which is appended to node hex
294 # omit "+" suffix which is appended to node hex
295 def formatrev(rev):
295 def formatrev(rev):
296 if rev is None:
296 if rev is None:
297 return '%d' % ctx.p1().rev()
297 return '%d' % ctx.p1().rev()
298 else:
298 else:
299 return '%d' % rev
299 return '%d' % rev
300 else:
300 else:
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 def formathex(hex):
306 def formathex(hex):
307 if hex is None:
307 if hex is None:
308 return '%s+' % fm.hexfunc(ctx.p1().node())
308 return '%s+' % fm.hexfunc(ctx.p1().node())
309 else:
309 else:
310 return '%s ' % hex
310 return '%s ' % hex
311 else:
311 else:
312 hexfn = fm.hexfunc
312 hexfn = fm.hexfunc
313 formatrev = formathex = str
313 formatrev = formathex = str
314
314
315 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
315 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
316 ('number', ' ', lambda x: x[0].rev(), formatrev),
316 ('number', ' ', lambda x: x[0].rev(), formatrev),
317 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
317 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
318 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
318 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
319 ('file', ' ', lambda x: x[0].path(), str),
319 ('file', ' ', lambda x: x[0].path(), str),
320 ('line_number', ':', lambda x: x[1], str),
320 ('line_number', ':', lambda x: x[1], str),
321 ]
321 ]
322 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
322 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
323
323
324 if (not opts.get('user') and not opts.get('changeset')
324 if (not opts.get('user') and not opts.get('changeset')
325 and not opts.get('date') and not opts.get('file')):
325 and not opts.get('date') and not opts.get('file')):
326 opts['number'] = True
326 opts['number'] = True
327
327
328 linenumber = opts.get('line_number') is not None
328 linenumber = opts.get('line_number') is not None
329 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
329 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
330 raise util.Abort(_('at least one of -n/-c is required for -l'))
330 raise util.Abort(_('at least one of -n/-c is required for -l'))
331
331
332 if fm:
332 if fm:
333 def makefunc(get, fmt):
333 def makefunc(get, fmt):
334 return get
334 return get
335 else:
335 else:
336 def makefunc(get, fmt):
336 def makefunc(get, fmt):
337 return lambda x: fmt(get(x))
337 return lambda x: fmt(get(x))
338 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
338 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
339 if opts.get(op)]
339 if opts.get(op)]
340 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
340 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
341 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
341 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
342 if opts.get(op))
342 if opts.get(op))
343
343
344 def bad(x, y):
344 def bad(x, y):
345 raise util.Abort("%s: %s" % (x, y))
345 raise util.Abort("%s: %s" % (x, y))
346
346
347 m = scmutil.match(ctx, pats, opts)
347 m = scmutil.match(ctx, pats, opts)
348 m.bad = bad
348 m.bad = bad
349 follow = not opts.get('no_follow')
349 follow = not opts.get('no_follow')
350 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
350 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
351 whitespace=True)
351 whitespace=True)
352 for abs in ctx.walk(m):
352 for abs in ctx.walk(m):
353 fctx = ctx[abs]
353 fctx = ctx[abs]
354 if not opts.get('text') and util.binary(fctx.data()):
354 if not opts.get('text') and util.binary(fctx.data()):
355 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
355 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
356 continue
356 continue
357
357
358 lines = fctx.annotate(follow=follow, linenumber=linenumber,
358 lines = fctx.annotate(follow=follow, linenumber=linenumber,
359 diffopts=diffopts)
359 diffopts=diffopts)
360 formats = []
360 formats = []
361 pieces = []
361 pieces = []
362
362
363 for f, sep in funcmap:
363 for f, sep in funcmap:
364 l = [f(n) for n, dummy in lines]
364 l = [f(n) for n, dummy in lines]
365 if l:
365 if l:
366 if fm:
366 if fm:
367 formats.append(['%s' for x in l])
367 formats.append(['%s' for x in l])
368 else:
368 else:
369 sizes = [encoding.colwidth(x) for x in l]
369 sizes = [encoding.colwidth(x) for x in l]
370 ml = max(sizes)
370 ml = max(sizes)
371 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
371 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
372 pieces.append(l)
372 pieces.append(l)
373
373
374 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
374 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
375 fm.startitem()
375 fm.startitem()
376 fm.write(fields, "".join(f), *p)
376 fm.write(fields, "".join(f), *p)
377 fm.write('line', ": %s", l[1])
377 fm.write('line', ": %s", l[1])
378
378
379 if lines and not lines[-1][1].endswith('\n'):
379 if lines and not lines[-1][1].endswith('\n'):
380 fm.plain('\n')
380 fm.plain('\n')
381
381
382 fm.end()
382 fm.end()
383
383
384 @command('archive',
384 @command('archive',
385 [('', 'no-decode', None, _('do not pass files through decoders')),
385 [('', 'no-decode', None, _('do not pass files through decoders')),
386 ('p', 'prefix', '', _('directory prefix for files in archive'),
386 ('p', 'prefix', '', _('directory prefix for files in archive'),
387 _('PREFIX')),
387 _('PREFIX')),
388 ('r', 'rev', '', _('revision to distribute'), _('REV')),
388 ('r', 'rev', '', _('revision to distribute'), _('REV')),
389 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
389 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
390 ] + subrepoopts + walkopts,
390 ] + subrepoopts + walkopts,
391 _('[OPTION]... DEST'))
391 _('[OPTION]... DEST'))
392 def archive(ui, repo, dest, **opts):
392 def archive(ui, repo, dest, **opts):
393 '''create an unversioned archive of a repository revision
393 '''create an unversioned archive of a repository revision
394
394
395 By default, the revision used is the parent of the working
395 By default, the revision used is the parent of the working
396 directory; use -r/--rev to specify a different revision.
396 directory; use -r/--rev to specify a different revision.
397
397
398 The archive type is automatically detected based on file
398 The archive type is automatically detected based on file
399 extension (or override using -t/--type).
399 extension (or override using -t/--type).
400
400
401 .. container:: verbose
401 .. container:: verbose
402
402
403 Examples:
403 Examples:
404
404
405 - create a zip file containing the 1.0 release::
405 - create a zip file containing the 1.0 release::
406
406
407 hg archive -r 1.0 project-1.0.zip
407 hg archive -r 1.0 project-1.0.zip
408
408
409 - create a tarball excluding .hg files::
409 - create a tarball excluding .hg files::
410
410
411 hg archive project.tar.gz -X ".hg*"
411 hg archive project.tar.gz -X ".hg*"
412
412
413 Valid types are:
413 Valid types are:
414
414
415 :``files``: a directory full of files (default)
415 :``files``: a directory full of files (default)
416 :``tar``: tar archive, uncompressed
416 :``tar``: tar archive, uncompressed
417 :``tbz2``: tar archive, compressed using bzip2
417 :``tbz2``: tar archive, compressed using bzip2
418 :``tgz``: tar archive, compressed using gzip
418 :``tgz``: tar archive, compressed using gzip
419 :``uzip``: zip archive, uncompressed
419 :``uzip``: zip archive, uncompressed
420 :``zip``: zip archive, compressed using deflate
420 :``zip``: zip archive, compressed using deflate
421
421
422 The exact name of the destination archive or directory is given
422 The exact name of the destination archive or directory is given
423 using a format string; see :hg:`help export` for details.
423 using a format string; see :hg:`help export` for details.
424
424
425 Each member added to an archive file has a directory prefix
425 Each member added to an archive file has a directory prefix
426 prepended. Use -p/--prefix to specify a format string for the
426 prepended. Use -p/--prefix to specify a format string for the
427 prefix. The default is the basename of the archive, with suffixes
427 prefix. The default is the basename of the archive, with suffixes
428 removed.
428 removed.
429
429
430 Returns 0 on success.
430 Returns 0 on success.
431 '''
431 '''
432
432
433 ctx = scmutil.revsingle(repo, opts.get('rev'))
433 ctx = scmutil.revsingle(repo, opts.get('rev'))
434 if not ctx:
434 if not ctx:
435 raise util.Abort(_('no working directory: please specify a revision'))
435 raise util.Abort(_('no working directory: please specify a revision'))
436 node = ctx.node()
436 node = ctx.node()
437 dest = cmdutil.makefilename(repo, dest, node)
437 dest = cmdutil.makefilename(repo, dest, node)
438 if os.path.realpath(dest) == repo.root:
438 if os.path.realpath(dest) == repo.root:
439 raise util.Abort(_('repository root cannot be destination'))
439 raise util.Abort(_('repository root cannot be destination'))
440
440
441 kind = opts.get('type') or archival.guesskind(dest) or 'files'
441 kind = opts.get('type') or archival.guesskind(dest) or 'files'
442 prefix = opts.get('prefix')
442 prefix = opts.get('prefix')
443
443
444 if dest == '-':
444 if dest == '-':
445 if kind == 'files':
445 if kind == 'files':
446 raise util.Abort(_('cannot archive plain files to stdout'))
446 raise util.Abort(_('cannot archive plain files to stdout'))
447 dest = cmdutil.makefileobj(repo, dest)
447 dest = cmdutil.makefileobj(repo, dest)
448 if not prefix:
448 if not prefix:
449 prefix = os.path.basename(repo.root) + '-%h'
449 prefix = os.path.basename(repo.root) + '-%h'
450
450
451 prefix = cmdutil.makefilename(repo, prefix, node)
451 prefix = cmdutil.makefilename(repo, prefix, node)
452 matchfn = scmutil.match(ctx, [], opts)
452 matchfn = scmutil.match(ctx, [], opts)
453 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
453 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
454 matchfn, prefix, subrepos=opts.get('subrepos'))
454 matchfn, prefix, subrepos=opts.get('subrepos'))
455
455
456 @command('backout',
456 @command('backout',
457 [('', 'merge', None, _('merge with old dirstate parent after backout')),
457 [('', 'merge', None, _('merge with old dirstate parent after backout')),
458 ('', 'commit', None, _('commit if no conflicts were encountered')),
458 ('', 'commit', None, _('commit if no conflicts were encountered')),
459 ('', 'parent', '',
459 ('', 'parent', '',
460 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
460 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
461 ('r', 'rev', '', _('revision to backout'), _('REV')),
461 ('r', 'rev', '', _('revision to backout'), _('REV')),
462 ('e', 'edit', False, _('invoke editor on commit messages')),
462 ('e', 'edit', False, _('invoke editor on commit messages')),
463 ] + mergetoolopts + walkopts + commitopts + commitopts2,
463 ] + mergetoolopts + walkopts + commitopts + commitopts2,
464 _('[OPTION]... [-r] REV'))
464 _('[OPTION]... [-r] REV'))
465 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
465 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
466 '''reverse effect of earlier changeset
466 '''reverse effect of earlier changeset
467
467
468 Prepare a new changeset with the effect of REV undone in the
468 Prepare a new changeset with the effect of REV undone in the
469 current working directory.
469 current working directory.
470
470
471 If REV is the parent of the working directory, then this new changeset
471 If REV is the parent of the working directory, then this new changeset
472 is committed automatically. Otherwise, hg needs to merge the
472 is committed automatically. Otherwise, hg needs to merge the
473 changes and the merged result is left uncommitted.
473 changes and the merged result is left uncommitted.
474
474
475 .. note::
475 .. note::
476
476
477 backout cannot be used to fix either an unwanted or
477 backout cannot be used to fix either an unwanted or
478 incorrect merge.
478 incorrect merge.
479
479
480 .. container:: verbose
480 .. container:: verbose
481
481
482 By default, the pending changeset will have one parent,
482 By default, the pending changeset will have one parent,
483 maintaining a linear history. With --merge, the pending
483 maintaining a linear history. With --merge, the pending
484 changeset will instead have two parents: the old parent of the
484 changeset will instead have two parents: the old parent of the
485 working directory and a new child of REV that simply undoes REV.
485 working directory and a new child of REV that simply undoes REV.
486
486
487 Before version 1.7, the behavior without --merge was equivalent
487 Before version 1.7, the behavior without --merge was equivalent
488 to specifying --merge followed by :hg:`update --clean .` to
488 to specifying --merge followed by :hg:`update --clean .` to
489 cancel the merge and leave the child of REV as a head to be
489 cancel the merge and leave the child of REV as a head to be
490 merged separately.
490 merged separately.
491
491
492 See :hg:`help dates` for a list of formats valid for -d/--date.
492 See :hg:`help dates` for a list of formats valid for -d/--date.
493
493
494 Returns 0 on success, 1 if nothing to backout or there are unresolved
494 Returns 0 on success, 1 if nothing to backout or there are unresolved
495 files.
495 files.
496 '''
496 '''
497 if rev and node:
497 if rev and node:
498 raise util.Abort(_("please specify just one revision"))
498 raise util.Abort(_("please specify just one revision"))
499
499
500 if not rev:
500 if not rev:
501 rev = node
501 rev = node
502
502
503 if not rev:
503 if not rev:
504 raise util.Abort(_("please specify a revision to backout"))
504 raise util.Abort(_("please specify a revision to backout"))
505
505
506 date = opts.get('date')
506 date = opts.get('date')
507 if date:
507 if date:
508 opts['date'] = util.parsedate(date)
508 opts['date'] = util.parsedate(date)
509
509
510 cmdutil.checkunfinished(repo)
510 cmdutil.checkunfinished(repo)
511 cmdutil.bailifchanged(repo)
511 cmdutil.bailifchanged(repo)
512 node = scmutil.revsingle(repo, rev).node()
512 node = scmutil.revsingle(repo, rev).node()
513
513
514 op1, op2 = repo.dirstate.parents()
514 op1, op2 = repo.dirstate.parents()
515 if not repo.changelog.isancestor(node, op1):
515 if not repo.changelog.isancestor(node, op1):
516 raise util.Abort(_('cannot backout change that is not an ancestor'))
516 raise util.Abort(_('cannot backout change that is not an ancestor'))
517
517
518 p1, p2 = repo.changelog.parents(node)
518 p1, p2 = repo.changelog.parents(node)
519 if p1 == nullid:
519 if p1 == nullid:
520 raise util.Abort(_('cannot backout a change with no parents'))
520 raise util.Abort(_('cannot backout a change with no parents'))
521 if p2 != nullid:
521 if p2 != nullid:
522 if not opts.get('parent'):
522 if not opts.get('parent'):
523 raise util.Abort(_('cannot backout a merge changeset'))
523 raise util.Abort(_('cannot backout a merge changeset'))
524 p = repo.lookup(opts['parent'])
524 p = repo.lookup(opts['parent'])
525 if p not in (p1, p2):
525 if p not in (p1, p2):
526 raise util.Abort(_('%s is not a parent of %s') %
526 raise util.Abort(_('%s is not a parent of %s') %
527 (short(p), short(node)))
527 (short(p), short(node)))
528 parent = p
528 parent = p
529 else:
529 else:
530 if opts.get('parent'):
530 if opts.get('parent'):
531 raise util.Abort(_('cannot use --parent on non-merge changeset'))
531 raise util.Abort(_('cannot use --parent on non-merge changeset'))
532 parent = p1
532 parent = p1
533
533
534 # the backout should appear on the same branch
534 # the backout should appear on the same branch
535 wlock = repo.wlock()
535 wlock = repo.wlock()
536 try:
536 try:
537 branch = repo.dirstate.branch()
537 branch = repo.dirstate.branch()
538 bheads = repo.branchheads(branch)
538 bheads = repo.branchheads(branch)
539 rctx = scmutil.revsingle(repo, hex(parent))
539 rctx = scmutil.revsingle(repo, hex(parent))
540 if not opts.get('merge') and op1 != node:
540 if not opts.get('merge') and op1 != node:
541 try:
541 try:
542 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
542 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
543 'backout')
543 'backout')
544 repo.dirstate.beginparentchange()
544 repo.dirstate.beginparentchange()
545 stats = mergemod.update(repo, parent, True, True, False,
545 stats = mergemod.update(repo, parent, True, True, False,
546 node, False)
546 node, False)
547 repo.setparents(op1, op2)
547 repo.setparents(op1, op2)
548 repo.dirstate.endparentchange()
548 repo.dirstate.endparentchange()
549 hg._showstats(repo, stats)
549 hg._showstats(repo, stats)
550 if stats[3]:
550 if stats[3]:
551 repo.ui.status(_("use 'hg resolve' to retry unresolved "
551 repo.ui.status(_("use 'hg resolve' to retry unresolved "
552 "file merges\n"))
552 "file merges\n"))
553 return 1
553 return 1
554 elif not commit:
554 elif not commit:
555 msg = _("changeset %s backed out, "
555 msg = _("changeset %s backed out, "
556 "don't forget to commit.\n")
556 "don't forget to commit.\n")
557 ui.status(msg % short(node))
557 ui.status(msg % short(node))
558 return 0
558 return 0
559 finally:
559 finally:
560 ui.setconfig('ui', 'forcemerge', '', '')
560 ui.setconfig('ui', 'forcemerge', '', '')
561 else:
561 else:
562 hg.clean(repo, node, show_stats=False)
562 hg.clean(repo, node, show_stats=False)
563 repo.dirstate.setbranch(branch)
563 repo.dirstate.setbranch(branch)
564 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
564 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
565
565
566
566
567 def commitfunc(ui, repo, message, match, opts):
567 def commitfunc(ui, repo, message, match, opts):
568 editform = 'backout'
568 editform = 'backout'
569 e = cmdutil.getcommiteditor(editform=editform, **opts)
569 e = cmdutil.getcommiteditor(editform=editform, **opts)
570 if not message:
570 if not message:
571 # we don't translate commit messages
571 # we don't translate commit messages
572 message = "Backed out changeset %s" % short(node)
572 message = "Backed out changeset %s" % short(node)
573 e = cmdutil.getcommiteditor(edit=True, editform=editform)
573 e = cmdutil.getcommiteditor(edit=True, editform=editform)
574 return repo.commit(message, opts.get('user'), opts.get('date'),
574 return repo.commit(message, opts.get('user'), opts.get('date'),
575 match, editor=e)
575 match, editor=e)
576 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
576 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
577 if not newnode:
577 if not newnode:
578 ui.status(_("nothing changed\n"))
578 ui.status(_("nothing changed\n"))
579 return 1
579 return 1
580 cmdutil.commitstatus(repo, newnode, branch, bheads)
580 cmdutil.commitstatus(repo, newnode, branch, bheads)
581
581
582 def nice(node):
582 def nice(node):
583 return '%d:%s' % (repo.changelog.rev(node), short(node))
583 return '%d:%s' % (repo.changelog.rev(node), short(node))
584 ui.status(_('changeset %s backs out changeset %s\n') %
584 ui.status(_('changeset %s backs out changeset %s\n') %
585 (nice(repo.changelog.tip()), nice(node)))
585 (nice(repo.changelog.tip()), nice(node)))
586 if opts.get('merge') and op1 != node:
586 if opts.get('merge') and op1 != node:
587 hg.clean(repo, op1, show_stats=False)
587 hg.clean(repo, op1, show_stats=False)
588 ui.status(_('merging with changeset %s\n')
588 ui.status(_('merging with changeset %s\n')
589 % nice(repo.changelog.tip()))
589 % nice(repo.changelog.tip()))
590 try:
590 try:
591 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
591 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
592 'backout')
592 'backout')
593 return hg.merge(repo, hex(repo.changelog.tip()))
593 return hg.merge(repo, hex(repo.changelog.tip()))
594 finally:
594 finally:
595 ui.setconfig('ui', 'forcemerge', '', '')
595 ui.setconfig('ui', 'forcemerge', '', '')
596 finally:
596 finally:
597 wlock.release()
597 wlock.release()
598 return 0
598 return 0
599
599
600 @command('bisect',
600 @command('bisect',
601 [('r', 'reset', False, _('reset bisect state')),
601 [('r', 'reset', False, _('reset bisect state')),
602 ('g', 'good', False, _('mark changeset good')),
602 ('g', 'good', False, _('mark changeset good')),
603 ('b', 'bad', False, _('mark changeset bad')),
603 ('b', 'bad', False, _('mark changeset bad')),
604 ('s', 'skip', False, _('skip testing changeset')),
604 ('s', 'skip', False, _('skip testing changeset')),
605 ('e', 'extend', False, _('extend the bisect range')),
605 ('e', 'extend', False, _('extend the bisect range')),
606 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
606 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
607 ('U', 'noupdate', False, _('do not update to target'))],
607 ('U', 'noupdate', False, _('do not update to target'))],
608 _("[-gbsr] [-U] [-c CMD] [REV]"))
608 _("[-gbsr] [-U] [-c CMD] [REV]"))
609 def bisect(ui, repo, rev=None, extra=None, command=None,
609 def bisect(ui, repo, rev=None, extra=None, command=None,
610 reset=None, good=None, bad=None, skip=None, extend=None,
610 reset=None, good=None, bad=None, skip=None, extend=None,
611 noupdate=None):
611 noupdate=None):
612 """subdivision search of changesets
612 """subdivision search of changesets
613
613
614 This command helps to find changesets which introduce problems. To
614 This command helps to find changesets which introduce problems. To
615 use, mark the earliest changeset you know exhibits the problem as
615 use, mark the earliest changeset you know exhibits the problem as
616 bad, then mark the latest changeset which is free from the problem
616 bad, then mark the latest changeset which is free from the problem
617 as good. Bisect will update your working directory to a revision
617 as good. Bisect will update your working directory to a revision
618 for testing (unless the -U/--noupdate option is specified). Once
618 for testing (unless the -U/--noupdate option is specified). Once
619 you have performed tests, mark the working directory as good or
619 you have performed tests, mark the working directory as good or
620 bad, and bisect will either update to another candidate changeset
620 bad, and bisect will either update to another candidate changeset
621 or announce that it has found the bad revision.
621 or announce that it has found the bad revision.
622
622
623 As a shortcut, you can also use the revision argument to mark a
623 As a shortcut, you can also use the revision argument to mark a
624 revision as good or bad without checking it out first.
624 revision as good or bad without checking it out first.
625
625
626 If you supply a command, it will be used for automatic bisection.
626 If you supply a command, it will be used for automatic bisection.
627 The environment variable HG_NODE will contain the ID of the
627 The environment variable HG_NODE will contain the ID of the
628 changeset being tested. The exit status of the command will be
628 changeset being tested. The exit status of the command will be
629 used to mark revisions as good or bad: status 0 means good, 125
629 used to mark revisions as good or bad: status 0 means good, 125
630 means to skip the revision, 127 (command not found) will abort the
630 means to skip the revision, 127 (command not found) will abort the
631 bisection, and any other non-zero exit status means the revision
631 bisection, and any other non-zero exit status means the revision
632 is bad.
632 is bad.
633
633
634 .. container:: verbose
634 .. container:: verbose
635
635
636 Some examples:
636 Some examples:
637
637
638 - start a bisection with known bad revision 34, and good revision 12::
638 - start a bisection with known bad revision 34, and good revision 12::
639
639
640 hg bisect --bad 34
640 hg bisect --bad 34
641 hg bisect --good 12
641 hg bisect --good 12
642
642
643 - advance the current bisection by marking current revision as good or
643 - advance the current bisection by marking current revision as good or
644 bad::
644 bad::
645
645
646 hg bisect --good
646 hg bisect --good
647 hg bisect --bad
647 hg bisect --bad
648
648
649 - mark the current revision, or a known revision, to be skipped (e.g. if
649 - mark the current revision, or a known revision, to be skipped (e.g. if
650 that revision is not usable because of another issue)::
650 that revision is not usable because of another issue)::
651
651
652 hg bisect --skip
652 hg bisect --skip
653 hg bisect --skip 23
653 hg bisect --skip 23
654
654
655 - skip all revisions that do not touch directories ``foo`` or ``bar``::
655 - skip all revisions that do not touch directories ``foo`` or ``bar``::
656
656
657 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
657 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
658
658
659 - forget the current bisection::
659 - forget the current bisection::
660
660
661 hg bisect --reset
661 hg bisect --reset
662
662
663 - use 'make && make tests' to automatically find the first broken
663 - use 'make && make tests' to automatically find the first broken
664 revision::
664 revision::
665
665
666 hg bisect --reset
666 hg bisect --reset
667 hg bisect --bad 34
667 hg bisect --bad 34
668 hg bisect --good 12
668 hg bisect --good 12
669 hg bisect --command "make && make tests"
669 hg bisect --command "make && make tests"
670
670
671 - see all changesets whose states are already known in the current
671 - see all changesets whose states are already known in the current
672 bisection::
672 bisection::
673
673
674 hg log -r "bisect(pruned)"
674 hg log -r "bisect(pruned)"
675
675
676 - see the changeset currently being bisected (especially useful
676 - see the changeset currently being bisected (especially useful
677 if running with -U/--noupdate)::
677 if running with -U/--noupdate)::
678
678
679 hg log -r "bisect(current)"
679 hg log -r "bisect(current)"
680
680
681 - see all changesets that took part in the current bisection::
681 - see all changesets that took part in the current bisection::
682
682
683 hg log -r "bisect(range)"
683 hg log -r "bisect(range)"
684
684
685 - you can even get a nice graph::
685 - you can even get a nice graph::
686
686
687 hg log --graph -r "bisect(range)"
687 hg log --graph -r "bisect(range)"
688
688
689 See :hg:`help revsets` for more about the `bisect()` keyword.
689 See :hg:`help revsets` for more about the `bisect()` keyword.
690
690
691 Returns 0 on success.
691 Returns 0 on success.
692 """
692 """
693 def extendbisectrange(nodes, good):
693 def extendbisectrange(nodes, good):
694 # bisect is incomplete when it ends on a merge node and
694 # bisect is incomplete when it ends on a merge node and
695 # one of the parent was not checked.
695 # one of the parent was not checked.
696 parents = repo[nodes[0]].parents()
696 parents = repo[nodes[0]].parents()
697 if len(parents) > 1:
697 if len(parents) > 1:
698 if good:
698 if good:
699 side = state['bad']
699 side = state['bad']
700 else:
700 else:
701 side = state['good']
701 side = state['good']
702 num = len(set(i.node() for i in parents) & set(side))
702 num = len(set(i.node() for i in parents) & set(side))
703 if num == 1:
703 if num == 1:
704 return parents[0].ancestor(parents[1])
704 return parents[0].ancestor(parents[1])
705 return None
705 return None
706
706
707 def print_result(nodes, good):
707 def print_result(nodes, good):
708 displayer = cmdutil.show_changeset(ui, repo, {})
708 displayer = cmdutil.show_changeset(ui, repo, {})
709 if len(nodes) == 1:
709 if len(nodes) == 1:
710 # narrowed it down to a single revision
710 # narrowed it down to a single revision
711 if good:
711 if good:
712 ui.write(_("The first good revision is:\n"))
712 ui.write(_("The first good revision is:\n"))
713 else:
713 else:
714 ui.write(_("The first bad revision is:\n"))
714 ui.write(_("The first bad revision is:\n"))
715 displayer.show(repo[nodes[0]])
715 displayer.show(repo[nodes[0]])
716 extendnode = extendbisectrange(nodes, good)
716 extendnode = extendbisectrange(nodes, good)
717 if extendnode is not None:
717 if extendnode is not None:
718 ui.write(_('Not all ancestors of this changeset have been'
718 ui.write(_('Not all ancestors of this changeset have been'
719 ' checked.\nUse bisect --extend to continue the '
719 ' checked.\nUse bisect --extend to continue the '
720 'bisection from\nthe common ancestor, %s.\n')
720 'bisection from\nthe common ancestor, %s.\n')
721 % extendnode)
721 % extendnode)
722 else:
722 else:
723 # multiple possible revisions
723 # multiple possible revisions
724 if good:
724 if good:
725 ui.write(_("Due to skipped revisions, the first "
725 ui.write(_("Due to skipped revisions, the first "
726 "good revision could be any of:\n"))
726 "good revision could be any of:\n"))
727 else:
727 else:
728 ui.write(_("Due to skipped revisions, the first "
728 ui.write(_("Due to skipped revisions, the first "
729 "bad revision could be any of:\n"))
729 "bad revision could be any of:\n"))
730 for n in nodes:
730 for n in nodes:
731 displayer.show(repo[n])
731 displayer.show(repo[n])
732 displayer.close()
732 displayer.close()
733
733
734 def check_state(state, interactive=True):
734 def check_state(state, interactive=True):
735 if not state['good'] or not state['bad']:
735 if not state['good'] or not state['bad']:
736 if (good or bad or skip or reset) and interactive:
736 if (good or bad or skip or reset) and interactive:
737 return
737 return
738 if not state['good']:
738 if not state['good']:
739 raise util.Abort(_('cannot bisect (no known good revisions)'))
739 raise util.Abort(_('cannot bisect (no known good revisions)'))
740 else:
740 else:
741 raise util.Abort(_('cannot bisect (no known bad revisions)'))
741 raise util.Abort(_('cannot bisect (no known bad revisions)'))
742 return True
742 return True
743
743
744 # backward compatibility
744 # backward compatibility
745 if rev in "good bad reset init".split():
745 if rev in "good bad reset init".split():
746 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
746 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
747 cmd, rev, extra = rev, extra, None
747 cmd, rev, extra = rev, extra, None
748 if cmd == "good":
748 if cmd == "good":
749 good = True
749 good = True
750 elif cmd == "bad":
750 elif cmd == "bad":
751 bad = True
751 bad = True
752 else:
752 else:
753 reset = True
753 reset = True
754 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
754 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
755 raise util.Abort(_('incompatible arguments'))
755 raise util.Abort(_('incompatible arguments'))
756
756
757 cmdutil.checkunfinished(repo)
757 cmdutil.checkunfinished(repo)
758
758
759 if reset:
759 if reset:
760 p = repo.join("bisect.state")
760 p = repo.join("bisect.state")
761 if os.path.exists(p):
761 if os.path.exists(p):
762 os.unlink(p)
762 os.unlink(p)
763 return
763 return
764
764
765 state = hbisect.load_state(repo)
765 state = hbisect.load_state(repo)
766
766
767 if command:
767 if command:
768 changesets = 1
768 changesets = 1
769 if noupdate:
769 if noupdate:
770 try:
770 try:
771 node = state['current'][0]
771 node = state['current'][0]
772 except LookupError:
772 except LookupError:
773 raise util.Abort(_('current bisect revision is unknown - '
773 raise util.Abort(_('current bisect revision is unknown - '
774 'start a new bisect to fix'))
774 'start a new bisect to fix'))
775 else:
775 else:
776 node, p2 = repo.dirstate.parents()
776 node, p2 = repo.dirstate.parents()
777 if p2 != nullid:
777 if p2 != nullid:
778 raise util.Abort(_('current bisect revision is a merge'))
778 raise util.Abort(_('current bisect revision is a merge'))
779 try:
779 try:
780 while changesets:
780 while changesets:
781 # update state
781 # update state
782 state['current'] = [node]
782 state['current'] = [node]
783 hbisect.save_state(repo, state)
783 hbisect.save_state(repo, state)
784 status = ui.system(command, environ={'HG_NODE': hex(node)})
784 status = ui.system(command, environ={'HG_NODE': hex(node)})
785 if status == 125:
785 if status == 125:
786 transition = "skip"
786 transition = "skip"
787 elif status == 0:
787 elif status == 0:
788 transition = "good"
788 transition = "good"
789 # status < 0 means process was killed
789 # status < 0 means process was killed
790 elif status == 127:
790 elif status == 127:
791 raise util.Abort(_("failed to execute %s") % command)
791 raise util.Abort(_("failed to execute %s") % command)
792 elif status < 0:
792 elif status < 0:
793 raise util.Abort(_("%s killed") % command)
793 raise util.Abort(_("%s killed") % command)
794 else:
794 else:
795 transition = "bad"
795 transition = "bad"
796 ctx = scmutil.revsingle(repo, rev, node)
796 ctx = scmutil.revsingle(repo, rev, node)
797 rev = None # clear for future iterations
797 rev = None # clear for future iterations
798 state[transition].append(ctx.node())
798 state[transition].append(ctx.node())
799 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
799 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
800 check_state(state, interactive=False)
800 check_state(state, interactive=False)
801 # bisect
801 # bisect
802 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
802 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
803 # update to next check
803 # update to next check
804 node = nodes[0]
804 node = nodes[0]
805 if not noupdate:
805 if not noupdate:
806 cmdutil.bailifchanged(repo)
806 cmdutil.bailifchanged(repo)
807 hg.clean(repo, node, show_stats=False)
807 hg.clean(repo, node, show_stats=False)
808 finally:
808 finally:
809 state['current'] = [node]
809 state['current'] = [node]
810 hbisect.save_state(repo, state)
810 hbisect.save_state(repo, state)
811 print_result(nodes, bgood)
811 print_result(nodes, bgood)
812 return
812 return
813
813
814 # update state
814 # update state
815
815
816 if rev:
816 if rev:
817 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
817 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
818 else:
818 else:
819 nodes = [repo.lookup('.')]
819 nodes = [repo.lookup('.')]
820
820
821 if good or bad or skip:
821 if good or bad or skip:
822 if good:
822 if good:
823 state['good'] += nodes
823 state['good'] += nodes
824 elif bad:
824 elif bad:
825 state['bad'] += nodes
825 state['bad'] += nodes
826 elif skip:
826 elif skip:
827 state['skip'] += nodes
827 state['skip'] += nodes
828 hbisect.save_state(repo, state)
828 hbisect.save_state(repo, state)
829
829
830 if not check_state(state):
830 if not check_state(state):
831 return
831 return
832
832
833 # actually bisect
833 # actually bisect
834 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
834 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
835 if extend:
835 if extend:
836 if not changesets:
836 if not changesets:
837 extendnode = extendbisectrange(nodes, good)
837 extendnode = extendbisectrange(nodes, good)
838 if extendnode is not None:
838 if extendnode is not None:
839 ui.write(_("Extending search to changeset %d:%s\n")
839 ui.write(_("Extending search to changeset %d:%s\n")
840 % (extendnode.rev(), extendnode))
840 % (extendnode.rev(), extendnode))
841 state['current'] = [extendnode.node()]
841 state['current'] = [extendnode.node()]
842 hbisect.save_state(repo, state)
842 hbisect.save_state(repo, state)
843 if noupdate:
843 if noupdate:
844 return
844 return
845 cmdutil.bailifchanged(repo)
845 cmdutil.bailifchanged(repo)
846 return hg.clean(repo, extendnode.node())
846 return hg.clean(repo, extendnode.node())
847 raise util.Abort(_("nothing to extend"))
847 raise util.Abort(_("nothing to extend"))
848
848
849 if changesets == 0:
849 if changesets == 0:
850 print_result(nodes, good)
850 print_result(nodes, good)
851 else:
851 else:
852 assert len(nodes) == 1 # only a single node can be tested next
852 assert len(nodes) == 1 # only a single node can be tested next
853 node = nodes[0]
853 node = nodes[0]
854 # compute the approximate number of remaining tests
854 # compute the approximate number of remaining tests
855 tests, size = 0, 2
855 tests, size = 0, 2
856 while size <= changesets:
856 while size <= changesets:
857 tests, size = tests + 1, size * 2
857 tests, size = tests + 1, size * 2
858 rev = repo.changelog.rev(node)
858 rev = repo.changelog.rev(node)
859 ui.write(_("Testing changeset %d:%s "
859 ui.write(_("Testing changeset %d:%s "
860 "(%d changesets remaining, ~%d tests)\n")
860 "(%d changesets remaining, ~%d tests)\n")
861 % (rev, short(node), changesets, tests))
861 % (rev, short(node), changesets, tests))
862 state['current'] = [node]
862 state['current'] = [node]
863 hbisect.save_state(repo, state)
863 hbisect.save_state(repo, state)
864 if not noupdate:
864 if not noupdate:
865 cmdutil.bailifchanged(repo)
865 cmdutil.bailifchanged(repo)
866 return hg.clean(repo, node)
866 return hg.clean(repo, node)
867
867
868 @command('bookmarks|bookmark',
868 @command('bookmarks|bookmark',
869 [('f', 'force', False, _('force')),
869 [('f', 'force', False, _('force')),
870 ('r', 'rev', '', _('revision'), _('REV')),
870 ('r', 'rev', '', _('revision'), _('REV')),
871 ('d', 'delete', False, _('delete a given bookmark')),
871 ('d', 'delete', False, _('delete a given bookmark')),
872 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
872 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
873 ('i', 'inactive', False, _('mark a bookmark inactive')),
873 ('i', 'inactive', False, _('mark a bookmark inactive')),
874 ] + formatteropts,
874 ] + formatteropts,
875 _('hg bookmarks [OPTIONS]... [NAME]...'))
875 _('hg bookmarks [OPTIONS]... [NAME]...'))
876 def bookmark(ui, repo, *names, **opts):
876 def bookmark(ui, repo, *names, **opts):
877 '''create a new bookmark or list existing bookmarks
877 '''create a new bookmark or list existing bookmarks
878
878
879 Bookmarks are labels on changesets to help track lines of development.
879 Bookmarks are labels on changesets to help track lines of development.
880 Bookmarks are unversioned and can be moved, renamed and deleted.
880 Bookmarks are unversioned and can be moved, renamed and deleted.
881 Deleting or moving a bookmark has no effect on the associated changesets.
881 Deleting or moving a bookmark has no effect on the associated changesets.
882
882
883 Creating or updating to a bookmark causes it to be marked as 'active'.
883 Creating or updating to a bookmark causes it to be marked as 'active'.
884 The active bookmark is indicated with a '*'.
884 The active bookmark is indicated with a '*'.
885 When a commit is made, the active bookmark will advance to the new commit.
885 When a commit is made, the active bookmark will advance to the new commit.
886 A plain :hg:`update` will also advance an active bookmark, if possible.
886 A plain :hg:`update` will also advance an active bookmark, if possible.
887 Updating away from a bookmark will cause it to be deactivated.
887 Updating away from a bookmark will cause it to be deactivated.
888
888
889 Bookmarks can be pushed and pulled between repositories (see
889 Bookmarks can be pushed and pulled between repositories (see
890 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
890 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
891 diverged, a new 'divergent bookmark' of the form 'name@path' will
891 diverged, a new 'divergent bookmark' of the form 'name@path' will
892 be created. Using :hg:`merge` will resolve the divergence.
892 be created. Using :hg:`merge` will resolve the divergence.
893
893
894 A bookmark named '@' has the special property that :hg:`clone` will
894 A bookmark named '@' has the special property that :hg:`clone` will
895 check it out by default if it exists.
895 check it out by default if it exists.
896
896
897 .. container:: verbose
897 .. container:: verbose
898
898
899 Examples:
899 Examples:
900
900
901 - create an active bookmark for a new line of development::
901 - create an active bookmark for a new line of development::
902
902
903 hg book new-feature
903 hg book new-feature
904
904
905 - create an inactive bookmark as a place marker::
905 - create an inactive bookmark as a place marker::
906
906
907 hg book -i reviewed
907 hg book -i reviewed
908
908
909 - create an inactive bookmark on another changeset::
909 - create an inactive bookmark on another changeset::
910
910
911 hg book -r .^ tested
911 hg book -r .^ tested
912
912
913 - move the '@' bookmark from another branch::
913 - move the '@' bookmark from another branch::
914
914
915 hg book -f @
915 hg book -f @
916 '''
916 '''
917 force = opts.get('force')
917 force = opts.get('force')
918 rev = opts.get('rev')
918 rev = opts.get('rev')
919 delete = opts.get('delete')
919 delete = opts.get('delete')
920 rename = opts.get('rename')
920 rename = opts.get('rename')
921 inactive = opts.get('inactive')
921 inactive = opts.get('inactive')
922
922
923 def checkformat(mark):
923 def checkformat(mark):
924 mark = mark.strip()
924 mark = mark.strip()
925 if not mark:
925 if not mark:
926 raise util.Abort(_("bookmark names cannot consist entirely of "
926 raise util.Abort(_("bookmark names cannot consist entirely of "
927 "whitespace"))
927 "whitespace"))
928 scmutil.checknewlabel(repo, mark, 'bookmark')
928 scmutil.checknewlabel(repo, mark, 'bookmark')
929 return mark
929 return mark
930
930
931 def checkconflict(repo, mark, cur, force=False, target=None):
931 def checkconflict(repo, mark, cur, force=False, target=None):
932 if mark in marks and not force:
932 if mark in marks and not force:
933 if target:
933 if target:
934 if marks[mark] == target and target == cur:
934 if marks[mark] == target and target == cur:
935 # re-activating a bookmark
935 # re-activating a bookmark
936 return
936 return
937 anc = repo.changelog.ancestors([repo[target].rev()])
937 anc = repo.changelog.ancestors([repo[target].rev()])
938 bmctx = repo[marks[mark]]
938 bmctx = repo[marks[mark]]
939 divs = [repo[b].node() for b in marks
939 divs = [repo[b].node() for b in marks
940 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
940 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
941
941
942 # allow resolving a single divergent bookmark even if moving
942 # allow resolving a single divergent bookmark even if moving
943 # the bookmark across branches when a revision is specified
943 # the bookmark across branches when a revision is specified
944 # that contains a divergent bookmark
944 # that contains a divergent bookmark
945 if bmctx.rev() not in anc and target in divs:
945 if bmctx.rev() not in anc and target in divs:
946 bookmarks.deletedivergent(repo, [target], mark)
946 bookmarks.deletedivergent(repo, [target], mark)
947 return
947 return
948
948
949 deletefrom = [b for b in divs
949 deletefrom = [b for b in divs
950 if repo[b].rev() in anc or b == target]
950 if repo[b].rev() in anc or b == target]
951 bookmarks.deletedivergent(repo, deletefrom, mark)
951 bookmarks.deletedivergent(repo, deletefrom, mark)
952 if bookmarks.validdest(repo, bmctx, repo[target]):
952 if bookmarks.validdest(repo, bmctx, repo[target]):
953 ui.status(_("moving bookmark '%s' forward from %s\n") %
953 ui.status(_("moving bookmark '%s' forward from %s\n") %
954 (mark, short(bmctx.node())))
954 (mark, short(bmctx.node())))
955 return
955 return
956 raise util.Abort(_("bookmark '%s' already exists "
956 raise util.Abort(_("bookmark '%s' already exists "
957 "(use -f to force)") % mark)
957 "(use -f to force)") % mark)
958 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
958 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
959 and not force):
959 and not force):
960 raise util.Abort(
960 raise util.Abort(
961 _("a bookmark cannot have the name of an existing branch"))
961 _("a bookmark cannot have the name of an existing branch"))
962
962
963 if delete and rename:
963 if delete and rename:
964 raise util.Abort(_("--delete and --rename are incompatible"))
964 raise util.Abort(_("--delete and --rename are incompatible"))
965 if delete and rev:
965 if delete and rev:
966 raise util.Abort(_("--rev is incompatible with --delete"))
966 raise util.Abort(_("--rev is incompatible with --delete"))
967 if rename and rev:
967 if rename and rev:
968 raise util.Abort(_("--rev is incompatible with --rename"))
968 raise util.Abort(_("--rev is incompatible with --rename"))
969 if not names and (delete or rev):
969 if not names and (delete or rev):
970 raise util.Abort(_("bookmark name required"))
970 raise util.Abort(_("bookmark name required"))
971
971
972 if delete or rename or names or inactive:
972 if delete or rename or names or inactive:
973 wlock = repo.wlock()
973 wlock = repo.wlock()
974 try:
974 try:
975 cur = repo.changectx('.').node()
975 cur = repo.changectx('.').node()
976 marks = repo._bookmarks
976 marks = repo._bookmarks
977 if delete:
977 if delete:
978 for mark in names:
978 for mark in names:
979 if mark not in marks:
979 if mark not in marks:
980 raise util.Abort(_("bookmark '%s' does not exist") %
980 raise util.Abort(_("bookmark '%s' does not exist") %
981 mark)
981 mark)
982 if mark == repo._bookmarkcurrent:
982 if mark == repo._bookmarkcurrent:
983 bookmarks.unsetcurrent(repo)
983 bookmarks.unsetcurrent(repo)
984 del marks[mark]
984 del marks[mark]
985 marks.write()
985 marks.write()
986
986
987 elif rename:
987 elif rename:
988 if not names:
988 if not names:
989 raise util.Abort(_("new bookmark name required"))
989 raise util.Abort(_("new bookmark name required"))
990 elif len(names) > 1:
990 elif len(names) > 1:
991 raise util.Abort(_("only one new bookmark name allowed"))
991 raise util.Abort(_("only one new bookmark name allowed"))
992 mark = checkformat(names[0])
992 mark = checkformat(names[0])
993 if rename not in marks:
993 if rename not in marks:
994 raise util.Abort(_("bookmark '%s' does not exist") % rename)
994 raise util.Abort(_("bookmark '%s' does not exist") % rename)
995 checkconflict(repo, mark, cur, force)
995 checkconflict(repo, mark, cur, force)
996 marks[mark] = marks[rename]
996 marks[mark] = marks[rename]
997 if repo._bookmarkcurrent == rename and not inactive:
997 if repo._bookmarkcurrent == rename and not inactive:
998 bookmarks.setcurrent(repo, mark)
998 bookmarks.setcurrent(repo, mark)
999 del marks[rename]
999 del marks[rename]
1000 marks.write()
1000 marks.write()
1001
1001
1002 elif names:
1002 elif names:
1003 newact = None
1003 newact = None
1004 for mark in names:
1004 for mark in names:
1005 mark = checkformat(mark)
1005 mark = checkformat(mark)
1006 if newact is None:
1006 if newact is None:
1007 newact = mark
1007 newact = mark
1008 if inactive and mark == repo._bookmarkcurrent:
1008 if inactive and mark == repo._bookmarkcurrent:
1009 bookmarks.unsetcurrent(repo)
1009 bookmarks.unsetcurrent(repo)
1010 return
1010 return
1011 tgt = cur
1011 tgt = cur
1012 if rev:
1012 if rev:
1013 tgt = scmutil.revsingle(repo, rev).node()
1013 tgt = scmutil.revsingle(repo, rev).node()
1014 checkconflict(repo, mark, cur, force, tgt)
1014 checkconflict(repo, mark, cur, force, tgt)
1015 marks[mark] = tgt
1015 marks[mark] = tgt
1016 if not inactive and cur == marks[newact] and not rev:
1016 if not inactive and cur == marks[newact] and not rev:
1017 bookmarks.setcurrent(repo, newact)
1017 bookmarks.setcurrent(repo, newact)
1018 elif cur != tgt and newact == repo._bookmarkcurrent:
1018 elif cur != tgt and newact == repo._bookmarkcurrent:
1019 bookmarks.unsetcurrent(repo)
1019 bookmarks.unsetcurrent(repo)
1020 marks.write()
1020 marks.write()
1021
1021
1022 elif inactive:
1022 elif inactive:
1023 if len(marks) == 0:
1023 if len(marks) == 0:
1024 ui.status(_("no bookmarks set\n"))
1024 ui.status(_("no bookmarks set\n"))
1025 elif not repo._bookmarkcurrent:
1025 elif not repo._bookmarkcurrent:
1026 ui.status(_("no active bookmark\n"))
1026 ui.status(_("no active bookmark\n"))
1027 else:
1027 else:
1028 bookmarks.unsetcurrent(repo)
1028 bookmarks.unsetcurrent(repo)
1029 finally:
1029 finally:
1030 wlock.release()
1030 wlock.release()
1031 else: # show bookmarks
1031 else: # show bookmarks
1032 fm = ui.formatter('bookmarks', opts)
1032 fm = ui.formatter('bookmarks', opts)
1033 hexfn = fm.hexfunc
1033 hexfn = fm.hexfunc
1034 marks = repo._bookmarks
1034 marks = repo._bookmarks
1035 if len(marks) == 0 and not fm:
1035 if len(marks) == 0 and not fm:
1036 ui.status(_("no bookmarks set\n"))
1036 ui.status(_("no bookmarks set\n"))
1037 for bmark, n in sorted(marks.iteritems()):
1037 for bmark, n in sorted(marks.iteritems()):
1038 current = repo._bookmarkcurrent
1038 current = repo._bookmarkcurrent
1039 if bmark == current:
1039 if bmark == current:
1040 prefix, label = '*', 'bookmarks.current'
1040 prefix, label = '*', 'bookmarks.current'
1041 else:
1041 else:
1042 prefix, label = ' ', ''
1042 prefix, label = ' ', ''
1043
1043
1044 fm.startitem()
1044 fm.startitem()
1045 if not ui.quiet:
1045 if not ui.quiet:
1046 fm.plain(' %s ' % prefix, label=label)
1046 fm.plain(' %s ' % prefix, label=label)
1047 fm.write('bookmark', '%s', bmark, label=label)
1047 fm.write('bookmark', '%s', bmark, label=label)
1048 pad = " " * (25 - encoding.colwidth(bmark))
1048 pad = " " * (25 - encoding.colwidth(bmark))
1049 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1049 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1050 repo.changelog.rev(n), hexfn(n), label=label)
1050 repo.changelog.rev(n), hexfn(n), label=label)
1051 fm.data(active=(bmark == current))
1051 fm.data(active=(bmark == current))
1052 fm.plain('\n')
1052 fm.plain('\n')
1053 fm.end()
1053 fm.end()
1054
1054
1055 @command('branch',
1055 @command('branch',
1056 [('f', 'force', None,
1056 [('f', 'force', None,
1057 _('set branch name even if it shadows an existing branch')),
1057 _('set branch name even if it shadows an existing branch')),
1058 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1058 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1059 _('[-fC] [NAME]'))
1059 _('[-fC] [NAME]'))
1060 def branch(ui, repo, label=None, **opts):
1060 def branch(ui, repo, label=None, **opts):
1061 """set or show the current branch name
1061 """set or show the current branch name
1062
1062
1063 .. note::
1063 .. note::
1064
1064
1065 Branch names are permanent and global. Use :hg:`bookmark` to create a
1065 Branch names are permanent and global. Use :hg:`bookmark` to create a
1066 light-weight bookmark instead. See :hg:`help glossary` for more
1066 light-weight bookmark instead. See :hg:`help glossary` for more
1067 information about named branches and bookmarks.
1067 information about named branches and bookmarks.
1068
1068
1069 With no argument, show the current branch name. With one argument,
1069 With no argument, show the current branch name. With one argument,
1070 set the working directory branch name (the branch will not exist
1070 set the working directory branch name (the branch will not exist
1071 in the repository until the next commit). Standard practice
1071 in the repository until the next commit). Standard practice
1072 recommends that primary development take place on the 'default'
1072 recommends that primary development take place on the 'default'
1073 branch.
1073 branch.
1074
1074
1075 Unless -f/--force is specified, branch will not let you set a
1075 Unless -f/--force is specified, branch will not let you set a
1076 branch name that already exists.
1076 branch name that already exists.
1077
1077
1078 Use -C/--clean to reset the working directory branch to that of
1078 Use -C/--clean to reset the working directory branch to that of
1079 the parent of the working directory, negating a previous branch
1079 the parent of the working directory, negating a previous branch
1080 change.
1080 change.
1081
1081
1082 Use the command :hg:`update` to switch to an existing branch. Use
1082 Use the command :hg:`update` to switch to an existing branch. Use
1083 :hg:`commit --close-branch` to mark this branch as closed.
1083 :hg:`commit --close-branch` to mark this branch as closed.
1084
1084
1085 Returns 0 on success.
1085 Returns 0 on success.
1086 """
1086 """
1087 if label:
1087 if label:
1088 label = label.strip()
1088 label = label.strip()
1089
1089
1090 if not opts.get('clean') and not label:
1090 if not opts.get('clean') and not label:
1091 ui.write("%s\n" % repo.dirstate.branch())
1091 ui.write("%s\n" % repo.dirstate.branch())
1092 return
1092 return
1093
1093
1094 wlock = repo.wlock()
1094 wlock = repo.wlock()
1095 try:
1095 try:
1096 if opts.get('clean'):
1096 if opts.get('clean'):
1097 label = repo[None].p1().branch()
1097 label = repo[None].p1().branch()
1098 repo.dirstate.setbranch(label)
1098 repo.dirstate.setbranch(label)
1099 ui.status(_('reset working directory to branch %s\n') % label)
1099 ui.status(_('reset working directory to branch %s\n') % label)
1100 elif label:
1100 elif label:
1101 if not opts.get('force') and label in repo.branchmap():
1101 if not opts.get('force') and label in repo.branchmap():
1102 if label not in [p.branch() for p in repo.parents()]:
1102 if label not in [p.branch() for p in repo.parents()]:
1103 raise util.Abort(_('a branch of the same name already'
1103 raise util.Abort(_('a branch of the same name already'
1104 ' exists'),
1104 ' exists'),
1105 # i18n: "it" refers to an existing branch
1105 # i18n: "it" refers to an existing branch
1106 hint=_("use 'hg update' to switch to it"))
1106 hint=_("use 'hg update' to switch to it"))
1107 scmutil.checknewlabel(repo, label, 'branch')
1107 scmutil.checknewlabel(repo, label, 'branch')
1108 repo.dirstate.setbranch(label)
1108 repo.dirstate.setbranch(label)
1109 ui.status(_('marked working directory as branch %s\n') % label)
1109 ui.status(_('marked working directory as branch %s\n') % label)
1110 ui.status(_('(branches are permanent and global, '
1110 ui.status(_('(branches are permanent and global, '
1111 'did you want a bookmark?)\n'))
1111 'did you want a bookmark?)\n'))
1112 finally:
1112 finally:
1113 wlock.release()
1113 wlock.release()
1114
1114
1115 @command('branches',
1115 @command('branches',
1116 [('a', 'active', False,
1116 [('a', 'active', False,
1117 _('show only branches that have unmerged heads (DEPRECATED)')),
1117 _('show only branches that have unmerged heads (DEPRECATED)')),
1118 ('c', 'closed', False, _('show normal and closed branches')),
1118 ('c', 'closed', False, _('show normal and closed branches')),
1119 ] + formatteropts,
1119 ] + formatteropts,
1120 _('[-ac]'))
1120 _('[-ac]'))
1121 def branches(ui, repo, active=False, closed=False, **opts):
1121 def branches(ui, repo, active=False, closed=False, **opts):
1122 """list repository named branches
1122 """list repository named branches
1123
1123
1124 List the repository's named branches, indicating which ones are
1124 List the repository's named branches, indicating which ones are
1125 inactive. If -c/--closed is specified, also list branches which have
1125 inactive. If -c/--closed is specified, also list branches which have
1126 been marked closed (see :hg:`commit --close-branch`).
1126 been marked closed (see :hg:`commit --close-branch`).
1127
1127
1128 Use the command :hg:`update` to switch to an existing branch.
1128 Use the command :hg:`update` to switch to an existing branch.
1129
1129
1130 Returns 0.
1130 Returns 0.
1131 """
1131 """
1132
1132
1133 fm = ui.formatter('branches', opts)
1133 fm = ui.formatter('branches', opts)
1134 hexfunc = fm.hexfunc
1134 hexfunc = fm.hexfunc
1135
1135
1136 allheads = set(repo.heads())
1136 allheads = set(repo.heads())
1137 branches = []
1137 branches = []
1138 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1138 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1139 isactive = not isclosed and bool(set(heads) & allheads)
1139 isactive = not isclosed and bool(set(heads) & allheads)
1140 branches.append((tag, repo[tip], isactive, not isclosed))
1140 branches.append((tag, repo[tip], isactive, not isclosed))
1141 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1141 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1142 reverse=True)
1142 reverse=True)
1143
1143
1144 for tag, ctx, isactive, isopen in branches:
1144 for tag, ctx, isactive, isopen in branches:
1145 if active and not isactive:
1145 if active and not isactive:
1146 continue
1146 continue
1147 if isactive:
1147 if isactive:
1148 label = 'branches.active'
1148 label = 'branches.active'
1149 notice = ''
1149 notice = ''
1150 elif not isopen:
1150 elif not isopen:
1151 if not closed:
1151 if not closed:
1152 continue
1152 continue
1153 label = 'branches.closed'
1153 label = 'branches.closed'
1154 notice = _(' (closed)')
1154 notice = _(' (closed)')
1155 else:
1155 else:
1156 label = 'branches.inactive'
1156 label = 'branches.inactive'
1157 notice = _(' (inactive)')
1157 notice = _(' (inactive)')
1158 current = (tag == repo.dirstate.branch())
1158 current = (tag == repo.dirstate.branch())
1159 if current:
1159 if current:
1160 label = 'branches.current'
1160 label = 'branches.current'
1161
1161
1162 fm.startitem()
1162 fm.startitem()
1163 fm.write('branch', '%s', tag, label=label)
1163 fm.write('branch', '%s', tag, label=label)
1164 rev = ctx.rev()
1164 rev = ctx.rev()
1165 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1165 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1166 fmt = ' ' * padsize + ' %d:%s'
1166 fmt = ' ' * padsize + ' %d:%s'
1167 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1167 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1168 label='log.changeset changeset.%s' % ctx.phasestr())
1168 label='log.changeset changeset.%s' % ctx.phasestr())
1169 fm.data(active=isactive, closed=not isopen, current=current)
1169 fm.data(active=isactive, closed=not isopen, current=current)
1170 if not ui.quiet:
1170 if not ui.quiet:
1171 fm.plain(notice)
1171 fm.plain(notice)
1172 fm.plain('\n')
1172 fm.plain('\n')
1173 fm.end()
1173 fm.end()
1174
1174
1175 @command('bundle',
1175 @command('bundle',
1176 [('f', 'force', None, _('run even when the destination is unrelated')),
1176 [('f', 'force', None, _('run even when the destination is unrelated')),
1177 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1177 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1178 _('REV')),
1178 _('REV')),
1179 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1179 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1180 _('BRANCH')),
1180 _('BRANCH')),
1181 ('', 'base', [],
1181 ('', 'base', [],
1182 _('a base changeset assumed to be available at the destination'),
1182 _('a base changeset assumed to be available at the destination'),
1183 _('REV')),
1183 _('REV')),
1184 ('a', 'all', None, _('bundle all changesets in the repository')),
1184 ('a', 'all', None, _('bundle all changesets in the repository')),
1185 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1185 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1186 ] + remoteopts,
1186 ] + remoteopts,
1187 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1187 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1188 def bundle(ui, repo, fname, dest=None, **opts):
1188 def bundle(ui, repo, fname, dest=None, **opts):
1189 """create a changegroup file
1189 """create a changegroup file
1190
1190
1191 Generate a compressed changegroup file collecting changesets not
1191 Generate a compressed changegroup file collecting changesets not
1192 known to be in another repository.
1192 known to be in another repository.
1193
1193
1194 If you omit the destination repository, then hg assumes the
1194 If you omit the destination repository, then hg assumes the
1195 destination will have all the nodes you specify with --base
1195 destination will have all the nodes you specify with --base
1196 parameters. To create a bundle containing all changesets, use
1196 parameters. To create a bundle containing all changesets, use
1197 -a/--all (or --base null).
1197 -a/--all (or --base null).
1198
1198
1199 You can change compression method with the -t/--type option.
1199 You can change compression method with the -t/--type option.
1200 The available compression methods are: none, bzip2, and
1200 The available compression methods are: none, bzip2, and
1201 gzip (by default, bundles are compressed using bzip2).
1201 gzip (by default, bundles are compressed using bzip2).
1202
1202
1203 The bundle file can then be transferred using conventional means
1203 The bundle file can then be transferred using conventional means
1204 and applied to another repository with the unbundle or pull
1204 and applied to another repository with the unbundle or pull
1205 command. This is useful when direct push and pull are not
1205 command. This is useful when direct push and pull are not
1206 available or when exporting an entire repository is undesirable.
1206 available or when exporting an entire repository is undesirable.
1207
1207
1208 Applying bundles preserves all changeset contents including
1208 Applying bundles preserves all changeset contents including
1209 permissions, copy/rename information, and revision history.
1209 permissions, copy/rename information, and revision history.
1210
1210
1211 Returns 0 on success, 1 if no changes found.
1211 Returns 0 on success, 1 if no changes found.
1212 """
1212 """
1213 revs = None
1213 revs = None
1214 if 'rev' in opts:
1214 if 'rev' in opts:
1215 revs = scmutil.revrange(repo, opts['rev'])
1215 revs = scmutil.revrange(repo, opts['rev'])
1216
1216
1217 bundletype = opts.get('type', 'bzip2').lower()
1217 bundletype = opts.get('type', 'bzip2').lower()
1218 btypes = {'none': 'HG10UN',
1218 btypes = {'none': 'HG10UN',
1219 'bzip2': 'HG10BZ',
1219 'bzip2': 'HG10BZ',
1220 'gzip': 'HG10GZ',
1220 'gzip': 'HG10GZ',
1221 'bundle2': 'HG20'}
1221 'bundle2': 'HG20'}
1222 bundletype = btypes.get(bundletype)
1222 bundletype = btypes.get(bundletype)
1223 if bundletype not in changegroup.bundletypes:
1223 if bundletype not in changegroup.bundletypes:
1224 raise util.Abort(_('unknown bundle type specified with --type'))
1224 raise util.Abort(_('unknown bundle type specified with --type'))
1225
1225
1226 if opts.get('all'):
1226 if opts.get('all'):
1227 base = ['null']
1227 base = ['null']
1228 else:
1228 else:
1229 base = scmutil.revrange(repo, opts.get('base'))
1229 base = scmutil.revrange(repo, opts.get('base'))
1230 # TODO: get desired bundlecaps from command line.
1230 # TODO: get desired bundlecaps from command line.
1231 bundlecaps = None
1231 bundlecaps = None
1232 if base:
1232 if base:
1233 if dest:
1233 if dest:
1234 raise util.Abort(_("--base is incompatible with specifying "
1234 raise util.Abort(_("--base is incompatible with specifying "
1235 "a destination"))
1235 "a destination"))
1236 common = [repo.lookup(rev) for rev in base]
1236 common = [repo.lookup(rev) for rev in base]
1237 heads = revs and map(repo.lookup, revs) or revs
1237 heads = revs and map(repo.lookup, revs) or revs
1238 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1238 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1239 common=common, bundlecaps=bundlecaps)
1239 common=common, bundlecaps=bundlecaps)
1240 outgoing = None
1240 outgoing = None
1241 else:
1241 else:
1242 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1242 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1243 dest, branches = hg.parseurl(dest, opts.get('branch'))
1243 dest, branches = hg.parseurl(dest, opts.get('branch'))
1244 other = hg.peer(repo, opts, dest)
1244 other = hg.peer(repo, opts, dest)
1245 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1245 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1246 heads = revs and map(repo.lookup, revs) or revs
1246 heads = revs and map(repo.lookup, revs) or revs
1247 outgoing = discovery.findcommonoutgoing(repo, other,
1247 outgoing = discovery.findcommonoutgoing(repo, other,
1248 onlyheads=heads,
1248 onlyheads=heads,
1249 force=opts.get('force'),
1249 force=opts.get('force'),
1250 portable=True)
1250 portable=True)
1251 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1251 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1252 bundlecaps)
1252 bundlecaps)
1253 if not cg:
1253 if not cg:
1254 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1254 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1255 return 1
1255 return 1
1256
1256
1257 changegroup.writebundle(ui, cg, fname, bundletype)
1257 changegroup.writebundle(ui, cg, fname, bundletype)
1258
1258
1259 @command('cat',
1259 @command('cat',
1260 [('o', 'output', '',
1260 [('o', 'output', '',
1261 _('print output to file with formatted name'), _('FORMAT')),
1261 _('print output to file with formatted name'), _('FORMAT')),
1262 ('r', 'rev', '', _('print the given revision'), _('REV')),
1262 ('r', 'rev', '', _('print the given revision'), _('REV')),
1263 ('', 'decode', None, _('apply any matching decode filter')),
1263 ('', 'decode', None, _('apply any matching decode filter')),
1264 ] + walkopts,
1264 ] + walkopts,
1265 _('[OPTION]... FILE...'),
1265 _('[OPTION]... FILE...'),
1266 inferrepo=True)
1266 inferrepo=True)
1267 def cat(ui, repo, file1, *pats, **opts):
1267 def cat(ui, repo, file1, *pats, **opts):
1268 """output the current or given revision of files
1268 """output the current or given revision of files
1269
1269
1270 Print the specified files as they were at the given revision. If
1270 Print the specified files as they were at the given revision. If
1271 no revision is given, the parent of the working directory is used.
1271 no revision is given, the parent of the working directory is used.
1272
1272
1273 Output may be to a file, in which case the name of the file is
1273 Output may be to a file, in which case the name of the file is
1274 given using a format string. The formatting rules as follows:
1274 given using a format string. The formatting rules as follows:
1275
1275
1276 :``%%``: literal "%" character
1276 :``%%``: literal "%" character
1277 :``%s``: basename of file being printed
1277 :``%s``: basename of file being printed
1278 :``%d``: dirname of file being printed, or '.' if in repository root
1278 :``%d``: dirname of file being printed, or '.' if in repository root
1279 :``%p``: root-relative path name of file being printed
1279 :``%p``: root-relative path name of file being printed
1280 :``%H``: changeset hash (40 hexadecimal digits)
1280 :``%H``: changeset hash (40 hexadecimal digits)
1281 :``%R``: changeset revision number
1281 :``%R``: changeset revision number
1282 :``%h``: short-form changeset hash (12 hexadecimal digits)
1282 :``%h``: short-form changeset hash (12 hexadecimal digits)
1283 :``%r``: zero-padded changeset revision number
1283 :``%r``: zero-padded changeset revision number
1284 :``%b``: basename of the exporting repository
1284 :``%b``: basename of the exporting repository
1285
1285
1286 Returns 0 on success.
1286 Returns 0 on success.
1287 """
1287 """
1288 ctx = scmutil.revsingle(repo, opts.get('rev'))
1288 ctx = scmutil.revsingle(repo, opts.get('rev'))
1289 m = scmutil.match(ctx, (file1,) + pats, opts)
1289 m = scmutil.match(ctx, (file1,) + pats, opts)
1290
1290
1291 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1291 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1292
1292
1293 @command('^clone',
1293 @command('^clone',
1294 [('U', 'noupdate', None, _('the clone will include an empty working '
1294 [('U', 'noupdate', None, _('the clone will include an empty working '
1295 'directory (only a repository)')),
1295 'directory (only a repository)')),
1296 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1296 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1297 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1297 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1298 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1298 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1299 ('', 'pull', None, _('use pull protocol to copy metadata')),
1299 ('', 'pull', None, _('use pull protocol to copy metadata')),
1300 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1300 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1301 ] + remoteopts,
1301 ] + remoteopts,
1302 _('[OPTION]... SOURCE [DEST]'),
1302 _('[OPTION]... SOURCE [DEST]'),
1303 norepo=True)
1303 norepo=True)
1304 def clone(ui, source, dest=None, **opts):
1304 def clone(ui, source, dest=None, **opts):
1305 """make a copy of an existing repository
1305 """make a copy of an existing repository
1306
1306
1307 Create a copy of an existing repository in a new directory.
1307 Create a copy of an existing repository in a new directory.
1308
1308
1309 If no destination directory name is specified, it defaults to the
1309 If no destination directory name is specified, it defaults to the
1310 basename of the source.
1310 basename of the source.
1311
1311
1312 The location of the source is added to the new repository's
1312 The location of the source is added to the new repository's
1313 ``.hg/hgrc`` file, as the default to be used for future pulls.
1313 ``.hg/hgrc`` file, as the default to be used for future pulls.
1314
1314
1315 Only local paths and ``ssh://`` URLs are supported as
1315 Only local paths and ``ssh://`` URLs are supported as
1316 destinations. For ``ssh://`` destinations, no working directory or
1316 destinations. For ``ssh://`` destinations, no working directory or
1317 ``.hg/hgrc`` will be created on the remote side.
1317 ``.hg/hgrc`` will be created on the remote side.
1318
1318
1319 To pull only a subset of changesets, specify one or more revisions
1319 To pull only a subset of changesets, specify one or more revisions
1320 identifiers with -r/--rev or branches with -b/--branch. The
1320 identifiers with -r/--rev or branches with -b/--branch. The
1321 resulting clone will contain only the specified changesets and
1321 resulting clone will contain only the specified changesets and
1322 their ancestors. These options (or 'clone src#rev dest') imply
1322 their ancestors. These options (or 'clone src#rev dest') imply
1323 --pull, even for local source repositories. Note that specifying a
1323 --pull, even for local source repositories. Note that specifying a
1324 tag will include the tagged changeset but not the changeset
1324 tag will include the tagged changeset but not the changeset
1325 containing the tag.
1325 containing the tag.
1326
1326
1327 If the source repository has a bookmark called '@' set, that
1327 If the source repository has a bookmark called '@' set, that
1328 revision will be checked out in the new repository by default.
1328 revision will be checked out in the new repository by default.
1329
1329
1330 To check out a particular version, use -u/--update, or
1330 To check out a particular version, use -u/--update, or
1331 -U/--noupdate to create a clone with no working directory.
1331 -U/--noupdate to create a clone with no working directory.
1332
1332
1333 .. container:: verbose
1333 .. container:: verbose
1334
1334
1335 For efficiency, hardlinks are used for cloning whenever the
1335 For efficiency, hardlinks are used for cloning whenever the
1336 source and destination are on the same filesystem (note this
1336 source and destination are on the same filesystem (note this
1337 applies only to the repository data, not to the working
1337 applies only to the repository data, not to the working
1338 directory). Some filesystems, such as AFS, implement hardlinking
1338 directory). Some filesystems, such as AFS, implement hardlinking
1339 incorrectly, but do not report errors. In these cases, use the
1339 incorrectly, but do not report errors. In these cases, use the
1340 --pull option to avoid hardlinking.
1340 --pull option to avoid hardlinking.
1341
1341
1342 In some cases, you can clone repositories and the working
1342 In some cases, you can clone repositories and the working
1343 directory using full hardlinks with ::
1343 directory using full hardlinks with ::
1344
1344
1345 $ cp -al REPO REPOCLONE
1345 $ cp -al REPO REPOCLONE
1346
1346
1347 This is the fastest way to clone, but it is not always safe. The
1347 This is the fastest way to clone, but it is not always safe. The
1348 operation is not atomic (making sure REPO is not modified during
1348 operation is not atomic (making sure REPO is not modified during
1349 the operation is up to you) and you have to make sure your
1349 the operation is up to you) and you have to make sure your
1350 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1350 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1351 so). Also, this is not compatible with certain extensions that
1351 so). Also, this is not compatible with certain extensions that
1352 place their metadata under the .hg directory, such as mq.
1352 place their metadata under the .hg directory, such as mq.
1353
1353
1354 Mercurial will update the working directory to the first applicable
1354 Mercurial will update the working directory to the first applicable
1355 revision from this list:
1355 revision from this list:
1356
1356
1357 a) null if -U or the source repository has no changesets
1357 a) null if -U or the source repository has no changesets
1358 b) if -u . and the source repository is local, the first parent of
1358 b) if -u . and the source repository is local, the first parent of
1359 the source repository's working directory
1359 the source repository's working directory
1360 c) the changeset specified with -u (if a branch name, this means the
1360 c) the changeset specified with -u (if a branch name, this means the
1361 latest head of that branch)
1361 latest head of that branch)
1362 d) the changeset specified with -r
1362 d) the changeset specified with -r
1363 e) the tipmost head specified with -b
1363 e) the tipmost head specified with -b
1364 f) the tipmost head specified with the url#branch source syntax
1364 f) the tipmost head specified with the url#branch source syntax
1365 g) the revision marked with the '@' bookmark, if present
1365 g) the revision marked with the '@' bookmark, if present
1366 h) the tipmost head of the default branch
1366 h) the tipmost head of the default branch
1367 i) tip
1367 i) tip
1368
1368
1369 Examples:
1369 Examples:
1370
1370
1371 - clone a remote repository to a new directory named hg/::
1371 - clone a remote repository to a new directory named hg/::
1372
1372
1373 hg clone http://selenic.com/hg
1373 hg clone http://selenic.com/hg
1374
1374
1375 - create a lightweight local clone::
1375 - create a lightweight local clone::
1376
1376
1377 hg clone project/ project-feature/
1377 hg clone project/ project-feature/
1378
1378
1379 - clone from an absolute path on an ssh server (note double-slash)::
1379 - clone from an absolute path on an ssh server (note double-slash)::
1380
1380
1381 hg clone ssh://user@server//home/projects/alpha/
1381 hg clone ssh://user@server//home/projects/alpha/
1382
1382
1383 - do a high-speed clone over a LAN while checking out a
1383 - do a high-speed clone over a LAN while checking out a
1384 specified version::
1384 specified version::
1385
1385
1386 hg clone --uncompressed http://server/repo -u 1.5
1386 hg clone --uncompressed http://server/repo -u 1.5
1387
1387
1388 - create a repository without changesets after a particular revision::
1388 - create a repository without changesets after a particular revision::
1389
1389
1390 hg clone -r 04e544 experimental/ good/
1390 hg clone -r 04e544 experimental/ good/
1391
1391
1392 - clone (and track) a particular named branch::
1392 - clone (and track) a particular named branch::
1393
1393
1394 hg clone http://selenic.com/hg#stable
1394 hg clone http://selenic.com/hg#stable
1395
1395
1396 See :hg:`help urls` for details on specifying URLs.
1396 See :hg:`help urls` for details on specifying URLs.
1397
1397
1398 Returns 0 on success.
1398 Returns 0 on success.
1399 """
1399 """
1400 if opts.get('noupdate') and opts.get('updaterev'):
1400 if opts.get('noupdate') and opts.get('updaterev'):
1401 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1401 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1402
1402
1403 r = hg.clone(ui, opts, source, dest,
1403 r = hg.clone(ui, opts, source, dest,
1404 pull=opts.get('pull'),
1404 pull=opts.get('pull'),
1405 stream=opts.get('uncompressed'),
1405 stream=opts.get('uncompressed'),
1406 rev=opts.get('rev'),
1406 rev=opts.get('rev'),
1407 update=opts.get('updaterev') or not opts.get('noupdate'),
1407 update=opts.get('updaterev') or not opts.get('noupdate'),
1408 branch=opts.get('branch'))
1408 branch=opts.get('branch'))
1409
1409
1410 return r is None
1410 return r is None
1411
1411
1412 @command('^commit|ci',
1412 @command('^commit|ci',
1413 [('A', 'addremove', None,
1413 [('A', 'addremove', None,
1414 _('mark new/missing files as added/removed before committing')),
1414 _('mark new/missing files as added/removed before committing')),
1415 ('', 'close-branch', None,
1415 ('', 'close-branch', None,
1416 _('mark a branch as closed, hiding it from the branch list')),
1416 _('mark a branch as closed, hiding it from the branch list')),
1417 ('', 'amend', None, _('amend the parent of the working directory')),
1417 ('', 'amend', None, _('amend the parent of the working directory')),
1418 ('s', 'secret', None, _('use the secret phase for committing')),
1418 ('s', 'secret', None, _('use the secret phase for committing')),
1419 ('e', 'edit', None, _('invoke editor on commit messages')),
1419 ('e', 'edit', None, _('invoke editor on commit messages')),
1420 ('i', 'interactive', None, _('use interactive mode')),
1420 ('i', 'interactive', None, _('use interactive mode')),
1421 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1421 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1422 _('[OPTION]... [FILE]...'),
1422 _('[OPTION]... [FILE]...'),
1423 inferrepo=True)
1423 inferrepo=True)
1424 def commit(ui, repo, *pats, **opts):
1424 def commit(ui, repo, *pats, **opts):
1425 """commit the specified files or all outstanding changes
1425 """commit the specified files or all outstanding changes
1426
1426
1427 Commit changes to the given files into the repository. Unlike a
1427 Commit changes to the given files into the repository. Unlike a
1428 centralized SCM, this operation is a local operation. See
1428 centralized SCM, this operation is a local operation. See
1429 :hg:`push` for a way to actively distribute your changes.
1429 :hg:`push` for a way to actively distribute your changes.
1430
1430
1431 If a list of files is omitted, all changes reported by :hg:`status`
1431 If a list of files is omitted, all changes reported by :hg:`status`
1432 will be committed.
1432 will be committed.
1433
1433
1434 If you are committing the result of a merge, do not provide any
1434 If you are committing the result of a merge, do not provide any
1435 filenames or -I/-X filters.
1435 filenames or -I/-X filters.
1436
1436
1437 If no commit message is specified, Mercurial starts your
1437 If no commit message is specified, Mercurial starts your
1438 configured editor where you can enter a message. In case your
1438 configured editor where you can enter a message. In case your
1439 commit fails, you will find a backup of your message in
1439 commit fails, you will find a backup of your message in
1440 ``.hg/last-message.txt``.
1440 ``.hg/last-message.txt``.
1441
1441
1442 The --amend flag can be used to amend the parent of the
1442 The --amend flag can be used to amend the parent of the
1443 working directory with a new commit that contains the changes
1443 working directory with a new commit that contains the changes
1444 in the parent in addition to those currently reported by :hg:`status`,
1444 in the parent in addition to those currently reported by :hg:`status`,
1445 if there are any. The old commit is stored in a backup bundle in
1445 if there are any. The old commit is stored in a backup bundle in
1446 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1446 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1447 on how to restore it).
1447 on how to restore it).
1448
1448
1449 Message, user and date are taken from the amended commit unless
1449 Message, user and date are taken from the amended commit unless
1450 specified. When a message isn't specified on the command line,
1450 specified. When a message isn't specified on the command line,
1451 the editor will open with the message of the amended commit.
1451 the editor will open with the message of the amended commit.
1452
1452
1453 It is not possible to amend public changesets (see :hg:`help phases`)
1453 It is not possible to amend public changesets (see :hg:`help phases`)
1454 or changesets that have children.
1454 or changesets that have children.
1455
1455
1456 See :hg:`help dates` for a list of formats valid for -d/--date.
1456 See :hg:`help dates` for a list of formats valid for -d/--date.
1457
1457
1458 Returns 0 on success, 1 if nothing changed.
1458 Returns 0 on success, 1 if nothing changed.
1459 """
1459 """
1460 if opts.get('interactive'):
1460 if opts.get('interactive'):
1461 opts.pop('interactive')
1461 opts.pop('interactive')
1462 cmdutil.dorecord(ui, repo, commit, 'commit', False,
1462 cmdutil.dorecord(ui, repo, commit, 'commit', False,
1463 cmdutil.recordfilter, *pats, **opts)
1463 cmdutil.recordfilter, *pats, **opts)
1464 return
1464 return
1465
1465
1466 if opts.get('subrepos'):
1466 if opts.get('subrepos'):
1467 if opts.get('amend'):
1467 if opts.get('amend'):
1468 raise util.Abort(_('cannot amend with --subrepos'))
1468 raise util.Abort(_('cannot amend with --subrepos'))
1469 # Let --subrepos on the command line override config setting.
1469 # Let --subrepos on the command line override config setting.
1470 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1470 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1471
1471
1472 cmdutil.checkunfinished(repo, commit=True)
1472 cmdutil.checkunfinished(repo, commit=True)
1473
1473
1474 branch = repo[None].branch()
1474 branch = repo[None].branch()
1475 bheads = repo.branchheads(branch)
1475 bheads = repo.branchheads(branch)
1476
1476
1477 extra = {}
1477 extra = {}
1478 if opts.get('close_branch'):
1478 if opts.get('close_branch'):
1479 extra['close'] = 1
1479 extra['close'] = 1
1480
1480
1481 if not bheads:
1481 if not bheads:
1482 raise util.Abort(_('can only close branch heads'))
1482 raise util.Abort(_('can only close branch heads'))
1483 elif opts.get('amend'):
1483 elif opts.get('amend'):
1484 if repo.parents()[0].p1().branch() != branch and \
1484 if repo.parents()[0].p1().branch() != branch and \
1485 repo.parents()[0].p2().branch() != branch:
1485 repo.parents()[0].p2().branch() != branch:
1486 raise util.Abort(_('can only close branch heads'))
1486 raise util.Abort(_('can only close branch heads'))
1487
1487
1488 if opts.get('amend'):
1488 if opts.get('amend'):
1489 if ui.configbool('ui', 'commitsubrepos'):
1489 if ui.configbool('ui', 'commitsubrepos'):
1490 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1490 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1491
1491
1492 old = repo['.']
1492 old = repo['.']
1493 if not old.mutable():
1493 if not old.mutable():
1494 raise util.Abort(_('cannot amend public changesets'))
1494 raise util.Abort(_('cannot amend public changesets'))
1495 if len(repo[None].parents()) > 1:
1495 if len(repo[None].parents()) > 1:
1496 raise util.Abort(_('cannot amend while merging'))
1496 raise util.Abort(_('cannot amend while merging'))
1497 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1497 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1498 if not allowunstable and old.children():
1498 if not allowunstable and old.children():
1499 raise util.Abort(_('cannot amend changeset with children'))
1499 raise util.Abort(_('cannot amend changeset with children'))
1500
1500
1501 # commitfunc is used only for temporary amend commit by cmdutil.amend
1501 # commitfunc is used only for temporary amend commit by cmdutil.amend
1502 def commitfunc(ui, repo, message, match, opts):
1502 def commitfunc(ui, repo, message, match, opts):
1503 return repo.commit(message,
1503 return repo.commit(message,
1504 opts.get('user') or old.user(),
1504 opts.get('user') or old.user(),
1505 opts.get('date') or old.date(),
1505 opts.get('date') or old.date(),
1506 match,
1506 match,
1507 extra=extra)
1507 extra=extra)
1508
1508
1509 current = repo._bookmarkcurrent
1509 current = repo._bookmarkcurrent
1510 marks = old.bookmarks()
1510 marks = old.bookmarks()
1511 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1511 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1512 if node == old.node():
1512 if node == old.node():
1513 ui.status(_("nothing changed\n"))
1513 ui.status(_("nothing changed\n"))
1514 return 1
1514 return 1
1515 elif marks:
1515 elif marks:
1516 ui.debug('moving bookmarks %r from %s to %s\n' %
1516 ui.debug('moving bookmarks %r from %s to %s\n' %
1517 (marks, old.hex(), hex(node)))
1517 (marks, old.hex(), hex(node)))
1518 newmarks = repo._bookmarks
1518 newmarks = repo._bookmarks
1519 for bm in marks:
1519 for bm in marks:
1520 newmarks[bm] = node
1520 newmarks[bm] = node
1521 if bm == current:
1521 if bm == current:
1522 bookmarks.setcurrent(repo, bm)
1522 bookmarks.setcurrent(repo, bm)
1523 newmarks.write()
1523 newmarks.write()
1524 else:
1524 else:
1525 def commitfunc(ui, repo, message, match, opts):
1525 def commitfunc(ui, repo, message, match, opts):
1526 backup = ui.backupconfig('phases', 'new-commit')
1526 backup = ui.backupconfig('phases', 'new-commit')
1527 baseui = repo.baseui
1527 baseui = repo.baseui
1528 basebackup = baseui.backupconfig('phases', 'new-commit')
1528 basebackup = baseui.backupconfig('phases', 'new-commit')
1529 try:
1529 try:
1530 if opts.get('secret'):
1530 if opts.get('secret'):
1531 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1531 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1532 # Propagate to subrepos
1532 # Propagate to subrepos
1533 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1533 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1534
1534
1535 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1535 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1536 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1536 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1537 return repo.commit(message, opts.get('user'), opts.get('date'),
1537 return repo.commit(message, opts.get('user'), opts.get('date'),
1538 match,
1538 match,
1539 editor=editor,
1539 editor=editor,
1540 extra=extra)
1540 extra=extra)
1541 finally:
1541 finally:
1542 ui.restoreconfig(backup)
1542 ui.restoreconfig(backup)
1543 repo.baseui.restoreconfig(basebackup)
1543 repo.baseui.restoreconfig(basebackup)
1544
1544
1545
1545
1546 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1546 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1547
1547
1548 if not node:
1548 if not node:
1549 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1549 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1550 if stat[3]:
1550 if stat[3]:
1551 ui.status(_("nothing changed (%d missing files, see "
1551 ui.status(_("nothing changed (%d missing files, see "
1552 "'hg status')\n") % len(stat[3]))
1552 "'hg status')\n") % len(stat[3]))
1553 else:
1553 else:
1554 ui.status(_("nothing changed\n"))
1554 ui.status(_("nothing changed\n"))
1555 return 1
1555 return 1
1556
1556
1557 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1557 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1558
1558
1559 @command('config|showconfig|debugconfig',
1559 @command('config|showconfig|debugconfig',
1560 [('u', 'untrusted', None, _('show untrusted configuration options')),
1560 [('u', 'untrusted', None, _('show untrusted configuration options')),
1561 ('e', 'edit', None, _('edit user config')),
1561 ('e', 'edit', None, _('edit user config')),
1562 ('l', 'local', None, _('edit repository config')),
1562 ('l', 'local', None, _('edit repository config')),
1563 ('g', 'global', None, _('edit global config'))],
1563 ('g', 'global', None, _('edit global config'))],
1564 _('[-u] [NAME]...'),
1564 _('[-u] [NAME]...'),
1565 optionalrepo=True)
1565 optionalrepo=True)
1566 def config(ui, repo, *values, **opts):
1566 def config(ui, repo, *values, **opts):
1567 """show combined config settings from all hgrc files
1567 """show combined config settings from all hgrc files
1568
1568
1569 With no arguments, print names and values of all config items.
1569 With no arguments, print names and values of all config items.
1570
1570
1571 With one argument of the form section.name, print just the value
1571 With one argument of the form section.name, print just the value
1572 of that config item.
1572 of that config item.
1573
1573
1574 With multiple arguments, print names and values of all config
1574 With multiple arguments, print names and values of all config
1575 items with matching section names.
1575 items with matching section names.
1576
1576
1577 With --edit, start an editor on the user-level config file. With
1577 With --edit, start an editor on the user-level config file. With
1578 --global, edit the system-wide config file. With --local, edit the
1578 --global, edit the system-wide config file. With --local, edit the
1579 repository-level config file.
1579 repository-level config file.
1580
1580
1581 With --debug, the source (filename and line number) is printed
1581 With --debug, the source (filename and line number) is printed
1582 for each config item.
1582 for each config item.
1583
1583
1584 See :hg:`help config` for more information about config files.
1584 See :hg:`help config` for more information about config files.
1585
1585
1586 Returns 0 on success, 1 if NAME does not exist.
1586 Returns 0 on success, 1 if NAME does not exist.
1587
1587
1588 """
1588 """
1589
1589
1590 if opts.get('edit') or opts.get('local') or opts.get('global'):
1590 if opts.get('edit') or opts.get('local') or opts.get('global'):
1591 if opts.get('local') and opts.get('global'):
1591 if opts.get('local') and opts.get('global'):
1592 raise util.Abort(_("can't use --local and --global together"))
1592 raise util.Abort(_("can't use --local and --global together"))
1593
1593
1594 if opts.get('local'):
1594 if opts.get('local'):
1595 if not repo:
1595 if not repo:
1596 raise util.Abort(_("can't use --local outside a repository"))
1596 raise util.Abort(_("can't use --local outside a repository"))
1597 paths = [repo.join('hgrc')]
1597 paths = [repo.join('hgrc')]
1598 elif opts.get('global'):
1598 elif opts.get('global'):
1599 paths = scmutil.systemrcpath()
1599 paths = scmutil.systemrcpath()
1600 else:
1600 else:
1601 paths = scmutil.userrcpath()
1601 paths = scmutil.userrcpath()
1602
1602
1603 for f in paths:
1603 for f in paths:
1604 if os.path.exists(f):
1604 if os.path.exists(f):
1605 break
1605 break
1606 else:
1606 else:
1607 if opts.get('global'):
1607 if opts.get('global'):
1608 samplehgrc = uimod.samplehgrcs['global']
1608 samplehgrc = uimod.samplehgrcs['global']
1609 elif opts.get('local'):
1609 elif opts.get('local'):
1610 samplehgrc = uimod.samplehgrcs['local']
1610 samplehgrc = uimod.samplehgrcs['local']
1611 else:
1611 else:
1612 samplehgrc = uimod.samplehgrcs['user']
1612 samplehgrc = uimod.samplehgrcs['user']
1613
1613
1614 f = paths[0]
1614 f = paths[0]
1615 fp = open(f, "w")
1615 fp = open(f, "w")
1616 fp.write(samplehgrc)
1616 fp.write(samplehgrc)
1617 fp.close()
1617 fp.close()
1618
1618
1619 editor = ui.geteditor()
1619 editor = ui.geteditor()
1620 ui.system("%s \"%s\"" % (editor, f),
1620 ui.system("%s \"%s\"" % (editor, f),
1621 onerr=util.Abort, errprefix=_("edit failed"))
1621 onerr=util.Abort, errprefix=_("edit failed"))
1622 return
1622 return
1623
1623
1624 for f in scmutil.rcpath():
1624 for f in scmutil.rcpath():
1625 ui.debug('read config from: %s\n' % f)
1625 ui.debug('read config from: %s\n' % f)
1626 untrusted = bool(opts.get('untrusted'))
1626 untrusted = bool(opts.get('untrusted'))
1627 if values:
1627 if values:
1628 sections = [v for v in values if '.' not in v]
1628 sections = [v for v in values if '.' not in v]
1629 items = [v for v in values if '.' in v]
1629 items = [v for v in values if '.' in v]
1630 if len(items) > 1 or items and sections:
1630 if len(items) > 1 or items and sections:
1631 raise util.Abort(_('only one config item permitted'))
1631 raise util.Abort(_('only one config item permitted'))
1632 matched = False
1632 matched = False
1633 for section, name, value in ui.walkconfig(untrusted=untrusted):
1633 for section, name, value in ui.walkconfig(untrusted=untrusted):
1634 value = str(value).replace('\n', '\\n')
1634 value = str(value).replace('\n', '\\n')
1635 sectname = section + '.' + name
1635 sectname = section + '.' + name
1636 if values:
1636 if values:
1637 for v in values:
1637 for v in values:
1638 if v == section:
1638 if v == section:
1639 ui.debug('%s: ' %
1639 ui.debug('%s: ' %
1640 ui.configsource(section, name, untrusted))
1640 ui.configsource(section, name, untrusted))
1641 ui.write('%s=%s\n' % (sectname, value))
1641 ui.write('%s=%s\n' % (sectname, value))
1642 matched = True
1642 matched = True
1643 elif v == sectname:
1643 elif v == sectname:
1644 ui.debug('%s: ' %
1644 ui.debug('%s: ' %
1645 ui.configsource(section, name, untrusted))
1645 ui.configsource(section, name, untrusted))
1646 ui.write(value, '\n')
1646 ui.write(value, '\n')
1647 matched = True
1647 matched = True
1648 else:
1648 else:
1649 ui.debug('%s: ' %
1649 ui.debug('%s: ' %
1650 ui.configsource(section, name, untrusted))
1650 ui.configsource(section, name, untrusted))
1651 ui.write('%s=%s\n' % (sectname, value))
1651 ui.write('%s=%s\n' % (sectname, value))
1652 matched = True
1652 matched = True
1653 if matched:
1653 if matched:
1654 return 0
1654 return 0
1655 return 1
1655 return 1
1656
1656
1657 @command('copy|cp',
1657 @command('copy|cp',
1658 [('A', 'after', None, _('record a copy that has already occurred')),
1658 [('A', 'after', None, _('record a copy that has already occurred')),
1659 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1659 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1660 ] + walkopts + dryrunopts,
1660 ] + walkopts + dryrunopts,
1661 _('[OPTION]... [SOURCE]... DEST'))
1661 _('[OPTION]... [SOURCE]... DEST'))
1662 def copy(ui, repo, *pats, **opts):
1662 def copy(ui, repo, *pats, **opts):
1663 """mark files as copied for the next commit
1663 """mark files as copied for the next commit
1664
1664
1665 Mark dest as having copies of source files. If dest is a
1665 Mark dest as having copies of source files. If dest is a
1666 directory, copies are put in that directory. If dest is a file,
1666 directory, copies are put in that directory. If dest is a file,
1667 the source must be a single file.
1667 the source must be a single file.
1668
1668
1669 By default, this command copies the contents of files as they
1669 By default, this command copies the contents of files as they
1670 exist in the working directory. If invoked with -A/--after, the
1670 exist in the working directory. If invoked with -A/--after, the
1671 operation is recorded, but no copying is performed.
1671 operation is recorded, but no copying is performed.
1672
1672
1673 This command takes effect with the next commit. To undo a copy
1673 This command takes effect with the next commit. To undo a copy
1674 before that, see :hg:`revert`.
1674 before that, see :hg:`revert`.
1675
1675
1676 Returns 0 on success, 1 if errors are encountered.
1676 Returns 0 on success, 1 if errors are encountered.
1677 """
1677 """
1678 wlock = repo.wlock(False)
1678 wlock = repo.wlock(False)
1679 try:
1679 try:
1680 return cmdutil.copy(ui, repo, pats, opts)
1680 return cmdutil.copy(ui, repo, pats, opts)
1681 finally:
1681 finally:
1682 wlock.release()
1682 wlock.release()
1683
1683
1684 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1684 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1685 def debugancestor(ui, repo, *args):
1685 def debugancestor(ui, repo, *args):
1686 """find the ancestor revision of two revisions in a given index"""
1686 """find the ancestor revision of two revisions in a given index"""
1687 if len(args) == 3:
1687 if len(args) == 3:
1688 index, rev1, rev2 = args
1688 index, rev1, rev2 = args
1689 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1689 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1690 lookup = r.lookup
1690 lookup = r.lookup
1691 elif len(args) == 2:
1691 elif len(args) == 2:
1692 if not repo:
1692 if not repo:
1693 raise util.Abort(_("there is no Mercurial repository here "
1693 raise util.Abort(_("there is no Mercurial repository here "
1694 "(.hg not found)"))
1694 "(.hg not found)"))
1695 rev1, rev2 = args
1695 rev1, rev2 = args
1696 r = repo.changelog
1696 r = repo.changelog
1697 lookup = repo.lookup
1697 lookup = repo.lookup
1698 else:
1698 else:
1699 raise util.Abort(_('either two or three arguments required'))
1699 raise util.Abort(_('either two or three arguments required'))
1700 a = r.ancestor(lookup(rev1), lookup(rev2))
1700 a = r.ancestor(lookup(rev1), lookup(rev2))
1701 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1701 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1702
1702
1703 @command('debugbuilddag',
1703 @command('debugbuilddag',
1704 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1704 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1705 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1705 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1706 ('n', 'new-file', None, _('add new file at each rev'))],
1706 ('n', 'new-file', None, _('add new file at each rev'))],
1707 _('[OPTION]... [TEXT]'))
1707 _('[OPTION]... [TEXT]'))
1708 def debugbuilddag(ui, repo, text=None,
1708 def debugbuilddag(ui, repo, text=None,
1709 mergeable_file=False,
1709 mergeable_file=False,
1710 overwritten_file=False,
1710 overwritten_file=False,
1711 new_file=False):
1711 new_file=False):
1712 """builds a repo with a given DAG from scratch in the current empty repo
1712 """builds a repo with a given DAG from scratch in the current empty repo
1713
1713
1714 The description of the DAG is read from stdin if not given on the
1714 The description of the DAG is read from stdin if not given on the
1715 command line.
1715 command line.
1716
1716
1717 Elements:
1717 Elements:
1718
1718
1719 - "+n" is a linear run of n nodes based on the current default parent
1719 - "+n" is a linear run of n nodes based on the current default parent
1720 - "." is a single node based on the current default parent
1720 - "." is a single node based on the current default parent
1721 - "$" resets the default parent to null (implied at the start);
1721 - "$" resets the default parent to null (implied at the start);
1722 otherwise the default parent is always the last node created
1722 otherwise the default parent is always the last node created
1723 - "<p" sets the default parent to the backref p
1723 - "<p" sets the default parent to the backref p
1724 - "*p" is a fork at parent p, which is a backref
1724 - "*p" is a fork at parent p, which is a backref
1725 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1725 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1726 - "/p2" is a merge of the preceding node and p2
1726 - "/p2" is a merge of the preceding node and p2
1727 - ":tag" defines a local tag for the preceding node
1727 - ":tag" defines a local tag for the preceding node
1728 - "@branch" sets the named branch for subsequent nodes
1728 - "@branch" sets the named branch for subsequent nodes
1729 - "#...\\n" is a comment up to the end of the line
1729 - "#...\\n" is a comment up to the end of the line
1730
1730
1731 Whitespace between the above elements is ignored.
1731 Whitespace between the above elements is ignored.
1732
1732
1733 A backref is either
1733 A backref is either
1734
1734
1735 - a number n, which references the node curr-n, where curr is the current
1735 - a number n, which references the node curr-n, where curr is the current
1736 node, or
1736 node, or
1737 - the name of a local tag you placed earlier using ":tag", or
1737 - the name of a local tag you placed earlier using ":tag", or
1738 - empty to denote the default parent.
1738 - empty to denote the default parent.
1739
1739
1740 All string valued-elements are either strictly alphanumeric, or must
1740 All string valued-elements are either strictly alphanumeric, or must
1741 be enclosed in double quotes ("..."), with "\\" as escape character.
1741 be enclosed in double quotes ("..."), with "\\" as escape character.
1742 """
1742 """
1743
1743
1744 if text is None:
1744 if text is None:
1745 ui.status(_("reading DAG from stdin\n"))
1745 ui.status(_("reading DAG from stdin\n"))
1746 text = ui.fin.read()
1746 text = ui.fin.read()
1747
1747
1748 cl = repo.changelog
1748 cl = repo.changelog
1749 if len(cl) > 0:
1749 if len(cl) > 0:
1750 raise util.Abort(_('repository is not empty'))
1750 raise util.Abort(_('repository is not empty'))
1751
1751
1752 # determine number of revs in DAG
1752 # determine number of revs in DAG
1753 total = 0
1753 total = 0
1754 for type, data in dagparser.parsedag(text):
1754 for type, data in dagparser.parsedag(text):
1755 if type == 'n':
1755 if type == 'n':
1756 total += 1
1756 total += 1
1757
1757
1758 if mergeable_file:
1758 if mergeable_file:
1759 linesperrev = 2
1759 linesperrev = 2
1760 # make a file with k lines per rev
1760 # make a file with k lines per rev
1761 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1761 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1762 initialmergedlines.append("")
1762 initialmergedlines.append("")
1763
1763
1764 tags = []
1764 tags = []
1765
1765
1766 lock = tr = None
1766 lock = tr = None
1767 try:
1767 try:
1768 lock = repo.lock()
1768 lock = repo.lock()
1769 tr = repo.transaction("builddag")
1769 tr = repo.transaction("builddag")
1770
1770
1771 at = -1
1771 at = -1
1772 atbranch = 'default'
1772 atbranch = 'default'
1773 nodeids = []
1773 nodeids = []
1774 id = 0
1774 id = 0
1775 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1775 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1776 for type, data in dagparser.parsedag(text):
1776 for type, data in dagparser.parsedag(text):
1777 if type == 'n':
1777 if type == 'n':
1778 ui.note(('node %s\n' % str(data)))
1778 ui.note(('node %s\n' % str(data)))
1779 id, ps = data
1779 id, ps = data
1780
1780
1781 files = []
1781 files = []
1782 fctxs = {}
1782 fctxs = {}
1783
1783
1784 p2 = None
1784 p2 = None
1785 if mergeable_file:
1785 if mergeable_file:
1786 fn = "mf"
1786 fn = "mf"
1787 p1 = repo[ps[0]]
1787 p1 = repo[ps[0]]
1788 if len(ps) > 1:
1788 if len(ps) > 1:
1789 p2 = repo[ps[1]]
1789 p2 = repo[ps[1]]
1790 pa = p1.ancestor(p2)
1790 pa = p1.ancestor(p2)
1791 base, local, other = [x[fn].data() for x in (pa, p1,
1791 base, local, other = [x[fn].data() for x in (pa, p1,
1792 p2)]
1792 p2)]
1793 m3 = simplemerge.Merge3Text(base, local, other)
1793 m3 = simplemerge.Merge3Text(base, local, other)
1794 ml = [l.strip() for l in m3.merge_lines()]
1794 ml = [l.strip() for l in m3.merge_lines()]
1795 ml.append("")
1795 ml.append("")
1796 elif at > 0:
1796 elif at > 0:
1797 ml = p1[fn].data().split("\n")
1797 ml = p1[fn].data().split("\n")
1798 else:
1798 else:
1799 ml = initialmergedlines
1799 ml = initialmergedlines
1800 ml[id * linesperrev] += " r%i" % id
1800 ml[id * linesperrev] += " r%i" % id
1801 mergedtext = "\n".join(ml)
1801 mergedtext = "\n".join(ml)
1802 files.append(fn)
1802 files.append(fn)
1803 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1803 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1804
1804
1805 if overwritten_file:
1805 if overwritten_file:
1806 fn = "of"
1806 fn = "of"
1807 files.append(fn)
1807 files.append(fn)
1808 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1808 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1809
1809
1810 if new_file:
1810 if new_file:
1811 fn = "nf%i" % id
1811 fn = "nf%i" % id
1812 files.append(fn)
1812 files.append(fn)
1813 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1813 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1814 if len(ps) > 1:
1814 if len(ps) > 1:
1815 if not p2:
1815 if not p2:
1816 p2 = repo[ps[1]]
1816 p2 = repo[ps[1]]
1817 for fn in p2:
1817 for fn in p2:
1818 if fn.startswith("nf"):
1818 if fn.startswith("nf"):
1819 files.append(fn)
1819 files.append(fn)
1820 fctxs[fn] = p2[fn]
1820 fctxs[fn] = p2[fn]
1821
1821
1822 def fctxfn(repo, cx, path):
1822 def fctxfn(repo, cx, path):
1823 return fctxs.get(path)
1823 return fctxs.get(path)
1824
1824
1825 if len(ps) == 0 or ps[0] < 0:
1825 if len(ps) == 0 or ps[0] < 0:
1826 pars = [None, None]
1826 pars = [None, None]
1827 elif len(ps) == 1:
1827 elif len(ps) == 1:
1828 pars = [nodeids[ps[0]], None]
1828 pars = [nodeids[ps[0]], None]
1829 else:
1829 else:
1830 pars = [nodeids[p] for p in ps]
1830 pars = [nodeids[p] for p in ps]
1831 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1831 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1832 date=(id, 0),
1832 date=(id, 0),
1833 user="debugbuilddag",
1833 user="debugbuilddag",
1834 extra={'branch': atbranch})
1834 extra={'branch': atbranch})
1835 nodeid = repo.commitctx(cx)
1835 nodeid = repo.commitctx(cx)
1836 nodeids.append(nodeid)
1836 nodeids.append(nodeid)
1837 at = id
1837 at = id
1838 elif type == 'l':
1838 elif type == 'l':
1839 id, name = data
1839 id, name = data
1840 ui.note(('tag %s\n' % name))
1840 ui.note(('tag %s\n' % name))
1841 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1841 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1842 elif type == 'a':
1842 elif type == 'a':
1843 ui.note(('branch %s\n' % data))
1843 ui.note(('branch %s\n' % data))
1844 atbranch = data
1844 atbranch = data
1845 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1845 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1846 tr.close()
1846 tr.close()
1847
1847
1848 if tags:
1848 if tags:
1849 repo.vfs.write("localtags", "".join(tags))
1849 repo.vfs.write("localtags", "".join(tags))
1850 finally:
1850 finally:
1851 ui.progress(_('building'), None)
1851 ui.progress(_('building'), None)
1852 release(tr, lock)
1852 release(tr, lock)
1853
1853
1854 @command('debugbundle',
1854 @command('debugbundle',
1855 [('a', 'all', None, _('show all details'))],
1855 [('a', 'all', None, _('show all details'))],
1856 _('FILE'),
1856 _('FILE'),
1857 norepo=True)
1857 norepo=True)
1858 def debugbundle(ui, bundlepath, all=None, **opts):
1858 def debugbundle(ui, bundlepath, all=None, **opts):
1859 """lists the contents of a bundle"""
1859 """lists the contents of a bundle"""
1860 f = hg.openpath(ui, bundlepath)
1860 f = hg.openpath(ui, bundlepath)
1861 try:
1861 try:
1862 gen = exchange.readbundle(ui, f, bundlepath)
1862 gen = exchange.readbundle(ui, f, bundlepath)
1863 if isinstance(gen, bundle2.unbundle20):
1863 if isinstance(gen, bundle2.unbundle20):
1864 return _debugbundle2(ui, gen, all=all, **opts)
1864 return _debugbundle2(ui, gen, all=all, **opts)
1865 if all:
1865 if all:
1866 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1866 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1867
1867
1868 def showchunks(named):
1868 def showchunks(named):
1869 ui.write("\n%s\n" % named)
1869 ui.write("\n%s\n" % named)
1870 chain = None
1870 chain = None
1871 while True:
1871 while True:
1872 chunkdata = gen.deltachunk(chain)
1872 chunkdata = gen.deltachunk(chain)
1873 if not chunkdata:
1873 if not chunkdata:
1874 break
1874 break
1875 node = chunkdata['node']
1875 node = chunkdata['node']
1876 p1 = chunkdata['p1']
1876 p1 = chunkdata['p1']
1877 p2 = chunkdata['p2']
1877 p2 = chunkdata['p2']
1878 cs = chunkdata['cs']
1878 cs = chunkdata['cs']
1879 deltabase = chunkdata['deltabase']
1879 deltabase = chunkdata['deltabase']
1880 delta = chunkdata['delta']
1880 delta = chunkdata['delta']
1881 ui.write("%s %s %s %s %s %s\n" %
1881 ui.write("%s %s %s %s %s %s\n" %
1882 (hex(node), hex(p1), hex(p2),
1882 (hex(node), hex(p1), hex(p2),
1883 hex(cs), hex(deltabase), len(delta)))
1883 hex(cs), hex(deltabase), len(delta)))
1884 chain = node
1884 chain = node
1885
1885
1886 chunkdata = gen.changelogheader()
1886 chunkdata = gen.changelogheader()
1887 showchunks("changelog")
1887 showchunks("changelog")
1888 chunkdata = gen.manifestheader()
1888 chunkdata = gen.manifestheader()
1889 showchunks("manifest")
1889 showchunks("manifest")
1890 while True:
1890 while True:
1891 chunkdata = gen.filelogheader()
1891 chunkdata = gen.filelogheader()
1892 if not chunkdata:
1892 if not chunkdata:
1893 break
1893 break
1894 fname = chunkdata['filename']
1894 fname = chunkdata['filename']
1895 showchunks(fname)
1895 showchunks(fname)
1896 else:
1896 else:
1897 if isinstance(gen, bundle2.unbundle20):
1897 if isinstance(gen, bundle2.unbundle20):
1898 raise util.Abort(_('use debugbundle2 for this file'))
1898 raise util.Abort(_('use debugbundle2 for this file'))
1899 chunkdata = gen.changelogheader()
1899 chunkdata = gen.changelogheader()
1900 chain = None
1900 chain = None
1901 while True:
1901 while True:
1902 chunkdata = gen.deltachunk(chain)
1902 chunkdata = gen.deltachunk(chain)
1903 if not chunkdata:
1903 if not chunkdata:
1904 break
1904 break
1905 node = chunkdata['node']
1905 node = chunkdata['node']
1906 ui.write("%s\n" % hex(node))
1906 ui.write("%s\n" % hex(node))
1907 chain = node
1907 chain = node
1908 finally:
1908 finally:
1909 f.close()
1909 f.close()
1910
1910
1911 def _debugbundle2(ui, gen, **opts):
1911 def _debugbundle2(ui, gen, **opts):
1912 """lists the contents of a bundle2"""
1912 """lists the contents of a bundle2"""
1913 if not isinstance(gen, bundle2.unbundle20):
1913 if not isinstance(gen, bundle2.unbundle20):
1914 raise util.Abort(_('not a bundle2 file'))
1914 raise util.Abort(_('not a bundle2 file'))
1915 ui.write(('Stream params: %s\n' % repr(gen.params)))
1915 ui.write(('Stream params: %s\n' % repr(gen.params)))
1916 for part in gen.iterparts():
1916 for part in gen.iterparts():
1917 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1917 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1918 if part.type == 'changegroup':
1918 if part.type == 'changegroup':
1919 version = part.params.get('version', '01')
1919 version = part.params.get('version', '01')
1920 cg = changegroup.packermap[version][1](part, 'UN')
1920 cg = changegroup.packermap[version][1](part, 'UN')
1921 chunkdata = cg.changelogheader()
1921 chunkdata = cg.changelogheader()
1922 chain = None
1922 chain = None
1923 while True:
1923 while True:
1924 chunkdata = cg.deltachunk(chain)
1924 chunkdata = cg.deltachunk(chain)
1925 if not chunkdata:
1925 if not chunkdata:
1926 break
1926 break
1927 node = chunkdata['node']
1927 node = chunkdata['node']
1928 ui.write(" %s\n" % hex(node))
1928 ui.write(" %s\n" % hex(node))
1929 chain = node
1929 chain = node
1930
1930
1931 @command('debugcheckstate', [], '')
1931 @command('debugcheckstate', [], '')
1932 def debugcheckstate(ui, repo):
1932 def debugcheckstate(ui, repo):
1933 """validate the correctness of the current dirstate"""
1933 """validate the correctness of the current dirstate"""
1934 parent1, parent2 = repo.dirstate.parents()
1934 parent1, parent2 = repo.dirstate.parents()
1935 m1 = repo[parent1].manifest()
1935 m1 = repo[parent1].manifest()
1936 m2 = repo[parent2].manifest()
1936 m2 = repo[parent2].manifest()
1937 errors = 0
1937 errors = 0
1938 for f in repo.dirstate:
1938 for f in repo.dirstate:
1939 state = repo.dirstate[f]
1939 state = repo.dirstate[f]
1940 if state in "nr" and f not in m1:
1940 if state in "nr" and f not in m1:
1941 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1941 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1942 errors += 1
1942 errors += 1
1943 if state in "a" and f in m1:
1943 if state in "a" and f in m1:
1944 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1944 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1945 errors += 1
1945 errors += 1
1946 if state in "m" and f not in m1 and f not in m2:
1946 if state in "m" and f not in m1 and f not in m2:
1947 ui.warn(_("%s in state %s, but not in either manifest\n") %
1947 ui.warn(_("%s in state %s, but not in either manifest\n") %
1948 (f, state))
1948 (f, state))
1949 errors += 1
1949 errors += 1
1950 for f in m1:
1950 for f in m1:
1951 state = repo.dirstate[f]
1951 state = repo.dirstate[f]
1952 if state not in "nrm":
1952 if state not in "nrm":
1953 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1953 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1954 errors += 1
1954 errors += 1
1955 if errors:
1955 if errors:
1956 error = _(".hg/dirstate inconsistent with current parent's manifest")
1956 error = _(".hg/dirstate inconsistent with current parent's manifest")
1957 raise util.Abort(error)
1957 raise util.Abort(error)
1958
1958
1959 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1959 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1960 def debugcommands(ui, cmd='', *args):
1960 def debugcommands(ui, cmd='', *args):
1961 """list all available commands and options"""
1961 """list all available commands and options"""
1962 for cmd, vals in sorted(table.iteritems()):
1962 for cmd, vals in sorted(table.iteritems()):
1963 cmd = cmd.split('|')[0].strip('^')
1963 cmd = cmd.split('|')[0].strip('^')
1964 opts = ', '.join([i[1] for i in vals[1]])
1964 opts = ', '.join([i[1] for i in vals[1]])
1965 ui.write('%s: %s\n' % (cmd, opts))
1965 ui.write('%s: %s\n' % (cmd, opts))
1966
1966
1967 @command('debugcomplete',
1967 @command('debugcomplete',
1968 [('o', 'options', None, _('show the command options'))],
1968 [('o', 'options', None, _('show the command options'))],
1969 _('[-o] CMD'),
1969 _('[-o] CMD'),
1970 norepo=True)
1970 norepo=True)
1971 def debugcomplete(ui, cmd='', **opts):
1971 def debugcomplete(ui, cmd='', **opts):
1972 """returns the completion list associated with the given command"""
1972 """returns the completion list associated with the given command"""
1973
1973
1974 if opts.get('options'):
1974 if opts.get('options'):
1975 options = []
1975 options = []
1976 otables = [globalopts]
1976 otables = [globalopts]
1977 if cmd:
1977 if cmd:
1978 aliases, entry = cmdutil.findcmd(cmd, table, False)
1978 aliases, entry = cmdutil.findcmd(cmd, table, False)
1979 otables.append(entry[1])
1979 otables.append(entry[1])
1980 for t in otables:
1980 for t in otables:
1981 for o in t:
1981 for o in t:
1982 if "(DEPRECATED)" in o[3]:
1982 if "(DEPRECATED)" in o[3]:
1983 continue
1983 continue
1984 if o[0]:
1984 if o[0]:
1985 options.append('-%s' % o[0])
1985 options.append('-%s' % o[0])
1986 options.append('--%s' % o[1])
1986 options.append('--%s' % o[1])
1987 ui.write("%s\n" % "\n".join(options))
1987 ui.write("%s\n" % "\n".join(options))
1988 return
1988 return
1989
1989
1990 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1990 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1991 if ui.verbose:
1991 if ui.verbose:
1992 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1992 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1993 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1993 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1994
1994
1995 @command('debugdag',
1995 @command('debugdag',
1996 [('t', 'tags', None, _('use tags as labels')),
1996 [('t', 'tags', None, _('use tags as labels')),
1997 ('b', 'branches', None, _('annotate with branch names')),
1997 ('b', 'branches', None, _('annotate with branch names')),
1998 ('', 'dots', None, _('use dots for runs')),
1998 ('', 'dots', None, _('use dots for runs')),
1999 ('s', 'spaces', None, _('separate elements by spaces'))],
1999 ('s', 'spaces', None, _('separate elements by spaces'))],
2000 _('[OPTION]... [FILE [REV]...]'),
2000 _('[OPTION]... [FILE [REV]...]'),
2001 optionalrepo=True)
2001 optionalrepo=True)
2002 def debugdag(ui, repo, file_=None, *revs, **opts):
2002 def debugdag(ui, repo, file_=None, *revs, **opts):
2003 """format the changelog or an index DAG as a concise textual description
2003 """format the changelog or an index DAG as a concise textual description
2004
2004
2005 If you pass a revlog index, the revlog's DAG is emitted. If you list
2005 If you pass a revlog index, the revlog's DAG is emitted. If you list
2006 revision numbers, they get labeled in the output as rN.
2006 revision numbers, they get labeled in the output as rN.
2007
2007
2008 Otherwise, the changelog DAG of the current repo is emitted.
2008 Otherwise, the changelog DAG of the current repo is emitted.
2009 """
2009 """
2010 spaces = opts.get('spaces')
2010 spaces = opts.get('spaces')
2011 dots = opts.get('dots')
2011 dots = opts.get('dots')
2012 if file_:
2012 if file_:
2013 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2013 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2014 revs = set((int(r) for r in revs))
2014 revs = set((int(r) for r in revs))
2015 def events():
2015 def events():
2016 for r in rlog:
2016 for r in rlog:
2017 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2017 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2018 if p != -1))
2018 if p != -1))
2019 if r in revs:
2019 if r in revs:
2020 yield 'l', (r, "r%i" % r)
2020 yield 'l', (r, "r%i" % r)
2021 elif repo:
2021 elif repo:
2022 cl = repo.changelog
2022 cl = repo.changelog
2023 tags = opts.get('tags')
2023 tags = opts.get('tags')
2024 branches = opts.get('branches')
2024 branches = opts.get('branches')
2025 if tags:
2025 if tags:
2026 labels = {}
2026 labels = {}
2027 for l, n in repo.tags().items():
2027 for l, n in repo.tags().items():
2028 labels.setdefault(cl.rev(n), []).append(l)
2028 labels.setdefault(cl.rev(n), []).append(l)
2029 def events():
2029 def events():
2030 b = "default"
2030 b = "default"
2031 for r in cl:
2031 for r in cl:
2032 if branches:
2032 if branches:
2033 newb = cl.read(cl.node(r))[5]['branch']
2033 newb = cl.read(cl.node(r))[5]['branch']
2034 if newb != b:
2034 if newb != b:
2035 yield 'a', newb
2035 yield 'a', newb
2036 b = newb
2036 b = newb
2037 yield 'n', (r, list(p for p in cl.parentrevs(r)
2037 yield 'n', (r, list(p for p in cl.parentrevs(r)
2038 if p != -1))
2038 if p != -1))
2039 if tags:
2039 if tags:
2040 ls = labels.get(r)
2040 ls = labels.get(r)
2041 if ls:
2041 if ls:
2042 for l in ls:
2042 for l in ls:
2043 yield 'l', (r, l)
2043 yield 'l', (r, l)
2044 else:
2044 else:
2045 raise util.Abort(_('need repo for changelog dag'))
2045 raise util.Abort(_('need repo for changelog dag'))
2046
2046
2047 for line in dagparser.dagtextlines(events(),
2047 for line in dagparser.dagtextlines(events(),
2048 addspaces=spaces,
2048 addspaces=spaces,
2049 wraplabels=True,
2049 wraplabels=True,
2050 wrapannotations=True,
2050 wrapannotations=True,
2051 wrapnonlinear=dots,
2051 wrapnonlinear=dots,
2052 usedots=dots,
2052 usedots=dots,
2053 maxlinewidth=70):
2053 maxlinewidth=70):
2054 ui.write(line)
2054 ui.write(line)
2055 ui.write("\n")
2055 ui.write("\n")
2056
2056
2057 @command('debugdata',
2057 @command('debugdata',
2058 [('c', 'changelog', False, _('open changelog')),
2058 [('c', 'changelog', False, _('open changelog')),
2059 ('m', 'manifest', False, _('open manifest'))],
2059 ('m', 'manifest', False, _('open manifest'))],
2060 _('-c|-m|FILE REV'))
2060 _('-c|-m|FILE REV'))
2061 def debugdata(ui, repo, file_, rev=None, **opts):
2061 def debugdata(ui, repo, file_, rev=None, **opts):
2062 """dump the contents of a data file revision"""
2062 """dump the contents of a data file revision"""
2063 if opts.get('changelog') or opts.get('manifest'):
2063 if opts.get('changelog') or opts.get('manifest'):
2064 file_, rev = None, file_
2064 file_, rev = None, file_
2065 elif rev is None:
2065 elif rev is None:
2066 raise error.CommandError('debugdata', _('invalid arguments'))
2066 raise error.CommandError('debugdata', _('invalid arguments'))
2067 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2067 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2068 try:
2068 try:
2069 ui.write(r.revision(r.lookup(rev)))
2069 ui.write(r.revision(r.lookup(rev)))
2070 except KeyError:
2070 except KeyError:
2071 raise util.Abort(_('invalid revision identifier %s') % rev)
2071 raise util.Abort(_('invalid revision identifier %s') % rev)
2072
2072
2073 @command('debugdate',
2073 @command('debugdate',
2074 [('e', 'extended', None, _('try extended date formats'))],
2074 [('e', 'extended', None, _('try extended date formats'))],
2075 _('[-e] DATE [RANGE]'),
2075 _('[-e] DATE [RANGE]'),
2076 norepo=True, optionalrepo=True)
2076 norepo=True, optionalrepo=True)
2077 def debugdate(ui, date, range=None, **opts):
2077 def debugdate(ui, date, range=None, **opts):
2078 """parse and display a date"""
2078 """parse and display a date"""
2079 if opts["extended"]:
2079 if opts["extended"]:
2080 d = util.parsedate(date, util.extendeddateformats)
2080 d = util.parsedate(date, util.extendeddateformats)
2081 else:
2081 else:
2082 d = util.parsedate(date)
2082 d = util.parsedate(date)
2083 ui.write(("internal: %s %s\n") % d)
2083 ui.write(("internal: %s %s\n") % d)
2084 ui.write(("standard: %s\n") % util.datestr(d))
2084 ui.write(("standard: %s\n") % util.datestr(d))
2085 if range:
2085 if range:
2086 m = util.matchdate(range)
2086 m = util.matchdate(range)
2087 ui.write(("match: %s\n") % m(d[0]))
2087 ui.write(("match: %s\n") % m(d[0]))
2088
2088
2089 @command('debugdiscovery',
2089 @command('debugdiscovery',
2090 [('', 'old', None, _('use old-style discovery')),
2090 [('', 'old', None, _('use old-style discovery')),
2091 ('', 'nonheads', None,
2091 ('', 'nonheads', None,
2092 _('use old-style discovery with non-heads included')),
2092 _('use old-style discovery with non-heads included')),
2093 ] + remoteopts,
2093 ] + remoteopts,
2094 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2094 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2095 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2095 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2096 """runs the changeset discovery protocol in isolation"""
2096 """runs the changeset discovery protocol in isolation"""
2097 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2097 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2098 opts.get('branch'))
2098 opts.get('branch'))
2099 remote = hg.peer(repo, opts, remoteurl)
2099 remote = hg.peer(repo, opts, remoteurl)
2100 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2100 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2101
2101
2102 # make sure tests are repeatable
2102 # make sure tests are repeatable
2103 random.seed(12323)
2103 random.seed(12323)
2104
2104
2105 def doit(localheads, remoteheads, remote=remote):
2105 def doit(localheads, remoteheads, remote=remote):
2106 if opts.get('old'):
2106 if opts.get('old'):
2107 if localheads:
2107 if localheads:
2108 raise util.Abort('cannot use localheads with old style '
2108 raise util.Abort('cannot use localheads with old style '
2109 'discovery')
2109 'discovery')
2110 if not util.safehasattr(remote, 'branches'):
2110 if not util.safehasattr(remote, 'branches'):
2111 # enable in-client legacy support
2111 # enable in-client legacy support
2112 remote = localrepo.locallegacypeer(remote.local())
2112 remote = localrepo.locallegacypeer(remote.local())
2113 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2113 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2114 force=True)
2114 force=True)
2115 common = set(common)
2115 common = set(common)
2116 if not opts.get('nonheads'):
2116 if not opts.get('nonheads'):
2117 ui.write(("unpruned common: %s\n") %
2117 ui.write(("unpruned common: %s\n") %
2118 " ".join(sorted(short(n) for n in common)))
2118 " ".join(sorted(short(n) for n in common)))
2119 dag = dagutil.revlogdag(repo.changelog)
2119 dag = dagutil.revlogdag(repo.changelog)
2120 all = dag.ancestorset(dag.internalizeall(common))
2120 all = dag.ancestorset(dag.internalizeall(common))
2121 common = dag.externalizeall(dag.headsetofconnecteds(all))
2121 common = dag.externalizeall(dag.headsetofconnecteds(all))
2122 else:
2122 else:
2123 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2123 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2124 common = set(common)
2124 common = set(common)
2125 rheads = set(hds)
2125 rheads = set(hds)
2126 lheads = set(repo.heads())
2126 lheads = set(repo.heads())
2127 ui.write(("common heads: %s\n") %
2127 ui.write(("common heads: %s\n") %
2128 " ".join(sorted(short(n) for n in common)))
2128 " ".join(sorted(short(n) for n in common)))
2129 if lheads <= common:
2129 if lheads <= common:
2130 ui.write(("local is subset\n"))
2130 ui.write(("local is subset\n"))
2131 elif rheads <= common:
2131 elif rheads <= common:
2132 ui.write(("remote is subset\n"))
2132 ui.write(("remote is subset\n"))
2133
2133
2134 serverlogs = opts.get('serverlog')
2134 serverlogs = opts.get('serverlog')
2135 if serverlogs:
2135 if serverlogs:
2136 for filename in serverlogs:
2136 for filename in serverlogs:
2137 logfile = open(filename, 'r')
2137 logfile = open(filename, 'r')
2138 try:
2138 try:
2139 line = logfile.readline()
2139 line = logfile.readline()
2140 while line:
2140 while line:
2141 parts = line.strip().split(';')
2141 parts = line.strip().split(';')
2142 op = parts[1]
2142 op = parts[1]
2143 if op == 'cg':
2143 if op == 'cg':
2144 pass
2144 pass
2145 elif op == 'cgss':
2145 elif op == 'cgss':
2146 doit(parts[2].split(' '), parts[3].split(' '))
2146 doit(parts[2].split(' '), parts[3].split(' '))
2147 elif op == 'unb':
2147 elif op == 'unb':
2148 doit(parts[3].split(' '), parts[2].split(' '))
2148 doit(parts[3].split(' '), parts[2].split(' '))
2149 line = logfile.readline()
2149 line = logfile.readline()
2150 finally:
2150 finally:
2151 logfile.close()
2151 logfile.close()
2152
2152
2153 else:
2153 else:
2154 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2154 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2155 opts.get('remote_head'))
2155 opts.get('remote_head'))
2156 localrevs = opts.get('local_head')
2156 localrevs = opts.get('local_head')
2157 doit(localrevs, remoterevs)
2157 doit(localrevs, remoterevs)
2158
2158
2159 @command('debugfileset',
2159 @command('debugfileset',
2160 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2160 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2161 _('[-r REV] FILESPEC'))
2161 _('[-r REV] FILESPEC'))
2162 def debugfileset(ui, repo, expr, **opts):
2162 def debugfileset(ui, repo, expr, **opts):
2163 '''parse and apply a fileset specification'''
2163 '''parse and apply a fileset specification'''
2164 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2164 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2165 if ui.verbose:
2165 if ui.verbose:
2166 tree = fileset.parse(expr)[0]
2166 tree = fileset.parse(expr)[0]
2167 ui.note(tree, "\n")
2167 ui.note(tree, "\n")
2168
2168
2169 for f in ctx.getfileset(expr):
2169 for f in ctx.getfileset(expr):
2170 ui.write("%s\n" % f)
2170 ui.write("%s\n" % f)
2171
2171
2172 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2172 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2173 def debugfsinfo(ui, path="."):
2173 def debugfsinfo(ui, path="."):
2174 """show information detected about current filesystem"""
2174 """show information detected about current filesystem"""
2175 util.writefile('.debugfsinfo', '')
2175 util.writefile('.debugfsinfo', '')
2176 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2176 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2177 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2177 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2178 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2178 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2179 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2179 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2180 and 'yes' or 'no'))
2180 and 'yes' or 'no'))
2181 os.unlink('.debugfsinfo')
2181 os.unlink('.debugfsinfo')
2182
2182
2183 @command('debuggetbundle',
2183 @command('debuggetbundle',
2184 [('H', 'head', [], _('id of head node'), _('ID')),
2184 [('H', 'head', [], _('id of head node'), _('ID')),
2185 ('C', 'common', [], _('id of common node'), _('ID')),
2185 ('C', 'common', [], _('id of common node'), _('ID')),
2186 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2186 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2187 _('REPO FILE [-H|-C ID]...'),
2187 _('REPO FILE [-H|-C ID]...'),
2188 norepo=True)
2188 norepo=True)
2189 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2189 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2190 """retrieves a bundle from a repo
2190 """retrieves a bundle from a repo
2191
2191
2192 Every ID must be a full-length hex node id string. Saves the bundle to the
2192 Every ID must be a full-length hex node id string. Saves the bundle to the
2193 given file.
2193 given file.
2194 """
2194 """
2195 repo = hg.peer(ui, opts, repopath)
2195 repo = hg.peer(ui, opts, repopath)
2196 if not repo.capable('getbundle'):
2196 if not repo.capable('getbundle'):
2197 raise util.Abort("getbundle() not supported by target repository")
2197 raise util.Abort("getbundle() not supported by target repository")
2198 args = {}
2198 args = {}
2199 if common:
2199 if common:
2200 args['common'] = [bin(s) for s in common]
2200 args['common'] = [bin(s) for s in common]
2201 if head:
2201 if head:
2202 args['heads'] = [bin(s) for s in head]
2202 args['heads'] = [bin(s) for s in head]
2203 # TODO: get desired bundlecaps from command line.
2203 # TODO: get desired bundlecaps from command line.
2204 args['bundlecaps'] = None
2204 args['bundlecaps'] = None
2205 bundle = repo.getbundle('debug', **args)
2205 bundle = repo.getbundle('debug', **args)
2206
2206
2207 bundletype = opts.get('type', 'bzip2').lower()
2207 bundletype = opts.get('type', 'bzip2').lower()
2208 btypes = {'none': 'HG10UN',
2208 btypes = {'none': 'HG10UN',
2209 'bzip2': 'HG10BZ',
2209 'bzip2': 'HG10BZ',
2210 'gzip': 'HG10GZ',
2210 'gzip': 'HG10GZ',
2211 'bundle2': 'HG20'}
2211 'bundle2': 'HG20'}
2212 bundletype = btypes.get(bundletype)
2212 bundletype = btypes.get(bundletype)
2213 if bundletype not in changegroup.bundletypes:
2213 if bundletype not in changegroup.bundletypes:
2214 raise util.Abort(_('unknown bundle type specified with --type'))
2214 raise util.Abort(_('unknown bundle type specified with --type'))
2215 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2215 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2216
2216
2217 @command('debugignore', [], '')
2217 @command('debugignore', [], '')
2218 def debugignore(ui, repo, *values, **opts):
2218 def debugignore(ui, repo, *values, **opts):
2219 """display the combined ignore pattern"""
2219 """display the combined ignore pattern"""
2220 ignore = repo.dirstate._ignore
2220 ignore = repo.dirstate._ignore
2221 includepat = getattr(ignore, 'includepat', None)
2221 includepat = getattr(ignore, 'includepat', None)
2222 if includepat is not None:
2222 if includepat is not None:
2223 ui.write("%s\n" % includepat)
2223 ui.write("%s\n" % includepat)
2224 else:
2224 else:
2225 raise util.Abort(_("no ignore patterns found"))
2225 raise util.Abort(_("no ignore patterns found"))
2226
2226
2227 @command('debugindex',
2227 @command('debugindex',
2228 [('c', 'changelog', False, _('open changelog')),
2228 [('c', 'changelog', False, _('open changelog')),
2229 ('m', 'manifest', False, _('open manifest')),
2229 ('m', 'manifest', False, _('open manifest')),
2230 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2230 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2231 _('[-f FORMAT] -c|-m|FILE'),
2231 _('[-f FORMAT] -c|-m|FILE'),
2232 optionalrepo=True)
2232 optionalrepo=True)
2233 def debugindex(ui, repo, file_=None, **opts):
2233 def debugindex(ui, repo, file_=None, **opts):
2234 """dump the contents of an index file"""
2234 """dump the contents of an index file"""
2235 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2235 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2236 format = opts.get('format', 0)
2236 format = opts.get('format', 0)
2237 if format not in (0, 1):
2237 if format not in (0, 1):
2238 raise util.Abort(_("unknown format %d") % format)
2238 raise util.Abort(_("unknown format %d") % format)
2239
2239
2240 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2240 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2241 if generaldelta:
2241 if generaldelta:
2242 basehdr = ' delta'
2242 basehdr = ' delta'
2243 else:
2243 else:
2244 basehdr = ' base'
2244 basehdr = ' base'
2245
2245
2246 if ui.debugflag:
2246 if ui.debugflag:
2247 shortfn = hex
2247 shortfn = hex
2248 else:
2248 else:
2249 shortfn = short
2249 shortfn = short
2250
2250
2251 # There might not be anything in r, so have a sane default
2251 # There might not be anything in r, so have a sane default
2252 idlen = 12
2252 idlen = 12
2253 for i in r:
2253 for i in r:
2254 idlen = len(shortfn(r.node(i)))
2254 idlen = len(shortfn(r.node(i)))
2255 break
2255 break
2256
2256
2257 if format == 0:
2257 if format == 0:
2258 ui.write(" rev offset length " + basehdr + " linkrev"
2258 ui.write(" rev offset length " + basehdr + " linkrev"
2259 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2259 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2260 elif format == 1:
2260 elif format == 1:
2261 ui.write(" rev flag offset length"
2261 ui.write(" rev flag offset length"
2262 " size " + basehdr + " link p1 p2"
2262 " size " + basehdr + " link p1 p2"
2263 " %s\n" % "nodeid".rjust(idlen))
2263 " %s\n" % "nodeid".rjust(idlen))
2264
2264
2265 for i in r:
2265 for i in r:
2266 node = r.node(i)
2266 node = r.node(i)
2267 if generaldelta:
2267 if generaldelta:
2268 base = r.deltaparent(i)
2268 base = r.deltaparent(i)
2269 else:
2269 else:
2270 base = r.chainbase(i)
2270 base = r.chainbase(i)
2271 if format == 0:
2271 if format == 0:
2272 try:
2272 try:
2273 pp = r.parents(node)
2273 pp = r.parents(node)
2274 except Exception:
2274 except Exception:
2275 pp = [nullid, nullid]
2275 pp = [nullid, nullid]
2276 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2276 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2277 i, r.start(i), r.length(i), base, r.linkrev(i),
2277 i, r.start(i), r.length(i), base, r.linkrev(i),
2278 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2278 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2279 elif format == 1:
2279 elif format == 1:
2280 pr = r.parentrevs(i)
2280 pr = r.parentrevs(i)
2281 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2281 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2282 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2282 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2283 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2283 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2284
2284
2285 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2285 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2286 def debugindexdot(ui, repo, file_):
2286 def debugindexdot(ui, repo, file_):
2287 """dump an index DAG as a graphviz dot file"""
2287 """dump an index DAG as a graphviz dot file"""
2288 r = None
2288 r = None
2289 if repo:
2289 if repo:
2290 filelog = repo.file(file_)
2290 filelog = repo.file(file_)
2291 if len(filelog):
2291 if len(filelog):
2292 r = filelog
2292 r = filelog
2293 if not r:
2293 if not r:
2294 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2294 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2295 ui.write(("digraph G {\n"))
2295 ui.write(("digraph G {\n"))
2296 for i in r:
2296 for i in r:
2297 node = r.node(i)
2297 node = r.node(i)
2298 pp = r.parents(node)
2298 pp = r.parents(node)
2299 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2299 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2300 if pp[1] != nullid:
2300 if pp[1] != nullid:
2301 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2301 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2302 ui.write("}\n")
2302 ui.write("}\n")
2303
2303
2304 @command('debuginstall', [], '', norepo=True)
2304 @command('debuginstall', [], '', norepo=True)
2305 def debuginstall(ui):
2305 def debuginstall(ui):
2306 '''test Mercurial installation
2306 '''test Mercurial installation
2307
2307
2308 Returns 0 on success.
2308 Returns 0 on success.
2309 '''
2309 '''
2310
2310
2311 def writetemp(contents):
2311 def writetemp(contents):
2312 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2312 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2313 f = os.fdopen(fd, "wb")
2313 f = os.fdopen(fd, "wb")
2314 f.write(contents)
2314 f.write(contents)
2315 f.close()
2315 f.close()
2316 return name
2316 return name
2317
2317
2318 problems = 0
2318 problems = 0
2319
2319
2320 # encoding
2320 # encoding
2321 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2321 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2322 try:
2322 try:
2323 encoding.fromlocal("test")
2323 encoding.fromlocal("test")
2324 except util.Abort, inst:
2324 except util.Abort, inst:
2325 ui.write(" %s\n" % inst)
2325 ui.write(" %s\n" % inst)
2326 ui.write(_(" (check that your locale is properly set)\n"))
2326 ui.write(_(" (check that your locale is properly set)\n"))
2327 problems += 1
2327 problems += 1
2328
2328
2329 # Python
2329 # Python
2330 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2330 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2331 ui.status(_("checking Python version (%s)\n")
2331 ui.status(_("checking Python version (%s)\n")
2332 % ("%s.%s.%s" % sys.version_info[:3]))
2332 % ("%s.%s.%s" % sys.version_info[:3]))
2333 ui.status(_("checking Python lib (%s)...\n")
2333 ui.status(_("checking Python lib (%s)...\n")
2334 % os.path.dirname(os.__file__))
2334 % os.path.dirname(os.__file__))
2335
2335
2336 # compiled modules
2336 # compiled modules
2337 ui.status(_("checking installed modules (%s)...\n")
2337 ui.status(_("checking installed modules (%s)...\n")
2338 % os.path.dirname(__file__))
2338 % os.path.dirname(__file__))
2339 try:
2339 try:
2340 import bdiff, mpatch, base85, osutil
2340 import bdiff, mpatch, base85, osutil
2341 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2341 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2342 except Exception, inst:
2342 except Exception, inst:
2343 ui.write(" %s\n" % inst)
2343 ui.write(" %s\n" % inst)
2344 ui.write(_(" One or more extensions could not be found"))
2344 ui.write(_(" One or more extensions could not be found"))
2345 ui.write(_(" (check that you compiled the extensions)\n"))
2345 ui.write(_(" (check that you compiled the extensions)\n"))
2346 problems += 1
2346 problems += 1
2347
2347
2348 # templates
2348 # templates
2349 import templater
2349 import templater
2350 p = templater.templatepaths()
2350 p = templater.templatepaths()
2351 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2351 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2352 if p:
2352 if p:
2353 m = templater.templatepath("map-cmdline.default")
2353 m = templater.templatepath("map-cmdline.default")
2354 if m:
2354 if m:
2355 # template found, check if it is working
2355 # template found, check if it is working
2356 try:
2356 try:
2357 templater.templater(m)
2357 templater.templater(m)
2358 except Exception, inst:
2358 except Exception, inst:
2359 ui.write(" %s\n" % inst)
2359 ui.write(" %s\n" % inst)
2360 p = None
2360 p = None
2361 else:
2361 else:
2362 ui.write(_(" template 'default' not found\n"))
2362 ui.write(_(" template 'default' not found\n"))
2363 p = None
2363 p = None
2364 else:
2364 else:
2365 ui.write(_(" no template directories found\n"))
2365 ui.write(_(" no template directories found\n"))
2366 if not p:
2366 if not p:
2367 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2367 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2368 problems += 1
2368 problems += 1
2369
2369
2370 # editor
2370 # editor
2371 ui.status(_("checking commit editor...\n"))
2371 ui.status(_("checking commit editor...\n"))
2372 editor = ui.geteditor()
2372 editor = ui.geteditor()
2373 editor = util.expandpath(editor)
2373 cmdpath = util.findexe(shlex.split(editor)[0])
2374 cmdpath = util.findexe(shlex.split(editor)[0])
2374 if not cmdpath:
2375 if not cmdpath:
2375 if editor == 'vi':
2376 if editor == 'vi':
2376 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2377 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2377 ui.write(_(" (specify a commit editor in your configuration"
2378 ui.write(_(" (specify a commit editor in your configuration"
2378 " file)\n"))
2379 " file)\n"))
2379 else:
2380 else:
2380 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2381 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2381 ui.write(_(" (specify a commit editor in your configuration"
2382 ui.write(_(" (specify a commit editor in your configuration"
2382 " file)\n"))
2383 " file)\n"))
2383 problems += 1
2384 problems += 1
2384
2385
2385 # check username
2386 # check username
2386 ui.status(_("checking username...\n"))
2387 ui.status(_("checking username...\n"))
2387 try:
2388 try:
2388 ui.username()
2389 ui.username()
2389 except util.Abort, e:
2390 except util.Abort, e:
2390 ui.write(" %s\n" % e)
2391 ui.write(" %s\n" % e)
2391 ui.write(_(" (specify a username in your configuration file)\n"))
2392 ui.write(_(" (specify a username in your configuration file)\n"))
2392 problems += 1
2393 problems += 1
2393
2394
2394 if not problems:
2395 if not problems:
2395 ui.status(_("no problems detected\n"))
2396 ui.status(_("no problems detected\n"))
2396 else:
2397 else:
2397 ui.write(_("%s problems detected,"
2398 ui.write(_("%s problems detected,"
2398 " please check your install!\n") % problems)
2399 " please check your install!\n") % problems)
2399
2400
2400 return problems
2401 return problems
2401
2402
2402 @command('debugknown', [], _('REPO ID...'), norepo=True)
2403 @command('debugknown', [], _('REPO ID...'), norepo=True)
2403 def debugknown(ui, repopath, *ids, **opts):
2404 def debugknown(ui, repopath, *ids, **opts):
2404 """test whether node ids are known to a repo
2405 """test whether node ids are known to a repo
2405
2406
2406 Every ID must be a full-length hex node id string. Returns a list of 0s
2407 Every ID must be a full-length hex node id string. Returns a list of 0s
2407 and 1s indicating unknown/known.
2408 and 1s indicating unknown/known.
2408 """
2409 """
2409 repo = hg.peer(ui, opts, repopath)
2410 repo = hg.peer(ui, opts, repopath)
2410 if not repo.capable('known'):
2411 if not repo.capable('known'):
2411 raise util.Abort("known() not supported by target repository")
2412 raise util.Abort("known() not supported by target repository")
2412 flags = repo.known([bin(s) for s in ids])
2413 flags = repo.known([bin(s) for s in ids])
2413 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2414 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2414
2415
2415 @command('debuglabelcomplete', [], _('LABEL...'))
2416 @command('debuglabelcomplete', [], _('LABEL...'))
2416 def debuglabelcomplete(ui, repo, *args):
2417 def debuglabelcomplete(ui, repo, *args):
2417 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2418 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2418 debugnamecomplete(ui, repo, *args)
2419 debugnamecomplete(ui, repo, *args)
2419
2420
2420 @command('debugnamecomplete', [], _('NAME...'))
2421 @command('debugnamecomplete', [], _('NAME...'))
2421 def debugnamecomplete(ui, repo, *args):
2422 def debugnamecomplete(ui, repo, *args):
2422 '''complete "names" - tags, open branch names, bookmark names'''
2423 '''complete "names" - tags, open branch names, bookmark names'''
2423
2424
2424 names = set()
2425 names = set()
2425 # since we previously only listed open branches, we will handle that
2426 # since we previously only listed open branches, we will handle that
2426 # specially (after this for loop)
2427 # specially (after this for loop)
2427 for name, ns in repo.names.iteritems():
2428 for name, ns in repo.names.iteritems():
2428 if name != 'branches':
2429 if name != 'branches':
2429 names.update(ns.listnames(repo))
2430 names.update(ns.listnames(repo))
2430 names.update(tag for (tag, heads, tip, closed)
2431 names.update(tag for (tag, heads, tip, closed)
2431 in repo.branchmap().iterbranches() if not closed)
2432 in repo.branchmap().iterbranches() if not closed)
2432 completions = set()
2433 completions = set()
2433 if not args:
2434 if not args:
2434 args = ['']
2435 args = ['']
2435 for a in args:
2436 for a in args:
2436 completions.update(n for n in names if n.startswith(a))
2437 completions.update(n for n in names if n.startswith(a))
2437 ui.write('\n'.join(sorted(completions)))
2438 ui.write('\n'.join(sorted(completions)))
2438 ui.write('\n')
2439 ui.write('\n')
2439
2440
2440 @command('debuglocks',
2441 @command('debuglocks',
2441 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2442 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2442 ('W', 'force-wlock', None,
2443 ('W', 'force-wlock', None,
2443 _('free the working state lock (DANGEROUS)'))],
2444 _('free the working state lock (DANGEROUS)'))],
2444 _('[OPTION]...'))
2445 _('[OPTION]...'))
2445 def debuglocks(ui, repo, **opts):
2446 def debuglocks(ui, repo, **opts):
2446 """show or modify state of locks
2447 """show or modify state of locks
2447
2448
2448 By default, this command will show which locks are held. This
2449 By default, this command will show which locks are held. This
2449 includes the user and process holding the lock, the amount of time
2450 includes the user and process holding the lock, the amount of time
2450 the lock has been held, and the machine name where the process is
2451 the lock has been held, and the machine name where the process is
2451 running if it's not local.
2452 running if it's not local.
2452
2453
2453 Locks protect the integrity of Mercurial's data, so should be
2454 Locks protect the integrity of Mercurial's data, so should be
2454 treated with care. System crashes or other interruptions may cause
2455 treated with care. System crashes or other interruptions may cause
2455 locks to not be properly released, though Mercurial will usually
2456 locks to not be properly released, though Mercurial will usually
2456 detect and remove such stale locks automatically.
2457 detect and remove such stale locks automatically.
2457
2458
2458 However, detecting stale locks may not always be possible (for
2459 However, detecting stale locks may not always be possible (for
2459 instance, on a shared filesystem). Removing locks may also be
2460 instance, on a shared filesystem). Removing locks may also be
2460 blocked by filesystem permissions.
2461 blocked by filesystem permissions.
2461
2462
2462 Returns 0 if no locks are held.
2463 Returns 0 if no locks are held.
2463
2464
2464 """
2465 """
2465
2466
2466 if opts.get('force_lock'):
2467 if opts.get('force_lock'):
2467 repo.svfs.unlink('lock')
2468 repo.svfs.unlink('lock')
2468 if opts.get('force_wlock'):
2469 if opts.get('force_wlock'):
2469 repo.vfs.unlink('wlock')
2470 repo.vfs.unlink('wlock')
2470 if opts.get('force_lock') or opts.get('force_lock'):
2471 if opts.get('force_lock') or opts.get('force_lock'):
2471 return 0
2472 return 0
2472
2473
2473 now = time.time()
2474 now = time.time()
2474 held = 0
2475 held = 0
2475
2476
2476 def report(vfs, name, method):
2477 def report(vfs, name, method):
2477 # this causes stale locks to get reaped for more accurate reporting
2478 # this causes stale locks to get reaped for more accurate reporting
2478 try:
2479 try:
2479 l = method(False)
2480 l = method(False)
2480 except error.LockHeld:
2481 except error.LockHeld:
2481 l = None
2482 l = None
2482
2483
2483 if l:
2484 if l:
2484 l.release()
2485 l.release()
2485 else:
2486 else:
2486 try:
2487 try:
2487 stat = vfs.lstat(name)
2488 stat = vfs.lstat(name)
2488 age = now - stat.st_mtime
2489 age = now - stat.st_mtime
2489 user = util.username(stat.st_uid)
2490 user = util.username(stat.st_uid)
2490 locker = vfs.readlock(name)
2491 locker = vfs.readlock(name)
2491 if ":" in locker:
2492 if ":" in locker:
2492 host, pid = locker.split(':')
2493 host, pid = locker.split(':')
2493 if host == socket.gethostname():
2494 if host == socket.gethostname():
2494 locker = 'user %s, process %s' % (user, pid)
2495 locker = 'user %s, process %s' % (user, pid)
2495 else:
2496 else:
2496 locker = 'user %s, process %s, host %s' \
2497 locker = 'user %s, process %s, host %s' \
2497 % (user, pid, host)
2498 % (user, pid, host)
2498 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2499 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2499 return 1
2500 return 1
2500 except OSError, e:
2501 except OSError, e:
2501 if e.errno != errno.ENOENT:
2502 if e.errno != errno.ENOENT:
2502 raise
2503 raise
2503
2504
2504 ui.write("%-6s free\n" % (name + ":"))
2505 ui.write("%-6s free\n" % (name + ":"))
2505 return 0
2506 return 0
2506
2507
2507 held += report(repo.svfs, "lock", repo.lock)
2508 held += report(repo.svfs, "lock", repo.lock)
2508 held += report(repo.vfs, "wlock", repo.wlock)
2509 held += report(repo.vfs, "wlock", repo.wlock)
2509
2510
2510 return held
2511 return held
2511
2512
2512 @command('debugobsolete',
2513 @command('debugobsolete',
2513 [('', 'flags', 0, _('markers flag')),
2514 [('', 'flags', 0, _('markers flag')),
2514 ('', 'record-parents', False,
2515 ('', 'record-parents', False,
2515 _('record parent information for the precursor')),
2516 _('record parent information for the precursor')),
2516 ('r', 'rev', [], _('display markers relevant to REV')),
2517 ('r', 'rev', [], _('display markers relevant to REV')),
2517 ] + commitopts2,
2518 ] + commitopts2,
2518 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2519 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2519 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2520 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2520 """create arbitrary obsolete marker
2521 """create arbitrary obsolete marker
2521
2522
2522 With no arguments, displays the list of obsolescence markers."""
2523 With no arguments, displays the list of obsolescence markers."""
2523
2524
2524 def parsenodeid(s):
2525 def parsenodeid(s):
2525 try:
2526 try:
2526 # We do not use revsingle/revrange functions here to accept
2527 # We do not use revsingle/revrange functions here to accept
2527 # arbitrary node identifiers, possibly not present in the
2528 # arbitrary node identifiers, possibly not present in the
2528 # local repository.
2529 # local repository.
2529 n = bin(s)
2530 n = bin(s)
2530 if len(n) != len(nullid):
2531 if len(n) != len(nullid):
2531 raise TypeError()
2532 raise TypeError()
2532 return n
2533 return n
2533 except TypeError:
2534 except TypeError:
2534 raise util.Abort('changeset references must be full hexadecimal '
2535 raise util.Abort('changeset references must be full hexadecimal '
2535 'node identifiers')
2536 'node identifiers')
2536
2537
2537 if precursor is not None:
2538 if precursor is not None:
2538 if opts['rev']:
2539 if opts['rev']:
2539 raise util.Abort('cannot select revision when creating marker')
2540 raise util.Abort('cannot select revision when creating marker')
2540 metadata = {}
2541 metadata = {}
2541 metadata['user'] = opts['user'] or ui.username()
2542 metadata['user'] = opts['user'] or ui.username()
2542 succs = tuple(parsenodeid(succ) for succ in successors)
2543 succs = tuple(parsenodeid(succ) for succ in successors)
2543 l = repo.lock()
2544 l = repo.lock()
2544 try:
2545 try:
2545 tr = repo.transaction('debugobsolete')
2546 tr = repo.transaction('debugobsolete')
2546 try:
2547 try:
2547 try:
2548 try:
2548 date = opts.get('date')
2549 date = opts.get('date')
2549 if date:
2550 if date:
2550 date = util.parsedate(date)
2551 date = util.parsedate(date)
2551 else:
2552 else:
2552 date = None
2553 date = None
2553 prec = parsenodeid(precursor)
2554 prec = parsenodeid(precursor)
2554 parents = None
2555 parents = None
2555 if opts['record_parents']:
2556 if opts['record_parents']:
2556 if prec not in repo.unfiltered():
2557 if prec not in repo.unfiltered():
2557 raise util.Abort('cannot used --record-parents on '
2558 raise util.Abort('cannot used --record-parents on '
2558 'unknown changesets')
2559 'unknown changesets')
2559 parents = repo.unfiltered()[prec].parents()
2560 parents = repo.unfiltered()[prec].parents()
2560 parents = tuple(p.node() for p in parents)
2561 parents = tuple(p.node() for p in parents)
2561 repo.obsstore.create(tr, prec, succs, opts['flags'],
2562 repo.obsstore.create(tr, prec, succs, opts['flags'],
2562 parents=parents, date=date,
2563 parents=parents, date=date,
2563 metadata=metadata)
2564 metadata=metadata)
2564 tr.close()
2565 tr.close()
2565 except ValueError, exc:
2566 except ValueError, exc:
2566 raise util.Abort(_('bad obsmarker input: %s') % exc)
2567 raise util.Abort(_('bad obsmarker input: %s') % exc)
2567 finally:
2568 finally:
2568 tr.release()
2569 tr.release()
2569 finally:
2570 finally:
2570 l.release()
2571 l.release()
2571 else:
2572 else:
2572 if opts['rev']:
2573 if opts['rev']:
2573 revs = scmutil.revrange(repo, opts['rev'])
2574 revs = scmutil.revrange(repo, opts['rev'])
2574 nodes = [repo[r].node() for r in revs]
2575 nodes = [repo[r].node() for r in revs]
2575 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2576 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2576 markers.sort(key=lambda x: x._data)
2577 markers.sort(key=lambda x: x._data)
2577 else:
2578 else:
2578 markers = obsolete.getmarkers(repo)
2579 markers = obsolete.getmarkers(repo)
2579
2580
2580 for m in markers:
2581 for m in markers:
2581 cmdutil.showmarker(ui, m)
2582 cmdutil.showmarker(ui, m)
2582
2583
2583 @command('debugpathcomplete',
2584 @command('debugpathcomplete',
2584 [('f', 'full', None, _('complete an entire path')),
2585 [('f', 'full', None, _('complete an entire path')),
2585 ('n', 'normal', None, _('show only normal files')),
2586 ('n', 'normal', None, _('show only normal files')),
2586 ('a', 'added', None, _('show only added files')),
2587 ('a', 'added', None, _('show only added files')),
2587 ('r', 'removed', None, _('show only removed files'))],
2588 ('r', 'removed', None, _('show only removed files'))],
2588 _('FILESPEC...'))
2589 _('FILESPEC...'))
2589 def debugpathcomplete(ui, repo, *specs, **opts):
2590 def debugpathcomplete(ui, repo, *specs, **opts):
2590 '''complete part or all of a tracked path
2591 '''complete part or all of a tracked path
2591
2592
2592 This command supports shells that offer path name completion. It
2593 This command supports shells that offer path name completion. It
2593 currently completes only files already known to the dirstate.
2594 currently completes only files already known to the dirstate.
2594
2595
2595 Completion extends only to the next path segment unless
2596 Completion extends only to the next path segment unless
2596 --full is specified, in which case entire paths are used.'''
2597 --full is specified, in which case entire paths are used.'''
2597
2598
2598 def complete(path, acceptable):
2599 def complete(path, acceptable):
2599 dirstate = repo.dirstate
2600 dirstate = repo.dirstate
2600 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2601 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2601 rootdir = repo.root + os.sep
2602 rootdir = repo.root + os.sep
2602 if spec != repo.root and not spec.startswith(rootdir):
2603 if spec != repo.root and not spec.startswith(rootdir):
2603 return [], []
2604 return [], []
2604 if os.path.isdir(spec):
2605 if os.path.isdir(spec):
2605 spec += '/'
2606 spec += '/'
2606 spec = spec[len(rootdir):]
2607 spec = spec[len(rootdir):]
2607 fixpaths = os.sep != '/'
2608 fixpaths = os.sep != '/'
2608 if fixpaths:
2609 if fixpaths:
2609 spec = spec.replace(os.sep, '/')
2610 spec = spec.replace(os.sep, '/')
2610 speclen = len(spec)
2611 speclen = len(spec)
2611 fullpaths = opts['full']
2612 fullpaths = opts['full']
2612 files, dirs = set(), set()
2613 files, dirs = set(), set()
2613 adddir, addfile = dirs.add, files.add
2614 adddir, addfile = dirs.add, files.add
2614 for f, st in dirstate.iteritems():
2615 for f, st in dirstate.iteritems():
2615 if f.startswith(spec) and st[0] in acceptable:
2616 if f.startswith(spec) and st[0] in acceptable:
2616 if fixpaths:
2617 if fixpaths:
2617 f = f.replace('/', os.sep)
2618 f = f.replace('/', os.sep)
2618 if fullpaths:
2619 if fullpaths:
2619 addfile(f)
2620 addfile(f)
2620 continue
2621 continue
2621 s = f.find(os.sep, speclen)
2622 s = f.find(os.sep, speclen)
2622 if s >= 0:
2623 if s >= 0:
2623 adddir(f[:s])
2624 adddir(f[:s])
2624 else:
2625 else:
2625 addfile(f)
2626 addfile(f)
2626 return files, dirs
2627 return files, dirs
2627
2628
2628 acceptable = ''
2629 acceptable = ''
2629 if opts['normal']:
2630 if opts['normal']:
2630 acceptable += 'nm'
2631 acceptable += 'nm'
2631 if opts['added']:
2632 if opts['added']:
2632 acceptable += 'a'
2633 acceptable += 'a'
2633 if opts['removed']:
2634 if opts['removed']:
2634 acceptable += 'r'
2635 acceptable += 'r'
2635 cwd = repo.getcwd()
2636 cwd = repo.getcwd()
2636 if not specs:
2637 if not specs:
2637 specs = ['.']
2638 specs = ['.']
2638
2639
2639 files, dirs = set(), set()
2640 files, dirs = set(), set()
2640 for spec in specs:
2641 for spec in specs:
2641 f, d = complete(spec, acceptable or 'nmar')
2642 f, d = complete(spec, acceptable or 'nmar')
2642 files.update(f)
2643 files.update(f)
2643 dirs.update(d)
2644 dirs.update(d)
2644 files.update(dirs)
2645 files.update(dirs)
2645 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2646 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2646 ui.write('\n')
2647 ui.write('\n')
2647
2648
2648 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2649 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2649 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2650 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2650 '''access the pushkey key/value protocol
2651 '''access the pushkey key/value protocol
2651
2652
2652 With two args, list the keys in the given namespace.
2653 With two args, list the keys in the given namespace.
2653
2654
2654 With five args, set a key to new if it currently is set to old.
2655 With five args, set a key to new if it currently is set to old.
2655 Reports success or failure.
2656 Reports success or failure.
2656 '''
2657 '''
2657
2658
2658 target = hg.peer(ui, {}, repopath)
2659 target = hg.peer(ui, {}, repopath)
2659 if keyinfo:
2660 if keyinfo:
2660 key, old, new = keyinfo
2661 key, old, new = keyinfo
2661 r = target.pushkey(namespace, key, old, new)
2662 r = target.pushkey(namespace, key, old, new)
2662 ui.status(str(r) + '\n')
2663 ui.status(str(r) + '\n')
2663 return not r
2664 return not r
2664 else:
2665 else:
2665 for k, v in sorted(target.listkeys(namespace).iteritems()):
2666 for k, v in sorted(target.listkeys(namespace).iteritems()):
2666 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2667 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2667 v.encode('string-escape')))
2668 v.encode('string-escape')))
2668
2669
2669 @command('debugpvec', [], _('A B'))
2670 @command('debugpvec', [], _('A B'))
2670 def debugpvec(ui, repo, a, b=None):
2671 def debugpvec(ui, repo, a, b=None):
2671 ca = scmutil.revsingle(repo, a)
2672 ca = scmutil.revsingle(repo, a)
2672 cb = scmutil.revsingle(repo, b)
2673 cb = scmutil.revsingle(repo, b)
2673 pa = pvec.ctxpvec(ca)
2674 pa = pvec.ctxpvec(ca)
2674 pb = pvec.ctxpvec(cb)
2675 pb = pvec.ctxpvec(cb)
2675 if pa == pb:
2676 if pa == pb:
2676 rel = "="
2677 rel = "="
2677 elif pa > pb:
2678 elif pa > pb:
2678 rel = ">"
2679 rel = ">"
2679 elif pa < pb:
2680 elif pa < pb:
2680 rel = "<"
2681 rel = "<"
2681 elif pa | pb:
2682 elif pa | pb:
2682 rel = "|"
2683 rel = "|"
2683 ui.write(_("a: %s\n") % pa)
2684 ui.write(_("a: %s\n") % pa)
2684 ui.write(_("b: %s\n") % pb)
2685 ui.write(_("b: %s\n") % pb)
2685 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2686 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2686 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2687 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2687 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2688 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2688 pa.distance(pb), rel))
2689 pa.distance(pb), rel))
2689
2690
2690 @command('debugrebuilddirstate|debugrebuildstate',
2691 @command('debugrebuilddirstate|debugrebuildstate',
2691 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2692 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2692 _('[-r REV]'))
2693 _('[-r REV]'))
2693 def debugrebuilddirstate(ui, repo, rev):
2694 def debugrebuilddirstate(ui, repo, rev):
2694 """rebuild the dirstate as it would look like for the given revision
2695 """rebuild the dirstate as it would look like for the given revision
2695
2696
2696 If no revision is specified the first current parent will be used.
2697 If no revision is specified the first current parent will be used.
2697
2698
2698 The dirstate will be set to the files of the given revision.
2699 The dirstate will be set to the files of the given revision.
2699 The actual working directory content or existing dirstate
2700 The actual working directory content or existing dirstate
2700 information such as adds or removes is not considered.
2701 information such as adds or removes is not considered.
2701
2702
2702 One use of this command is to make the next :hg:`status` invocation
2703 One use of this command is to make the next :hg:`status` invocation
2703 check the actual file content.
2704 check the actual file content.
2704 """
2705 """
2705 ctx = scmutil.revsingle(repo, rev)
2706 ctx = scmutil.revsingle(repo, rev)
2706 wlock = repo.wlock()
2707 wlock = repo.wlock()
2707 try:
2708 try:
2708 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2709 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2709 finally:
2710 finally:
2710 wlock.release()
2711 wlock.release()
2711
2712
2712 @command('debugrename',
2713 @command('debugrename',
2713 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2714 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2714 _('[-r REV] FILE'))
2715 _('[-r REV] FILE'))
2715 def debugrename(ui, repo, file1, *pats, **opts):
2716 def debugrename(ui, repo, file1, *pats, **opts):
2716 """dump rename information"""
2717 """dump rename information"""
2717
2718
2718 ctx = scmutil.revsingle(repo, opts.get('rev'))
2719 ctx = scmutil.revsingle(repo, opts.get('rev'))
2719 m = scmutil.match(ctx, (file1,) + pats, opts)
2720 m = scmutil.match(ctx, (file1,) + pats, opts)
2720 for abs in ctx.walk(m):
2721 for abs in ctx.walk(m):
2721 fctx = ctx[abs]
2722 fctx = ctx[abs]
2722 o = fctx.filelog().renamed(fctx.filenode())
2723 o = fctx.filelog().renamed(fctx.filenode())
2723 rel = m.rel(abs)
2724 rel = m.rel(abs)
2724 if o:
2725 if o:
2725 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2726 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2726 else:
2727 else:
2727 ui.write(_("%s not renamed\n") % rel)
2728 ui.write(_("%s not renamed\n") % rel)
2728
2729
2729 @command('debugrevlog',
2730 @command('debugrevlog',
2730 [('c', 'changelog', False, _('open changelog')),
2731 [('c', 'changelog', False, _('open changelog')),
2731 ('m', 'manifest', False, _('open manifest')),
2732 ('m', 'manifest', False, _('open manifest')),
2732 ('d', 'dump', False, _('dump index data'))],
2733 ('d', 'dump', False, _('dump index data'))],
2733 _('-c|-m|FILE'),
2734 _('-c|-m|FILE'),
2734 optionalrepo=True)
2735 optionalrepo=True)
2735 def debugrevlog(ui, repo, file_=None, **opts):
2736 def debugrevlog(ui, repo, file_=None, **opts):
2736 """show data and statistics about a revlog"""
2737 """show data and statistics about a revlog"""
2737 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2738 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2738
2739
2739 if opts.get("dump"):
2740 if opts.get("dump"):
2740 numrevs = len(r)
2741 numrevs = len(r)
2741 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2742 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2742 " rawsize totalsize compression heads chainlen\n")
2743 " rawsize totalsize compression heads chainlen\n")
2743 ts = 0
2744 ts = 0
2744 heads = set()
2745 heads = set()
2745
2746
2746 for rev in xrange(numrevs):
2747 for rev in xrange(numrevs):
2747 dbase = r.deltaparent(rev)
2748 dbase = r.deltaparent(rev)
2748 if dbase == -1:
2749 if dbase == -1:
2749 dbase = rev
2750 dbase = rev
2750 cbase = r.chainbase(rev)
2751 cbase = r.chainbase(rev)
2751 clen = r.chainlen(rev)
2752 clen = r.chainlen(rev)
2752 p1, p2 = r.parentrevs(rev)
2753 p1, p2 = r.parentrevs(rev)
2753 rs = r.rawsize(rev)
2754 rs = r.rawsize(rev)
2754 ts = ts + rs
2755 ts = ts + rs
2755 heads -= set(r.parentrevs(rev))
2756 heads -= set(r.parentrevs(rev))
2756 heads.add(rev)
2757 heads.add(rev)
2757 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2758 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2758 "%11d %5d %8d\n" %
2759 "%11d %5d %8d\n" %
2759 (rev, p1, p2, r.start(rev), r.end(rev),
2760 (rev, p1, p2, r.start(rev), r.end(rev),
2760 r.start(dbase), r.start(cbase),
2761 r.start(dbase), r.start(cbase),
2761 r.start(p1), r.start(p2),
2762 r.start(p1), r.start(p2),
2762 rs, ts, ts / r.end(rev), len(heads), clen))
2763 rs, ts, ts / r.end(rev), len(heads), clen))
2763 return 0
2764 return 0
2764
2765
2765 v = r.version
2766 v = r.version
2766 format = v & 0xFFFF
2767 format = v & 0xFFFF
2767 flags = []
2768 flags = []
2768 gdelta = False
2769 gdelta = False
2769 if v & revlog.REVLOGNGINLINEDATA:
2770 if v & revlog.REVLOGNGINLINEDATA:
2770 flags.append('inline')
2771 flags.append('inline')
2771 if v & revlog.REVLOGGENERALDELTA:
2772 if v & revlog.REVLOGGENERALDELTA:
2772 gdelta = True
2773 gdelta = True
2773 flags.append('generaldelta')
2774 flags.append('generaldelta')
2774 if not flags:
2775 if not flags:
2775 flags = ['(none)']
2776 flags = ['(none)']
2776
2777
2777 nummerges = 0
2778 nummerges = 0
2778 numfull = 0
2779 numfull = 0
2779 numprev = 0
2780 numprev = 0
2780 nump1 = 0
2781 nump1 = 0
2781 nump2 = 0
2782 nump2 = 0
2782 numother = 0
2783 numother = 0
2783 nump1prev = 0
2784 nump1prev = 0
2784 nump2prev = 0
2785 nump2prev = 0
2785 chainlengths = []
2786 chainlengths = []
2786
2787
2787 datasize = [None, 0, 0L]
2788 datasize = [None, 0, 0L]
2788 fullsize = [None, 0, 0L]
2789 fullsize = [None, 0, 0L]
2789 deltasize = [None, 0, 0L]
2790 deltasize = [None, 0, 0L]
2790
2791
2791 def addsize(size, l):
2792 def addsize(size, l):
2792 if l[0] is None or size < l[0]:
2793 if l[0] is None or size < l[0]:
2793 l[0] = size
2794 l[0] = size
2794 if size > l[1]:
2795 if size > l[1]:
2795 l[1] = size
2796 l[1] = size
2796 l[2] += size
2797 l[2] += size
2797
2798
2798 numrevs = len(r)
2799 numrevs = len(r)
2799 for rev in xrange(numrevs):
2800 for rev in xrange(numrevs):
2800 p1, p2 = r.parentrevs(rev)
2801 p1, p2 = r.parentrevs(rev)
2801 delta = r.deltaparent(rev)
2802 delta = r.deltaparent(rev)
2802 if format > 0:
2803 if format > 0:
2803 addsize(r.rawsize(rev), datasize)
2804 addsize(r.rawsize(rev), datasize)
2804 if p2 != nullrev:
2805 if p2 != nullrev:
2805 nummerges += 1
2806 nummerges += 1
2806 size = r.length(rev)
2807 size = r.length(rev)
2807 if delta == nullrev:
2808 if delta == nullrev:
2808 chainlengths.append(0)
2809 chainlengths.append(0)
2809 numfull += 1
2810 numfull += 1
2810 addsize(size, fullsize)
2811 addsize(size, fullsize)
2811 else:
2812 else:
2812 chainlengths.append(chainlengths[delta] + 1)
2813 chainlengths.append(chainlengths[delta] + 1)
2813 addsize(size, deltasize)
2814 addsize(size, deltasize)
2814 if delta == rev - 1:
2815 if delta == rev - 1:
2815 numprev += 1
2816 numprev += 1
2816 if delta == p1:
2817 if delta == p1:
2817 nump1prev += 1
2818 nump1prev += 1
2818 elif delta == p2:
2819 elif delta == p2:
2819 nump2prev += 1
2820 nump2prev += 1
2820 elif delta == p1:
2821 elif delta == p1:
2821 nump1 += 1
2822 nump1 += 1
2822 elif delta == p2:
2823 elif delta == p2:
2823 nump2 += 1
2824 nump2 += 1
2824 elif delta != nullrev:
2825 elif delta != nullrev:
2825 numother += 1
2826 numother += 1
2826
2827
2827 # Adjust size min value for empty cases
2828 # Adjust size min value for empty cases
2828 for size in (datasize, fullsize, deltasize):
2829 for size in (datasize, fullsize, deltasize):
2829 if size[0] is None:
2830 if size[0] is None:
2830 size[0] = 0
2831 size[0] = 0
2831
2832
2832 numdeltas = numrevs - numfull
2833 numdeltas = numrevs - numfull
2833 numoprev = numprev - nump1prev - nump2prev
2834 numoprev = numprev - nump1prev - nump2prev
2834 totalrawsize = datasize[2]
2835 totalrawsize = datasize[2]
2835 datasize[2] /= numrevs
2836 datasize[2] /= numrevs
2836 fulltotal = fullsize[2]
2837 fulltotal = fullsize[2]
2837 fullsize[2] /= numfull
2838 fullsize[2] /= numfull
2838 deltatotal = deltasize[2]
2839 deltatotal = deltasize[2]
2839 if numrevs - numfull > 0:
2840 if numrevs - numfull > 0:
2840 deltasize[2] /= numrevs - numfull
2841 deltasize[2] /= numrevs - numfull
2841 totalsize = fulltotal + deltatotal
2842 totalsize = fulltotal + deltatotal
2842 avgchainlen = sum(chainlengths) / numrevs
2843 avgchainlen = sum(chainlengths) / numrevs
2843 maxchainlen = max(chainlengths)
2844 maxchainlen = max(chainlengths)
2844 compratio = totalrawsize / totalsize
2845 compratio = totalrawsize / totalsize
2845
2846
2846 basedfmtstr = '%%%dd\n'
2847 basedfmtstr = '%%%dd\n'
2847 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2848 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2848
2849
2849 def dfmtstr(max):
2850 def dfmtstr(max):
2850 return basedfmtstr % len(str(max))
2851 return basedfmtstr % len(str(max))
2851 def pcfmtstr(max, padding=0):
2852 def pcfmtstr(max, padding=0):
2852 return basepcfmtstr % (len(str(max)), ' ' * padding)
2853 return basepcfmtstr % (len(str(max)), ' ' * padding)
2853
2854
2854 def pcfmt(value, total):
2855 def pcfmt(value, total):
2855 return (value, 100 * float(value) / total)
2856 return (value, 100 * float(value) / total)
2856
2857
2857 ui.write(('format : %d\n') % format)
2858 ui.write(('format : %d\n') % format)
2858 ui.write(('flags : %s\n') % ', '.join(flags))
2859 ui.write(('flags : %s\n') % ', '.join(flags))
2859
2860
2860 ui.write('\n')
2861 ui.write('\n')
2861 fmt = pcfmtstr(totalsize)
2862 fmt = pcfmtstr(totalsize)
2862 fmt2 = dfmtstr(totalsize)
2863 fmt2 = dfmtstr(totalsize)
2863 ui.write(('revisions : ') + fmt2 % numrevs)
2864 ui.write(('revisions : ') + fmt2 % numrevs)
2864 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2865 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2865 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2866 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2866 ui.write(('revisions : ') + fmt2 % numrevs)
2867 ui.write(('revisions : ') + fmt2 % numrevs)
2867 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2868 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2868 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2869 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2869 ui.write(('revision size : ') + fmt2 % totalsize)
2870 ui.write(('revision size : ') + fmt2 % totalsize)
2870 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2871 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2871 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2872 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2872
2873
2873 ui.write('\n')
2874 ui.write('\n')
2874 fmt = dfmtstr(max(avgchainlen, compratio))
2875 fmt = dfmtstr(max(avgchainlen, compratio))
2875 ui.write(('avg chain length : ') + fmt % avgchainlen)
2876 ui.write(('avg chain length : ') + fmt % avgchainlen)
2876 ui.write(('max chain length : ') + fmt % maxchainlen)
2877 ui.write(('max chain length : ') + fmt % maxchainlen)
2877 ui.write(('compression ratio : ') + fmt % compratio)
2878 ui.write(('compression ratio : ') + fmt % compratio)
2878
2879
2879 if format > 0:
2880 if format > 0:
2880 ui.write('\n')
2881 ui.write('\n')
2881 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2882 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2882 % tuple(datasize))
2883 % tuple(datasize))
2883 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2884 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2884 % tuple(fullsize))
2885 % tuple(fullsize))
2885 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2886 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2886 % tuple(deltasize))
2887 % tuple(deltasize))
2887
2888
2888 if numdeltas > 0:
2889 if numdeltas > 0:
2889 ui.write('\n')
2890 ui.write('\n')
2890 fmt = pcfmtstr(numdeltas)
2891 fmt = pcfmtstr(numdeltas)
2891 fmt2 = pcfmtstr(numdeltas, 4)
2892 fmt2 = pcfmtstr(numdeltas, 4)
2892 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2893 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2893 if numprev > 0:
2894 if numprev > 0:
2894 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2895 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2895 numprev))
2896 numprev))
2896 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2897 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2897 numprev))
2898 numprev))
2898 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2899 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2899 numprev))
2900 numprev))
2900 if gdelta:
2901 if gdelta:
2901 ui.write(('deltas against p1 : ')
2902 ui.write(('deltas against p1 : ')
2902 + fmt % pcfmt(nump1, numdeltas))
2903 + fmt % pcfmt(nump1, numdeltas))
2903 ui.write(('deltas against p2 : ')
2904 ui.write(('deltas against p2 : ')
2904 + fmt % pcfmt(nump2, numdeltas))
2905 + fmt % pcfmt(nump2, numdeltas))
2905 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2906 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2906 numdeltas))
2907 numdeltas))
2907
2908
2908 @command('debugrevspec',
2909 @command('debugrevspec',
2909 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2910 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2910 ('REVSPEC'))
2911 ('REVSPEC'))
2911 def debugrevspec(ui, repo, expr, **opts):
2912 def debugrevspec(ui, repo, expr, **opts):
2912 """parse and apply a revision specification
2913 """parse and apply a revision specification
2913
2914
2914 Use --verbose to print the parsed tree before and after aliases
2915 Use --verbose to print the parsed tree before and after aliases
2915 expansion.
2916 expansion.
2916 """
2917 """
2917 if ui.verbose:
2918 if ui.verbose:
2918 tree = revset.parse(expr)[0]
2919 tree = revset.parse(expr)[0]
2919 ui.note(revset.prettyformat(tree), "\n")
2920 ui.note(revset.prettyformat(tree), "\n")
2920 newtree = revset.findaliases(ui, tree)
2921 newtree = revset.findaliases(ui, tree)
2921 if newtree != tree:
2922 if newtree != tree:
2922 ui.note(revset.prettyformat(newtree), "\n")
2923 ui.note(revset.prettyformat(newtree), "\n")
2923 tree = newtree
2924 tree = newtree
2924 newtree = revset.foldconcat(tree)
2925 newtree = revset.foldconcat(tree)
2925 if newtree != tree:
2926 if newtree != tree:
2926 ui.note(revset.prettyformat(newtree), "\n")
2927 ui.note(revset.prettyformat(newtree), "\n")
2927 if opts["optimize"]:
2928 if opts["optimize"]:
2928 weight, optimizedtree = revset.optimize(newtree, True)
2929 weight, optimizedtree = revset.optimize(newtree, True)
2929 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2930 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2930 func = revset.match(ui, expr)
2931 func = revset.match(ui, expr)
2931 revs = func(repo)
2932 revs = func(repo)
2932 if ui.verbose:
2933 if ui.verbose:
2933 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
2934 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
2934 for c in revs:
2935 for c in revs:
2935 ui.write("%s\n" % c)
2936 ui.write("%s\n" % c)
2936
2937
2937 @command('debugsetparents', [], _('REV1 [REV2]'))
2938 @command('debugsetparents', [], _('REV1 [REV2]'))
2938 def debugsetparents(ui, repo, rev1, rev2=None):
2939 def debugsetparents(ui, repo, rev1, rev2=None):
2939 """manually set the parents of the current working directory
2940 """manually set the parents of the current working directory
2940
2941
2941 This is useful for writing repository conversion tools, but should
2942 This is useful for writing repository conversion tools, but should
2942 be used with care. For example, neither the working directory nor the
2943 be used with care. For example, neither the working directory nor the
2943 dirstate is updated, so file status may be incorrect after running this
2944 dirstate is updated, so file status may be incorrect after running this
2944 command.
2945 command.
2945
2946
2946 Returns 0 on success.
2947 Returns 0 on success.
2947 """
2948 """
2948
2949
2949 r1 = scmutil.revsingle(repo, rev1).node()
2950 r1 = scmutil.revsingle(repo, rev1).node()
2950 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2951 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2951
2952
2952 wlock = repo.wlock()
2953 wlock = repo.wlock()
2953 try:
2954 try:
2954 repo.dirstate.beginparentchange()
2955 repo.dirstate.beginparentchange()
2955 repo.setparents(r1, r2)
2956 repo.setparents(r1, r2)
2956 repo.dirstate.endparentchange()
2957 repo.dirstate.endparentchange()
2957 finally:
2958 finally:
2958 wlock.release()
2959 wlock.release()
2959
2960
2960 @command('debugdirstate|debugstate',
2961 @command('debugdirstate|debugstate',
2961 [('', 'nodates', None, _('do not display the saved mtime')),
2962 [('', 'nodates', None, _('do not display the saved mtime')),
2962 ('', 'datesort', None, _('sort by saved mtime'))],
2963 ('', 'datesort', None, _('sort by saved mtime'))],
2963 _('[OPTION]...'))
2964 _('[OPTION]...'))
2964 def debugstate(ui, repo, nodates=None, datesort=None):
2965 def debugstate(ui, repo, nodates=None, datesort=None):
2965 """show the contents of the current dirstate"""
2966 """show the contents of the current dirstate"""
2966 timestr = ""
2967 timestr = ""
2967 if datesort:
2968 if datesort:
2968 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2969 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2969 else:
2970 else:
2970 keyfunc = None # sort by filename
2971 keyfunc = None # sort by filename
2971 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2972 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2972 if ent[3] == -1:
2973 if ent[3] == -1:
2973 timestr = 'unset '
2974 timestr = 'unset '
2974 elif nodates:
2975 elif nodates:
2975 timestr = 'set '
2976 timestr = 'set '
2976 else:
2977 else:
2977 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2978 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2978 time.localtime(ent[3]))
2979 time.localtime(ent[3]))
2979 if ent[1] & 020000:
2980 if ent[1] & 020000:
2980 mode = 'lnk'
2981 mode = 'lnk'
2981 else:
2982 else:
2982 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2983 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2983 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2984 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2984 for f in repo.dirstate.copies():
2985 for f in repo.dirstate.copies():
2985 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2986 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2986
2987
2987 @command('debugsub',
2988 @command('debugsub',
2988 [('r', 'rev', '',
2989 [('r', 'rev', '',
2989 _('revision to check'), _('REV'))],
2990 _('revision to check'), _('REV'))],
2990 _('[-r REV] [REV]'))
2991 _('[-r REV] [REV]'))
2991 def debugsub(ui, repo, rev=None):
2992 def debugsub(ui, repo, rev=None):
2992 ctx = scmutil.revsingle(repo, rev, None)
2993 ctx = scmutil.revsingle(repo, rev, None)
2993 for k, v in sorted(ctx.substate.items()):
2994 for k, v in sorted(ctx.substate.items()):
2994 ui.write(('path %s\n') % k)
2995 ui.write(('path %s\n') % k)
2995 ui.write((' source %s\n') % v[0])
2996 ui.write((' source %s\n') % v[0])
2996 ui.write((' revision %s\n') % v[1])
2997 ui.write((' revision %s\n') % v[1])
2997
2998
2998 @command('debugsuccessorssets',
2999 @command('debugsuccessorssets',
2999 [],
3000 [],
3000 _('[REV]'))
3001 _('[REV]'))
3001 def debugsuccessorssets(ui, repo, *revs):
3002 def debugsuccessorssets(ui, repo, *revs):
3002 """show set of successors for revision
3003 """show set of successors for revision
3003
3004
3004 A successors set of changeset A is a consistent group of revisions that
3005 A successors set of changeset A is a consistent group of revisions that
3005 succeed A. It contains non-obsolete changesets only.
3006 succeed A. It contains non-obsolete changesets only.
3006
3007
3007 In most cases a changeset A has a single successors set containing a single
3008 In most cases a changeset A has a single successors set containing a single
3008 successor (changeset A replaced by A').
3009 successor (changeset A replaced by A').
3009
3010
3010 A changeset that is made obsolete with no successors are called "pruned".
3011 A changeset that is made obsolete with no successors are called "pruned".
3011 Such changesets have no successors sets at all.
3012 Such changesets have no successors sets at all.
3012
3013
3013 A changeset that has been "split" will have a successors set containing
3014 A changeset that has been "split" will have a successors set containing
3014 more than one successor.
3015 more than one successor.
3015
3016
3016 A changeset that has been rewritten in multiple different ways is called
3017 A changeset that has been rewritten in multiple different ways is called
3017 "divergent". Such changesets have multiple successor sets (each of which
3018 "divergent". Such changesets have multiple successor sets (each of which
3018 may also be split, i.e. have multiple successors).
3019 may also be split, i.e. have multiple successors).
3019
3020
3020 Results are displayed as follows::
3021 Results are displayed as follows::
3021
3022
3022 <rev1>
3023 <rev1>
3023 <successors-1A>
3024 <successors-1A>
3024 <rev2>
3025 <rev2>
3025 <successors-2A>
3026 <successors-2A>
3026 <successors-2B1> <successors-2B2> <successors-2B3>
3027 <successors-2B1> <successors-2B2> <successors-2B3>
3027
3028
3028 Here rev2 has two possible (i.e. divergent) successors sets. The first
3029 Here rev2 has two possible (i.e. divergent) successors sets. The first
3029 holds one element, whereas the second holds three (i.e. the changeset has
3030 holds one element, whereas the second holds three (i.e. the changeset has
3030 been split).
3031 been split).
3031 """
3032 """
3032 # passed to successorssets caching computation from one call to another
3033 # passed to successorssets caching computation from one call to another
3033 cache = {}
3034 cache = {}
3034 ctx2str = str
3035 ctx2str = str
3035 node2str = short
3036 node2str = short
3036 if ui.debug():
3037 if ui.debug():
3037 def ctx2str(ctx):
3038 def ctx2str(ctx):
3038 return ctx.hex()
3039 return ctx.hex()
3039 node2str = hex
3040 node2str = hex
3040 for rev in scmutil.revrange(repo, revs):
3041 for rev in scmutil.revrange(repo, revs):
3041 ctx = repo[rev]
3042 ctx = repo[rev]
3042 ui.write('%s\n'% ctx2str(ctx))
3043 ui.write('%s\n'% ctx2str(ctx))
3043 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3044 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3044 if succsset:
3045 if succsset:
3045 ui.write(' ')
3046 ui.write(' ')
3046 ui.write(node2str(succsset[0]))
3047 ui.write(node2str(succsset[0]))
3047 for node in succsset[1:]:
3048 for node in succsset[1:]:
3048 ui.write(' ')
3049 ui.write(' ')
3049 ui.write(node2str(node))
3050 ui.write(node2str(node))
3050 ui.write('\n')
3051 ui.write('\n')
3051
3052
3052 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3053 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3053 def debugwalk(ui, repo, *pats, **opts):
3054 def debugwalk(ui, repo, *pats, **opts):
3054 """show how files match on given patterns"""
3055 """show how files match on given patterns"""
3055 m = scmutil.match(repo[None], pats, opts)
3056 m = scmutil.match(repo[None], pats, opts)
3056 items = list(repo.walk(m))
3057 items = list(repo.walk(m))
3057 if not items:
3058 if not items:
3058 return
3059 return
3059 f = lambda fn: fn
3060 f = lambda fn: fn
3060 if ui.configbool('ui', 'slash') and os.sep != '/':
3061 if ui.configbool('ui', 'slash') and os.sep != '/':
3061 f = lambda fn: util.normpath(fn)
3062 f = lambda fn: util.normpath(fn)
3062 fmt = 'f %%-%ds %%-%ds %%s' % (
3063 fmt = 'f %%-%ds %%-%ds %%s' % (
3063 max([len(abs) for abs in items]),
3064 max([len(abs) for abs in items]),
3064 max([len(m.rel(abs)) for abs in items]))
3065 max([len(m.rel(abs)) for abs in items]))
3065 for abs in items:
3066 for abs in items:
3066 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3067 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3067 ui.write("%s\n" % line.rstrip())
3068 ui.write("%s\n" % line.rstrip())
3068
3069
3069 @command('debugwireargs',
3070 @command('debugwireargs',
3070 [('', 'three', '', 'three'),
3071 [('', 'three', '', 'three'),
3071 ('', 'four', '', 'four'),
3072 ('', 'four', '', 'four'),
3072 ('', 'five', '', 'five'),
3073 ('', 'five', '', 'five'),
3073 ] + remoteopts,
3074 ] + remoteopts,
3074 _('REPO [OPTIONS]... [ONE [TWO]]'),
3075 _('REPO [OPTIONS]... [ONE [TWO]]'),
3075 norepo=True)
3076 norepo=True)
3076 def debugwireargs(ui, repopath, *vals, **opts):
3077 def debugwireargs(ui, repopath, *vals, **opts):
3077 repo = hg.peer(ui, opts, repopath)
3078 repo = hg.peer(ui, opts, repopath)
3078 for opt in remoteopts:
3079 for opt in remoteopts:
3079 del opts[opt[1]]
3080 del opts[opt[1]]
3080 args = {}
3081 args = {}
3081 for k, v in opts.iteritems():
3082 for k, v in opts.iteritems():
3082 if v:
3083 if v:
3083 args[k] = v
3084 args[k] = v
3084 # run twice to check that we don't mess up the stream for the next command
3085 # run twice to check that we don't mess up the stream for the next command
3085 res1 = repo.debugwireargs(*vals, **args)
3086 res1 = repo.debugwireargs(*vals, **args)
3086 res2 = repo.debugwireargs(*vals, **args)
3087 res2 = repo.debugwireargs(*vals, **args)
3087 ui.write("%s\n" % res1)
3088 ui.write("%s\n" % res1)
3088 if res1 != res2:
3089 if res1 != res2:
3089 ui.warn("%s\n" % res2)
3090 ui.warn("%s\n" % res2)
3090
3091
3091 @command('^diff',
3092 @command('^diff',
3092 [('r', 'rev', [], _('revision'), _('REV')),
3093 [('r', 'rev', [], _('revision'), _('REV')),
3093 ('c', 'change', '', _('change made by revision'), _('REV'))
3094 ('c', 'change', '', _('change made by revision'), _('REV'))
3094 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3095 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3095 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3096 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3096 inferrepo=True)
3097 inferrepo=True)
3097 def diff(ui, repo, *pats, **opts):
3098 def diff(ui, repo, *pats, **opts):
3098 """diff repository (or selected files)
3099 """diff repository (or selected files)
3099
3100
3100 Show differences between revisions for the specified files.
3101 Show differences between revisions for the specified files.
3101
3102
3102 Differences between files are shown using the unified diff format.
3103 Differences between files are shown using the unified diff format.
3103
3104
3104 .. note::
3105 .. note::
3105
3106
3106 diff may generate unexpected results for merges, as it will
3107 diff may generate unexpected results for merges, as it will
3107 default to comparing against the working directory's first
3108 default to comparing against the working directory's first
3108 parent changeset if no revisions are specified.
3109 parent changeset if no revisions are specified.
3109
3110
3110 When two revision arguments are given, then changes are shown
3111 When two revision arguments are given, then changes are shown
3111 between those revisions. If only one revision is specified then
3112 between those revisions. If only one revision is specified then
3112 that revision is compared to the working directory, and, when no
3113 that revision is compared to the working directory, and, when no
3113 revisions are specified, the working directory files are compared
3114 revisions are specified, the working directory files are compared
3114 to its parent.
3115 to its parent.
3115
3116
3116 Alternatively you can specify -c/--change with a revision to see
3117 Alternatively you can specify -c/--change with a revision to see
3117 the changes in that changeset relative to its first parent.
3118 the changes in that changeset relative to its first parent.
3118
3119
3119 Without the -a/--text option, diff will avoid generating diffs of
3120 Without the -a/--text option, diff will avoid generating diffs of
3120 files it detects as binary. With -a, diff will generate a diff
3121 files it detects as binary. With -a, diff will generate a diff
3121 anyway, probably with undesirable results.
3122 anyway, probably with undesirable results.
3122
3123
3123 Use the -g/--git option to generate diffs in the git extended diff
3124 Use the -g/--git option to generate diffs in the git extended diff
3124 format. For more information, read :hg:`help diffs`.
3125 format. For more information, read :hg:`help diffs`.
3125
3126
3126 .. container:: verbose
3127 .. container:: verbose
3127
3128
3128 Examples:
3129 Examples:
3129
3130
3130 - compare a file in the current working directory to its parent::
3131 - compare a file in the current working directory to its parent::
3131
3132
3132 hg diff foo.c
3133 hg diff foo.c
3133
3134
3134 - compare two historical versions of a directory, with rename info::
3135 - compare two historical versions of a directory, with rename info::
3135
3136
3136 hg diff --git -r 1.0:1.2 lib/
3137 hg diff --git -r 1.0:1.2 lib/
3137
3138
3138 - get change stats relative to the last change on some date::
3139 - get change stats relative to the last change on some date::
3139
3140
3140 hg diff --stat -r "date('may 2')"
3141 hg diff --stat -r "date('may 2')"
3141
3142
3142 - diff all newly-added files that contain a keyword::
3143 - diff all newly-added files that contain a keyword::
3143
3144
3144 hg diff "set:added() and grep(GNU)"
3145 hg diff "set:added() and grep(GNU)"
3145
3146
3146 - compare a revision and its parents::
3147 - compare a revision and its parents::
3147
3148
3148 hg diff -c 9353 # compare against first parent
3149 hg diff -c 9353 # compare against first parent
3149 hg diff -r 9353^:9353 # same using revset syntax
3150 hg diff -r 9353^:9353 # same using revset syntax
3150 hg diff -r 9353^2:9353 # compare against the second parent
3151 hg diff -r 9353^2:9353 # compare against the second parent
3151
3152
3152 Returns 0 on success.
3153 Returns 0 on success.
3153 """
3154 """
3154
3155
3155 revs = opts.get('rev')
3156 revs = opts.get('rev')
3156 change = opts.get('change')
3157 change = opts.get('change')
3157 stat = opts.get('stat')
3158 stat = opts.get('stat')
3158 reverse = opts.get('reverse')
3159 reverse = opts.get('reverse')
3159
3160
3160 if revs and change:
3161 if revs and change:
3161 msg = _('cannot specify --rev and --change at the same time')
3162 msg = _('cannot specify --rev and --change at the same time')
3162 raise util.Abort(msg)
3163 raise util.Abort(msg)
3163 elif change:
3164 elif change:
3164 node2 = scmutil.revsingle(repo, change, None).node()
3165 node2 = scmutil.revsingle(repo, change, None).node()
3165 node1 = repo[node2].p1().node()
3166 node1 = repo[node2].p1().node()
3166 else:
3167 else:
3167 node1, node2 = scmutil.revpair(repo, revs)
3168 node1, node2 = scmutil.revpair(repo, revs)
3168
3169
3169 if reverse:
3170 if reverse:
3170 node1, node2 = node2, node1
3171 node1, node2 = node2, node1
3171
3172
3172 diffopts = patch.diffallopts(ui, opts)
3173 diffopts = patch.diffallopts(ui, opts)
3173 m = scmutil.match(repo[node2], pats, opts)
3174 m = scmutil.match(repo[node2], pats, opts)
3174 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3175 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3175 listsubrepos=opts.get('subrepos'),
3176 listsubrepos=opts.get('subrepos'),
3176 root=opts.get('root'))
3177 root=opts.get('root'))
3177
3178
3178 @command('^export',
3179 @command('^export',
3179 [('o', 'output', '',
3180 [('o', 'output', '',
3180 _('print output to file with formatted name'), _('FORMAT')),
3181 _('print output to file with formatted name'), _('FORMAT')),
3181 ('', 'switch-parent', None, _('diff against the second parent')),
3182 ('', 'switch-parent', None, _('diff against the second parent')),
3182 ('r', 'rev', [], _('revisions to export'), _('REV')),
3183 ('r', 'rev', [], _('revisions to export'), _('REV')),
3183 ] + diffopts,
3184 ] + diffopts,
3184 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3185 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3185 def export(ui, repo, *changesets, **opts):
3186 def export(ui, repo, *changesets, **opts):
3186 """dump the header and diffs for one or more changesets
3187 """dump the header and diffs for one or more changesets
3187
3188
3188 Print the changeset header and diffs for one or more revisions.
3189 Print the changeset header and diffs for one or more revisions.
3189 If no revision is given, the parent of the working directory is used.
3190 If no revision is given, the parent of the working directory is used.
3190
3191
3191 The information shown in the changeset header is: author, date,
3192 The information shown in the changeset header is: author, date,
3192 branch name (if non-default), changeset hash, parent(s) and commit
3193 branch name (if non-default), changeset hash, parent(s) and commit
3193 comment.
3194 comment.
3194
3195
3195 .. note::
3196 .. note::
3196
3197
3197 export may generate unexpected diff output for merge
3198 export may generate unexpected diff output for merge
3198 changesets, as it will compare the merge changeset against its
3199 changesets, as it will compare the merge changeset against its
3199 first parent only.
3200 first parent only.
3200
3201
3201 Output may be to a file, in which case the name of the file is
3202 Output may be to a file, in which case the name of the file is
3202 given using a format string. The formatting rules are as follows:
3203 given using a format string. The formatting rules are as follows:
3203
3204
3204 :``%%``: literal "%" character
3205 :``%%``: literal "%" character
3205 :``%H``: changeset hash (40 hexadecimal digits)
3206 :``%H``: changeset hash (40 hexadecimal digits)
3206 :``%N``: number of patches being generated
3207 :``%N``: number of patches being generated
3207 :``%R``: changeset revision number
3208 :``%R``: changeset revision number
3208 :``%b``: basename of the exporting repository
3209 :``%b``: basename of the exporting repository
3209 :``%h``: short-form changeset hash (12 hexadecimal digits)
3210 :``%h``: short-form changeset hash (12 hexadecimal digits)
3210 :``%m``: first line of the commit message (only alphanumeric characters)
3211 :``%m``: first line of the commit message (only alphanumeric characters)
3211 :``%n``: zero-padded sequence number, starting at 1
3212 :``%n``: zero-padded sequence number, starting at 1
3212 :``%r``: zero-padded changeset revision number
3213 :``%r``: zero-padded changeset revision number
3213
3214
3214 Without the -a/--text option, export will avoid generating diffs
3215 Without the -a/--text option, export will avoid generating diffs
3215 of files it detects as binary. With -a, export will generate a
3216 of files it detects as binary. With -a, export will generate a
3216 diff anyway, probably with undesirable results.
3217 diff anyway, probably with undesirable results.
3217
3218
3218 Use the -g/--git option to generate diffs in the git extended diff
3219 Use the -g/--git option to generate diffs in the git extended diff
3219 format. See :hg:`help diffs` for more information.
3220 format. See :hg:`help diffs` for more information.
3220
3221
3221 With the --switch-parent option, the diff will be against the
3222 With the --switch-parent option, the diff will be against the
3222 second parent. It can be useful to review a merge.
3223 second parent. It can be useful to review a merge.
3223
3224
3224 .. container:: verbose
3225 .. container:: verbose
3225
3226
3226 Examples:
3227 Examples:
3227
3228
3228 - use export and import to transplant a bugfix to the current
3229 - use export and import to transplant a bugfix to the current
3229 branch::
3230 branch::
3230
3231
3231 hg export -r 9353 | hg import -
3232 hg export -r 9353 | hg import -
3232
3233
3233 - export all the changesets between two revisions to a file with
3234 - export all the changesets between two revisions to a file with
3234 rename information::
3235 rename information::
3235
3236
3236 hg export --git -r 123:150 > changes.txt
3237 hg export --git -r 123:150 > changes.txt
3237
3238
3238 - split outgoing changes into a series of patches with
3239 - split outgoing changes into a series of patches with
3239 descriptive names::
3240 descriptive names::
3240
3241
3241 hg export -r "outgoing()" -o "%n-%m.patch"
3242 hg export -r "outgoing()" -o "%n-%m.patch"
3242
3243
3243 Returns 0 on success.
3244 Returns 0 on success.
3244 """
3245 """
3245 changesets += tuple(opts.get('rev', []))
3246 changesets += tuple(opts.get('rev', []))
3246 if not changesets:
3247 if not changesets:
3247 changesets = ['.']
3248 changesets = ['.']
3248 revs = scmutil.revrange(repo, changesets)
3249 revs = scmutil.revrange(repo, changesets)
3249 if not revs:
3250 if not revs:
3250 raise util.Abort(_("export requires at least one changeset"))
3251 raise util.Abort(_("export requires at least one changeset"))
3251 if len(revs) > 1:
3252 if len(revs) > 1:
3252 ui.note(_('exporting patches:\n'))
3253 ui.note(_('exporting patches:\n'))
3253 else:
3254 else:
3254 ui.note(_('exporting patch:\n'))
3255 ui.note(_('exporting patch:\n'))
3255 cmdutil.export(repo, revs, template=opts.get('output'),
3256 cmdutil.export(repo, revs, template=opts.get('output'),
3256 switch_parent=opts.get('switch_parent'),
3257 switch_parent=opts.get('switch_parent'),
3257 opts=patch.diffallopts(ui, opts))
3258 opts=patch.diffallopts(ui, opts))
3258
3259
3259 @command('files',
3260 @command('files',
3260 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3261 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3261 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3262 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3262 ] + walkopts + formatteropts + subrepoopts,
3263 ] + walkopts + formatteropts + subrepoopts,
3263 _('[OPTION]... [PATTERN]...'))
3264 _('[OPTION]... [PATTERN]...'))
3264 def files(ui, repo, *pats, **opts):
3265 def files(ui, repo, *pats, **opts):
3265 """list tracked files
3266 """list tracked files
3266
3267
3267 Print files under Mercurial control in the working directory or
3268 Print files under Mercurial control in the working directory or
3268 specified revision whose names match the given patterns (excluding
3269 specified revision whose names match the given patterns (excluding
3269 removed files).
3270 removed files).
3270
3271
3271 If no patterns are given to match, this command prints the names
3272 If no patterns are given to match, this command prints the names
3272 of all files under Mercurial control in the working directory.
3273 of all files under Mercurial control in the working directory.
3273
3274
3274 .. container:: verbose
3275 .. container:: verbose
3275
3276
3276 Examples:
3277 Examples:
3277
3278
3278 - list all files under the current directory::
3279 - list all files under the current directory::
3279
3280
3280 hg files .
3281 hg files .
3281
3282
3282 - shows sizes and flags for current revision::
3283 - shows sizes and flags for current revision::
3283
3284
3284 hg files -vr .
3285 hg files -vr .
3285
3286
3286 - list all files named README::
3287 - list all files named README::
3287
3288
3288 hg files -I "**/README"
3289 hg files -I "**/README"
3289
3290
3290 - list all binary files::
3291 - list all binary files::
3291
3292
3292 hg files "set:binary()"
3293 hg files "set:binary()"
3293
3294
3294 - find files containing a regular expression::
3295 - find files containing a regular expression::
3295
3296
3296 hg files "set:grep('bob')"
3297 hg files "set:grep('bob')"
3297
3298
3298 - search tracked file contents with xargs and grep::
3299 - search tracked file contents with xargs and grep::
3299
3300
3300 hg files -0 | xargs -0 grep foo
3301 hg files -0 | xargs -0 grep foo
3301
3302
3302 See :hg:`help patterns` and :hg:`help filesets` for more information
3303 See :hg:`help patterns` and :hg:`help filesets` for more information
3303 on specifying file patterns.
3304 on specifying file patterns.
3304
3305
3305 Returns 0 if a match is found, 1 otherwise.
3306 Returns 0 if a match is found, 1 otherwise.
3306
3307
3307 """
3308 """
3308 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3309 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3309
3310
3310 end = '\n'
3311 end = '\n'
3311 if opts.get('print0'):
3312 if opts.get('print0'):
3312 end = '\0'
3313 end = '\0'
3313 fm = ui.formatter('files', opts)
3314 fm = ui.formatter('files', opts)
3314 fmt = '%s' + end
3315 fmt = '%s' + end
3315
3316
3316 m = scmutil.match(ctx, pats, opts)
3317 m = scmutil.match(ctx, pats, opts)
3317 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3318 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3318
3319
3319 fm.end()
3320 fm.end()
3320
3321
3321 return ret
3322 return ret
3322
3323
3323 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3324 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3324 def forget(ui, repo, *pats, **opts):
3325 def forget(ui, repo, *pats, **opts):
3325 """forget the specified files on the next commit
3326 """forget the specified files on the next commit
3326
3327
3327 Mark the specified files so they will no longer be tracked
3328 Mark the specified files so they will no longer be tracked
3328 after the next commit.
3329 after the next commit.
3329
3330
3330 This only removes files from the current branch, not from the
3331 This only removes files from the current branch, not from the
3331 entire project history, and it does not delete them from the
3332 entire project history, and it does not delete them from the
3332 working directory.
3333 working directory.
3333
3334
3334 To undo a forget before the next commit, see :hg:`add`.
3335 To undo a forget before the next commit, see :hg:`add`.
3335
3336
3336 .. container:: verbose
3337 .. container:: verbose
3337
3338
3338 Examples:
3339 Examples:
3339
3340
3340 - forget newly-added binary files::
3341 - forget newly-added binary files::
3341
3342
3342 hg forget "set:added() and binary()"
3343 hg forget "set:added() and binary()"
3343
3344
3344 - forget files that would be excluded by .hgignore::
3345 - forget files that would be excluded by .hgignore::
3345
3346
3346 hg forget "set:hgignore()"
3347 hg forget "set:hgignore()"
3347
3348
3348 Returns 0 on success.
3349 Returns 0 on success.
3349 """
3350 """
3350
3351
3351 if not pats:
3352 if not pats:
3352 raise util.Abort(_('no files specified'))
3353 raise util.Abort(_('no files specified'))
3353
3354
3354 m = scmutil.match(repo[None], pats, opts)
3355 m = scmutil.match(repo[None], pats, opts)
3355 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3356 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3356 return rejected and 1 or 0
3357 return rejected and 1 or 0
3357
3358
3358 @command(
3359 @command(
3359 'graft',
3360 'graft',
3360 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3361 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3361 ('c', 'continue', False, _('resume interrupted graft')),
3362 ('c', 'continue', False, _('resume interrupted graft')),
3362 ('e', 'edit', False, _('invoke editor on commit messages')),
3363 ('e', 'edit', False, _('invoke editor on commit messages')),
3363 ('', 'log', None, _('append graft info to log message')),
3364 ('', 'log', None, _('append graft info to log message')),
3364 ('f', 'force', False, _('force graft')),
3365 ('f', 'force', False, _('force graft')),
3365 ('D', 'currentdate', False,
3366 ('D', 'currentdate', False,
3366 _('record the current date as commit date')),
3367 _('record the current date as commit date')),
3367 ('U', 'currentuser', False,
3368 ('U', 'currentuser', False,
3368 _('record the current user as committer'), _('DATE'))]
3369 _('record the current user as committer'), _('DATE'))]
3369 + commitopts2 + mergetoolopts + dryrunopts,
3370 + commitopts2 + mergetoolopts + dryrunopts,
3370 _('[OPTION]... [-r] REV...'))
3371 _('[OPTION]... [-r] REV...'))
3371 def graft(ui, repo, *revs, **opts):
3372 def graft(ui, repo, *revs, **opts):
3372 '''copy changes from other branches onto the current branch
3373 '''copy changes from other branches onto the current branch
3373
3374
3374 This command uses Mercurial's merge logic to copy individual
3375 This command uses Mercurial's merge logic to copy individual
3375 changes from other branches without merging branches in the
3376 changes from other branches without merging branches in the
3376 history graph. This is sometimes known as 'backporting' or
3377 history graph. This is sometimes known as 'backporting' or
3377 'cherry-picking'. By default, graft will copy user, date, and
3378 'cherry-picking'. By default, graft will copy user, date, and
3378 description from the source changesets.
3379 description from the source changesets.
3379
3380
3380 Changesets that are ancestors of the current revision, that have
3381 Changesets that are ancestors of the current revision, that have
3381 already been grafted, or that are merges will be skipped.
3382 already been grafted, or that are merges will be skipped.
3382
3383
3383 If --log is specified, log messages will have a comment appended
3384 If --log is specified, log messages will have a comment appended
3384 of the form::
3385 of the form::
3385
3386
3386 (grafted from CHANGESETHASH)
3387 (grafted from CHANGESETHASH)
3387
3388
3388 If --force is specified, revisions will be grafted even if they
3389 If --force is specified, revisions will be grafted even if they
3389 are already ancestors of or have been grafted to the destination.
3390 are already ancestors of or have been grafted to the destination.
3390 This is useful when the revisions have since been backed out.
3391 This is useful when the revisions have since been backed out.
3391
3392
3392 If a graft merge results in conflicts, the graft process is
3393 If a graft merge results in conflicts, the graft process is
3393 interrupted so that the current merge can be manually resolved.
3394 interrupted so that the current merge can be manually resolved.
3394 Once all conflicts are addressed, the graft process can be
3395 Once all conflicts are addressed, the graft process can be
3395 continued with the -c/--continue option.
3396 continued with the -c/--continue option.
3396
3397
3397 .. note::
3398 .. note::
3398
3399
3399 The -c/--continue option does not reapply earlier options, except
3400 The -c/--continue option does not reapply earlier options, except
3400 for --force.
3401 for --force.
3401
3402
3402 .. container:: verbose
3403 .. container:: verbose
3403
3404
3404 Examples:
3405 Examples:
3405
3406
3406 - copy a single change to the stable branch and edit its description::
3407 - copy a single change to the stable branch and edit its description::
3407
3408
3408 hg update stable
3409 hg update stable
3409 hg graft --edit 9393
3410 hg graft --edit 9393
3410
3411
3411 - graft a range of changesets with one exception, updating dates::
3412 - graft a range of changesets with one exception, updating dates::
3412
3413
3413 hg graft -D "2085::2093 and not 2091"
3414 hg graft -D "2085::2093 and not 2091"
3414
3415
3415 - continue a graft after resolving conflicts::
3416 - continue a graft after resolving conflicts::
3416
3417
3417 hg graft -c
3418 hg graft -c
3418
3419
3419 - show the source of a grafted changeset::
3420 - show the source of a grafted changeset::
3420
3421
3421 hg log --debug -r .
3422 hg log --debug -r .
3422
3423
3423 See :hg:`help revisions` and :hg:`help revsets` for more about
3424 See :hg:`help revisions` and :hg:`help revsets` for more about
3424 specifying revisions.
3425 specifying revisions.
3425
3426
3426 Returns 0 on successful completion.
3427 Returns 0 on successful completion.
3427 '''
3428 '''
3428
3429
3429 revs = list(revs)
3430 revs = list(revs)
3430 revs.extend(opts['rev'])
3431 revs.extend(opts['rev'])
3431
3432
3432 if not opts.get('user') and opts.get('currentuser'):
3433 if not opts.get('user') and opts.get('currentuser'):
3433 opts['user'] = ui.username()
3434 opts['user'] = ui.username()
3434 if not opts.get('date') and opts.get('currentdate'):
3435 if not opts.get('date') and opts.get('currentdate'):
3435 opts['date'] = "%d %d" % util.makedate()
3436 opts['date'] = "%d %d" % util.makedate()
3436
3437
3437 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3438 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3438
3439
3439 cont = False
3440 cont = False
3440 if opts['continue']:
3441 if opts['continue']:
3441 cont = True
3442 cont = True
3442 if revs:
3443 if revs:
3443 raise util.Abort(_("can't specify --continue and revisions"))
3444 raise util.Abort(_("can't specify --continue and revisions"))
3444 # read in unfinished revisions
3445 # read in unfinished revisions
3445 try:
3446 try:
3446 nodes = repo.vfs.read('graftstate').splitlines()
3447 nodes = repo.vfs.read('graftstate').splitlines()
3447 revs = [repo[node].rev() for node in nodes]
3448 revs = [repo[node].rev() for node in nodes]
3448 except IOError, inst:
3449 except IOError, inst:
3449 if inst.errno != errno.ENOENT:
3450 if inst.errno != errno.ENOENT:
3450 raise
3451 raise
3451 raise util.Abort(_("no graft state found, can't continue"))
3452 raise util.Abort(_("no graft state found, can't continue"))
3452 else:
3453 else:
3453 cmdutil.checkunfinished(repo)
3454 cmdutil.checkunfinished(repo)
3454 cmdutil.bailifchanged(repo)
3455 cmdutil.bailifchanged(repo)
3455 if not revs:
3456 if not revs:
3456 raise util.Abort(_('no revisions specified'))
3457 raise util.Abort(_('no revisions specified'))
3457 revs = scmutil.revrange(repo, revs)
3458 revs = scmutil.revrange(repo, revs)
3458
3459
3459 skipped = set()
3460 skipped = set()
3460 # check for merges
3461 # check for merges
3461 for rev in repo.revs('%ld and merge()', revs):
3462 for rev in repo.revs('%ld and merge()', revs):
3462 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3463 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3463 skipped.add(rev)
3464 skipped.add(rev)
3464 revs = [r for r in revs if r not in skipped]
3465 revs = [r for r in revs if r not in skipped]
3465 if not revs:
3466 if not revs:
3466 return -1
3467 return -1
3467
3468
3468 # Don't check in the --continue case, in effect retaining --force across
3469 # Don't check in the --continue case, in effect retaining --force across
3469 # --continues. That's because without --force, any revisions we decided to
3470 # --continues. That's because without --force, any revisions we decided to
3470 # skip would have been filtered out here, so they wouldn't have made their
3471 # skip would have been filtered out here, so they wouldn't have made their
3471 # way to the graftstate. With --force, any revisions we would have otherwise
3472 # way to the graftstate. With --force, any revisions we would have otherwise
3472 # skipped would not have been filtered out, and if they hadn't been applied
3473 # skipped would not have been filtered out, and if they hadn't been applied
3473 # already, they'd have been in the graftstate.
3474 # already, they'd have been in the graftstate.
3474 if not (cont or opts.get('force')):
3475 if not (cont or opts.get('force')):
3475 # check for ancestors of dest branch
3476 # check for ancestors of dest branch
3476 crev = repo['.'].rev()
3477 crev = repo['.'].rev()
3477 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3478 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3478 # Cannot use x.remove(y) on smart set, this has to be a list.
3479 # Cannot use x.remove(y) on smart set, this has to be a list.
3479 # XXX make this lazy in the future
3480 # XXX make this lazy in the future
3480 revs = list(revs)
3481 revs = list(revs)
3481 # don't mutate while iterating, create a copy
3482 # don't mutate while iterating, create a copy
3482 for rev in list(revs):
3483 for rev in list(revs):
3483 if rev in ancestors:
3484 if rev in ancestors:
3484 ui.warn(_('skipping ancestor revision %d:%s\n') %
3485 ui.warn(_('skipping ancestor revision %d:%s\n') %
3485 (rev, repo[rev]))
3486 (rev, repo[rev]))
3486 # XXX remove on list is slow
3487 # XXX remove on list is slow
3487 revs.remove(rev)
3488 revs.remove(rev)
3488 if not revs:
3489 if not revs:
3489 return -1
3490 return -1
3490
3491
3491 # analyze revs for earlier grafts
3492 # analyze revs for earlier grafts
3492 ids = {}
3493 ids = {}
3493 for ctx in repo.set("%ld", revs):
3494 for ctx in repo.set("%ld", revs):
3494 ids[ctx.hex()] = ctx.rev()
3495 ids[ctx.hex()] = ctx.rev()
3495 n = ctx.extra().get('source')
3496 n = ctx.extra().get('source')
3496 if n:
3497 if n:
3497 ids[n] = ctx.rev()
3498 ids[n] = ctx.rev()
3498
3499
3499 # check ancestors for earlier grafts
3500 # check ancestors for earlier grafts
3500 ui.debug('scanning for duplicate grafts\n')
3501 ui.debug('scanning for duplicate grafts\n')
3501
3502
3502 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3503 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3503 ctx = repo[rev]
3504 ctx = repo[rev]
3504 n = ctx.extra().get('source')
3505 n = ctx.extra().get('source')
3505 if n in ids:
3506 if n in ids:
3506 try:
3507 try:
3507 r = repo[n].rev()
3508 r = repo[n].rev()
3508 except error.RepoLookupError:
3509 except error.RepoLookupError:
3509 r = None
3510 r = None
3510 if r in revs:
3511 if r in revs:
3511 ui.warn(_('skipping revision %d:%s '
3512 ui.warn(_('skipping revision %d:%s '
3512 '(already grafted to %d:%s)\n')
3513 '(already grafted to %d:%s)\n')
3513 % (r, repo[r], rev, ctx))
3514 % (r, repo[r], rev, ctx))
3514 revs.remove(r)
3515 revs.remove(r)
3515 elif ids[n] in revs:
3516 elif ids[n] in revs:
3516 if r is None:
3517 if r is None:
3517 ui.warn(_('skipping already grafted revision %d:%s '
3518 ui.warn(_('skipping already grafted revision %d:%s '
3518 '(%d:%s also has unknown origin %s)\n')
3519 '(%d:%s also has unknown origin %s)\n')
3519 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3520 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3520 else:
3521 else:
3521 ui.warn(_('skipping already grafted revision %d:%s '
3522 ui.warn(_('skipping already grafted revision %d:%s '
3522 '(%d:%s also has origin %d:%s)\n')
3523 '(%d:%s also has origin %d:%s)\n')
3523 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3524 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3524 revs.remove(ids[n])
3525 revs.remove(ids[n])
3525 elif ctx.hex() in ids:
3526 elif ctx.hex() in ids:
3526 r = ids[ctx.hex()]
3527 r = ids[ctx.hex()]
3527 ui.warn(_('skipping already grafted revision %d:%s '
3528 ui.warn(_('skipping already grafted revision %d:%s '
3528 '(was grafted from %d:%s)\n') %
3529 '(was grafted from %d:%s)\n') %
3529 (r, repo[r], rev, ctx))
3530 (r, repo[r], rev, ctx))
3530 revs.remove(r)
3531 revs.remove(r)
3531 if not revs:
3532 if not revs:
3532 return -1
3533 return -1
3533
3534
3534 wlock = repo.wlock()
3535 wlock = repo.wlock()
3535 try:
3536 try:
3536 for pos, ctx in enumerate(repo.set("%ld", revs)):
3537 for pos, ctx in enumerate(repo.set("%ld", revs)):
3537 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3538 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3538 ctx.description().split('\n', 1)[0])
3539 ctx.description().split('\n', 1)[0])
3539 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3540 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3540 if names:
3541 if names:
3541 desc += ' (%s)' % ' '.join(names)
3542 desc += ' (%s)' % ' '.join(names)
3542 ui.status(_('grafting %s\n') % desc)
3543 ui.status(_('grafting %s\n') % desc)
3543 if opts.get('dry_run'):
3544 if opts.get('dry_run'):
3544 continue
3545 continue
3545
3546
3546 source = ctx.extra().get('source')
3547 source = ctx.extra().get('source')
3547 extra = {}
3548 extra = {}
3548 if source:
3549 if source:
3549 extra['source'] = source
3550 extra['source'] = source
3550 extra['intermediate-source'] = ctx.hex()
3551 extra['intermediate-source'] = ctx.hex()
3551 else:
3552 else:
3552 extra['source'] = ctx.hex()
3553 extra['source'] = ctx.hex()
3553 user = ctx.user()
3554 user = ctx.user()
3554 if opts.get('user'):
3555 if opts.get('user'):
3555 user = opts['user']
3556 user = opts['user']
3556 date = ctx.date()
3557 date = ctx.date()
3557 if opts.get('date'):
3558 if opts.get('date'):
3558 date = opts['date']
3559 date = opts['date']
3559 message = ctx.description()
3560 message = ctx.description()
3560 if opts.get('log'):
3561 if opts.get('log'):
3561 message += '\n(grafted from %s)' % ctx.hex()
3562 message += '\n(grafted from %s)' % ctx.hex()
3562
3563
3563 # we don't merge the first commit when continuing
3564 # we don't merge the first commit when continuing
3564 if not cont:
3565 if not cont:
3565 # perform the graft merge with p1(rev) as 'ancestor'
3566 # perform the graft merge with p1(rev) as 'ancestor'
3566 try:
3567 try:
3567 # ui.forcemerge is an internal variable, do not document
3568 # ui.forcemerge is an internal variable, do not document
3568 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3569 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3569 'graft')
3570 'graft')
3570 stats = mergemod.graft(repo, ctx, ctx.p1(),
3571 stats = mergemod.graft(repo, ctx, ctx.p1(),
3571 ['local', 'graft'])
3572 ['local', 'graft'])
3572 finally:
3573 finally:
3573 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3574 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3574 # report any conflicts
3575 # report any conflicts
3575 if stats and stats[3] > 0:
3576 if stats and stats[3] > 0:
3576 # write out state for --continue
3577 # write out state for --continue
3577 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3578 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3578 repo.vfs.write('graftstate', ''.join(nodelines))
3579 repo.vfs.write('graftstate', ''.join(nodelines))
3579 raise util.Abort(
3580 raise util.Abort(
3580 _("unresolved conflicts, can't continue"),
3581 _("unresolved conflicts, can't continue"),
3581 hint=_('use hg resolve and hg graft --continue'))
3582 hint=_('use hg resolve and hg graft --continue'))
3582 else:
3583 else:
3583 cont = False
3584 cont = False
3584
3585
3585 # commit
3586 # commit
3586 node = repo.commit(text=message, user=user,
3587 node = repo.commit(text=message, user=user,
3587 date=date, extra=extra, editor=editor)
3588 date=date, extra=extra, editor=editor)
3588 if node is None:
3589 if node is None:
3589 ui.warn(
3590 ui.warn(
3590 _('note: graft of %d:%s created no changes to commit\n') %
3591 _('note: graft of %d:%s created no changes to commit\n') %
3591 (ctx.rev(), ctx))
3592 (ctx.rev(), ctx))
3592 finally:
3593 finally:
3593 wlock.release()
3594 wlock.release()
3594
3595
3595 # remove state when we complete successfully
3596 # remove state when we complete successfully
3596 if not opts.get('dry_run'):
3597 if not opts.get('dry_run'):
3597 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3598 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3598
3599
3599 return 0
3600 return 0
3600
3601
3601 @command('grep',
3602 @command('grep',
3602 [('0', 'print0', None, _('end fields with NUL')),
3603 [('0', 'print0', None, _('end fields with NUL')),
3603 ('', 'all', None, _('print all revisions that match')),
3604 ('', 'all', None, _('print all revisions that match')),
3604 ('a', 'text', None, _('treat all files as text')),
3605 ('a', 'text', None, _('treat all files as text')),
3605 ('f', 'follow', None,
3606 ('f', 'follow', None,
3606 _('follow changeset history,'
3607 _('follow changeset history,'
3607 ' or file history across copies and renames')),
3608 ' or file history across copies and renames')),
3608 ('i', 'ignore-case', None, _('ignore case when matching')),
3609 ('i', 'ignore-case', None, _('ignore case when matching')),
3609 ('l', 'files-with-matches', None,
3610 ('l', 'files-with-matches', None,
3610 _('print only filenames and revisions that match')),
3611 _('print only filenames and revisions that match')),
3611 ('n', 'line-number', None, _('print matching line numbers')),
3612 ('n', 'line-number', None, _('print matching line numbers')),
3612 ('r', 'rev', [],
3613 ('r', 'rev', [],
3613 _('only search files changed within revision range'), _('REV')),
3614 _('only search files changed within revision range'), _('REV')),
3614 ('u', 'user', None, _('list the author (long with -v)')),
3615 ('u', 'user', None, _('list the author (long with -v)')),
3615 ('d', 'date', None, _('list the date (short with -q)')),
3616 ('d', 'date', None, _('list the date (short with -q)')),
3616 ] + walkopts,
3617 ] + walkopts,
3617 _('[OPTION]... PATTERN [FILE]...'),
3618 _('[OPTION]... PATTERN [FILE]...'),
3618 inferrepo=True)
3619 inferrepo=True)
3619 def grep(ui, repo, pattern, *pats, **opts):
3620 def grep(ui, repo, pattern, *pats, **opts):
3620 """search for a pattern in specified files and revisions
3621 """search for a pattern in specified files and revisions
3621
3622
3622 Search revisions of files for a regular expression.
3623 Search revisions of files for a regular expression.
3623
3624
3624 This command behaves differently than Unix grep. It only accepts
3625 This command behaves differently than Unix grep. It only accepts
3625 Python/Perl regexps. It searches repository history, not the
3626 Python/Perl regexps. It searches repository history, not the
3626 working directory. It always prints the revision number in which a
3627 working directory. It always prints the revision number in which a
3627 match appears.
3628 match appears.
3628
3629
3629 By default, grep only prints output for the first revision of a
3630 By default, grep only prints output for the first revision of a
3630 file in which it finds a match. To get it to print every revision
3631 file in which it finds a match. To get it to print every revision
3631 that contains a change in match status ("-" for a match that
3632 that contains a change in match status ("-" for a match that
3632 becomes a non-match, or "+" for a non-match that becomes a match),
3633 becomes a non-match, or "+" for a non-match that becomes a match),
3633 use the --all flag.
3634 use the --all flag.
3634
3635
3635 Returns 0 if a match is found, 1 otherwise.
3636 Returns 0 if a match is found, 1 otherwise.
3636 """
3637 """
3637 reflags = re.M
3638 reflags = re.M
3638 if opts.get('ignore_case'):
3639 if opts.get('ignore_case'):
3639 reflags |= re.I
3640 reflags |= re.I
3640 try:
3641 try:
3641 regexp = util.re.compile(pattern, reflags)
3642 regexp = util.re.compile(pattern, reflags)
3642 except re.error, inst:
3643 except re.error, inst:
3643 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3644 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3644 return 1
3645 return 1
3645 sep, eol = ':', '\n'
3646 sep, eol = ':', '\n'
3646 if opts.get('print0'):
3647 if opts.get('print0'):
3647 sep = eol = '\0'
3648 sep = eol = '\0'
3648
3649
3649 getfile = util.lrucachefunc(repo.file)
3650 getfile = util.lrucachefunc(repo.file)
3650
3651
3651 def matchlines(body):
3652 def matchlines(body):
3652 begin = 0
3653 begin = 0
3653 linenum = 0
3654 linenum = 0
3654 while begin < len(body):
3655 while begin < len(body):
3655 match = regexp.search(body, begin)
3656 match = regexp.search(body, begin)
3656 if not match:
3657 if not match:
3657 break
3658 break
3658 mstart, mend = match.span()
3659 mstart, mend = match.span()
3659 linenum += body.count('\n', begin, mstart) + 1
3660 linenum += body.count('\n', begin, mstart) + 1
3660 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3661 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3661 begin = body.find('\n', mend) + 1 or len(body) + 1
3662 begin = body.find('\n', mend) + 1 or len(body) + 1
3662 lend = begin - 1
3663 lend = begin - 1
3663 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3664 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3664
3665
3665 class linestate(object):
3666 class linestate(object):
3666 def __init__(self, line, linenum, colstart, colend):
3667 def __init__(self, line, linenum, colstart, colend):
3667 self.line = line
3668 self.line = line
3668 self.linenum = linenum
3669 self.linenum = linenum
3669 self.colstart = colstart
3670 self.colstart = colstart
3670 self.colend = colend
3671 self.colend = colend
3671
3672
3672 def __hash__(self):
3673 def __hash__(self):
3673 return hash((self.linenum, self.line))
3674 return hash((self.linenum, self.line))
3674
3675
3675 def __eq__(self, other):
3676 def __eq__(self, other):
3676 return self.line == other.line
3677 return self.line == other.line
3677
3678
3678 def __iter__(self):
3679 def __iter__(self):
3679 yield (self.line[:self.colstart], '')
3680 yield (self.line[:self.colstart], '')
3680 yield (self.line[self.colstart:self.colend], 'grep.match')
3681 yield (self.line[self.colstart:self.colend], 'grep.match')
3681 rest = self.line[self.colend:]
3682 rest = self.line[self.colend:]
3682 while rest != '':
3683 while rest != '':
3683 match = regexp.search(rest)
3684 match = regexp.search(rest)
3684 if not match:
3685 if not match:
3685 yield (rest, '')
3686 yield (rest, '')
3686 break
3687 break
3687 mstart, mend = match.span()
3688 mstart, mend = match.span()
3688 yield (rest[:mstart], '')
3689 yield (rest[:mstart], '')
3689 yield (rest[mstart:mend], 'grep.match')
3690 yield (rest[mstart:mend], 'grep.match')
3690 rest = rest[mend:]
3691 rest = rest[mend:]
3691
3692
3692 matches = {}
3693 matches = {}
3693 copies = {}
3694 copies = {}
3694 def grepbody(fn, rev, body):
3695 def grepbody(fn, rev, body):
3695 matches[rev].setdefault(fn, [])
3696 matches[rev].setdefault(fn, [])
3696 m = matches[rev][fn]
3697 m = matches[rev][fn]
3697 for lnum, cstart, cend, line in matchlines(body):
3698 for lnum, cstart, cend, line in matchlines(body):
3698 s = linestate(line, lnum, cstart, cend)
3699 s = linestate(line, lnum, cstart, cend)
3699 m.append(s)
3700 m.append(s)
3700
3701
3701 def difflinestates(a, b):
3702 def difflinestates(a, b):
3702 sm = difflib.SequenceMatcher(None, a, b)
3703 sm = difflib.SequenceMatcher(None, a, b)
3703 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3704 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3704 if tag == 'insert':
3705 if tag == 'insert':
3705 for i in xrange(blo, bhi):
3706 for i in xrange(blo, bhi):
3706 yield ('+', b[i])
3707 yield ('+', b[i])
3707 elif tag == 'delete':
3708 elif tag == 'delete':
3708 for i in xrange(alo, ahi):
3709 for i in xrange(alo, ahi):
3709 yield ('-', a[i])
3710 yield ('-', a[i])
3710 elif tag == 'replace':
3711 elif tag == 'replace':
3711 for i in xrange(alo, ahi):
3712 for i in xrange(alo, ahi):
3712 yield ('-', a[i])
3713 yield ('-', a[i])
3713 for i in xrange(blo, bhi):
3714 for i in xrange(blo, bhi):
3714 yield ('+', b[i])
3715 yield ('+', b[i])
3715
3716
3716 def display(fn, ctx, pstates, states):
3717 def display(fn, ctx, pstates, states):
3717 rev = ctx.rev()
3718 rev = ctx.rev()
3718 if ui.quiet:
3719 if ui.quiet:
3719 datefunc = util.shortdate
3720 datefunc = util.shortdate
3720 else:
3721 else:
3721 datefunc = util.datestr
3722 datefunc = util.datestr
3722 found = False
3723 found = False
3723 @util.cachefunc
3724 @util.cachefunc
3724 def binary():
3725 def binary():
3725 flog = getfile(fn)
3726 flog = getfile(fn)
3726 return util.binary(flog.read(ctx.filenode(fn)))
3727 return util.binary(flog.read(ctx.filenode(fn)))
3727
3728
3728 if opts.get('all'):
3729 if opts.get('all'):
3729 iter = difflinestates(pstates, states)
3730 iter = difflinestates(pstates, states)
3730 else:
3731 else:
3731 iter = [('', l) for l in states]
3732 iter = [('', l) for l in states]
3732 for change, l in iter:
3733 for change, l in iter:
3733 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3734 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3734
3735
3735 if opts.get('line_number'):
3736 if opts.get('line_number'):
3736 cols.append((str(l.linenum), 'grep.linenumber'))
3737 cols.append((str(l.linenum), 'grep.linenumber'))
3737 if opts.get('all'):
3738 if opts.get('all'):
3738 cols.append((change, 'grep.change'))
3739 cols.append((change, 'grep.change'))
3739 if opts.get('user'):
3740 if opts.get('user'):
3740 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3741 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3741 if opts.get('date'):
3742 if opts.get('date'):
3742 cols.append((datefunc(ctx.date()), 'grep.date'))
3743 cols.append((datefunc(ctx.date()), 'grep.date'))
3743 for col, label in cols[:-1]:
3744 for col, label in cols[:-1]:
3744 ui.write(col, label=label)
3745 ui.write(col, label=label)
3745 ui.write(sep, label='grep.sep')
3746 ui.write(sep, label='grep.sep')
3746 ui.write(cols[-1][0], label=cols[-1][1])
3747 ui.write(cols[-1][0], label=cols[-1][1])
3747 if not opts.get('files_with_matches'):
3748 if not opts.get('files_with_matches'):
3748 ui.write(sep, label='grep.sep')
3749 ui.write(sep, label='grep.sep')
3749 if not opts.get('text') and binary():
3750 if not opts.get('text') and binary():
3750 ui.write(" Binary file matches")
3751 ui.write(" Binary file matches")
3751 else:
3752 else:
3752 for s, label in l:
3753 for s, label in l:
3753 ui.write(s, label=label)
3754 ui.write(s, label=label)
3754 ui.write(eol)
3755 ui.write(eol)
3755 found = True
3756 found = True
3756 if opts.get('files_with_matches'):
3757 if opts.get('files_with_matches'):
3757 break
3758 break
3758 return found
3759 return found
3759
3760
3760 skip = {}
3761 skip = {}
3761 revfiles = {}
3762 revfiles = {}
3762 matchfn = scmutil.match(repo[None], pats, opts)
3763 matchfn = scmutil.match(repo[None], pats, opts)
3763 found = False
3764 found = False
3764 follow = opts.get('follow')
3765 follow = opts.get('follow')
3765
3766
3766 def prep(ctx, fns):
3767 def prep(ctx, fns):
3767 rev = ctx.rev()
3768 rev = ctx.rev()
3768 pctx = ctx.p1()
3769 pctx = ctx.p1()
3769 parent = pctx.rev()
3770 parent = pctx.rev()
3770 matches.setdefault(rev, {})
3771 matches.setdefault(rev, {})
3771 matches.setdefault(parent, {})
3772 matches.setdefault(parent, {})
3772 files = revfiles.setdefault(rev, [])
3773 files = revfiles.setdefault(rev, [])
3773 for fn in fns:
3774 for fn in fns:
3774 flog = getfile(fn)
3775 flog = getfile(fn)
3775 try:
3776 try:
3776 fnode = ctx.filenode(fn)
3777 fnode = ctx.filenode(fn)
3777 except error.LookupError:
3778 except error.LookupError:
3778 continue
3779 continue
3779
3780
3780 copied = flog.renamed(fnode)
3781 copied = flog.renamed(fnode)
3781 copy = follow and copied and copied[0]
3782 copy = follow and copied and copied[0]
3782 if copy:
3783 if copy:
3783 copies.setdefault(rev, {})[fn] = copy
3784 copies.setdefault(rev, {})[fn] = copy
3784 if fn in skip:
3785 if fn in skip:
3785 if copy:
3786 if copy:
3786 skip[copy] = True
3787 skip[copy] = True
3787 continue
3788 continue
3788 files.append(fn)
3789 files.append(fn)
3789
3790
3790 if fn not in matches[rev]:
3791 if fn not in matches[rev]:
3791 grepbody(fn, rev, flog.read(fnode))
3792 grepbody(fn, rev, flog.read(fnode))
3792
3793
3793 pfn = copy or fn
3794 pfn = copy or fn
3794 if pfn not in matches[parent]:
3795 if pfn not in matches[parent]:
3795 try:
3796 try:
3796 fnode = pctx.filenode(pfn)
3797 fnode = pctx.filenode(pfn)
3797 grepbody(pfn, parent, flog.read(fnode))
3798 grepbody(pfn, parent, flog.read(fnode))
3798 except error.LookupError:
3799 except error.LookupError:
3799 pass
3800 pass
3800
3801
3801 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3802 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3802 rev = ctx.rev()
3803 rev = ctx.rev()
3803 parent = ctx.p1().rev()
3804 parent = ctx.p1().rev()
3804 for fn in sorted(revfiles.get(rev, [])):
3805 for fn in sorted(revfiles.get(rev, [])):
3805 states = matches[rev][fn]
3806 states = matches[rev][fn]
3806 copy = copies.get(rev, {}).get(fn)
3807 copy = copies.get(rev, {}).get(fn)
3807 if fn in skip:
3808 if fn in skip:
3808 if copy:
3809 if copy:
3809 skip[copy] = True
3810 skip[copy] = True
3810 continue
3811 continue
3811 pstates = matches.get(parent, {}).get(copy or fn, [])
3812 pstates = matches.get(parent, {}).get(copy or fn, [])
3812 if pstates or states:
3813 if pstates or states:
3813 r = display(fn, ctx, pstates, states)
3814 r = display(fn, ctx, pstates, states)
3814 found = found or r
3815 found = found or r
3815 if r and not opts.get('all'):
3816 if r and not opts.get('all'):
3816 skip[fn] = True
3817 skip[fn] = True
3817 if copy:
3818 if copy:
3818 skip[copy] = True
3819 skip[copy] = True
3819 del matches[rev]
3820 del matches[rev]
3820 del revfiles[rev]
3821 del revfiles[rev]
3821
3822
3822 return not found
3823 return not found
3823
3824
3824 @command('heads',
3825 @command('heads',
3825 [('r', 'rev', '',
3826 [('r', 'rev', '',
3826 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3827 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3827 ('t', 'topo', False, _('show topological heads only')),
3828 ('t', 'topo', False, _('show topological heads only')),
3828 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3829 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3829 ('c', 'closed', False, _('show normal and closed branch heads')),
3830 ('c', 'closed', False, _('show normal and closed branch heads')),
3830 ] + templateopts,
3831 ] + templateopts,
3831 _('[-ct] [-r STARTREV] [REV]...'))
3832 _('[-ct] [-r STARTREV] [REV]...'))
3832 def heads(ui, repo, *branchrevs, **opts):
3833 def heads(ui, repo, *branchrevs, **opts):
3833 """show branch heads
3834 """show branch heads
3834
3835
3835 With no arguments, show all open branch heads in the repository.
3836 With no arguments, show all open branch heads in the repository.
3836 Branch heads are changesets that have no descendants on the
3837 Branch heads are changesets that have no descendants on the
3837 same branch. They are where development generally takes place and
3838 same branch. They are where development generally takes place and
3838 are the usual targets for update and merge operations.
3839 are the usual targets for update and merge operations.
3839
3840
3840 If one or more REVs are given, only open branch heads on the
3841 If one or more REVs are given, only open branch heads on the
3841 branches associated with the specified changesets are shown. This
3842 branches associated with the specified changesets are shown. This
3842 means that you can use :hg:`heads .` to see the heads on the
3843 means that you can use :hg:`heads .` to see the heads on the
3843 currently checked-out branch.
3844 currently checked-out branch.
3844
3845
3845 If -c/--closed is specified, also show branch heads marked closed
3846 If -c/--closed is specified, also show branch heads marked closed
3846 (see :hg:`commit --close-branch`).
3847 (see :hg:`commit --close-branch`).
3847
3848
3848 If STARTREV is specified, only those heads that are descendants of
3849 If STARTREV is specified, only those heads that are descendants of
3849 STARTREV will be displayed.
3850 STARTREV will be displayed.
3850
3851
3851 If -t/--topo is specified, named branch mechanics will be ignored and only
3852 If -t/--topo is specified, named branch mechanics will be ignored and only
3852 topological heads (changesets with no children) will be shown.
3853 topological heads (changesets with no children) will be shown.
3853
3854
3854 Returns 0 if matching heads are found, 1 if not.
3855 Returns 0 if matching heads are found, 1 if not.
3855 """
3856 """
3856
3857
3857 start = None
3858 start = None
3858 if 'rev' in opts:
3859 if 'rev' in opts:
3859 start = scmutil.revsingle(repo, opts['rev'], None).node()
3860 start = scmutil.revsingle(repo, opts['rev'], None).node()
3860
3861
3861 if opts.get('topo'):
3862 if opts.get('topo'):
3862 heads = [repo[h] for h in repo.heads(start)]
3863 heads = [repo[h] for h in repo.heads(start)]
3863 else:
3864 else:
3864 heads = []
3865 heads = []
3865 for branch in repo.branchmap():
3866 for branch in repo.branchmap():
3866 heads += repo.branchheads(branch, start, opts.get('closed'))
3867 heads += repo.branchheads(branch, start, opts.get('closed'))
3867 heads = [repo[h] for h in heads]
3868 heads = [repo[h] for h in heads]
3868
3869
3869 if branchrevs:
3870 if branchrevs:
3870 branches = set(repo[br].branch() for br in branchrevs)
3871 branches = set(repo[br].branch() for br in branchrevs)
3871 heads = [h for h in heads if h.branch() in branches]
3872 heads = [h for h in heads if h.branch() in branches]
3872
3873
3873 if opts.get('active') and branchrevs:
3874 if opts.get('active') and branchrevs:
3874 dagheads = repo.heads(start)
3875 dagheads = repo.heads(start)
3875 heads = [h for h in heads if h.node() in dagheads]
3876 heads = [h for h in heads if h.node() in dagheads]
3876
3877
3877 if branchrevs:
3878 if branchrevs:
3878 haveheads = set(h.branch() for h in heads)
3879 haveheads = set(h.branch() for h in heads)
3879 if branches - haveheads:
3880 if branches - haveheads:
3880 headless = ', '.join(b for b in branches - haveheads)
3881 headless = ', '.join(b for b in branches - haveheads)
3881 msg = _('no open branch heads found on branches %s')
3882 msg = _('no open branch heads found on branches %s')
3882 if opts.get('rev'):
3883 if opts.get('rev'):
3883 msg += _(' (started at %s)') % opts['rev']
3884 msg += _(' (started at %s)') % opts['rev']
3884 ui.warn((msg + '\n') % headless)
3885 ui.warn((msg + '\n') % headless)
3885
3886
3886 if not heads:
3887 if not heads:
3887 return 1
3888 return 1
3888
3889
3889 heads = sorted(heads, key=lambda x: -x.rev())
3890 heads = sorted(heads, key=lambda x: -x.rev())
3890 displayer = cmdutil.show_changeset(ui, repo, opts)
3891 displayer = cmdutil.show_changeset(ui, repo, opts)
3891 for ctx in heads:
3892 for ctx in heads:
3892 displayer.show(ctx)
3893 displayer.show(ctx)
3893 displayer.close()
3894 displayer.close()
3894
3895
3895 @command('help',
3896 @command('help',
3896 [('e', 'extension', None, _('show only help for extensions')),
3897 [('e', 'extension', None, _('show only help for extensions')),
3897 ('c', 'command', None, _('show only help for commands')),
3898 ('c', 'command', None, _('show only help for commands')),
3898 ('k', 'keyword', '', _('show topics matching keyword')),
3899 ('k', 'keyword', '', _('show topics matching keyword')),
3899 ],
3900 ],
3900 _('[-ec] [TOPIC]'),
3901 _('[-ec] [TOPIC]'),
3901 norepo=True)
3902 norepo=True)
3902 def help_(ui, name=None, **opts):
3903 def help_(ui, name=None, **opts):
3903 """show help for a given topic or a help overview
3904 """show help for a given topic or a help overview
3904
3905
3905 With no arguments, print a list of commands with short help messages.
3906 With no arguments, print a list of commands with short help messages.
3906
3907
3907 Given a topic, extension, or command name, print help for that
3908 Given a topic, extension, or command name, print help for that
3908 topic.
3909 topic.
3909
3910
3910 Returns 0 if successful.
3911 Returns 0 if successful.
3911 """
3912 """
3912
3913
3913 textwidth = min(ui.termwidth(), 80) - 2
3914 textwidth = min(ui.termwidth(), 80) - 2
3914
3915
3915 keep = []
3916 keep = []
3916 if ui.verbose:
3917 if ui.verbose:
3917 keep.append('verbose')
3918 keep.append('verbose')
3918 if sys.platform.startswith('win'):
3919 if sys.platform.startswith('win'):
3919 keep.append('windows')
3920 keep.append('windows')
3920 elif sys.platform == 'OpenVMS':
3921 elif sys.platform == 'OpenVMS':
3921 keep.append('vms')
3922 keep.append('vms')
3922 elif sys.platform == 'plan9':
3923 elif sys.platform == 'plan9':
3923 keep.append('plan9')
3924 keep.append('plan9')
3924 else:
3925 else:
3925 keep.append('unix')
3926 keep.append('unix')
3926 keep.append(sys.platform.lower())
3927 keep.append(sys.platform.lower())
3927
3928
3928 section = None
3929 section = None
3929 if name and '.' in name:
3930 if name and '.' in name:
3930 name, section = name.split('.', 1)
3931 name, section = name.split('.', 1)
3931
3932
3932 text = help.help_(ui, name, **opts)
3933 text = help.help_(ui, name, **opts)
3933
3934
3934 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3935 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3935 section=section)
3936 section=section)
3936 if section and not formatted:
3937 if section and not formatted:
3937 raise util.Abort(_("help section not found"))
3938 raise util.Abort(_("help section not found"))
3938
3939
3939 if 'verbose' in pruned:
3940 if 'verbose' in pruned:
3940 keep.append('omitted')
3941 keep.append('omitted')
3941 else:
3942 else:
3942 keep.append('notomitted')
3943 keep.append('notomitted')
3943 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3944 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3944 section=section)
3945 section=section)
3945 ui.write(formatted)
3946 ui.write(formatted)
3946
3947
3947
3948
3948 @command('identify|id',
3949 @command('identify|id',
3949 [('r', 'rev', '',
3950 [('r', 'rev', '',
3950 _('identify the specified revision'), _('REV')),
3951 _('identify the specified revision'), _('REV')),
3951 ('n', 'num', None, _('show local revision number')),
3952 ('n', 'num', None, _('show local revision number')),
3952 ('i', 'id', None, _('show global revision id')),
3953 ('i', 'id', None, _('show global revision id')),
3953 ('b', 'branch', None, _('show branch')),
3954 ('b', 'branch', None, _('show branch')),
3954 ('t', 'tags', None, _('show tags')),
3955 ('t', 'tags', None, _('show tags')),
3955 ('B', 'bookmarks', None, _('show bookmarks')),
3956 ('B', 'bookmarks', None, _('show bookmarks')),
3956 ] + remoteopts,
3957 ] + remoteopts,
3957 _('[-nibtB] [-r REV] [SOURCE]'),
3958 _('[-nibtB] [-r REV] [SOURCE]'),
3958 optionalrepo=True)
3959 optionalrepo=True)
3959 def identify(ui, repo, source=None, rev=None,
3960 def identify(ui, repo, source=None, rev=None,
3960 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3961 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3961 """identify the working directory or specified revision
3962 """identify the working directory or specified revision
3962
3963
3963 Print a summary identifying the repository state at REV using one or
3964 Print a summary identifying the repository state at REV using one or
3964 two parent hash identifiers, followed by a "+" if the working
3965 two parent hash identifiers, followed by a "+" if the working
3965 directory has uncommitted changes, the branch name (if not default),
3966 directory has uncommitted changes, the branch name (if not default),
3966 a list of tags, and a list of bookmarks.
3967 a list of tags, and a list of bookmarks.
3967
3968
3968 When REV is not given, print a summary of the current state of the
3969 When REV is not given, print a summary of the current state of the
3969 repository.
3970 repository.
3970
3971
3971 Specifying a path to a repository root or Mercurial bundle will
3972 Specifying a path to a repository root or Mercurial bundle will
3972 cause lookup to operate on that repository/bundle.
3973 cause lookup to operate on that repository/bundle.
3973
3974
3974 .. container:: verbose
3975 .. container:: verbose
3975
3976
3976 Examples:
3977 Examples:
3977
3978
3978 - generate a build identifier for the working directory::
3979 - generate a build identifier for the working directory::
3979
3980
3980 hg id --id > build-id.dat
3981 hg id --id > build-id.dat
3981
3982
3982 - find the revision corresponding to a tag::
3983 - find the revision corresponding to a tag::
3983
3984
3984 hg id -n -r 1.3
3985 hg id -n -r 1.3
3985
3986
3986 - check the most recent revision of a remote repository::
3987 - check the most recent revision of a remote repository::
3987
3988
3988 hg id -r tip http://selenic.com/hg/
3989 hg id -r tip http://selenic.com/hg/
3989
3990
3990 Returns 0 if successful.
3991 Returns 0 if successful.
3991 """
3992 """
3992
3993
3993 if not repo and not source:
3994 if not repo and not source:
3994 raise util.Abort(_("there is no Mercurial repository here "
3995 raise util.Abort(_("there is no Mercurial repository here "
3995 "(.hg not found)"))
3996 "(.hg not found)"))
3996
3997
3997 if ui.debugflag:
3998 if ui.debugflag:
3998 hexfunc = hex
3999 hexfunc = hex
3999 else:
4000 else:
4000 hexfunc = short
4001 hexfunc = short
4001 default = not (num or id or branch or tags or bookmarks)
4002 default = not (num or id or branch or tags or bookmarks)
4002 output = []
4003 output = []
4003 revs = []
4004 revs = []
4004
4005
4005 if source:
4006 if source:
4006 source, branches = hg.parseurl(ui.expandpath(source))
4007 source, branches = hg.parseurl(ui.expandpath(source))
4007 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4008 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4008 repo = peer.local()
4009 repo = peer.local()
4009 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4010 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4010
4011
4011 if not repo:
4012 if not repo:
4012 if num or branch or tags:
4013 if num or branch or tags:
4013 raise util.Abort(
4014 raise util.Abort(
4014 _("can't query remote revision number, branch, or tags"))
4015 _("can't query remote revision number, branch, or tags"))
4015 if not rev and revs:
4016 if not rev and revs:
4016 rev = revs[0]
4017 rev = revs[0]
4017 if not rev:
4018 if not rev:
4018 rev = "tip"
4019 rev = "tip"
4019
4020
4020 remoterev = peer.lookup(rev)
4021 remoterev = peer.lookup(rev)
4021 if default or id:
4022 if default or id:
4022 output = [hexfunc(remoterev)]
4023 output = [hexfunc(remoterev)]
4023
4024
4024 def getbms():
4025 def getbms():
4025 bms = []
4026 bms = []
4026
4027
4027 if 'bookmarks' in peer.listkeys('namespaces'):
4028 if 'bookmarks' in peer.listkeys('namespaces'):
4028 hexremoterev = hex(remoterev)
4029 hexremoterev = hex(remoterev)
4029 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4030 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4030 if bmr == hexremoterev]
4031 if bmr == hexremoterev]
4031
4032
4032 return sorted(bms)
4033 return sorted(bms)
4033
4034
4034 if bookmarks:
4035 if bookmarks:
4035 output.extend(getbms())
4036 output.extend(getbms())
4036 elif default and not ui.quiet:
4037 elif default and not ui.quiet:
4037 # multiple bookmarks for a single parent separated by '/'
4038 # multiple bookmarks for a single parent separated by '/'
4038 bm = '/'.join(getbms())
4039 bm = '/'.join(getbms())
4039 if bm:
4040 if bm:
4040 output.append(bm)
4041 output.append(bm)
4041 else:
4042 else:
4042 if not rev:
4043 if not rev:
4043 ctx = repo[None]
4044 ctx = repo[None]
4044 parents = ctx.parents()
4045 parents = ctx.parents()
4045 changed = ""
4046 changed = ""
4046 if default or id or num:
4047 if default or id or num:
4047 if (util.any(repo.status())
4048 if (util.any(repo.status())
4048 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
4049 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
4049 changed = '+'
4050 changed = '+'
4050 if default or id:
4051 if default or id:
4051 output = ["%s%s" %
4052 output = ["%s%s" %
4052 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4053 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4053 if num:
4054 if num:
4054 output.append("%s%s" %
4055 output.append("%s%s" %
4055 ('+'.join([str(p.rev()) for p in parents]), changed))
4056 ('+'.join([str(p.rev()) for p in parents]), changed))
4056 else:
4057 else:
4057 ctx = scmutil.revsingle(repo, rev)
4058 ctx = scmutil.revsingle(repo, rev)
4058 if default or id:
4059 if default or id:
4059 output = [hexfunc(ctx.node())]
4060 output = [hexfunc(ctx.node())]
4060 if num:
4061 if num:
4061 output.append(str(ctx.rev()))
4062 output.append(str(ctx.rev()))
4062
4063
4063 if default and not ui.quiet:
4064 if default and not ui.quiet:
4064 b = ctx.branch()
4065 b = ctx.branch()
4065 if b != 'default':
4066 if b != 'default':
4066 output.append("(%s)" % b)
4067 output.append("(%s)" % b)
4067
4068
4068 # multiple tags for a single parent separated by '/'
4069 # multiple tags for a single parent separated by '/'
4069 t = '/'.join(ctx.tags())
4070 t = '/'.join(ctx.tags())
4070 if t:
4071 if t:
4071 output.append(t)
4072 output.append(t)
4072
4073
4073 # multiple bookmarks for a single parent separated by '/'
4074 # multiple bookmarks for a single parent separated by '/'
4074 bm = '/'.join(ctx.bookmarks())
4075 bm = '/'.join(ctx.bookmarks())
4075 if bm:
4076 if bm:
4076 output.append(bm)
4077 output.append(bm)
4077 else:
4078 else:
4078 if branch:
4079 if branch:
4079 output.append(ctx.branch())
4080 output.append(ctx.branch())
4080
4081
4081 if tags:
4082 if tags:
4082 output.extend(ctx.tags())
4083 output.extend(ctx.tags())
4083
4084
4084 if bookmarks:
4085 if bookmarks:
4085 output.extend(ctx.bookmarks())
4086 output.extend(ctx.bookmarks())
4086
4087
4087 ui.write("%s\n" % ' '.join(output))
4088 ui.write("%s\n" % ' '.join(output))
4088
4089
4089 @command('import|patch',
4090 @command('import|patch',
4090 [('p', 'strip', 1,
4091 [('p', 'strip', 1,
4091 _('directory strip option for patch. This has the same '
4092 _('directory strip option for patch. This has the same '
4092 'meaning as the corresponding patch option'), _('NUM')),
4093 'meaning as the corresponding patch option'), _('NUM')),
4093 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4094 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4094 ('e', 'edit', False, _('invoke editor on commit messages')),
4095 ('e', 'edit', False, _('invoke editor on commit messages')),
4095 ('f', 'force', None,
4096 ('f', 'force', None,
4096 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4097 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4097 ('', 'no-commit', None,
4098 ('', 'no-commit', None,
4098 _("don't commit, just update the working directory")),
4099 _("don't commit, just update the working directory")),
4099 ('', 'bypass', None,
4100 ('', 'bypass', None,
4100 _("apply patch without touching the working directory")),
4101 _("apply patch without touching the working directory")),
4101 ('', 'partial', None,
4102 ('', 'partial', None,
4102 _('commit even if some hunks fail')),
4103 _('commit even if some hunks fail')),
4103 ('', 'exact', None,
4104 ('', 'exact', None,
4104 _('apply patch to the nodes from which it was generated')),
4105 _('apply patch to the nodes from which it was generated')),
4105 ('', 'prefix', '',
4106 ('', 'prefix', '',
4106 _('apply patch to subdirectory'), _('DIR')),
4107 _('apply patch to subdirectory'), _('DIR')),
4107 ('', 'import-branch', None,
4108 ('', 'import-branch', None,
4108 _('use any branch information in patch (implied by --exact)'))] +
4109 _('use any branch information in patch (implied by --exact)'))] +
4109 commitopts + commitopts2 + similarityopts,
4110 commitopts + commitopts2 + similarityopts,
4110 _('[OPTION]... PATCH...'))
4111 _('[OPTION]... PATCH...'))
4111 def import_(ui, repo, patch1=None, *patches, **opts):
4112 def import_(ui, repo, patch1=None, *patches, **opts):
4112 """import an ordered set of patches
4113 """import an ordered set of patches
4113
4114
4114 Import a list of patches and commit them individually (unless
4115 Import a list of patches and commit them individually (unless
4115 --no-commit is specified).
4116 --no-commit is specified).
4116
4117
4117 Because import first applies changes to the working directory,
4118 Because import first applies changes to the working directory,
4118 import will abort if there are outstanding changes.
4119 import will abort if there are outstanding changes.
4119
4120
4120 You can import a patch straight from a mail message. Even patches
4121 You can import a patch straight from a mail message. Even patches
4121 as attachments work (to use the body part, it must have type
4122 as attachments work (to use the body part, it must have type
4122 text/plain or text/x-patch). From and Subject headers of email
4123 text/plain or text/x-patch). From and Subject headers of email
4123 message are used as default committer and commit message. All
4124 message are used as default committer and commit message. All
4124 text/plain body parts before first diff are added to commit
4125 text/plain body parts before first diff are added to commit
4125 message.
4126 message.
4126
4127
4127 If the imported patch was generated by :hg:`export`, user and
4128 If the imported patch was generated by :hg:`export`, user and
4128 description from patch override values from message headers and
4129 description from patch override values from message headers and
4129 body. Values given on command line with -m/--message and -u/--user
4130 body. Values given on command line with -m/--message and -u/--user
4130 override these.
4131 override these.
4131
4132
4132 If --exact is specified, import will set the working directory to
4133 If --exact is specified, import will set the working directory to
4133 the parent of each patch before applying it, and will abort if the
4134 the parent of each patch before applying it, and will abort if the
4134 resulting changeset has a different ID than the one recorded in
4135 resulting changeset has a different ID than the one recorded in
4135 the patch. This may happen due to character set problems or other
4136 the patch. This may happen due to character set problems or other
4136 deficiencies in the text patch format.
4137 deficiencies in the text patch format.
4137
4138
4138 Use --bypass to apply and commit patches directly to the
4139 Use --bypass to apply and commit patches directly to the
4139 repository, not touching the working directory. Without --exact,
4140 repository, not touching the working directory. Without --exact,
4140 patches will be applied on top of the working directory parent
4141 patches will be applied on top of the working directory parent
4141 revision.
4142 revision.
4142
4143
4143 With -s/--similarity, hg will attempt to discover renames and
4144 With -s/--similarity, hg will attempt to discover renames and
4144 copies in the patch in the same way as :hg:`addremove`.
4145 copies in the patch in the same way as :hg:`addremove`.
4145
4146
4146 Use --partial to ensure a changeset will be created from the patch
4147 Use --partial to ensure a changeset will be created from the patch
4147 even if some hunks fail to apply. Hunks that fail to apply will be
4148 even if some hunks fail to apply. Hunks that fail to apply will be
4148 written to a <target-file>.rej file. Conflicts can then be resolved
4149 written to a <target-file>.rej file. Conflicts can then be resolved
4149 by hand before :hg:`commit --amend` is run to update the created
4150 by hand before :hg:`commit --amend` is run to update the created
4150 changeset. This flag exists to let people import patches that
4151 changeset. This flag exists to let people import patches that
4151 partially apply without losing the associated metadata (author,
4152 partially apply without losing the associated metadata (author,
4152 date, description, ...). Note that when none of the hunk applies
4153 date, description, ...). Note that when none of the hunk applies
4153 cleanly, :hg:`import --partial` will create an empty changeset,
4154 cleanly, :hg:`import --partial` will create an empty changeset,
4154 importing only the patch metadata.
4155 importing only the patch metadata.
4155
4156
4156 To read a patch from standard input, use "-" as the patch name. If
4157 To read a patch from standard input, use "-" as the patch name. If
4157 a URL is specified, the patch will be downloaded from it.
4158 a URL is specified, the patch will be downloaded from it.
4158 See :hg:`help dates` for a list of formats valid for -d/--date.
4159 See :hg:`help dates` for a list of formats valid for -d/--date.
4159
4160
4160 .. container:: verbose
4161 .. container:: verbose
4161
4162
4162 Examples:
4163 Examples:
4163
4164
4164 - import a traditional patch from a website and detect renames::
4165 - import a traditional patch from a website and detect renames::
4165
4166
4166 hg import -s 80 http://example.com/bugfix.patch
4167 hg import -s 80 http://example.com/bugfix.patch
4167
4168
4168 - import a changeset from an hgweb server::
4169 - import a changeset from an hgweb server::
4169
4170
4170 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4171 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4171
4172
4172 - import all the patches in an Unix-style mbox::
4173 - import all the patches in an Unix-style mbox::
4173
4174
4174 hg import incoming-patches.mbox
4175 hg import incoming-patches.mbox
4175
4176
4176 - attempt to exactly restore an exported changeset (not always
4177 - attempt to exactly restore an exported changeset (not always
4177 possible)::
4178 possible)::
4178
4179
4179 hg import --exact proposed-fix.patch
4180 hg import --exact proposed-fix.patch
4180
4181
4181 Returns 0 on success, 1 on partial success (see --partial).
4182 Returns 0 on success, 1 on partial success (see --partial).
4182 """
4183 """
4183
4184
4184 if not patch1:
4185 if not patch1:
4185 raise util.Abort(_('need at least one patch to import'))
4186 raise util.Abort(_('need at least one patch to import'))
4186
4187
4187 patches = (patch1,) + patches
4188 patches = (patch1,) + patches
4188
4189
4189 date = opts.get('date')
4190 date = opts.get('date')
4190 if date:
4191 if date:
4191 opts['date'] = util.parsedate(date)
4192 opts['date'] = util.parsedate(date)
4192
4193
4193 update = not opts.get('bypass')
4194 update = not opts.get('bypass')
4194 if not update and opts.get('no_commit'):
4195 if not update and opts.get('no_commit'):
4195 raise util.Abort(_('cannot use --no-commit with --bypass'))
4196 raise util.Abort(_('cannot use --no-commit with --bypass'))
4196 try:
4197 try:
4197 sim = float(opts.get('similarity') or 0)
4198 sim = float(opts.get('similarity') or 0)
4198 except ValueError:
4199 except ValueError:
4199 raise util.Abort(_('similarity must be a number'))
4200 raise util.Abort(_('similarity must be a number'))
4200 if sim < 0 or sim > 100:
4201 if sim < 0 or sim > 100:
4201 raise util.Abort(_('similarity must be between 0 and 100'))
4202 raise util.Abort(_('similarity must be between 0 and 100'))
4202 if sim and not update:
4203 if sim and not update:
4203 raise util.Abort(_('cannot use --similarity with --bypass'))
4204 raise util.Abort(_('cannot use --similarity with --bypass'))
4204 if opts.get('exact') and opts.get('edit'):
4205 if opts.get('exact') and opts.get('edit'):
4205 raise util.Abort(_('cannot use --exact with --edit'))
4206 raise util.Abort(_('cannot use --exact with --edit'))
4206 if opts.get('exact') and opts.get('prefix'):
4207 if opts.get('exact') and opts.get('prefix'):
4207 raise util.Abort(_('cannot use --exact with --prefix'))
4208 raise util.Abort(_('cannot use --exact with --prefix'))
4208
4209
4209 if update:
4210 if update:
4210 cmdutil.checkunfinished(repo)
4211 cmdutil.checkunfinished(repo)
4211 if (opts.get('exact') or not opts.get('force')) and update:
4212 if (opts.get('exact') or not opts.get('force')) and update:
4212 cmdutil.bailifchanged(repo)
4213 cmdutil.bailifchanged(repo)
4213
4214
4214 base = opts["base"]
4215 base = opts["base"]
4215 wlock = lock = tr = None
4216 wlock = lock = tr = None
4216 msgs = []
4217 msgs = []
4217 ret = 0
4218 ret = 0
4218
4219
4219
4220
4220 try:
4221 try:
4221 try:
4222 try:
4222 wlock = repo.wlock()
4223 wlock = repo.wlock()
4223 repo.dirstate.beginparentchange()
4224 repo.dirstate.beginparentchange()
4224 if not opts.get('no_commit'):
4225 if not opts.get('no_commit'):
4225 lock = repo.lock()
4226 lock = repo.lock()
4226 tr = repo.transaction('import')
4227 tr = repo.transaction('import')
4227 parents = repo.parents()
4228 parents = repo.parents()
4228 for patchurl in patches:
4229 for patchurl in patches:
4229 if patchurl == '-':
4230 if patchurl == '-':
4230 ui.status(_('applying patch from stdin\n'))
4231 ui.status(_('applying patch from stdin\n'))
4231 patchfile = ui.fin
4232 patchfile = ui.fin
4232 patchurl = 'stdin' # for error message
4233 patchurl = 'stdin' # for error message
4233 else:
4234 else:
4234 patchurl = os.path.join(base, patchurl)
4235 patchurl = os.path.join(base, patchurl)
4235 ui.status(_('applying %s\n') % patchurl)
4236 ui.status(_('applying %s\n') % patchurl)
4236 patchfile = hg.openpath(ui, patchurl)
4237 patchfile = hg.openpath(ui, patchurl)
4237
4238
4238 haspatch = False
4239 haspatch = False
4239 for hunk in patch.split(patchfile):
4240 for hunk in patch.split(patchfile):
4240 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4241 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4241 parents, opts,
4242 parents, opts,
4242 msgs, hg.clean)
4243 msgs, hg.clean)
4243 if msg:
4244 if msg:
4244 haspatch = True
4245 haspatch = True
4245 ui.note(msg + '\n')
4246 ui.note(msg + '\n')
4246 if update or opts.get('exact'):
4247 if update or opts.get('exact'):
4247 parents = repo.parents()
4248 parents = repo.parents()
4248 else:
4249 else:
4249 parents = [repo[node]]
4250 parents = [repo[node]]
4250 if rej:
4251 if rej:
4251 ui.write_err(_("patch applied partially\n"))
4252 ui.write_err(_("patch applied partially\n"))
4252 ui.write_err(_("(fix the .rej files and run "
4253 ui.write_err(_("(fix the .rej files and run "
4253 "`hg commit --amend`)\n"))
4254 "`hg commit --amend`)\n"))
4254 ret = 1
4255 ret = 1
4255 break
4256 break
4256
4257
4257 if not haspatch:
4258 if not haspatch:
4258 raise util.Abort(_('%s: no diffs found') % patchurl)
4259 raise util.Abort(_('%s: no diffs found') % patchurl)
4259
4260
4260 if tr:
4261 if tr:
4261 tr.close()
4262 tr.close()
4262 if msgs:
4263 if msgs:
4263 repo.savecommitmessage('\n* * *\n'.join(msgs))
4264 repo.savecommitmessage('\n* * *\n'.join(msgs))
4264 repo.dirstate.endparentchange()
4265 repo.dirstate.endparentchange()
4265 return ret
4266 return ret
4266 except: # re-raises
4267 except: # re-raises
4267 # wlock.release() indirectly calls dirstate.write(): since
4268 # wlock.release() indirectly calls dirstate.write(): since
4268 # we're crashing, we do not want to change the working dir
4269 # we're crashing, we do not want to change the working dir
4269 # parent after all, so make sure it writes nothing
4270 # parent after all, so make sure it writes nothing
4270 repo.dirstate.invalidate()
4271 repo.dirstate.invalidate()
4271 raise
4272 raise
4272 finally:
4273 finally:
4273 if tr:
4274 if tr:
4274 tr.release()
4275 tr.release()
4275 release(lock, wlock)
4276 release(lock, wlock)
4276
4277
4277 @command('incoming|in',
4278 @command('incoming|in',
4278 [('f', 'force', None,
4279 [('f', 'force', None,
4279 _('run even if remote repository is unrelated')),
4280 _('run even if remote repository is unrelated')),
4280 ('n', 'newest-first', None, _('show newest record first')),
4281 ('n', 'newest-first', None, _('show newest record first')),
4281 ('', 'bundle', '',
4282 ('', 'bundle', '',
4282 _('file to store the bundles into'), _('FILE')),
4283 _('file to store the bundles into'), _('FILE')),
4283 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4284 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4284 ('B', 'bookmarks', False, _("compare bookmarks")),
4285 ('B', 'bookmarks', False, _("compare bookmarks")),
4285 ('b', 'branch', [],
4286 ('b', 'branch', [],
4286 _('a specific branch you would like to pull'), _('BRANCH')),
4287 _('a specific branch you would like to pull'), _('BRANCH')),
4287 ] + logopts + remoteopts + subrepoopts,
4288 ] + logopts + remoteopts + subrepoopts,
4288 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4289 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4289 def incoming(ui, repo, source="default", **opts):
4290 def incoming(ui, repo, source="default", **opts):
4290 """show new changesets found in source
4291 """show new changesets found in source
4291
4292
4292 Show new changesets found in the specified path/URL or the default
4293 Show new changesets found in the specified path/URL or the default
4293 pull location. These are the changesets that would have been pulled
4294 pull location. These are the changesets that would have been pulled
4294 if a pull at the time you issued this command.
4295 if a pull at the time you issued this command.
4295
4296
4296 See pull for valid source format details.
4297 See pull for valid source format details.
4297
4298
4298 .. container:: verbose
4299 .. container:: verbose
4299
4300
4300 With -B/--bookmarks, the result of bookmark comparison between
4301 With -B/--bookmarks, the result of bookmark comparison between
4301 local and remote repositories is displayed. With -v/--verbose,
4302 local and remote repositories is displayed. With -v/--verbose,
4302 status is also displayed for each bookmark like below::
4303 status is also displayed for each bookmark like below::
4303
4304
4304 BM1 01234567890a added
4305 BM1 01234567890a added
4305 BM2 1234567890ab advanced
4306 BM2 1234567890ab advanced
4306 BM3 234567890abc diverged
4307 BM3 234567890abc diverged
4307 BM4 34567890abcd changed
4308 BM4 34567890abcd changed
4308
4309
4309 The action taken locally when pulling depends on the
4310 The action taken locally when pulling depends on the
4310 status of each bookmark:
4311 status of each bookmark:
4311
4312
4312 :``added``: pull will create it
4313 :``added``: pull will create it
4313 :``advanced``: pull will update it
4314 :``advanced``: pull will update it
4314 :``diverged``: pull will create a divergent bookmark
4315 :``diverged``: pull will create a divergent bookmark
4315 :``changed``: result depends on remote changesets
4316 :``changed``: result depends on remote changesets
4316
4317
4317 From the point of view of pulling behavior, bookmark
4318 From the point of view of pulling behavior, bookmark
4318 existing only in the remote repository are treated as ``added``,
4319 existing only in the remote repository are treated as ``added``,
4319 even if it is in fact locally deleted.
4320 even if it is in fact locally deleted.
4320
4321
4321 .. container:: verbose
4322 .. container:: verbose
4322
4323
4323 For remote repository, using --bundle avoids downloading the
4324 For remote repository, using --bundle avoids downloading the
4324 changesets twice if the incoming is followed by a pull.
4325 changesets twice if the incoming is followed by a pull.
4325
4326
4326 Examples:
4327 Examples:
4327
4328
4328 - show incoming changes with patches and full description::
4329 - show incoming changes with patches and full description::
4329
4330
4330 hg incoming -vp
4331 hg incoming -vp
4331
4332
4332 - show incoming changes excluding merges, store a bundle::
4333 - show incoming changes excluding merges, store a bundle::
4333
4334
4334 hg in -vpM --bundle incoming.hg
4335 hg in -vpM --bundle incoming.hg
4335 hg pull incoming.hg
4336 hg pull incoming.hg
4336
4337
4337 - briefly list changes inside a bundle::
4338 - briefly list changes inside a bundle::
4338
4339
4339 hg in changes.hg -T "{desc|firstline}\\n"
4340 hg in changes.hg -T "{desc|firstline}\\n"
4340
4341
4341 Returns 0 if there are incoming changes, 1 otherwise.
4342 Returns 0 if there are incoming changes, 1 otherwise.
4342 """
4343 """
4343 if opts.get('graph'):
4344 if opts.get('graph'):
4344 cmdutil.checkunsupportedgraphflags([], opts)
4345 cmdutil.checkunsupportedgraphflags([], opts)
4345 def display(other, chlist, displayer):
4346 def display(other, chlist, displayer):
4346 revdag = cmdutil.graphrevs(other, chlist, opts)
4347 revdag = cmdutil.graphrevs(other, chlist, opts)
4347 showparents = [ctx.node() for ctx in repo[None].parents()]
4348 showparents = [ctx.node() for ctx in repo[None].parents()]
4348 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4349 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4349 graphmod.asciiedges)
4350 graphmod.asciiedges)
4350
4351
4351 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4352 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4352 return 0
4353 return 0
4353
4354
4354 if opts.get('bundle') and opts.get('subrepos'):
4355 if opts.get('bundle') and opts.get('subrepos'):
4355 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4356 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4356
4357
4357 if opts.get('bookmarks'):
4358 if opts.get('bookmarks'):
4358 source, branches = hg.parseurl(ui.expandpath(source),
4359 source, branches = hg.parseurl(ui.expandpath(source),
4359 opts.get('branch'))
4360 opts.get('branch'))
4360 other = hg.peer(repo, opts, source)
4361 other = hg.peer(repo, opts, source)
4361 if 'bookmarks' not in other.listkeys('namespaces'):
4362 if 'bookmarks' not in other.listkeys('namespaces'):
4362 ui.warn(_("remote doesn't support bookmarks\n"))
4363 ui.warn(_("remote doesn't support bookmarks\n"))
4363 return 0
4364 return 0
4364 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4365 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4365 return bookmarks.incoming(ui, repo, other)
4366 return bookmarks.incoming(ui, repo, other)
4366
4367
4367 repo._subtoppath = ui.expandpath(source)
4368 repo._subtoppath = ui.expandpath(source)
4368 try:
4369 try:
4369 return hg.incoming(ui, repo, source, opts)
4370 return hg.incoming(ui, repo, source, opts)
4370 finally:
4371 finally:
4371 del repo._subtoppath
4372 del repo._subtoppath
4372
4373
4373
4374
4374 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4375 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4375 norepo=True)
4376 norepo=True)
4376 def init(ui, dest=".", **opts):
4377 def init(ui, dest=".", **opts):
4377 """create a new repository in the given directory
4378 """create a new repository in the given directory
4378
4379
4379 Initialize a new repository in the given directory. If the given
4380 Initialize a new repository in the given directory. If the given
4380 directory does not exist, it will be created.
4381 directory does not exist, it will be created.
4381
4382
4382 If no directory is given, the current directory is used.
4383 If no directory is given, the current directory is used.
4383
4384
4384 It is possible to specify an ``ssh://`` URL as the destination.
4385 It is possible to specify an ``ssh://`` URL as the destination.
4385 See :hg:`help urls` for more information.
4386 See :hg:`help urls` for more information.
4386
4387
4387 Returns 0 on success.
4388 Returns 0 on success.
4388 """
4389 """
4389 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4390 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4390
4391
4391 @command('locate',
4392 @command('locate',
4392 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4393 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4393 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4394 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4394 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4395 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4395 ] + walkopts,
4396 ] + walkopts,
4396 _('[OPTION]... [PATTERN]...'))
4397 _('[OPTION]... [PATTERN]...'))
4397 def locate(ui, repo, *pats, **opts):
4398 def locate(ui, repo, *pats, **opts):
4398 """locate files matching specific patterns (DEPRECATED)
4399 """locate files matching specific patterns (DEPRECATED)
4399
4400
4400 Print files under Mercurial control in the working directory whose
4401 Print files under Mercurial control in the working directory whose
4401 names match the given patterns.
4402 names match the given patterns.
4402
4403
4403 By default, this command searches all directories in the working
4404 By default, this command searches all directories in the working
4404 directory. To search just the current directory and its
4405 directory. To search just the current directory and its
4405 subdirectories, use "--include .".
4406 subdirectories, use "--include .".
4406
4407
4407 If no patterns are given to match, this command prints the names
4408 If no patterns are given to match, this command prints the names
4408 of all files under Mercurial control in the working directory.
4409 of all files under Mercurial control in the working directory.
4409
4410
4410 If you want to feed the output of this command into the "xargs"
4411 If you want to feed the output of this command into the "xargs"
4411 command, use the -0 option to both this command and "xargs". This
4412 command, use the -0 option to both this command and "xargs". This
4412 will avoid the problem of "xargs" treating single filenames that
4413 will avoid the problem of "xargs" treating single filenames that
4413 contain whitespace as multiple filenames.
4414 contain whitespace as multiple filenames.
4414
4415
4415 See :hg:`help files` for a more versatile command.
4416 See :hg:`help files` for a more versatile command.
4416
4417
4417 Returns 0 if a match is found, 1 otherwise.
4418 Returns 0 if a match is found, 1 otherwise.
4418 """
4419 """
4419 if opts.get('print0'):
4420 if opts.get('print0'):
4420 end = '\0'
4421 end = '\0'
4421 else:
4422 else:
4422 end = '\n'
4423 end = '\n'
4423 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4424 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4424
4425
4425 ret = 1
4426 ret = 1
4426 ctx = repo[rev]
4427 ctx = repo[rev]
4427 m = scmutil.match(ctx, pats, opts, default='relglob')
4428 m = scmutil.match(ctx, pats, opts, default='relglob')
4428 m.bad = lambda x, y: False
4429 m.bad = lambda x, y: False
4429
4430
4430 for abs in ctx.matches(m):
4431 for abs in ctx.matches(m):
4431 if opts.get('fullpath'):
4432 if opts.get('fullpath'):
4432 ui.write(repo.wjoin(abs), end)
4433 ui.write(repo.wjoin(abs), end)
4433 else:
4434 else:
4434 ui.write(((pats and m.rel(abs)) or abs), end)
4435 ui.write(((pats and m.rel(abs)) or abs), end)
4435 ret = 0
4436 ret = 0
4436
4437
4437 return ret
4438 return ret
4438
4439
4439 @command('^log|history',
4440 @command('^log|history',
4440 [('f', 'follow', None,
4441 [('f', 'follow', None,
4441 _('follow changeset history, or file history across copies and renames')),
4442 _('follow changeset history, or file history across copies and renames')),
4442 ('', 'follow-first', None,
4443 ('', 'follow-first', None,
4443 _('only follow the first parent of merge changesets (DEPRECATED)')),
4444 _('only follow the first parent of merge changesets (DEPRECATED)')),
4444 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4445 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4445 ('C', 'copies', None, _('show copied files')),
4446 ('C', 'copies', None, _('show copied files')),
4446 ('k', 'keyword', [],
4447 ('k', 'keyword', [],
4447 _('do case-insensitive search for a given text'), _('TEXT')),
4448 _('do case-insensitive search for a given text'), _('TEXT')),
4448 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4449 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4449 ('', 'removed', None, _('include revisions where files were removed')),
4450 ('', 'removed', None, _('include revisions where files were removed')),
4450 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4451 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4451 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4452 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4452 ('', 'only-branch', [],
4453 ('', 'only-branch', [],
4453 _('show only changesets within the given named branch (DEPRECATED)'),
4454 _('show only changesets within the given named branch (DEPRECATED)'),
4454 _('BRANCH')),
4455 _('BRANCH')),
4455 ('b', 'branch', [],
4456 ('b', 'branch', [],
4456 _('show changesets within the given named branch'), _('BRANCH')),
4457 _('show changesets within the given named branch'), _('BRANCH')),
4457 ('P', 'prune', [],
4458 ('P', 'prune', [],
4458 _('do not display revision or any of its ancestors'), _('REV')),
4459 _('do not display revision or any of its ancestors'), _('REV')),
4459 ] + logopts + walkopts,
4460 ] + logopts + walkopts,
4460 _('[OPTION]... [FILE]'),
4461 _('[OPTION]... [FILE]'),
4461 inferrepo=True)
4462 inferrepo=True)
4462 def log(ui, repo, *pats, **opts):
4463 def log(ui, repo, *pats, **opts):
4463 """show revision history of entire repository or files
4464 """show revision history of entire repository or files
4464
4465
4465 Print the revision history of the specified files or the entire
4466 Print the revision history of the specified files or the entire
4466 project.
4467 project.
4467
4468
4468 If no revision range is specified, the default is ``tip:0`` unless
4469 If no revision range is specified, the default is ``tip:0`` unless
4469 --follow is set, in which case the working directory parent is
4470 --follow is set, in which case the working directory parent is
4470 used as the starting revision.
4471 used as the starting revision.
4471
4472
4472 File history is shown without following rename or copy history of
4473 File history is shown without following rename or copy history of
4473 files. Use -f/--follow with a filename to follow history across
4474 files. Use -f/--follow with a filename to follow history across
4474 renames and copies. --follow without a filename will only show
4475 renames and copies. --follow without a filename will only show
4475 ancestors or descendants of the starting revision.
4476 ancestors or descendants of the starting revision.
4476
4477
4477 By default this command prints revision number and changeset id,
4478 By default this command prints revision number and changeset id,
4478 tags, non-trivial parents, user, date and time, and a summary for
4479 tags, non-trivial parents, user, date and time, and a summary for
4479 each commit. When the -v/--verbose switch is used, the list of
4480 each commit. When the -v/--verbose switch is used, the list of
4480 changed files and full commit message are shown.
4481 changed files and full commit message are shown.
4481
4482
4482 With --graph the revisions are shown as an ASCII art DAG with the most
4483 With --graph the revisions are shown as an ASCII art DAG with the most
4483 recent changeset at the top.
4484 recent changeset at the top.
4484 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4485 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4485 and '+' represents a fork where the changeset from the lines below is a
4486 and '+' represents a fork where the changeset from the lines below is a
4486 parent of the 'o' merge on the same line.
4487 parent of the 'o' merge on the same line.
4487
4488
4488 .. note::
4489 .. note::
4489
4490
4490 log -p/--patch may generate unexpected diff output for merge
4491 log -p/--patch may generate unexpected diff output for merge
4491 changesets, as it will only compare the merge changeset against
4492 changesets, as it will only compare the merge changeset against
4492 its first parent. Also, only files different from BOTH parents
4493 its first parent. Also, only files different from BOTH parents
4493 will appear in files:.
4494 will appear in files:.
4494
4495
4495 .. note::
4496 .. note::
4496
4497
4497 for performance reasons, log FILE may omit duplicate changes
4498 for performance reasons, log FILE may omit duplicate changes
4498 made on branches and will not show removals or mode changes. To
4499 made on branches and will not show removals or mode changes. To
4499 see all such changes, use the --removed switch.
4500 see all such changes, use the --removed switch.
4500
4501
4501 .. container:: verbose
4502 .. container:: verbose
4502
4503
4503 Some examples:
4504 Some examples:
4504
4505
4505 - changesets with full descriptions and file lists::
4506 - changesets with full descriptions and file lists::
4506
4507
4507 hg log -v
4508 hg log -v
4508
4509
4509 - changesets ancestral to the working directory::
4510 - changesets ancestral to the working directory::
4510
4511
4511 hg log -f
4512 hg log -f
4512
4513
4513 - last 10 commits on the current branch::
4514 - last 10 commits on the current branch::
4514
4515
4515 hg log -l 10 -b .
4516 hg log -l 10 -b .
4516
4517
4517 - changesets showing all modifications of a file, including removals::
4518 - changesets showing all modifications of a file, including removals::
4518
4519
4519 hg log --removed file.c
4520 hg log --removed file.c
4520
4521
4521 - all changesets that touch a directory, with diffs, excluding merges::
4522 - all changesets that touch a directory, with diffs, excluding merges::
4522
4523
4523 hg log -Mp lib/
4524 hg log -Mp lib/
4524
4525
4525 - all revision numbers that match a keyword::
4526 - all revision numbers that match a keyword::
4526
4527
4527 hg log -k bug --template "{rev}\\n"
4528 hg log -k bug --template "{rev}\\n"
4528
4529
4529 - list available log templates::
4530 - list available log templates::
4530
4531
4531 hg log -T list
4532 hg log -T list
4532
4533
4533 - check if a given changeset is included in a tagged release::
4534 - check if a given changeset is included in a tagged release::
4534
4535
4535 hg log -r "a21ccf and ancestor(1.9)"
4536 hg log -r "a21ccf and ancestor(1.9)"
4536
4537
4537 - find all changesets by some user in a date range::
4538 - find all changesets by some user in a date range::
4538
4539
4539 hg log -k alice -d "may 2008 to jul 2008"
4540 hg log -k alice -d "may 2008 to jul 2008"
4540
4541
4541 - summary of all changesets after the last tag::
4542 - summary of all changesets after the last tag::
4542
4543
4543 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4544 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4544
4545
4545 See :hg:`help dates` for a list of formats valid for -d/--date.
4546 See :hg:`help dates` for a list of formats valid for -d/--date.
4546
4547
4547 See :hg:`help revisions` and :hg:`help revsets` for more about
4548 See :hg:`help revisions` and :hg:`help revsets` for more about
4548 specifying revisions.
4549 specifying revisions.
4549
4550
4550 See :hg:`help templates` for more about pre-packaged styles and
4551 See :hg:`help templates` for more about pre-packaged styles and
4551 specifying custom templates.
4552 specifying custom templates.
4552
4553
4553 Returns 0 on success.
4554 Returns 0 on success.
4554
4555
4555 """
4556 """
4556 if opts.get('follow') and opts.get('rev'):
4557 if opts.get('follow') and opts.get('rev'):
4557 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4558 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4558 del opts['follow']
4559 del opts['follow']
4559
4560
4560 if opts.get('graph'):
4561 if opts.get('graph'):
4561 return cmdutil.graphlog(ui, repo, *pats, **opts)
4562 return cmdutil.graphlog(ui, repo, *pats, **opts)
4562
4563
4563 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4564 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4564 limit = cmdutil.loglimit(opts)
4565 limit = cmdutil.loglimit(opts)
4565 count = 0
4566 count = 0
4566
4567
4567 getrenamed = None
4568 getrenamed = None
4568 if opts.get('copies'):
4569 if opts.get('copies'):
4569 endrev = None
4570 endrev = None
4570 if opts.get('rev'):
4571 if opts.get('rev'):
4571 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4572 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4572 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4573 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4573
4574
4574 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4575 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4575 for rev in revs:
4576 for rev in revs:
4576 if count == limit:
4577 if count == limit:
4577 break
4578 break
4578 ctx = repo[rev]
4579 ctx = repo[rev]
4579 copies = None
4580 copies = None
4580 if getrenamed is not None and rev:
4581 if getrenamed is not None and rev:
4581 copies = []
4582 copies = []
4582 for fn in ctx.files():
4583 for fn in ctx.files():
4583 rename = getrenamed(fn, rev)
4584 rename = getrenamed(fn, rev)
4584 if rename:
4585 if rename:
4585 copies.append((fn, rename[0]))
4586 copies.append((fn, rename[0]))
4586 if filematcher:
4587 if filematcher:
4587 revmatchfn = filematcher(ctx.rev())
4588 revmatchfn = filematcher(ctx.rev())
4588 else:
4589 else:
4589 revmatchfn = None
4590 revmatchfn = None
4590 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4591 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4591 if displayer.flush(rev):
4592 if displayer.flush(rev):
4592 count += 1
4593 count += 1
4593
4594
4594 displayer.close()
4595 displayer.close()
4595
4596
4596 @command('manifest',
4597 @command('manifest',
4597 [('r', 'rev', '', _('revision to display'), _('REV')),
4598 [('r', 'rev', '', _('revision to display'), _('REV')),
4598 ('', 'all', False, _("list files from all revisions"))]
4599 ('', 'all', False, _("list files from all revisions"))]
4599 + formatteropts,
4600 + formatteropts,
4600 _('[-r REV]'))
4601 _('[-r REV]'))
4601 def manifest(ui, repo, node=None, rev=None, **opts):
4602 def manifest(ui, repo, node=None, rev=None, **opts):
4602 """output the current or given revision of the project manifest
4603 """output the current or given revision of the project manifest
4603
4604
4604 Print a list of version controlled files for the given revision.
4605 Print a list of version controlled files for the given revision.
4605 If no revision is given, the first parent of the working directory
4606 If no revision is given, the first parent of the working directory
4606 is used, or the null revision if no revision is checked out.
4607 is used, or the null revision if no revision is checked out.
4607
4608
4608 With -v, print file permissions, symlink and executable bits.
4609 With -v, print file permissions, symlink and executable bits.
4609 With --debug, print file revision hashes.
4610 With --debug, print file revision hashes.
4610
4611
4611 If option --all is specified, the list of all files from all revisions
4612 If option --all is specified, the list of all files from all revisions
4612 is printed. This includes deleted and renamed files.
4613 is printed. This includes deleted and renamed files.
4613
4614
4614 Returns 0 on success.
4615 Returns 0 on success.
4615 """
4616 """
4616
4617
4617 fm = ui.formatter('manifest', opts)
4618 fm = ui.formatter('manifest', opts)
4618
4619
4619 if opts.get('all'):
4620 if opts.get('all'):
4620 if rev or node:
4621 if rev or node:
4621 raise util.Abort(_("can't specify a revision with --all"))
4622 raise util.Abort(_("can't specify a revision with --all"))
4622
4623
4623 res = []
4624 res = []
4624 prefix = "data/"
4625 prefix = "data/"
4625 suffix = ".i"
4626 suffix = ".i"
4626 plen = len(prefix)
4627 plen = len(prefix)
4627 slen = len(suffix)
4628 slen = len(suffix)
4628 lock = repo.lock()
4629 lock = repo.lock()
4629 try:
4630 try:
4630 for fn, b, size in repo.store.datafiles():
4631 for fn, b, size in repo.store.datafiles():
4631 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4632 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4632 res.append(fn[plen:-slen])
4633 res.append(fn[plen:-slen])
4633 finally:
4634 finally:
4634 lock.release()
4635 lock.release()
4635 for f in res:
4636 for f in res:
4636 fm.startitem()
4637 fm.startitem()
4637 fm.write("path", '%s\n', f)
4638 fm.write("path", '%s\n', f)
4638 fm.end()
4639 fm.end()
4639 return
4640 return
4640
4641
4641 if rev and node:
4642 if rev and node:
4642 raise util.Abort(_("please specify just one revision"))
4643 raise util.Abort(_("please specify just one revision"))
4643
4644
4644 if not node:
4645 if not node:
4645 node = rev
4646 node = rev
4646
4647
4647 char = {'l': '@', 'x': '*', '': ''}
4648 char = {'l': '@', 'x': '*', '': ''}
4648 mode = {'l': '644', 'x': '755', '': '644'}
4649 mode = {'l': '644', 'x': '755', '': '644'}
4649 ctx = scmutil.revsingle(repo, node)
4650 ctx = scmutil.revsingle(repo, node)
4650 mf = ctx.manifest()
4651 mf = ctx.manifest()
4651 for f in ctx:
4652 for f in ctx:
4652 fm.startitem()
4653 fm.startitem()
4653 fl = ctx[f].flags()
4654 fl = ctx[f].flags()
4654 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4655 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4655 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4656 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4656 fm.write('path', '%s\n', f)
4657 fm.write('path', '%s\n', f)
4657 fm.end()
4658 fm.end()
4658
4659
4659 @command('^merge',
4660 @command('^merge',
4660 [('f', 'force', None,
4661 [('f', 'force', None,
4661 _('force a merge including outstanding changes (DEPRECATED)')),
4662 _('force a merge including outstanding changes (DEPRECATED)')),
4662 ('r', 'rev', '', _('revision to merge'), _('REV')),
4663 ('r', 'rev', '', _('revision to merge'), _('REV')),
4663 ('P', 'preview', None,
4664 ('P', 'preview', None,
4664 _('review revisions to merge (no merge is performed)'))
4665 _('review revisions to merge (no merge is performed)'))
4665 ] + mergetoolopts,
4666 ] + mergetoolopts,
4666 _('[-P] [-f] [[-r] REV]'))
4667 _('[-P] [-f] [[-r] REV]'))
4667 def merge(ui, repo, node=None, **opts):
4668 def merge(ui, repo, node=None, **opts):
4668 """merge another revision into working directory
4669 """merge another revision into working directory
4669
4670
4670 The current working directory is updated with all changes made in
4671 The current working directory is updated with all changes made in
4671 the requested revision since the last common predecessor revision.
4672 the requested revision since the last common predecessor revision.
4672
4673
4673 Files that changed between either parent are marked as changed for
4674 Files that changed between either parent are marked as changed for
4674 the next commit and a commit must be performed before any further
4675 the next commit and a commit must be performed before any further
4675 updates to the repository are allowed. The next commit will have
4676 updates to the repository are allowed. The next commit will have
4676 two parents.
4677 two parents.
4677
4678
4678 ``--tool`` can be used to specify the merge tool used for file
4679 ``--tool`` can be used to specify the merge tool used for file
4679 merges. It overrides the HGMERGE environment variable and your
4680 merges. It overrides the HGMERGE environment variable and your
4680 configuration files. See :hg:`help merge-tools` for options.
4681 configuration files. See :hg:`help merge-tools` for options.
4681
4682
4682 If no revision is specified, the working directory's parent is a
4683 If no revision is specified, the working directory's parent is a
4683 head revision, and the current branch contains exactly one other
4684 head revision, and the current branch contains exactly one other
4684 head, the other head is merged with by default. Otherwise, an
4685 head, the other head is merged with by default. Otherwise, an
4685 explicit revision with which to merge with must be provided.
4686 explicit revision with which to merge with must be provided.
4686
4687
4687 :hg:`resolve` must be used to resolve unresolved files.
4688 :hg:`resolve` must be used to resolve unresolved files.
4688
4689
4689 To undo an uncommitted merge, use :hg:`update --clean .` which
4690 To undo an uncommitted merge, use :hg:`update --clean .` which
4690 will check out a clean copy of the original merge parent, losing
4691 will check out a clean copy of the original merge parent, losing
4691 all changes.
4692 all changes.
4692
4693
4693 Returns 0 on success, 1 if there are unresolved files.
4694 Returns 0 on success, 1 if there are unresolved files.
4694 """
4695 """
4695
4696
4696 if opts.get('rev') and node:
4697 if opts.get('rev') and node:
4697 raise util.Abort(_("please specify just one revision"))
4698 raise util.Abort(_("please specify just one revision"))
4698 if not node:
4699 if not node:
4699 node = opts.get('rev')
4700 node = opts.get('rev')
4700
4701
4701 if node:
4702 if node:
4702 node = scmutil.revsingle(repo, node).node()
4703 node = scmutil.revsingle(repo, node).node()
4703
4704
4704 if not node and repo._bookmarkcurrent:
4705 if not node and repo._bookmarkcurrent:
4705 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4706 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4706 curhead = repo[repo._bookmarkcurrent].node()
4707 curhead = repo[repo._bookmarkcurrent].node()
4707 if len(bmheads) == 2:
4708 if len(bmheads) == 2:
4708 if curhead == bmheads[0]:
4709 if curhead == bmheads[0]:
4709 node = bmheads[1]
4710 node = bmheads[1]
4710 else:
4711 else:
4711 node = bmheads[0]
4712 node = bmheads[0]
4712 elif len(bmheads) > 2:
4713 elif len(bmheads) > 2:
4713 raise util.Abort(_("multiple matching bookmarks to merge - "
4714 raise util.Abort(_("multiple matching bookmarks to merge - "
4714 "please merge with an explicit rev or bookmark"),
4715 "please merge with an explicit rev or bookmark"),
4715 hint=_("run 'hg heads' to see all heads"))
4716 hint=_("run 'hg heads' to see all heads"))
4716 elif len(bmheads) <= 1:
4717 elif len(bmheads) <= 1:
4717 raise util.Abort(_("no matching bookmark to merge - "
4718 raise util.Abort(_("no matching bookmark to merge - "
4718 "please merge with an explicit rev or bookmark"),
4719 "please merge with an explicit rev or bookmark"),
4719 hint=_("run 'hg heads' to see all heads"))
4720 hint=_("run 'hg heads' to see all heads"))
4720
4721
4721 if not node and not repo._bookmarkcurrent:
4722 if not node and not repo._bookmarkcurrent:
4722 branch = repo[None].branch()
4723 branch = repo[None].branch()
4723 bheads = repo.branchheads(branch)
4724 bheads = repo.branchheads(branch)
4724 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4725 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4725
4726
4726 if len(nbhs) > 2:
4727 if len(nbhs) > 2:
4727 raise util.Abort(_("branch '%s' has %d heads - "
4728 raise util.Abort(_("branch '%s' has %d heads - "
4728 "please merge with an explicit rev")
4729 "please merge with an explicit rev")
4729 % (branch, len(bheads)),
4730 % (branch, len(bheads)),
4730 hint=_("run 'hg heads .' to see heads"))
4731 hint=_("run 'hg heads .' to see heads"))
4731
4732
4732 parent = repo.dirstate.p1()
4733 parent = repo.dirstate.p1()
4733 if len(nbhs) <= 1:
4734 if len(nbhs) <= 1:
4734 if len(bheads) > 1:
4735 if len(bheads) > 1:
4735 raise util.Abort(_("heads are bookmarked - "
4736 raise util.Abort(_("heads are bookmarked - "
4736 "please merge with an explicit rev"),
4737 "please merge with an explicit rev"),
4737 hint=_("run 'hg heads' to see all heads"))
4738 hint=_("run 'hg heads' to see all heads"))
4738 if len(repo.heads()) > 1:
4739 if len(repo.heads()) > 1:
4739 raise util.Abort(_("branch '%s' has one head - "
4740 raise util.Abort(_("branch '%s' has one head - "
4740 "please merge with an explicit rev")
4741 "please merge with an explicit rev")
4741 % branch,
4742 % branch,
4742 hint=_("run 'hg heads' to see all heads"))
4743 hint=_("run 'hg heads' to see all heads"))
4743 msg, hint = _('nothing to merge'), None
4744 msg, hint = _('nothing to merge'), None
4744 if parent != repo.lookup(branch):
4745 if parent != repo.lookup(branch):
4745 hint = _("use 'hg update' instead")
4746 hint = _("use 'hg update' instead")
4746 raise util.Abort(msg, hint=hint)
4747 raise util.Abort(msg, hint=hint)
4747
4748
4748 if parent not in bheads:
4749 if parent not in bheads:
4749 raise util.Abort(_('working directory not at a head revision'),
4750 raise util.Abort(_('working directory not at a head revision'),
4750 hint=_("use 'hg update' or merge with an "
4751 hint=_("use 'hg update' or merge with an "
4751 "explicit revision"))
4752 "explicit revision"))
4752 if parent == nbhs[0]:
4753 if parent == nbhs[0]:
4753 node = nbhs[-1]
4754 node = nbhs[-1]
4754 else:
4755 else:
4755 node = nbhs[0]
4756 node = nbhs[0]
4756
4757
4757 if opts.get('preview'):
4758 if opts.get('preview'):
4758 # find nodes that are ancestors of p2 but not of p1
4759 # find nodes that are ancestors of p2 but not of p1
4759 p1 = repo.lookup('.')
4760 p1 = repo.lookup('.')
4760 p2 = repo.lookup(node)
4761 p2 = repo.lookup(node)
4761 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4762 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4762
4763
4763 displayer = cmdutil.show_changeset(ui, repo, opts)
4764 displayer = cmdutil.show_changeset(ui, repo, opts)
4764 for node in nodes:
4765 for node in nodes:
4765 displayer.show(repo[node])
4766 displayer.show(repo[node])
4766 displayer.close()
4767 displayer.close()
4767 return 0
4768 return 0
4768
4769
4769 try:
4770 try:
4770 # ui.forcemerge is an internal variable, do not document
4771 # ui.forcemerge is an internal variable, do not document
4771 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4772 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4772 return hg.merge(repo, node, force=opts.get('force'))
4773 return hg.merge(repo, node, force=opts.get('force'))
4773 finally:
4774 finally:
4774 ui.setconfig('ui', 'forcemerge', '', 'merge')
4775 ui.setconfig('ui', 'forcemerge', '', 'merge')
4775
4776
4776 @command('outgoing|out',
4777 @command('outgoing|out',
4777 [('f', 'force', None, _('run even when the destination is unrelated')),
4778 [('f', 'force', None, _('run even when the destination is unrelated')),
4778 ('r', 'rev', [],
4779 ('r', 'rev', [],
4779 _('a changeset intended to be included in the destination'), _('REV')),
4780 _('a changeset intended to be included in the destination'), _('REV')),
4780 ('n', 'newest-first', None, _('show newest record first')),
4781 ('n', 'newest-first', None, _('show newest record first')),
4781 ('B', 'bookmarks', False, _('compare bookmarks')),
4782 ('B', 'bookmarks', False, _('compare bookmarks')),
4782 ('b', 'branch', [], _('a specific branch you would like to push'),
4783 ('b', 'branch', [], _('a specific branch you would like to push'),
4783 _('BRANCH')),
4784 _('BRANCH')),
4784 ] + logopts + remoteopts + subrepoopts,
4785 ] + logopts + remoteopts + subrepoopts,
4785 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4786 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4786 def outgoing(ui, repo, dest=None, **opts):
4787 def outgoing(ui, repo, dest=None, **opts):
4787 """show changesets not found in the destination
4788 """show changesets not found in the destination
4788
4789
4789 Show changesets not found in the specified destination repository
4790 Show changesets not found in the specified destination repository
4790 or the default push location. These are the changesets that would
4791 or the default push location. These are the changesets that would
4791 be pushed if a push was requested.
4792 be pushed if a push was requested.
4792
4793
4793 See pull for details of valid destination formats.
4794 See pull for details of valid destination formats.
4794
4795
4795 .. container:: verbose
4796 .. container:: verbose
4796
4797
4797 With -B/--bookmarks, the result of bookmark comparison between
4798 With -B/--bookmarks, the result of bookmark comparison between
4798 local and remote repositories is displayed. With -v/--verbose,
4799 local and remote repositories is displayed. With -v/--verbose,
4799 status is also displayed for each bookmark like below::
4800 status is also displayed for each bookmark like below::
4800
4801
4801 BM1 01234567890a added
4802 BM1 01234567890a added
4802 BM2 deleted
4803 BM2 deleted
4803 BM3 234567890abc advanced
4804 BM3 234567890abc advanced
4804 BM4 34567890abcd diverged
4805 BM4 34567890abcd diverged
4805 BM5 4567890abcde changed
4806 BM5 4567890abcde changed
4806
4807
4807 The action taken when pushing depends on the
4808 The action taken when pushing depends on the
4808 status of each bookmark:
4809 status of each bookmark:
4809
4810
4810 :``added``: push with ``-B`` will create it
4811 :``added``: push with ``-B`` will create it
4811 :``deleted``: push with ``-B`` will delete it
4812 :``deleted``: push with ``-B`` will delete it
4812 :``advanced``: push will update it
4813 :``advanced``: push will update it
4813 :``diverged``: push with ``-B`` will update it
4814 :``diverged``: push with ``-B`` will update it
4814 :``changed``: push with ``-B`` will update it
4815 :``changed``: push with ``-B`` will update it
4815
4816
4816 From the point of view of pushing behavior, bookmarks
4817 From the point of view of pushing behavior, bookmarks
4817 existing only in the remote repository are treated as
4818 existing only in the remote repository are treated as
4818 ``deleted``, even if it is in fact added remotely.
4819 ``deleted``, even if it is in fact added remotely.
4819
4820
4820 Returns 0 if there are outgoing changes, 1 otherwise.
4821 Returns 0 if there are outgoing changes, 1 otherwise.
4821 """
4822 """
4822 if opts.get('graph'):
4823 if opts.get('graph'):
4823 cmdutil.checkunsupportedgraphflags([], opts)
4824 cmdutil.checkunsupportedgraphflags([], opts)
4824 o, other = hg._outgoing(ui, repo, dest, opts)
4825 o, other = hg._outgoing(ui, repo, dest, opts)
4825 if not o:
4826 if not o:
4826 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4827 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4827 return
4828 return
4828
4829
4829 revdag = cmdutil.graphrevs(repo, o, opts)
4830 revdag = cmdutil.graphrevs(repo, o, opts)
4830 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4831 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4831 showparents = [ctx.node() for ctx in repo[None].parents()]
4832 showparents = [ctx.node() for ctx in repo[None].parents()]
4832 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4833 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4833 graphmod.asciiedges)
4834 graphmod.asciiedges)
4834 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4835 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4835 return 0
4836 return 0
4836
4837
4837 if opts.get('bookmarks'):
4838 if opts.get('bookmarks'):
4838 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4839 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4839 dest, branches = hg.parseurl(dest, opts.get('branch'))
4840 dest, branches = hg.parseurl(dest, opts.get('branch'))
4840 other = hg.peer(repo, opts, dest)
4841 other = hg.peer(repo, opts, dest)
4841 if 'bookmarks' not in other.listkeys('namespaces'):
4842 if 'bookmarks' not in other.listkeys('namespaces'):
4842 ui.warn(_("remote doesn't support bookmarks\n"))
4843 ui.warn(_("remote doesn't support bookmarks\n"))
4843 return 0
4844 return 0
4844 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4845 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4845 return bookmarks.outgoing(ui, repo, other)
4846 return bookmarks.outgoing(ui, repo, other)
4846
4847
4847 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4848 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4848 try:
4849 try:
4849 return hg.outgoing(ui, repo, dest, opts)
4850 return hg.outgoing(ui, repo, dest, opts)
4850 finally:
4851 finally:
4851 del repo._subtoppath
4852 del repo._subtoppath
4852
4853
4853 @command('parents',
4854 @command('parents',
4854 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4855 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4855 ] + templateopts,
4856 ] + templateopts,
4856 _('[-r REV] [FILE]'),
4857 _('[-r REV] [FILE]'),
4857 inferrepo=True)
4858 inferrepo=True)
4858 def parents(ui, repo, file_=None, **opts):
4859 def parents(ui, repo, file_=None, **opts):
4859 """show the parents of the working directory or revision (DEPRECATED)
4860 """show the parents of the working directory or revision (DEPRECATED)
4860
4861
4861 Print the working directory's parent revisions. If a revision is
4862 Print the working directory's parent revisions. If a revision is
4862 given via -r/--rev, the parent of that revision will be printed.
4863 given via -r/--rev, the parent of that revision will be printed.
4863 If a file argument is given, the revision in which the file was
4864 If a file argument is given, the revision in which the file was
4864 last changed (before the working directory revision or the
4865 last changed (before the working directory revision or the
4865 argument to --rev if given) is printed.
4866 argument to --rev if given) is printed.
4866
4867
4867 See :hg:`summary` and :hg:`help revsets` for related information.
4868 See :hg:`summary` and :hg:`help revsets` for related information.
4868
4869
4869 Returns 0 on success.
4870 Returns 0 on success.
4870 """
4871 """
4871
4872
4872 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4873 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4873
4874
4874 if file_:
4875 if file_:
4875 m = scmutil.match(ctx, (file_,), opts)
4876 m = scmutil.match(ctx, (file_,), opts)
4876 if m.anypats() or len(m.files()) != 1:
4877 if m.anypats() or len(m.files()) != 1:
4877 raise util.Abort(_('can only specify an explicit filename'))
4878 raise util.Abort(_('can only specify an explicit filename'))
4878 file_ = m.files()[0]
4879 file_ = m.files()[0]
4879 filenodes = []
4880 filenodes = []
4880 for cp in ctx.parents():
4881 for cp in ctx.parents():
4881 if not cp:
4882 if not cp:
4882 continue
4883 continue
4883 try:
4884 try:
4884 filenodes.append(cp.filenode(file_))
4885 filenodes.append(cp.filenode(file_))
4885 except error.LookupError:
4886 except error.LookupError:
4886 pass
4887 pass
4887 if not filenodes:
4888 if not filenodes:
4888 raise util.Abort(_("'%s' not found in manifest!") % file_)
4889 raise util.Abort(_("'%s' not found in manifest!") % file_)
4889 p = []
4890 p = []
4890 for fn in filenodes:
4891 for fn in filenodes:
4891 fctx = repo.filectx(file_, fileid=fn)
4892 fctx = repo.filectx(file_, fileid=fn)
4892 p.append(fctx.node())
4893 p.append(fctx.node())
4893 else:
4894 else:
4894 p = [cp.node() for cp in ctx.parents()]
4895 p = [cp.node() for cp in ctx.parents()]
4895
4896
4896 displayer = cmdutil.show_changeset(ui, repo, opts)
4897 displayer = cmdutil.show_changeset(ui, repo, opts)
4897 for n in p:
4898 for n in p:
4898 if n != nullid:
4899 if n != nullid:
4899 displayer.show(repo[n])
4900 displayer.show(repo[n])
4900 displayer.close()
4901 displayer.close()
4901
4902
4902 @command('paths', [], _('[NAME]'), optionalrepo=True)
4903 @command('paths', [], _('[NAME]'), optionalrepo=True)
4903 def paths(ui, repo, search=None):
4904 def paths(ui, repo, search=None):
4904 """show aliases for remote repositories
4905 """show aliases for remote repositories
4905
4906
4906 Show definition of symbolic path name NAME. If no name is given,
4907 Show definition of symbolic path name NAME. If no name is given,
4907 show definition of all available names.
4908 show definition of all available names.
4908
4909
4909 Option -q/--quiet suppresses all output when searching for NAME
4910 Option -q/--quiet suppresses all output when searching for NAME
4910 and shows only the path names when listing all definitions.
4911 and shows only the path names when listing all definitions.
4911
4912
4912 Path names are defined in the [paths] section of your
4913 Path names are defined in the [paths] section of your
4913 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4914 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4914 repository, ``.hg/hgrc`` is used, too.
4915 repository, ``.hg/hgrc`` is used, too.
4915
4916
4916 The path names ``default`` and ``default-push`` have a special
4917 The path names ``default`` and ``default-push`` have a special
4917 meaning. When performing a push or pull operation, they are used
4918 meaning. When performing a push or pull operation, they are used
4918 as fallbacks if no location is specified on the command-line.
4919 as fallbacks if no location is specified on the command-line.
4919 When ``default-push`` is set, it will be used for push and
4920 When ``default-push`` is set, it will be used for push and
4920 ``default`` will be used for pull; otherwise ``default`` is used
4921 ``default`` will be used for pull; otherwise ``default`` is used
4921 as the fallback for both. When cloning a repository, the clone
4922 as the fallback for both. When cloning a repository, the clone
4922 source is written as ``default`` in ``.hg/hgrc``. Note that
4923 source is written as ``default`` in ``.hg/hgrc``. Note that
4923 ``default`` and ``default-push`` apply to all inbound (e.g.
4924 ``default`` and ``default-push`` apply to all inbound (e.g.
4924 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4925 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4925 :hg:`bundle`) operations.
4926 :hg:`bundle`) operations.
4926
4927
4927 See :hg:`help urls` for more information.
4928 See :hg:`help urls` for more information.
4928
4929
4929 Returns 0 on success.
4930 Returns 0 on success.
4930 """
4931 """
4931 if search:
4932 if search:
4932 for name, path in sorted(ui.paths.iteritems()):
4933 for name, path in sorted(ui.paths.iteritems()):
4933 if name == search:
4934 if name == search:
4934 ui.status("%s\n" % util.hidepassword(path.loc))
4935 ui.status("%s\n" % util.hidepassword(path.loc))
4935 return
4936 return
4936 if not ui.quiet:
4937 if not ui.quiet:
4937 ui.warn(_("not found!\n"))
4938 ui.warn(_("not found!\n"))
4938 return 1
4939 return 1
4939 else:
4940 else:
4940 for name, path in sorted(ui.paths.iteritems()):
4941 for name, path in sorted(ui.paths.iteritems()):
4941 if ui.quiet:
4942 if ui.quiet:
4942 ui.write("%s\n" % name)
4943 ui.write("%s\n" % name)
4943 else:
4944 else:
4944 ui.write("%s = %s\n" % (name,
4945 ui.write("%s = %s\n" % (name,
4945 util.hidepassword(path.loc)))
4946 util.hidepassword(path.loc)))
4946
4947
4947 @command('phase',
4948 @command('phase',
4948 [('p', 'public', False, _('set changeset phase to public')),
4949 [('p', 'public', False, _('set changeset phase to public')),
4949 ('d', 'draft', False, _('set changeset phase to draft')),
4950 ('d', 'draft', False, _('set changeset phase to draft')),
4950 ('s', 'secret', False, _('set changeset phase to secret')),
4951 ('s', 'secret', False, _('set changeset phase to secret')),
4951 ('f', 'force', False, _('allow to move boundary backward')),
4952 ('f', 'force', False, _('allow to move boundary backward')),
4952 ('r', 'rev', [], _('target revision'), _('REV')),
4953 ('r', 'rev', [], _('target revision'), _('REV')),
4953 ],
4954 ],
4954 _('[-p|-d|-s] [-f] [-r] REV...'))
4955 _('[-p|-d|-s] [-f] [-r] REV...'))
4955 def phase(ui, repo, *revs, **opts):
4956 def phase(ui, repo, *revs, **opts):
4956 """set or show the current phase name
4957 """set or show the current phase name
4957
4958
4958 With no argument, show the phase name of specified revisions.
4959 With no argument, show the phase name of specified revisions.
4959
4960
4960 With one of -p/--public, -d/--draft or -s/--secret, change the
4961 With one of -p/--public, -d/--draft or -s/--secret, change the
4961 phase value of the specified revisions.
4962 phase value of the specified revisions.
4962
4963
4963 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4964 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4964 lower phase to an higher phase. Phases are ordered as follows::
4965 lower phase to an higher phase. Phases are ordered as follows::
4965
4966
4966 public < draft < secret
4967 public < draft < secret
4967
4968
4968 Returns 0 on success, 1 if no phases were changed or some could not
4969 Returns 0 on success, 1 if no phases were changed or some could not
4969 be changed.
4970 be changed.
4970 """
4971 """
4971 # search for a unique phase argument
4972 # search for a unique phase argument
4972 targetphase = None
4973 targetphase = None
4973 for idx, name in enumerate(phases.phasenames):
4974 for idx, name in enumerate(phases.phasenames):
4974 if opts[name]:
4975 if opts[name]:
4975 if targetphase is not None:
4976 if targetphase is not None:
4976 raise util.Abort(_('only one phase can be specified'))
4977 raise util.Abort(_('only one phase can be specified'))
4977 targetphase = idx
4978 targetphase = idx
4978
4979
4979 # look for specified revision
4980 # look for specified revision
4980 revs = list(revs)
4981 revs = list(revs)
4981 revs.extend(opts['rev'])
4982 revs.extend(opts['rev'])
4982 if not revs:
4983 if not revs:
4983 raise util.Abort(_('no revisions specified'))
4984 raise util.Abort(_('no revisions specified'))
4984
4985
4985 revs = scmutil.revrange(repo, revs)
4986 revs = scmutil.revrange(repo, revs)
4986
4987
4987 lock = None
4988 lock = None
4988 ret = 0
4989 ret = 0
4989 if targetphase is None:
4990 if targetphase is None:
4990 # display
4991 # display
4991 for r in revs:
4992 for r in revs:
4992 ctx = repo[r]
4993 ctx = repo[r]
4993 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4994 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4994 else:
4995 else:
4995 tr = None
4996 tr = None
4996 lock = repo.lock()
4997 lock = repo.lock()
4997 try:
4998 try:
4998 tr = repo.transaction("phase")
4999 tr = repo.transaction("phase")
4999 # set phase
5000 # set phase
5000 if not revs:
5001 if not revs:
5001 raise util.Abort(_('empty revision set'))
5002 raise util.Abort(_('empty revision set'))
5002 nodes = [repo[r].node() for r in revs]
5003 nodes = [repo[r].node() for r in revs]
5003 # moving revision from public to draft may hide them
5004 # moving revision from public to draft may hide them
5004 # We have to check result on an unfiltered repository
5005 # We have to check result on an unfiltered repository
5005 unfi = repo.unfiltered()
5006 unfi = repo.unfiltered()
5006 getphase = unfi._phasecache.phase
5007 getphase = unfi._phasecache.phase
5007 olddata = [getphase(unfi, r) for r in unfi]
5008 olddata = [getphase(unfi, r) for r in unfi]
5008 phases.advanceboundary(repo, tr, targetphase, nodes)
5009 phases.advanceboundary(repo, tr, targetphase, nodes)
5009 if opts['force']:
5010 if opts['force']:
5010 phases.retractboundary(repo, tr, targetphase, nodes)
5011 phases.retractboundary(repo, tr, targetphase, nodes)
5011 tr.close()
5012 tr.close()
5012 finally:
5013 finally:
5013 if tr is not None:
5014 if tr is not None:
5014 tr.release()
5015 tr.release()
5015 lock.release()
5016 lock.release()
5016 getphase = unfi._phasecache.phase
5017 getphase = unfi._phasecache.phase
5017 newdata = [getphase(unfi, r) for r in unfi]
5018 newdata = [getphase(unfi, r) for r in unfi]
5018 changes = sum(newdata[r] != olddata[r] for r in unfi)
5019 changes = sum(newdata[r] != olddata[r] for r in unfi)
5019 cl = unfi.changelog
5020 cl = unfi.changelog
5020 rejected = [n for n in nodes
5021 rejected = [n for n in nodes
5021 if newdata[cl.rev(n)] < targetphase]
5022 if newdata[cl.rev(n)] < targetphase]
5022 if rejected:
5023 if rejected:
5023 ui.warn(_('cannot move %i changesets to a higher '
5024 ui.warn(_('cannot move %i changesets to a higher '
5024 'phase, use --force\n') % len(rejected))
5025 'phase, use --force\n') % len(rejected))
5025 ret = 1
5026 ret = 1
5026 if changes:
5027 if changes:
5027 msg = _('phase changed for %i changesets\n') % changes
5028 msg = _('phase changed for %i changesets\n') % changes
5028 if ret:
5029 if ret:
5029 ui.status(msg)
5030 ui.status(msg)
5030 else:
5031 else:
5031 ui.note(msg)
5032 ui.note(msg)
5032 else:
5033 else:
5033 ui.warn(_('no phases changed\n'))
5034 ui.warn(_('no phases changed\n'))
5034 ret = 1
5035 ret = 1
5035 return ret
5036 return ret
5036
5037
5037 def postincoming(ui, repo, modheads, optupdate, checkout):
5038 def postincoming(ui, repo, modheads, optupdate, checkout):
5038 if modheads == 0:
5039 if modheads == 0:
5039 return
5040 return
5040 if optupdate:
5041 if optupdate:
5041 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
5042 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
5042 try:
5043 try:
5043 ret = hg.update(repo, checkout)
5044 ret = hg.update(repo, checkout)
5044 except util.Abort, inst:
5045 except util.Abort, inst:
5045 ui.warn(_("not updating: %s\n") % str(inst))
5046 ui.warn(_("not updating: %s\n") % str(inst))
5046 if inst.hint:
5047 if inst.hint:
5047 ui.warn(_("(%s)\n") % inst.hint)
5048 ui.warn(_("(%s)\n") % inst.hint)
5048 return 0
5049 return 0
5049 if not ret and not checkout:
5050 if not ret and not checkout:
5050 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5051 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5051 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5052 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5052 return ret
5053 return ret
5053 if modheads > 1:
5054 if modheads > 1:
5054 currentbranchheads = len(repo.branchheads())
5055 currentbranchheads = len(repo.branchheads())
5055 if currentbranchheads == modheads:
5056 if currentbranchheads == modheads:
5056 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5057 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5057 elif currentbranchheads > 1:
5058 elif currentbranchheads > 1:
5058 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5059 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5059 "merge)\n"))
5060 "merge)\n"))
5060 else:
5061 else:
5061 ui.status(_("(run 'hg heads' to see heads)\n"))
5062 ui.status(_("(run 'hg heads' to see heads)\n"))
5062 else:
5063 else:
5063 ui.status(_("(run 'hg update' to get a working copy)\n"))
5064 ui.status(_("(run 'hg update' to get a working copy)\n"))
5064
5065
5065 @command('^pull',
5066 @command('^pull',
5066 [('u', 'update', None,
5067 [('u', 'update', None,
5067 _('update to new branch head if changesets were pulled')),
5068 _('update to new branch head if changesets were pulled')),
5068 ('f', 'force', None, _('run even when remote repository is unrelated')),
5069 ('f', 'force', None, _('run even when remote repository is unrelated')),
5069 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5070 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5070 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5071 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5071 ('b', 'branch', [], _('a specific branch you would like to pull'),
5072 ('b', 'branch', [], _('a specific branch you would like to pull'),
5072 _('BRANCH')),
5073 _('BRANCH')),
5073 ] + remoteopts,
5074 ] + remoteopts,
5074 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5075 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5075 def pull(ui, repo, source="default", **opts):
5076 def pull(ui, repo, source="default", **opts):
5076 """pull changes from the specified source
5077 """pull changes from the specified source
5077
5078
5078 Pull changes from a remote repository to a local one.
5079 Pull changes from a remote repository to a local one.
5079
5080
5080 This finds all changes from the repository at the specified path
5081 This finds all changes from the repository at the specified path
5081 or URL and adds them to a local repository (the current one unless
5082 or URL and adds them to a local repository (the current one unless
5082 -R is specified). By default, this does not update the copy of the
5083 -R is specified). By default, this does not update the copy of the
5083 project in the working directory.
5084 project in the working directory.
5084
5085
5085 Use :hg:`incoming` if you want to see what would have been added
5086 Use :hg:`incoming` if you want to see what would have been added
5086 by a pull at the time you issued this command. If you then decide
5087 by a pull at the time you issued this command. If you then decide
5087 to add those changes to the repository, you should use :hg:`pull
5088 to add those changes to the repository, you should use :hg:`pull
5088 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5089 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5089
5090
5090 If SOURCE is omitted, the 'default' path will be used.
5091 If SOURCE is omitted, the 'default' path will be used.
5091 See :hg:`help urls` for more information.
5092 See :hg:`help urls` for more information.
5092
5093
5093 Returns 0 on success, 1 if an update had unresolved files.
5094 Returns 0 on success, 1 if an update had unresolved files.
5094 """
5095 """
5095 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5096 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5096 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5097 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5097 other = hg.peer(repo, opts, source)
5098 other = hg.peer(repo, opts, source)
5098 try:
5099 try:
5099 revs, checkout = hg.addbranchrevs(repo, other, branches,
5100 revs, checkout = hg.addbranchrevs(repo, other, branches,
5100 opts.get('rev'))
5101 opts.get('rev'))
5101
5102
5102 remotebookmarks = other.listkeys('bookmarks')
5103 remotebookmarks = other.listkeys('bookmarks')
5103
5104
5104 if opts.get('bookmark'):
5105 if opts.get('bookmark'):
5105 if not revs:
5106 if not revs:
5106 revs = []
5107 revs = []
5107 for b in opts['bookmark']:
5108 for b in opts['bookmark']:
5108 if b not in remotebookmarks:
5109 if b not in remotebookmarks:
5109 raise util.Abort(_('remote bookmark %s not found!') % b)
5110 raise util.Abort(_('remote bookmark %s not found!') % b)
5110 revs.append(remotebookmarks[b])
5111 revs.append(remotebookmarks[b])
5111
5112
5112 if revs:
5113 if revs:
5113 try:
5114 try:
5114 revs = [other.lookup(rev) for rev in revs]
5115 revs = [other.lookup(rev) for rev in revs]
5115 except error.CapabilityError:
5116 except error.CapabilityError:
5116 err = _("other repository doesn't support revision lookup, "
5117 err = _("other repository doesn't support revision lookup, "
5117 "so a rev cannot be specified.")
5118 "so a rev cannot be specified.")
5118 raise util.Abort(err)
5119 raise util.Abort(err)
5119
5120
5120 modheads = exchange.pull(repo, other, heads=revs,
5121 modheads = exchange.pull(repo, other, heads=revs,
5121 force=opts.get('force'),
5122 force=opts.get('force'),
5122 bookmarks=opts.get('bookmark', ())).cgresult
5123 bookmarks=opts.get('bookmark', ())).cgresult
5123 if checkout:
5124 if checkout:
5124 checkout = str(repo.changelog.rev(other.lookup(checkout)))
5125 checkout = str(repo.changelog.rev(other.lookup(checkout)))
5125 repo._subtoppath = source
5126 repo._subtoppath = source
5126 try:
5127 try:
5127 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5128 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5128
5129
5129 finally:
5130 finally:
5130 del repo._subtoppath
5131 del repo._subtoppath
5131
5132
5132 finally:
5133 finally:
5133 other.close()
5134 other.close()
5134 return ret
5135 return ret
5135
5136
5136 @command('^push',
5137 @command('^push',
5137 [('f', 'force', None, _('force push')),
5138 [('f', 'force', None, _('force push')),
5138 ('r', 'rev', [],
5139 ('r', 'rev', [],
5139 _('a changeset intended to be included in the destination'),
5140 _('a changeset intended to be included in the destination'),
5140 _('REV')),
5141 _('REV')),
5141 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5142 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5142 ('b', 'branch', [],
5143 ('b', 'branch', [],
5143 _('a specific branch you would like to push'), _('BRANCH')),
5144 _('a specific branch you would like to push'), _('BRANCH')),
5144 ('', 'new-branch', False, _('allow pushing a new branch')),
5145 ('', 'new-branch', False, _('allow pushing a new branch')),
5145 ] + remoteopts,
5146 ] + remoteopts,
5146 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5147 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5147 def push(ui, repo, dest=None, **opts):
5148 def push(ui, repo, dest=None, **opts):
5148 """push changes to the specified destination
5149 """push changes to the specified destination
5149
5150
5150 Push changesets from the local repository to the specified
5151 Push changesets from the local repository to the specified
5151 destination.
5152 destination.
5152
5153
5153 This operation is symmetrical to pull: it is identical to a pull
5154 This operation is symmetrical to pull: it is identical to a pull
5154 in the destination repository from the current one.
5155 in the destination repository from the current one.
5155
5156
5156 By default, push will not allow creation of new heads at the
5157 By default, push will not allow creation of new heads at the
5157 destination, since multiple heads would make it unclear which head
5158 destination, since multiple heads would make it unclear which head
5158 to use. In this situation, it is recommended to pull and merge
5159 to use. In this situation, it is recommended to pull and merge
5159 before pushing.
5160 before pushing.
5160
5161
5161 Use --new-branch if you want to allow push to create a new named
5162 Use --new-branch if you want to allow push to create a new named
5162 branch that is not present at the destination. This allows you to
5163 branch that is not present at the destination. This allows you to
5163 only create a new branch without forcing other changes.
5164 only create a new branch without forcing other changes.
5164
5165
5165 .. note::
5166 .. note::
5166
5167
5167 Extra care should be taken with the -f/--force option,
5168 Extra care should be taken with the -f/--force option,
5168 which will push all new heads on all branches, an action which will
5169 which will push all new heads on all branches, an action which will
5169 almost always cause confusion for collaborators.
5170 almost always cause confusion for collaborators.
5170
5171
5171 If -r/--rev is used, the specified revision and all its ancestors
5172 If -r/--rev is used, the specified revision and all its ancestors
5172 will be pushed to the remote repository.
5173 will be pushed to the remote repository.
5173
5174
5174 If -B/--bookmark is used, the specified bookmarked revision, its
5175 If -B/--bookmark is used, the specified bookmarked revision, its
5175 ancestors, and the bookmark will be pushed to the remote
5176 ancestors, and the bookmark will be pushed to the remote
5176 repository.
5177 repository.
5177
5178
5178 Please see :hg:`help urls` for important details about ``ssh://``
5179 Please see :hg:`help urls` for important details about ``ssh://``
5179 URLs. If DESTINATION is omitted, a default path will be used.
5180 URLs. If DESTINATION is omitted, a default path will be used.
5180
5181
5181 Returns 0 if push was successful, 1 if nothing to push.
5182 Returns 0 if push was successful, 1 if nothing to push.
5182 """
5183 """
5183
5184
5184 if opts.get('bookmark'):
5185 if opts.get('bookmark'):
5185 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5186 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5186 for b in opts['bookmark']:
5187 for b in opts['bookmark']:
5187 # translate -B options to -r so changesets get pushed
5188 # translate -B options to -r so changesets get pushed
5188 if b in repo._bookmarks:
5189 if b in repo._bookmarks:
5189 opts.setdefault('rev', []).append(b)
5190 opts.setdefault('rev', []).append(b)
5190 else:
5191 else:
5191 # if we try to push a deleted bookmark, translate it to null
5192 # if we try to push a deleted bookmark, translate it to null
5192 # this lets simultaneous -r, -b options continue working
5193 # this lets simultaneous -r, -b options continue working
5193 opts.setdefault('rev', []).append("null")
5194 opts.setdefault('rev', []).append("null")
5194
5195
5195 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5196 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5196 dest, branches = hg.parseurl(dest, opts.get('branch'))
5197 dest, branches = hg.parseurl(dest, opts.get('branch'))
5197 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5198 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5198 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5199 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5199 try:
5200 try:
5200 other = hg.peer(repo, opts, dest)
5201 other = hg.peer(repo, opts, dest)
5201 except error.RepoError:
5202 except error.RepoError:
5202 if dest == "default-push":
5203 if dest == "default-push":
5203 raise util.Abort(_("default repository not configured!"),
5204 raise util.Abort(_("default repository not configured!"),
5204 hint=_('see the "path" section in "hg help config"'))
5205 hint=_('see the "path" section in "hg help config"'))
5205 else:
5206 else:
5206 raise
5207 raise
5207
5208
5208 if revs:
5209 if revs:
5209 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5210 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5210 if not revs:
5211 if not revs:
5211 raise util.Abort(_("specified revisions evaluate to an empty set"),
5212 raise util.Abort(_("specified revisions evaluate to an empty set"),
5212 hint=_("use different revision arguments"))
5213 hint=_("use different revision arguments"))
5213
5214
5214 repo._subtoppath = dest
5215 repo._subtoppath = dest
5215 try:
5216 try:
5216 # push subrepos depth-first for coherent ordering
5217 # push subrepos depth-first for coherent ordering
5217 c = repo['']
5218 c = repo['']
5218 subs = c.substate # only repos that are committed
5219 subs = c.substate # only repos that are committed
5219 for s in sorted(subs):
5220 for s in sorted(subs):
5220 result = c.sub(s).push(opts)
5221 result = c.sub(s).push(opts)
5221 if result == 0:
5222 if result == 0:
5222 return not result
5223 return not result
5223 finally:
5224 finally:
5224 del repo._subtoppath
5225 del repo._subtoppath
5225 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5226 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5226 newbranch=opts.get('new_branch'),
5227 newbranch=opts.get('new_branch'),
5227 bookmarks=opts.get('bookmark', ()))
5228 bookmarks=opts.get('bookmark', ()))
5228
5229
5229 result = not pushop.cgresult
5230 result = not pushop.cgresult
5230
5231
5231 if pushop.bkresult is not None:
5232 if pushop.bkresult is not None:
5232 if pushop.bkresult == 2:
5233 if pushop.bkresult == 2:
5233 result = 2
5234 result = 2
5234 elif not result and pushop.bkresult:
5235 elif not result and pushop.bkresult:
5235 result = 2
5236 result = 2
5236
5237
5237 return result
5238 return result
5238
5239
5239 @command('recover', [])
5240 @command('recover', [])
5240 def recover(ui, repo):
5241 def recover(ui, repo):
5241 """roll back an interrupted transaction
5242 """roll back an interrupted transaction
5242
5243
5243 Recover from an interrupted commit or pull.
5244 Recover from an interrupted commit or pull.
5244
5245
5245 This command tries to fix the repository status after an
5246 This command tries to fix the repository status after an
5246 interrupted operation. It should only be necessary when Mercurial
5247 interrupted operation. It should only be necessary when Mercurial
5247 suggests it.
5248 suggests it.
5248
5249
5249 Returns 0 if successful, 1 if nothing to recover or verify fails.
5250 Returns 0 if successful, 1 if nothing to recover or verify fails.
5250 """
5251 """
5251 if repo.recover():
5252 if repo.recover():
5252 return hg.verify(repo)
5253 return hg.verify(repo)
5253 return 1
5254 return 1
5254
5255
5255 @command('^remove|rm',
5256 @command('^remove|rm',
5256 [('A', 'after', None, _('record delete for missing files')),
5257 [('A', 'after', None, _('record delete for missing files')),
5257 ('f', 'force', None,
5258 ('f', 'force', None,
5258 _('remove (and delete) file even if added or modified')),
5259 _('remove (and delete) file even if added or modified')),
5259 ] + subrepoopts + walkopts,
5260 ] + subrepoopts + walkopts,
5260 _('[OPTION]... FILE...'),
5261 _('[OPTION]... FILE...'),
5261 inferrepo=True)
5262 inferrepo=True)
5262 def remove(ui, repo, *pats, **opts):
5263 def remove(ui, repo, *pats, **opts):
5263 """remove the specified files on the next commit
5264 """remove the specified files on the next commit
5264
5265
5265 Schedule the indicated files for removal from the current branch.
5266 Schedule the indicated files for removal from the current branch.
5266
5267
5267 This command schedules the files to be removed at the next commit.
5268 This command schedules the files to be removed at the next commit.
5268 To undo a remove before that, see :hg:`revert`. To undo added
5269 To undo a remove before that, see :hg:`revert`. To undo added
5269 files, see :hg:`forget`.
5270 files, see :hg:`forget`.
5270
5271
5271 .. container:: verbose
5272 .. container:: verbose
5272
5273
5273 -A/--after can be used to remove only files that have already
5274 -A/--after can be used to remove only files that have already
5274 been deleted, -f/--force can be used to force deletion, and -Af
5275 been deleted, -f/--force can be used to force deletion, and -Af
5275 can be used to remove files from the next revision without
5276 can be used to remove files from the next revision without
5276 deleting them from the working directory.
5277 deleting them from the working directory.
5277
5278
5278 The following table details the behavior of remove for different
5279 The following table details the behavior of remove for different
5279 file states (columns) and option combinations (rows). The file
5280 file states (columns) and option combinations (rows). The file
5280 states are Added [A], Clean [C], Modified [M] and Missing [!]
5281 states are Added [A], Clean [C], Modified [M] and Missing [!]
5281 (as reported by :hg:`status`). The actions are Warn, Remove
5282 (as reported by :hg:`status`). The actions are Warn, Remove
5282 (from branch) and Delete (from disk):
5283 (from branch) and Delete (from disk):
5283
5284
5284 ========= == == == ==
5285 ========= == == == ==
5285 opt/state A C M !
5286 opt/state A C M !
5286 ========= == == == ==
5287 ========= == == == ==
5287 none W RD W R
5288 none W RD W R
5288 -f R RD RD R
5289 -f R RD RD R
5289 -A W W W R
5290 -A W W W R
5290 -Af R R R R
5291 -Af R R R R
5291 ========= == == == ==
5292 ========= == == == ==
5292
5293
5293 Note that remove never deletes files in Added [A] state from the
5294 Note that remove never deletes files in Added [A] state from the
5294 working directory, not even if option --force is specified.
5295 working directory, not even if option --force is specified.
5295
5296
5296 Returns 0 on success, 1 if any warnings encountered.
5297 Returns 0 on success, 1 if any warnings encountered.
5297 """
5298 """
5298
5299
5299 after, force = opts.get('after'), opts.get('force')
5300 after, force = opts.get('after'), opts.get('force')
5300 if not pats and not after:
5301 if not pats and not after:
5301 raise util.Abort(_('no files specified'))
5302 raise util.Abort(_('no files specified'))
5302
5303
5303 m = scmutil.match(repo[None], pats, opts)
5304 m = scmutil.match(repo[None], pats, opts)
5304 subrepos = opts.get('subrepos')
5305 subrepos = opts.get('subrepos')
5305 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5306 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5306
5307
5307 @command('rename|move|mv',
5308 @command('rename|move|mv',
5308 [('A', 'after', None, _('record a rename that has already occurred')),
5309 [('A', 'after', None, _('record a rename that has already occurred')),
5309 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5310 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5310 ] + walkopts + dryrunopts,
5311 ] + walkopts + dryrunopts,
5311 _('[OPTION]... SOURCE... DEST'))
5312 _('[OPTION]... SOURCE... DEST'))
5312 def rename(ui, repo, *pats, **opts):
5313 def rename(ui, repo, *pats, **opts):
5313 """rename files; equivalent of copy + remove
5314 """rename files; equivalent of copy + remove
5314
5315
5315 Mark dest as copies of sources; mark sources for deletion. If dest
5316 Mark dest as copies of sources; mark sources for deletion. If dest
5316 is a directory, copies are put in that directory. If dest is a
5317 is a directory, copies are put in that directory. If dest is a
5317 file, there can only be one source.
5318 file, there can only be one source.
5318
5319
5319 By default, this command copies the contents of files as they
5320 By default, this command copies the contents of files as they
5320 exist in the working directory. If invoked with -A/--after, the
5321 exist in the working directory. If invoked with -A/--after, the
5321 operation is recorded, but no copying is performed.
5322 operation is recorded, but no copying is performed.
5322
5323
5323 This command takes effect at the next commit. To undo a rename
5324 This command takes effect at the next commit. To undo a rename
5324 before that, see :hg:`revert`.
5325 before that, see :hg:`revert`.
5325
5326
5326 Returns 0 on success, 1 if errors are encountered.
5327 Returns 0 on success, 1 if errors are encountered.
5327 """
5328 """
5328 wlock = repo.wlock(False)
5329 wlock = repo.wlock(False)
5329 try:
5330 try:
5330 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5331 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5331 finally:
5332 finally:
5332 wlock.release()
5333 wlock.release()
5333
5334
5334 @command('resolve',
5335 @command('resolve',
5335 [('a', 'all', None, _('select all unresolved files')),
5336 [('a', 'all', None, _('select all unresolved files')),
5336 ('l', 'list', None, _('list state of files needing merge')),
5337 ('l', 'list', None, _('list state of files needing merge')),
5337 ('m', 'mark', None, _('mark files as resolved')),
5338 ('m', 'mark', None, _('mark files as resolved')),
5338 ('u', 'unmark', None, _('mark files as unresolved')),
5339 ('u', 'unmark', None, _('mark files as unresolved')),
5339 ('n', 'no-status', None, _('hide status prefix'))]
5340 ('n', 'no-status', None, _('hide status prefix'))]
5340 + mergetoolopts + walkopts + formatteropts,
5341 + mergetoolopts + walkopts + formatteropts,
5341 _('[OPTION]... [FILE]...'),
5342 _('[OPTION]... [FILE]...'),
5342 inferrepo=True)
5343 inferrepo=True)
5343 def resolve(ui, repo, *pats, **opts):
5344 def resolve(ui, repo, *pats, **opts):
5344 """redo merges or set/view the merge status of files
5345 """redo merges or set/view the merge status of files
5345
5346
5346 Merges with unresolved conflicts are often the result of
5347 Merges with unresolved conflicts are often the result of
5347 non-interactive merging using the ``internal:merge`` configuration
5348 non-interactive merging using the ``internal:merge`` configuration
5348 setting, or a command-line merge tool like ``diff3``. The resolve
5349 setting, or a command-line merge tool like ``diff3``. The resolve
5349 command is used to manage the files involved in a merge, after
5350 command is used to manage the files involved in a merge, after
5350 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5351 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5351 working directory must have two parents). See :hg:`help
5352 working directory must have two parents). See :hg:`help
5352 merge-tools` for information on configuring merge tools.
5353 merge-tools` for information on configuring merge tools.
5353
5354
5354 The resolve command can be used in the following ways:
5355 The resolve command can be used in the following ways:
5355
5356
5356 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5357 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5357 files, discarding any previous merge attempts. Re-merging is not
5358 files, discarding any previous merge attempts. Re-merging is not
5358 performed for files already marked as resolved. Use ``--all/-a``
5359 performed for files already marked as resolved. Use ``--all/-a``
5359 to select all unresolved files. ``--tool`` can be used to specify
5360 to select all unresolved files. ``--tool`` can be used to specify
5360 the merge tool used for the given files. It overrides the HGMERGE
5361 the merge tool used for the given files. It overrides the HGMERGE
5361 environment variable and your configuration files. Previous file
5362 environment variable and your configuration files. Previous file
5362 contents are saved with a ``.orig`` suffix.
5363 contents are saved with a ``.orig`` suffix.
5363
5364
5364 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5365 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5365 (e.g. after having manually fixed-up the files). The default is
5366 (e.g. after having manually fixed-up the files). The default is
5366 to mark all unresolved files.
5367 to mark all unresolved files.
5367
5368
5368 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5369 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5369 default is to mark all resolved files.
5370 default is to mark all resolved files.
5370
5371
5371 - :hg:`resolve -l`: list files which had or still have conflicts.
5372 - :hg:`resolve -l`: list files which had or still have conflicts.
5372 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5373 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5373
5374
5374 Note that Mercurial will not let you commit files with unresolved
5375 Note that Mercurial will not let you commit files with unresolved
5375 merge conflicts. You must use :hg:`resolve -m ...` before you can
5376 merge conflicts. You must use :hg:`resolve -m ...` before you can
5376 commit after a conflicting merge.
5377 commit after a conflicting merge.
5377
5378
5378 Returns 0 on success, 1 if any files fail a resolve attempt.
5379 Returns 0 on success, 1 if any files fail a resolve attempt.
5379 """
5380 """
5380
5381
5381 all, mark, unmark, show, nostatus = \
5382 all, mark, unmark, show, nostatus = \
5382 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5383 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5383
5384
5384 if (show and (mark or unmark)) or (mark and unmark):
5385 if (show and (mark or unmark)) or (mark and unmark):
5385 raise util.Abort(_("too many options specified"))
5386 raise util.Abort(_("too many options specified"))
5386 if pats and all:
5387 if pats and all:
5387 raise util.Abort(_("can't specify --all and patterns"))
5388 raise util.Abort(_("can't specify --all and patterns"))
5388 if not (all or pats or show or mark or unmark):
5389 if not (all or pats or show or mark or unmark):
5389 raise util.Abort(_('no files or directories specified'),
5390 raise util.Abort(_('no files or directories specified'),
5390 hint=('use --all to remerge all files'))
5391 hint=('use --all to remerge all files'))
5391
5392
5392 if show:
5393 if show:
5393 fm = ui.formatter('resolve', opts)
5394 fm = ui.formatter('resolve', opts)
5394 ms = mergemod.mergestate(repo)
5395 ms = mergemod.mergestate(repo)
5395 m = scmutil.match(repo[None], pats, opts)
5396 m = scmutil.match(repo[None], pats, opts)
5396 for f in ms:
5397 for f in ms:
5397 if not m(f):
5398 if not m(f):
5398 continue
5399 continue
5399 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5400 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5400 fm.startitem()
5401 fm.startitem()
5401 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5402 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5402 fm.write('path', '%s\n', f, label=l)
5403 fm.write('path', '%s\n', f, label=l)
5403 fm.end()
5404 fm.end()
5404 return 0
5405 return 0
5405
5406
5406 wlock = repo.wlock()
5407 wlock = repo.wlock()
5407 try:
5408 try:
5408 ms = mergemod.mergestate(repo)
5409 ms = mergemod.mergestate(repo)
5409
5410
5410 if not (ms.active() or repo.dirstate.p2() != nullid):
5411 if not (ms.active() or repo.dirstate.p2() != nullid):
5411 raise util.Abort(
5412 raise util.Abort(
5412 _('resolve command not applicable when not merging'))
5413 _('resolve command not applicable when not merging'))
5413
5414
5414 m = scmutil.match(repo[None], pats, opts)
5415 m = scmutil.match(repo[None], pats, opts)
5415 ret = 0
5416 ret = 0
5416 didwork = False
5417 didwork = False
5417
5418
5418 for f in ms:
5419 for f in ms:
5419 if not m(f):
5420 if not m(f):
5420 continue
5421 continue
5421
5422
5422 didwork = True
5423 didwork = True
5423
5424
5424 if mark:
5425 if mark:
5425 ms.mark(f, "r")
5426 ms.mark(f, "r")
5426 elif unmark:
5427 elif unmark:
5427 ms.mark(f, "u")
5428 ms.mark(f, "u")
5428 else:
5429 else:
5429 wctx = repo[None]
5430 wctx = repo[None]
5430
5431
5431 # backup pre-resolve (merge uses .orig for its own purposes)
5432 # backup pre-resolve (merge uses .orig for its own purposes)
5432 a = repo.wjoin(f)
5433 a = repo.wjoin(f)
5433 util.copyfile(a, a + ".resolve")
5434 util.copyfile(a, a + ".resolve")
5434
5435
5435 try:
5436 try:
5436 # resolve file
5437 # resolve file
5437 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5438 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5438 'resolve')
5439 'resolve')
5439 if ms.resolve(f, wctx):
5440 if ms.resolve(f, wctx):
5440 ret = 1
5441 ret = 1
5441 finally:
5442 finally:
5442 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5443 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5443 ms.commit()
5444 ms.commit()
5444
5445
5445 # replace filemerge's .orig file with our resolve file
5446 # replace filemerge's .orig file with our resolve file
5446 util.rename(a + ".resolve", a + ".orig")
5447 util.rename(a + ".resolve", a + ".orig")
5447
5448
5448 ms.commit()
5449 ms.commit()
5449
5450
5450 if not didwork and pats:
5451 if not didwork and pats:
5451 ui.warn(_("arguments do not match paths that need resolving\n"))
5452 ui.warn(_("arguments do not match paths that need resolving\n"))
5452
5453
5453 finally:
5454 finally:
5454 wlock.release()
5455 wlock.release()
5455
5456
5456 # Nudge users into finishing an unfinished operation
5457 # Nudge users into finishing an unfinished operation
5457 if not list(ms.unresolved()):
5458 if not list(ms.unresolved()):
5458 ui.status(_('(no more unresolved files)\n'))
5459 ui.status(_('(no more unresolved files)\n'))
5459
5460
5460 return ret
5461 return ret
5461
5462
5462 @command('revert',
5463 @command('revert',
5463 [('a', 'all', None, _('revert all changes when no arguments given')),
5464 [('a', 'all', None, _('revert all changes when no arguments given')),
5464 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5465 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5465 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5466 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5466 ('C', 'no-backup', None, _('do not save backup copies of files')),
5467 ('C', 'no-backup', None, _('do not save backup copies of files')),
5467 ('i', 'interactive', None,
5468 ('i', 'interactive', None,
5468 _('interactively select the changes (EXPERIMENTAL)')),
5469 _('interactively select the changes (EXPERIMENTAL)')),
5469 ] + walkopts + dryrunopts,
5470 ] + walkopts + dryrunopts,
5470 _('[OPTION]... [-r REV] [NAME]...'))
5471 _('[OPTION]... [-r REV] [NAME]...'))
5471 def revert(ui, repo, *pats, **opts):
5472 def revert(ui, repo, *pats, **opts):
5472 """restore files to their checkout state
5473 """restore files to their checkout state
5473
5474
5474 .. note::
5475 .. note::
5475
5476
5476 To check out earlier revisions, you should use :hg:`update REV`.
5477 To check out earlier revisions, you should use :hg:`update REV`.
5477 To cancel an uncommitted merge (and lose your changes),
5478 To cancel an uncommitted merge (and lose your changes),
5478 use :hg:`update --clean .`.
5479 use :hg:`update --clean .`.
5479
5480
5480 With no revision specified, revert the specified files or directories
5481 With no revision specified, revert the specified files or directories
5481 to the contents they had in the parent of the working directory.
5482 to the contents they had in the parent of the working directory.
5482 This restores the contents of files to an unmodified
5483 This restores the contents of files to an unmodified
5483 state and unschedules adds, removes, copies, and renames. If the
5484 state and unschedules adds, removes, copies, and renames. If the
5484 working directory has two parents, you must explicitly specify a
5485 working directory has two parents, you must explicitly specify a
5485 revision.
5486 revision.
5486
5487
5487 Using the -r/--rev or -d/--date options, revert the given files or
5488 Using the -r/--rev or -d/--date options, revert the given files or
5488 directories to their states as of a specific revision. Because
5489 directories to their states as of a specific revision. Because
5489 revert does not change the working directory parents, this will
5490 revert does not change the working directory parents, this will
5490 cause these files to appear modified. This can be helpful to "back
5491 cause these files to appear modified. This can be helpful to "back
5491 out" some or all of an earlier change. See :hg:`backout` for a
5492 out" some or all of an earlier change. See :hg:`backout` for a
5492 related method.
5493 related method.
5493
5494
5494 Modified files are saved with a .orig suffix before reverting.
5495 Modified files are saved with a .orig suffix before reverting.
5495 To disable these backups, use --no-backup.
5496 To disable these backups, use --no-backup.
5496
5497
5497 See :hg:`help dates` for a list of formats valid for -d/--date.
5498 See :hg:`help dates` for a list of formats valid for -d/--date.
5498
5499
5499 Returns 0 on success.
5500 Returns 0 on success.
5500 """
5501 """
5501
5502
5502 if opts.get("date"):
5503 if opts.get("date"):
5503 if opts.get("rev"):
5504 if opts.get("rev"):
5504 raise util.Abort(_("you can't specify a revision and a date"))
5505 raise util.Abort(_("you can't specify a revision and a date"))
5505 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5506 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5506
5507
5507 parent, p2 = repo.dirstate.parents()
5508 parent, p2 = repo.dirstate.parents()
5508 if not opts.get('rev') and p2 != nullid:
5509 if not opts.get('rev') and p2 != nullid:
5509 # revert after merge is a trap for new users (issue2915)
5510 # revert after merge is a trap for new users (issue2915)
5510 raise util.Abort(_('uncommitted merge with no revision specified'),
5511 raise util.Abort(_('uncommitted merge with no revision specified'),
5511 hint=_('use "hg update" or see "hg help revert"'))
5512 hint=_('use "hg update" or see "hg help revert"'))
5512
5513
5513 ctx = scmutil.revsingle(repo, opts.get('rev'))
5514 ctx = scmutil.revsingle(repo, opts.get('rev'))
5514
5515
5515 if (not (pats or opts.get('include') or opts.get('exclude') or
5516 if (not (pats or opts.get('include') or opts.get('exclude') or
5516 opts.get('all') or opts.get('interactive'))):
5517 opts.get('all') or opts.get('interactive'))):
5517 msg = _("no files or directories specified")
5518 msg = _("no files or directories specified")
5518 if p2 != nullid:
5519 if p2 != nullid:
5519 hint = _("uncommitted merge, use --all to discard all changes,"
5520 hint = _("uncommitted merge, use --all to discard all changes,"
5520 " or 'hg update -C .' to abort the merge")
5521 " or 'hg update -C .' to abort the merge")
5521 raise util.Abort(msg, hint=hint)
5522 raise util.Abort(msg, hint=hint)
5522 dirty = util.any(repo.status())
5523 dirty = util.any(repo.status())
5523 node = ctx.node()
5524 node = ctx.node()
5524 if node != parent:
5525 if node != parent:
5525 if dirty:
5526 if dirty:
5526 hint = _("uncommitted changes, use --all to discard all"
5527 hint = _("uncommitted changes, use --all to discard all"
5527 " changes, or 'hg update %s' to update") % ctx.rev()
5528 " changes, or 'hg update %s' to update") % ctx.rev()
5528 else:
5529 else:
5529 hint = _("use --all to revert all files,"
5530 hint = _("use --all to revert all files,"
5530 " or 'hg update %s' to update") % ctx.rev()
5531 " or 'hg update %s' to update") % ctx.rev()
5531 elif dirty:
5532 elif dirty:
5532 hint = _("uncommitted changes, use --all to discard all changes")
5533 hint = _("uncommitted changes, use --all to discard all changes")
5533 else:
5534 else:
5534 hint = _("use --all to revert all files")
5535 hint = _("use --all to revert all files")
5535 raise util.Abort(msg, hint=hint)
5536 raise util.Abort(msg, hint=hint)
5536
5537
5537 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5538 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5538
5539
5539 @command('rollback', dryrunopts +
5540 @command('rollback', dryrunopts +
5540 [('f', 'force', False, _('ignore safety measures'))])
5541 [('f', 'force', False, _('ignore safety measures'))])
5541 def rollback(ui, repo, **opts):
5542 def rollback(ui, repo, **opts):
5542 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5543 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5543
5544
5544 Please use :hg:`commit --amend` instead of rollback to correct
5545 Please use :hg:`commit --amend` instead of rollback to correct
5545 mistakes in the last commit.
5546 mistakes in the last commit.
5546
5547
5547 This command should be used with care. There is only one level of
5548 This command should be used with care. There is only one level of
5548 rollback, and there is no way to undo a rollback. It will also
5549 rollback, and there is no way to undo a rollback. It will also
5549 restore the dirstate at the time of the last transaction, losing
5550 restore the dirstate at the time of the last transaction, losing
5550 any dirstate changes since that time. This command does not alter
5551 any dirstate changes since that time. This command does not alter
5551 the working directory.
5552 the working directory.
5552
5553
5553 Transactions are used to encapsulate the effects of all commands
5554 Transactions are used to encapsulate the effects of all commands
5554 that create new changesets or propagate existing changesets into a
5555 that create new changesets or propagate existing changesets into a
5555 repository.
5556 repository.
5556
5557
5557 .. container:: verbose
5558 .. container:: verbose
5558
5559
5559 For example, the following commands are transactional, and their
5560 For example, the following commands are transactional, and their
5560 effects can be rolled back:
5561 effects can be rolled back:
5561
5562
5562 - commit
5563 - commit
5563 - import
5564 - import
5564 - pull
5565 - pull
5565 - push (with this repository as the destination)
5566 - push (with this repository as the destination)
5566 - unbundle
5567 - unbundle
5567
5568
5568 To avoid permanent data loss, rollback will refuse to rollback a
5569 To avoid permanent data loss, rollback will refuse to rollback a
5569 commit transaction if it isn't checked out. Use --force to
5570 commit transaction if it isn't checked out. Use --force to
5570 override this protection.
5571 override this protection.
5571
5572
5572 This command is not intended for use on public repositories. Once
5573 This command is not intended for use on public repositories. Once
5573 changes are visible for pull by other users, rolling a transaction
5574 changes are visible for pull by other users, rolling a transaction
5574 back locally is ineffective (someone else may already have pulled
5575 back locally is ineffective (someone else may already have pulled
5575 the changes). Furthermore, a race is possible with readers of the
5576 the changes). Furthermore, a race is possible with readers of the
5576 repository; for example an in-progress pull from the repository
5577 repository; for example an in-progress pull from the repository
5577 may fail if a rollback is performed.
5578 may fail if a rollback is performed.
5578
5579
5579 Returns 0 on success, 1 if no rollback data is available.
5580 Returns 0 on success, 1 if no rollback data is available.
5580 """
5581 """
5581 return repo.rollback(dryrun=opts.get('dry_run'),
5582 return repo.rollback(dryrun=opts.get('dry_run'),
5582 force=opts.get('force'))
5583 force=opts.get('force'))
5583
5584
5584 @command('root', [])
5585 @command('root', [])
5585 def root(ui, repo):
5586 def root(ui, repo):
5586 """print the root (top) of the current working directory
5587 """print the root (top) of the current working directory
5587
5588
5588 Print the root directory of the current repository.
5589 Print the root directory of the current repository.
5589
5590
5590 Returns 0 on success.
5591 Returns 0 on success.
5591 """
5592 """
5592 ui.write(repo.root + "\n")
5593 ui.write(repo.root + "\n")
5593
5594
5594 @command('^serve',
5595 @command('^serve',
5595 [('A', 'accesslog', '', _('name of access log file to write to'),
5596 [('A', 'accesslog', '', _('name of access log file to write to'),
5596 _('FILE')),
5597 _('FILE')),
5597 ('d', 'daemon', None, _('run server in background')),
5598 ('d', 'daemon', None, _('run server in background')),
5598 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5599 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5599 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5600 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5600 # use string type, then we can check if something was passed
5601 # use string type, then we can check if something was passed
5601 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5602 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5602 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5603 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5603 _('ADDR')),
5604 _('ADDR')),
5604 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5605 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5605 _('PREFIX')),
5606 _('PREFIX')),
5606 ('n', 'name', '',
5607 ('n', 'name', '',
5607 _('name to show in web pages (default: working directory)'), _('NAME')),
5608 _('name to show in web pages (default: working directory)'), _('NAME')),
5608 ('', 'web-conf', '',
5609 ('', 'web-conf', '',
5609 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5610 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5610 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5611 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5611 _('FILE')),
5612 _('FILE')),
5612 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5613 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5613 ('', 'stdio', None, _('for remote clients')),
5614 ('', 'stdio', None, _('for remote clients')),
5614 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5615 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5615 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5616 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5616 ('', 'style', '', _('template style to use'), _('STYLE')),
5617 ('', 'style', '', _('template style to use'), _('STYLE')),
5617 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5618 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5618 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5619 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5619 _('[OPTION]...'),
5620 _('[OPTION]...'),
5620 optionalrepo=True)
5621 optionalrepo=True)
5621 def serve(ui, repo, **opts):
5622 def serve(ui, repo, **opts):
5622 """start stand-alone webserver
5623 """start stand-alone webserver
5623
5624
5624 Start a local HTTP repository browser and pull server. You can use
5625 Start a local HTTP repository browser and pull server. You can use
5625 this for ad-hoc sharing and browsing of repositories. It is
5626 this for ad-hoc sharing and browsing of repositories. It is
5626 recommended to use a real web server to serve a repository for
5627 recommended to use a real web server to serve a repository for
5627 longer periods of time.
5628 longer periods of time.
5628
5629
5629 Please note that the server does not implement access control.
5630 Please note that the server does not implement access control.
5630 This means that, by default, anybody can read from the server and
5631 This means that, by default, anybody can read from the server and
5631 nobody can write to it by default. Set the ``web.allow_push``
5632 nobody can write to it by default. Set the ``web.allow_push``
5632 option to ``*`` to allow everybody to push to the server. You
5633 option to ``*`` to allow everybody to push to the server. You
5633 should use a real web server if you need to authenticate users.
5634 should use a real web server if you need to authenticate users.
5634
5635
5635 By default, the server logs accesses to stdout and errors to
5636 By default, the server logs accesses to stdout and errors to
5636 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5637 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5637 files.
5638 files.
5638
5639
5639 To have the server choose a free port number to listen on, specify
5640 To have the server choose a free port number to listen on, specify
5640 a port number of 0; in this case, the server will print the port
5641 a port number of 0; in this case, the server will print the port
5641 number it uses.
5642 number it uses.
5642
5643
5643 Returns 0 on success.
5644 Returns 0 on success.
5644 """
5645 """
5645
5646
5646 if opts["stdio"] and opts["cmdserver"]:
5647 if opts["stdio"] and opts["cmdserver"]:
5647 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5648 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5648
5649
5649 if opts["stdio"]:
5650 if opts["stdio"]:
5650 if repo is None:
5651 if repo is None:
5651 raise error.RepoError(_("there is no Mercurial repository here"
5652 raise error.RepoError(_("there is no Mercurial repository here"
5652 " (.hg not found)"))
5653 " (.hg not found)"))
5653 s = sshserver.sshserver(ui, repo)
5654 s = sshserver.sshserver(ui, repo)
5654 s.serve_forever()
5655 s.serve_forever()
5655
5656
5656 if opts["cmdserver"]:
5657 if opts["cmdserver"]:
5657 service = commandserver.createservice(ui, repo, opts)
5658 service = commandserver.createservice(ui, repo, opts)
5658 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5659 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5659
5660
5660 # this way we can check if something was given in the command-line
5661 # this way we can check if something was given in the command-line
5661 if opts.get('port'):
5662 if opts.get('port'):
5662 opts['port'] = util.getport(opts.get('port'))
5663 opts['port'] = util.getport(opts.get('port'))
5663
5664
5664 if repo:
5665 if repo:
5665 baseui = repo.baseui
5666 baseui = repo.baseui
5666 else:
5667 else:
5667 baseui = ui
5668 baseui = ui
5668 optlist = ("name templates style address port prefix ipv6"
5669 optlist = ("name templates style address port prefix ipv6"
5669 " accesslog errorlog certificate encoding")
5670 " accesslog errorlog certificate encoding")
5670 for o in optlist.split():
5671 for o in optlist.split():
5671 val = opts.get(o, '')
5672 val = opts.get(o, '')
5672 if val in (None, ''): # should check against default options instead
5673 if val in (None, ''): # should check against default options instead
5673 continue
5674 continue
5674 baseui.setconfig("web", o, val, 'serve')
5675 baseui.setconfig("web", o, val, 'serve')
5675 if repo and repo.ui != baseui:
5676 if repo and repo.ui != baseui:
5676 repo.ui.setconfig("web", o, val, 'serve')
5677 repo.ui.setconfig("web", o, val, 'serve')
5677
5678
5678 o = opts.get('web_conf') or opts.get('webdir_conf')
5679 o = opts.get('web_conf') or opts.get('webdir_conf')
5679 if not o:
5680 if not o:
5680 if not repo:
5681 if not repo:
5681 raise error.RepoError(_("there is no Mercurial repository"
5682 raise error.RepoError(_("there is no Mercurial repository"
5682 " here (.hg not found)"))
5683 " here (.hg not found)"))
5683 o = repo
5684 o = repo
5684
5685
5685 app = hgweb.hgweb(o, baseui=baseui)
5686 app = hgweb.hgweb(o, baseui=baseui)
5686 service = httpservice(ui, app, opts)
5687 service = httpservice(ui, app, opts)
5687 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5688 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5688
5689
5689 class httpservice(object):
5690 class httpservice(object):
5690 def __init__(self, ui, app, opts):
5691 def __init__(self, ui, app, opts):
5691 self.ui = ui
5692 self.ui = ui
5692 self.app = app
5693 self.app = app
5693 self.opts = opts
5694 self.opts = opts
5694
5695
5695 def init(self):
5696 def init(self):
5696 util.setsignalhandler()
5697 util.setsignalhandler()
5697 self.httpd = hgweb_server.create_server(self.ui, self.app)
5698 self.httpd = hgweb_server.create_server(self.ui, self.app)
5698
5699
5699 if self.opts['port'] and not self.ui.verbose:
5700 if self.opts['port'] and not self.ui.verbose:
5700 return
5701 return
5701
5702
5702 if self.httpd.prefix:
5703 if self.httpd.prefix:
5703 prefix = self.httpd.prefix.strip('/') + '/'
5704 prefix = self.httpd.prefix.strip('/') + '/'
5704 else:
5705 else:
5705 prefix = ''
5706 prefix = ''
5706
5707
5707 port = ':%d' % self.httpd.port
5708 port = ':%d' % self.httpd.port
5708 if port == ':80':
5709 if port == ':80':
5709 port = ''
5710 port = ''
5710
5711
5711 bindaddr = self.httpd.addr
5712 bindaddr = self.httpd.addr
5712 if bindaddr == '0.0.0.0':
5713 if bindaddr == '0.0.0.0':
5713 bindaddr = '*'
5714 bindaddr = '*'
5714 elif ':' in bindaddr: # IPv6
5715 elif ':' in bindaddr: # IPv6
5715 bindaddr = '[%s]' % bindaddr
5716 bindaddr = '[%s]' % bindaddr
5716
5717
5717 fqaddr = self.httpd.fqaddr
5718 fqaddr = self.httpd.fqaddr
5718 if ':' in fqaddr:
5719 if ':' in fqaddr:
5719 fqaddr = '[%s]' % fqaddr
5720 fqaddr = '[%s]' % fqaddr
5720 if self.opts['port']:
5721 if self.opts['port']:
5721 write = self.ui.status
5722 write = self.ui.status
5722 else:
5723 else:
5723 write = self.ui.write
5724 write = self.ui.write
5724 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5725 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5725 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5726 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5726 self.ui.flush() # avoid buffering of status message
5727 self.ui.flush() # avoid buffering of status message
5727
5728
5728 def run(self):
5729 def run(self):
5729 self.httpd.serve_forever()
5730 self.httpd.serve_forever()
5730
5731
5731
5732
5732 @command('^status|st',
5733 @command('^status|st',
5733 [('A', 'all', None, _('show status of all files')),
5734 [('A', 'all', None, _('show status of all files')),
5734 ('m', 'modified', None, _('show only modified files')),
5735 ('m', 'modified', None, _('show only modified files')),
5735 ('a', 'added', None, _('show only added files')),
5736 ('a', 'added', None, _('show only added files')),
5736 ('r', 'removed', None, _('show only removed files')),
5737 ('r', 'removed', None, _('show only removed files')),
5737 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5738 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5738 ('c', 'clean', None, _('show only files without changes')),
5739 ('c', 'clean', None, _('show only files without changes')),
5739 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5740 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5740 ('i', 'ignored', None, _('show only ignored files')),
5741 ('i', 'ignored', None, _('show only ignored files')),
5741 ('n', 'no-status', None, _('hide status prefix')),
5742 ('n', 'no-status', None, _('hide status prefix')),
5742 ('C', 'copies', None, _('show source of copied files')),
5743 ('C', 'copies', None, _('show source of copied files')),
5743 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5744 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5744 ('', 'rev', [], _('show difference from revision'), _('REV')),
5745 ('', 'rev', [], _('show difference from revision'), _('REV')),
5745 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5746 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5746 ] + walkopts + subrepoopts + formatteropts,
5747 ] + walkopts + subrepoopts + formatteropts,
5747 _('[OPTION]... [FILE]...'),
5748 _('[OPTION]... [FILE]...'),
5748 inferrepo=True)
5749 inferrepo=True)
5749 def status(ui, repo, *pats, **opts):
5750 def status(ui, repo, *pats, **opts):
5750 """show changed files in the working directory
5751 """show changed files in the working directory
5751
5752
5752 Show status of files in the repository. If names are given, only
5753 Show status of files in the repository. If names are given, only
5753 files that match are shown. Files that are clean or ignored or
5754 files that match are shown. Files that are clean or ignored or
5754 the source of a copy/move operation, are not listed unless
5755 the source of a copy/move operation, are not listed unless
5755 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5756 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5756 Unless options described with "show only ..." are given, the
5757 Unless options described with "show only ..." are given, the
5757 options -mardu are used.
5758 options -mardu are used.
5758
5759
5759 Option -q/--quiet hides untracked (unknown and ignored) files
5760 Option -q/--quiet hides untracked (unknown and ignored) files
5760 unless explicitly requested with -u/--unknown or -i/--ignored.
5761 unless explicitly requested with -u/--unknown or -i/--ignored.
5761
5762
5762 .. note::
5763 .. note::
5763
5764
5764 status may appear to disagree with diff if permissions have
5765 status may appear to disagree with diff if permissions have
5765 changed or a merge has occurred. The standard diff format does
5766 changed or a merge has occurred. The standard diff format does
5766 not report permission changes and diff only reports changes
5767 not report permission changes and diff only reports changes
5767 relative to one merge parent.
5768 relative to one merge parent.
5768
5769
5769 If one revision is given, it is used as the base revision.
5770 If one revision is given, it is used as the base revision.
5770 If two revisions are given, the differences between them are
5771 If two revisions are given, the differences between them are
5771 shown. The --change option can also be used as a shortcut to list
5772 shown. The --change option can also be used as a shortcut to list
5772 the changed files of a revision from its first parent.
5773 the changed files of a revision from its first parent.
5773
5774
5774 The codes used to show the status of files are::
5775 The codes used to show the status of files are::
5775
5776
5776 M = modified
5777 M = modified
5777 A = added
5778 A = added
5778 R = removed
5779 R = removed
5779 C = clean
5780 C = clean
5780 ! = missing (deleted by non-hg command, but still tracked)
5781 ! = missing (deleted by non-hg command, but still tracked)
5781 ? = not tracked
5782 ? = not tracked
5782 I = ignored
5783 I = ignored
5783 = origin of the previous file (with --copies)
5784 = origin of the previous file (with --copies)
5784
5785
5785 .. container:: verbose
5786 .. container:: verbose
5786
5787
5787 Examples:
5788 Examples:
5788
5789
5789 - show changes in the working directory relative to a
5790 - show changes in the working directory relative to a
5790 changeset::
5791 changeset::
5791
5792
5792 hg status --rev 9353
5793 hg status --rev 9353
5793
5794
5794 - show changes in the working directory relative to the
5795 - show changes in the working directory relative to the
5795 current directory (see :hg:`help patterns` for more information)::
5796 current directory (see :hg:`help patterns` for more information)::
5796
5797
5797 hg status re:
5798 hg status re:
5798
5799
5799 - show all changes including copies in an existing changeset::
5800 - show all changes including copies in an existing changeset::
5800
5801
5801 hg status --copies --change 9353
5802 hg status --copies --change 9353
5802
5803
5803 - get a NUL separated list of added files, suitable for xargs::
5804 - get a NUL separated list of added files, suitable for xargs::
5804
5805
5805 hg status -an0
5806 hg status -an0
5806
5807
5807 Returns 0 on success.
5808 Returns 0 on success.
5808 """
5809 """
5809
5810
5810 revs = opts.get('rev')
5811 revs = opts.get('rev')
5811 change = opts.get('change')
5812 change = opts.get('change')
5812
5813
5813 if revs and change:
5814 if revs and change:
5814 msg = _('cannot specify --rev and --change at the same time')
5815 msg = _('cannot specify --rev and --change at the same time')
5815 raise util.Abort(msg)
5816 raise util.Abort(msg)
5816 elif change:
5817 elif change:
5817 node2 = scmutil.revsingle(repo, change, None).node()
5818 node2 = scmutil.revsingle(repo, change, None).node()
5818 node1 = repo[node2].p1().node()
5819 node1 = repo[node2].p1().node()
5819 else:
5820 else:
5820 node1, node2 = scmutil.revpair(repo, revs)
5821 node1, node2 = scmutil.revpair(repo, revs)
5821
5822
5822 if pats:
5823 if pats:
5823 cwd = repo.getcwd()
5824 cwd = repo.getcwd()
5824 else:
5825 else:
5825 cwd = ''
5826 cwd = ''
5826
5827
5827 if opts.get('print0'):
5828 if opts.get('print0'):
5828 end = '\0'
5829 end = '\0'
5829 else:
5830 else:
5830 end = '\n'
5831 end = '\n'
5831 copy = {}
5832 copy = {}
5832 states = 'modified added removed deleted unknown ignored clean'.split()
5833 states = 'modified added removed deleted unknown ignored clean'.split()
5833 show = [k for k in states if opts.get(k)]
5834 show = [k for k in states if opts.get(k)]
5834 if opts.get('all'):
5835 if opts.get('all'):
5835 show += ui.quiet and (states[:4] + ['clean']) or states
5836 show += ui.quiet and (states[:4] + ['clean']) or states
5836 if not show:
5837 if not show:
5837 if ui.quiet:
5838 if ui.quiet:
5838 show = states[:4]
5839 show = states[:4]
5839 else:
5840 else:
5840 show = states[:5]
5841 show = states[:5]
5841
5842
5842 m = scmutil.match(repo[node2], pats, opts)
5843 m = scmutil.match(repo[node2], pats, opts)
5843 stat = repo.status(node1, node2, m,
5844 stat = repo.status(node1, node2, m,
5844 'ignored' in show, 'clean' in show, 'unknown' in show,
5845 'ignored' in show, 'clean' in show, 'unknown' in show,
5845 opts.get('subrepos'))
5846 opts.get('subrepos'))
5846 changestates = zip(states, 'MAR!?IC', stat)
5847 changestates = zip(states, 'MAR!?IC', stat)
5847
5848
5848 if (opts.get('all') or opts.get('copies')
5849 if (opts.get('all') or opts.get('copies')
5849 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5850 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5850 copy = copies.pathcopies(repo[node1], repo[node2], m)
5851 copy = copies.pathcopies(repo[node1], repo[node2], m)
5851
5852
5852 fm = ui.formatter('status', opts)
5853 fm = ui.formatter('status', opts)
5853 fmt = '%s' + end
5854 fmt = '%s' + end
5854 showchar = not opts.get('no_status')
5855 showchar = not opts.get('no_status')
5855
5856
5856 for state, char, files in changestates:
5857 for state, char, files in changestates:
5857 if state in show:
5858 if state in show:
5858 label = 'status.' + state
5859 label = 'status.' + state
5859 for f in files:
5860 for f in files:
5860 fm.startitem()
5861 fm.startitem()
5861 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5862 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5862 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5863 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5863 if f in copy:
5864 if f in copy:
5864 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5865 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5865 label='status.copied')
5866 label='status.copied')
5866 fm.end()
5867 fm.end()
5867
5868
5868 @command('^summary|sum',
5869 @command('^summary|sum',
5869 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5870 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5870 def summary(ui, repo, **opts):
5871 def summary(ui, repo, **opts):
5871 """summarize working directory state
5872 """summarize working directory state
5872
5873
5873 This generates a brief summary of the working directory state,
5874 This generates a brief summary of the working directory state,
5874 including parents, branch, commit status, and available updates.
5875 including parents, branch, commit status, and available updates.
5875
5876
5876 With the --remote option, this will check the default paths for
5877 With the --remote option, this will check the default paths for
5877 incoming and outgoing changes. This can be time-consuming.
5878 incoming and outgoing changes. This can be time-consuming.
5878
5879
5879 Returns 0 on success.
5880 Returns 0 on success.
5880 """
5881 """
5881
5882
5882 ctx = repo[None]
5883 ctx = repo[None]
5883 parents = ctx.parents()
5884 parents = ctx.parents()
5884 pnode = parents[0].node()
5885 pnode = parents[0].node()
5885 marks = []
5886 marks = []
5886
5887
5887 for p in parents:
5888 for p in parents:
5888 # label with log.changeset (instead of log.parent) since this
5889 # label with log.changeset (instead of log.parent) since this
5889 # shows a working directory parent *changeset*:
5890 # shows a working directory parent *changeset*:
5890 # i18n: column positioning for "hg summary"
5891 # i18n: column positioning for "hg summary"
5891 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5892 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5892 label='log.changeset changeset.%s' % p.phasestr())
5893 label='log.changeset changeset.%s' % p.phasestr())
5893 ui.write(' '.join(p.tags()), label='log.tag')
5894 ui.write(' '.join(p.tags()), label='log.tag')
5894 if p.bookmarks():
5895 if p.bookmarks():
5895 marks.extend(p.bookmarks())
5896 marks.extend(p.bookmarks())
5896 if p.rev() == -1:
5897 if p.rev() == -1:
5897 if not len(repo):
5898 if not len(repo):
5898 ui.write(_(' (empty repository)'))
5899 ui.write(_(' (empty repository)'))
5899 else:
5900 else:
5900 ui.write(_(' (no revision checked out)'))
5901 ui.write(_(' (no revision checked out)'))
5901 ui.write('\n')
5902 ui.write('\n')
5902 if p.description():
5903 if p.description():
5903 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5904 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5904 label='log.summary')
5905 label='log.summary')
5905
5906
5906 branch = ctx.branch()
5907 branch = ctx.branch()
5907 bheads = repo.branchheads(branch)
5908 bheads = repo.branchheads(branch)
5908 # i18n: column positioning for "hg summary"
5909 # i18n: column positioning for "hg summary"
5909 m = _('branch: %s\n') % branch
5910 m = _('branch: %s\n') % branch
5910 if branch != 'default':
5911 if branch != 'default':
5911 ui.write(m, label='log.branch')
5912 ui.write(m, label='log.branch')
5912 else:
5913 else:
5913 ui.status(m, label='log.branch')
5914 ui.status(m, label='log.branch')
5914
5915
5915 if marks:
5916 if marks:
5916 current = repo._bookmarkcurrent
5917 current = repo._bookmarkcurrent
5917 # i18n: column positioning for "hg summary"
5918 # i18n: column positioning for "hg summary"
5918 ui.write(_('bookmarks:'), label='log.bookmark')
5919 ui.write(_('bookmarks:'), label='log.bookmark')
5919 if current is not None:
5920 if current is not None:
5920 if current in marks:
5921 if current in marks:
5921 ui.write(' *' + current, label='bookmarks.current')
5922 ui.write(' *' + current, label='bookmarks.current')
5922 marks.remove(current)
5923 marks.remove(current)
5923 else:
5924 else:
5924 ui.write(' [%s]' % current, label='bookmarks.current')
5925 ui.write(' [%s]' % current, label='bookmarks.current')
5925 for m in marks:
5926 for m in marks:
5926 ui.write(' ' + m, label='log.bookmark')
5927 ui.write(' ' + m, label='log.bookmark')
5927 ui.write('\n', label='log.bookmark')
5928 ui.write('\n', label='log.bookmark')
5928
5929
5929 status = repo.status(unknown=True)
5930 status = repo.status(unknown=True)
5930
5931
5931 c = repo.dirstate.copies()
5932 c = repo.dirstate.copies()
5932 copied, renamed = [], []
5933 copied, renamed = [], []
5933 for d, s in c.iteritems():
5934 for d, s in c.iteritems():
5934 if s in status.removed:
5935 if s in status.removed:
5935 status.removed.remove(s)
5936 status.removed.remove(s)
5936 renamed.append(d)
5937 renamed.append(d)
5937 else:
5938 else:
5938 copied.append(d)
5939 copied.append(d)
5939 if d in status.added:
5940 if d in status.added:
5940 status.added.remove(d)
5941 status.added.remove(d)
5941
5942
5942 ms = mergemod.mergestate(repo)
5943 ms = mergemod.mergestate(repo)
5943 unresolved = [f for f in ms if ms[f] == 'u']
5944 unresolved = [f for f in ms if ms[f] == 'u']
5944
5945
5945 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5946 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5946
5947
5947 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5948 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5948 (ui.label(_('%d added'), 'status.added'), status.added),
5949 (ui.label(_('%d added'), 'status.added'), status.added),
5949 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5950 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5950 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5951 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5951 (ui.label(_('%d copied'), 'status.copied'), copied),
5952 (ui.label(_('%d copied'), 'status.copied'), copied),
5952 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5953 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5953 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5954 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5954 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5955 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5955 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5956 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5956 t = []
5957 t = []
5957 for l, s in labels:
5958 for l, s in labels:
5958 if s:
5959 if s:
5959 t.append(l % len(s))
5960 t.append(l % len(s))
5960
5961
5961 t = ', '.join(t)
5962 t = ', '.join(t)
5962 cleanworkdir = False
5963 cleanworkdir = False
5963
5964
5964 if repo.vfs.exists('updatestate'):
5965 if repo.vfs.exists('updatestate'):
5965 t += _(' (interrupted update)')
5966 t += _(' (interrupted update)')
5966 elif len(parents) > 1:
5967 elif len(parents) > 1:
5967 t += _(' (merge)')
5968 t += _(' (merge)')
5968 elif branch != parents[0].branch():
5969 elif branch != parents[0].branch():
5969 t += _(' (new branch)')
5970 t += _(' (new branch)')
5970 elif (parents[0].closesbranch() and
5971 elif (parents[0].closesbranch() and
5971 pnode in repo.branchheads(branch, closed=True)):
5972 pnode in repo.branchheads(branch, closed=True)):
5972 t += _(' (head closed)')
5973 t += _(' (head closed)')
5973 elif not (status.modified or status.added or status.removed or renamed or
5974 elif not (status.modified or status.added or status.removed or renamed or
5974 copied or subs):
5975 copied or subs):
5975 t += _(' (clean)')
5976 t += _(' (clean)')
5976 cleanworkdir = True
5977 cleanworkdir = True
5977 elif pnode not in bheads:
5978 elif pnode not in bheads:
5978 t += _(' (new branch head)')
5979 t += _(' (new branch head)')
5979
5980
5980 if cleanworkdir:
5981 if cleanworkdir:
5981 # i18n: column positioning for "hg summary"
5982 # i18n: column positioning for "hg summary"
5982 ui.status(_('commit: %s\n') % t.strip())
5983 ui.status(_('commit: %s\n') % t.strip())
5983 else:
5984 else:
5984 # i18n: column positioning for "hg summary"
5985 # i18n: column positioning for "hg summary"
5985 ui.write(_('commit: %s\n') % t.strip())
5986 ui.write(_('commit: %s\n') % t.strip())
5986
5987
5987 # all ancestors of branch heads - all ancestors of parent = new csets
5988 # all ancestors of branch heads - all ancestors of parent = new csets
5988 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5989 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5989 bheads))
5990 bheads))
5990
5991
5991 if new == 0:
5992 if new == 0:
5992 # i18n: column positioning for "hg summary"
5993 # i18n: column positioning for "hg summary"
5993 ui.status(_('update: (current)\n'))
5994 ui.status(_('update: (current)\n'))
5994 elif pnode not in bheads:
5995 elif pnode not in bheads:
5995 # i18n: column positioning for "hg summary"
5996 # i18n: column positioning for "hg summary"
5996 ui.write(_('update: %d new changesets (update)\n') % new)
5997 ui.write(_('update: %d new changesets (update)\n') % new)
5997 else:
5998 else:
5998 # i18n: column positioning for "hg summary"
5999 # i18n: column positioning for "hg summary"
5999 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6000 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6000 (new, len(bheads)))
6001 (new, len(bheads)))
6001
6002
6002 cmdutil.summaryhooks(ui, repo)
6003 cmdutil.summaryhooks(ui, repo)
6003
6004
6004 if opts.get('remote'):
6005 if opts.get('remote'):
6005 needsincoming, needsoutgoing = True, True
6006 needsincoming, needsoutgoing = True, True
6006 else:
6007 else:
6007 needsincoming, needsoutgoing = False, False
6008 needsincoming, needsoutgoing = False, False
6008 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6009 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6009 if i:
6010 if i:
6010 needsincoming = True
6011 needsincoming = True
6011 if o:
6012 if o:
6012 needsoutgoing = True
6013 needsoutgoing = True
6013 if not needsincoming and not needsoutgoing:
6014 if not needsincoming and not needsoutgoing:
6014 return
6015 return
6015
6016
6016 def getincoming():
6017 def getincoming():
6017 source, branches = hg.parseurl(ui.expandpath('default'))
6018 source, branches = hg.parseurl(ui.expandpath('default'))
6018 sbranch = branches[0]
6019 sbranch = branches[0]
6019 try:
6020 try:
6020 other = hg.peer(repo, {}, source)
6021 other = hg.peer(repo, {}, source)
6021 except error.RepoError:
6022 except error.RepoError:
6022 if opts.get('remote'):
6023 if opts.get('remote'):
6023 raise
6024 raise
6024 return source, sbranch, None, None, None
6025 return source, sbranch, None, None, None
6025 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6026 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6026 if revs:
6027 if revs:
6027 revs = [other.lookup(rev) for rev in revs]
6028 revs = [other.lookup(rev) for rev in revs]
6028 ui.debug('comparing with %s\n' % util.hidepassword(source))
6029 ui.debug('comparing with %s\n' % util.hidepassword(source))
6029 repo.ui.pushbuffer()
6030 repo.ui.pushbuffer()
6030 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6031 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6031 repo.ui.popbuffer()
6032 repo.ui.popbuffer()
6032 return source, sbranch, other, commoninc, commoninc[1]
6033 return source, sbranch, other, commoninc, commoninc[1]
6033
6034
6034 if needsincoming:
6035 if needsincoming:
6035 source, sbranch, sother, commoninc, incoming = getincoming()
6036 source, sbranch, sother, commoninc, incoming = getincoming()
6036 else:
6037 else:
6037 source = sbranch = sother = commoninc = incoming = None
6038 source = sbranch = sother = commoninc = incoming = None
6038
6039
6039 def getoutgoing():
6040 def getoutgoing():
6040 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6041 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6041 dbranch = branches[0]
6042 dbranch = branches[0]
6042 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6043 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6043 if source != dest:
6044 if source != dest:
6044 try:
6045 try:
6045 dother = hg.peer(repo, {}, dest)
6046 dother = hg.peer(repo, {}, dest)
6046 except error.RepoError:
6047 except error.RepoError:
6047 if opts.get('remote'):
6048 if opts.get('remote'):
6048 raise
6049 raise
6049 return dest, dbranch, None, None
6050 return dest, dbranch, None, None
6050 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6051 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6051 elif sother is None:
6052 elif sother is None:
6052 # there is no explicit destination peer, but source one is invalid
6053 # there is no explicit destination peer, but source one is invalid
6053 return dest, dbranch, None, None
6054 return dest, dbranch, None, None
6054 else:
6055 else:
6055 dother = sother
6056 dother = sother
6056 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6057 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6057 common = None
6058 common = None
6058 else:
6059 else:
6059 common = commoninc
6060 common = commoninc
6060 if revs:
6061 if revs:
6061 revs = [repo.lookup(rev) for rev in revs]
6062 revs = [repo.lookup(rev) for rev in revs]
6062 repo.ui.pushbuffer()
6063 repo.ui.pushbuffer()
6063 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6064 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6064 commoninc=common)
6065 commoninc=common)
6065 repo.ui.popbuffer()
6066 repo.ui.popbuffer()
6066 return dest, dbranch, dother, outgoing
6067 return dest, dbranch, dother, outgoing
6067
6068
6068 if needsoutgoing:
6069 if needsoutgoing:
6069 dest, dbranch, dother, outgoing = getoutgoing()
6070 dest, dbranch, dother, outgoing = getoutgoing()
6070 else:
6071 else:
6071 dest = dbranch = dother = outgoing = None
6072 dest = dbranch = dother = outgoing = None
6072
6073
6073 if opts.get('remote'):
6074 if opts.get('remote'):
6074 t = []
6075 t = []
6075 if incoming:
6076 if incoming:
6076 t.append(_('1 or more incoming'))
6077 t.append(_('1 or more incoming'))
6077 o = outgoing.missing
6078 o = outgoing.missing
6078 if o:
6079 if o:
6079 t.append(_('%d outgoing') % len(o))
6080 t.append(_('%d outgoing') % len(o))
6080 other = dother or sother
6081 other = dother or sother
6081 if 'bookmarks' in other.listkeys('namespaces'):
6082 if 'bookmarks' in other.listkeys('namespaces'):
6082 counts = bookmarks.summary(repo, other)
6083 counts = bookmarks.summary(repo, other)
6083 if counts[0] > 0:
6084 if counts[0] > 0:
6084 t.append(_('%d incoming bookmarks') % counts[0])
6085 t.append(_('%d incoming bookmarks') % counts[0])
6085 if counts[1] > 0:
6086 if counts[1] > 0:
6086 t.append(_('%d outgoing bookmarks') % counts[1])
6087 t.append(_('%d outgoing bookmarks') % counts[1])
6087
6088
6088 if t:
6089 if t:
6089 # i18n: column positioning for "hg summary"
6090 # i18n: column positioning for "hg summary"
6090 ui.write(_('remote: %s\n') % (', '.join(t)))
6091 ui.write(_('remote: %s\n') % (', '.join(t)))
6091 else:
6092 else:
6092 # i18n: column positioning for "hg summary"
6093 # i18n: column positioning for "hg summary"
6093 ui.status(_('remote: (synced)\n'))
6094 ui.status(_('remote: (synced)\n'))
6094
6095
6095 cmdutil.summaryremotehooks(ui, repo, opts,
6096 cmdutil.summaryremotehooks(ui, repo, opts,
6096 ((source, sbranch, sother, commoninc),
6097 ((source, sbranch, sother, commoninc),
6097 (dest, dbranch, dother, outgoing)))
6098 (dest, dbranch, dother, outgoing)))
6098
6099
6099 @command('tag',
6100 @command('tag',
6100 [('f', 'force', None, _('force tag')),
6101 [('f', 'force', None, _('force tag')),
6101 ('l', 'local', None, _('make the tag local')),
6102 ('l', 'local', None, _('make the tag local')),
6102 ('r', 'rev', '', _('revision to tag'), _('REV')),
6103 ('r', 'rev', '', _('revision to tag'), _('REV')),
6103 ('', 'remove', None, _('remove a tag')),
6104 ('', 'remove', None, _('remove a tag')),
6104 # -l/--local is already there, commitopts cannot be used
6105 # -l/--local is already there, commitopts cannot be used
6105 ('e', 'edit', None, _('invoke editor on commit messages')),
6106 ('e', 'edit', None, _('invoke editor on commit messages')),
6106 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6107 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6107 ] + commitopts2,
6108 ] + commitopts2,
6108 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6109 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6109 def tag(ui, repo, name1, *names, **opts):
6110 def tag(ui, repo, name1, *names, **opts):
6110 """add one or more tags for the current or given revision
6111 """add one or more tags for the current or given revision
6111
6112
6112 Name a particular revision using <name>.
6113 Name a particular revision using <name>.
6113
6114
6114 Tags are used to name particular revisions of the repository and are
6115 Tags are used to name particular revisions of the repository and are
6115 very useful to compare different revisions, to go back to significant
6116 very useful to compare different revisions, to go back to significant
6116 earlier versions or to mark branch points as releases, etc. Changing
6117 earlier versions or to mark branch points as releases, etc. Changing
6117 an existing tag is normally disallowed; use -f/--force to override.
6118 an existing tag is normally disallowed; use -f/--force to override.
6118
6119
6119 If no revision is given, the parent of the working directory is
6120 If no revision is given, the parent of the working directory is
6120 used.
6121 used.
6121
6122
6122 To facilitate version control, distribution, and merging of tags,
6123 To facilitate version control, distribution, and merging of tags,
6123 they are stored as a file named ".hgtags" which is managed similarly
6124 they are stored as a file named ".hgtags" which is managed similarly
6124 to other project files and can be hand-edited if necessary. This
6125 to other project files and can be hand-edited if necessary. This
6125 also means that tagging creates a new commit. The file
6126 also means that tagging creates a new commit. The file
6126 ".hg/localtags" is used for local tags (not shared among
6127 ".hg/localtags" is used for local tags (not shared among
6127 repositories).
6128 repositories).
6128
6129
6129 Tag commits are usually made at the head of a branch. If the parent
6130 Tag commits are usually made at the head of a branch. If the parent
6130 of the working directory is not a branch head, :hg:`tag` aborts; use
6131 of the working directory is not a branch head, :hg:`tag` aborts; use
6131 -f/--force to force the tag commit to be based on a non-head
6132 -f/--force to force the tag commit to be based on a non-head
6132 changeset.
6133 changeset.
6133
6134
6134 See :hg:`help dates` for a list of formats valid for -d/--date.
6135 See :hg:`help dates` for a list of formats valid for -d/--date.
6135
6136
6136 Since tag names have priority over branch names during revision
6137 Since tag names have priority over branch names during revision
6137 lookup, using an existing branch name as a tag name is discouraged.
6138 lookup, using an existing branch name as a tag name is discouraged.
6138
6139
6139 Returns 0 on success.
6140 Returns 0 on success.
6140 """
6141 """
6141 wlock = lock = None
6142 wlock = lock = None
6142 try:
6143 try:
6143 wlock = repo.wlock()
6144 wlock = repo.wlock()
6144 lock = repo.lock()
6145 lock = repo.lock()
6145 rev_ = "."
6146 rev_ = "."
6146 names = [t.strip() for t in (name1,) + names]
6147 names = [t.strip() for t in (name1,) + names]
6147 if len(names) != len(set(names)):
6148 if len(names) != len(set(names)):
6148 raise util.Abort(_('tag names must be unique'))
6149 raise util.Abort(_('tag names must be unique'))
6149 for n in names:
6150 for n in names:
6150 scmutil.checknewlabel(repo, n, 'tag')
6151 scmutil.checknewlabel(repo, n, 'tag')
6151 if not n:
6152 if not n:
6152 raise util.Abort(_('tag names cannot consist entirely of '
6153 raise util.Abort(_('tag names cannot consist entirely of '
6153 'whitespace'))
6154 'whitespace'))
6154 if opts.get('rev') and opts.get('remove'):
6155 if opts.get('rev') and opts.get('remove'):
6155 raise util.Abort(_("--rev and --remove are incompatible"))
6156 raise util.Abort(_("--rev and --remove are incompatible"))
6156 if opts.get('rev'):
6157 if opts.get('rev'):
6157 rev_ = opts['rev']
6158 rev_ = opts['rev']
6158 message = opts.get('message')
6159 message = opts.get('message')
6159 if opts.get('remove'):
6160 if opts.get('remove'):
6160 if opts.get('local'):
6161 if opts.get('local'):
6161 expectedtype = 'local'
6162 expectedtype = 'local'
6162 else:
6163 else:
6163 expectedtype = 'global'
6164 expectedtype = 'global'
6164
6165
6165 for n in names:
6166 for n in names:
6166 if not repo.tagtype(n):
6167 if not repo.tagtype(n):
6167 raise util.Abort(_("tag '%s' does not exist") % n)
6168 raise util.Abort(_("tag '%s' does not exist") % n)
6168 if repo.tagtype(n) != expectedtype:
6169 if repo.tagtype(n) != expectedtype:
6169 if expectedtype == 'global':
6170 if expectedtype == 'global':
6170 raise util.Abort(_("tag '%s' is not a global tag") % n)
6171 raise util.Abort(_("tag '%s' is not a global tag") % n)
6171 else:
6172 else:
6172 raise util.Abort(_("tag '%s' is not a local tag") % n)
6173 raise util.Abort(_("tag '%s' is not a local tag") % n)
6173 rev_ = nullid
6174 rev_ = nullid
6174 if not message:
6175 if not message:
6175 # we don't translate commit messages
6176 # we don't translate commit messages
6176 message = 'Removed tag %s' % ', '.join(names)
6177 message = 'Removed tag %s' % ', '.join(names)
6177 elif not opts.get('force'):
6178 elif not opts.get('force'):
6178 for n in names:
6179 for n in names:
6179 if n in repo.tags():
6180 if n in repo.tags():
6180 raise util.Abort(_("tag '%s' already exists "
6181 raise util.Abort(_("tag '%s' already exists "
6181 "(use -f to force)") % n)
6182 "(use -f to force)") % n)
6182 if not opts.get('local'):
6183 if not opts.get('local'):
6183 p1, p2 = repo.dirstate.parents()
6184 p1, p2 = repo.dirstate.parents()
6184 if p2 != nullid:
6185 if p2 != nullid:
6185 raise util.Abort(_('uncommitted merge'))
6186 raise util.Abort(_('uncommitted merge'))
6186 bheads = repo.branchheads()
6187 bheads = repo.branchheads()
6187 if not opts.get('force') and bheads and p1 not in bheads:
6188 if not opts.get('force') and bheads and p1 not in bheads:
6188 raise util.Abort(_('not at a branch head (use -f to force)'))
6189 raise util.Abort(_('not at a branch head (use -f to force)'))
6189 r = scmutil.revsingle(repo, rev_).node()
6190 r = scmutil.revsingle(repo, rev_).node()
6190
6191
6191 if not message:
6192 if not message:
6192 # we don't translate commit messages
6193 # we don't translate commit messages
6193 message = ('Added tag %s for changeset %s' %
6194 message = ('Added tag %s for changeset %s' %
6194 (', '.join(names), short(r)))
6195 (', '.join(names), short(r)))
6195
6196
6196 date = opts.get('date')
6197 date = opts.get('date')
6197 if date:
6198 if date:
6198 date = util.parsedate(date)
6199 date = util.parsedate(date)
6199
6200
6200 if opts.get('remove'):
6201 if opts.get('remove'):
6201 editform = 'tag.remove'
6202 editform = 'tag.remove'
6202 else:
6203 else:
6203 editform = 'tag.add'
6204 editform = 'tag.add'
6204 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6205 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6205
6206
6206 # don't allow tagging the null rev
6207 # don't allow tagging the null rev
6207 if (not opts.get('remove') and
6208 if (not opts.get('remove') and
6208 scmutil.revsingle(repo, rev_).rev() == nullrev):
6209 scmutil.revsingle(repo, rev_).rev() == nullrev):
6209 raise util.Abort(_("cannot tag null revision"))
6210 raise util.Abort(_("cannot tag null revision"))
6210
6211
6211 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6212 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6212 editor=editor)
6213 editor=editor)
6213 finally:
6214 finally:
6214 release(lock, wlock)
6215 release(lock, wlock)
6215
6216
6216 @command('tags', formatteropts, '')
6217 @command('tags', formatteropts, '')
6217 def tags(ui, repo, **opts):
6218 def tags(ui, repo, **opts):
6218 """list repository tags
6219 """list repository tags
6219
6220
6220 This lists both regular and local tags. When the -v/--verbose
6221 This lists both regular and local tags. When the -v/--verbose
6221 switch is used, a third column "local" is printed for local tags.
6222 switch is used, a third column "local" is printed for local tags.
6222
6223
6223 Returns 0 on success.
6224 Returns 0 on success.
6224 """
6225 """
6225
6226
6226 fm = ui.formatter('tags', opts)
6227 fm = ui.formatter('tags', opts)
6227 hexfunc = fm.hexfunc
6228 hexfunc = fm.hexfunc
6228 tagtype = ""
6229 tagtype = ""
6229
6230
6230 for t, n in reversed(repo.tagslist()):
6231 for t, n in reversed(repo.tagslist()):
6231 hn = hexfunc(n)
6232 hn = hexfunc(n)
6232 label = 'tags.normal'
6233 label = 'tags.normal'
6233 tagtype = ''
6234 tagtype = ''
6234 if repo.tagtype(t) == 'local':
6235 if repo.tagtype(t) == 'local':
6235 label = 'tags.local'
6236 label = 'tags.local'
6236 tagtype = 'local'
6237 tagtype = 'local'
6237
6238
6238 fm.startitem()
6239 fm.startitem()
6239 fm.write('tag', '%s', t, label=label)
6240 fm.write('tag', '%s', t, label=label)
6240 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6241 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6241 fm.condwrite(not ui.quiet, 'rev node', fmt,
6242 fm.condwrite(not ui.quiet, 'rev node', fmt,
6242 repo.changelog.rev(n), hn, label=label)
6243 repo.changelog.rev(n), hn, label=label)
6243 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6244 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6244 tagtype, label=label)
6245 tagtype, label=label)
6245 fm.plain('\n')
6246 fm.plain('\n')
6246 fm.end()
6247 fm.end()
6247
6248
6248 @command('tip',
6249 @command('tip',
6249 [('p', 'patch', None, _('show patch')),
6250 [('p', 'patch', None, _('show patch')),
6250 ('g', 'git', None, _('use git extended diff format')),
6251 ('g', 'git', None, _('use git extended diff format')),
6251 ] + templateopts,
6252 ] + templateopts,
6252 _('[-p] [-g]'))
6253 _('[-p] [-g]'))
6253 def tip(ui, repo, **opts):
6254 def tip(ui, repo, **opts):
6254 """show the tip revision (DEPRECATED)
6255 """show the tip revision (DEPRECATED)
6255
6256
6256 The tip revision (usually just called the tip) is the changeset
6257 The tip revision (usually just called the tip) is the changeset
6257 most recently added to the repository (and therefore the most
6258 most recently added to the repository (and therefore the most
6258 recently changed head).
6259 recently changed head).
6259
6260
6260 If you have just made a commit, that commit will be the tip. If
6261 If you have just made a commit, that commit will be the tip. If
6261 you have just pulled changes from another repository, the tip of
6262 you have just pulled changes from another repository, the tip of
6262 that repository becomes the current tip. The "tip" tag is special
6263 that repository becomes the current tip. The "tip" tag is special
6263 and cannot be renamed or assigned to a different changeset.
6264 and cannot be renamed or assigned to a different changeset.
6264
6265
6265 This command is deprecated, please use :hg:`heads` instead.
6266 This command is deprecated, please use :hg:`heads` instead.
6266
6267
6267 Returns 0 on success.
6268 Returns 0 on success.
6268 """
6269 """
6269 displayer = cmdutil.show_changeset(ui, repo, opts)
6270 displayer = cmdutil.show_changeset(ui, repo, opts)
6270 displayer.show(repo['tip'])
6271 displayer.show(repo['tip'])
6271 displayer.close()
6272 displayer.close()
6272
6273
6273 @command('unbundle',
6274 @command('unbundle',
6274 [('u', 'update', None,
6275 [('u', 'update', None,
6275 _('update to new branch head if changesets were unbundled'))],
6276 _('update to new branch head if changesets were unbundled'))],
6276 _('[-u] FILE...'))
6277 _('[-u] FILE...'))
6277 def unbundle(ui, repo, fname1, *fnames, **opts):
6278 def unbundle(ui, repo, fname1, *fnames, **opts):
6278 """apply one or more changegroup files
6279 """apply one or more changegroup files
6279
6280
6280 Apply one or more compressed changegroup files generated by the
6281 Apply one or more compressed changegroup files generated by the
6281 bundle command.
6282 bundle command.
6282
6283
6283 Returns 0 on success, 1 if an update has unresolved files.
6284 Returns 0 on success, 1 if an update has unresolved files.
6284 """
6285 """
6285 fnames = (fname1,) + fnames
6286 fnames = (fname1,) + fnames
6286
6287
6287 lock = repo.lock()
6288 lock = repo.lock()
6288 try:
6289 try:
6289 for fname in fnames:
6290 for fname in fnames:
6290 f = hg.openpath(ui, fname)
6291 f = hg.openpath(ui, fname)
6291 gen = exchange.readbundle(ui, f, fname)
6292 gen = exchange.readbundle(ui, f, fname)
6292 if isinstance(gen, bundle2.unbundle20):
6293 if isinstance(gen, bundle2.unbundle20):
6293 tr = repo.transaction('unbundle')
6294 tr = repo.transaction('unbundle')
6294 try:
6295 try:
6295 op = bundle2.processbundle(repo, gen, lambda: tr)
6296 op = bundle2.processbundle(repo, gen, lambda: tr)
6296 tr.close()
6297 tr.close()
6297 finally:
6298 finally:
6298 if tr:
6299 if tr:
6299 tr.release()
6300 tr.release()
6300 changes = [r.get('result', 0)
6301 changes = [r.get('result', 0)
6301 for r in op.records['changegroup']]
6302 for r in op.records['changegroup']]
6302 modheads = changegroup.combineresults(changes)
6303 modheads = changegroup.combineresults(changes)
6303 else:
6304 else:
6304 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6305 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6305 'bundle:' + fname)
6306 'bundle:' + fname)
6306 finally:
6307 finally:
6307 lock.release()
6308 lock.release()
6308
6309
6309 return postincoming(ui, repo, modheads, opts.get('update'), None)
6310 return postincoming(ui, repo, modheads, opts.get('update'), None)
6310
6311
6311 @command('^update|up|checkout|co',
6312 @command('^update|up|checkout|co',
6312 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6313 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6313 ('c', 'check', None,
6314 ('c', 'check', None,
6314 _('update across branches if no uncommitted changes')),
6315 _('update across branches if no uncommitted changes')),
6315 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6316 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6316 ('r', 'rev', '', _('revision'), _('REV'))
6317 ('r', 'rev', '', _('revision'), _('REV'))
6317 ] + mergetoolopts,
6318 ] + mergetoolopts,
6318 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6319 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6319 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6320 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6320 tool=None):
6321 tool=None):
6321 """update working directory (or switch revisions)
6322 """update working directory (or switch revisions)
6322
6323
6323 Update the repository's working directory to the specified
6324 Update the repository's working directory to the specified
6324 changeset. If no changeset is specified, update to the tip of the
6325 changeset. If no changeset is specified, update to the tip of the
6325 current named branch and move the current bookmark (see :hg:`help
6326 current named branch and move the current bookmark (see :hg:`help
6326 bookmarks`).
6327 bookmarks`).
6327
6328
6328 Update sets the working directory's parent revision to the specified
6329 Update sets the working directory's parent revision to the specified
6329 changeset (see :hg:`help parents`).
6330 changeset (see :hg:`help parents`).
6330
6331
6331 If the changeset is not a descendant or ancestor of the working
6332 If the changeset is not a descendant or ancestor of the working
6332 directory's parent, the update is aborted. With the -c/--check
6333 directory's parent, the update is aborted. With the -c/--check
6333 option, the working directory is checked for uncommitted changes; if
6334 option, the working directory is checked for uncommitted changes; if
6334 none are found, the working directory is updated to the specified
6335 none are found, the working directory is updated to the specified
6335 changeset.
6336 changeset.
6336
6337
6337 .. container:: verbose
6338 .. container:: verbose
6338
6339
6339 The following rules apply when the working directory contains
6340 The following rules apply when the working directory contains
6340 uncommitted changes:
6341 uncommitted changes:
6341
6342
6342 1. If neither -c/--check nor -C/--clean is specified, and if
6343 1. If neither -c/--check nor -C/--clean is specified, and if
6343 the requested changeset is an ancestor or descendant of
6344 the requested changeset is an ancestor or descendant of
6344 the working directory's parent, the uncommitted changes
6345 the working directory's parent, the uncommitted changes
6345 are merged into the requested changeset and the merged
6346 are merged into the requested changeset and the merged
6346 result is left uncommitted. If the requested changeset is
6347 result is left uncommitted. If the requested changeset is
6347 not an ancestor or descendant (that is, it is on another
6348 not an ancestor or descendant (that is, it is on another
6348 branch), the update is aborted and the uncommitted changes
6349 branch), the update is aborted and the uncommitted changes
6349 are preserved.
6350 are preserved.
6350
6351
6351 2. With the -c/--check option, the update is aborted and the
6352 2. With the -c/--check option, the update is aborted and the
6352 uncommitted changes are preserved.
6353 uncommitted changes are preserved.
6353
6354
6354 3. With the -C/--clean option, uncommitted changes are discarded and
6355 3. With the -C/--clean option, uncommitted changes are discarded and
6355 the working directory is updated to the requested changeset.
6356 the working directory is updated to the requested changeset.
6356
6357
6357 To cancel an uncommitted merge (and lose your changes), use
6358 To cancel an uncommitted merge (and lose your changes), use
6358 :hg:`update --clean .`.
6359 :hg:`update --clean .`.
6359
6360
6360 Use null as the changeset to remove the working directory (like
6361 Use null as the changeset to remove the working directory (like
6361 :hg:`clone -U`).
6362 :hg:`clone -U`).
6362
6363
6363 If you want to revert just one file to an older revision, use
6364 If you want to revert just one file to an older revision, use
6364 :hg:`revert [-r REV] NAME`.
6365 :hg:`revert [-r REV] NAME`.
6365
6366
6366 See :hg:`help dates` for a list of formats valid for -d/--date.
6367 See :hg:`help dates` for a list of formats valid for -d/--date.
6367
6368
6368 Returns 0 on success, 1 if there are unresolved files.
6369 Returns 0 on success, 1 if there are unresolved files.
6369 """
6370 """
6370 if rev and node:
6371 if rev and node:
6371 raise util.Abort(_("please specify just one revision"))
6372 raise util.Abort(_("please specify just one revision"))
6372
6373
6373 if rev is None or rev == '':
6374 if rev is None or rev == '':
6374 rev = node
6375 rev = node
6375
6376
6376 cmdutil.clearunfinished(repo)
6377 cmdutil.clearunfinished(repo)
6377
6378
6378 # with no argument, we also move the current bookmark, if any
6379 # with no argument, we also move the current bookmark, if any
6379 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6380 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6380
6381
6381 # if we defined a bookmark, we have to remember the original bookmark name
6382 # if we defined a bookmark, we have to remember the original bookmark name
6382 brev = rev
6383 brev = rev
6383 rev = scmutil.revsingle(repo, rev, rev).rev()
6384 rev = scmutil.revsingle(repo, rev, rev).rev()
6384
6385
6385 if check and clean:
6386 if check and clean:
6386 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6387 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6387
6388
6388 if date:
6389 if date:
6389 if rev is not None:
6390 if rev is not None:
6390 raise util.Abort(_("you can't specify a revision and a date"))
6391 raise util.Abort(_("you can't specify a revision and a date"))
6391 rev = cmdutil.finddate(ui, repo, date)
6392 rev = cmdutil.finddate(ui, repo, date)
6392
6393
6393 if check:
6394 if check:
6394 cmdutil.bailifchanged(repo, merge=False)
6395 cmdutil.bailifchanged(repo, merge=False)
6395 if rev is None:
6396 if rev is None:
6396 rev = repo[repo[None].branch()].rev()
6397 rev = repo[repo[None].branch()].rev()
6397
6398
6398 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6399 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6399
6400
6400 if clean:
6401 if clean:
6401 ret = hg.clean(repo, rev)
6402 ret = hg.clean(repo, rev)
6402 else:
6403 else:
6403 ret = hg.update(repo, rev)
6404 ret = hg.update(repo, rev)
6404
6405
6405 if not ret and movemarkfrom:
6406 if not ret and movemarkfrom:
6406 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6407 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6407 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6408 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6408 elif brev in repo._bookmarks:
6409 elif brev in repo._bookmarks:
6409 bookmarks.setcurrent(repo, brev)
6410 bookmarks.setcurrent(repo, brev)
6410 ui.status(_("(activating bookmark %s)\n") % brev)
6411 ui.status(_("(activating bookmark %s)\n") % brev)
6411 elif brev:
6412 elif brev:
6412 if repo._bookmarkcurrent:
6413 if repo._bookmarkcurrent:
6413 ui.status(_("(leaving bookmark %s)\n") %
6414 ui.status(_("(leaving bookmark %s)\n") %
6414 repo._bookmarkcurrent)
6415 repo._bookmarkcurrent)
6415 bookmarks.unsetcurrent(repo)
6416 bookmarks.unsetcurrent(repo)
6416
6417
6417 return ret
6418 return ret
6418
6419
6419 @command('verify', [])
6420 @command('verify', [])
6420 def verify(ui, repo):
6421 def verify(ui, repo):
6421 """verify the integrity of the repository
6422 """verify the integrity of the repository
6422
6423
6423 Verify the integrity of the current repository.
6424 Verify the integrity of the current repository.
6424
6425
6425 This will perform an extensive check of the repository's
6426 This will perform an extensive check of the repository's
6426 integrity, validating the hashes and checksums of each entry in
6427 integrity, validating the hashes and checksums of each entry in
6427 the changelog, manifest, and tracked files, as well as the
6428 the changelog, manifest, and tracked files, as well as the
6428 integrity of their crosslinks and indices.
6429 integrity of their crosslinks and indices.
6429
6430
6430 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6431 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6431 for more information about recovery from corruption of the
6432 for more information about recovery from corruption of the
6432 repository.
6433 repository.
6433
6434
6434 Returns 0 on success, 1 if errors are encountered.
6435 Returns 0 on success, 1 if errors are encountered.
6435 """
6436 """
6436 return hg.verify(repo)
6437 return hg.verify(repo)
6437
6438
6438 @command('version', [], norepo=True)
6439 @command('version', [], norepo=True)
6439 def version_(ui):
6440 def version_(ui):
6440 """output version and copyright information"""
6441 """output version and copyright information"""
6441 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6442 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6442 % util.version())
6443 % util.version())
6443 ui.status(_(
6444 ui.status(_(
6444 "(see http://mercurial.selenic.com for more information)\n"
6445 "(see http://mercurial.selenic.com for more information)\n"
6445 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6446 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6446 "This is free software; see the source for copying conditions. "
6447 "This is free software; see the source for copying conditions. "
6447 "There is NO\nwarranty; "
6448 "There is NO\nwarranty; "
6448 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6449 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6449 ))
6450 ))
6450
6451
6451 ui.note(_("\nEnabled extensions:\n\n"))
6452 ui.note(_("\nEnabled extensions:\n\n"))
6452 if ui.verbose:
6453 if ui.verbose:
6453 # format names and versions into columns
6454 # format names and versions into columns
6454 names = []
6455 names = []
6455 vers = []
6456 vers = []
6456 for name, module in extensions.extensions():
6457 for name, module in extensions.extensions():
6457 names.append(name)
6458 names.append(name)
6458 vers.append(extensions.moduleversion(module))
6459 vers.append(extensions.moduleversion(module))
6459 if names:
6460 if names:
6460 maxnamelen = max(len(n) for n in names)
6461 maxnamelen = max(len(n) for n in names)
6461 for i, name in enumerate(names):
6462 for i, name in enumerate(names):
6462 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
6463 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
@@ -1,26 +1,43
1 hg debuginstall
1 hg debuginstall
2 $ hg debuginstall
2 $ hg debuginstall
3 checking encoding (ascii)...
3 checking encoding (ascii)...
4 checking Python executable (*) (glob)
4 checking Python executable (*) (glob)
5 checking Python version (2.*) (glob)
5 checking Python version (2.*) (glob)
6 checking Python lib (*lib*)... (glob)
6 checking Python lib (*lib*)... (glob)
7 checking installed modules (*mercurial)... (glob)
7 checking installed modules (*mercurial)... (glob)
8 checking templates (*mercurial?templates)... (glob)
8 checking templates (*mercurial?templates)... (glob)
9 checking commit editor...
9 checking commit editor...
10 checking username...
10 checking username...
11 no problems detected
11 no problems detected
12
12
13 hg debuginstall with no username
13 hg debuginstall with no username
14 $ HGUSER= hg debuginstall
14 $ HGUSER= hg debuginstall
15 checking encoding (ascii)...
15 checking encoding (ascii)...
16 checking Python executable (*) (glob)
16 checking Python executable (*) (glob)
17 checking Python version (2.*) (glob)
17 checking Python version (2.*) (glob)
18 checking Python lib (*lib*)... (glob)
18 checking Python lib (*lib*)... (glob)
19 checking installed modules (*mercurial)... (glob)
19 checking installed modules (*mercurial)... (glob)
20 checking templates (*mercurial?templates)... (glob)
20 checking templates (*mercurial?templates)... (glob)
21 checking commit editor...
21 checking commit editor...
22 checking username...
22 checking username...
23 no username supplied
23 no username supplied
24 (specify a username in your configuration file)
24 (specify a username in your configuration file)
25 1 problems detected, please check your install!
25 1 problems detected, please check your install!
26 [1]
26 [1]
27
28 path variables are expanded (~ is the same as $TESTTMP)
29 $ mkdir tools
30 $ touch tools/testeditor.exe
31 #if execbit
32 $ chmod 755 tools/testeditor.exe
33 #endif
34 $ hg debuginstall --config ui.editor=~/tools/testeditor.exe
35 checking encoding (ascii)...
36 checking Python executable (*) (glob)
37 checking Python version (*) (glob)
38 checking Python lib (*lib*)... (glob)
39 checking installed modules (*mercurial)... (glob)
40 checking templates (*mercurial?templates)... (glob)
41 checking commit editor...
42 checking username...
43 no problems detected
General Comments 0
You need to be logged in to leave comments. Login now