##// END OF EJS Templates
locate: deprecate in favor of files
Matt Mackall -
r22431:eaeee6f9 default
parent child Browse files
Show More
@@ -1,6204 +1,6204
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
12 import sys
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
21 import dagparser, context, simplemerge, graphmod
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
24 import phases, obsolete, exchange
25
25
26 table = {}
26 table = {}
27
27
28 command = cmdutil.command(table)
28 command = cmdutil.command(table)
29
29
30 # Space delimited list of commands that don't require local repositories.
30 # Space delimited list of commands that don't require local repositories.
31 # This should be populated by passing norepo=True into the @command decorator.
31 # This should be populated by passing norepo=True into the @command decorator.
32 norepo = ''
32 norepo = ''
33 # Space delimited list of commands that optionally require local repositories.
33 # Space delimited list of commands that optionally require local repositories.
34 # This should be populated by passing optionalrepo=True into the @command
34 # This should be populated by passing optionalrepo=True into the @command
35 # decorator.
35 # decorator.
36 optionalrepo = ''
36 optionalrepo = ''
37 # Space delimited list of commands that will examine arguments looking for
37 # Space delimited list of commands that will examine arguments looking for
38 # a repository. This should be populated by passing inferrepo=True into the
38 # a repository. This should be populated by passing inferrepo=True into the
39 # @command decorator.
39 # @command decorator.
40 inferrepo = ''
40 inferrepo = ''
41
41
42 # common command options
42 # common command options
43
43
44 globalopts = [
44 globalopts = [
45 ('R', 'repository', '',
45 ('R', 'repository', '',
46 _('repository root directory or name of overlay bundle file'),
46 _('repository root directory or name of overlay bundle file'),
47 _('REPO')),
47 _('REPO')),
48 ('', 'cwd', '',
48 ('', 'cwd', '',
49 _('change working directory'), _('DIR')),
49 _('change working directory'), _('DIR')),
50 ('y', 'noninteractive', None,
50 ('y', 'noninteractive', None,
51 _('do not prompt, automatically pick the first choice for all prompts')),
51 _('do not prompt, automatically pick the first choice for all prompts')),
52 ('q', 'quiet', None, _('suppress output')),
52 ('q', 'quiet', None, _('suppress output')),
53 ('v', 'verbose', None, _('enable additional output')),
53 ('v', 'verbose', None, _('enable additional output')),
54 ('', 'config', [],
54 ('', 'config', [],
55 _('set/override config option (use \'section.name=value\')'),
55 _('set/override config option (use \'section.name=value\')'),
56 _('CONFIG')),
56 _('CONFIG')),
57 ('', 'debug', None, _('enable debugging output')),
57 ('', 'debug', None, _('enable debugging output')),
58 ('', 'debugger', None, _('start debugger')),
58 ('', 'debugger', None, _('start debugger')),
59 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
59 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
60 _('ENCODE')),
60 _('ENCODE')),
61 ('', 'encodingmode', encoding.encodingmode,
61 ('', 'encodingmode', encoding.encodingmode,
62 _('set the charset encoding mode'), _('MODE')),
62 _('set the charset encoding mode'), _('MODE')),
63 ('', 'traceback', None, _('always print a traceback on exception')),
63 ('', 'traceback', None, _('always print a traceback on exception')),
64 ('', 'time', None, _('time how long the command takes')),
64 ('', 'time', None, _('time how long the command takes')),
65 ('', 'profile', None, _('print command execution profile')),
65 ('', 'profile', None, _('print command execution profile')),
66 ('', 'version', None, _('output version information and exit')),
66 ('', 'version', None, _('output version information and exit')),
67 ('h', 'help', None, _('display help and exit')),
67 ('h', 'help', None, _('display help and exit')),
68 ('', 'hidden', False, _('consider hidden changesets')),
68 ('', 'hidden', False, _('consider hidden changesets')),
69 ]
69 ]
70
70
71 dryrunopts = [('n', 'dry-run', None,
71 dryrunopts = [('n', 'dry-run', None,
72 _('do not perform actions, just print output'))]
72 _('do not perform actions, just print output'))]
73
73
74 remoteopts = [
74 remoteopts = [
75 ('e', 'ssh', '',
75 ('e', 'ssh', '',
76 _('specify ssh command to use'), _('CMD')),
76 _('specify ssh command to use'), _('CMD')),
77 ('', 'remotecmd', '',
77 ('', 'remotecmd', '',
78 _('specify hg command to run on the remote side'), _('CMD')),
78 _('specify hg command to run on the remote side'), _('CMD')),
79 ('', 'insecure', None,
79 ('', 'insecure', None,
80 _('do not verify server certificate (ignoring web.cacerts config)')),
80 _('do not verify server certificate (ignoring web.cacerts config)')),
81 ]
81 ]
82
82
83 walkopts = [
83 walkopts = [
84 ('I', 'include', [],
84 ('I', 'include', [],
85 _('include names matching the given patterns'), _('PATTERN')),
85 _('include names matching the given patterns'), _('PATTERN')),
86 ('X', 'exclude', [],
86 ('X', 'exclude', [],
87 _('exclude names matching the given patterns'), _('PATTERN')),
87 _('exclude names matching the given patterns'), _('PATTERN')),
88 ]
88 ]
89
89
90 commitopts = [
90 commitopts = [
91 ('m', 'message', '',
91 ('m', 'message', '',
92 _('use text as commit message'), _('TEXT')),
92 _('use text as commit message'), _('TEXT')),
93 ('l', 'logfile', '',
93 ('l', 'logfile', '',
94 _('read commit message from file'), _('FILE')),
94 _('read commit message from file'), _('FILE')),
95 ]
95 ]
96
96
97 commitopts2 = [
97 commitopts2 = [
98 ('d', 'date', '',
98 ('d', 'date', '',
99 _('record the specified date as commit date'), _('DATE')),
99 _('record the specified date as commit date'), _('DATE')),
100 ('u', 'user', '',
100 ('u', 'user', '',
101 _('record the specified user as committer'), _('USER')),
101 _('record the specified user as committer'), _('USER')),
102 ]
102 ]
103
103
104 # hidden for now
104 # hidden for now
105 formatteropts = [
105 formatteropts = [
106 ('T', 'template', '',
106 ('T', 'template', '',
107 _('display with template (DEPRECATED)'), _('TEMPLATE')),
107 _('display with template (DEPRECATED)'), _('TEMPLATE')),
108 ]
108 ]
109
109
110 templateopts = [
110 templateopts = [
111 ('', 'style', '',
111 ('', 'style', '',
112 _('display using template map file (DEPRECATED)'), _('STYLE')),
112 _('display using template map file (DEPRECATED)'), _('STYLE')),
113 ('T', 'template', '',
113 ('T', 'template', '',
114 _('display with template'), _('TEMPLATE')),
114 _('display with template'), _('TEMPLATE')),
115 ]
115 ]
116
116
117 logopts = [
117 logopts = [
118 ('p', 'patch', None, _('show patch')),
118 ('p', 'patch', None, _('show patch')),
119 ('g', 'git', None, _('use git extended diff format')),
119 ('g', 'git', None, _('use git extended diff format')),
120 ('l', 'limit', '',
120 ('l', 'limit', '',
121 _('limit number of changes displayed'), _('NUM')),
121 _('limit number of changes displayed'), _('NUM')),
122 ('M', 'no-merges', None, _('do not show merges')),
122 ('M', 'no-merges', None, _('do not show merges')),
123 ('', 'stat', None, _('output diffstat-style summary of changes')),
123 ('', 'stat', None, _('output diffstat-style summary of changes')),
124 ('G', 'graph', None, _("show the revision DAG")),
124 ('G', 'graph', None, _("show the revision DAG")),
125 ] + templateopts
125 ] + templateopts
126
126
127 diffopts = [
127 diffopts = [
128 ('a', 'text', None, _('treat all files as text')),
128 ('a', 'text', None, _('treat all files as text')),
129 ('g', 'git', None, _('use git extended diff format')),
129 ('g', 'git', None, _('use git extended diff format')),
130 ('', 'nodates', None, _('omit dates from diff headers'))
130 ('', 'nodates', None, _('omit dates from diff headers'))
131 ]
131 ]
132
132
133 diffwsopts = [
133 diffwsopts = [
134 ('w', 'ignore-all-space', None,
134 ('w', 'ignore-all-space', None,
135 _('ignore white space when comparing lines')),
135 _('ignore white space when comparing lines')),
136 ('b', 'ignore-space-change', None,
136 ('b', 'ignore-space-change', None,
137 _('ignore changes in the amount of white space')),
137 _('ignore changes in the amount of white space')),
138 ('B', 'ignore-blank-lines', None,
138 ('B', 'ignore-blank-lines', None,
139 _('ignore changes whose lines are all blank')),
139 _('ignore changes whose lines are all blank')),
140 ]
140 ]
141
141
142 diffopts2 = [
142 diffopts2 = [
143 ('p', 'show-function', None, _('show which function each change is in')),
143 ('p', 'show-function', None, _('show which function each change is in')),
144 ('', 'reverse', None, _('produce a diff that undoes the changes')),
144 ('', 'reverse', None, _('produce a diff that undoes the changes')),
145 ] + diffwsopts + [
145 ] + diffwsopts + [
146 ('U', 'unified', '',
146 ('U', 'unified', '',
147 _('number of lines of context to show'), _('NUM')),
147 _('number of lines of context to show'), _('NUM')),
148 ('', 'stat', None, _('output diffstat-style summary of changes')),
148 ('', 'stat', None, _('output diffstat-style summary of changes')),
149 ]
149 ]
150
150
151 mergetoolopts = [
151 mergetoolopts = [
152 ('t', 'tool', '', _('specify merge tool')),
152 ('t', 'tool', '', _('specify merge tool')),
153 ]
153 ]
154
154
155 similarityopts = [
155 similarityopts = [
156 ('s', 'similarity', '',
156 ('s', 'similarity', '',
157 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
157 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
158 ]
158 ]
159
159
160 subrepoopts = [
160 subrepoopts = [
161 ('S', 'subrepos', None,
161 ('S', 'subrepos', None,
162 _('recurse into subrepositories'))
162 _('recurse into subrepositories'))
163 ]
163 ]
164
164
165 # Commands start here, listed alphabetically
165 # Commands start here, listed alphabetically
166
166
167 @command('^add',
167 @command('^add',
168 walkopts + subrepoopts + dryrunopts,
168 walkopts + subrepoopts + dryrunopts,
169 _('[OPTION]... [FILE]...'),
169 _('[OPTION]... [FILE]...'),
170 inferrepo=True)
170 inferrepo=True)
171 def add(ui, repo, *pats, **opts):
171 def add(ui, repo, *pats, **opts):
172 """add the specified files on the next commit
172 """add the specified files on the next commit
173
173
174 Schedule files to be version controlled and added to the
174 Schedule files to be version controlled and added to the
175 repository.
175 repository.
176
176
177 The files will be added to the repository at the next commit. To
177 The files will be added to the repository at the next commit. To
178 undo an add before that, see :hg:`forget`.
178 undo an add before that, see :hg:`forget`.
179
179
180 If no names are given, add all files to the repository.
180 If no names are given, add all files to the repository.
181
181
182 .. container:: verbose
182 .. container:: verbose
183
183
184 An example showing how new (unknown) files are added
184 An example showing how new (unknown) files are added
185 automatically by :hg:`add`::
185 automatically by :hg:`add`::
186
186
187 $ ls
187 $ ls
188 foo.c
188 foo.c
189 $ hg status
189 $ hg status
190 ? foo.c
190 ? foo.c
191 $ hg add
191 $ hg add
192 adding foo.c
192 adding foo.c
193 $ hg status
193 $ hg status
194 A foo.c
194 A foo.c
195
195
196 Returns 0 if all files are successfully added.
196 Returns 0 if all files are successfully added.
197 """
197 """
198
198
199 m = scmutil.match(repo[None], pats, opts)
199 m = scmutil.match(repo[None], pats, opts)
200 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
200 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
201 opts.get('subrepos'), prefix="", explicitonly=False)
201 opts.get('subrepos'), prefix="", explicitonly=False)
202 return rejected and 1 or 0
202 return rejected and 1 or 0
203
203
204 @command('addremove',
204 @command('addremove',
205 similarityopts + walkopts + dryrunopts,
205 similarityopts + walkopts + dryrunopts,
206 _('[OPTION]... [FILE]...'),
206 _('[OPTION]... [FILE]...'),
207 inferrepo=True)
207 inferrepo=True)
208 def addremove(ui, repo, *pats, **opts):
208 def addremove(ui, repo, *pats, **opts):
209 """add all new files, delete all missing files
209 """add all new files, delete all missing files
210
210
211 Add all new files and remove all missing files from the
211 Add all new files and remove all missing files from the
212 repository.
212 repository.
213
213
214 New files are ignored if they match any of the patterns in
214 New files are ignored if they match any of the patterns in
215 ``.hgignore``. As with add, these changes take effect at the next
215 ``.hgignore``. As with add, these changes take effect at the next
216 commit.
216 commit.
217
217
218 Use the -s/--similarity option to detect renamed files. This
218 Use the -s/--similarity option to detect renamed files. This
219 option takes a percentage between 0 (disabled) and 100 (files must
219 option takes a percentage between 0 (disabled) and 100 (files must
220 be identical) as its parameter. With a parameter greater than 0,
220 be identical) as its parameter. With a parameter greater than 0,
221 this compares every removed file with every added file and records
221 this compares every removed file with every added file and records
222 those similar enough as renames. Detecting renamed files this way
222 those similar enough as renames. Detecting renamed files this way
223 can be expensive. After using this option, :hg:`status -C` can be
223 can be expensive. After using this option, :hg:`status -C` can be
224 used to check which files were identified as moved or renamed. If
224 used to check which files were identified as moved or renamed. If
225 not specified, -s/--similarity defaults to 100 and only renames of
225 not specified, -s/--similarity defaults to 100 and only renames of
226 identical files are detected.
226 identical files are detected.
227
227
228 Returns 0 if all files are successfully added.
228 Returns 0 if all files are successfully added.
229 """
229 """
230 try:
230 try:
231 sim = float(opts.get('similarity') or 100)
231 sim = float(opts.get('similarity') or 100)
232 except ValueError:
232 except ValueError:
233 raise util.Abort(_('similarity must be a number'))
233 raise util.Abort(_('similarity must be a number'))
234 if sim < 0 or sim > 100:
234 if sim < 0 or sim > 100:
235 raise util.Abort(_('similarity must be between 0 and 100'))
235 raise util.Abort(_('similarity must be between 0 and 100'))
236 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
236 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
237
237
238 @command('^annotate|blame',
238 @command('^annotate|blame',
239 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
239 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
240 ('', 'follow', None,
240 ('', 'follow', None,
241 _('follow copies/renames and list the filename (DEPRECATED)')),
241 _('follow copies/renames and list the filename (DEPRECATED)')),
242 ('', 'no-follow', None, _("don't follow copies and renames")),
242 ('', 'no-follow', None, _("don't follow copies and renames")),
243 ('a', 'text', None, _('treat all files as text')),
243 ('a', 'text', None, _('treat all files as text')),
244 ('u', 'user', None, _('list the author (long with -v)')),
244 ('u', 'user', None, _('list the author (long with -v)')),
245 ('f', 'file', None, _('list the filename')),
245 ('f', 'file', None, _('list the filename')),
246 ('d', 'date', None, _('list the date (short with -q)')),
246 ('d', 'date', None, _('list the date (short with -q)')),
247 ('n', 'number', None, _('list the revision number (default)')),
247 ('n', 'number', None, _('list the revision number (default)')),
248 ('c', 'changeset', None, _('list the changeset')),
248 ('c', 'changeset', None, _('list the changeset')),
249 ('l', 'line-number', None, _('show line number at the first appearance'))
249 ('l', 'line-number', None, _('show line number at the first appearance'))
250 ] + diffwsopts + walkopts,
250 ] + diffwsopts + walkopts,
251 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
251 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
252 inferrepo=True)
252 inferrepo=True)
253 def annotate(ui, repo, *pats, **opts):
253 def annotate(ui, repo, *pats, **opts):
254 """show changeset information by line for each file
254 """show changeset information by line for each file
255
255
256 List changes in files, showing the revision id responsible for
256 List changes in files, showing the revision id responsible for
257 each line
257 each line
258
258
259 This command is useful for discovering when a change was made and
259 This command is useful for discovering when a change was made and
260 by whom.
260 by whom.
261
261
262 Without the -a/--text option, annotate will avoid processing files
262 Without the -a/--text option, annotate will avoid processing files
263 it detects as binary. With -a, annotate will annotate the file
263 it detects as binary. With -a, annotate will annotate the file
264 anyway, although the results will probably be neither useful
264 anyway, although the results will probably be neither useful
265 nor desirable.
265 nor desirable.
266
266
267 Returns 0 on success.
267 Returns 0 on success.
268 """
268 """
269 if not pats:
269 if not pats:
270 raise util.Abort(_('at least one filename or pattern is required'))
270 raise util.Abort(_('at least one filename or pattern is required'))
271
271
272 if opts.get('follow'):
272 if opts.get('follow'):
273 # --follow is deprecated and now just an alias for -f/--file
273 # --follow is deprecated and now just an alias for -f/--file
274 # to mimic the behavior of Mercurial before version 1.5
274 # to mimic the behavior of Mercurial before version 1.5
275 opts['file'] = True
275 opts['file'] = True
276
276
277 datefunc = ui.quiet and util.shortdate or util.datestr
277 datefunc = ui.quiet and util.shortdate or util.datestr
278 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
278 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
279 hexfn = ui.debugflag and hex or short
279 hexfn = ui.debugflag and hex or short
280
280
281 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
281 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
282 ('number', ' ', lambda x: str(x[0].rev())),
282 ('number', ' ', lambda x: str(x[0].rev())),
283 ('changeset', ' ', lambda x: hexfn(x[0].node())),
283 ('changeset', ' ', lambda x: hexfn(x[0].node())),
284 ('date', ' ', getdate),
284 ('date', ' ', getdate),
285 ('file', ' ', lambda x: x[0].path()),
285 ('file', ' ', lambda x: x[0].path()),
286 ('line_number', ':', lambda x: str(x[1])),
286 ('line_number', ':', lambda x: str(x[1])),
287 ]
287 ]
288
288
289 if (not opts.get('user') and not opts.get('changeset')
289 if (not opts.get('user') and not opts.get('changeset')
290 and not opts.get('date') and not opts.get('file')):
290 and not opts.get('date') and not opts.get('file')):
291 opts['number'] = True
291 opts['number'] = True
292
292
293 linenumber = opts.get('line_number') is not None
293 linenumber = opts.get('line_number') is not None
294 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
294 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
295 raise util.Abort(_('at least one of -n/-c is required for -l'))
295 raise util.Abort(_('at least one of -n/-c is required for -l'))
296
296
297 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
297 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
298 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
298 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
299
299
300 def bad(x, y):
300 def bad(x, y):
301 raise util.Abort("%s: %s" % (x, y))
301 raise util.Abort("%s: %s" % (x, y))
302
302
303 ctx = scmutil.revsingle(repo, opts.get('rev'))
303 ctx = scmutil.revsingle(repo, opts.get('rev'))
304 m = scmutil.match(ctx, pats, opts)
304 m = scmutil.match(ctx, pats, opts)
305 m.bad = bad
305 m.bad = bad
306 follow = not opts.get('no_follow')
306 follow = not opts.get('no_follow')
307 diffopts = patch.diffopts(ui, opts, section='annotate')
307 diffopts = patch.diffopts(ui, opts, section='annotate')
308 for abs in ctx.walk(m):
308 for abs in ctx.walk(m):
309 fctx = ctx[abs]
309 fctx = ctx[abs]
310 if not opts.get('text') and util.binary(fctx.data()):
310 if not opts.get('text') and util.binary(fctx.data()):
311 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
311 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
312 continue
312 continue
313
313
314 lines = fctx.annotate(follow=follow, linenumber=linenumber,
314 lines = fctx.annotate(follow=follow, linenumber=linenumber,
315 diffopts=diffopts)
315 diffopts=diffopts)
316 pieces = []
316 pieces = []
317
317
318 for f, sep in funcmap:
318 for f, sep in funcmap:
319 l = [f(n) for n, dummy in lines]
319 l = [f(n) for n, dummy in lines]
320 if l:
320 if l:
321 sized = [(x, encoding.colwidth(x)) for x in l]
321 sized = [(x, encoding.colwidth(x)) for x in l]
322 ml = max([w for x, w in sized])
322 ml = max([w for x, w in sized])
323 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
323 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
324 for x, w in sized])
324 for x, w in sized])
325
325
326 if pieces:
326 if pieces:
327 for p, l in zip(zip(*pieces), lines):
327 for p, l in zip(zip(*pieces), lines):
328 ui.write("%s: %s" % ("".join(p), l[1]))
328 ui.write("%s: %s" % ("".join(p), l[1]))
329
329
330 if lines and not lines[-1][1].endswith('\n'):
330 if lines and not lines[-1][1].endswith('\n'):
331 ui.write('\n')
331 ui.write('\n')
332
332
333 @command('archive',
333 @command('archive',
334 [('', 'no-decode', None, _('do not pass files through decoders')),
334 [('', 'no-decode', None, _('do not pass files through decoders')),
335 ('p', 'prefix', '', _('directory prefix for files in archive'),
335 ('p', 'prefix', '', _('directory prefix for files in archive'),
336 _('PREFIX')),
336 _('PREFIX')),
337 ('r', 'rev', '', _('revision to distribute'), _('REV')),
337 ('r', 'rev', '', _('revision to distribute'), _('REV')),
338 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
338 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
339 ] + subrepoopts + walkopts,
339 ] + subrepoopts + walkopts,
340 _('[OPTION]... DEST'))
340 _('[OPTION]... DEST'))
341 def archive(ui, repo, dest, **opts):
341 def archive(ui, repo, dest, **opts):
342 '''create an unversioned archive of a repository revision
342 '''create an unversioned archive of a repository revision
343
343
344 By default, the revision used is the parent of the working
344 By default, the revision used is the parent of the working
345 directory; use -r/--rev to specify a different revision.
345 directory; use -r/--rev to specify a different revision.
346
346
347 The archive type is automatically detected based on file
347 The archive type is automatically detected based on file
348 extension (or override using -t/--type).
348 extension (or override using -t/--type).
349
349
350 .. container:: verbose
350 .. container:: verbose
351
351
352 Examples:
352 Examples:
353
353
354 - create a zip file containing the 1.0 release::
354 - create a zip file containing the 1.0 release::
355
355
356 hg archive -r 1.0 project-1.0.zip
356 hg archive -r 1.0 project-1.0.zip
357
357
358 - create a tarball excluding .hg files::
358 - create a tarball excluding .hg files::
359
359
360 hg archive project.tar.gz -X ".hg*"
360 hg archive project.tar.gz -X ".hg*"
361
361
362 Valid types are:
362 Valid types are:
363
363
364 :``files``: a directory full of files (default)
364 :``files``: a directory full of files (default)
365 :``tar``: tar archive, uncompressed
365 :``tar``: tar archive, uncompressed
366 :``tbz2``: tar archive, compressed using bzip2
366 :``tbz2``: tar archive, compressed using bzip2
367 :``tgz``: tar archive, compressed using gzip
367 :``tgz``: tar archive, compressed using gzip
368 :``uzip``: zip archive, uncompressed
368 :``uzip``: zip archive, uncompressed
369 :``zip``: zip archive, compressed using deflate
369 :``zip``: zip archive, compressed using deflate
370
370
371 The exact name of the destination archive or directory is given
371 The exact name of the destination archive or directory is given
372 using a format string; see :hg:`help export` for details.
372 using a format string; see :hg:`help export` for details.
373
373
374 Each member added to an archive file has a directory prefix
374 Each member added to an archive file has a directory prefix
375 prepended. Use -p/--prefix to specify a format string for the
375 prepended. Use -p/--prefix to specify a format string for the
376 prefix. The default is the basename of the archive, with suffixes
376 prefix. The default is the basename of the archive, with suffixes
377 removed.
377 removed.
378
378
379 Returns 0 on success.
379 Returns 0 on success.
380 '''
380 '''
381
381
382 ctx = scmutil.revsingle(repo, opts.get('rev'))
382 ctx = scmutil.revsingle(repo, opts.get('rev'))
383 if not ctx:
383 if not ctx:
384 raise util.Abort(_('no working directory: please specify a revision'))
384 raise util.Abort(_('no working directory: please specify a revision'))
385 node = ctx.node()
385 node = ctx.node()
386 dest = cmdutil.makefilename(repo, dest, node)
386 dest = cmdutil.makefilename(repo, dest, node)
387 if os.path.realpath(dest) == repo.root:
387 if os.path.realpath(dest) == repo.root:
388 raise util.Abort(_('repository root cannot be destination'))
388 raise util.Abort(_('repository root cannot be destination'))
389
389
390 kind = opts.get('type') or archival.guesskind(dest) or 'files'
390 kind = opts.get('type') or archival.guesskind(dest) or 'files'
391 prefix = opts.get('prefix')
391 prefix = opts.get('prefix')
392
392
393 if dest == '-':
393 if dest == '-':
394 if kind == 'files':
394 if kind == 'files':
395 raise util.Abort(_('cannot archive plain files to stdout'))
395 raise util.Abort(_('cannot archive plain files to stdout'))
396 dest = cmdutil.makefileobj(repo, dest)
396 dest = cmdutil.makefileobj(repo, dest)
397 if not prefix:
397 if not prefix:
398 prefix = os.path.basename(repo.root) + '-%h'
398 prefix = os.path.basename(repo.root) + '-%h'
399
399
400 prefix = cmdutil.makefilename(repo, prefix, node)
400 prefix = cmdutil.makefilename(repo, prefix, node)
401 matchfn = scmutil.match(ctx, [], opts)
401 matchfn = scmutil.match(ctx, [], opts)
402 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
402 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
403 matchfn, prefix, subrepos=opts.get('subrepos'))
403 matchfn, prefix, subrepos=opts.get('subrepos'))
404
404
405 @command('backout',
405 @command('backout',
406 [('', 'merge', None, _('merge with old dirstate parent after backout')),
406 [('', 'merge', None, _('merge with old dirstate parent after backout')),
407 ('', 'parent', '',
407 ('', 'parent', '',
408 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
408 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
409 ('r', 'rev', '', _('revision to backout'), _('REV')),
409 ('r', 'rev', '', _('revision to backout'), _('REV')),
410 ('e', 'edit', False, _('invoke editor on commit messages')),
410 ('e', 'edit', False, _('invoke editor on commit messages')),
411 ] + mergetoolopts + walkopts + commitopts + commitopts2,
411 ] + mergetoolopts + walkopts + commitopts + commitopts2,
412 _('[OPTION]... [-r] REV'))
412 _('[OPTION]... [-r] REV'))
413 def backout(ui, repo, node=None, rev=None, **opts):
413 def backout(ui, repo, node=None, rev=None, **opts):
414 '''reverse effect of earlier changeset
414 '''reverse effect of earlier changeset
415
415
416 Prepare a new changeset with the effect of REV undone in the
416 Prepare a new changeset with the effect of REV undone in the
417 current working directory.
417 current working directory.
418
418
419 If REV is the parent of the working directory, then this new changeset
419 If REV is the parent of the working directory, then this new changeset
420 is committed automatically. Otherwise, hg needs to merge the
420 is committed automatically. Otherwise, hg needs to merge the
421 changes and the merged result is left uncommitted.
421 changes and the merged result is left uncommitted.
422
422
423 .. note::
423 .. note::
424
424
425 backout cannot be used to fix either an unwanted or
425 backout cannot be used to fix either an unwanted or
426 incorrect merge.
426 incorrect merge.
427
427
428 .. container:: verbose
428 .. container:: verbose
429
429
430 By default, the pending changeset will have one parent,
430 By default, the pending changeset will have one parent,
431 maintaining a linear history. With --merge, the pending
431 maintaining a linear history. With --merge, the pending
432 changeset will instead have two parents: the old parent of the
432 changeset will instead have two parents: the old parent of the
433 working directory and a new child of REV that simply undoes REV.
433 working directory and a new child of REV that simply undoes REV.
434
434
435 Before version 1.7, the behavior without --merge was equivalent
435 Before version 1.7, the behavior without --merge was equivalent
436 to specifying --merge followed by :hg:`update --clean .` to
436 to specifying --merge followed by :hg:`update --clean .` to
437 cancel the merge and leave the child of REV as a head to be
437 cancel the merge and leave the child of REV as a head to be
438 merged separately.
438 merged separately.
439
439
440 See :hg:`help dates` for a list of formats valid for -d/--date.
440 See :hg:`help dates` for a list of formats valid for -d/--date.
441
441
442 Returns 0 on success, 1 if nothing to backout or there are unresolved
442 Returns 0 on success, 1 if nothing to backout or there are unresolved
443 files.
443 files.
444 '''
444 '''
445 if rev and node:
445 if rev and node:
446 raise util.Abort(_("please specify just one revision"))
446 raise util.Abort(_("please specify just one revision"))
447
447
448 if not rev:
448 if not rev:
449 rev = node
449 rev = node
450
450
451 if not rev:
451 if not rev:
452 raise util.Abort(_("please specify a revision to backout"))
452 raise util.Abort(_("please specify a revision to backout"))
453
453
454 date = opts.get('date')
454 date = opts.get('date')
455 if date:
455 if date:
456 opts['date'] = util.parsedate(date)
456 opts['date'] = util.parsedate(date)
457
457
458 cmdutil.checkunfinished(repo)
458 cmdutil.checkunfinished(repo)
459 cmdutil.bailifchanged(repo)
459 cmdutil.bailifchanged(repo)
460 node = scmutil.revsingle(repo, rev).node()
460 node = scmutil.revsingle(repo, rev).node()
461
461
462 op1, op2 = repo.dirstate.parents()
462 op1, op2 = repo.dirstate.parents()
463 if not repo.changelog.isancestor(node, op1):
463 if not repo.changelog.isancestor(node, op1):
464 raise util.Abort(_('cannot backout change that is not an ancestor'))
464 raise util.Abort(_('cannot backout change that is not an ancestor'))
465
465
466 p1, p2 = repo.changelog.parents(node)
466 p1, p2 = repo.changelog.parents(node)
467 if p1 == nullid:
467 if p1 == nullid:
468 raise util.Abort(_('cannot backout a change with no parents'))
468 raise util.Abort(_('cannot backout a change with no parents'))
469 if p2 != nullid:
469 if p2 != nullid:
470 if not opts.get('parent'):
470 if not opts.get('parent'):
471 raise util.Abort(_('cannot backout a merge changeset'))
471 raise util.Abort(_('cannot backout a merge changeset'))
472 p = repo.lookup(opts['parent'])
472 p = repo.lookup(opts['parent'])
473 if p not in (p1, p2):
473 if p not in (p1, p2):
474 raise util.Abort(_('%s is not a parent of %s') %
474 raise util.Abort(_('%s is not a parent of %s') %
475 (short(p), short(node)))
475 (short(p), short(node)))
476 parent = p
476 parent = p
477 else:
477 else:
478 if opts.get('parent'):
478 if opts.get('parent'):
479 raise util.Abort(_('cannot use --parent on non-merge changeset'))
479 raise util.Abort(_('cannot use --parent on non-merge changeset'))
480 parent = p1
480 parent = p1
481
481
482 # the backout should appear on the same branch
482 # the backout should appear on the same branch
483 wlock = repo.wlock()
483 wlock = repo.wlock()
484 try:
484 try:
485 branch = repo.dirstate.branch()
485 branch = repo.dirstate.branch()
486 bheads = repo.branchheads(branch)
486 bheads = repo.branchheads(branch)
487 rctx = scmutil.revsingle(repo, hex(parent))
487 rctx = scmutil.revsingle(repo, hex(parent))
488 if not opts.get('merge') and op1 != node:
488 if not opts.get('merge') and op1 != node:
489 try:
489 try:
490 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
490 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
491 'backout')
491 'backout')
492 repo.dirstate.beginparentchange()
492 repo.dirstate.beginparentchange()
493 stats = mergemod.update(repo, parent, True, True, False,
493 stats = mergemod.update(repo, parent, True, True, False,
494 node, False)
494 node, False)
495 repo.setparents(op1, op2)
495 repo.setparents(op1, op2)
496 repo.dirstate.endparentchange()
496 repo.dirstate.endparentchange()
497 hg._showstats(repo, stats)
497 hg._showstats(repo, stats)
498 if stats[3]:
498 if stats[3]:
499 repo.ui.status(_("use 'hg resolve' to retry unresolved "
499 repo.ui.status(_("use 'hg resolve' to retry unresolved "
500 "file merges\n"))
500 "file merges\n"))
501 else:
501 else:
502 msg = _("changeset %s backed out, "
502 msg = _("changeset %s backed out, "
503 "don't forget to commit.\n")
503 "don't forget to commit.\n")
504 ui.status(msg % short(node))
504 ui.status(msg % short(node))
505 return stats[3] > 0
505 return stats[3] > 0
506 finally:
506 finally:
507 ui.setconfig('ui', 'forcemerge', '', '')
507 ui.setconfig('ui', 'forcemerge', '', '')
508 else:
508 else:
509 hg.clean(repo, node, show_stats=False)
509 hg.clean(repo, node, show_stats=False)
510 repo.dirstate.setbranch(branch)
510 repo.dirstate.setbranch(branch)
511 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
511 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
512
512
513
513
514 def commitfunc(ui, repo, message, match, opts):
514 def commitfunc(ui, repo, message, match, opts):
515 editform = 'backout'
515 editform = 'backout'
516 e = cmdutil.getcommiteditor(editform=editform, **opts)
516 e = cmdutil.getcommiteditor(editform=editform, **opts)
517 if not message:
517 if not message:
518 # we don't translate commit messages
518 # we don't translate commit messages
519 message = "Backed out changeset %s" % short(node)
519 message = "Backed out changeset %s" % short(node)
520 e = cmdutil.getcommiteditor(edit=True, editform=editform)
520 e = cmdutil.getcommiteditor(edit=True, editform=editform)
521 return repo.commit(message, opts.get('user'), opts.get('date'),
521 return repo.commit(message, opts.get('user'), opts.get('date'),
522 match, editor=e)
522 match, editor=e)
523 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
523 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
524 if not newnode:
524 if not newnode:
525 ui.status(_("nothing changed\n"))
525 ui.status(_("nothing changed\n"))
526 return 1
526 return 1
527 cmdutil.commitstatus(repo, newnode, branch, bheads)
527 cmdutil.commitstatus(repo, newnode, branch, bheads)
528
528
529 def nice(node):
529 def nice(node):
530 return '%d:%s' % (repo.changelog.rev(node), short(node))
530 return '%d:%s' % (repo.changelog.rev(node), short(node))
531 ui.status(_('changeset %s backs out changeset %s\n') %
531 ui.status(_('changeset %s backs out changeset %s\n') %
532 (nice(repo.changelog.tip()), nice(node)))
532 (nice(repo.changelog.tip()), nice(node)))
533 if opts.get('merge') and op1 != node:
533 if opts.get('merge') and op1 != node:
534 hg.clean(repo, op1, show_stats=False)
534 hg.clean(repo, op1, show_stats=False)
535 ui.status(_('merging with changeset %s\n')
535 ui.status(_('merging with changeset %s\n')
536 % nice(repo.changelog.tip()))
536 % nice(repo.changelog.tip()))
537 try:
537 try:
538 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
538 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
539 'backout')
539 'backout')
540 return hg.merge(repo, hex(repo.changelog.tip()))
540 return hg.merge(repo, hex(repo.changelog.tip()))
541 finally:
541 finally:
542 ui.setconfig('ui', 'forcemerge', '', '')
542 ui.setconfig('ui', 'forcemerge', '', '')
543 finally:
543 finally:
544 wlock.release()
544 wlock.release()
545 return 0
545 return 0
546
546
547 @command('bisect',
547 @command('bisect',
548 [('r', 'reset', False, _('reset bisect state')),
548 [('r', 'reset', False, _('reset bisect state')),
549 ('g', 'good', False, _('mark changeset good')),
549 ('g', 'good', False, _('mark changeset good')),
550 ('b', 'bad', False, _('mark changeset bad')),
550 ('b', 'bad', False, _('mark changeset bad')),
551 ('s', 'skip', False, _('skip testing changeset')),
551 ('s', 'skip', False, _('skip testing changeset')),
552 ('e', 'extend', False, _('extend the bisect range')),
552 ('e', 'extend', False, _('extend the bisect range')),
553 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
553 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
554 ('U', 'noupdate', False, _('do not update to target'))],
554 ('U', 'noupdate', False, _('do not update to target'))],
555 _("[-gbsr] [-U] [-c CMD] [REV]"))
555 _("[-gbsr] [-U] [-c CMD] [REV]"))
556 def bisect(ui, repo, rev=None, extra=None, command=None,
556 def bisect(ui, repo, rev=None, extra=None, command=None,
557 reset=None, good=None, bad=None, skip=None, extend=None,
557 reset=None, good=None, bad=None, skip=None, extend=None,
558 noupdate=None):
558 noupdate=None):
559 """subdivision search of changesets
559 """subdivision search of changesets
560
560
561 This command helps to find changesets which introduce problems. To
561 This command helps to find changesets which introduce problems. To
562 use, mark the earliest changeset you know exhibits the problem as
562 use, mark the earliest changeset you know exhibits the problem as
563 bad, then mark the latest changeset which is free from the problem
563 bad, then mark the latest changeset which is free from the problem
564 as good. Bisect will update your working directory to a revision
564 as good. Bisect will update your working directory to a revision
565 for testing (unless the -U/--noupdate option is specified). Once
565 for testing (unless the -U/--noupdate option is specified). Once
566 you have performed tests, mark the working directory as good or
566 you have performed tests, mark the working directory as good or
567 bad, and bisect will either update to another candidate changeset
567 bad, and bisect will either update to another candidate changeset
568 or announce that it has found the bad revision.
568 or announce that it has found the bad revision.
569
569
570 As a shortcut, you can also use the revision argument to mark a
570 As a shortcut, you can also use the revision argument to mark a
571 revision as good or bad without checking it out first.
571 revision as good or bad without checking it out first.
572
572
573 If you supply a command, it will be used for automatic bisection.
573 If you supply a command, it will be used for automatic bisection.
574 The environment variable HG_NODE will contain the ID of the
574 The environment variable HG_NODE will contain the ID of the
575 changeset being tested. The exit status of the command will be
575 changeset being tested. The exit status of the command will be
576 used to mark revisions as good or bad: status 0 means good, 125
576 used to mark revisions as good or bad: status 0 means good, 125
577 means to skip the revision, 127 (command not found) will abort the
577 means to skip the revision, 127 (command not found) will abort the
578 bisection, and any other non-zero exit status means the revision
578 bisection, and any other non-zero exit status means the revision
579 is bad.
579 is bad.
580
580
581 .. container:: verbose
581 .. container:: verbose
582
582
583 Some examples:
583 Some examples:
584
584
585 - start a bisection with known bad revision 34, and good revision 12::
585 - start a bisection with known bad revision 34, and good revision 12::
586
586
587 hg bisect --bad 34
587 hg bisect --bad 34
588 hg bisect --good 12
588 hg bisect --good 12
589
589
590 - advance the current bisection by marking current revision as good or
590 - advance the current bisection by marking current revision as good or
591 bad::
591 bad::
592
592
593 hg bisect --good
593 hg bisect --good
594 hg bisect --bad
594 hg bisect --bad
595
595
596 - mark the current revision, or a known revision, to be skipped (e.g. if
596 - mark the current revision, or a known revision, to be skipped (e.g. if
597 that revision is not usable because of another issue)::
597 that revision is not usable because of another issue)::
598
598
599 hg bisect --skip
599 hg bisect --skip
600 hg bisect --skip 23
600 hg bisect --skip 23
601
601
602 - skip all revisions that do not touch directories ``foo`` or ``bar``::
602 - skip all revisions that do not touch directories ``foo`` or ``bar``::
603
603
604 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
604 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
605
605
606 - forget the current bisection::
606 - forget the current bisection::
607
607
608 hg bisect --reset
608 hg bisect --reset
609
609
610 - use 'make && make tests' to automatically find the first broken
610 - use 'make && make tests' to automatically find the first broken
611 revision::
611 revision::
612
612
613 hg bisect --reset
613 hg bisect --reset
614 hg bisect --bad 34
614 hg bisect --bad 34
615 hg bisect --good 12
615 hg bisect --good 12
616 hg bisect --command "make && make tests"
616 hg bisect --command "make && make tests"
617
617
618 - see all changesets whose states are already known in the current
618 - see all changesets whose states are already known in the current
619 bisection::
619 bisection::
620
620
621 hg log -r "bisect(pruned)"
621 hg log -r "bisect(pruned)"
622
622
623 - see the changeset currently being bisected (especially useful
623 - see the changeset currently being bisected (especially useful
624 if running with -U/--noupdate)::
624 if running with -U/--noupdate)::
625
625
626 hg log -r "bisect(current)"
626 hg log -r "bisect(current)"
627
627
628 - see all changesets that took part in the current bisection::
628 - see all changesets that took part in the current bisection::
629
629
630 hg log -r "bisect(range)"
630 hg log -r "bisect(range)"
631
631
632 - you can even get a nice graph::
632 - you can even get a nice graph::
633
633
634 hg log --graph -r "bisect(range)"
634 hg log --graph -r "bisect(range)"
635
635
636 See :hg:`help revsets` for more about the `bisect()` keyword.
636 See :hg:`help revsets` for more about the `bisect()` keyword.
637
637
638 Returns 0 on success.
638 Returns 0 on success.
639 """
639 """
640 def extendbisectrange(nodes, good):
640 def extendbisectrange(nodes, good):
641 # bisect is incomplete when it ends on a merge node and
641 # bisect is incomplete when it ends on a merge node and
642 # one of the parent was not checked.
642 # one of the parent was not checked.
643 parents = repo[nodes[0]].parents()
643 parents = repo[nodes[0]].parents()
644 if len(parents) > 1:
644 if len(parents) > 1:
645 side = good and state['bad'] or state['good']
645 side = good and state['bad'] or state['good']
646 num = len(set(i.node() for i in parents) & set(side))
646 num = len(set(i.node() for i in parents) & set(side))
647 if num == 1:
647 if num == 1:
648 return parents[0].ancestor(parents[1])
648 return parents[0].ancestor(parents[1])
649 return None
649 return None
650
650
651 def print_result(nodes, good):
651 def print_result(nodes, good):
652 displayer = cmdutil.show_changeset(ui, repo, {})
652 displayer = cmdutil.show_changeset(ui, repo, {})
653 if len(nodes) == 1:
653 if len(nodes) == 1:
654 # narrowed it down to a single revision
654 # narrowed it down to a single revision
655 if good:
655 if good:
656 ui.write(_("The first good revision is:\n"))
656 ui.write(_("The first good revision is:\n"))
657 else:
657 else:
658 ui.write(_("The first bad revision is:\n"))
658 ui.write(_("The first bad revision is:\n"))
659 displayer.show(repo[nodes[0]])
659 displayer.show(repo[nodes[0]])
660 extendnode = extendbisectrange(nodes, good)
660 extendnode = extendbisectrange(nodes, good)
661 if extendnode is not None:
661 if extendnode is not None:
662 ui.write(_('Not all ancestors of this changeset have been'
662 ui.write(_('Not all ancestors of this changeset have been'
663 ' checked.\nUse bisect --extend to continue the '
663 ' checked.\nUse bisect --extend to continue the '
664 'bisection from\nthe common ancestor, %s.\n')
664 'bisection from\nthe common ancestor, %s.\n')
665 % extendnode)
665 % extendnode)
666 else:
666 else:
667 # multiple possible revisions
667 # multiple possible revisions
668 if good:
668 if good:
669 ui.write(_("Due to skipped revisions, the first "
669 ui.write(_("Due to skipped revisions, the first "
670 "good revision could be any of:\n"))
670 "good revision could be any of:\n"))
671 else:
671 else:
672 ui.write(_("Due to skipped revisions, the first "
672 ui.write(_("Due to skipped revisions, the first "
673 "bad revision could be any of:\n"))
673 "bad revision could be any of:\n"))
674 for n in nodes:
674 for n in nodes:
675 displayer.show(repo[n])
675 displayer.show(repo[n])
676 displayer.close()
676 displayer.close()
677
677
678 def check_state(state, interactive=True):
678 def check_state(state, interactive=True):
679 if not state['good'] or not state['bad']:
679 if not state['good'] or not state['bad']:
680 if (good or bad or skip or reset) and interactive:
680 if (good or bad or skip or reset) and interactive:
681 return
681 return
682 if not state['good']:
682 if not state['good']:
683 raise util.Abort(_('cannot bisect (no known good revisions)'))
683 raise util.Abort(_('cannot bisect (no known good revisions)'))
684 else:
684 else:
685 raise util.Abort(_('cannot bisect (no known bad revisions)'))
685 raise util.Abort(_('cannot bisect (no known bad revisions)'))
686 return True
686 return True
687
687
688 # backward compatibility
688 # backward compatibility
689 if rev in "good bad reset init".split():
689 if rev in "good bad reset init".split():
690 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
690 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
691 cmd, rev, extra = rev, extra, None
691 cmd, rev, extra = rev, extra, None
692 if cmd == "good":
692 if cmd == "good":
693 good = True
693 good = True
694 elif cmd == "bad":
694 elif cmd == "bad":
695 bad = True
695 bad = True
696 else:
696 else:
697 reset = True
697 reset = True
698 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
698 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
699 raise util.Abort(_('incompatible arguments'))
699 raise util.Abort(_('incompatible arguments'))
700
700
701 cmdutil.checkunfinished(repo)
701 cmdutil.checkunfinished(repo)
702
702
703 if reset:
703 if reset:
704 p = repo.join("bisect.state")
704 p = repo.join("bisect.state")
705 if os.path.exists(p):
705 if os.path.exists(p):
706 os.unlink(p)
706 os.unlink(p)
707 return
707 return
708
708
709 state = hbisect.load_state(repo)
709 state = hbisect.load_state(repo)
710
710
711 if command:
711 if command:
712 changesets = 1
712 changesets = 1
713 if noupdate:
713 if noupdate:
714 try:
714 try:
715 node = state['current'][0]
715 node = state['current'][0]
716 except LookupError:
716 except LookupError:
717 raise util.Abort(_('current bisect revision is unknown - '
717 raise util.Abort(_('current bisect revision is unknown - '
718 'start a new bisect to fix'))
718 'start a new bisect to fix'))
719 else:
719 else:
720 node, p2 = repo.dirstate.parents()
720 node, p2 = repo.dirstate.parents()
721 if p2 != nullid:
721 if p2 != nullid:
722 raise util.Abort(_('current bisect revision is a merge'))
722 raise util.Abort(_('current bisect revision is a merge'))
723 try:
723 try:
724 while changesets:
724 while changesets:
725 # update state
725 # update state
726 state['current'] = [node]
726 state['current'] = [node]
727 hbisect.save_state(repo, state)
727 hbisect.save_state(repo, state)
728 status = util.system(command,
728 status = util.system(command,
729 environ={'HG_NODE': hex(node)},
729 environ={'HG_NODE': hex(node)},
730 out=ui.fout)
730 out=ui.fout)
731 if status == 125:
731 if status == 125:
732 transition = "skip"
732 transition = "skip"
733 elif status == 0:
733 elif status == 0:
734 transition = "good"
734 transition = "good"
735 # status < 0 means process was killed
735 # status < 0 means process was killed
736 elif status == 127:
736 elif status == 127:
737 raise util.Abort(_("failed to execute %s") % command)
737 raise util.Abort(_("failed to execute %s") % command)
738 elif status < 0:
738 elif status < 0:
739 raise util.Abort(_("%s killed") % command)
739 raise util.Abort(_("%s killed") % command)
740 else:
740 else:
741 transition = "bad"
741 transition = "bad"
742 ctx = scmutil.revsingle(repo, rev, node)
742 ctx = scmutil.revsingle(repo, rev, node)
743 rev = None # clear for future iterations
743 rev = None # clear for future iterations
744 state[transition].append(ctx.node())
744 state[transition].append(ctx.node())
745 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
745 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
746 check_state(state, interactive=False)
746 check_state(state, interactive=False)
747 # bisect
747 # bisect
748 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
748 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
749 # update to next check
749 # update to next check
750 node = nodes[0]
750 node = nodes[0]
751 if not noupdate:
751 if not noupdate:
752 cmdutil.bailifchanged(repo)
752 cmdutil.bailifchanged(repo)
753 hg.clean(repo, node, show_stats=False)
753 hg.clean(repo, node, show_stats=False)
754 finally:
754 finally:
755 state['current'] = [node]
755 state['current'] = [node]
756 hbisect.save_state(repo, state)
756 hbisect.save_state(repo, state)
757 print_result(nodes, bgood)
757 print_result(nodes, bgood)
758 return
758 return
759
759
760 # update state
760 # update state
761
761
762 if rev:
762 if rev:
763 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
763 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
764 else:
764 else:
765 nodes = [repo.lookup('.')]
765 nodes = [repo.lookup('.')]
766
766
767 if good or bad or skip:
767 if good or bad or skip:
768 if good:
768 if good:
769 state['good'] += nodes
769 state['good'] += nodes
770 elif bad:
770 elif bad:
771 state['bad'] += nodes
771 state['bad'] += nodes
772 elif skip:
772 elif skip:
773 state['skip'] += nodes
773 state['skip'] += nodes
774 hbisect.save_state(repo, state)
774 hbisect.save_state(repo, state)
775
775
776 if not check_state(state):
776 if not check_state(state):
777 return
777 return
778
778
779 # actually bisect
779 # actually bisect
780 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
780 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
781 if extend:
781 if extend:
782 if not changesets:
782 if not changesets:
783 extendnode = extendbisectrange(nodes, good)
783 extendnode = extendbisectrange(nodes, good)
784 if extendnode is not None:
784 if extendnode is not None:
785 ui.write(_("Extending search to changeset %d:%s\n")
785 ui.write(_("Extending search to changeset %d:%s\n")
786 % (extendnode.rev(), extendnode))
786 % (extendnode.rev(), extendnode))
787 state['current'] = [extendnode.node()]
787 state['current'] = [extendnode.node()]
788 hbisect.save_state(repo, state)
788 hbisect.save_state(repo, state)
789 if noupdate:
789 if noupdate:
790 return
790 return
791 cmdutil.bailifchanged(repo)
791 cmdutil.bailifchanged(repo)
792 return hg.clean(repo, extendnode.node())
792 return hg.clean(repo, extendnode.node())
793 raise util.Abort(_("nothing to extend"))
793 raise util.Abort(_("nothing to extend"))
794
794
795 if changesets == 0:
795 if changesets == 0:
796 print_result(nodes, good)
796 print_result(nodes, good)
797 else:
797 else:
798 assert len(nodes) == 1 # only a single node can be tested next
798 assert len(nodes) == 1 # only a single node can be tested next
799 node = nodes[0]
799 node = nodes[0]
800 # compute the approximate number of remaining tests
800 # compute the approximate number of remaining tests
801 tests, size = 0, 2
801 tests, size = 0, 2
802 while size <= changesets:
802 while size <= changesets:
803 tests, size = tests + 1, size * 2
803 tests, size = tests + 1, size * 2
804 rev = repo.changelog.rev(node)
804 rev = repo.changelog.rev(node)
805 ui.write(_("Testing changeset %d:%s "
805 ui.write(_("Testing changeset %d:%s "
806 "(%d changesets remaining, ~%d tests)\n")
806 "(%d changesets remaining, ~%d tests)\n")
807 % (rev, short(node), changesets, tests))
807 % (rev, short(node), changesets, tests))
808 state['current'] = [node]
808 state['current'] = [node]
809 hbisect.save_state(repo, state)
809 hbisect.save_state(repo, state)
810 if not noupdate:
810 if not noupdate:
811 cmdutil.bailifchanged(repo)
811 cmdutil.bailifchanged(repo)
812 return hg.clean(repo, node)
812 return hg.clean(repo, node)
813
813
814 @command('bookmarks|bookmark',
814 @command('bookmarks|bookmark',
815 [('f', 'force', False, _('force')),
815 [('f', 'force', False, _('force')),
816 ('r', 'rev', '', _('revision'), _('REV')),
816 ('r', 'rev', '', _('revision'), _('REV')),
817 ('d', 'delete', False, _('delete a given bookmark')),
817 ('d', 'delete', False, _('delete a given bookmark')),
818 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
818 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
819 ('i', 'inactive', False, _('mark a bookmark inactive'))],
819 ('i', 'inactive', False, _('mark a bookmark inactive'))],
820 _('hg bookmarks [OPTIONS]... [NAME]...'))
820 _('hg bookmarks [OPTIONS]... [NAME]...'))
821 def bookmark(ui, repo, *names, **opts):
821 def bookmark(ui, repo, *names, **opts):
822 '''create a new bookmark or list existing bookmarks
822 '''create a new bookmark or list existing bookmarks
823
823
824 Bookmarks are labels on changesets to help track lines of development.
824 Bookmarks are labels on changesets to help track lines of development.
825 Bookmarks are unversioned and can be moved, renamed and deleted.
825 Bookmarks are unversioned and can be moved, renamed and deleted.
826 Deleting or moving a bookmark has no effect on the associated changesets.
826 Deleting or moving a bookmark has no effect on the associated changesets.
827
827
828 Creating or updating to a bookmark causes it to be marked as 'active'.
828 Creating or updating to a bookmark causes it to be marked as 'active'.
829 The active bookmark is indicated with a '*'.
829 The active bookmark is indicated with a '*'.
830 When a commit is made, the active bookmark will advance to the new commit.
830 When a commit is made, the active bookmark will advance to the new commit.
831 A plain :hg:`update` will also advance an active bookmark, if possible.
831 A plain :hg:`update` will also advance an active bookmark, if possible.
832 Updating away from a bookmark will cause it to be deactivated.
832 Updating away from a bookmark will cause it to be deactivated.
833
833
834 Bookmarks can be pushed and pulled between repositories (see
834 Bookmarks can be pushed and pulled between repositories (see
835 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
835 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
836 diverged, a new 'divergent bookmark' of the form 'name@path' will
836 diverged, a new 'divergent bookmark' of the form 'name@path' will
837 be created. Using :hg:'merge' will resolve the divergence.
837 be created. Using :hg:'merge' will resolve the divergence.
838
838
839 A bookmark named '@' has the special property that :hg:`clone` will
839 A bookmark named '@' has the special property that :hg:`clone` will
840 check it out by default if it exists.
840 check it out by default if it exists.
841
841
842 .. container:: verbose
842 .. container:: verbose
843
843
844 Examples:
844 Examples:
845
845
846 - create an active bookmark for a new line of development::
846 - create an active bookmark for a new line of development::
847
847
848 hg book new-feature
848 hg book new-feature
849
849
850 - create an inactive bookmark as a place marker::
850 - create an inactive bookmark as a place marker::
851
851
852 hg book -i reviewed
852 hg book -i reviewed
853
853
854 - create an inactive bookmark on another changeset::
854 - create an inactive bookmark on another changeset::
855
855
856 hg book -r .^ tested
856 hg book -r .^ tested
857
857
858 - move the '@' bookmark from another branch::
858 - move the '@' bookmark from another branch::
859
859
860 hg book -f @
860 hg book -f @
861 '''
861 '''
862 force = opts.get('force')
862 force = opts.get('force')
863 rev = opts.get('rev')
863 rev = opts.get('rev')
864 delete = opts.get('delete')
864 delete = opts.get('delete')
865 rename = opts.get('rename')
865 rename = opts.get('rename')
866 inactive = opts.get('inactive')
866 inactive = opts.get('inactive')
867
867
868 def checkformat(mark):
868 def checkformat(mark):
869 mark = mark.strip()
869 mark = mark.strip()
870 if not mark:
870 if not mark:
871 raise util.Abort(_("bookmark names cannot consist entirely of "
871 raise util.Abort(_("bookmark names cannot consist entirely of "
872 "whitespace"))
872 "whitespace"))
873 scmutil.checknewlabel(repo, mark, 'bookmark')
873 scmutil.checknewlabel(repo, mark, 'bookmark')
874 return mark
874 return mark
875
875
876 def checkconflict(repo, mark, cur, force=False, target=None):
876 def checkconflict(repo, mark, cur, force=False, target=None):
877 if mark in marks and not force:
877 if mark in marks and not force:
878 if target:
878 if target:
879 if marks[mark] == target and target == cur:
879 if marks[mark] == target and target == cur:
880 # re-activating a bookmark
880 # re-activating a bookmark
881 return
881 return
882 anc = repo.changelog.ancestors([repo[target].rev()])
882 anc = repo.changelog.ancestors([repo[target].rev()])
883 bmctx = repo[marks[mark]]
883 bmctx = repo[marks[mark]]
884 divs = [repo[b].node() for b in marks
884 divs = [repo[b].node() for b in marks
885 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
885 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
886
886
887 # allow resolving a single divergent bookmark even if moving
887 # allow resolving a single divergent bookmark even if moving
888 # the bookmark across branches when a revision is specified
888 # the bookmark across branches when a revision is specified
889 # that contains a divergent bookmark
889 # that contains a divergent bookmark
890 if bmctx.rev() not in anc and target in divs:
890 if bmctx.rev() not in anc and target in divs:
891 bookmarks.deletedivergent(repo, [target], mark)
891 bookmarks.deletedivergent(repo, [target], mark)
892 return
892 return
893
893
894 deletefrom = [b for b in divs
894 deletefrom = [b for b in divs
895 if repo[b].rev() in anc or b == target]
895 if repo[b].rev() in anc or b == target]
896 bookmarks.deletedivergent(repo, deletefrom, mark)
896 bookmarks.deletedivergent(repo, deletefrom, mark)
897 if bookmarks.validdest(repo, bmctx, repo[target]):
897 if bookmarks.validdest(repo, bmctx, repo[target]):
898 ui.status(_("moving bookmark '%s' forward from %s\n") %
898 ui.status(_("moving bookmark '%s' forward from %s\n") %
899 (mark, short(bmctx.node())))
899 (mark, short(bmctx.node())))
900 return
900 return
901 raise util.Abort(_("bookmark '%s' already exists "
901 raise util.Abort(_("bookmark '%s' already exists "
902 "(use -f to force)") % mark)
902 "(use -f to force)") % mark)
903 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
903 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
904 and not force):
904 and not force):
905 raise util.Abort(
905 raise util.Abort(
906 _("a bookmark cannot have the name of an existing branch"))
906 _("a bookmark cannot have the name of an existing branch"))
907
907
908 if delete and rename:
908 if delete and rename:
909 raise util.Abort(_("--delete and --rename are incompatible"))
909 raise util.Abort(_("--delete and --rename are incompatible"))
910 if delete and rev:
910 if delete and rev:
911 raise util.Abort(_("--rev is incompatible with --delete"))
911 raise util.Abort(_("--rev is incompatible with --delete"))
912 if rename and rev:
912 if rename and rev:
913 raise util.Abort(_("--rev is incompatible with --rename"))
913 raise util.Abort(_("--rev is incompatible with --rename"))
914 if not names and (delete or rev):
914 if not names and (delete or rev):
915 raise util.Abort(_("bookmark name required"))
915 raise util.Abort(_("bookmark name required"))
916
916
917 if delete or rename or names or inactive:
917 if delete or rename or names or inactive:
918 wlock = repo.wlock()
918 wlock = repo.wlock()
919 try:
919 try:
920 cur = repo.changectx('.').node()
920 cur = repo.changectx('.').node()
921 marks = repo._bookmarks
921 marks = repo._bookmarks
922 if delete:
922 if delete:
923 for mark in names:
923 for mark in names:
924 if mark not in marks:
924 if mark not in marks:
925 raise util.Abort(_("bookmark '%s' does not exist") %
925 raise util.Abort(_("bookmark '%s' does not exist") %
926 mark)
926 mark)
927 if mark == repo._bookmarkcurrent:
927 if mark == repo._bookmarkcurrent:
928 bookmarks.unsetcurrent(repo)
928 bookmarks.unsetcurrent(repo)
929 del marks[mark]
929 del marks[mark]
930 marks.write()
930 marks.write()
931
931
932 elif rename:
932 elif rename:
933 if not names:
933 if not names:
934 raise util.Abort(_("new bookmark name required"))
934 raise util.Abort(_("new bookmark name required"))
935 elif len(names) > 1:
935 elif len(names) > 1:
936 raise util.Abort(_("only one new bookmark name allowed"))
936 raise util.Abort(_("only one new bookmark name allowed"))
937 mark = checkformat(names[0])
937 mark = checkformat(names[0])
938 if rename not in marks:
938 if rename not in marks:
939 raise util.Abort(_("bookmark '%s' does not exist") % rename)
939 raise util.Abort(_("bookmark '%s' does not exist") % rename)
940 checkconflict(repo, mark, cur, force)
940 checkconflict(repo, mark, cur, force)
941 marks[mark] = marks[rename]
941 marks[mark] = marks[rename]
942 if repo._bookmarkcurrent == rename and not inactive:
942 if repo._bookmarkcurrent == rename and not inactive:
943 bookmarks.setcurrent(repo, mark)
943 bookmarks.setcurrent(repo, mark)
944 del marks[rename]
944 del marks[rename]
945 marks.write()
945 marks.write()
946
946
947 elif names:
947 elif names:
948 newact = None
948 newact = None
949 for mark in names:
949 for mark in names:
950 mark = checkformat(mark)
950 mark = checkformat(mark)
951 if newact is None:
951 if newact is None:
952 newact = mark
952 newact = mark
953 if inactive and mark == repo._bookmarkcurrent:
953 if inactive and mark == repo._bookmarkcurrent:
954 bookmarks.unsetcurrent(repo)
954 bookmarks.unsetcurrent(repo)
955 return
955 return
956 tgt = cur
956 tgt = cur
957 if rev:
957 if rev:
958 tgt = scmutil.revsingle(repo, rev).node()
958 tgt = scmutil.revsingle(repo, rev).node()
959 checkconflict(repo, mark, cur, force, tgt)
959 checkconflict(repo, mark, cur, force, tgt)
960 marks[mark] = tgt
960 marks[mark] = tgt
961 if not inactive and cur == marks[newact] and not rev:
961 if not inactive and cur == marks[newact] and not rev:
962 bookmarks.setcurrent(repo, newact)
962 bookmarks.setcurrent(repo, newact)
963 elif cur != tgt and newact == repo._bookmarkcurrent:
963 elif cur != tgt and newact == repo._bookmarkcurrent:
964 bookmarks.unsetcurrent(repo)
964 bookmarks.unsetcurrent(repo)
965 marks.write()
965 marks.write()
966
966
967 elif inactive:
967 elif inactive:
968 if len(marks) == 0:
968 if len(marks) == 0:
969 ui.status(_("no bookmarks set\n"))
969 ui.status(_("no bookmarks set\n"))
970 elif not repo._bookmarkcurrent:
970 elif not repo._bookmarkcurrent:
971 ui.status(_("no active bookmark\n"))
971 ui.status(_("no active bookmark\n"))
972 else:
972 else:
973 bookmarks.unsetcurrent(repo)
973 bookmarks.unsetcurrent(repo)
974 finally:
974 finally:
975 wlock.release()
975 wlock.release()
976 else: # show bookmarks
976 else: # show bookmarks
977 hexfn = ui.debugflag and hex or short
977 hexfn = ui.debugflag and hex or short
978 marks = repo._bookmarks
978 marks = repo._bookmarks
979 if len(marks) == 0:
979 if len(marks) == 0:
980 ui.status(_("no bookmarks set\n"))
980 ui.status(_("no bookmarks set\n"))
981 else:
981 else:
982 for bmark, n in sorted(marks.iteritems()):
982 for bmark, n in sorted(marks.iteritems()):
983 current = repo._bookmarkcurrent
983 current = repo._bookmarkcurrent
984 if bmark == current:
984 if bmark == current:
985 prefix, label = '*', 'bookmarks.current'
985 prefix, label = '*', 'bookmarks.current'
986 else:
986 else:
987 prefix, label = ' ', ''
987 prefix, label = ' ', ''
988
988
989 if ui.quiet:
989 if ui.quiet:
990 ui.write("%s\n" % bmark, label=label)
990 ui.write("%s\n" % bmark, label=label)
991 else:
991 else:
992 pad = " " * (25 - encoding.colwidth(bmark))
992 pad = " " * (25 - encoding.colwidth(bmark))
993 ui.write(" %s %s%s %d:%s\n" % (
993 ui.write(" %s %s%s %d:%s\n" % (
994 prefix, bmark, pad, repo.changelog.rev(n), hexfn(n)),
994 prefix, bmark, pad, repo.changelog.rev(n), hexfn(n)),
995 label=label)
995 label=label)
996
996
997 @command('branch',
997 @command('branch',
998 [('f', 'force', None,
998 [('f', 'force', None,
999 _('set branch name even if it shadows an existing branch')),
999 _('set branch name even if it shadows an existing branch')),
1000 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1000 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1001 _('[-fC] [NAME]'))
1001 _('[-fC] [NAME]'))
1002 def branch(ui, repo, label=None, **opts):
1002 def branch(ui, repo, label=None, **opts):
1003 """set or show the current branch name
1003 """set or show the current branch name
1004
1004
1005 .. note::
1005 .. note::
1006
1006
1007 Branch names are permanent and global. Use :hg:`bookmark` to create a
1007 Branch names are permanent and global. Use :hg:`bookmark` to create a
1008 light-weight bookmark instead. See :hg:`help glossary` for more
1008 light-weight bookmark instead. See :hg:`help glossary` for more
1009 information about named branches and bookmarks.
1009 information about named branches and bookmarks.
1010
1010
1011 With no argument, show the current branch name. With one argument,
1011 With no argument, show the current branch name. With one argument,
1012 set the working directory branch name (the branch will not exist
1012 set the working directory branch name (the branch will not exist
1013 in the repository until the next commit). Standard practice
1013 in the repository until the next commit). Standard practice
1014 recommends that primary development take place on the 'default'
1014 recommends that primary development take place on the 'default'
1015 branch.
1015 branch.
1016
1016
1017 Unless -f/--force is specified, branch will not let you set a
1017 Unless -f/--force is specified, branch will not let you set a
1018 branch name that already exists, even if it's inactive.
1018 branch name that already exists, even if it's inactive.
1019
1019
1020 Use -C/--clean to reset the working directory branch to that of
1020 Use -C/--clean to reset the working directory branch to that of
1021 the parent of the working directory, negating a previous branch
1021 the parent of the working directory, negating a previous branch
1022 change.
1022 change.
1023
1023
1024 Use the command :hg:`update` to switch to an existing branch. Use
1024 Use the command :hg:`update` to switch to an existing branch. Use
1025 :hg:`commit --close-branch` to mark this branch as closed.
1025 :hg:`commit --close-branch` to mark this branch as closed.
1026
1026
1027 Returns 0 on success.
1027 Returns 0 on success.
1028 """
1028 """
1029 if label:
1029 if label:
1030 label = label.strip()
1030 label = label.strip()
1031
1031
1032 if not opts.get('clean') and not label:
1032 if not opts.get('clean') and not label:
1033 ui.write("%s\n" % repo.dirstate.branch())
1033 ui.write("%s\n" % repo.dirstate.branch())
1034 return
1034 return
1035
1035
1036 wlock = repo.wlock()
1036 wlock = repo.wlock()
1037 try:
1037 try:
1038 if opts.get('clean'):
1038 if opts.get('clean'):
1039 label = repo[None].p1().branch()
1039 label = repo[None].p1().branch()
1040 repo.dirstate.setbranch(label)
1040 repo.dirstate.setbranch(label)
1041 ui.status(_('reset working directory to branch %s\n') % label)
1041 ui.status(_('reset working directory to branch %s\n') % label)
1042 elif label:
1042 elif label:
1043 if not opts.get('force') and label in repo.branchmap():
1043 if not opts.get('force') and label in repo.branchmap():
1044 if label not in [p.branch() for p in repo.parents()]:
1044 if label not in [p.branch() for p in repo.parents()]:
1045 raise util.Abort(_('a branch of the same name already'
1045 raise util.Abort(_('a branch of the same name already'
1046 ' exists'),
1046 ' exists'),
1047 # i18n: "it" refers to an existing branch
1047 # i18n: "it" refers to an existing branch
1048 hint=_("use 'hg update' to switch to it"))
1048 hint=_("use 'hg update' to switch to it"))
1049 scmutil.checknewlabel(repo, label, 'branch')
1049 scmutil.checknewlabel(repo, label, 'branch')
1050 repo.dirstate.setbranch(label)
1050 repo.dirstate.setbranch(label)
1051 ui.status(_('marked working directory as branch %s\n') % label)
1051 ui.status(_('marked working directory as branch %s\n') % label)
1052 ui.status(_('(branches are permanent and global, '
1052 ui.status(_('(branches are permanent and global, '
1053 'did you want a bookmark?)\n'))
1053 'did you want a bookmark?)\n'))
1054 finally:
1054 finally:
1055 wlock.release()
1055 wlock.release()
1056
1056
1057 @command('branches',
1057 @command('branches',
1058 [('a', 'active', False, _('show only branches that have unmerged heads')),
1058 [('a', 'active', False, _('show only branches that have unmerged heads')),
1059 ('c', 'closed', False, _('show normal and closed branches'))],
1059 ('c', 'closed', False, _('show normal and closed branches'))],
1060 _('[-ac]'))
1060 _('[-ac]'))
1061 def branches(ui, repo, active=False, closed=False):
1061 def branches(ui, repo, active=False, closed=False):
1062 """list repository named branches
1062 """list repository named branches
1063
1063
1064 List the repository's named branches, indicating which ones are
1064 List the repository's named branches, indicating which ones are
1065 inactive. If -c/--closed is specified, also list branches which have
1065 inactive. If -c/--closed is specified, also list branches which have
1066 been marked closed (see :hg:`commit --close-branch`).
1066 been marked closed (see :hg:`commit --close-branch`).
1067
1067
1068 If -a/--active is specified, only show active branches. A branch
1068 If -a/--active is specified, only show active branches. A branch
1069 is considered active if it contains repository heads.
1069 is considered active if it contains repository heads.
1070
1070
1071 Use the command :hg:`update` to switch to an existing branch.
1071 Use the command :hg:`update` to switch to an existing branch.
1072
1072
1073 Returns 0.
1073 Returns 0.
1074 """
1074 """
1075
1075
1076 hexfunc = ui.debugflag and hex or short
1076 hexfunc = ui.debugflag and hex or short
1077
1077
1078 allheads = set(repo.heads())
1078 allheads = set(repo.heads())
1079 branches = []
1079 branches = []
1080 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1080 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1081 isactive = not isclosed and bool(set(heads) & allheads)
1081 isactive = not isclosed and bool(set(heads) & allheads)
1082 branches.append((tag, repo[tip], isactive, not isclosed))
1082 branches.append((tag, repo[tip], isactive, not isclosed))
1083 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1083 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1084 reverse=True)
1084 reverse=True)
1085
1085
1086 for tag, ctx, isactive, isopen in branches:
1086 for tag, ctx, isactive, isopen in branches:
1087 if (not active) or isactive:
1087 if (not active) or isactive:
1088 if isactive:
1088 if isactive:
1089 label = 'branches.active'
1089 label = 'branches.active'
1090 notice = ''
1090 notice = ''
1091 elif not isopen:
1091 elif not isopen:
1092 if not closed:
1092 if not closed:
1093 continue
1093 continue
1094 label = 'branches.closed'
1094 label = 'branches.closed'
1095 notice = _(' (closed)')
1095 notice = _(' (closed)')
1096 else:
1096 else:
1097 label = 'branches.inactive'
1097 label = 'branches.inactive'
1098 notice = _(' (inactive)')
1098 notice = _(' (inactive)')
1099 if tag == repo.dirstate.branch():
1099 if tag == repo.dirstate.branch():
1100 label = 'branches.current'
1100 label = 'branches.current'
1101 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(tag))
1101 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(tag))
1102 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1102 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1103 'log.changeset changeset.%s' % ctx.phasestr())
1103 'log.changeset changeset.%s' % ctx.phasestr())
1104 labeledtag = ui.label(tag, label)
1104 labeledtag = ui.label(tag, label)
1105 if ui.quiet:
1105 if ui.quiet:
1106 ui.write("%s\n" % labeledtag)
1106 ui.write("%s\n" % labeledtag)
1107 else:
1107 else:
1108 ui.write("%s %s%s\n" % (labeledtag, rev, notice))
1108 ui.write("%s %s%s\n" % (labeledtag, rev, notice))
1109
1109
1110 @command('bundle',
1110 @command('bundle',
1111 [('f', 'force', None, _('run even when the destination is unrelated')),
1111 [('f', 'force', None, _('run even when the destination is unrelated')),
1112 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1112 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1113 _('REV')),
1113 _('REV')),
1114 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1114 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1115 _('BRANCH')),
1115 _('BRANCH')),
1116 ('', 'base', [],
1116 ('', 'base', [],
1117 _('a base changeset assumed to be available at the destination'),
1117 _('a base changeset assumed to be available at the destination'),
1118 _('REV')),
1118 _('REV')),
1119 ('a', 'all', None, _('bundle all changesets in the repository')),
1119 ('a', 'all', None, _('bundle all changesets in the repository')),
1120 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1120 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1121 ] + remoteopts,
1121 ] + remoteopts,
1122 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1122 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1123 def bundle(ui, repo, fname, dest=None, **opts):
1123 def bundle(ui, repo, fname, dest=None, **opts):
1124 """create a changegroup file
1124 """create a changegroup file
1125
1125
1126 Generate a compressed changegroup file collecting changesets not
1126 Generate a compressed changegroup file collecting changesets not
1127 known to be in another repository.
1127 known to be in another repository.
1128
1128
1129 If you omit the destination repository, then hg assumes the
1129 If you omit the destination repository, then hg assumes the
1130 destination will have all the nodes you specify with --base
1130 destination will have all the nodes you specify with --base
1131 parameters. To create a bundle containing all changesets, use
1131 parameters. To create a bundle containing all changesets, use
1132 -a/--all (or --base null).
1132 -a/--all (or --base null).
1133
1133
1134 You can change compression method with the -t/--type option.
1134 You can change compression method with the -t/--type option.
1135 The available compression methods are: none, bzip2, and
1135 The available compression methods are: none, bzip2, and
1136 gzip (by default, bundles are compressed using bzip2).
1136 gzip (by default, bundles are compressed using bzip2).
1137
1137
1138 The bundle file can then be transferred using conventional means
1138 The bundle file can then be transferred using conventional means
1139 and applied to another repository with the unbundle or pull
1139 and applied to another repository with the unbundle or pull
1140 command. This is useful when direct push and pull are not
1140 command. This is useful when direct push and pull are not
1141 available or when exporting an entire repository is undesirable.
1141 available or when exporting an entire repository is undesirable.
1142
1142
1143 Applying bundles preserves all changeset contents including
1143 Applying bundles preserves all changeset contents including
1144 permissions, copy/rename information, and revision history.
1144 permissions, copy/rename information, and revision history.
1145
1145
1146 Returns 0 on success, 1 if no changes found.
1146 Returns 0 on success, 1 if no changes found.
1147 """
1147 """
1148 revs = None
1148 revs = None
1149 if 'rev' in opts:
1149 if 'rev' in opts:
1150 revs = scmutil.revrange(repo, opts['rev'])
1150 revs = scmutil.revrange(repo, opts['rev'])
1151
1151
1152 bundletype = opts.get('type', 'bzip2').lower()
1152 bundletype = opts.get('type', 'bzip2').lower()
1153 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1153 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1154 bundletype = btypes.get(bundletype)
1154 bundletype = btypes.get(bundletype)
1155 if bundletype not in changegroup.bundletypes:
1155 if bundletype not in changegroup.bundletypes:
1156 raise util.Abort(_('unknown bundle type specified with --type'))
1156 raise util.Abort(_('unknown bundle type specified with --type'))
1157
1157
1158 if opts.get('all'):
1158 if opts.get('all'):
1159 base = ['null']
1159 base = ['null']
1160 else:
1160 else:
1161 base = scmutil.revrange(repo, opts.get('base'))
1161 base = scmutil.revrange(repo, opts.get('base'))
1162 # TODO: get desired bundlecaps from command line.
1162 # TODO: get desired bundlecaps from command line.
1163 bundlecaps = None
1163 bundlecaps = None
1164 if base:
1164 if base:
1165 if dest:
1165 if dest:
1166 raise util.Abort(_("--base is incompatible with specifying "
1166 raise util.Abort(_("--base is incompatible with specifying "
1167 "a destination"))
1167 "a destination"))
1168 common = [repo.lookup(rev) for rev in base]
1168 common = [repo.lookup(rev) for rev in base]
1169 heads = revs and map(repo.lookup, revs) or revs
1169 heads = revs and map(repo.lookup, revs) or revs
1170 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1170 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1171 common=common, bundlecaps=bundlecaps)
1171 common=common, bundlecaps=bundlecaps)
1172 outgoing = None
1172 outgoing = None
1173 else:
1173 else:
1174 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1174 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1175 dest, branches = hg.parseurl(dest, opts.get('branch'))
1175 dest, branches = hg.parseurl(dest, opts.get('branch'))
1176 other = hg.peer(repo, opts, dest)
1176 other = hg.peer(repo, opts, dest)
1177 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1177 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1178 heads = revs and map(repo.lookup, revs) or revs
1178 heads = revs and map(repo.lookup, revs) or revs
1179 outgoing = discovery.findcommonoutgoing(repo, other,
1179 outgoing = discovery.findcommonoutgoing(repo, other,
1180 onlyheads=heads,
1180 onlyheads=heads,
1181 force=opts.get('force'),
1181 force=opts.get('force'),
1182 portable=True)
1182 portable=True)
1183 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1183 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1184 bundlecaps)
1184 bundlecaps)
1185 if not cg:
1185 if not cg:
1186 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1186 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1187 return 1
1187 return 1
1188
1188
1189 changegroup.writebundle(cg, fname, bundletype)
1189 changegroup.writebundle(cg, fname, bundletype)
1190
1190
1191 @command('cat',
1191 @command('cat',
1192 [('o', 'output', '',
1192 [('o', 'output', '',
1193 _('print output to file with formatted name'), _('FORMAT')),
1193 _('print output to file with formatted name'), _('FORMAT')),
1194 ('r', 'rev', '', _('print the given revision'), _('REV')),
1194 ('r', 'rev', '', _('print the given revision'), _('REV')),
1195 ('', 'decode', None, _('apply any matching decode filter')),
1195 ('', 'decode', None, _('apply any matching decode filter')),
1196 ] + walkopts,
1196 ] + walkopts,
1197 _('[OPTION]... FILE...'),
1197 _('[OPTION]... FILE...'),
1198 inferrepo=True)
1198 inferrepo=True)
1199 def cat(ui, repo, file1, *pats, **opts):
1199 def cat(ui, repo, file1, *pats, **opts):
1200 """output the current or given revision of files
1200 """output the current or given revision of files
1201
1201
1202 Print the specified files as they were at the given revision. If
1202 Print the specified files as they were at the given revision. If
1203 no revision is given, the parent of the working directory is used.
1203 no revision is given, the parent of the working directory is used.
1204
1204
1205 Output may be to a file, in which case the name of the file is
1205 Output may be to a file, in which case the name of the file is
1206 given using a format string. The formatting rules as follows:
1206 given using a format string. The formatting rules as follows:
1207
1207
1208 :``%%``: literal "%" character
1208 :``%%``: literal "%" character
1209 :``%s``: basename of file being printed
1209 :``%s``: basename of file being printed
1210 :``%d``: dirname of file being printed, or '.' if in repository root
1210 :``%d``: dirname of file being printed, or '.' if in repository root
1211 :``%p``: root-relative path name of file being printed
1211 :``%p``: root-relative path name of file being printed
1212 :``%H``: changeset hash (40 hexadecimal digits)
1212 :``%H``: changeset hash (40 hexadecimal digits)
1213 :``%R``: changeset revision number
1213 :``%R``: changeset revision number
1214 :``%h``: short-form changeset hash (12 hexadecimal digits)
1214 :``%h``: short-form changeset hash (12 hexadecimal digits)
1215 :``%r``: zero-padded changeset revision number
1215 :``%r``: zero-padded changeset revision number
1216 :``%b``: basename of the exporting repository
1216 :``%b``: basename of the exporting repository
1217
1217
1218 Returns 0 on success.
1218 Returns 0 on success.
1219 """
1219 """
1220 ctx = scmutil.revsingle(repo, opts.get('rev'))
1220 ctx = scmutil.revsingle(repo, opts.get('rev'))
1221 m = scmutil.match(ctx, (file1,) + pats, opts)
1221 m = scmutil.match(ctx, (file1,) + pats, opts)
1222
1222
1223 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1223 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1224
1224
1225 @command('^clone',
1225 @command('^clone',
1226 [('U', 'noupdate', None,
1226 [('U', 'noupdate', None,
1227 _('the clone will include an empty working copy (only a repository)')),
1227 _('the clone will include an empty working copy (only a repository)')),
1228 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1228 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1229 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1229 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1230 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1230 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1231 ('', 'pull', None, _('use pull protocol to copy metadata')),
1231 ('', 'pull', None, _('use pull protocol to copy metadata')),
1232 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1232 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1233 ] + remoteopts,
1233 ] + remoteopts,
1234 _('[OPTION]... SOURCE [DEST]'),
1234 _('[OPTION]... SOURCE [DEST]'),
1235 norepo=True)
1235 norepo=True)
1236 def clone(ui, source, dest=None, **opts):
1236 def clone(ui, source, dest=None, **opts):
1237 """make a copy of an existing repository
1237 """make a copy of an existing repository
1238
1238
1239 Create a copy of an existing repository in a new directory.
1239 Create a copy of an existing repository in a new directory.
1240
1240
1241 If no destination directory name is specified, it defaults to the
1241 If no destination directory name is specified, it defaults to the
1242 basename of the source.
1242 basename of the source.
1243
1243
1244 The location of the source is added to the new repository's
1244 The location of the source is added to the new repository's
1245 ``.hg/hgrc`` file, as the default to be used for future pulls.
1245 ``.hg/hgrc`` file, as the default to be used for future pulls.
1246
1246
1247 Only local paths and ``ssh://`` URLs are supported as
1247 Only local paths and ``ssh://`` URLs are supported as
1248 destinations. For ``ssh://`` destinations, no working directory or
1248 destinations. For ``ssh://`` destinations, no working directory or
1249 ``.hg/hgrc`` will be created on the remote side.
1249 ``.hg/hgrc`` will be created on the remote side.
1250
1250
1251 To pull only a subset of changesets, specify one or more revisions
1251 To pull only a subset of changesets, specify one or more revisions
1252 identifiers with -r/--rev or branches with -b/--branch. The
1252 identifiers with -r/--rev or branches with -b/--branch. The
1253 resulting clone will contain only the specified changesets and
1253 resulting clone will contain only the specified changesets and
1254 their ancestors. These options (or 'clone src#rev dest') imply
1254 their ancestors. These options (or 'clone src#rev dest') imply
1255 --pull, even for local source repositories. Note that specifying a
1255 --pull, even for local source repositories. Note that specifying a
1256 tag will include the tagged changeset but not the changeset
1256 tag will include the tagged changeset but not the changeset
1257 containing the tag.
1257 containing the tag.
1258
1258
1259 If the source repository has a bookmark called '@' set, that
1259 If the source repository has a bookmark called '@' set, that
1260 revision will be checked out in the new repository by default.
1260 revision will be checked out in the new repository by default.
1261
1261
1262 To check out a particular version, use -u/--update, or
1262 To check out a particular version, use -u/--update, or
1263 -U/--noupdate to create a clone with no working directory.
1263 -U/--noupdate to create a clone with no working directory.
1264
1264
1265 .. container:: verbose
1265 .. container:: verbose
1266
1266
1267 For efficiency, hardlinks are used for cloning whenever the
1267 For efficiency, hardlinks are used for cloning whenever the
1268 source and destination are on the same filesystem (note this
1268 source and destination are on the same filesystem (note this
1269 applies only to the repository data, not to the working
1269 applies only to the repository data, not to the working
1270 directory). Some filesystems, such as AFS, implement hardlinking
1270 directory). Some filesystems, such as AFS, implement hardlinking
1271 incorrectly, but do not report errors. In these cases, use the
1271 incorrectly, but do not report errors. In these cases, use the
1272 --pull option to avoid hardlinking.
1272 --pull option to avoid hardlinking.
1273
1273
1274 In some cases, you can clone repositories and the working
1274 In some cases, you can clone repositories and the working
1275 directory using full hardlinks with ::
1275 directory using full hardlinks with ::
1276
1276
1277 $ cp -al REPO REPOCLONE
1277 $ cp -al REPO REPOCLONE
1278
1278
1279 This is the fastest way to clone, but it is not always safe. The
1279 This is the fastest way to clone, but it is not always safe. The
1280 operation is not atomic (making sure REPO is not modified during
1280 operation is not atomic (making sure REPO is not modified during
1281 the operation is up to you) and you have to make sure your
1281 the operation is up to you) and you have to make sure your
1282 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1282 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1283 so). Also, this is not compatible with certain extensions that
1283 so). Also, this is not compatible with certain extensions that
1284 place their metadata under the .hg directory, such as mq.
1284 place their metadata under the .hg directory, such as mq.
1285
1285
1286 Mercurial will update the working directory to the first applicable
1286 Mercurial will update the working directory to the first applicable
1287 revision from this list:
1287 revision from this list:
1288
1288
1289 a) null if -U or the source repository has no changesets
1289 a) null if -U or the source repository has no changesets
1290 b) if -u . and the source repository is local, the first parent of
1290 b) if -u . and the source repository is local, the first parent of
1291 the source repository's working directory
1291 the source repository's working directory
1292 c) the changeset specified with -u (if a branch name, this means the
1292 c) the changeset specified with -u (if a branch name, this means the
1293 latest head of that branch)
1293 latest head of that branch)
1294 d) the changeset specified with -r
1294 d) the changeset specified with -r
1295 e) the tipmost head specified with -b
1295 e) the tipmost head specified with -b
1296 f) the tipmost head specified with the url#branch source syntax
1296 f) the tipmost head specified with the url#branch source syntax
1297 g) the revision marked with the '@' bookmark, if present
1297 g) the revision marked with the '@' bookmark, if present
1298 h) the tipmost head of the default branch
1298 h) the tipmost head of the default branch
1299 i) tip
1299 i) tip
1300
1300
1301 Examples:
1301 Examples:
1302
1302
1303 - clone a remote repository to a new directory named hg/::
1303 - clone a remote repository to a new directory named hg/::
1304
1304
1305 hg clone http://selenic.com/hg
1305 hg clone http://selenic.com/hg
1306
1306
1307 - create a lightweight local clone::
1307 - create a lightweight local clone::
1308
1308
1309 hg clone project/ project-feature/
1309 hg clone project/ project-feature/
1310
1310
1311 - clone from an absolute path on an ssh server (note double-slash)::
1311 - clone from an absolute path on an ssh server (note double-slash)::
1312
1312
1313 hg clone ssh://user@server//home/projects/alpha/
1313 hg clone ssh://user@server//home/projects/alpha/
1314
1314
1315 - do a high-speed clone over a LAN while checking out a
1315 - do a high-speed clone over a LAN while checking out a
1316 specified version::
1316 specified version::
1317
1317
1318 hg clone --uncompressed http://server/repo -u 1.5
1318 hg clone --uncompressed http://server/repo -u 1.5
1319
1319
1320 - create a repository without changesets after a particular revision::
1320 - create a repository without changesets after a particular revision::
1321
1321
1322 hg clone -r 04e544 experimental/ good/
1322 hg clone -r 04e544 experimental/ good/
1323
1323
1324 - clone (and track) a particular named branch::
1324 - clone (and track) a particular named branch::
1325
1325
1326 hg clone http://selenic.com/hg#stable
1326 hg clone http://selenic.com/hg#stable
1327
1327
1328 See :hg:`help urls` for details on specifying URLs.
1328 See :hg:`help urls` for details on specifying URLs.
1329
1329
1330 Returns 0 on success.
1330 Returns 0 on success.
1331 """
1331 """
1332 if opts.get('noupdate') and opts.get('updaterev'):
1332 if opts.get('noupdate') and opts.get('updaterev'):
1333 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1333 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1334
1334
1335 r = hg.clone(ui, opts, source, dest,
1335 r = hg.clone(ui, opts, source, dest,
1336 pull=opts.get('pull'),
1336 pull=opts.get('pull'),
1337 stream=opts.get('uncompressed'),
1337 stream=opts.get('uncompressed'),
1338 rev=opts.get('rev'),
1338 rev=opts.get('rev'),
1339 update=opts.get('updaterev') or not opts.get('noupdate'),
1339 update=opts.get('updaterev') or not opts.get('noupdate'),
1340 branch=opts.get('branch'))
1340 branch=opts.get('branch'))
1341
1341
1342 return r is None
1342 return r is None
1343
1343
1344 @command('^commit|ci',
1344 @command('^commit|ci',
1345 [('A', 'addremove', None,
1345 [('A', 'addremove', None,
1346 _('mark new/missing files as added/removed before committing')),
1346 _('mark new/missing files as added/removed before committing')),
1347 ('', 'close-branch', None,
1347 ('', 'close-branch', None,
1348 _('mark a branch as closed, hiding it from the branch list')),
1348 _('mark a branch as closed, hiding it from the branch list')),
1349 ('', 'amend', None, _('amend the parent of the working dir')),
1349 ('', 'amend', None, _('amend the parent of the working dir')),
1350 ('s', 'secret', None, _('use the secret phase for committing')),
1350 ('s', 'secret', None, _('use the secret phase for committing')),
1351 ('e', 'edit', None, _('invoke editor on commit messages')),
1351 ('e', 'edit', None, _('invoke editor on commit messages')),
1352 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1352 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1353 _('[OPTION]... [FILE]...'),
1353 _('[OPTION]... [FILE]...'),
1354 inferrepo=True)
1354 inferrepo=True)
1355 def commit(ui, repo, *pats, **opts):
1355 def commit(ui, repo, *pats, **opts):
1356 """commit the specified files or all outstanding changes
1356 """commit the specified files or all outstanding changes
1357
1357
1358 Commit changes to the given files into the repository. Unlike a
1358 Commit changes to the given files into the repository. Unlike a
1359 centralized SCM, this operation is a local operation. See
1359 centralized SCM, this operation is a local operation. See
1360 :hg:`push` for a way to actively distribute your changes.
1360 :hg:`push` for a way to actively distribute your changes.
1361
1361
1362 If a list of files is omitted, all changes reported by :hg:`status`
1362 If a list of files is omitted, all changes reported by :hg:`status`
1363 will be committed.
1363 will be committed.
1364
1364
1365 If you are committing the result of a merge, do not provide any
1365 If you are committing the result of a merge, do not provide any
1366 filenames or -I/-X filters.
1366 filenames or -I/-X filters.
1367
1367
1368 If no commit message is specified, Mercurial starts your
1368 If no commit message is specified, Mercurial starts your
1369 configured editor where you can enter a message. In case your
1369 configured editor where you can enter a message. In case your
1370 commit fails, you will find a backup of your message in
1370 commit fails, you will find a backup of your message in
1371 ``.hg/last-message.txt``.
1371 ``.hg/last-message.txt``.
1372
1372
1373 The --amend flag can be used to amend the parent of the
1373 The --amend flag can be used to amend the parent of the
1374 working directory with a new commit that contains the changes
1374 working directory with a new commit that contains the changes
1375 in the parent in addition to those currently reported by :hg:`status`,
1375 in the parent in addition to those currently reported by :hg:`status`,
1376 if there are any. The old commit is stored in a backup bundle in
1376 if there are any. The old commit is stored in a backup bundle in
1377 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1377 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1378 on how to restore it).
1378 on how to restore it).
1379
1379
1380 Message, user and date are taken from the amended commit unless
1380 Message, user and date are taken from the amended commit unless
1381 specified. When a message isn't specified on the command line,
1381 specified. When a message isn't specified on the command line,
1382 the editor will open with the message of the amended commit.
1382 the editor will open with the message of the amended commit.
1383
1383
1384 It is not possible to amend public changesets (see :hg:`help phases`)
1384 It is not possible to amend public changesets (see :hg:`help phases`)
1385 or changesets that have children.
1385 or changesets that have children.
1386
1386
1387 See :hg:`help dates` for a list of formats valid for -d/--date.
1387 See :hg:`help dates` for a list of formats valid for -d/--date.
1388
1388
1389 Returns 0 on success, 1 if nothing changed.
1389 Returns 0 on success, 1 if nothing changed.
1390 """
1390 """
1391 if opts.get('subrepos'):
1391 if opts.get('subrepos'):
1392 if opts.get('amend'):
1392 if opts.get('amend'):
1393 raise util.Abort(_('cannot amend with --subrepos'))
1393 raise util.Abort(_('cannot amend with --subrepos'))
1394 # Let --subrepos on the command line override config setting.
1394 # Let --subrepos on the command line override config setting.
1395 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1395 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1396
1396
1397 cmdutil.checkunfinished(repo, commit=True)
1397 cmdutil.checkunfinished(repo, commit=True)
1398
1398
1399 branch = repo[None].branch()
1399 branch = repo[None].branch()
1400 bheads = repo.branchheads(branch)
1400 bheads = repo.branchheads(branch)
1401
1401
1402 extra = {}
1402 extra = {}
1403 if opts.get('close_branch'):
1403 if opts.get('close_branch'):
1404 extra['close'] = 1
1404 extra['close'] = 1
1405
1405
1406 if not bheads:
1406 if not bheads:
1407 raise util.Abort(_('can only close branch heads'))
1407 raise util.Abort(_('can only close branch heads'))
1408 elif opts.get('amend'):
1408 elif opts.get('amend'):
1409 if repo.parents()[0].p1().branch() != branch and \
1409 if repo.parents()[0].p1().branch() != branch and \
1410 repo.parents()[0].p2().branch() != branch:
1410 repo.parents()[0].p2().branch() != branch:
1411 raise util.Abort(_('can only close branch heads'))
1411 raise util.Abort(_('can only close branch heads'))
1412
1412
1413 if opts.get('amend'):
1413 if opts.get('amend'):
1414 if ui.configbool('ui', 'commitsubrepos'):
1414 if ui.configbool('ui', 'commitsubrepos'):
1415 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1415 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1416
1416
1417 old = repo['.']
1417 old = repo['.']
1418 if not old.mutable():
1418 if not old.mutable():
1419 raise util.Abort(_('cannot amend public changesets'))
1419 raise util.Abort(_('cannot amend public changesets'))
1420 if len(repo[None].parents()) > 1:
1420 if len(repo[None].parents()) > 1:
1421 raise util.Abort(_('cannot amend while merging'))
1421 raise util.Abort(_('cannot amend while merging'))
1422 if (not obsolete._enabled) and old.children():
1422 if (not obsolete._enabled) and old.children():
1423 raise util.Abort(_('cannot amend changeset with children'))
1423 raise util.Abort(_('cannot amend changeset with children'))
1424
1424
1425 # commitfunc is used only for temporary amend commit by cmdutil.amend
1425 # commitfunc is used only for temporary amend commit by cmdutil.amend
1426 def commitfunc(ui, repo, message, match, opts):
1426 def commitfunc(ui, repo, message, match, opts):
1427 return repo.commit(message,
1427 return repo.commit(message,
1428 opts.get('user') or old.user(),
1428 opts.get('user') or old.user(),
1429 opts.get('date') or old.date(),
1429 opts.get('date') or old.date(),
1430 match,
1430 match,
1431 extra=extra)
1431 extra=extra)
1432
1432
1433 current = repo._bookmarkcurrent
1433 current = repo._bookmarkcurrent
1434 marks = old.bookmarks()
1434 marks = old.bookmarks()
1435 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1435 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1436 if node == old.node():
1436 if node == old.node():
1437 ui.status(_("nothing changed\n"))
1437 ui.status(_("nothing changed\n"))
1438 return 1
1438 return 1
1439 elif marks:
1439 elif marks:
1440 ui.debug('moving bookmarks %r from %s to %s\n' %
1440 ui.debug('moving bookmarks %r from %s to %s\n' %
1441 (marks, old.hex(), hex(node)))
1441 (marks, old.hex(), hex(node)))
1442 newmarks = repo._bookmarks
1442 newmarks = repo._bookmarks
1443 for bm in marks:
1443 for bm in marks:
1444 newmarks[bm] = node
1444 newmarks[bm] = node
1445 if bm == current:
1445 if bm == current:
1446 bookmarks.setcurrent(repo, bm)
1446 bookmarks.setcurrent(repo, bm)
1447 newmarks.write()
1447 newmarks.write()
1448 else:
1448 else:
1449 def commitfunc(ui, repo, message, match, opts):
1449 def commitfunc(ui, repo, message, match, opts):
1450 backup = ui.backupconfig('phases', 'new-commit')
1450 backup = ui.backupconfig('phases', 'new-commit')
1451 baseui = repo.baseui
1451 baseui = repo.baseui
1452 basebackup = baseui.backupconfig('phases', 'new-commit')
1452 basebackup = baseui.backupconfig('phases', 'new-commit')
1453 try:
1453 try:
1454 if opts.get('secret'):
1454 if opts.get('secret'):
1455 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1455 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1456 # Propagate to subrepos
1456 # Propagate to subrepos
1457 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1457 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1458
1458
1459 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1459 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1460 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1460 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1461 return repo.commit(message, opts.get('user'), opts.get('date'),
1461 return repo.commit(message, opts.get('user'), opts.get('date'),
1462 match,
1462 match,
1463 editor=editor,
1463 editor=editor,
1464 extra=extra)
1464 extra=extra)
1465 finally:
1465 finally:
1466 ui.restoreconfig(backup)
1466 ui.restoreconfig(backup)
1467 repo.baseui.restoreconfig(basebackup)
1467 repo.baseui.restoreconfig(basebackup)
1468
1468
1469
1469
1470 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1470 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1471
1471
1472 if not node:
1472 if not node:
1473 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1473 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1474 if stat[3]:
1474 if stat[3]:
1475 ui.status(_("nothing changed (%d missing files, see "
1475 ui.status(_("nothing changed (%d missing files, see "
1476 "'hg status')\n") % len(stat[3]))
1476 "'hg status')\n") % len(stat[3]))
1477 else:
1477 else:
1478 ui.status(_("nothing changed\n"))
1478 ui.status(_("nothing changed\n"))
1479 return 1
1479 return 1
1480
1480
1481 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1481 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1482
1482
1483 @command('config|showconfig|debugconfig',
1483 @command('config|showconfig|debugconfig',
1484 [('u', 'untrusted', None, _('show untrusted configuration options')),
1484 [('u', 'untrusted', None, _('show untrusted configuration options')),
1485 ('e', 'edit', None, _('edit user config')),
1485 ('e', 'edit', None, _('edit user config')),
1486 ('l', 'local', None, _('edit repository config')),
1486 ('l', 'local', None, _('edit repository config')),
1487 ('g', 'global', None, _('edit global config'))],
1487 ('g', 'global', None, _('edit global config'))],
1488 _('[-u] [NAME]...'),
1488 _('[-u] [NAME]...'),
1489 optionalrepo=True)
1489 optionalrepo=True)
1490 def config(ui, repo, *values, **opts):
1490 def config(ui, repo, *values, **opts):
1491 """show combined config settings from all hgrc files
1491 """show combined config settings from all hgrc files
1492
1492
1493 With no arguments, print names and values of all config items.
1493 With no arguments, print names and values of all config items.
1494
1494
1495 With one argument of the form section.name, print just the value
1495 With one argument of the form section.name, print just the value
1496 of that config item.
1496 of that config item.
1497
1497
1498 With multiple arguments, print names and values of all config
1498 With multiple arguments, print names and values of all config
1499 items with matching section names.
1499 items with matching section names.
1500
1500
1501 With --edit, start an editor on the user-level config file. With
1501 With --edit, start an editor on the user-level config file. With
1502 --global, edit the system-wide config file. With --local, edit the
1502 --global, edit the system-wide config file. With --local, edit the
1503 repository-level config file.
1503 repository-level config file.
1504
1504
1505 With --debug, the source (filename and line number) is printed
1505 With --debug, the source (filename and line number) is printed
1506 for each config item.
1506 for each config item.
1507
1507
1508 See :hg:`help config` for more information about config files.
1508 See :hg:`help config` for more information about config files.
1509
1509
1510 Returns 0 on success, 1 if NAME does not exist.
1510 Returns 0 on success, 1 if NAME does not exist.
1511
1511
1512 """
1512 """
1513
1513
1514 if opts.get('edit') or opts.get('local') or opts.get('global'):
1514 if opts.get('edit') or opts.get('local') or opts.get('global'):
1515 if opts.get('local') and opts.get('global'):
1515 if opts.get('local') and opts.get('global'):
1516 raise util.Abort(_("can't use --local and --global together"))
1516 raise util.Abort(_("can't use --local and --global together"))
1517
1517
1518 if opts.get('local'):
1518 if opts.get('local'):
1519 if not repo:
1519 if not repo:
1520 raise util.Abort(_("can't use --local outside a repository"))
1520 raise util.Abort(_("can't use --local outside a repository"))
1521 paths = [repo.join('hgrc')]
1521 paths = [repo.join('hgrc')]
1522 elif opts.get('global'):
1522 elif opts.get('global'):
1523 paths = scmutil.systemrcpath()
1523 paths = scmutil.systemrcpath()
1524 else:
1524 else:
1525 paths = scmutil.userrcpath()
1525 paths = scmutil.userrcpath()
1526
1526
1527 for f in paths:
1527 for f in paths:
1528 if os.path.exists(f):
1528 if os.path.exists(f):
1529 break
1529 break
1530 else:
1530 else:
1531 from ui import samplehgrcs
1531 from ui import samplehgrcs
1532
1532
1533 if opts.get('global'):
1533 if opts.get('global'):
1534 samplehgrc = samplehgrcs['global']
1534 samplehgrc = samplehgrcs['global']
1535 elif opts.get('local'):
1535 elif opts.get('local'):
1536 samplehgrc = samplehgrcs['local']
1536 samplehgrc = samplehgrcs['local']
1537 else:
1537 else:
1538 samplehgrc = samplehgrcs['user']
1538 samplehgrc = samplehgrcs['user']
1539
1539
1540 f = paths[0]
1540 f = paths[0]
1541 fp = open(f, "w")
1541 fp = open(f, "w")
1542 fp.write(samplehgrc)
1542 fp.write(samplehgrc)
1543 fp.close()
1543 fp.close()
1544
1544
1545 editor = ui.geteditor()
1545 editor = ui.geteditor()
1546 util.system("%s \"%s\"" % (editor, f),
1546 util.system("%s \"%s\"" % (editor, f),
1547 onerr=util.Abort, errprefix=_("edit failed"),
1547 onerr=util.Abort, errprefix=_("edit failed"),
1548 out=ui.fout)
1548 out=ui.fout)
1549 return
1549 return
1550
1550
1551 for f in scmutil.rcpath():
1551 for f in scmutil.rcpath():
1552 ui.debug('read config from: %s\n' % f)
1552 ui.debug('read config from: %s\n' % f)
1553 untrusted = bool(opts.get('untrusted'))
1553 untrusted = bool(opts.get('untrusted'))
1554 if values:
1554 if values:
1555 sections = [v for v in values if '.' not in v]
1555 sections = [v for v in values if '.' not in v]
1556 items = [v for v in values if '.' in v]
1556 items = [v for v in values if '.' in v]
1557 if len(items) > 1 or items and sections:
1557 if len(items) > 1 or items and sections:
1558 raise util.Abort(_('only one config item permitted'))
1558 raise util.Abort(_('only one config item permitted'))
1559 matched = False
1559 matched = False
1560 for section, name, value in ui.walkconfig(untrusted=untrusted):
1560 for section, name, value in ui.walkconfig(untrusted=untrusted):
1561 value = str(value).replace('\n', '\\n')
1561 value = str(value).replace('\n', '\\n')
1562 sectname = section + '.' + name
1562 sectname = section + '.' + name
1563 if values:
1563 if values:
1564 for v in values:
1564 for v in values:
1565 if v == section:
1565 if v == section:
1566 ui.debug('%s: ' %
1566 ui.debug('%s: ' %
1567 ui.configsource(section, name, untrusted))
1567 ui.configsource(section, name, untrusted))
1568 ui.write('%s=%s\n' % (sectname, value))
1568 ui.write('%s=%s\n' % (sectname, value))
1569 matched = True
1569 matched = True
1570 elif v == sectname:
1570 elif v == sectname:
1571 ui.debug('%s: ' %
1571 ui.debug('%s: ' %
1572 ui.configsource(section, name, untrusted))
1572 ui.configsource(section, name, untrusted))
1573 ui.write(value, '\n')
1573 ui.write(value, '\n')
1574 matched = True
1574 matched = True
1575 else:
1575 else:
1576 ui.debug('%s: ' %
1576 ui.debug('%s: ' %
1577 ui.configsource(section, name, untrusted))
1577 ui.configsource(section, name, untrusted))
1578 ui.write('%s=%s\n' % (sectname, value))
1578 ui.write('%s=%s\n' % (sectname, value))
1579 matched = True
1579 matched = True
1580 if matched:
1580 if matched:
1581 return 0
1581 return 0
1582 return 1
1582 return 1
1583
1583
1584 @command('copy|cp',
1584 @command('copy|cp',
1585 [('A', 'after', None, _('record a copy that has already occurred')),
1585 [('A', 'after', None, _('record a copy that has already occurred')),
1586 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1586 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1587 ] + walkopts + dryrunopts,
1587 ] + walkopts + dryrunopts,
1588 _('[OPTION]... [SOURCE]... DEST'))
1588 _('[OPTION]... [SOURCE]... DEST'))
1589 def copy(ui, repo, *pats, **opts):
1589 def copy(ui, repo, *pats, **opts):
1590 """mark files as copied for the next commit
1590 """mark files as copied for the next commit
1591
1591
1592 Mark dest as having copies of source files. If dest is a
1592 Mark dest as having copies of source files. If dest is a
1593 directory, copies are put in that directory. If dest is a file,
1593 directory, copies are put in that directory. If dest is a file,
1594 the source must be a single file.
1594 the source must be a single file.
1595
1595
1596 By default, this command copies the contents of files as they
1596 By default, this command copies the contents of files as they
1597 exist in the working directory. If invoked with -A/--after, the
1597 exist in the working directory. If invoked with -A/--after, the
1598 operation is recorded, but no copying is performed.
1598 operation is recorded, but no copying is performed.
1599
1599
1600 This command takes effect with the next commit. To undo a copy
1600 This command takes effect with the next commit. To undo a copy
1601 before that, see :hg:`revert`.
1601 before that, see :hg:`revert`.
1602
1602
1603 Returns 0 on success, 1 if errors are encountered.
1603 Returns 0 on success, 1 if errors are encountered.
1604 """
1604 """
1605 wlock = repo.wlock(False)
1605 wlock = repo.wlock(False)
1606 try:
1606 try:
1607 return cmdutil.copy(ui, repo, pats, opts)
1607 return cmdutil.copy(ui, repo, pats, opts)
1608 finally:
1608 finally:
1609 wlock.release()
1609 wlock.release()
1610
1610
1611 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1611 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1612 def debugancestor(ui, repo, *args):
1612 def debugancestor(ui, repo, *args):
1613 """find the ancestor revision of two revisions in a given index"""
1613 """find the ancestor revision of two revisions in a given index"""
1614 if len(args) == 3:
1614 if len(args) == 3:
1615 index, rev1, rev2 = args
1615 index, rev1, rev2 = args
1616 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1616 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1617 lookup = r.lookup
1617 lookup = r.lookup
1618 elif len(args) == 2:
1618 elif len(args) == 2:
1619 if not repo:
1619 if not repo:
1620 raise util.Abort(_("there is no Mercurial repository here "
1620 raise util.Abort(_("there is no Mercurial repository here "
1621 "(.hg not found)"))
1621 "(.hg not found)"))
1622 rev1, rev2 = args
1622 rev1, rev2 = args
1623 r = repo.changelog
1623 r = repo.changelog
1624 lookup = repo.lookup
1624 lookup = repo.lookup
1625 else:
1625 else:
1626 raise util.Abort(_('either two or three arguments required'))
1626 raise util.Abort(_('either two or three arguments required'))
1627 a = r.ancestor(lookup(rev1), lookup(rev2))
1627 a = r.ancestor(lookup(rev1), lookup(rev2))
1628 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1628 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1629
1629
1630 @command('debugbuilddag',
1630 @command('debugbuilddag',
1631 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1631 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1632 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1632 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1633 ('n', 'new-file', None, _('add new file at each rev'))],
1633 ('n', 'new-file', None, _('add new file at each rev'))],
1634 _('[OPTION]... [TEXT]'))
1634 _('[OPTION]... [TEXT]'))
1635 def debugbuilddag(ui, repo, text=None,
1635 def debugbuilddag(ui, repo, text=None,
1636 mergeable_file=False,
1636 mergeable_file=False,
1637 overwritten_file=False,
1637 overwritten_file=False,
1638 new_file=False):
1638 new_file=False):
1639 """builds a repo with a given DAG from scratch in the current empty repo
1639 """builds a repo with a given DAG from scratch in the current empty repo
1640
1640
1641 The description of the DAG is read from stdin if not given on the
1641 The description of the DAG is read from stdin if not given on the
1642 command line.
1642 command line.
1643
1643
1644 Elements:
1644 Elements:
1645
1645
1646 - "+n" is a linear run of n nodes based on the current default parent
1646 - "+n" is a linear run of n nodes based on the current default parent
1647 - "." is a single node based on the current default parent
1647 - "." is a single node based on the current default parent
1648 - "$" resets the default parent to null (implied at the start);
1648 - "$" resets the default parent to null (implied at the start);
1649 otherwise the default parent is always the last node created
1649 otherwise the default parent is always the last node created
1650 - "<p" sets the default parent to the backref p
1650 - "<p" sets the default parent to the backref p
1651 - "*p" is a fork at parent p, which is a backref
1651 - "*p" is a fork at parent p, which is a backref
1652 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1652 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1653 - "/p2" is a merge of the preceding node and p2
1653 - "/p2" is a merge of the preceding node and p2
1654 - ":tag" defines a local tag for the preceding node
1654 - ":tag" defines a local tag for the preceding node
1655 - "@branch" sets the named branch for subsequent nodes
1655 - "@branch" sets the named branch for subsequent nodes
1656 - "#...\\n" is a comment up to the end of the line
1656 - "#...\\n" is a comment up to the end of the line
1657
1657
1658 Whitespace between the above elements is ignored.
1658 Whitespace between the above elements is ignored.
1659
1659
1660 A backref is either
1660 A backref is either
1661
1661
1662 - a number n, which references the node curr-n, where curr is the current
1662 - a number n, which references the node curr-n, where curr is the current
1663 node, or
1663 node, or
1664 - the name of a local tag you placed earlier using ":tag", or
1664 - the name of a local tag you placed earlier using ":tag", or
1665 - empty to denote the default parent.
1665 - empty to denote the default parent.
1666
1666
1667 All string valued-elements are either strictly alphanumeric, or must
1667 All string valued-elements are either strictly alphanumeric, or must
1668 be enclosed in double quotes ("..."), with "\\" as escape character.
1668 be enclosed in double quotes ("..."), with "\\" as escape character.
1669 """
1669 """
1670
1670
1671 if text is None:
1671 if text is None:
1672 ui.status(_("reading DAG from stdin\n"))
1672 ui.status(_("reading DAG from stdin\n"))
1673 text = ui.fin.read()
1673 text = ui.fin.read()
1674
1674
1675 cl = repo.changelog
1675 cl = repo.changelog
1676 if len(cl) > 0:
1676 if len(cl) > 0:
1677 raise util.Abort(_('repository is not empty'))
1677 raise util.Abort(_('repository is not empty'))
1678
1678
1679 # determine number of revs in DAG
1679 # determine number of revs in DAG
1680 total = 0
1680 total = 0
1681 for type, data in dagparser.parsedag(text):
1681 for type, data in dagparser.parsedag(text):
1682 if type == 'n':
1682 if type == 'n':
1683 total += 1
1683 total += 1
1684
1684
1685 if mergeable_file:
1685 if mergeable_file:
1686 linesperrev = 2
1686 linesperrev = 2
1687 # make a file with k lines per rev
1687 # make a file with k lines per rev
1688 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1688 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1689 initialmergedlines.append("")
1689 initialmergedlines.append("")
1690
1690
1691 tags = []
1691 tags = []
1692
1692
1693 lock = tr = None
1693 lock = tr = None
1694 try:
1694 try:
1695 lock = repo.lock()
1695 lock = repo.lock()
1696 tr = repo.transaction("builddag")
1696 tr = repo.transaction("builddag")
1697
1697
1698 at = -1
1698 at = -1
1699 atbranch = 'default'
1699 atbranch = 'default'
1700 nodeids = []
1700 nodeids = []
1701 id = 0
1701 id = 0
1702 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1702 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1703 for type, data in dagparser.parsedag(text):
1703 for type, data in dagparser.parsedag(text):
1704 if type == 'n':
1704 if type == 'n':
1705 ui.note(('node %s\n' % str(data)))
1705 ui.note(('node %s\n' % str(data)))
1706 id, ps = data
1706 id, ps = data
1707
1707
1708 files = []
1708 files = []
1709 fctxs = {}
1709 fctxs = {}
1710
1710
1711 p2 = None
1711 p2 = None
1712 if mergeable_file:
1712 if mergeable_file:
1713 fn = "mf"
1713 fn = "mf"
1714 p1 = repo[ps[0]]
1714 p1 = repo[ps[0]]
1715 if len(ps) > 1:
1715 if len(ps) > 1:
1716 p2 = repo[ps[1]]
1716 p2 = repo[ps[1]]
1717 pa = p1.ancestor(p2)
1717 pa = p1.ancestor(p2)
1718 base, local, other = [x[fn].data() for x in (pa, p1,
1718 base, local, other = [x[fn].data() for x in (pa, p1,
1719 p2)]
1719 p2)]
1720 m3 = simplemerge.Merge3Text(base, local, other)
1720 m3 = simplemerge.Merge3Text(base, local, other)
1721 ml = [l.strip() for l in m3.merge_lines()]
1721 ml = [l.strip() for l in m3.merge_lines()]
1722 ml.append("")
1722 ml.append("")
1723 elif at > 0:
1723 elif at > 0:
1724 ml = p1[fn].data().split("\n")
1724 ml = p1[fn].data().split("\n")
1725 else:
1725 else:
1726 ml = initialmergedlines
1726 ml = initialmergedlines
1727 ml[id * linesperrev] += " r%i" % id
1727 ml[id * linesperrev] += " r%i" % id
1728 mergedtext = "\n".join(ml)
1728 mergedtext = "\n".join(ml)
1729 files.append(fn)
1729 files.append(fn)
1730 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1730 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1731
1731
1732 if overwritten_file:
1732 if overwritten_file:
1733 fn = "of"
1733 fn = "of"
1734 files.append(fn)
1734 files.append(fn)
1735 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1735 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1736
1736
1737 if new_file:
1737 if new_file:
1738 fn = "nf%i" % id
1738 fn = "nf%i" % id
1739 files.append(fn)
1739 files.append(fn)
1740 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1740 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1741 if len(ps) > 1:
1741 if len(ps) > 1:
1742 if not p2:
1742 if not p2:
1743 p2 = repo[ps[1]]
1743 p2 = repo[ps[1]]
1744 for fn in p2:
1744 for fn in p2:
1745 if fn.startswith("nf"):
1745 if fn.startswith("nf"):
1746 files.append(fn)
1746 files.append(fn)
1747 fctxs[fn] = p2[fn]
1747 fctxs[fn] = p2[fn]
1748
1748
1749 def fctxfn(repo, cx, path):
1749 def fctxfn(repo, cx, path):
1750 return fctxs.get(path)
1750 return fctxs.get(path)
1751
1751
1752 if len(ps) == 0 or ps[0] < 0:
1752 if len(ps) == 0 or ps[0] < 0:
1753 pars = [None, None]
1753 pars = [None, None]
1754 elif len(ps) == 1:
1754 elif len(ps) == 1:
1755 pars = [nodeids[ps[0]], None]
1755 pars = [nodeids[ps[0]], None]
1756 else:
1756 else:
1757 pars = [nodeids[p] for p in ps]
1757 pars = [nodeids[p] for p in ps]
1758 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1758 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1759 date=(id, 0),
1759 date=(id, 0),
1760 user="debugbuilddag",
1760 user="debugbuilddag",
1761 extra={'branch': atbranch})
1761 extra={'branch': atbranch})
1762 nodeid = repo.commitctx(cx)
1762 nodeid = repo.commitctx(cx)
1763 nodeids.append(nodeid)
1763 nodeids.append(nodeid)
1764 at = id
1764 at = id
1765 elif type == 'l':
1765 elif type == 'l':
1766 id, name = data
1766 id, name = data
1767 ui.note(('tag %s\n' % name))
1767 ui.note(('tag %s\n' % name))
1768 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1768 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1769 elif type == 'a':
1769 elif type == 'a':
1770 ui.note(('branch %s\n' % data))
1770 ui.note(('branch %s\n' % data))
1771 atbranch = data
1771 atbranch = data
1772 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1772 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1773 tr.close()
1773 tr.close()
1774
1774
1775 if tags:
1775 if tags:
1776 repo.opener.write("localtags", "".join(tags))
1776 repo.opener.write("localtags", "".join(tags))
1777 finally:
1777 finally:
1778 ui.progress(_('building'), None)
1778 ui.progress(_('building'), None)
1779 release(tr, lock)
1779 release(tr, lock)
1780
1780
1781 @command('debugbundle',
1781 @command('debugbundle',
1782 [('a', 'all', None, _('show all details'))],
1782 [('a', 'all', None, _('show all details'))],
1783 _('FILE'),
1783 _('FILE'),
1784 norepo=True)
1784 norepo=True)
1785 def debugbundle(ui, bundlepath, all=None, **opts):
1785 def debugbundle(ui, bundlepath, all=None, **opts):
1786 """lists the contents of a bundle"""
1786 """lists the contents of a bundle"""
1787 f = hg.openpath(ui, bundlepath)
1787 f = hg.openpath(ui, bundlepath)
1788 try:
1788 try:
1789 gen = exchange.readbundle(ui, f, bundlepath)
1789 gen = exchange.readbundle(ui, f, bundlepath)
1790 if all:
1790 if all:
1791 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1791 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1792
1792
1793 def showchunks(named):
1793 def showchunks(named):
1794 ui.write("\n%s\n" % named)
1794 ui.write("\n%s\n" % named)
1795 chain = None
1795 chain = None
1796 while True:
1796 while True:
1797 chunkdata = gen.deltachunk(chain)
1797 chunkdata = gen.deltachunk(chain)
1798 if not chunkdata:
1798 if not chunkdata:
1799 break
1799 break
1800 node = chunkdata['node']
1800 node = chunkdata['node']
1801 p1 = chunkdata['p1']
1801 p1 = chunkdata['p1']
1802 p2 = chunkdata['p2']
1802 p2 = chunkdata['p2']
1803 cs = chunkdata['cs']
1803 cs = chunkdata['cs']
1804 deltabase = chunkdata['deltabase']
1804 deltabase = chunkdata['deltabase']
1805 delta = chunkdata['delta']
1805 delta = chunkdata['delta']
1806 ui.write("%s %s %s %s %s %s\n" %
1806 ui.write("%s %s %s %s %s %s\n" %
1807 (hex(node), hex(p1), hex(p2),
1807 (hex(node), hex(p1), hex(p2),
1808 hex(cs), hex(deltabase), len(delta)))
1808 hex(cs), hex(deltabase), len(delta)))
1809 chain = node
1809 chain = node
1810
1810
1811 chunkdata = gen.changelogheader()
1811 chunkdata = gen.changelogheader()
1812 showchunks("changelog")
1812 showchunks("changelog")
1813 chunkdata = gen.manifestheader()
1813 chunkdata = gen.manifestheader()
1814 showchunks("manifest")
1814 showchunks("manifest")
1815 while True:
1815 while True:
1816 chunkdata = gen.filelogheader()
1816 chunkdata = gen.filelogheader()
1817 if not chunkdata:
1817 if not chunkdata:
1818 break
1818 break
1819 fname = chunkdata['filename']
1819 fname = chunkdata['filename']
1820 showchunks(fname)
1820 showchunks(fname)
1821 else:
1821 else:
1822 chunkdata = gen.changelogheader()
1822 chunkdata = gen.changelogheader()
1823 chain = None
1823 chain = None
1824 while True:
1824 while True:
1825 chunkdata = gen.deltachunk(chain)
1825 chunkdata = gen.deltachunk(chain)
1826 if not chunkdata:
1826 if not chunkdata:
1827 break
1827 break
1828 node = chunkdata['node']
1828 node = chunkdata['node']
1829 ui.write("%s\n" % hex(node))
1829 ui.write("%s\n" % hex(node))
1830 chain = node
1830 chain = node
1831 finally:
1831 finally:
1832 f.close()
1832 f.close()
1833
1833
1834 @command('debugcheckstate', [], '')
1834 @command('debugcheckstate', [], '')
1835 def debugcheckstate(ui, repo):
1835 def debugcheckstate(ui, repo):
1836 """validate the correctness of the current dirstate"""
1836 """validate the correctness of the current dirstate"""
1837 parent1, parent2 = repo.dirstate.parents()
1837 parent1, parent2 = repo.dirstate.parents()
1838 m1 = repo[parent1].manifest()
1838 m1 = repo[parent1].manifest()
1839 m2 = repo[parent2].manifest()
1839 m2 = repo[parent2].manifest()
1840 errors = 0
1840 errors = 0
1841 for f in repo.dirstate:
1841 for f in repo.dirstate:
1842 state = repo.dirstate[f]
1842 state = repo.dirstate[f]
1843 if state in "nr" and f not in m1:
1843 if state in "nr" and f not in m1:
1844 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1844 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1845 errors += 1
1845 errors += 1
1846 if state in "a" and f in m1:
1846 if state in "a" and f in m1:
1847 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1847 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1848 errors += 1
1848 errors += 1
1849 if state in "m" and f not in m1 and f not in m2:
1849 if state in "m" and f not in m1 and f not in m2:
1850 ui.warn(_("%s in state %s, but not in either manifest\n") %
1850 ui.warn(_("%s in state %s, but not in either manifest\n") %
1851 (f, state))
1851 (f, state))
1852 errors += 1
1852 errors += 1
1853 for f in m1:
1853 for f in m1:
1854 state = repo.dirstate[f]
1854 state = repo.dirstate[f]
1855 if state not in "nrm":
1855 if state not in "nrm":
1856 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1856 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1857 errors += 1
1857 errors += 1
1858 if errors:
1858 if errors:
1859 error = _(".hg/dirstate inconsistent with current parent's manifest")
1859 error = _(".hg/dirstate inconsistent with current parent's manifest")
1860 raise util.Abort(error)
1860 raise util.Abort(error)
1861
1861
1862 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1862 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1863 def debugcommands(ui, cmd='', *args):
1863 def debugcommands(ui, cmd='', *args):
1864 """list all available commands and options"""
1864 """list all available commands and options"""
1865 for cmd, vals in sorted(table.iteritems()):
1865 for cmd, vals in sorted(table.iteritems()):
1866 cmd = cmd.split('|')[0].strip('^')
1866 cmd = cmd.split('|')[0].strip('^')
1867 opts = ', '.join([i[1] for i in vals[1]])
1867 opts = ', '.join([i[1] for i in vals[1]])
1868 ui.write('%s: %s\n' % (cmd, opts))
1868 ui.write('%s: %s\n' % (cmd, opts))
1869
1869
1870 @command('debugcomplete',
1870 @command('debugcomplete',
1871 [('o', 'options', None, _('show the command options'))],
1871 [('o', 'options', None, _('show the command options'))],
1872 _('[-o] CMD'),
1872 _('[-o] CMD'),
1873 norepo=True)
1873 norepo=True)
1874 def debugcomplete(ui, cmd='', **opts):
1874 def debugcomplete(ui, cmd='', **opts):
1875 """returns the completion list associated with the given command"""
1875 """returns the completion list associated with the given command"""
1876
1876
1877 if opts.get('options'):
1877 if opts.get('options'):
1878 options = []
1878 options = []
1879 otables = [globalopts]
1879 otables = [globalopts]
1880 if cmd:
1880 if cmd:
1881 aliases, entry = cmdutil.findcmd(cmd, table, False)
1881 aliases, entry = cmdutil.findcmd(cmd, table, False)
1882 otables.append(entry[1])
1882 otables.append(entry[1])
1883 for t in otables:
1883 for t in otables:
1884 for o in t:
1884 for o in t:
1885 if "(DEPRECATED)" in o[3]:
1885 if "(DEPRECATED)" in o[3]:
1886 continue
1886 continue
1887 if o[0]:
1887 if o[0]:
1888 options.append('-%s' % o[0])
1888 options.append('-%s' % o[0])
1889 options.append('--%s' % o[1])
1889 options.append('--%s' % o[1])
1890 ui.write("%s\n" % "\n".join(options))
1890 ui.write("%s\n" % "\n".join(options))
1891 return
1891 return
1892
1892
1893 cmdlist = cmdutil.findpossible(cmd, table)
1893 cmdlist = cmdutil.findpossible(cmd, table)
1894 if ui.verbose:
1894 if ui.verbose:
1895 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1895 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1896 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1896 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1897
1897
1898 @command('debugdag',
1898 @command('debugdag',
1899 [('t', 'tags', None, _('use tags as labels')),
1899 [('t', 'tags', None, _('use tags as labels')),
1900 ('b', 'branches', None, _('annotate with branch names')),
1900 ('b', 'branches', None, _('annotate with branch names')),
1901 ('', 'dots', None, _('use dots for runs')),
1901 ('', 'dots', None, _('use dots for runs')),
1902 ('s', 'spaces', None, _('separate elements by spaces'))],
1902 ('s', 'spaces', None, _('separate elements by spaces'))],
1903 _('[OPTION]... [FILE [REV]...]'),
1903 _('[OPTION]... [FILE [REV]...]'),
1904 optionalrepo=True)
1904 optionalrepo=True)
1905 def debugdag(ui, repo, file_=None, *revs, **opts):
1905 def debugdag(ui, repo, file_=None, *revs, **opts):
1906 """format the changelog or an index DAG as a concise textual description
1906 """format the changelog or an index DAG as a concise textual description
1907
1907
1908 If you pass a revlog index, the revlog's DAG is emitted. If you list
1908 If you pass a revlog index, the revlog's DAG is emitted. If you list
1909 revision numbers, they get labeled in the output as rN.
1909 revision numbers, they get labeled in the output as rN.
1910
1910
1911 Otherwise, the changelog DAG of the current repo is emitted.
1911 Otherwise, the changelog DAG of the current repo is emitted.
1912 """
1912 """
1913 spaces = opts.get('spaces')
1913 spaces = opts.get('spaces')
1914 dots = opts.get('dots')
1914 dots = opts.get('dots')
1915 if file_:
1915 if file_:
1916 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1916 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1917 revs = set((int(r) for r in revs))
1917 revs = set((int(r) for r in revs))
1918 def events():
1918 def events():
1919 for r in rlog:
1919 for r in rlog:
1920 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1920 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1921 if p != -1))
1921 if p != -1))
1922 if r in revs:
1922 if r in revs:
1923 yield 'l', (r, "r%i" % r)
1923 yield 'l', (r, "r%i" % r)
1924 elif repo:
1924 elif repo:
1925 cl = repo.changelog
1925 cl = repo.changelog
1926 tags = opts.get('tags')
1926 tags = opts.get('tags')
1927 branches = opts.get('branches')
1927 branches = opts.get('branches')
1928 if tags:
1928 if tags:
1929 labels = {}
1929 labels = {}
1930 for l, n in repo.tags().items():
1930 for l, n in repo.tags().items():
1931 labels.setdefault(cl.rev(n), []).append(l)
1931 labels.setdefault(cl.rev(n), []).append(l)
1932 def events():
1932 def events():
1933 b = "default"
1933 b = "default"
1934 for r in cl:
1934 for r in cl:
1935 if branches:
1935 if branches:
1936 newb = cl.read(cl.node(r))[5]['branch']
1936 newb = cl.read(cl.node(r))[5]['branch']
1937 if newb != b:
1937 if newb != b:
1938 yield 'a', newb
1938 yield 'a', newb
1939 b = newb
1939 b = newb
1940 yield 'n', (r, list(p for p in cl.parentrevs(r)
1940 yield 'n', (r, list(p for p in cl.parentrevs(r)
1941 if p != -1))
1941 if p != -1))
1942 if tags:
1942 if tags:
1943 ls = labels.get(r)
1943 ls = labels.get(r)
1944 if ls:
1944 if ls:
1945 for l in ls:
1945 for l in ls:
1946 yield 'l', (r, l)
1946 yield 'l', (r, l)
1947 else:
1947 else:
1948 raise util.Abort(_('need repo for changelog dag'))
1948 raise util.Abort(_('need repo for changelog dag'))
1949
1949
1950 for line in dagparser.dagtextlines(events(),
1950 for line in dagparser.dagtextlines(events(),
1951 addspaces=spaces,
1951 addspaces=spaces,
1952 wraplabels=True,
1952 wraplabels=True,
1953 wrapannotations=True,
1953 wrapannotations=True,
1954 wrapnonlinear=dots,
1954 wrapnonlinear=dots,
1955 usedots=dots,
1955 usedots=dots,
1956 maxlinewidth=70):
1956 maxlinewidth=70):
1957 ui.write(line)
1957 ui.write(line)
1958 ui.write("\n")
1958 ui.write("\n")
1959
1959
1960 @command('debugdata',
1960 @command('debugdata',
1961 [('c', 'changelog', False, _('open changelog')),
1961 [('c', 'changelog', False, _('open changelog')),
1962 ('m', 'manifest', False, _('open manifest'))],
1962 ('m', 'manifest', False, _('open manifest'))],
1963 _('-c|-m|FILE REV'))
1963 _('-c|-m|FILE REV'))
1964 def debugdata(ui, repo, file_, rev=None, **opts):
1964 def debugdata(ui, repo, file_, rev=None, **opts):
1965 """dump the contents of a data file revision"""
1965 """dump the contents of a data file revision"""
1966 if opts.get('changelog') or opts.get('manifest'):
1966 if opts.get('changelog') or opts.get('manifest'):
1967 file_, rev = None, file_
1967 file_, rev = None, file_
1968 elif rev is None:
1968 elif rev is None:
1969 raise error.CommandError('debugdata', _('invalid arguments'))
1969 raise error.CommandError('debugdata', _('invalid arguments'))
1970 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1970 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1971 try:
1971 try:
1972 ui.write(r.revision(r.lookup(rev)))
1972 ui.write(r.revision(r.lookup(rev)))
1973 except KeyError:
1973 except KeyError:
1974 raise util.Abort(_('invalid revision identifier %s') % rev)
1974 raise util.Abort(_('invalid revision identifier %s') % rev)
1975
1975
1976 @command('debugdate',
1976 @command('debugdate',
1977 [('e', 'extended', None, _('try extended date formats'))],
1977 [('e', 'extended', None, _('try extended date formats'))],
1978 _('[-e] DATE [RANGE]'),
1978 _('[-e] DATE [RANGE]'),
1979 norepo=True, optionalrepo=True)
1979 norepo=True, optionalrepo=True)
1980 def debugdate(ui, date, range=None, **opts):
1980 def debugdate(ui, date, range=None, **opts):
1981 """parse and display a date"""
1981 """parse and display a date"""
1982 if opts["extended"]:
1982 if opts["extended"]:
1983 d = util.parsedate(date, util.extendeddateformats)
1983 d = util.parsedate(date, util.extendeddateformats)
1984 else:
1984 else:
1985 d = util.parsedate(date)
1985 d = util.parsedate(date)
1986 ui.write(("internal: %s %s\n") % d)
1986 ui.write(("internal: %s %s\n") % d)
1987 ui.write(("standard: %s\n") % util.datestr(d))
1987 ui.write(("standard: %s\n") % util.datestr(d))
1988 if range:
1988 if range:
1989 m = util.matchdate(range)
1989 m = util.matchdate(range)
1990 ui.write(("match: %s\n") % m(d[0]))
1990 ui.write(("match: %s\n") % m(d[0]))
1991
1991
1992 @command('debugdiscovery',
1992 @command('debugdiscovery',
1993 [('', 'old', None, _('use old-style discovery')),
1993 [('', 'old', None, _('use old-style discovery')),
1994 ('', 'nonheads', None,
1994 ('', 'nonheads', None,
1995 _('use old-style discovery with non-heads included')),
1995 _('use old-style discovery with non-heads included')),
1996 ] + remoteopts,
1996 ] + remoteopts,
1997 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1997 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1998 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1998 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1999 """runs the changeset discovery protocol in isolation"""
1999 """runs the changeset discovery protocol in isolation"""
2000 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2000 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2001 opts.get('branch'))
2001 opts.get('branch'))
2002 remote = hg.peer(repo, opts, remoteurl)
2002 remote = hg.peer(repo, opts, remoteurl)
2003 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2003 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2004
2004
2005 # make sure tests are repeatable
2005 # make sure tests are repeatable
2006 random.seed(12323)
2006 random.seed(12323)
2007
2007
2008 def doit(localheads, remoteheads, remote=remote):
2008 def doit(localheads, remoteheads, remote=remote):
2009 if opts.get('old'):
2009 if opts.get('old'):
2010 if localheads:
2010 if localheads:
2011 raise util.Abort('cannot use localheads with old style '
2011 raise util.Abort('cannot use localheads with old style '
2012 'discovery')
2012 'discovery')
2013 if not util.safehasattr(remote, 'branches'):
2013 if not util.safehasattr(remote, 'branches'):
2014 # enable in-client legacy support
2014 # enable in-client legacy support
2015 remote = localrepo.locallegacypeer(remote.local())
2015 remote = localrepo.locallegacypeer(remote.local())
2016 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2016 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2017 force=True)
2017 force=True)
2018 common = set(common)
2018 common = set(common)
2019 if not opts.get('nonheads'):
2019 if not opts.get('nonheads'):
2020 ui.write(("unpruned common: %s\n") %
2020 ui.write(("unpruned common: %s\n") %
2021 " ".join(sorted(short(n) for n in common)))
2021 " ".join(sorted(short(n) for n in common)))
2022 dag = dagutil.revlogdag(repo.changelog)
2022 dag = dagutil.revlogdag(repo.changelog)
2023 all = dag.ancestorset(dag.internalizeall(common))
2023 all = dag.ancestorset(dag.internalizeall(common))
2024 common = dag.externalizeall(dag.headsetofconnecteds(all))
2024 common = dag.externalizeall(dag.headsetofconnecteds(all))
2025 else:
2025 else:
2026 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2026 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2027 common = set(common)
2027 common = set(common)
2028 rheads = set(hds)
2028 rheads = set(hds)
2029 lheads = set(repo.heads())
2029 lheads = set(repo.heads())
2030 ui.write(("common heads: %s\n") %
2030 ui.write(("common heads: %s\n") %
2031 " ".join(sorted(short(n) for n in common)))
2031 " ".join(sorted(short(n) for n in common)))
2032 if lheads <= common:
2032 if lheads <= common:
2033 ui.write(("local is subset\n"))
2033 ui.write(("local is subset\n"))
2034 elif rheads <= common:
2034 elif rheads <= common:
2035 ui.write(("remote is subset\n"))
2035 ui.write(("remote is subset\n"))
2036
2036
2037 serverlogs = opts.get('serverlog')
2037 serverlogs = opts.get('serverlog')
2038 if serverlogs:
2038 if serverlogs:
2039 for filename in serverlogs:
2039 for filename in serverlogs:
2040 logfile = open(filename, 'r')
2040 logfile = open(filename, 'r')
2041 try:
2041 try:
2042 line = logfile.readline()
2042 line = logfile.readline()
2043 while line:
2043 while line:
2044 parts = line.strip().split(';')
2044 parts = line.strip().split(';')
2045 op = parts[1]
2045 op = parts[1]
2046 if op == 'cg':
2046 if op == 'cg':
2047 pass
2047 pass
2048 elif op == 'cgss':
2048 elif op == 'cgss':
2049 doit(parts[2].split(' '), parts[3].split(' '))
2049 doit(parts[2].split(' '), parts[3].split(' '))
2050 elif op == 'unb':
2050 elif op == 'unb':
2051 doit(parts[3].split(' '), parts[2].split(' '))
2051 doit(parts[3].split(' '), parts[2].split(' '))
2052 line = logfile.readline()
2052 line = logfile.readline()
2053 finally:
2053 finally:
2054 logfile.close()
2054 logfile.close()
2055
2055
2056 else:
2056 else:
2057 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2057 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2058 opts.get('remote_head'))
2058 opts.get('remote_head'))
2059 localrevs = opts.get('local_head')
2059 localrevs = opts.get('local_head')
2060 doit(localrevs, remoterevs)
2060 doit(localrevs, remoterevs)
2061
2061
2062 @command('debugfileset',
2062 @command('debugfileset',
2063 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2063 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2064 _('[-r REV] FILESPEC'))
2064 _('[-r REV] FILESPEC'))
2065 def debugfileset(ui, repo, expr, **opts):
2065 def debugfileset(ui, repo, expr, **opts):
2066 '''parse and apply a fileset specification'''
2066 '''parse and apply a fileset specification'''
2067 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2067 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2068 if ui.verbose:
2068 if ui.verbose:
2069 tree = fileset.parse(expr)[0]
2069 tree = fileset.parse(expr)[0]
2070 ui.note(tree, "\n")
2070 ui.note(tree, "\n")
2071
2071
2072 for f in ctx.getfileset(expr):
2072 for f in ctx.getfileset(expr):
2073 ui.write("%s\n" % f)
2073 ui.write("%s\n" % f)
2074
2074
2075 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2075 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2076 def debugfsinfo(ui, path="."):
2076 def debugfsinfo(ui, path="."):
2077 """show information detected about current filesystem"""
2077 """show information detected about current filesystem"""
2078 util.writefile('.debugfsinfo', '')
2078 util.writefile('.debugfsinfo', '')
2079 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2079 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2080 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2080 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2081 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2081 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2082 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2082 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2083 and 'yes' or 'no'))
2083 and 'yes' or 'no'))
2084 os.unlink('.debugfsinfo')
2084 os.unlink('.debugfsinfo')
2085
2085
2086 @command('debuggetbundle',
2086 @command('debuggetbundle',
2087 [('H', 'head', [], _('id of head node'), _('ID')),
2087 [('H', 'head', [], _('id of head node'), _('ID')),
2088 ('C', 'common', [], _('id of common node'), _('ID')),
2088 ('C', 'common', [], _('id of common node'), _('ID')),
2089 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2089 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2090 _('REPO FILE [-H|-C ID]...'),
2090 _('REPO FILE [-H|-C ID]...'),
2091 norepo=True)
2091 norepo=True)
2092 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2092 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2093 """retrieves a bundle from a repo
2093 """retrieves a bundle from a repo
2094
2094
2095 Every ID must be a full-length hex node id string. Saves the bundle to the
2095 Every ID must be a full-length hex node id string. Saves the bundle to the
2096 given file.
2096 given file.
2097 """
2097 """
2098 repo = hg.peer(ui, opts, repopath)
2098 repo = hg.peer(ui, opts, repopath)
2099 if not repo.capable('getbundle'):
2099 if not repo.capable('getbundle'):
2100 raise util.Abort("getbundle() not supported by target repository")
2100 raise util.Abort("getbundle() not supported by target repository")
2101 args = {}
2101 args = {}
2102 if common:
2102 if common:
2103 args['common'] = [bin(s) for s in common]
2103 args['common'] = [bin(s) for s in common]
2104 if head:
2104 if head:
2105 args['heads'] = [bin(s) for s in head]
2105 args['heads'] = [bin(s) for s in head]
2106 # TODO: get desired bundlecaps from command line.
2106 # TODO: get desired bundlecaps from command line.
2107 args['bundlecaps'] = None
2107 args['bundlecaps'] = None
2108 bundle = repo.getbundle('debug', **args)
2108 bundle = repo.getbundle('debug', **args)
2109
2109
2110 bundletype = opts.get('type', 'bzip2').lower()
2110 bundletype = opts.get('type', 'bzip2').lower()
2111 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2111 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2112 bundletype = btypes.get(bundletype)
2112 bundletype = btypes.get(bundletype)
2113 if bundletype not in changegroup.bundletypes:
2113 if bundletype not in changegroup.bundletypes:
2114 raise util.Abort(_('unknown bundle type specified with --type'))
2114 raise util.Abort(_('unknown bundle type specified with --type'))
2115 changegroup.writebundle(bundle, bundlepath, bundletype)
2115 changegroup.writebundle(bundle, bundlepath, bundletype)
2116
2116
2117 @command('debugignore', [], '')
2117 @command('debugignore', [], '')
2118 def debugignore(ui, repo, *values, **opts):
2118 def debugignore(ui, repo, *values, **opts):
2119 """display the combined ignore pattern"""
2119 """display the combined ignore pattern"""
2120 ignore = repo.dirstate._ignore
2120 ignore = repo.dirstate._ignore
2121 includepat = getattr(ignore, 'includepat', None)
2121 includepat = getattr(ignore, 'includepat', None)
2122 if includepat is not None:
2122 if includepat is not None:
2123 ui.write("%s\n" % includepat)
2123 ui.write("%s\n" % includepat)
2124 else:
2124 else:
2125 raise util.Abort(_("no ignore patterns found"))
2125 raise util.Abort(_("no ignore patterns found"))
2126
2126
2127 @command('debugindex',
2127 @command('debugindex',
2128 [('c', 'changelog', False, _('open changelog')),
2128 [('c', 'changelog', False, _('open changelog')),
2129 ('m', 'manifest', False, _('open manifest')),
2129 ('m', 'manifest', False, _('open manifest')),
2130 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2130 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2131 _('[-f FORMAT] -c|-m|FILE'),
2131 _('[-f FORMAT] -c|-m|FILE'),
2132 optionalrepo=True)
2132 optionalrepo=True)
2133 def debugindex(ui, repo, file_=None, **opts):
2133 def debugindex(ui, repo, file_=None, **opts):
2134 """dump the contents of an index file"""
2134 """dump the contents of an index file"""
2135 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2135 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2136 format = opts.get('format', 0)
2136 format = opts.get('format', 0)
2137 if format not in (0, 1):
2137 if format not in (0, 1):
2138 raise util.Abort(_("unknown format %d") % format)
2138 raise util.Abort(_("unknown format %d") % format)
2139
2139
2140 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2140 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2141 if generaldelta:
2141 if generaldelta:
2142 basehdr = ' delta'
2142 basehdr = ' delta'
2143 else:
2143 else:
2144 basehdr = ' base'
2144 basehdr = ' base'
2145
2145
2146 if format == 0:
2146 if format == 0:
2147 ui.write(" rev offset length " + basehdr + " linkrev"
2147 ui.write(" rev offset length " + basehdr + " linkrev"
2148 " nodeid p1 p2\n")
2148 " nodeid p1 p2\n")
2149 elif format == 1:
2149 elif format == 1:
2150 ui.write(" rev flag offset length"
2150 ui.write(" rev flag offset length"
2151 " size " + basehdr + " link p1 p2"
2151 " size " + basehdr + " link p1 p2"
2152 " nodeid\n")
2152 " nodeid\n")
2153
2153
2154 for i in r:
2154 for i in r:
2155 node = r.node(i)
2155 node = r.node(i)
2156 if generaldelta:
2156 if generaldelta:
2157 base = r.deltaparent(i)
2157 base = r.deltaparent(i)
2158 else:
2158 else:
2159 base = r.chainbase(i)
2159 base = r.chainbase(i)
2160 if format == 0:
2160 if format == 0:
2161 try:
2161 try:
2162 pp = r.parents(node)
2162 pp = r.parents(node)
2163 except Exception:
2163 except Exception:
2164 pp = [nullid, nullid]
2164 pp = [nullid, nullid]
2165 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2165 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2166 i, r.start(i), r.length(i), base, r.linkrev(i),
2166 i, r.start(i), r.length(i), base, r.linkrev(i),
2167 short(node), short(pp[0]), short(pp[1])))
2167 short(node), short(pp[0]), short(pp[1])))
2168 elif format == 1:
2168 elif format == 1:
2169 pr = r.parentrevs(i)
2169 pr = r.parentrevs(i)
2170 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2170 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2171 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2171 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2172 base, r.linkrev(i), pr[0], pr[1], short(node)))
2172 base, r.linkrev(i), pr[0], pr[1], short(node)))
2173
2173
2174 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2174 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2175 def debugindexdot(ui, repo, file_):
2175 def debugindexdot(ui, repo, file_):
2176 """dump an index DAG as a graphviz dot file"""
2176 """dump an index DAG as a graphviz dot file"""
2177 r = None
2177 r = None
2178 if repo:
2178 if repo:
2179 filelog = repo.file(file_)
2179 filelog = repo.file(file_)
2180 if len(filelog):
2180 if len(filelog):
2181 r = filelog
2181 r = filelog
2182 if not r:
2182 if not r:
2183 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2183 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2184 ui.write(("digraph G {\n"))
2184 ui.write(("digraph G {\n"))
2185 for i in r:
2185 for i in r:
2186 node = r.node(i)
2186 node = r.node(i)
2187 pp = r.parents(node)
2187 pp = r.parents(node)
2188 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2188 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2189 if pp[1] != nullid:
2189 if pp[1] != nullid:
2190 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2190 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2191 ui.write("}\n")
2191 ui.write("}\n")
2192
2192
2193 @command('debuginstall', [], '', norepo=True)
2193 @command('debuginstall', [], '', norepo=True)
2194 def debuginstall(ui):
2194 def debuginstall(ui):
2195 '''test Mercurial installation
2195 '''test Mercurial installation
2196
2196
2197 Returns 0 on success.
2197 Returns 0 on success.
2198 '''
2198 '''
2199
2199
2200 def writetemp(contents):
2200 def writetemp(contents):
2201 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2201 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2202 f = os.fdopen(fd, "wb")
2202 f = os.fdopen(fd, "wb")
2203 f.write(contents)
2203 f.write(contents)
2204 f.close()
2204 f.close()
2205 return name
2205 return name
2206
2206
2207 problems = 0
2207 problems = 0
2208
2208
2209 # encoding
2209 # encoding
2210 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2210 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2211 try:
2211 try:
2212 encoding.fromlocal("test")
2212 encoding.fromlocal("test")
2213 except util.Abort, inst:
2213 except util.Abort, inst:
2214 ui.write(" %s\n" % inst)
2214 ui.write(" %s\n" % inst)
2215 ui.write(_(" (check that your locale is properly set)\n"))
2215 ui.write(_(" (check that your locale is properly set)\n"))
2216 problems += 1
2216 problems += 1
2217
2217
2218 # Python
2218 # Python
2219 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2219 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2220 ui.status(_("checking Python version (%s)\n")
2220 ui.status(_("checking Python version (%s)\n")
2221 % ("%s.%s.%s" % sys.version_info[:3]))
2221 % ("%s.%s.%s" % sys.version_info[:3]))
2222 ui.status(_("checking Python lib (%s)...\n")
2222 ui.status(_("checking Python lib (%s)...\n")
2223 % os.path.dirname(os.__file__))
2223 % os.path.dirname(os.__file__))
2224
2224
2225 # compiled modules
2225 # compiled modules
2226 ui.status(_("checking installed modules (%s)...\n")
2226 ui.status(_("checking installed modules (%s)...\n")
2227 % os.path.dirname(__file__))
2227 % os.path.dirname(__file__))
2228 try:
2228 try:
2229 import bdiff, mpatch, base85, osutil
2229 import bdiff, mpatch, base85, osutil
2230 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2230 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2231 except Exception, inst:
2231 except Exception, inst:
2232 ui.write(" %s\n" % inst)
2232 ui.write(" %s\n" % inst)
2233 ui.write(_(" One or more extensions could not be found"))
2233 ui.write(_(" One or more extensions could not be found"))
2234 ui.write(_(" (check that you compiled the extensions)\n"))
2234 ui.write(_(" (check that you compiled the extensions)\n"))
2235 problems += 1
2235 problems += 1
2236
2236
2237 # templates
2237 # templates
2238 import templater
2238 import templater
2239 p = templater.templatepath()
2239 p = templater.templatepath()
2240 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2240 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2241 if p:
2241 if p:
2242 m = templater.templatepath("map-cmdline.default")
2242 m = templater.templatepath("map-cmdline.default")
2243 if m:
2243 if m:
2244 # template found, check if it is working
2244 # template found, check if it is working
2245 try:
2245 try:
2246 templater.templater(m)
2246 templater.templater(m)
2247 except Exception, inst:
2247 except Exception, inst:
2248 ui.write(" %s\n" % inst)
2248 ui.write(" %s\n" % inst)
2249 p = None
2249 p = None
2250 else:
2250 else:
2251 ui.write(_(" template 'default' not found\n"))
2251 ui.write(_(" template 'default' not found\n"))
2252 p = None
2252 p = None
2253 else:
2253 else:
2254 ui.write(_(" no template directories found\n"))
2254 ui.write(_(" no template directories found\n"))
2255 if not p:
2255 if not p:
2256 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2256 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2257 problems += 1
2257 problems += 1
2258
2258
2259 # editor
2259 # editor
2260 ui.status(_("checking commit editor...\n"))
2260 ui.status(_("checking commit editor...\n"))
2261 editor = ui.geteditor()
2261 editor = ui.geteditor()
2262 cmdpath = util.findexe(shlex.split(editor)[0])
2262 cmdpath = util.findexe(shlex.split(editor)[0])
2263 if not cmdpath:
2263 if not cmdpath:
2264 if editor == 'vi':
2264 if editor == 'vi':
2265 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2265 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2266 ui.write(_(" (specify a commit editor in your configuration"
2266 ui.write(_(" (specify a commit editor in your configuration"
2267 " file)\n"))
2267 " file)\n"))
2268 else:
2268 else:
2269 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2269 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2270 ui.write(_(" (specify a commit editor in your configuration"
2270 ui.write(_(" (specify a commit editor in your configuration"
2271 " file)\n"))
2271 " file)\n"))
2272 problems += 1
2272 problems += 1
2273
2273
2274 # check username
2274 # check username
2275 ui.status(_("checking username...\n"))
2275 ui.status(_("checking username...\n"))
2276 try:
2276 try:
2277 ui.username()
2277 ui.username()
2278 except util.Abort, e:
2278 except util.Abort, e:
2279 ui.write(" %s\n" % e)
2279 ui.write(" %s\n" % e)
2280 ui.write(_(" (specify a username in your configuration file)\n"))
2280 ui.write(_(" (specify a username in your configuration file)\n"))
2281 problems += 1
2281 problems += 1
2282
2282
2283 if not problems:
2283 if not problems:
2284 ui.status(_("no problems detected\n"))
2284 ui.status(_("no problems detected\n"))
2285 else:
2285 else:
2286 ui.write(_("%s problems detected,"
2286 ui.write(_("%s problems detected,"
2287 " please check your install!\n") % problems)
2287 " please check your install!\n") % problems)
2288
2288
2289 return problems
2289 return problems
2290
2290
2291 @command('debugknown', [], _('REPO ID...'), norepo=True)
2291 @command('debugknown', [], _('REPO ID...'), norepo=True)
2292 def debugknown(ui, repopath, *ids, **opts):
2292 def debugknown(ui, repopath, *ids, **opts):
2293 """test whether node ids are known to a repo
2293 """test whether node ids are known to a repo
2294
2294
2295 Every ID must be a full-length hex node id string. Returns a list of 0s
2295 Every ID must be a full-length hex node id string. Returns a list of 0s
2296 and 1s indicating unknown/known.
2296 and 1s indicating unknown/known.
2297 """
2297 """
2298 repo = hg.peer(ui, opts, repopath)
2298 repo = hg.peer(ui, opts, repopath)
2299 if not repo.capable('known'):
2299 if not repo.capable('known'):
2300 raise util.Abort("known() not supported by target repository")
2300 raise util.Abort("known() not supported by target repository")
2301 flags = repo.known([bin(s) for s in ids])
2301 flags = repo.known([bin(s) for s in ids])
2302 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2302 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2303
2303
2304 @command('debuglabelcomplete', [], _('LABEL...'))
2304 @command('debuglabelcomplete', [], _('LABEL...'))
2305 def debuglabelcomplete(ui, repo, *args):
2305 def debuglabelcomplete(ui, repo, *args):
2306 '''complete "labels" - tags, open branch names, bookmark names'''
2306 '''complete "labels" - tags, open branch names, bookmark names'''
2307
2307
2308 labels = set()
2308 labels = set()
2309 labels.update(t[0] for t in repo.tagslist())
2309 labels.update(t[0] for t in repo.tagslist())
2310 labels.update(repo._bookmarks.keys())
2310 labels.update(repo._bookmarks.keys())
2311 labels.update(tag for (tag, heads, tip, closed)
2311 labels.update(tag for (tag, heads, tip, closed)
2312 in repo.branchmap().iterbranches() if not closed)
2312 in repo.branchmap().iterbranches() if not closed)
2313 completions = set()
2313 completions = set()
2314 if not args:
2314 if not args:
2315 args = ['']
2315 args = ['']
2316 for a in args:
2316 for a in args:
2317 completions.update(l for l in labels if l.startswith(a))
2317 completions.update(l for l in labels if l.startswith(a))
2318 ui.write('\n'.join(sorted(completions)))
2318 ui.write('\n'.join(sorted(completions)))
2319 ui.write('\n')
2319 ui.write('\n')
2320
2320
2321 @command('debugobsolete',
2321 @command('debugobsolete',
2322 [('', 'flags', 0, _('markers flag')),
2322 [('', 'flags', 0, _('markers flag')),
2323 ('', 'record-parents', False,
2323 ('', 'record-parents', False,
2324 _('record parent information for the precursor')),
2324 _('record parent information for the precursor')),
2325 ('r', 'rev', [], _('display markers relevant to REV')),
2325 ('r', 'rev', [], _('display markers relevant to REV')),
2326 ] + commitopts2,
2326 ] + commitopts2,
2327 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2327 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2328 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2328 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2329 """create arbitrary obsolete marker
2329 """create arbitrary obsolete marker
2330
2330
2331 With no arguments, displays the list of obsolescence markers."""
2331 With no arguments, displays the list of obsolescence markers."""
2332
2332
2333 def parsenodeid(s):
2333 def parsenodeid(s):
2334 try:
2334 try:
2335 # We do not use revsingle/revrange functions here to accept
2335 # We do not use revsingle/revrange functions here to accept
2336 # arbitrary node identifiers, possibly not present in the
2336 # arbitrary node identifiers, possibly not present in the
2337 # local repository.
2337 # local repository.
2338 n = bin(s)
2338 n = bin(s)
2339 if len(n) != len(nullid):
2339 if len(n) != len(nullid):
2340 raise TypeError()
2340 raise TypeError()
2341 return n
2341 return n
2342 except TypeError:
2342 except TypeError:
2343 raise util.Abort('changeset references must be full hexadecimal '
2343 raise util.Abort('changeset references must be full hexadecimal '
2344 'node identifiers')
2344 'node identifiers')
2345
2345
2346 if precursor is not None:
2346 if precursor is not None:
2347 if opts['rev']:
2347 if opts['rev']:
2348 raise util.Abort('cannot select revision when creating marker')
2348 raise util.Abort('cannot select revision when creating marker')
2349 metadata = {}
2349 metadata = {}
2350 metadata['user'] = opts['user'] or ui.username()
2350 metadata['user'] = opts['user'] or ui.username()
2351 succs = tuple(parsenodeid(succ) for succ in successors)
2351 succs = tuple(parsenodeid(succ) for succ in successors)
2352 l = repo.lock()
2352 l = repo.lock()
2353 try:
2353 try:
2354 tr = repo.transaction('debugobsolete')
2354 tr = repo.transaction('debugobsolete')
2355 try:
2355 try:
2356 try:
2356 try:
2357 date = opts.get('date')
2357 date = opts.get('date')
2358 if date:
2358 if date:
2359 date = util.parsedate(date)
2359 date = util.parsedate(date)
2360 else:
2360 else:
2361 date = None
2361 date = None
2362 prec = parsenodeid(precursor)
2362 prec = parsenodeid(precursor)
2363 parents = None
2363 parents = None
2364 if opts['record_parents']:
2364 if opts['record_parents']:
2365 if prec not in repo.unfiltered():
2365 if prec not in repo.unfiltered():
2366 raise util.Abort('cannot used --record-parents on '
2366 raise util.Abort('cannot used --record-parents on '
2367 'unknown changesets')
2367 'unknown changesets')
2368 parents = repo.unfiltered()[prec].parents()
2368 parents = repo.unfiltered()[prec].parents()
2369 parents = tuple(p.node() for p in parents)
2369 parents = tuple(p.node() for p in parents)
2370 repo.obsstore.create(tr, prec, succs, opts['flags'],
2370 repo.obsstore.create(tr, prec, succs, opts['flags'],
2371 parents=parents, date=date,
2371 parents=parents, date=date,
2372 metadata=metadata)
2372 metadata=metadata)
2373 tr.close()
2373 tr.close()
2374 except ValueError, exc:
2374 except ValueError, exc:
2375 raise util.Abort(_('bad obsmarker input: %s') % exc)
2375 raise util.Abort(_('bad obsmarker input: %s') % exc)
2376 finally:
2376 finally:
2377 tr.release()
2377 tr.release()
2378 finally:
2378 finally:
2379 l.release()
2379 l.release()
2380 else:
2380 else:
2381 if opts['rev']:
2381 if opts['rev']:
2382 revs = scmutil.revrange(repo, opts['rev'])
2382 revs = scmutil.revrange(repo, opts['rev'])
2383 nodes = [repo[r].node() for r in revs]
2383 nodes = [repo[r].node() for r in revs]
2384 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2384 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2385 markers.sort(key=lambda x: x._data)
2385 markers.sort(key=lambda x: x._data)
2386 else:
2386 else:
2387 markers = obsolete.getmarkers(repo)
2387 markers = obsolete.getmarkers(repo)
2388
2388
2389 for m in markers:
2389 for m in markers:
2390 cmdutil.showmarker(ui, m)
2390 cmdutil.showmarker(ui, m)
2391
2391
2392 @command('debugpathcomplete',
2392 @command('debugpathcomplete',
2393 [('f', 'full', None, _('complete an entire path')),
2393 [('f', 'full', None, _('complete an entire path')),
2394 ('n', 'normal', None, _('show only normal files')),
2394 ('n', 'normal', None, _('show only normal files')),
2395 ('a', 'added', None, _('show only added files')),
2395 ('a', 'added', None, _('show only added files')),
2396 ('r', 'removed', None, _('show only removed files'))],
2396 ('r', 'removed', None, _('show only removed files'))],
2397 _('FILESPEC...'))
2397 _('FILESPEC...'))
2398 def debugpathcomplete(ui, repo, *specs, **opts):
2398 def debugpathcomplete(ui, repo, *specs, **opts):
2399 '''complete part or all of a tracked path
2399 '''complete part or all of a tracked path
2400
2400
2401 This command supports shells that offer path name completion. It
2401 This command supports shells that offer path name completion. It
2402 currently completes only files already known to the dirstate.
2402 currently completes only files already known to the dirstate.
2403
2403
2404 Completion extends only to the next path segment unless
2404 Completion extends only to the next path segment unless
2405 --full is specified, in which case entire paths are used.'''
2405 --full is specified, in which case entire paths are used.'''
2406
2406
2407 def complete(path, acceptable):
2407 def complete(path, acceptable):
2408 dirstate = repo.dirstate
2408 dirstate = repo.dirstate
2409 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2409 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2410 rootdir = repo.root + os.sep
2410 rootdir = repo.root + os.sep
2411 if spec != repo.root and not spec.startswith(rootdir):
2411 if spec != repo.root and not spec.startswith(rootdir):
2412 return [], []
2412 return [], []
2413 if os.path.isdir(spec):
2413 if os.path.isdir(spec):
2414 spec += '/'
2414 spec += '/'
2415 spec = spec[len(rootdir):]
2415 spec = spec[len(rootdir):]
2416 fixpaths = os.sep != '/'
2416 fixpaths = os.sep != '/'
2417 if fixpaths:
2417 if fixpaths:
2418 spec = spec.replace(os.sep, '/')
2418 spec = spec.replace(os.sep, '/')
2419 speclen = len(spec)
2419 speclen = len(spec)
2420 fullpaths = opts['full']
2420 fullpaths = opts['full']
2421 files, dirs = set(), set()
2421 files, dirs = set(), set()
2422 adddir, addfile = dirs.add, files.add
2422 adddir, addfile = dirs.add, files.add
2423 for f, st in dirstate.iteritems():
2423 for f, st in dirstate.iteritems():
2424 if f.startswith(spec) and st[0] in acceptable:
2424 if f.startswith(spec) and st[0] in acceptable:
2425 if fixpaths:
2425 if fixpaths:
2426 f = f.replace('/', os.sep)
2426 f = f.replace('/', os.sep)
2427 if fullpaths:
2427 if fullpaths:
2428 addfile(f)
2428 addfile(f)
2429 continue
2429 continue
2430 s = f.find(os.sep, speclen)
2430 s = f.find(os.sep, speclen)
2431 if s >= 0:
2431 if s >= 0:
2432 adddir(f[:s])
2432 adddir(f[:s])
2433 else:
2433 else:
2434 addfile(f)
2434 addfile(f)
2435 return files, dirs
2435 return files, dirs
2436
2436
2437 acceptable = ''
2437 acceptable = ''
2438 if opts['normal']:
2438 if opts['normal']:
2439 acceptable += 'nm'
2439 acceptable += 'nm'
2440 if opts['added']:
2440 if opts['added']:
2441 acceptable += 'a'
2441 acceptable += 'a'
2442 if opts['removed']:
2442 if opts['removed']:
2443 acceptable += 'r'
2443 acceptable += 'r'
2444 cwd = repo.getcwd()
2444 cwd = repo.getcwd()
2445 if not specs:
2445 if not specs:
2446 specs = ['.']
2446 specs = ['.']
2447
2447
2448 files, dirs = set(), set()
2448 files, dirs = set(), set()
2449 for spec in specs:
2449 for spec in specs:
2450 f, d = complete(spec, acceptable or 'nmar')
2450 f, d = complete(spec, acceptable or 'nmar')
2451 files.update(f)
2451 files.update(f)
2452 dirs.update(d)
2452 dirs.update(d)
2453 files.update(dirs)
2453 files.update(dirs)
2454 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2454 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2455 ui.write('\n')
2455 ui.write('\n')
2456
2456
2457 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2457 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2458 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2458 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2459 '''access the pushkey key/value protocol
2459 '''access the pushkey key/value protocol
2460
2460
2461 With two args, list the keys in the given namespace.
2461 With two args, list the keys in the given namespace.
2462
2462
2463 With five args, set a key to new if it currently is set to old.
2463 With five args, set a key to new if it currently is set to old.
2464 Reports success or failure.
2464 Reports success or failure.
2465 '''
2465 '''
2466
2466
2467 target = hg.peer(ui, {}, repopath)
2467 target = hg.peer(ui, {}, repopath)
2468 if keyinfo:
2468 if keyinfo:
2469 key, old, new = keyinfo
2469 key, old, new = keyinfo
2470 r = target.pushkey(namespace, key, old, new)
2470 r = target.pushkey(namespace, key, old, new)
2471 ui.status(str(r) + '\n')
2471 ui.status(str(r) + '\n')
2472 return not r
2472 return not r
2473 else:
2473 else:
2474 for k, v in sorted(target.listkeys(namespace).iteritems()):
2474 for k, v in sorted(target.listkeys(namespace).iteritems()):
2475 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2475 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2476 v.encode('string-escape')))
2476 v.encode('string-escape')))
2477
2477
2478 @command('debugpvec', [], _('A B'))
2478 @command('debugpvec', [], _('A B'))
2479 def debugpvec(ui, repo, a, b=None):
2479 def debugpvec(ui, repo, a, b=None):
2480 ca = scmutil.revsingle(repo, a)
2480 ca = scmutil.revsingle(repo, a)
2481 cb = scmutil.revsingle(repo, b)
2481 cb = scmutil.revsingle(repo, b)
2482 pa = pvec.ctxpvec(ca)
2482 pa = pvec.ctxpvec(ca)
2483 pb = pvec.ctxpvec(cb)
2483 pb = pvec.ctxpvec(cb)
2484 if pa == pb:
2484 if pa == pb:
2485 rel = "="
2485 rel = "="
2486 elif pa > pb:
2486 elif pa > pb:
2487 rel = ">"
2487 rel = ">"
2488 elif pa < pb:
2488 elif pa < pb:
2489 rel = "<"
2489 rel = "<"
2490 elif pa | pb:
2490 elif pa | pb:
2491 rel = "|"
2491 rel = "|"
2492 ui.write(_("a: %s\n") % pa)
2492 ui.write(_("a: %s\n") % pa)
2493 ui.write(_("b: %s\n") % pb)
2493 ui.write(_("b: %s\n") % pb)
2494 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2494 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2495 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2495 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2496 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2496 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2497 pa.distance(pb), rel))
2497 pa.distance(pb), rel))
2498
2498
2499 @command('debugrebuilddirstate|debugrebuildstate',
2499 @command('debugrebuilddirstate|debugrebuildstate',
2500 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2500 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2501 _('[-r REV]'))
2501 _('[-r REV]'))
2502 def debugrebuilddirstate(ui, repo, rev):
2502 def debugrebuilddirstate(ui, repo, rev):
2503 """rebuild the dirstate as it would look like for the given revision
2503 """rebuild the dirstate as it would look like for the given revision
2504
2504
2505 If no revision is specified the first current parent will be used.
2505 If no revision is specified the first current parent will be used.
2506
2506
2507 The dirstate will be set to the files of the given revision.
2507 The dirstate will be set to the files of the given revision.
2508 The actual working directory content or existing dirstate
2508 The actual working directory content or existing dirstate
2509 information such as adds or removes is not considered.
2509 information such as adds or removes is not considered.
2510
2510
2511 One use of this command is to make the next :hg:`status` invocation
2511 One use of this command is to make the next :hg:`status` invocation
2512 check the actual file content.
2512 check the actual file content.
2513 """
2513 """
2514 ctx = scmutil.revsingle(repo, rev)
2514 ctx = scmutil.revsingle(repo, rev)
2515 wlock = repo.wlock()
2515 wlock = repo.wlock()
2516 try:
2516 try:
2517 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2517 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2518 finally:
2518 finally:
2519 wlock.release()
2519 wlock.release()
2520
2520
2521 @command('debugrename',
2521 @command('debugrename',
2522 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2522 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2523 _('[-r REV] FILE'))
2523 _('[-r REV] FILE'))
2524 def debugrename(ui, repo, file1, *pats, **opts):
2524 def debugrename(ui, repo, file1, *pats, **opts):
2525 """dump rename information"""
2525 """dump rename information"""
2526
2526
2527 ctx = scmutil.revsingle(repo, opts.get('rev'))
2527 ctx = scmutil.revsingle(repo, opts.get('rev'))
2528 m = scmutil.match(ctx, (file1,) + pats, opts)
2528 m = scmutil.match(ctx, (file1,) + pats, opts)
2529 for abs in ctx.walk(m):
2529 for abs in ctx.walk(m):
2530 fctx = ctx[abs]
2530 fctx = ctx[abs]
2531 o = fctx.filelog().renamed(fctx.filenode())
2531 o = fctx.filelog().renamed(fctx.filenode())
2532 rel = m.rel(abs)
2532 rel = m.rel(abs)
2533 if o:
2533 if o:
2534 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2534 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2535 else:
2535 else:
2536 ui.write(_("%s not renamed\n") % rel)
2536 ui.write(_("%s not renamed\n") % rel)
2537
2537
2538 @command('debugrevlog',
2538 @command('debugrevlog',
2539 [('c', 'changelog', False, _('open changelog')),
2539 [('c', 'changelog', False, _('open changelog')),
2540 ('m', 'manifest', False, _('open manifest')),
2540 ('m', 'manifest', False, _('open manifest')),
2541 ('d', 'dump', False, _('dump index data'))],
2541 ('d', 'dump', False, _('dump index data'))],
2542 _('-c|-m|FILE'),
2542 _('-c|-m|FILE'),
2543 optionalrepo=True)
2543 optionalrepo=True)
2544 def debugrevlog(ui, repo, file_=None, **opts):
2544 def debugrevlog(ui, repo, file_=None, **opts):
2545 """show data and statistics about a revlog"""
2545 """show data and statistics about a revlog"""
2546 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2546 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2547
2547
2548 if opts.get("dump"):
2548 if opts.get("dump"):
2549 numrevs = len(r)
2549 numrevs = len(r)
2550 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2550 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2551 " rawsize totalsize compression heads chainlen\n")
2551 " rawsize totalsize compression heads chainlen\n")
2552 ts = 0
2552 ts = 0
2553 heads = set()
2553 heads = set()
2554 rindex = r.index
2554 rindex = r.index
2555
2555
2556 def chainbaseandlen(rev):
2556 def chainbaseandlen(rev):
2557 clen = 0
2557 clen = 0
2558 base = rindex[rev][3]
2558 base = rindex[rev][3]
2559 while base != rev:
2559 while base != rev:
2560 clen += 1
2560 clen += 1
2561 rev = base
2561 rev = base
2562 base = rindex[rev][3]
2562 base = rindex[rev][3]
2563 return base, clen
2563 return base, clen
2564
2564
2565 for rev in xrange(numrevs):
2565 for rev in xrange(numrevs):
2566 dbase = r.deltaparent(rev)
2566 dbase = r.deltaparent(rev)
2567 if dbase == -1:
2567 if dbase == -1:
2568 dbase = rev
2568 dbase = rev
2569 cbase, clen = chainbaseandlen(rev)
2569 cbase, clen = chainbaseandlen(rev)
2570 p1, p2 = r.parentrevs(rev)
2570 p1, p2 = r.parentrevs(rev)
2571 rs = r.rawsize(rev)
2571 rs = r.rawsize(rev)
2572 ts = ts + rs
2572 ts = ts + rs
2573 heads -= set(r.parentrevs(rev))
2573 heads -= set(r.parentrevs(rev))
2574 heads.add(rev)
2574 heads.add(rev)
2575 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2575 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2576 "%11d %5d %8d\n" %
2576 "%11d %5d %8d\n" %
2577 (rev, p1, p2, r.start(rev), r.end(rev),
2577 (rev, p1, p2, r.start(rev), r.end(rev),
2578 r.start(dbase), r.start(cbase),
2578 r.start(dbase), r.start(cbase),
2579 r.start(p1), r.start(p2),
2579 r.start(p1), r.start(p2),
2580 rs, ts, ts / r.end(rev), len(heads), clen))
2580 rs, ts, ts / r.end(rev), len(heads), clen))
2581 return 0
2581 return 0
2582
2582
2583 v = r.version
2583 v = r.version
2584 format = v & 0xFFFF
2584 format = v & 0xFFFF
2585 flags = []
2585 flags = []
2586 gdelta = False
2586 gdelta = False
2587 if v & revlog.REVLOGNGINLINEDATA:
2587 if v & revlog.REVLOGNGINLINEDATA:
2588 flags.append('inline')
2588 flags.append('inline')
2589 if v & revlog.REVLOGGENERALDELTA:
2589 if v & revlog.REVLOGGENERALDELTA:
2590 gdelta = True
2590 gdelta = True
2591 flags.append('generaldelta')
2591 flags.append('generaldelta')
2592 if not flags:
2592 if not flags:
2593 flags = ['(none)']
2593 flags = ['(none)']
2594
2594
2595 nummerges = 0
2595 nummerges = 0
2596 numfull = 0
2596 numfull = 0
2597 numprev = 0
2597 numprev = 0
2598 nump1 = 0
2598 nump1 = 0
2599 nump2 = 0
2599 nump2 = 0
2600 numother = 0
2600 numother = 0
2601 nump1prev = 0
2601 nump1prev = 0
2602 nump2prev = 0
2602 nump2prev = 0
2603 chainlengths = []
2603 chainlengths = []
2604
2604
2605 datasize = [None, 0, 0L]
2605 datasize = [None, 0, 0L]
2606 fullsize = [None, 0, 0L]
2606 fullsize = [None, 0, 0L]
2607 deltasize = [None, 0, 0L]
2607 deltasize = [None, 0, 0L]
2608
2608
2609 def addsize(size, l):
2609 def addsize(size, l):
2610 if l[0] is None or size < l[0]:
2610 if l[0] is None or size < l[0]:
2611 l[0] = size
2611 l[0] = size
2612 if size > l[1]:
2612 if size > l[1]:
2613 l[1] = size
2613 l[1] = size
2614 l[2] += size
2614 l[2] += size
2615
2615
2616 numrevs = len(r)
2616 numrevs = len(r)
2617 for rev in xrange(numrevs):
2617 for rev in xrange(numrevs):
2618 p1, p2 = r.parentrevs(rev)
2618 p1, p2 = r.parentrevs(rev)
2619 delta = r.deltaparent(rev)
2619 delta = r.deltaparent(rev)
2620 if format > 0:
2620 if format > 0:
2621 addsize(r.rawsize(rev), datasize)
2621 addsize(r.rawsize(rev), datasize)
2622 if p2 != nullrev:
2622 if p2 != nullrev:
2623 nummerges += 1
2623 nummerges += 1
2624 size = r.length(rev)
2624 size = r.length(rev)
2625 if delta == nullrev:
2625 if delta == nullrev:
2626 chainlengths.append(0)
2626 chainlengths.append(0)
2627 numfull += 1
2627 numfull += 1
2628 addsize(size, fullsize)
2628 addsize(size, fullsize)
2629 else:
2629 else:
2630 chainlengths.append(chainlengths[delta] + 1)
2630 chainlengths.append(chainlengths[delta] + 1)
2631 addsize(size, deltasize)
2631 addsize(size, deltasize)
2632 if delta == rev - 1:
2632 if delta == rev - 1:
2633 numprev += 1
2633 numprev += 1
2634 if delta == p1:
2634 if delta == p1:
2635 nump1prev += 1
2635 nump1prev += 1
2636 elif delta == p2:
2636 elif delta == p2:
2637 nump2prev += 1
2637 nump2prev += 1
2638 elif delta == p1:
2638 elif delta == p1:
2639 nump1 += 1
2639 nump1 += 1
2640 elif delta == p2:
2640 elif delta == p2:
2641 nump2 += 1
2641 nump2 += 1
2642 elif delta != nullrev:
2642 elif delta != nullrev:
2643 numother += 1
2643 numother += 1
2644
2644
2645 # Adjust size min value for empty cases
2645 # Adjust size min value for empty cases
2646 for size in (datasize, fullsize, deltasize):
2646 for size in (datasize, fullsize, deltasize):
2647 if size[0] is None:
2647 if size[0] is None:
2648 size[0] = 0
2648 size[0] = 0
2649
2649
2650 numdeltas = numrevs - numfull
2650 numdeltas = numrevs - numfull
2651 numoprev = numprev - nump1prev - nump2prev
2651 numoprev = numprev - nump1prev - nump2prev
2652 totalrawsize = datasize[2]
2652 totalrawsize = datasize[2]
2653 datasize[2] /= numrevs
2653 datasize[2] /= numrevs
2654 fulltotal = fullsize[2]
2654 fulltotal = fullsize[2]
2655 fullsize[2] /= numfull
2655 fullsize[2] /= numfull
2656 deltatotal = deltasize[2]
2656 deltatotal = deltasize[2]
2657 if numrevs - numfull > 0:
2657 if numrevs - numfull > 0:
2658 deltasize[2] /= numrevs - numfull
2658 deltasize[2] /= numrevs - numfull
2659 totalsize = fulltotal + deltatotal
2659 totalsize = fulltotal + deltatotal
2660 avgchainlen = sum(chainlengths) / numrevs
2660 avgchainlen = sum(chainlengths) / numrevs
2661 compratio = totalrawsize / totalsize
2661 compratio = totalrawsize / totalsize
2662
2662
2663 basedfmtstr = '%%%dd\n'
2663 basedfmtstr = '%%%dd\n'
2664 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2664 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2665
2665
2666 def dfmtstr(max):
2666 def dfmtstr(max):
2667 return basedfmtstr % len(str(max))
2667 return basedfmtstr % len(str(max))
2668 def pcfmtstr(max, padding=0):
2668 def pcfmtstr(max, padding=0):
2669 return basepcfmtstr % (len(str(max)), ' ' * padding)
2669 return basepcfmtstr % (len(str(max)), ' ' * padding)
2670
2670
2671 def pcfmt(value, total):
2671 def pcfmt(value, total):
2672 return (value, 100 * float(value) / total)
2672 return (value, 100 * float(value) / total)
2673
2673
2674 ui.write(('format : %d\n') % format)
2674 ui.write(('format : %d\n') % format)
2675 ui.write(('flags : %s\n') % ', '.join(flags))
2675 ui.write(('flags : %s\n') % ', '.join(flags))
2676
2676
2677 ui.write('\n')
2677 ui.write('\n')
2678 fmt = pcfmtstr(totalsize)
2678 fmt = pcfmtstr(totalsize)
2679 fmt2 = dfmtstr(totalsize)
2679 fmt2 = dfmtstr(totalsize)
2680 ui.write(('revisions : ') + fmt2 % numrevs)
2680 ui.write(('revisions : ') + fmt2 % numrevs)
2681 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2681 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2682 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2682 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2683 ui.write(('revisions : ') + fmt2 % numrevs)
2683 ui.write(('revisions : ') + fmt2 % numrevs)
2684 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2684 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2685 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2685 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2686 ui.write(('revision size : ') + fmt2 % totalsize)
2686 ui.write(('revision size : ') + fmt2 % totalsize)
2687 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2687 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2688 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2688 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2689
2689
2690 ui.write('\n')
2690 ui.write('\n')
2691 fmt = dfmtstr(max(avgchainlen, compratio))
2691 fmt = dfmtstr(max(avgchainlen, compratio))
2692 ui.write(('avg chain length : ') + fmt % avgchainlen)
2692 ui.write(('avg chain length : ') + fmt % avgchainlen)
2693 ui.write(('compression ratio : ') + fmt % compratio)
2693 ui.write(('compression ratio : ') + fmt % compratio)
2694
2694
2695 if format > 0:
2695 if format > 0:
2696 ui.write('\n')
2696 ui.write('\n')
2697 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2697 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2698 % tuple(datasize))
2698 % tuple(datasize))
2699 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2699 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2700 % tuple(fullsize))
2700 % tuple(fullsize))
2701 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2701 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2702 % tuple(deltasize))
2702 % tuple(deltasize))
2703
2703
2704 if numdeltas > 0:
2704 if numdeltas > 0:
2705 ui.write('\n')
2705 ui.write('\n')
2706 fmt = pcfmtstr(numdeltas)
2706 fmt = pcfmtstr(numdeltas)
2707 fmt2 = pcfmtstr(numdeltas, 4)
2707 fmt2 = pcfmtstr(numdeltas, 4)
2708 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2708 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2709 if numprev > 0:
2709 if numprev > 0:
2710 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2710 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2711 numprev))
2711 numprev))
2712 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2712 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2713 numprev))
2713 numprev))
2714 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2714 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2715 numprev))
2715 numprev))
2716 if gdelta:
2716 if gdelta:
2717 ui.write(('deltas against p1 : ')
2717 ui.write(('deltas against p1 : ')
2718 + fmt % pcfmt(nump1, numdeltas))
2718 + fmt % pcfmt(nump1, numdeltas))
2719 ui.write(('deltas against p2 : ')
2719 ui.write(('deltas against p2 : ')
2720 + fmt % pcfmt(nump2, numdeltas))
2720 + fmt % pcfmt(nump2, numdeltas))
2721 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2721 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2722 numdeltas))
2722 numdeltas))
2723
2723
2724 @command('debugrevspec',
2724 @command('debugrevspec',
2725 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2725 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2726 ('REVSPEC'))
2726 ('REVSPEC'))
2727 def debugrevspec(ui, repo, expr, **opts):
2727 def debugrevspec(ui, repo, expr, **opts):
2728 """parse and apply a revision specification
2728 """parse and apply a revision specification
2729
2729
2730 Use --verbose to print the parsed tree before and after aliases
2730 Use --verbose to print the parsed tree before and after aliases
2731 expansion.
2731 expansion.
2732 """
2732 """
2733 if ui.verbose:
2733 if ui.verbose:
2734 tree = revset.parse(expr)[0]
2734 tree = revset.parse(expr)[0]
2735 ui.note(revset.prettyformat(tree), "\n")
2735 ui.note(revset.prettyformat(tree), "\n")
2736 newtree = revset.findaliases(ui, tree)
2736 newtree = revset.findaliases(ui, tree)
2737 if newtree != tree:
2737 if newtree != tree:
2738 ui.note(revset.prettyformat(newtree), "\n")
2738 ui.note(revset.prettyformat(newtree), "\n")
2739 if opts["optimize"]:
2739 if opts["optimize"]:
2740 weight, optimizedtree = revset.optimize(newtree, True)
2740 weight, optimizedtree = revset.optimize(newtree, True)
2741 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2741 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2742 func = revset.match(ui, expr)
2742 func = revset.match(ui, expr)
2743 for c in func(repo, revset.spanset(repo)):
2743 for c in func(repo, revset.spanset(repo)):
2744 ui.write("%s\n" % c)
2744 ui.write("%s\n" % c)
2745
2745
2746 @command('debugsetparents', [], _('REV1 [REV2]'))
2746 @command('debugsetparents', [], _('REV1 [REV2]'))
2747 def debugsetparents(ui, repo, rev1, rev2=None):
2747 def debugsetparents(ui, repo, rev1, rev2=None):
2748 """manually set the parents of the current working directory
2748 """manually set the parents of the current working directory
2749
2749
2750 This is useful for writing repository conversion tools, but should
2750 This is useful for writing repository conversion tools, but should
2751 be used with care.
2751 be used with care.
2752
2752
2753 Returns 0 on success.
2753 Returns 0 on success.
2754 """
2754 """
2755
2755
2756 r1 = scmutil.revsingle(repo, rev1).node()
2756 r1 = scmutil.revsingle(repo, rev1).node()
2757 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2757 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2758
2758
2759 wlock = repo.wlock()
2759 wlock = repo.wlock()
2760 try:
2760 try:
2761 repo.dirstate.beginparentchange()
2761 repo.dirstate.beginparentchange()
2762 repo.setparents(r1, r2)
2762 repo.setparents(r1, r2)
2763 repo.dirstate.endparentchange()
2763 repo.dirstate.endparentchange()
2764 finally:
2764 finally:
2765 wlock.release()
2765 wlock.release()
2766
2766
2767 @command('debugdirstate|debugstate',
2767 @command('debugdirstate|debugstate',
2768 [('', 'nodates', None, _('do not display the saved mtime')),
2768 [('', 'nodates', None, _('do not display the saved mtime')),
2769 ('', 'datesort', None, _('sort by saved mtime'))],
2769 ('', 'datesort', None, _('sort by saved mtime'))],
2770 _('[OPTION]...'))
2770 _('[OPTION]...'))
2771 def debugstate(ui, repo, nodates=None, datesort=None):
2771 def debugstate(ui, repo, nodates=None, datesort=None):
2772 """show the contents of the current dirstate"""
2772 """show the contents of the current dirstate"""
2773 timestr = ""
2773 timestr = ""
2774 showdate = not nodates
2774 showdate = not nodates
2775 if datesort:
2775 if datesort:
2776 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2776 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2777 else:
2777 else:
2778 keyfunc = None # sort by filename
2778 keyfunc = None # sort by filename
2779 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2779 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2780 if showdate:
2780 if showdate:
2781 if ent[3] == -1:
2781 if ent[3] == -1:
2782 # Pad or slice to locale representation
2782 # Pad or slice to locale representation
2783 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2783 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2784 time.localtime(0)))
2784 time.localtime(0)))
2785 timestr = 'unset'
2785 timestr = 'unset'
2786 timestr = (timestr[:locale_len] +
2786 timestr = (timestr[:locale_len] +
2787 ' ' * (locale_len - len(timestr)))
2787 ' ' * (locale_len - len(timestr)))
2788 else:
2788 else:
2789 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2789 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2790 time.localtime(ent[3]))
2790 time.localtime(ent[3]))
2791 if ent[1] & 020000:
2791 if ent[1] & 020000:
2792 mode = 'lnk'
2792 mode = 'lnk'
2793 else:
2793 else:
2794 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2794 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2795 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2795 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2796 for f in repo.dirstate.copies():
2796 for f in repo.dirstate.copies():
2797 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2797 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2798
2798
2799 @command('debugsub',
2799 @command('debugsub',
2800 [('r', 'rev', '',
2800 [('r', 'rev', '',
2801 _('revision to check'), _('REV'))],
2801 _('revision to check'), _('REV'))],
2802 _('[-r REV] [REV]'))
2802 _('[-r REV] [REV]'))
2803 def debugsub(ui, repo, rev=None):
2803 def debugsub(ui, repo, rev=None):
2804 ctx = scmutil.revsingle(repo, rev, None)
2804 ctx = scmutil.revsingle(repo, rev, None)
2805 for k, v in sorted(ctx.substate.items()):
2805 for k, v in sorted(ctx.substate.items()):
2806 ui.write(('path %s\n') % k)
2806 ui.write(('path %s\n') % k)
2807 ui.write((' source %s\n') % v[0])
2807 ui.write((' source %s\n') % v[0])
2808 ui.write((' revision %s\n') % v[1])
2808 ui.write((' revision %s\n') % v[1])
2809
2809
2810 @command('debugsuccessorssets',
2810 @command('debugsuccessorssets',
2811 [],
2811 [],
2812 _('[REV]'))
2812 _('[REV]'))
2813 def debugsuccessorssets(ui, repo, *revs):
2813 def debugsuccessorssets(ui, repo, *revs):
2814 """show set of successors for revision
2814 """show set of successors for revision
2815
2815
2816 A successors set of changeset A is a consistent group of revisions that
2816 A successors set of changeset A is a consistent group of revisions that
2817 succeed A. It contains non-obsolete changesets only.
2817 succeed A. It contains non-obsolete changesets only.
2818
2818
2819 In most cases a changeset A has a single successors set containing a single
2819 In most cases a changeset A has a single successors set containing a single
2820 successor (changeset A replaced by A').
2820 successor (changeset A replaced by A').
2821
2821
2822 A changeset that is made obsolete with no successors are called "pruned".
2822 A changeset that is made obsolete with no successors are called "pruned".
2823 Such changesets have no successors sets at all.
2823 Such changesets have no successors sets at all.
2824
2824
2825 A changeset that has been "split" will have a successors set containing
2825 A changeset that has been "split" will have a successors set containing
2826 more than one successor.
2826 more than one successor.
2827
2827
2828 A changeset that has been rewritten in multiple different ways is called
2828 A changeset that has been rewritten in multiple different ways is called
2829 "divergent". Such changesets have multiple successor sets (each of which
2829 "divergent". Such changesets have multiple successor sets (each of which
2830 may also be split, i.e. have multiple successors).
2830 may also be split, i.e. have multiple successors).
2831
2831
2832 Results are displayed as follows::
2832 Results are displayed as follows::
2833
2833
2834 <rev1>
2834 <rev1>
2835 <successors-1A>
2835 <successors-1A>
2836 <rev2>
2836 <rev2>
2837 <successors-2A>
2837 <successors-2A>
2838 <successors-2B1> <successors-2B2> <successors-2B3>
2838 <successors-2B1> <successors-2B2> <successors-2B3>
2839
2839
2840 Here rev2 has two possible (i.e. divergent) successors sets. The first
2840 Here rev2 has two possible (i.e. divergent) successors sets. The first
2841 holds one element, whereas the second holds three (i.e. the changeset has
2841 holds one element, whereas the second holds three (i.e. the changeset has
2842 been split).
2842 been split).
2843 """
2843 """
2844 # passed to successorssets caching computation from one call to another
2844 # passed to successorssets caching computation from one call to another
2845 cache = {}
2845 cache = {}
2846 ctx2str = str
2846 ctx2str = str
2847 node2str = short
2847 node2str = short
2848 if ui.debug():
2848 if ui.debug():
2849 def ctx2str(ctx):
2849 def ctx2str(ctx):
2850 return ctx.hex()
2850 return ctx.hex()
2851 node2str = hex
2851 node2str = hex
2852 for rev in scmutil.revrange(repo, revs):
2852 for rev in scmutil.revrange(repo, revs):
2853 ctx = repo[rev]
2853 ctx = repo[rev]
2854 ui.write('%s\n'% ctx2str(ctx))
2854 ui.write('%s\n'% ctx2str(ctx))
2855 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2855 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2856 if succsset:
2856 if succsset:
2857 ui.write(' ')
2857 ui.write(' ')
2858 ui.write(node2str(succsset[0]))
2858 ui.write(node2str(succsset[0]))
2859 for node in succsset[1:]:
2859 for node in succsset[1:]:
2860 ui.write(' ')
2860 ui.write(' ')
2861 ui.write(node2str(node))
2861 ui.write(node2str(node))
2862 ui.write('\n')
2862 ui.write('\n')
2863
2863
2864 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2864 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2865 def debugwalk(ui, repo, *pats, **opts):
2865 def debugwalk(ui, repo, *pats, **opts):
2866 """show how files match on given patterns"""
2866 """show how files match on given patterns"""
2867 m = scmutil.match(repo[None], pats, opts)
2867 m = scmutil.match(repo[None], pats, opts)
2868 items = list(repo.walk(m))
2868 items = list(repo.walk(m))
2869 if not items:
2869 if not items:
2870 return
2870 return
2871 f = lambda fn: fn
2871 f = lambda fn: fn
2872 if ui.configbool('ui', 'slash') and os.sep != '/':
2872 if ui.configbool('ui', 'slash') and os.sep != '/':
2873 f = lambda fn: util.normpath(fn)
2873 f = lambda fn: util.normpath(fn)
2874 fmt = 'f %%-%ds %%-%ds %%s' % (
2874 fmt = 'f %%-%ds %%-%ds %%s' % (
2875 max([len(abs) for abs in items]),
2875 max([len(abs) for abs in items]),
2876 max([len(m.rel(abs)) for abs in items]))
2876 max([len(m.rel(abs)) for abs in items]))
2877 for abs in items:
2877 for abs in items:
2878 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2878 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2879 ui.write("%s\n" % line.rstrip())
2879 ui.write("%s\n" % line.rstrip())
2880
2880
2881 @command('debugwireargs',
2881 @command('debugwireargs',
2882 [('', 'three', '', 'three'),
2882 [('', 'three', '', 'three'),
2883 ('', 'four', '', 'four'),
2883 ('', 'four', '', 'four'),
2884 ('', 'five', '', 'five'),
2884 ('', 'five', '', 'five'),
2885 ] + remoteopts,
2885 ] + remoteopts,
2886 _('REPO [OPTIONS]... [ONE [TWO]]'),
2886 _('REPO [OPTIONS]... [ONE [TWO]]'),
2887 norepo=True)
2887 norepo=True)
2888 def debugwireargs(ui, repopath, *vals, **opts):
2888 def debugwireargs(ui, repopath, *vals, **opts):
2889 repo = hg.peer(ui, opts, repopath)
2889 repo = hg.peer(ui, opts, repopath)
2890 for opt in remoteopts:
2890 for opt in remoteopts:
2891 del opts[opt[1]]
2891 del opts[opt[1]]
2892 args = {}
2892 args = {}
2893 for k, v in opts.iteritems():
2893 for k, v in opts.iteritems():
2894 if v:
2894 if v:
2895 args[k] = v
2895 args[k] = v
2896 # run twice to check that we don't mess up the stream for the next command
2896 # run twice to check that we don't mess up the stream for the next command
2897 res1 = repo.debugwireargs(*vals, **args)
2897 res1 = repo.debugwireargs(*vals, **args)
2898 res2 = repo.debugwireargs(*vals, **args)
2898 res2 = repo.debugwireargs(*vals, **args)
2899 ui.write("%s\n" % res1)
2899 ui.write("%s\n" % res1)
2900 if res1 != res2:
2900 if res1 != res2:
2901 ui.warn("%s\n" % res2)
2901 ui.warn("%s\n" % res2)
2902
2902
2903 @command('^diff',
2903 @command('^diff',
2904 [('r', 'rev', [], _('revision'), _('REV')),
2904 [('r', 'rev', [], _('revision'), _('REV')),
2905 ('c', 'change', '', _('change made by revision'), _('REV'))
2905 ('c', 'change', '', _('change made by revision'), _('REV'))
2906 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2906 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2907 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2907 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2908 inferrepo=True)
2908 inferrepo=True)
2909 def diff(ui, repo, *pats, **opts):
2909 def diff(ui, repo, *pats, **opts):
2910 """diff repository (or selected files)
2910 """diff repository (or selected files)
2911
2911
2912 Show differences between revisions for the specified files.
2912 Show differences between revisions for the specified files.
2913
2913
2914 Differences between files are shown using the unified diff format.
2914 Differences between files are shown using the unified diff format.
2915
2915
2916 .. note::
2916 .. note::
2917
2917
2918 diff may generate unexpected results for merges, as it will
2918 diff may generate unexpected results for merges, as it will
2919 default to comparing against the working directory's first
2919 default to comparing against the working directory's first
2920 parent changeset if no revisions are specified.
2920 parent changeset if no revisions are specified.
2921
2921
2922 When two revision arguments are given, then changes are shown
2922 When two revision arguments are given, then changes are shown
2923 between those revisions. If only one revision is specified then
2923 between those revisions. If only one revision is specified then
2924 that revision is compared to the working directory, and, when no
2924 that revision is compared to the working directory, and, when no
2925 revisions are specified, the working directory files are compared
2925 revisions are specified, the working directory files are compared
2926 to its parent.
2926 to its parent.
2927
2927
2928 Alternatively you can specify -c/--change with a revision to see
2928 Alternatively you can specify -c/--change with a revision to see
2929 the changes in that changeset relative to its first parent.
2929 the changes in that changeset relative to its first parent.
2930
2930
2931 Without the -a/--text option, diff will avoid generating diffs of
2931 Without the -a/--text option, diff will avoid generating diffs of
2932 files it detects as binary. With -a, diff will generate a diff
2932 files it detects as binary. With -a, diff will generate a diff
2933 anyway, probably with undesirable results.
2933 anyway, probably with undesirable results.
2934
2934
2935 Use the -g/--git option to generate diffs in the git extended diff
2935 Use the -g/--git option to generate diffs in the git extended diff
2936 format. For more information, read :hg:`help diffs`.
2936 format. For more information, read :hg:`help diffs`.
2937
2937
2938 .. container:: verbose
2938 .. container:: verbose
2939
2939
2940 Examples:
2940 Examples:
2941
2941
2942 - compare a file in the current working directory to its parent::
2942 - compare a file in the current working directory to its parent::
2943
2943
2944 hg diff foo.c
2944 hg diff foo.c
2945
2945
2946 - compare two historical versions of a directory, with rename info::
2946 - compare two historical versions of a directory, with rename info::
2947
2947
2948 hg diff --git -r 1.0:1.2 lib/
2948 hg diff --git -r 1.0:1.2 lib/
2949
2949
2950 - get change stats relative to the last change on some date::
2950 - get change stats relative to the last change on some date::
2951
2951
2952 hg diff --stat -r "date('may 2')"
2952 hg diff --stat -r "date('may 2')"
2953
2953
2954 - diff all newly-added files that contain a keyword::
2954 - diff all newly-added files that contain a keyword::
2955
2955
2956 hg diff "set:added() and grep(GNU)"
2956 hg diff "set:added() and grep(GNU)"
2957
2957
2958 - compare a revision and its parents::
2958 - compare a revision and its parents::
2959
2959
2960 hg diff -c 9353 # compare against first parent
2960 hg diff -c 9353 # compare against first parent
2961 hg diff -r 9353^:9353 # same using revset syntax
2961 hg diff -r 9353^:9353 # same using revset syntax
2962 hg diff -r 9353^2:9353 # compare against the second parent
2962 hg diff -r 9353^2:9353 # compare against the second parent
2963
2963
2964 Returns 0 on success.
2964 Returns 0 on success.
2965 """
2965 """
2966
2966
2967 revs = opts.get('rev')
2967 revs = opts.get('rev')
2968 change = opts.get('change')
2968 change = opts.get('change')
2969 stat = opts.get('stat')
2969 stat = opts.get('stat')
2970 reverse = opts.get('reverse')
2970 reverse = opts.get('reverse')
2971
2971
2972 if revs and change:
2972 if revs and change:
2973 msg = _('cannot specify --rev and --change at the same time')
2973 msg = _('cannot specify --rev and --change at the same time')
2974 raise util.Abort(msg)
2974 raise util.Abort(msg)
2975 elif change:
2975 elif change:
2976 node2 = scmutil.revsingle(repo, change, None).node()
2976 node2 = scmutil.revsingle(repo, change, None).node()
2977 node1 = repo[node2].p1().node()
2977 node1 = repo[node2].p1().node()
2978 else:
2978 else:
2979 node1, node2 = scmutil.revpair(repo, revs)
2979 node1, node2 = scmutil.revpair(repo, revs)
2980
2980
2981 if reverse:
2981 if reverse:
2982 node1, node2 = node2, node1
2982 node1, node2 = node2, node1
2983
2983
2984 diffopts = patch.diffopts(ui, opts)
2984 diffopts = patch.diffopts(ui, opts)
2985 m = scmutil.match(repo[node2], pats, opts)
2985 m = scmutil.match(repo[node2], pats, opts)
2986 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2986 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2987 listsubrepos=opts.get('subrepos'))
2987 listsubrepos=opts.get('subrepos'))
2988
2988
2989 @command('^export',
2989 @command('^export',
2990 [('o', 'output', '',
2990 [('o', 'output', '',
2991 _('print output to file with formatted name'), _('FORMAT')),
2991 _('print output to file with formatted name'), _('FORMAT')),
2992 ('', 'switch-parent', None, _('diff against the second parent')),
2992 ('', 'switch-parent', None, _('diff against the second parent')),
2993 ('r', 'rev', [], _('revisions to export'), _('REV')),
2993 ('r', 'rev', [], _('revisions to export'), _('REV')),
2994 ] + diffopts,
2994 ] + diffopts,
2995 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2995 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2996 def export(ui, repo, *changesets, **opts):
2996 def export(ui, repo, *changesets, **opts):
2997 """dump the header and diffs for one or more changesets
2997 """dump the header and diffs for one or more changesets
2998
2998
2999 Print the changeset header and diffs for one or more revisions.
2999 Print the changeset header and diffs for one or more revisions.
3000 If no revision is given, the parent of the working directory is used.
3000 If no revision is given, the parent of the working directory is used.
3001
3001
3002 The information shown in the changeset header is: author, date,
3002 The information shown in the changeset header is: author, date,
3003 branch name (if non-default), changeset hash, parent(s) and commit
3003 branch name (if non-default), changeset hash, parent(s) and commit
3004 comment.
3004 comment.
3005
3005
3006 .. note::
3006 .. note::
3007
3007
3008 export may generate unexpected diff output for merge
3008 export may generate unexpected diff output for merge
3009 changesets, as it will compare the merge changeset against its
3009 changesets, as it will compare the merge changeset against its
3010 first parent only.
3010 first parent only.
3011
3011
3012 Output may be to a file, in which case the name of the file is
3012 Output may be to a file, in which case the name of the file is
3013 given using a format string. The formatting rules are as follows:
3013 given using a format string. The formatting rules are as follows:
3014
3014
3015 :``%%``: literal "%" character
3015 :``%%``: literal "%" character
3016 :``%H``: changeset hash (40 hexadecimal digits)
3016 :``%H``: changeset hash (40 hexadecimal digits)
3017 :``%N``: number of patches being generated
3017 :``%N``: number of patches being generated
3018 :``%R``: changeset revision number
3018 :``%R``: changeset revision number
3019 :``%b``: basename of the exporting repository
3019 :``%b``: basename of the exporting repository
3020 :``%h``: short-form changeset hash (12 hexadecimal digits)
3020 :``%h``: short-form changeset hash (12 hexadecimal digits)
3021 :``%m``: first line of the commit message (only alphanumeric characters)
3021 :``%m``: first line of the commit message (only alphanumeric characters)
3022 :``%n``: zero-padded sequence number, starting at 1
3022 :``%n``: zero-padded sequence number, starting at 1
3023 :``%r``: zero-padded changeset revision number
3023 :``%r``: zero-padded changeset revision number
3024
3024
3025 Without the -a/--text option, export will avoid generating diffs
3025 Without the -a/--text option, export will avoid generating diffs
3026 of files it detects as binary. With -a, export will generate a
3026 of files it detects as binary. With -a, export will generate a
3027 diff anyway, probably with undesirable results.
3027 diff anyway, probably with undesirable results.
3028
3028
3029 Use the -g/--git option to generate diffs in the git extended diff
3029 Use the -g/--git option to generate diffs in the git extended diff
3030 format. See :hg:`help diffs` for more information.
3030 format. See :hg:`help diffs` for more information.
3031
3031
3032 With the --switch-parent option, the diff will be against the
3032 With the --switch-parent option, the diff will be against the
3033 second parent. It can be useful to review a merge.
3033 second parent. It can be useful to review a merge.
3034
3034
3035 .. container:: verbose
3035 .. container:: verbose
3036
3036
3037 Examples:
3037 Examples:
3038
3038
3039 - use export and import to transplant a bugfix to the current
3039 - use export and import to transplant a bugfix to the current
3040 branch::
3040 branch::
3041
3041
3042 hg export -r 9353 | hg import -
3042 hg export -r 9353 | hg import -
3043
3043
3044 - export all the changesets between two revisions to a file with
3044 - export all the changesets between two revisions to a file with
3045 rename information::
3045 rename information::
3046
3046
3047 hg export --git -r 123:150 > changes.txt
3047 hg export --git -r 123:150 > changes.txt
3048
3048
3049 - split outgoing changes into a series of patches with
3049 - split outgoing changes into a series of patches with
3050 descriptive names::
3050 descriptive names::
3051
3051
3052 hg export -r "outgoing()" -o "%n-%m.patch"
3052 hg export -r "outgoing()" -o "%n-%m.patch"
3053
3053
3054 Returns 0 on success.
3054 Returns 0 on success.
3055 """
3055 """
3056 changesets += tuple(opts.get('rev', []))
3056 changesets += tuple(opts.get('rev', []))
3057 if not changesets:
3057 if not changesets:
3058 changesets = ['.']
3058 changesets = ['.']
3059 revs = scmutil.revrange(repo, changesets)
3059 revs = scmutil.revrange(repo, changesets)
3060 if not revs:
3060 if not revs:
3061 raise util.Abort(_("export requires at least one changeset"))
3061 raise util.Abort(_("export requires at least one changeset"))
3062 if len(revs) > 1:
3062 if len(revs) > 1:
3063 ui.note(_('exporting patches:\n'))
3063 ui.note(_('exporting patches:\n'))
3064 else:
3064 else:
3065 ui.note(_('exporting patch:\n'))
3065 ui.note(_('exporting patch:\n'))
3066 cmdutil.export(repo, revs, template=opts.get('output'),
3066 cmdutil.export(repo, revs, template=opts.get('output'),
3067 switch_parent=opts.get('switch_parent'),
3067 switch_parent=opts.get('switch_parent'),
3068 opts=patch.diffopts(ui, opts))
3068 opts=patch.diffopts(ui, opts))
3069
3069
3070 @command('files',
3070 @command('files',
3071 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3071 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3072 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3072 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3073 ] + walkopts + formatteropts,
3073 ] + walkopts + formatteropts,
3074 _('[OPTION]... [PATTERN]...'))
3074 _('[OPTION]... [PATTERN]...'))
3075 def files(ui, repo, *pats, **opts):
3075 def files(ui, repo, *pats, **opts):
3076 """list tracked files
3076 """list tracked files
3077
3077
3078 Print files under Mercurial control in the working directory or
3078 Print files under Mercurial control in the working directory or
3079 specified revision whose names match the given patterns (excluding
3079 specified revision whose names match the given patterns (excluding
3080 removed files).
3080 removed files).
3081
3081
3082 If no patterns are given to match, this command prints the names
3082 If no patterns are given to match, this command prints the names
3083 of all files under Mercurial control in the working copy.
3083 of all files under Mercurial control in the working copy.
3084
3084
3085 .. container:: verbose
3085 .. container:: verbose
3086
3086
3087 Examples:
3087 Examples:
3088
3088
3089 - list all files under the current directory::
3089 - list all files under the current directory::
3090
3090
3091 hg files .
3091 hg files .
3092
3092
3093 - shows sizes and flags for current revision::
3093 - shows sizes and flags for current revision::
3094
3094
3095 hg files -vr .
3095 hg files -vr .
3096
3096
3097 - list all files named README::
3097 - list all files named README::
3098
3098
3099 hg files -I "**/README"
3099 hg files -I "**/README"
3100
3100
3101 - list all binary files::
3101 - list all binary files::
3102
3102
3103 hg files "set:binary()"
3103 hg files "set:binary()"
3104
3104
3105 - find files containing a regular expression:
3105 - find files containing a regular expression:
3106
3106
3107 hg files "set:grep('bob')"
3107 hg files "set:grep('bob')"
3108
3108
3109 - search tracked file contents with xargs and grep::
3109 - search tracked file contents with xargs and grep::
3110
3110
3111 hg files -0 | xargs -0 grep foo
3111 hg files -0 | xargs -0 grep foo
3112
3112
3113 See :hg:'help pattern' and :hg:'help revsets' for more information
3113 See :hg:'help pattern' and :hg:'help revsets' for more information
3114 on specifying file patterns.
3114 on specifying file patterns.
3115
3115
3116 Returns 0 if a match is found, 1 otherwise.
3116 Returns 0 if a match is found, 1 otherwise.
3117
3117
3118 """
3118 """
3119 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3119 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3120 rev = ctx.rev()
3120 rev = ctx.rev()
3121 ret = 1
3121 ret = 1
3122
3122
3123 end = '\n'
3123 end = '\n'
3124 if opts.get('print0'):
3124 if opts.get('print0'):
3125 end = '\0'
3125 end = '\0'
3126 fm = ui.formatter('status', opts)
3126 fm = ui.formatter('status', opts)
3127 fmt = '%s' + end
3127 fmt = '%s' + end
3128
3128
3129 m = scmutil.match(ctx, pats, opts)
3129 m = scmutil.match(ctx, pats, opts)
3130 for f in ctx.walk(m):
3130 for f in ctx.walk(m):
3131 if rev is None and repo.dirstate[f] in 'R?!':
3131 if rev is None and repo.dirstate[f] in 'R?!':
3132 continue
3132 continue
3133 fm.startitem()
3133 fm.startitem()
3134 if ui.verbose:
3134 if ui.verbose:
3135 fc = ctx[f]
3135 fc = ctx[f]
3136 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
3136 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
3137 fm.data(abspath=f)
3137 fm.data(abspath=f)
3138 fm.write('path', fmt, m.rel(f))
3138 fm.write('path', fmt, m.rel(f))
3139 ret = 0
3139 ret = 0
3140
3140
3141 fm.end()
3141 fm.end()
3142
3142
3143 return ret
3143 return ret
3144
3144
3145 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3145 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3146 def forget(ui, repo, *pats, **opts):
3146 def forget(ui, repo, *pats, **opts):
3147 """forget the specified files on the next commit
3147 """forget the specified files on the next commit
3148
3148
3149 Mark the specified files so they will no longer be tracked
3149 Mark the specified files so they will no longer be tracked
3150 after the next commit.
3150 after the next commit.
3151
3151
3152 This only removes files from the current branch, not from the
3152 This only removes files from the current branch, not from the
3153 entire project history, and it does not delete them from the
3153 entire project history, and it does not delete them from the
3154 working directory.
3154 working directory.
3155
3155
3156 To undo a forget before the next commit, see :hg:`add`.
3156 To undo a forget before the next commit, see :hg:`add`.
3157
3157
3158 .. container:: verbose
3158 .. container:: verbose
3159
3159
3160 Examples:
3160 Examples:
3161
3161
3162 - forget newly-added binary files::
3162 - forget newly-added binary files::
3163
3163
3164 hg forget "set:added() and binary()"
3164 hg forget "set:added() and binary()"
3165
3165
3166 - forget files that would be excluded by .hgignore::
3166 - forget files that would be excluded by .hgignore::
3167
3167
3168 hg forget "set:hgignore()"
3168 hg forget "set:hgignore()"
3169
3169
3170 Returns 0 on success.
3170 Returns 0 on success.
3171 """
3171 """
3172
3172
3173 if not pats:
3173 if not pats:
3174 raise util.Abort(_('no files specified'))
3174 raise util.Abort(_('no files specified'))
3175
3175
3176 m = scmutil.match(repo[None], pats, opts)
3176 m = scmutil.match(repo[None], pats, opts)
3177 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3177 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3178 return rejected and 1 or 0
3178 return rejected and 1 or 0
3179
3179
3180 @command(
3180 @command(
3181 'graft',
3181 'graft',
3182 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3182 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3183 ('c', 'continue', False, _('resume interrupted graft')),
3183 ('c', 'continue', False, _('resume interrupted graft')),
3184 ('e', 'edit', False, _('invoke editor on commit messages')),
3184 ('e', 'edit', False, _('invoke editor on commit messages')),
3185 ('', 'log', None, _('append graft info to log message')),
3185 ('', 'log', None, _('append graft info to log message')),
3186 ('f', 'force', False, _('force graft')),
3186 ('f', 'force', False, _('force graft')),
3187 ('D', 'currentdate', False,
3187 ('D', 'currentdate', False,
3188 _('record the current date as commit date')),
3188 _('record the current date as commit date')),
3189 ('U', 'currentuser', False,
3189 ('U', 'currentuser', False,
3190 _('record the current user as committer'), _('DATE'))]
3190 _('record the current user as committer'), _('DATE'))]
3191 + commitopts2 + mergetoolopts + dryrunopts,
3191 + commitopts2 + mergetoolopts + dryrunopts,
3192 _('[OPTION]... [-r] REV...'))
3192 _('[OPTION]... [-r] REV...'))
3193 def graft(ui, repo, *revs, **opts):
3193 def graft(ui, repo, *revs, **opts):
3194 '''copy changes from other branches onto the current branch
3194 '''copy changes from other branches onto the current branch
3195
3195
3196 This command uses Mercurial's merge logic to copy individual
3196 This command uses Mercurial's merge logic to copy individual
3197 changes from other branches without merging branches in the
3197 changes from other branches without merging branches in the
3198 history graph. This is sometimes known as 'backporting' or
3198 history graph. This is sometimes known as 'backporting' or
3199 'cherry-picking'. By default, graft will copy user, date, and
3199 'cherry-picking'. By default, graft will copy user, date, and
3200 description from the source changesets.
3200 description from the source changesets.
3201
3201
3202 Changesets that are ancestors of the current revision, that have
3202 Changesets that are ancestors of the current revision, that have
3203 already been grafted, or that are merges will be skipped.
3203 already been grafted, or that are merges will be skipped.
3204
3204
3205 If --log is specified, log messages will have a comment appended
3205 If --log is specified, log messages will have a comment appended
3206 of the form::
3206 of the form::
3207
3207
3208 (grafted from CHANGESETHASH)
3208 (grafted from CHANGESETHASH)
3209
3209
3210 If --force is specified, revisions will be grafted even if they
3210 If --force is specified, revisions will be grafted even if they
3211 are already ancestors of or have been grafted to the destination.
3211 are already ancestors of or have been grafted to the destination.
3212 This is useful when the revisions have since been backed out.
3212 This is useful when the revisions have since been backed out.
3213
3213
3214 If a graft merge results in conflicts, the graft process is
3214 If a graft merge results in conflicts, the graft process is
3215 interrupted so that the current merge can be manually resolved.
3215 interrupted so that the current merge can be manually resolved.
3216 Once all conflicts are addressed, the graft process can be
3216 Once all conflicts are addressed, the graft process can be
3217 continued with the -c/--continue option.
3217 continued with the -c/--continue option.
3218
3218
3219 .. note::
3219 .. note::
3220
3220
3221 The -c/--continue option does not reapply earlier options, except
3221 The -c/--continue option does not reapply earlier options, except
3222 for --force.
3222 for --force.
3223
3223
3224 .. container:: verbose
3224 .. container:: verbose
3225
3225
3226 Examples:
3226 Examples:
3227
3227
3228 - copy a single change to the stable branch and edit its description::
3228 - copy a single change to the stable branch and edit its description::
3229
3229
3230 hg update stable
3230 hg update stable
3231 hg graft --edit 9393
3231 hg graft --edit 9393
3232
3232
3233 - graft a range of changesets with one exception, updating dates::
3233 - graft a range of changesets with one exception, updating dates::
3234
3234
3235 hg graft -D "2085::2093 and not 2091"
3235 hg graft -D "2085::2093 and not 2091"
3236
3236
3237 - continue a graft after resolving conflicts::
3237 - continue a graft after resolving conflicts::
3238
3238
3239 hg graft -c
3239 hg graft -c
3240
3240
3241 - show the source of a grafted changeset::
3241 - show the source of a grafted changeset::
3242
3242
3243 hg log --debug -r .
3243 hg log --debug -r .
3244
3244
3245 See :hg:`help revisions` and :hg:`help revsets` for more about
3245 See :hg:`help revisions` and :hg:`help revsets` for more about
3246 specifying revisions.
3246 specifying revisions.
3247
3247
3248 Returns 0 on successful completion.
3248 Returns 0 on successful completion.
3249 '''
3249 '''
3250
3250
3251 revs = list(revs)
3251 revs = list(revs)
3252 revs.extend(opts['rev'])
3252 revs.extend(opts['rev'])
3253
3253
3254 if not opts.get('user') and opts.get('currentuser'):
3254 if not opts.get('user') and opts.get('currentuser'):
3255 opts['user'] = ui.username()
3255 opts['user'] = ui.username()
3256 if not opts.get('date') and opts.get('currentdate'):
3256 if not opts.get('date') and opts.get('currentdate'):
3257 opts['date'] = "%d %d" % util.makedate()
3257 opts['date'] = "%d %d" % util.makedate()
3258
3258
3259 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3259 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3260
3260
3261 cont = False
3261 cont = False
3262 if opts['continue']:
3262 if opts['continue']:
3263 cont = True
3263 cont = True
3264 if revs:
3264 if revs:
3265 raise util.Abort(_("can't specify --continue and revisions"))
3265 raise util.Abort(_("can't specify --continue and revisions"))
3266 # read in unfinished revisions
3266 # read in unfinished revisions
3267 try:
3267 try:
3268 nodes = repo.opener.read('graftstate').splitlines()
3268 nodes = repo.opener.read('graftstate').splitlines()
3269 revs = [repo[node].rev() for node in nodes]
3269 revs = [repo[node].rev() for node in nodes]
3270 except IOError, inst:
3270 except IOError, inst:
3271 if inst.errno != errno.ENOENT:
3271 if inst.errno != errno.ENOENT:
3272 raise
3272 raise
3273 raise util.Abort(_("no graft state found, can't continue"))
3273 raise util.Abort(_("no graft state found, can't continue"))
3274 else:
3274 else:
3275 cmdutil.checkunfinished(repo)
3275 cmdutil.checkunfinished(repo)
3276 cmdutil.bailifchanged(repo)
3276 cmdutil.bailifchanged(repo)
3277 if not revs:
3277 if not revs:
3278 raise util.Abort(_('no revisions specified'))
3278 raise util.Abort(_('no revisions specified'))
3279 revs = scmutil.revrange(repo, revs)
3279 revs = scmutil.revrange(repo, revs)
3280
3280
3281 # check for merges
3281 # check for merges
3282 for rev in repo.revs('%ld and merge()', revs):
3282 for rev in repo.revs('%ld and merge()', revs):
3283 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3283 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3284 revs.remove(rev)
3284 revs.remove(rev)
3285 if not revs:
3285 if not revs:
3286 return -1
3286 return -1
3287
3287
3288 # Don't check in the --continue case, in effect retaining --force across
3288 # Don't check in the --continue case, in effect retaining --force across
3289 # --continues. That's because without --force, any revisions we decided to
3289 # --continues. That's because without --force, any revisions we decided to
3290 # skip would have been filtered out here, so they wouldn't have made their
3290 # skip would have been filtered out here, so they wouldn't have made their
3291 # way to the graftstate. With --force, any revisions we would have otherwise
3291 # way to the graftstate. With --force, any revisions we would have otherwise
3292 # skipped would not have been filtered out, and if they hadn't been applied
3292 # skipped would not have been filtered out, and if they hadn't been applied
3293 # already, they'd have been in the graftstate.
3293 # already, they'd have been in the graftstate.
3294 if not (cont or opts.get('force')):
3294 if not (cont or opts.get('force')):
3295 # check for ancestors of dest branch
3295 # check for ancestors of dest branch
3296 crev = repo['.'].rev()
3296 crev = repo['.'].rev()
3297 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3297 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3298 # Cannot use x.remove(y) on smart set, this has to be a list.
3298 # Cannot use x.remove(y) on smart set, this has to be a list.
3299 # XXX make this lazy in the future
3299 # XXX make this lazy in the future
3300 revs = list(revs)
3300 revs = list(revs)
3301 # don't mutate while iterating, create a copy
3301 # don't mutate while iterating, create a copy
3302 for rev in list(revs):
3302 for rev in list(revs):
3303 if rev in ancestors:
3303 if rev in ancestors:
3304 ui.warn(_('skipping ancestor revision %s\n') % rev)
3304 ui.warn(_('skipping ancestor revision %s\n') % rev)
3305 # XXX remove on list is slow
3305 # XXX remove on list is slow
3306 revs.remove(rev)
3306 revs.remove(rev)
3307 if not revs:
3307 if not revs:
3308 return -1
3308 return -1
3309
3309
3310 # analyze revs for earlier grafts
3310 # analyze revs for earlier grafts
3311 ids = {}
3311 ids = {}
3312 for ctx in repo.set("%ld", revs):
3312 for ctx in repo.set("%ld", revs):
3313 ids[ctx.hex()] = ctx.rev()
3313 ids[ctx.hex()] = ctx.rev()
3314 n = ctx.extra().get('source')
3314 n = ctx.extra().get('source')
3315 if n:
3315 if n:
3316 ids[n] = ctx.rev()
3316 ids[n] = ctx.rev()
3317
3317
3318 # check ancestors for earlier grafts
3318 # check ancestors for earlier grafts
3319 ui.debug('scanning for duplicate grafts\n')
3319 ui.debug('scanning for duplicate grafts\n')
3320
3320
3321 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3321 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3322 ctx = repo[rev]
3322 ctx = repo[rev]
3323 n = ctx.extra().get('source')
3323 n = ctx.extra().get('source')
3324 if n in ids:
3324 if n in ids:
3325 try:
3325 try:
3326 r = repo[n].rev()
3326 r = repo[n].rev()
3327 except error.RepoLookupError:
3327 except error.RepoLookupError:
3328 r = None
3328 r = None
3329 if r in revs:
3329 if r in revs:
3330 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3330 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3331 % (r, rev))
3331 % (r, rev))
3332 revs.remove(r)
3332 revs.remove(r)
3333 elif ids[n] in revs:
3333 elif ids[n] in revs:
3334 if r is None:
3334 if r is None:
3335 ui.warn(_('skipping already grafted revision %s '
3335 ui.warn(_('skipping already grafted revision %s '
3336 '(%s also has unknown origin %s)\n')
3336 '(%s also has unknown origin %s)\n')
3337 % (ids[n], rev, n))
3337 % (ids[n], rev, n))
3338 else:
3338 else:
3339 ui.warn(_('skipping already grafted revision %s '
3339 ui.warn(_('skipping already grafted revision %s '
3340 '(%s also has origin %d)\n')
3340 '(%s also has origin %d)\n')
3341 % (ids[n], rev, r))
3341 % (ids[n], rev, r))
3342 revs.remove(ids[n])
3342 revs.remove(ids[n])
3343 elif ctx.hex() in ids:
3343 elif ctx.hex() in ids:
3344 r = ids[ctx.hex()]
3344 r = ids[ctx.hex()]
3345 ui.warn(_('skipping already grafted revision %s '
3345 ui.warn(_('skipping already grafted revision %s '
3346 '(was grafted from %d)\n') % (r, rev))
3346 '(was grafted from %d)\n') % (r, rev))
3347 revs.remove(r)
3347 revs.remove(r)
3348 if not revs:
3348 if not revs:
3349 return -1
3349 return -1
3350
3350
3351 wlock = repo.wlock()
3351 wlock = repo.wlock()
3352 try:
3352 try:
3353 current = repo['.']
3353 current = repo['.']
3354 for pos, ctx in enumerate(repo.set("%ld", revs)):
3354 for pos, ctx in enumerate(repo.set("%ld", revs)):
3355
3355
3356 ui.status(_('grafting revision %s\n') % ctx.rev())
3356 ui.status(_('grafting revision %s\n') % ctx.rev())
3357 if opts.get('dry_run'):
3357 if opts.get('dry_run'):
3358 continue
3358 continue
3359
3359
3360 source = ctx.extra().get('source')
3360 source = ctx.extra().get('source')
3361 if not source:
3361 if not source:
3362 source = ctx.hex()
3362 source = ctx.hex()
3363 extra = {'source': source}
3363 extra = {'source': source}
3364 user = ctx.user()
3364 user = ctx.user()
3365 if opts.get('user'):
3365 if opts.get('user'):
3366 user = opts['user']
3366 user = opts['user']
3367 date = ctx.date()
3367 date = ctx.date()
3368 if opts.get('date'):
3368 if opts.get('date'):
3369 date = opts['date']
3369 date = opts['date']
3370 message = ctx.description()
3370 message = ctx.description()
3371 if opts.get('log'):
3371 if opts.get('log'):
3372 message += '\n(grafted from %s)' % ctx.hex()
3372 message += '\n(grafted from %s)' % ctx.hex()
3373
3373
3374 # we don't merge the first commit when continuing
3374 # we don't merge the first commit when continuing
3375 if not cont:
3375 if not cont:
3376 # perform the graft merge with p1(rev) as 'ancestor'
3376 # perform the graft merge with p1(rev) as 'ancestor'
3377 try:
3377 try:
3378 # ui.forcemerge is an internal variable, do not document
3378 # ui.forcemerge is an internal variable, do not document
3379 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3379 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3380 'graft')
3380 'graft')
3381 stats = mergemod.update(repo, ctx.node(), True, True, False,
3381 stats = mergemod.update(repo, ctx.node(), True, True, False,
3382 ctx.p1().node(),
3382 ctx.p1().node(),
3383 labels=['local', 'graft'])
3383 labels=['local', 'graft'])
3384 finally:
3384 finally:
3385 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3385 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3386 # report any conflicts
3386 # report any conflicts
3387 if stats and stats[3] > 0:
3387 if stats and stats[3] > 0:
3388 # write out state for --continue
3388 # write out state for --continue
3389 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3389 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3390 repo.opener.write('graftstate', ''.join(nodelines))
3390 repo.opener.write('graftstate', ''.join(nodelines))
3391 raise util.Abort(
3391 raise util.Abort(
3392 _("unresolved conflicts, can't continue"),
3392 _("unresolved conflicts, can't continue"),
3393 hint=_('use hg resolve and hg graft --continue'))
3393 hint=_('use hg resolve and hg graft --continue'))
3394 else:
3394 else:
3395 cont = False
3395 cont = False
3396
3396
3397 # drop the second merge parent
3397 # drop the second merge parent
3398 repo.dirstate.beginparentchange()
3398 repo.dirstate.beginparentchange()
3399 repo.setparents(current.node(), nullid)
3399 repo.setparents(current.node(), nullid)
3400 repo.dirstate.write()
3400 repo.dirstate.write()
3401 # fix up dirstate for copies and renames
3401 # fix up dirstate for copies and renames
3402 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3402 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3403 repo.dirstate.endparentchange()
3403 repo.dirstate.endparentchange()
3404
3404
3405 # commit
3405 # commit
3406 node = repo.commit(text=message, user=user,
3406 node = repo.commit(text=message, user=user,
3407 date=date, extra=extra, editor=editor)
3407 date=date, extra=extra, editor=editor)
3408 if node is None:
3408 if node is None:
3409 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3409 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3410 else:
3410 else:
3411 current = repo[node]
3411 current = repo[node]
3412 finally:
3412 finally:
3413 wlock.release()
3413 wlock.release()
3414
3414
3415 # remove state when we complete successfully
3415 # remove state when we complete successfully
3416 if not opts.get('dry_run'):
3416 if not opts.get('dry_run'):
3417 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3417 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3418
3418
3419 return 0
3419 return 0
3420
3420
3421 @command('grep',
3421 @command('grep',
3422 [('0', 'print0', None, _('end fields with NUL')),
3422 [('0', 'print0', None, _('end fields with NUL')),
3423 ('', 'all', None, _('print all revisions that match')),
3423 ('', 'all', None, _('print all revisions that match')),
3424 ('a', 'text', None, _('treat all files as text')),
3424 ('a', 'text', None, _('treat all files as text')),
3425 ('f', 'follow', None,
3425 ('f', 'follow', None,
3426 _('follow changeset history,'
3426 _('follow changeset history,'
3427 ' or file history across copies and renames')),
3427 ' or file history across copies and renames')),
3428 ('i', 'ignore-case', None, _('ignore case when matching')),
3428 ('i', 'ignore-case', None, _('ignore case when matching')),
3429 ('l', 'files-with-matches', None,
3429 ('l', 'files-with-matches', None,
3430 _('print only filenames and revisions that match')),
3430 _('print only filenames and revisions that match')),
3431 ('n', 'line-number', None, _('print matching line numbers')),
3431 ('n', 'line-number', None, _('print matching line numbers')),
3432 ('r', 'rev', [],
3432 ('r', 'rev', [],
3433 _('only search files changed within revision range'), _('REV')),
3433 _('only search files changed within revision range'), _('REV')),
3434 ('u', 'user', None, _('list the author (long with -v)')),
3434 ('u', 'user', None, _('list the author (long with -v)')),
3435 ('d', 'date', None, _('list the date (short with -q)')),
3435 ('d', 'date', None, _('list the date (short with -q)')),
3436 ] + walkopts,
3436 ] + walkopts,
3437 _('[OPTION]... PATTERN [FILE]...'),
3437 _('[OPTION]... PATTERN [FILE]...'),
3438 inferrepo=True)
3438 inferrepo=True)
3439 def grep(ui, repo, pattern, *pats, **opts):
3439 def grep(ui, repo, pattern, *pats, **opts):
3440 """search for a pattern in specified files and revisions
3440 """search for a pattern in specified files and revisions
3441
3441
3442 Search revisions of files for a regular expression.
3442 Search revisions of files for a regular expression.
3443
3443
3444 This command behaves differently than Unix grep. It only accepts
3444 This command behaves differently than Unix grep. It only accepts
3445 Python/Perl regexps. It searches repository history, not the
3445 Python/Perl regexps. It searches repository history, not the
3446 working directory. It always prints the revision number in which a
3446 working directory. It always prints the revision number in which a
3447 match appears.
3447 match appears.
3448
3448
3449 By default, grep only prints output for the first revision of a
3449 By default, grep only prints output for the first revision of a
3450 file in which it finds a match. To get it to print every revision
3450 file in which it finds a match. To get it to print every revision
3451 that contains a change in match status ("-" for a match that
3451 that contains a change in match status ("-" for a match that
3452 becomes a non-match, or "+" for a non-match that becomes a match),
3452 becomes a non-match, or "+" for a non-match that becomes a match),
3453 use the --all flag.
3453 use the --all flag.
3454
3454
3455 Returns 0 if a match is found, 1 otherwise.
3455 Returns 0 if a match is found, 1 otherwise.
3456 """
3456 """
3457 reflags = re.M
3457 reflags = re.M
3458 if opts.get('ignore_case'):
3458 if opts.get('ignore_case'):
3459 reflags |= re.I
3459 reflags |= re.I
3460 try:
3460 try:
3461 regexp = util.re.compile(pattern, reflags)
3461 regexp = util.re.compile(pattern, reflags)
3462 except re.error, inst:
3462 except re.error, inst:
3463 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3463 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3464 return 1
3464 return 1
3465 sep, eol = ':', '\n'
3465 sep, eol = ':', '\n'
3466 if opts.get('print0'):
3466 if opts.get('print0'):
3467 sep = eol = '\0'
3467 sep = eol = '\0'
3468
3468
3469 getfile = util.lrucachefunc(repo.file)
3469 getfile = util.lrucachefunc(repo.file)
3470
3470
3471 def matchlines(body):
3471 def matchlines(body):
3472 begin = 0
3472 begin = 0
3473 linenum = 0
3473 linenum = 0
3474 while begin < len(body):
3474 while begin < len(body):
3475 match = regexp.search(body, begin)
3475 match = regexp.search(body, begin)
3476 if not match:
3476 if not match:
3477 break
3477 break
3478 mstart, mend = match.span()
3478 mstart, mend = match.span()
3479 linenum += body.count('\n', begin, mstart) + 1
3479 linenum += body.count('\n', begin, mstart) + 1
3480 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3480 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3481 begin = body.find('\n', mend) + 1 or len(body) + 1
3481 begin = body.find('\n', mend) + 1 or len(body) + 1
3482 lend = begin - 1
3482 lend = begin - 1
3483 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3483 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3484
3484
3485 class linestate(object):
3485 class linestate(object):
3486 def __init__(self, line, linenum, colstart, colend):
3486 def __init__(self, line, linenum, colstart, colend):
3487 self.line = line
3487 self.line = line
3488 self.linenum = linenum
3488 self.linenum = linenum
3489 self.colstart = colstart
3489 self.colstart = colstart
3490 self.colend = colend
3490 self.colend = colend
3491
3491
3492 def __hash__(self):
3492 def __hash__(self):
3493 return hash((self.linenum, self.line))
3493 return hash((self.linenum, self.line))
3494
3494
3495 def __eq__(self, other):
3495 def __eq__(self, other):
3496 return self.line == other.line
3496 return self.line == other.line
3497
3497
3498 def __iter__(self):
3498 def __iter__(self):
3499 yield (self.line[:self.colstart], '')
3499 yield (self.line[:self.colstart], '')
3500 yield (self.line[self.colstart:self.colend], 'grep.match')
3500 yield (self.line[self.colstart:self.colend], 'grep.match')
3501 rest = self.line[self.colend:]
3501 rest = self.line[self.colend:]
3502 while rest != '':
3502 while rest != '':
3503 match = regexp.search(rest)
3503 match = regexp.search(rest)
3504 if not match:
3504 if not match:
3505 yield (rest, '')
3505 yield (rest, '')
3506 break
3506 break
3507 mstart, mend = match.span()
3507 mstart, mend = match.span()
3508 yield (rest[:mstart], '')
3508 yield (rest[:mstart], '')
3509 yield (rest[mstart:mend], 'grep.match')
3509 yield (rest[mstart:mend], 'grep.match')
3510 rest = rest[mend:]
3510 rest = rest[mend:]
3511
3511
3512 matches = {}
3512 matches = {}
3513 copies = {}
3513 copies = {}
3514 def grepbody(fn, rev, body):
3514 def grepbody(fn, rev, body):
3515 matches[rev].setdefault(fn, [])
3515 matches[rev].setdefault(fn, [])
3516 m = matches[rev][fn]
3516 m = matches[rev][fn]
3517 for lnum, cstart, cend, line in matchlines(body):
3517 for lnum, cstart, cend, line in matchlines(body):
3518 s = linestate(line, lnum, cstart, cend)
3518 s = linestate(line, lnum, cstart, cend)
3519 m.append(s)
3519 m.append(s)
3520
3520
3521 def difflinestates(a, b):
3521 def difflinestates(a, b):
3522 sm = difflib.SequenceMatcher(None, a, b)
3522 sm = difflib.SequenceMatcher(None, a, b)
3523 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3523 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3524 if tag == 'insert':
3524 if tag == 'insert':
3525 for i in xrange(blo, bhi):
3525 for i in xrange(blo, bhi):
3526 yield ('+', b[i])
3526 yield ('+', b[i])
3527 elif tag == 'delete':
3527 elif tag == 'delete':
3528 for i in xrange(alo, ahi):
3528 for i in xrange(alo, ahi):
3529 yield ('-', a[i])
3529 yield ('-', a[i])
3530 elif tag == 'replace':
3530 elif tag == 'replace':
3531 for i in xrange(alo, ahi):
3531 for i in xrange(alo, ahi):
3532 yield ('-', a[i])
3532 yield ('-', a[i])
3533 for i in xrange(blo, bhi):
3533 for i in xrange(blo, bhi):
3534 yield ('+', b[i])
3534 yield ('+', b[i])
3535
3535
3536 def display(fn, ctx, pstates, states):
3536 def display(fn, ctx, pstates, states):
3537 rev = ctx.rev()
3537 rev = ctx.rev()
3538 datefunc = ui.quiet and util.shortdate or util.datestr
3538 datefunc = ui.quiet and util.shortdate or util.datestr
3539 found = False
3539 found = False
3540 @util.cachefunc
3540 @util.cachefunc
3541 def binary():
3541 def binary():
3542 flog = getfile(fn)
3542 flog = getfile(fn)
3543 return util.binary(flog.read(ctx.filenode(fn)))
3543 return util.binary(flog.read(ctx.filenode(fn)))
3544
3544
3545 if opts.get('all'):
3545 if opts.get('all'):
3546 iter = difflinestates(pstates, states)
3546 iter = difflinestates(pstates, states)
3547 else:
3547 else:
3548 iter = [('', l) for l in states]
3548 iter = [('', l) for l in states]
3549 for change, l in iter:
3549 for change, l in iter:
3550 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3550 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3551
3551
3552 if opts.get('line_number'):
3552 if opts.get('line_number'):
3553 cols.append((str(l.linenum), 'grep.linenumber'))
3553 cols.append((str(l.linenum), 'grep.linenumber'))
3554 if opts.get('all'):
3554 if opts.get('all'):
3555 cols.append((change, 'grep.change'))
3555 cols.append((change, 'grep.change'))
3556 if opts.get('user'):
3556 if opts.get('user'):
3557 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3557 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3558 if opts.get('date'):
3558 if opts.get('date'):
3559 cols.append((datefunc(ctx.date()), 'grep.date'))
3559 cols.append((datefunc(ctx.date()), 'grep.date'))
3560 for col, label in cols[:-1]:
3560 for col, label in cols[:-1]:
3561 ui.write(col, label=label)
3561 ui.write(col, label=label)
3562 ui.write(sep, label='grep.sep')
3562 ui.write(sep, label='grep.sep')
3563 ui.write(cols[-1][0], label=cols[-1][1])
3563 ui.write(cols[-1][0], label=cols[-1][1])
3564 if not opts.get('files_with_matches'):
3564 if not opts.get('files_with_matches'):
3565 ui.write(sep, label='grep.sep')
3565 ui.write(sep, label='grep.sep')
3566 if not opts.get('text') and binary():
3566 if not opts.get('text') and binary():
3567 ui.write(" Binary file matches")
3567 ui.write(" Binary file matches")
3568 else:
3568 else:
3569 for s, label in l:
3569 for s, label in l:
3570 ui.write(s, label=label)
3570 ui.write(s, label=label)
3571 ui.write(eol)
3571 ui.write(eol)
3572 found = True
3572 found = True
3573 if opts.get('files_with_matches'):
3573 if opts.get('files_with_matches'):
3574 break
3574 break
3575 return found
3575 return found
3576
3576
3577 skip = {}
3577 skip = {}
3578 revfiles = {}
3578 revfiles = {}
3579 matchfn = scmutil.match(repo[None], pats, opts)
3579 matchfn = scmutil.match(repo[None], pats, opts)
3580 found = False
3580 found = False
3581 follow = opts.get('follow')
3581 follow = opts.get('follow')
3582
3582
3583 def prep(ctx, fns):
3583 def prep(ctx, fns):
3584 rev = ctx.rev()
3584 rev = ctx.rev()
3585 pctx = ctx.p1()
3585 pctx = ctx.p1()
3586 parent = pctx.rev()
3586 parent = pctx.rev()
3587 matches.setdefault(rev, {})
3587 matches.setdefault(rev, {})
3588 matches.setdefault(parent, {})
3588 matches.setdefault(parent, {})
3589 files = revfiles.setdefault(rev, [])
3589 files = revfiles.setdefault(rev, [])
3590 for fn in fns:
3590 for fn in fns:
3591 flog = getfile(fn)
3591 flog = getfile(fn)
3592 try:
3592 try:
3593 fnode = ctx.filenode(fn)
3593 fnode = ctx.filenode(fn)
3594 except error.LookupError:
3594 except error.LookupError:
3595 continue
3595 continue
3596
3596
3597 copied = flog.renamed(fnode)
3597 copied = flog.renamed(fnode)
3598 copy = follow and copied and copied[0]
3598 copy = follow and copied and copied[0]
3599 if copy:
3599 if copy:
3600 copies.setdefault(rev, {})[fn] = copy
3600 copies.setdefault(rev, {})[fn] = copy
3601 if fn in skip:
3601 if fn in skip:
3602 if copy:
3602 if copy:
3603 skip[copy] = True
3603 skip[copy] = True
3604 continue
3604 continue
3605 files.append(fn)
3605 files.append(fn)
3606
3606
3607 if fn not in matches[rev]:
3607 if fn not in matches[rev]:
3608 grepbody(fn, rev, flog.read(fnode))
3608 grepbody(fn, rev, flog.read(fnode))
3609
3609
3610 pfn = copy or fn
3610 pfn = copy or fn
3611 if pfn not in matches[parent]:
3611 if pfn not in matches[parent]:
3612 try:
3612 try:
3613 fnode = pctx.filenode(pfn)
3613 fnode = pctx.filenode(pfn)
3614 grepbody(pfn, parent, flog.read(fnode))
3614 grepbody(pfn, parent, flog.read(fnode))
3615 except error.LookupError:
3615 except error.LookupError:
3616 pass
3616 pass
3617
3617
3618 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3618 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3619 rev = ctx.rev()
3619 rev = ctx.rev()
3620 parent = ctx.p1().rev()
3620 parent = ctx.p1().rev()
3621 for fn in sorted(revfiles.get(rev, [])):
3621 for fn in sorted(revfiles.get(rev, [])):
3622 states = matches[rev][fn]
3622 states = matches[rev][fn]
3623 copy = copies.get(rev, {}).get(fn)
3623 copy = copies.get(rev, {}).get(fn)
3624 if fn in skip:
3624 if fn in skip:
3625 if copy:
3625 if copy:
3626 skip[copy] = True
3626 skip[copy] = True
3627 continue
3627 continue
3628 pstates = matches.get(parent, {}).get(copy or fn, [])
3628 pstates = matches.get(parent, {}).get(copy or fn, [])
3629 if pstates or states:
3629 if pstates or states:
3630 r = display(fn, ctx, pstates, states)
3630 r = display(fn, ctx, pstates, states)
3631 found = found or r
3631 found = found or r
3632 if r and not opts.get('all'):
3632 if r and not opts.get('all'):
3633 skip[fn] = True
3633 skip[fn] = True
3634 if copy:
3634 if copy:
3635 skip[copy] = True
3635 skip[copy] = True
3636 del matches[rev]
3636 del matches[rev]
3637 del revfiles[rev]
3637 del revfiles[rev]
3638
3638
3639 return not found
3639 return not found
3640
3640
3641 @command('heads',
3641 @command('heads',
3642 [('r', 'rev', '',
3642 [('r', 'rev', '',
3643 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3643 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3644 ('t', 'topo', False, _('show topological heads only')),
3644 ('t', 'topo', False, _('show topological heads only')),
3645 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3645 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3646 ('c', 'closed', False, _('show normal and closed branch heads')),
3646 ('c', 'closed', False, _('show normal and closed branch heads')),
3647 ] + templateopts,
3647 ] + templateopts,
3648 _('[-ct] [-r STARTREV] [REV]...'))
3648 _('[-ct] [-r STARTREV] [REV]...'))
3649 def heads(ui, repo, *branchrevs, **opts):
3649 def heads(ui, repo, *branchrevs, **opts):
3650 """show branch heads
3650 """show branch heads
3651
3651
3652 With no arguments, show all open branch heads in the repository.
3652 With no arguments, show all open branch heads in the repository.
3653 Branch heads are changesets that have no descendants on the
3653 Branch heads are changesets that have no descendants on the
3654 same branch. They are where development generally takes place and
3654 same branch. They are where development generally takes place and
3655 are the usual targets for update and merge operations.
3655 are the usual targets for update and merge operations.
3656
3656
3657 If one or more REVs are given, only open branch heads on the
3657 If one or more REVs are given, only open branch heads on the
3658 branches associated with the specified changesets are shown. This
3658 branches associated with the specified changesets are shown. This
3659 means that you can use :hg:`heads .` to see the heads on the
3659 means that you can use :hg:`heads .` to see the heads on the
3660 currently checked-out branch.
3660 currently checked-out branch.
3661
3661
3662 If -c/--closed is specified, also show branch heads marked closed
3662 If -c/--closed is specified, also show branch heads marked closed
3663 (see :hg:`commit --close-branch`).
3663 (see :hg:`commit --close-branch`).
3664
3664
3665 If STARTREV is specified, only those heads that are descendants of
3665 If STARTREV is specified, only those heads that are descendants of
3666 STARTREV will be displayed.
3666 STARTREV will be displayed.
3667
3667
3668 If -t/--topo is specified, named branch mechanics will be ignored and only
3668 If -t/--topo is specified, named branch mechanics will be ignored and only
3669 topological heads (changesets with no children) will be shown.
3669 topological heads (changesets with no children) will be shown.
3670
3670
3671 Returns 0 if matching heads are found, 1 if not.
3671 Returns 0 if matching heads are found, 1 if not.
3672 """
3672 """
3673
3673
3674 start = None
3674 start = None
3675 if 'rev' in opts:
3675 if 'rev' in opts:
3676 start = scmutil.revsingle(repo, opts['rev'], None).node()
3676 start = scmutil.revsingle(repo, opts['rev'], None).node()
3677
3677
3678 if opts.get('topo'):
3678 if opts.get('topo'):
3679 heads = [repo[h] for h in repo.heads(start)]
3679 heads = [repo[h] for h in repo.heads(start)]
3680 else:
3680 else:
3681 heads = []
3681 heads = []
3682 for branch in repo.branchmap():
3682 for branch in repo.branchmap():
3683 heads += repo.branchheads(branch, start, opts.get('closed'))
3683 heads += repo.branchheads(branch, start, opts.get('closed'))
3684 heads = [repo[h] for h in heads]
3684 heads = [repo[h] for h in heads]
3685
3685
3686 if branchrevs:
3686 if branchrevs:
3687 branches = set(repo[br].branch() for br in branchrevs)
3687 branches = set(repo[br].branch() for br in branchrevs)
3688 heads = [h for h in heads if h.branch() in branches]
3688 heads = [h for h in heads if h.branch() in branches]
3689
3689
3690 if opts.get('active') and branchrevs:
3690 if opts.get('active') and branchrevs:
3691 dagheads = repo.heads(start)
3691 dagheads = repo.heads(start)
3692 heads = [h for h in heads if h.node() in dagheads]
3692 heads = [h for h in heads if h.node() in dagheads]
3693
3693
3694 if branchrevs:
3694 if branchrevs:
3695 haveheads = set(h.branch() for h in heads)
3695 haveheads = set(h.branch() for h in heads)
3696 if branches - haveheads:
3696 if branches - haveheads:
3697 headless = ', '.join(b for b in branches - haveheads)
3697 headless = ', '.join(b for b in branches - haveheads)
3698 msg = _('no open branch heads found on branches %s')
3698 msg = _('no open branch heads found on branches %s')
3699 if opts.get('rev'):
3699 if opts.get('rev'):
3700 msg += _(' (started at %s)') % opts['rev']
3700 msg += _(' (started at %s)') % opts['rev']
3701 ui.warn((msg + '\n') % headless)
3701 ui.warn((msg + '\n') % headless)
3702
3702
3703 if not heads:
3703 if not heads:
3704 return 1
3704 return 1
3705
3705
3706 heads = sorted(heads, key=lambda x: -x.rev())
3706 heads = sorted(heads, key=lambda x: -x.rev())
3707 displayer = cmdutil.show_changeset(ui, repo, opts)
3707 displayer = cmdutil.show_changeset(ui, repo, opts)
3708 for ctx in heads:
3708 for ctx in heads:
3709 displayer.show(ctx)
3709 displayer.show(ctx)
3710 displayer.close()
3710 displayer.close()
3711
3711
3712 @command('help',
3712 @command('help',
3713 [('e', 'extension', None, _('show only help for extensions')),
3713 [('e', 'extension', None, _('show only help for extensions')),
3714 ('c', 'command', None, _('show only help for commands')),
3714 ('c', 'command', None, _('show only help for commands')),
3715 ('k', 'keyword', '', _('show topics matching keyword')),
3715 ('k', 'keyword', '', _('show topics matching keyword')),
3716 ],
3716 ],
3717 _('[-ec] [TOPIC]'),
3717 _('[-ec] [TOPIC]'),
3718 norepo=True)
3718 norepo=True)
3719 def help_(ui, name=None, **opts):
3719 def help_(ui, name=None, **opts):
3720 """show help for a given topic or a help overview
3720 """show help for a given topic or a help overview
3721
3721
3722 With no arguments, print a list of commands with short help messages.
3722 With no arguments, print a list of commands with short help messages.
3723
3723
3724 Given a topic, extension, or command name, print help for that
3724 Given a topic, extension, or command name, print help for that
3725 topic.
3725 topic.
3726
3726
3727 Returns 0 if successful.
3727 Returns 0 if successful.
3728 """
3728 """
3729
3729
3730 textwidth = min(ui.termwidth(), 80) - 2
3730 textwidth = min(ui.termwidth(), 80) - 2
3731
3731
3732 keep = ui.verbose and ['verbose'] or []
3732 keep = ui.verbose and ['verbose'] or []
3733 text = help.help_(ui, name, **opts)
3733 text = help.help_(ui, name, **opts)
3734
3734
3735 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3735 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3736 if 'verbose' in pruned:
3736 if 'verbose' in pruned:
3737 keep.append('omitted')
3737 keep.append('omitted')
3738 else:
3738 else:
3739 keep.append('notomitted')
3739 keep.append('notomitted')
3740 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3740 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3741 ui.write(formatted)
3741 ui.write(formatted)
3742
3742
3743
3743
3744 @command('identify|id',
3744 @command('identify|id',
3745 [('r', 'rev', '',
3745 [('r', 'rev', '',
3746 _('identify the specified revision'), _('REV')),
3746 _('identify the specified revision'), _('REV')),
3747 ('n', 'num', None, _('show local revision number')),
3747 ('n', 'num', None, _('show local revision number')),
3748 ('i', 'id', None, _('show global revision id')),
3748 ('i', 'id', None, _('show global revision id')),
3749 ('b', 'branch', None, _('show branch')),
3749 ('b', 'branch', None, _('show branch')),
3750 ('t', 'tags', None, _('show tags')),
3750 ('t', 'tags', None, _('show tags')),
3751 ('B', 'bookmarks', None, _('show bookmarks')),
3751 ('B', 'bookmarks', None, _('show bookmarks')),
3752 ] + remoteopts,
3752 ] + remoteopts,
3753 _('[-nibtB] [-r REV] [SOURCE]'),
3753 _('[-nibtB] [-r REV] [SOURCE]'),
3754 optionalrepo=True)
3754 optionalrepo=True)
3755 def identify(ui, repo, source=None, rev=None,
3755 def identify(ui, repo, source=None, rev=None,
3756 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3756 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3757 """identify the working copy or specified revision
3757 """identify the working copy or specified revision
3758
3758
3759 Print a summary identifying the repository state at REV using one or
3759 Print a summary identifying the repository state at REV using one or
3760 two parent hash identifiers, followed by a "+" if the working
3760 two parent hash identifiers, followed by a "+" if the working
3761 directory has uncommitted changes, the branch name (if not default),
3761 directory has uncommitted changes, the branch name (if not default),
3762 a list of tags, and a list of bookmarks.
3762 a list of tags, and a list of bookmarks.
3763
3763
3764 When REV is not given, print a summary of the current state of the
3764 When REV is not given, print a summary of the current state of the
3765 repository.
3765 repository.
3766
3766
3767 Specifying a path to a repository root or Mercurial bundle will
3767 Specifying a path to a repository root or Mercurial bundle will
3768 cause lookup to operate on that repository/bundle.
3768 cause lookup to operate on that repository/bundle.
3769
3769
3770 .. container:: verbose
3770 .. container:: verbose
3771
3771
3772 Examples:
3772 Examples:
3773
3773
3774 - generate a build identifier for the working directory::
3774 - generate a build identifier for the working directory::
3775
3775
3776 hg id --id > build-id.dat
3776 hg id --id > build-id.dat
3777
3777
3778 - find the revision corresponding to a tag::
3778 - find the revision corresponding to a tag::
3779
3779
3780 hg id -n -r 1.3
3780 hg id -n -r 1.3
3781
3781
3782 - check the most recent revision of a remote repository::
3782 - check the most recent revision of a remote repository::
3783
3783
3784 hg id -r tip http://selenic.com/hg/
3784 hg id -r tip http://selenic.com/hg/
3785
3785
3786 Returns 0 if successful.
3786 Returns 0 if successful.
3787 """
3787 """
3788
3788
3789 if not repo and not source:
3789 if not repo and not source:
3790 raise util.Abort(_("there is no Mercurial repository here "
3790 raise util.Abort(_("there is no Mercurial repository here "
3791 "(.hg not found)"))
3791 "(.hg not found)"))
3792
3792
3793 hexfunc = ui.debugflag and hex or short
3793 hexfunc = ui.debugflag and hex or short
3794 default = not (num or id or branch or tags or bookmarks)
3794 default = not (num or id or branch or tags or bookmarks)
3795 output = []
3795 output = []
3796 revs = []
3796 revs = []
3797
3797
3798 if source:
3798 if source:
3799 source, branches = hg.parseurl(ui.expandpath(source))
3799 source, branches = hg.parseurl(ui.expandpath(source))
3800 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3800 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3801 repo = peer.local()
3801 repo = peer.local()
3802 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3802 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3803
3803
3804 if not repo:
3804 if not repo:
3805 if num or branch or tags:
3805 if num or branch or tags:
3806 raise util.Abort(
3806 raise util.Abort(
3807 _("can't query remote revision number, branch, or tags"))
3807 _("can't query remote revision number, branch, or tags"))
3808 if not rev and revs:
3808 if not rev and revs:
3809 rev = revs[0]
3809 rev = revs[0]
3810 if not rev:
3810 if not rev:
3811 rev = "tip"
3811 rev = "tip"
3812
3812
3813 remoterev = peer.lookup(rev)
3813 remoterev = peer.lookup(rev)
3814 if default or id:
3814 if default or id:
3815 output = [hexfunc(remoterev)]
3815 output = [hexfunc(remoterev)]
3816
3816
3817 def getbms():
3817 def getbms():
3818 bms = []
3818 bms = []
3819
3819
3820 if 'bookmarks' in peer.listkeys('namespaces'):
3820 if 'bookmarks' in peer.listkeys('namespaces'):
3821 hexremoterev = hex(remoterev)
3821 hexremoterev = hex(remoterev)
3822 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3822 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3823 if bmr == hexremoterev]
3823 if bmr == hexremoterev]
3824
3824
3825 return sorted(bms)
3825 return sorted(bms)
3826
3826
3827 if bookmarks:
3827 if bookmarks:
3828 output.extend(getbms())
3828 output.extend(getbms())
3829 elif default and not ui.quiet:
3829 elif default and not ui.quiet:
3830 # multiple bookmarks for a single parent separated by '/'
3830 # multiple bookmarks for a single parent separated by '/'
3831 bm = '/'.join(getbms())
3831 bm = '/'.join(getbms())
3832 if bm:
3832 if bm:
3833 output.append(bm)
3833 output.append(bm)
3834 else:
3834 else:
3835 if not rev:
3835 if not rev:
3836 ctx = repo[None]
3836 ctx = repo[None]
3837 parents = ctx.parents()
3837 parents = ctx.parents()
3838 changed = ""
3838 changed = ""
3839 if default or id or num:
3839 if default or id or num:
3840 if (util.any(repo.status())
3840 if (util.any(repo.status())
3841 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3841 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3842 changed = '+'
3842 changed = '+'
3843 if default or id:
3843 if default or id:
3844 output = ["%s%s" %
3844 output = ["%s%s" %
3845 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3845 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3846 if num:
3846 if num:
3847 output.append("%s%s" %
3847 output.append("%s%s" %
3848 ('+'.join([str(p.rev()) for p in parents]), changed))
3848 ('+'.join([str(p.rev()) for p in parents]), changed))
3849 else:
3849 else:
3850 ctx = scmutil.revsingle(repo, rev)
3850 ctx = scmutil.revsingle(repo, rev)
3851 if default or id:
3851 if default or id:
3852 output = [hexfunc(ctx.node())]
3852 output = [hexfunc(ctx.node())]
3853 if num:
3853 if num:
3854 output.append(str(ctx.rev()))
3854 output.append(str(ctx.rev()))
3855
3855
3856 if default and not ui.quiet:
3856 if default and not ui.quiet:
3857 b = ctx.branch()
3857 b = ctx.branch()
3858 if b != 'default':
3858 if b != 'default':
3859 output.append("(%s)" % b)
3859 output.append("(%s)" % b)
3860
3860
3861 # multiple tags for a single parent separated by '/'
3861 # multiple tags for a single parent separated by '/'
3862 t = '/'.join(ctx.tags())
3862 t = '/'.join(ctx.tags())
3863 if t:
3863 if t:
3864 output.append(t)
3864 output.append(t)
3865
3865
3866 # multiple bookmarks for a single parent separated by '/'
3866 # multiple bookmarks for a single parent separated by '/'
3867 bm = '/'.join(ctx.bookmarks())
3867 bm = '/'.join(ctx.bookmarks())
3868 if bm:
3868 if bm:
3869 output.append(bm)
3869 output.append(bm)
3870 else:
3870 else:
3871 if branch:
3871 if branch:
3872 output.append(ctx.branch())
3872 output.append(ctx.branch())
3873
3873
3874 if tags:
3874 if tags:
3875 output.extend(ctx.tags())
3875 output.extend(ctx.tags())
3876
3876
3877 if bookmarks:
3877 if bookmarks:
3878 output.extend(ctx.bookmarks())
3878 output.extend(ctx.bookmarks())
3879
3879
3880 ui.write("%s\n" % ' '.join(output))
3880 ui.write("%s\n" % ' '.join(output))
3881
3881
3882 @command('import|patch',
3882 @command('import|patch',
3883 [('p', 'strip', 1,
3883 [('p', 'strip', 1,
3884 _('directory strip option for patch. This has the same '
3884 _('directory strip option for patch. This has the same '
3885 'meaning as the corresponding patch option'), _('NUM')),
3885 'meaning as the corresponding patch option'), _('NUM')),
3886 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3886 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3887 ('e', 'edit', False, _('invoke editor on commit messages')),
3887 ('e', 'edit', False, _('invoke editor on commit messages')),
3888 ('f', 'force', None,
3888 ('f', 'force', None,
3889 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3889 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3890 ('', 'no-commit', None,
3890 ('', 'no-commit', None,
3891 _("don't commit, just update the working directory")),
3891 _("don't commit, just update the working directory")),
3892 ('', 'bypass', None,
3892 ('', 'bypass', None,
3893 _("apply patch without touching the working directory")),
3893 _("apply patch without touching the working directory")),
3894 ('', 'partial', None,
3894 ('', 'partial', None,
3895 _('commit even if some hunks fail')),
3895 _('commit even if some hunks fail')),
3896 ('', 'exact', None,
3896 ('', 'exact', None,
3897 _('apply patch to the nodes from which it was generated')),
3897 _('apply patch to the nodes from which it was generated')),
3898 ('', 'import-branch', None,
3898 ('', 'import-branch', None,
3899 _('use any branch information in patch (implied by --exact)'))] +
3899 _('use any branch information in patch (implied by --exact)'))] +
3900 commitopts + commitopts2 + similarityopts,
3900 commitopts + commitopts2 + similarityopts,
3901 _('[OPTION]... PATCH...'))
3901 _('[OPTION]... PATCH...'))
3902 def import_(ui, repo, patch1=None, *patches, **opts):
3902 def import_(ui, repo, patch1=None, *patches, **opts):
3903 """import an ordered set of patches
3903 """import an ordered set of patches
3904
3904
3905 Import a list of patches and commit them individually (unless
3905 Import a list of patches and commit them individually (unless
3906 --no-commit is specified).
3906 --no-commit is specified).
3907
3907
3908 Because import first applies changes to the working directory,
3908 Because import first applies changes to the working directory,
3909 import will abort if there are outstanding changes.
3909 import will abort if there are outstanding changes.
3910
3910
3911 You can import a patch straight from a mail message. Even patches
3911 You can import a patch straight from a mail message. Even patches
3912 as attachments work (to use the body part, it must have type
3912 as attachments work (to use the body part, it must have type
3913 text/plain or text/x-patch). From and Subject headers of email
3913 text/plain or text/x-patch). From and Subject headers of email
3914 message are used as default committer and commit message. All
3914 message are used as default committer and commit message. All
3915 text/plain body parts before first diff are added to commit
3915 text/plain body parts before first diff are added to commit
3916 message.
3916 message.
3917
3917
3918 If the imported patch was generated by :hg:`export`, user and
3918 If the imported patch was generated by :hg:`export`, user and
3919 description from patch override values from message headers and
3919 description from patch override values from message headers and
3920 body. Values given on command line with -m/--message and -u/--user
3920 body. Values given on command line with -m/--message and -u/--user
3921 override these.
3921 override these.
3922
3922
3923 If --exact is specified, import will set the working directory to
3923 If --exact is specified, import will set the working directory to
3924 the parent of each patch before applying it, and will abort if the
3924 the parent of each patch before applying it, and will abort if the
3925 resulting changeset has a different ID than the one recorded in
3925 resulting changeset has a different ID than the one recorded in
3926 the patch. This may happen due to character set problems or other
3926 the patch. This may happen due to character set problems or other
3927 deficiencies in the text patch format.
3927 deficiencies in the text patch format.
3928
3928
3929 Use --bypass to apply and commit patches directly to the
3929 Use --bypass to apply and commit patches directly to the
3930 repository, not touching the working directory. Without --exact,
3930 repository, not touching the working directory. Without --exact,
3931 patches will be applied on top of the working directory parent
3931 patches will be applied on top of the working directory parent
3932 revision.
3932 revision.
3933
3933
3934 With -s/--similarity, hg will attempt to discover renames and
3934 With -s/--similarity, hg will attempt to discover renames and
3935 copies in the patch in the same way as :hg:`addremove`.
3935 copies in the patch in the same way as :hg:`addremove`.
3936
3936
3937 Use --partial to ensure a changeset will be created from the patch
3937 Use --partial to ensure a changeset will be created from the patch
3938 even if some hunks fail to apply. Hunks that fail to apply will be
3938 even if some hunks fail to apply. Hunks that fail to apply will be
3939 written to a <target-file>.rej file. Conflicts can then be resolved
3939 written to a <target-file>.rej file. Conflicts can then be resolved
3940 by hand before :hg:`commit --amend` is run to update the created
3940 by hand before :hg:`commit --amend` is run to update the created
3941 changeset. This flag exists to let people import patches that
3941 changeset. This flag exists to let people import patches that
3942 partially apply without losing the associated metadata (author,
3942 partially apply without losing the associated metadata (author,
3943 date, description, ...). Note that when none of the hunk applies
3943 date, description, ...). Note that when none of the hunk applies
3944 cleanly, :hg:`import --partial` will create an empty changeset,
3944 cleanly, :hg:`import --partial` will create an empty changeset,
3945 importing only the patch metadata.
3945 importing only the patch metadata.
3946
3946
3947 To read a patch from standard input, use "-" as the patch name. If
3947 To read a patch from standard input, use "-" as the patch name. If
3948 a URL is specified, the patch will be downloaded from it.
3948 a URL is specified, the patch will be downloaded from it.
3949 See :hg:`help dates` for a list of formats valid for -d/--date.
3949 See :hg:`help dates` for a list of formats valid for -d/--date.
3950
3950
3951 .. container:: verbose
3951 .. container:: verbose
3952
3952
3953 Examples:
3953 Examples:
3954
3954
3955 - import a traditional patch from a website and detect renames::
3955 - import a traditional patch from a website and detect renames::
3956
3956
3957 hg import -s 80 http://example.com/bugfix.patch
3957 hg import -s 80 http://example.com/bugfix.patch
3958
3958
3959 - import a changeset from an hgweb server::
3959 - import a changeset from an hgweb server::
3960
3960
3961 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3961 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3962
3962
3963 - import all the patches in an Unix-style mbox::
3963 - import all the patches in an Unix-style mbox::
3964
3964
3965 hg import incoming-patches.mbox
3965 hg import incoming-patches.mbox
3966
3966
3967 - attempt to exactly restore an exported changeset (not always
3967 - attempt to exactly restore an exported changeset (not always
3968 possible)::
3968 possible)::
3969
3969
3970 hg import --exact proposed-fix.patch
3970 hg import --exact proposed-fix.patch
3971
3971
3972 Returns 0 on success, 1 on partial success (see --partial).
3972 Returns 0 on success, 1 on partial success (see --partial).
3973 """
3973 """
3974
3974
3975 if not patch1:
3975 if not patch1:
3976 raise util.Abort(_('need at least one patch to import'))
3976 raise util.Abort(_('need at least one patch to import'))
3977
3977
3978 patches = (patch1,) + patches
3978 patches = (patch1,) + patches
3979
3979
3980 date = opts.get('date')
3980 date = opts.get('date')
3981 if date:
3981 if date:
3982 opts['date'] = util.parsedate(date)
3982 opts['date'] = util.parsedate(date)
3983
3983
3984 update = not opts.get('bypass')
3984 update = not opts.get('bypass')
3985 if not update and opts.get('no_commit'):
3985 if not update and opts.get('no_commit'):
3986 raise util.Abort(_('cannot use --no-commit with --bypass'))
3986 raise util.Abort(_('cannot use --no-commit with --bypass'))
3987 try:
3987 try:
3988 sim = float(opts.get('similarity') or 0)
3988 sim = float(opts.get('similarity') or 0)
3989 except ValueError:
3989 except ValueError:
3990 raise util.Abort(_('similarity must be a number'))
3990 raise util.Abort(_('similarity must be a number'))
3991 if sim < 0 or sim > 100:
3991 if sim < 0 or sim > 100:
3992 raise util.Abort(_('similarity must be between 0 and 100'))
3992 raise util.Abort(_('similarity must be between 0 and 100'))
3993 if sim and not update:
3993 if sim and not update:
3994 raise util.Abort(_('cannot use --similarity with --bypass'))
3994 raise util.Abort(_('cannot use --similarity with --bypass'))
3995 if opts.get('exact') and opts.get('edit'):
3995 if opts.get('exact') and opts.get('edit'):
3996 raise util.Abort(_('cannot use --exact with --edit'))
3996 raise util.Abort(_('cannot use --exact with --edit'))
3997
3997
3998 if update:
3998 if update:
3999 cmdutil.checkunfinished(repo)
3999 cmdutil.checkunfinished(repo)
4000 if (opts.get('exact') or not opts.get('force')) and update:
4000 if (opts.get('exact') or not opts.get('force')) and update:
4001 cmdutil.bailifchanged(repo)
4001 cmdutil.bailifchanged(repo)
4002
4002
4003 base = opts["base"]
4003 base = opts["base"]
4004 wlock = lock = tr = None
4004 wlock = lock = tr = None
4005 msgs = []
4005 msgs = []
4006 ret = 0
4006 ret = 0
4007
4007
4008
4008
4009 try:
4009 try:
4010 try:
4010 try:
4011 wlock = repo.wlock()
4011 wlock = repo.wlock()
4012 repo.dirstate.beginparentchange()
4012 repo.dirstate.beginparentchange()
4013 if not opts.get('no_commit'):
4013 if not opts.get('no_commit'):
4014 lock = repo.lock()
4014 lock = repo.lock()
4015 tr = repo.transaction('import')
4015 tr = repo.transaction('import')
4016 parents = repo.parents()
4016 parents = repo.parents()
4017 for patchurl in patches:
4017 for patchurl in patches:
4018 if patchurl == '-':
4018 if patchurl == '-':
4019 ui.status(_('applying patch from stdin\n'))
4019 ui.status(_('applying patch from stdin\n'))
4020 patchfile = ui.fin
4020 patchfile = ui.fin
4021 patchurl = 'stdin' # for error message
4021 patchurl = 'stdin' # for error message
4022 else:
4022 else:
4023 patchurl = os.path.join(base, patchurl)
4023 patchurl = os.path.join(base, patchurl)
4024 ui.status(_('applying %s\n') % patchurl)
4024 ui.status(_('applying %s\n') % patchurl)
4025 patchfile = hg.openpath(ui, patchurl)
4025 patchfile = hg.openpath(ui, patchurl)
4026
4026
4027 haspatch = False
4027 haspatch = False
4028 for hunk in patch.split(patchfile):
4028 for hunk in patch.split(patchfile):
4029 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4029 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4030 parents, opts,
4030 parents, opts,
4031 msgs, hg.clean)
4031 msgs, hg.clean)
4032 if msg:
4032 if msg:
4033 haspatch = True
4033 haspatch = True
4034 ui.note(msg + '\n')
4034 ui.note(msg + '\n')
4035 if update or opts.get('exact'):
4035 if update or opts.get('exact'):
4036 parents = repo.parents()
4036 parents = repo.parents()
4037 else:
4037 else:
4038 parents = [repo[node]]
4038 parents = [repo[node]]
4039 if rej:
4039 if rej:
4040 ui.write_err(_("patch applied partially\n"))
4040 ui.write_err(_("patch applied partially\n"))
4041 ui.write_err(_("(fix the .rej files and run "
4041 ui.write_err(_("(fix the .rej files and run "
4042 "`hg commit --amend`)\n"))
4042 "`hg commit --amend`)\n"))
4043 ret = 1
4043 ret = 1
4044 break
4044 break
4045
4045
4046 if not haspatch:
4046 if not haspatch:
4047 raise util.Abort(_('%s: no diffs found') % patchurl)
4047 raise util.Abort(_('%s: no diffs found') % patchurl)
4048
4048
4049 if tr:
4049 if tr:
4050 tr.close()
4050 tr.close()
4051 if msgs:
4051 if msgs:
4052 repo.savecommitmessage('\n* * *\n'.join(msgs))
4052 repo.savecommitmessage('\n* * *\n'.join(msgs))
4053 repo.dirstate.endparentchange()
4053 repo.dirstate.endparentchange()
4054 return ret
4054 return ret
4055 except: # re-raises
4055 except: # re-raises
4056 # wlock.release() indirectly calls dirstate.write(): since
4056 # wlock.release() indirectly calls dirstate.write(): since
4057 # we're crashing, we do not want to change the working dir
4057 # we're crashing, we do not want to change the working dir
4058 # parent after all, so make sure it writes nothing
4058 # parent after all, so make sure it writes nothing
4059 repo.dirstate.invalidate()
4059 repo.dirstate.invalidate()
4060 raise
4060 raise
4061 finally:
4061 finally:
4062 if tr:
4062 if tr:
4063 tr.release()
4063 tr.release()
4064 release(lock, wlock)
4064 release(lock, wlock)
4065
4065
4066 @command('incoming|in',
4066 @command('incoming|in',
4067 [('f', 'force', None,
4067 [('f', 'force', None,
4068 _('run even if remote repository is unrelated')),
4068 _('run even if remote repository is unrelated')),
4069 ('n', 'newest-first', None, _('show newest record first')),
4069 ('n', 'newest-first', None, _('show newest record first')),
4070 ('', 'bundle', '',
4070 ('', 'bundle', '',
4071 _('file to store the bundles into'), _('FILE')),
4071 _('file to store the bundles into'), _('FILE')),
4072 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4072 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4073 ('B', 'bookmarks', False, _("compare bookmarks")),
4073 ('B', 'bookmarks', False, _("compare bookmarks")),
4074 ('b', 'branch', [],
4074 ('b', 'branch', [],
4075 _('a specific branch you would like to pull'), _('BRANCH')),
4075 _('a specific branch you would like to pull'), _('BRANCH')),
4076 ] + logopts + remoteopts + subrepoopts,
4076 ] + logopts + remoteopts + subrepoopts,
4077 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4077 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4078 def incoming(ui, repo, source="default", **opts):
4078 def incoming(ui, repo, source="default", **opts):
4079 """show new changesets found in source
4079 """show new changesets found in source
4080
4080
4081 Show new changesets found in the specified path/URL or the default
4081 Show new changesets found in the specified path/URL or the default
4082 pull location. These are the changesets that would have been pulled
4082 pull location. These are the changesets that would have been pulled
4083 if a pull at the time you issued this command.
4083 if a pull at the time you issued this command.
4084
4084
4085 For remote repository, using --bundle avoids downloading the
4085 For remote repository, using --bundle avoids downloading the
4086 changesets twice if the incoming is followed by a pull.
4086 changesets twice if the incoming is followed by a pull.
4087
4087
4088 See pull for valid source format details.
4088 See pull for valid source format details.
4089
4089
4090 .. container:: verbose
4090 .. container:: verbose
4091
4091
4092 Examples:
4092 Examples:
4093
4093
4094 - show incoming changes with patches and full description::
4094 - show incoming changes with patches and full description::
4095
4095
4096 hg incoming -vp
4096 hg incoming -vp
4097
4097
4098 - show incoming changes excluding merges, store a bundle::
4098 - show incoming changes excluding merges, store a bundle::
4099
4099
4100 hg in -vpM --bundle incoming.hg
4100 hg in -vpM --bundle incoming.hg
4101 hg pull incoming.hg
4101 hg pull incoming.hg
4102
4102
4103 - briefly list changes inside a bundle::
4103 - briefly list changes inside a bundle::
4104
4104
4105 hg in changes.hg -T "{desc|firstline}\\n"
4105 hg in changes.hg -T "{desc|firstline}\\n"
4106
4106
4107 Returns 0 if there are incoming changes, 1 otherwise.
4107 Returns 0 if there are incoming changes, 1 otherwise.
4108 """
4108 """
4109 if opts.get('graph'):
4109 if opts.get('graph'):
4110 cmdutil.checkunsupportedgraphflags([], opts)
4110 cmdutil.checkunsupportedgraphflags([], opts)
4111 def display(other, chlist, displayer):
4111 def display(other, chlist, displayer):
4112 revdag = cmdutil.graphrevs(other, chlist, opts)
4112 revdag = cmdutil.graphrevs(other, chlist, opts)
4113 showparents = [ctx.node() for ctx in repo[None].parents()]
4113 showparents = [ctx.node() for ctx in repo[None].parents()]
4114 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4114 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4115 graphmod.asciiedges)
4115 graphmod.asciiedges)
4116
4116
4117 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4117 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4118 return 0
4118 return 0
4119
4119
4120 if opts.get('bundle') and opts.get('subrepos'):
4120 if opts.get('bundle') and opts.get('subrepos'):
4121 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4121 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4122
4122
4123 if opts.get('bookmarks'):
4123 if opts.get('bookmarks'):
4124 source, branches = hg.parseurl(ui.expandpath(source),
4124 source, branches = hg.parseurl(ui.expandpath(source),
4125 opts.get('branch'))
4125 opts.get('branch'))
4126 other = hg.peer(repo, opts, source)
4126 other = hg.peer(repo, opts, source)
4127 if 'bookmarks' not in other.listkeys('namespaces'):
4127 if 'bookmarks' not in other.listkeys('namespaces'):
4128 ui.warn(_("remote doesn't support bookmarks\n"))
4128 ui.warn(_("remote doesn't support bookmarks\n"))
4129 return 0
4129 return 0
4130 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4130 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4131 return bookmarks.diff(ui, repo, other)
4131 return bookmarks.diff(ui, repo, other)
4132
4132
4133 repo._subtoppath = ui.expandpath(source)
4133 repo._subtoppath = ui.expandpath(source)
4134 try:
4134 try:
4135 return hg.incoming(ui, repo, source, opts)
4135 return hg.incoming(ui, repo, source, opts)
4136 finally:
4136 finally:
4137 del repo._subtoppath
4137 del repo._subtoppath
4138
4138
4139
4139
4140 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4140 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4141 norepo=True)
4141 norepo=True)
4142 def init(ui, dest=".", **opts):
4142 def init(ui, dest=".", **opts):
4143 """create a new repository in the given directory
4143 """create a new repository in the given directory
4144
4144
4145 Initialize a new repository in the given directory. If the given
4145 Initialize a new repository in the given directory. If the given
4146 directory does not exist, it will be created.
4146 directory does not exist, it will be created.
4147
4147
4148 If no directory is given, the current directory is used.
4148 If no directory is given, the current directory is used.
4149
4149
4150 It is possible to specify an ``ssh://`` URL as the destination.
4150 It is possible to specify an ``ssh://`` URL as the destination.
4151 See :hg:`help urls` for more information.
4151 See :hg:`help urls` for more information.
4152
4152
4153 Returns 0 on success.
4153 Returns 0 on success.
4154 """
4154 """
4155 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4155 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4156
4156
4157 @command('locate',
4157 @command('locate',
4158 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4158 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4159 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4159 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4160 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4160 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4161 ] + walkopts,
4161 ] + walkopts,
4162 _('[OPTION]... [PATTERN]...'))
4162 _('[OPTION]... [PATTERN]...'))
4163 def locate(ui, repo, *pats, **opts):
4163 def locate(ui, repo, *pats, **opts):
4164 """locate files matching specific patterns
4164 """locate files matching specific patterns (DEPRECATED)
4165
4165
4166 Print files under Mercurial control in the working directory whose
4166 Print files under Mercurial control in the working directory whose
4167 names match the given patterns.
4167 names match the given patterns.
4168
4168
4169 By default, this command searches all directories in the working
4169 By default, this command searches all directories in the working
4170 directory. To search just the current directory and its
4170 directory. To search just the current directory and its
4171 subdirectories, use "--include .".
4171 subdirectories, use "--include .".
4172
4172
4173 If no patterns are given to match, this command prints the names
4173 If no patterns are given to match, this command prints the names
4174 of all files under Mercurial control in the working directory.
4174 of all files under Mercurial control in the working directory.
4175
4175
4176 If you want to feed the output of this command into the "xargs"
4176 If you want to feed the output of this command into the "xargs"
4177 command, use the -0 option to both this command and "xargs". This
4177 command, use the -0 option to both this command and "xargs". This
4178 will avoid the problem of "xargs" treating single filenames that
4178 will avoid the problem of "xargs" treating single filenames that
4179 contain whitespace as multiple filenames.
4179 contain whitespace as multiple filenames.
4180
4180
4181 Returns 0 if a match is found, 1 otherwise.
4181 Returns 0 if a match is found, 1 otherwise.
4182 """
4182 """
4183 end = opts.get('print0') and '\0' or '\n'
4183 end = opts.get('print0') and '\0' or '\n'
4184 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4184 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4185
4185
4186 ret = 1
4186 ret = 1
4187 ctx = repo[rev]
4187 ctx = repo[rev]
4188 m = scmutil.match(ctx, pats, opts, default='relglob')
4188 m = scmutil.match(ctx, pats, opts, default='relglob')
4189 m.bad = lambda x, y: False
4189 m.bad = lambda x, y: False
4190
4190
4191 for abs in ctx.matches(m):
4191 for abs in ctx.matches(m):
4192 if opts.get('fullpath'):
4192 if opts.get('fullpath'):
4193 ui.write(repo.wjoin(abs), end)
4193 ui.write(repo.wjoin(abs), end)
4194 else:
4194 else:
4195 ui.write(((pats and m.rel(abs)) or abs), end)
4195 ui.write(((pats and m.rel(abs)) or abs), end)
4196 ret = 0
4196 ret = 0
4197
4197
4198 return ret
4198 return ret
4199
4199
4200 @command('^log|history',
4200 @command('^log|history',
4201 [('f', 'follow', None,
4201 [('f', 'follow', None,
4202 _('follow changeset history, or file history across copies and renames')),
4202 _('follow changeset history, or file history across copies and renames')),
4203 ('', 'follow-first', None,
4203 ('', 'follow-first', None,
4204 _('only follow the first parent of merge changesets (DEPRECATED)')),
4204 _('only follow the first parent of merge changesets (DEPRECATED)')),
4205 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4205 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4206 ('C', 'copies', None, _('show copied files')),
4206 ('C', 'copies', None, _('show copied files')),
4207 ('k', 'keyword', [],
4207 ('k', 'keyword', [],
4208 _('do case-insensitive search for a given text'), _('TEXT')),
4208 _('do case-insensitive search for a given text'), _('TEXT')),
4209 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4209 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4210 ('', 'removed', None, _('include revisions where files were removed')),
4210 ('', 'removed', None, _('include revisions where files were removed')),
4211 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4211 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4212 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4212 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4213 ('', 'only-branch', [],
4213 ('', 'only-branch', [],
4214 _('show only changesets within the given named branch (DEPRECATED)'),
4214 _('show only changesets within the given named branch (DEPRECATED)'),
4215 _('BRANCH')),
4215 _('BRANCH')),
4216 ('b', 'branch', [],
4216 ('b', 'branch', [],
4217 _('show changesets within the given named branch'), _('BRANCH')),
4217 _('show changesets within the given named branch'), _('BRANCH')),
4218 ('P', 'prune', [],
4218 ('P', 'prune', [],
4219 _('do not display revision or any of its ancestors'), _('REV')),
4219 _('do not display revision or any of its ancestors'), _('REV')),
4220 ] + logopts + walkopts,
4220 ] + logopts + walkopts,
4221 _('[OPTION]... [FILE]'),
4221 _('[OPTION]... [FILE]'),
4222 inferrepo=True)
4222 inferrepo=True)
4223 def log(ui, repo, *pats, **opts):
4223 def log(ui, repo, *pats, **opts):
4224 """show revision history of entire repository or files
4224 """show revision history of entire repository or files
4225
4225
4226 Print the revision history of the specified files or the entire
4226 Print the revision history of the specified files or the entire
4227 project.
4227 project.
4228
4228
4229 If no revision range is specified, the default is ``tip:0`` unless
4229 If no revision range is specified, the default is ``tip:0`` unless
4230 --follow is set, in which case the working directory parent is
4230 --follow is set, in which case the working directory parent is
4231 used as the starting revision.
4231 used as the starting revision.
4232
4232
4233 File history is shown without following rename or copy history of
4233 File history is shown without following rename or copy history of
4234 files. Use -f/--follow with a filename to follow history across
4234 files. Use -f/--follow with a filename to follow history across
4235 renames and copies. --follow without a filename will only show
4235 renames and copies. --follow without a filename will only show
4236 ancestors or descendants of the starting revision.
4236 ancestors or descendants of the starting revision.
4237
4237
4238 By default this command prints revision number and changeset id,
4238 By default this command prints revision number and changeset id,
4239 tags, non-trivial parents, user, date and time, and a summary for
4239 tags, non-trivial parents, user, date and time, and a summary for
4240 each commit. When the -v/--verbose switch is used, the list of
4240 each commit. When the -v/--verbose switch is used, the list of
4241 changed files and full commit message are shown.
4241 changed files and full commit message are shown.
4242
4242
4243 With --graph the revisions are shown as an ASCII art DAG with the most
4243 With --graph the revisions are shown as an ASCII art DAG with the most
4244 recent changeset at the top.
4244 recent changeset at the top.
4245 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4245 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4246 and '+' represents a fork where the changeset from the lines below is a
4246 and '+' represents a fork where the changeset from the lines below is a
4247 parent of the 'o' merge on the same line.
4247 parent of the 'o' merge on the same line.
4248
4248
4249 .. note::
4249 .. note::
4250
4250
4251 log -p/--patch may generate unexpected diff output for merge
4251 log -p/--patch may generate unexpected diff output for merge
4252 changesets, as it will only compare the merge changeset against
4252 changesets, as it will only compare the merge changeset against
4253 its first parent. Also, only files different from BOTH parents
4253 its first parent. Also, only files different from BOTH parents
4254 will appear in files:.
4254 will appear in files:.
4255
4255
4256 .. note::
4256 .. note::
4257
4257
4258 for performance reasons, log FILE may omit duplicate changes
4258 for performance reasons, log FILE may omit duplicate changes
4259 made on branches and will not show deletions. To see all
4259 made on branches and will not show deletions. To see all
4260 changes including duplicates and deletions, use the --removed
4260 changes including duplicates and deletions, use the --removed
4261 switch.
4261 switch.
4262
4262
4263 .. container:: verbose
4263 .. container:: verbose
4264
4264
4265 Some examples:
4265 Some examples:
4266
4266
4267 - changesets with full descriptions and file lists::
4267 - changesets with full descriptions and file lists::
4268
4268
4269 hg log -v
4269 hg log -v
4270
4270
4271 - changesets ancestral to the working directory::
4271 - changesets ancestral to the working directory::
4272
4272
4273 hg log -f
4273 hg log -f
4274
4274
4275 - last 10 commits on the current branch::
4275 - last 10 commits on the current branch::
4276
4276
4277 hg log -l 10 -b .
4277 hg log -l 10 -b .
4278
4278
4279 - changesets showing all modifications of a file, including removals::
4279 - changesets showing all modifications of a file, including removals::
4280
4280
4281 hg log --removed file.c
4281 hg log --removed file.c
4282
4282
4283 - all changesets that touch a directory, with diffs, excluding merges::
4283 - all changesets that touch a directory, with diffs, excluding merges::
4284
4284
4285 hg log -Mp lib/
4285 hg log -Mp lib/
4286
4286
4287 - all revision numbers that match a keyword::
4287 - all revision numbers that match a keyword::
4288
4288
4289 hg log -k bug --template "{rev}\\n"
4289 hg log -k bug --template "{rev}\\n"
4290
4290
4291 - list available log templates::
4291 - list available log templates::
4292
4292
4293 hg log -T list
4293 hg log -T list
4294
4294
4295 - check if a given changeset is included is a tagged release::
4295 - check if a given changeset is included is a tagged release::
4296
4296
4297 hg log -r "a21ccf and ancestor(1.9)"
4297 hg log -r "a21ccf and ancestor(1.9)"
4298
4298
4299 - find all changesets by some user in a date range::
4299 - find all changesets by some user in a date range::
4300
4300
4301 hg log -k alice -d "may 2008 to jul 2008"
4301 hg log -k alice -d "may 2008 to jul 2008"
4302
4302
4303 - summary of all changesets after the last tag::
4303 - summary of all changesets after the last tag::
4304
4304
4305 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4305 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4306
4306
4307 See :hg:`help dates` for a list of formats valid for -d/--date.
4307 See :hg:`help dates` for a list of formats valid for -d/--date.
4308
4308
4309 See :hg:`help revisions` and :hg:`help revsets` for more about
4309 See :hg:`help revisions` and :hg:`help revsets` for more about
4310 specifying revisions.
4310 specifying revisions.
4311
4311
4312 See :hg:`help templates` for more about pre-packaged styles and
4312 See :hg:`help templates` for more about pre-packaged styles and
4313 specifying custom templates.
4313 specifying custom templates.
4314
4314
4315 Returns 0 on success.
4315 Returns 0 on success.
4316 """
4316 """
4317 if opts.get('graph'):
4317 if opts.get('graph'):
4318 return cmdutil.graphlog(ui, repo, *pats, **opts)
4318 return cmdutil.graphlog(ui, repo, *pats, **opts)
4319
4319
4320 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4320 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4321 limit = cmdutil.loglimit(opts)
4321 limit = cmdutil.loglimit(opts)
4322 count = 0
4322 count = 0
4323
4323
4324 getrenamed = None
4324 getrenamed = None
4325 if opts.get('copies'):
4325 if opts.get('copies'):
4326 endrev = None
4326 endrev = None
4327 if opts.get('rev'):
4327 if opts.get('rev'):
4328 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4328 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4329 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4329 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4330
4330
4331 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4331 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4332 for rev in revs:
4332 for rev in revs:
4333 if count == limit:
4333 if count == limit:
4334 break
4334 break
4335 ctx = repo[rev]
4335 ctx = repo[rev]
4336 copies = None
4336 copies = None
4337 if getrenamed is not None and rev:
4337 if getrenamed is not None and rev:
4338 copies = []
4338 copies = []
4339 for fn in ctx.files():
4339 for fn in ctx.files():
4340 rename = getrenamed(fn, rev)
4340 rename = getrenamed(fn, rev)
4341 if rename:
4341 if rename:
4342 copies.append((fn, rename[0]))
4342 copies.append((fn, rename[0]))
4343 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4343 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4344 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4344 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4345 if displayer.flush(rev):
4345 if displayer.flush(rev):
4346 count += 1
4346 count += 1
4347
4347
4348 displayer.close()
4348 displayer.close()
4349
4349
4350 @command('manifest',
4350 @command('manifest',
4351 [('r', 'rev', '', _('revision to display'), _('REV')),
4351 [('r', 'rev', '', _('revision to display'), _('REV')),
4352 ('', 'all', False, _("list files from all revisions"))]
4352 ('', 'all', False, _("list files from all revisions"))]
4353 + formatteropts,
4353 + formatteropts,
4354 _('[-r REV]'))
4354 _('[-r REV]'))
4355 def manifest(ui, repo, node=None, rev=None, **opts):
4355 def manifest(ui, repo, node=None, rev=None, **opts):
4356 """output the current or given revision of the project manifest
4356 """output the current or given revision of the project manifest
4357
4357
4358 Print a list of version controlled files for the given revision.
4358 Print a list of version controlled files for the given revision.
4359 If no revision is given, the first parent of the working directory
4359 If no revision is given, the first parent of the working directory
4360 is used, or the null revision if no revision is checked out.
4360 is used, or the null revision if no revision is checked out.
4361
4361
4362 With -v, print file permissions, symlink and executable bits.
4362 With -v, print file permissions, symlink and executable bits.
4363 With --debug, print file revision hashes.
4363 With --debug, print file revision hashes.
4364
4364
4365 If option --all is specified, the list of all files from all revisions
4365 If option --all is specified, the list of all files from all revisions
4366 is printed. This includes deleted and renamed files.
4366 is printed. This includes deleted and renamed files.
4367
4367
4368 Returns 0 on success.
4368 Returns 0 on success.
4369 """
4369 """
4370
4370
4371 fm = ui.formatter('manifest', opts)
4371 fm = ui.formatter('manifest', opts)
4372
4372
4373 if opts.get('all'):
4373 if opts.get('all'):
4374 if rev or node:
4374 if rev or node:
4375 raise util.Abort(_("can't specify a revision with --all"))
4375 raise util.Abort(_("can't specify a revision with --all"))
4376
4376
4377 res = []
4377 res = []
4378 prefix = "data/"
4378 prefix = "data/"
4379 suffix = ".i"
4379 suffix = ".i"
4380 plen = len(prefix)
4380 plen = len(prefix)
4381 slen = len(suffix)
4381 slen = len(suffix)
4382 lock = repo.lock()
4382 lock = repo.lock()
4383 try:
4383 try:
4384 for fn, b, size in repo.store.datafiles():
4384 for fn, b, size in repo.store.datafiles():
4385 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4385 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4386 res.append(fn[plen:-slen])
4386 res.append(fn[plen:-slen])
4387 finally:
4387 finally:
4388 lock.release()
4388 lock.release()
4389 for f in res:
4389 for f in res:
4390 fm.startitem()
4390 fm.startitem()
4391 fm.write("path", '%s\n', f)
4391 fm.write("path", '%s\n', f)
4392 fm.end()
4392 fm.end()
4393 return
4393 return
4394
4394
4395 if rev and node:
4395 if rev and node:
4396 raise util.Abort(_("please specify just one revision"))
4396 raise util.Abort(_("please specify just one revision"))
4397
4397
4398 if not node:
4398 if not node:
4399 node = rev
4399 node = rev
4400
4400
4401 char = {'l': '@', 'x': '*', '': ''}
4401 char = {'l': '@', 'x': '*', '': ''}
4402 mode = {'l': '644', 'x': '755', '': '644'}
4402 mode = {'l': '644', 'x': '755', '': '644'}
4403 ctx = scmutil.revsingle(repo, node)
4403 ctx = scmutil.revsingle(repo, node)
4404 mf = ctx.manifest()
4404 mf = ctx.manifest()
4405 for f in ctx:
4405 for f in ctx:
4406 fm.startitem()
4406 fm.startitem()
4407 fl = ctx[f].flags()
4407 fl = ctx[f].flags()
4408 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4408 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4409 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4409 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4410 fm.write('path', '%s\n', f)
4410 fm.write('path', '%s\n', f)
4411 fm.end()
4411 fm.end()
4412
4412
4413 @command('^merge',
4413 @command('^merge',
4414 [('f', 'force', None,
4414 [('f', 'force', None,
4415 _('force a merge including outstanding changes (DEPRECATED)')),
4415 _('force a merge including outstanding changes (DEPRECATED)')),
4416 ('r', 'rev', '', _('revision to merge'), _('REV')),
4416 ('r', 'rev', '', _('revision to merge'), _('REV')),
4417 ('P', 'preview', None,
4417 ('P', 'preview', None,
4418 _('review revisions to merge (no merge is performed)'))
4418 _('review revisions to merge (no merge is performed)'))
4419 ] + mergetoolopts,
4419 ] + mergetoolopts,
4420 _('[-P] [-f] [[-r] REV]'))
4420 _('[-P] [-f] [[-r] REV]'))
4421 def merge(ui, repo, node=None, **opts):
4421 def merge(ui, repo, node=None, **opts):
4422 """merge working directory with another revision
4422 """merge working directory with another revision
4423
4423
4424 The current working directory is updated with all changes made in
4424 The current working directory is updated with all changes made in
4425 the requested revision since the last common predecessor revision.
4425 the requested revision since the last common predecessor revision.
4426
4426
4427 Files that changed between either parent are marked as changed for
4427 Files that changed between either parent are marked as changed for
4428 the next commit and a commit must be performed before any further
4428 the next commit and a commit must be performed before any further
4429 updates to the repository are allowed. The next commit will have
4429 updates to the repository are allowed. The next commit will have
4430 two parents.
4430 two parents.
4431
4431
4432 ``--tool`` can be used to specify the merge tool used for file
4432 ``--tool`` can be used to specify the merge tool used for file
4433 merges. It overrides the HGMERGE environment variable and your
4433 merges. It overrides the HGMERGE environment variable and your
4434 configuration files. See :hg:`help merge-tools` for options.
4434 configuration files. See :hg:`help merge-tools` for options.
4435
4435
4436 If no revision is specified, the working directory's parent is a
4436 If no revision is specified, the working directory's parent is a
4437 head revision, and the current branch contains exactly one other
4437 head revision, and the current branch contains exactly one other
4438 head, the other head is merged with by default. Otherwise, an
4438 head, the other head is merged with by default. Otherwise, an
4439 explicit revision with which to merge with must be provided.
4439 explicit revision with which to merge with must be provided.
4440
4440
4441 :hg:`resolve` must be used to resolve unresolved files.
4441 :hg:`resolve` must be used to resolve unresolved files.
4442
4442
4443 To undo an uncommitted merge, use :hg:`update --clean .` which
4443 To undo an uncommitted merge, use :hg:`update --clean .` which
4444 will check out a clean copy of the original merge parent, losing
4444 will check out a clean copy of the original merge parent, losing
4445 all changes.
4445 all changes.
4446
4446
4447 Returns 0 on success, 1 if there are unresolved files.
4447 Returns 0 on success, 1 if there are unresolved files.
4448 """
4448 """
4449
4449
4450 if opts.get('rev') and node:
4450 if opts.get('rev') and node:
4451 raise util.Abort(_("please specify just one revision"))
4451 raise util.Abort(_("please specify just one revision"))
4452 if not node:
4452 if not node:
4453 node = opts.get('rev')
4453 node = opts.get('rev')
4454
4454
4455 if node:
4455 if node:
4456 node = scmutil.revsingle(repo, node).node()
4456 node = scmutil.revsingle(repo, node).node()
4457
4457
4458 if not node and repo._bookmarkcurrent:
4458 if not node and repo._bookmarkcurrent:
4459 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4459 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4460 curhead = repo[repo._bookmarkcurrent].node()
4460 curhead = repo[repo._bookmarkcurrent].node()
4461 if len(bmheads) == 2:
4461 if len(bmheads) == 2:
4462 if curhead == bmheads[0]:
4462 if curhead == bmheads[0]:
4463 node = bmheads[1]
4463 node = bmheads[1]
4464 else:
4464 else:
4465 node = bmheads[0]
4465 node = bmheads[0]
4466 elif len(bmheads) > 2:
4466 elif len(bmheads) > 2:
4467 raise util.Abort(_("multiple matching bookmarks to merge - "
4467 raise util.Abort(_("multiple matching bookmarks to merge - "
4468 "please merge with an explicit rev or bookmark"),
4468 "please merge with an explicit rev or bookmark"),
4469 hint=_("run 'hg heads' to see all heads"))
4469 hint=_("run 'hg heads' to see all heads"))
4470 elif len(bmheads) <= 1:
4470 elif len(bmheads) <= 1:
4471 raise util.Abort(_("no matching bookmark to merge - "
4471 raise util.Abort(_("no matching bookmark to merge - "
4472 "please merge with an explicit rev or bookmark"),
4472 "please merge with an explicit rev or bookmark"),
4473 hint=_("run 'hg heads' to see all heads"))
4473 hint=_("run 'hg heads' to see all heads"))
4474
4474
4475 if not node and not repo._bookmarkcurrent:
4475 if not node and not repo._bookmarkcurrent:
4476 branch = repo[None].branch()
4476 branch = repo[None].branch()
4477 bheads = repo.branchheads(branch)
4477 bheads = repo.branchheads(branch)
4478 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4478 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4479
4479
4480 if len(nbhs) > 2:
4480 if len(nbhs) > 2:
4481 raise util.Abort(_("branch '%s' has %d heads - "
4481 raise util.Abort(_("branch '%s' has %d heads - "
4482 "please merge with an explicit rev")
4482 "please merge with an explicit rev")
4483 % (branch, len(bheads)),
4483 % (branch, len(bheads)),
4484 hint=_("run 'hg heads .' to see heads"))
4484 hint=_("run 'hg heads .' to see heads"))
4485
4485
4486 parent = repo.dirstate.p1()
4486 parent = repo.dirstate.p1()
4487 if len(nbhs) <= 1:
4487 if len(nbhs) <= 1:
4488 if len(bheads) > 1:
4488 if len(bheads) > 1:
4489 raise util.Abort(_("heads are bookmarked - "
4489 raise util.Abort(_("heads are bookmarked - "
4490 "please merge with an explicit rev"),
4490 "please merge with an explicit rev"),
4491 hint=_("run 'hg heads' to see all heads"))
4491 hint=_("run 'hg heads' to see all heads"))
4492 if len(repo.heads()) > 1:
4492 if len(repo.heads()) > 1:
4493 raise util.Abort(_("branch '%s' has one head - "
4493 raise util.Abort(_("branch '%s' has one head - "
4494 "please merge with an explicit rev")
4494 "please merge with an explicit rev")
4495 % branch,
4495 % branch,
4496 hint=_("run 'hg heads' to see all heads"))
4496 hint=_("run 'hg heads' to see all heads"))
4497 msg, hint = _('nothing to merge'), None
4497 msg, hint = _('nothing to merge'), None
4498 if parent != repo.lookup(branch):
4498 if parent != repo.lookup(branch):
4499 hint = _("use 'hg update' instead")
4499 hint = _("use 'hg update' instead")
4500 raise util.Abort(msg, hint=hint)
4500 raise util.Abort(msg, hint=hint)
4501
4501
4502 if parent not in bheads:
4502 if parent not in bheads:
4503 raise util.Abort(_('working directory not at a head revision'),
4503 raise util.Abort(_('working directory not at a head revision'),
4504 hint=_("use 'hg update' or merge with an "
4504 hint=_("use 'hg update' or merge with an "
4505 "explicit revision"))
4505 "explicit revision"))
4506 if parent == nbhs[0]:
4506 if parent == nbhs[0]:
4507 node = nbhs[-1]
4507 node = nbhs[-1]
4508 else:
4508 else:
4509 node = nbhs[0]
4509 node = nbhs[0]
4510
4510
4511 if opts.get('preview'):
4511 if opts.get('preview'):
4512 # find nodes that are ancestors of p2 but not of p1
4512 # find nodes that are ancestors of p2 but not of p1
4513 p1 = repo.lookup('.')
4513 p1 = repo.lookup('.')
4514 p2 = repo.lookup(node)
4514 p2 = repo.lookup(node)
4515 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4515 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4516
4516
4517 displayer = cmdutil.show_changeset(ui, repo, opts)
4517 displayer = cmdutil.show_changeset(ui, repo, opts)
4518 for node in nodes:
4518 for node in nodes:
4519 displayer.show(repo[node])
4519 displayer.show(repo[node])
4520 displayer.close()
4520 displayer.close()
4521 return 0
4521 return 0
4522
4522
4523 try:
4523 try:
4524 # ui.forcemerge is an internal variable, do not document
4524 # ui.forcemerge is an internal variable, do not document
4525 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4525 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4526 return hg.merge(repo, node, force=opts.get('force'))
4526 return hg.merge(repo, node, force=opts.get('force'))
4527 finally:
4527 finally:
4528 ui.setconfig('ui', 'forcemerge', '', 'merge')
4528 ui.setconfig('ui', 'forcemerge', '', 'merge')
4529
4529
4530 @command('outgoing|out',
4530 @command('outgoing|out',
4531 [('f', 'force', None, _('run even when the destination is unrelated')),
4531 [('f', 'force', None, _('run even when the destination is unrelated')),
4532 ('r', 'rev', [],
4532 ('r', 'rev', [],
4533 _('a changeset intended to be included in the destination'), _('REV')),
4533 _('a changeset intended to be included in the destination'), _('REV')),
4534 ('n', 'newest-first', None, _('show newest record first')),
4534 ('n', 'newest-first', None, _('show newest record first')),
4535 ('B', 'bookmarks', False, _('compare bookmarks')),
4535 ('B', 'bookmarks', False, _('compare bookmarks')),
4536 ('b', 'branch', [], _('a specific branch you would like to push'),
4536 ('b', 'branch', [], _('a specific branch you would like to push'),
4537 _('BRANCH')),
4537 _('BRANCH')),
4538 ] + logopts + remoteopts + subrepoopts,
4538 ] + logopts + remoteopts + subrepoopts,
4539 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4539 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4540 def outgoing(ui, repo, dest=None, **opts):
4540 def outgoing(ui, repo, dest=None, **opts):
4541 """show changesets not found in the destination
4541 """show changesets not found in the destination
4542
4542
4543 Show changesets not found in the specified destination repository
4543 Show changesets not found in the specified destination repository
4544 or the default push location. These are the changesets that would
4544 or the default push location. These are the changesets that would
4545 be pushed if a push was requested.
4545 be pushed if a push was requested.
4546
4546
4547 See pull for details of valid destination formats.
4547 See pull for details of valid destination formats.
4548
4548
4549 Returns 0 if there are outgoing changes, 1 otherwise.
4549 Returns 0 if there are outgoing changes, 1 otherwise.
4550 """
4550 """
4551 if opts.get('graph'):
4551 if opts.get('graph'):
4552 cmdutil.checkunsupportedgraphflags([], opts)
4552 cmdutil.checkunsupportedgraphflags([], opts)
4553 o, other = hg._outgoing(ui, repo, dest, opts)
4553 o, other = hg._outgoing(ui, repo, dest, opts)
4554 if not o:
4554 if not o:
4555 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4555 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4556 return
4556 return
4557
4557
4558 revdag = cmdutil.graphrevs(repo, o, opts)
4558 revdag = cmdutil.graphrevs(repo, o, opts)
4559 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4559 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4560 showparents = [ctx.node() for ctx in repo[None].parents()]
4560 showparents = [ctx.node() for ctx in repo[None].parents()]
4561 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4561 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4562 graphmod.asciiedges)
4562 graphmod.asciiedges)
4563 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4563 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4564 return 0
4564 return 0
4565
4565
4566 if opts.get('bookmarks'):
4566 if opts.get('bookmarks'):
4567 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4567 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4568 dest, branches = hg.parseurl(dest, opts.get('branch'))
4568 dest, branches = hg.parseurl(dest, opts.get('branch'))
4569 other = hg.peer(repo, opts, dest)
4569 other = hg.peer(repo, opts, dest)
4570 if 'bookmarks' not in other.listkeys('namespaces'):
4570 if 'bookmarks' not in other.listkeys('namespaces'):
4571 ui.warn(_("remote doesn't support bookmarks\n"))
4571 ui.warn(_("remote doesn't support bookmarks\n"))
4572 return 0
4572 return 0
4573 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4573 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4574 return bookmarks.diff(ui, other, repo)
4574 return bookmarks.diff(ui, other, repo)
4575
4575
4576 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4576 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4577 try:
4577 try:
4578 return hg.outgoing(ui, repo, dest, opts)
4578 return hg.outgoing(ui, repo, dest, opts)
4579 finally:
4579 finally:
4580 del repo._subtoppath
4580 del repo._subtoppath
4581
4581
4582 @command('parents',
4582 @command('parents',
4583 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4583 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4584 ] + templateopts,
4584 ] + templateopts,
4585 _('[-r REV] [FILE]'),
4585 _('[-r REV] [FILE]'),
4586 inferrepo=True)
4586 inferrepo=True)
4587 def parents(ui, repo, file_=None, **opts):
4587 def parents(ui, repo, file_=None, **opts):
4588 """show the parents of the working directory or revision
4588 """show the parents of the working directory or revision
4589
4589
4590 Print the working directory's parent revisions. If a revision is
4590 Print the working directory's parent revisions. If a revision is
4591 given via -r/--rev, the parent of that revision will be printed.
4591 given via -r/--rev, the parent of that revision will be printed.
4592 If a file argument is given, the revision in which the file was
4592 If a file argument is given, the revision in which the file was
4593 last changed (before the working directory revision or the
4593 last changed (before the working directory revision or the
4594 argument to --rev if given) is printed.
4594 argument to --rev if given) is printed.
4595
4595
4596 Returns 0 on success.
4596 Returns 0 on success.
4597 """
4597 """
4598
4598
4599 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4599 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4600
4600
4601 if file_:
4601 if file_:
4602 m = scmutil.match(ctx, (file_,), opts)
4602 m = scmutil.match(ctx, (file_,), opts)
4603 if m.anypats() or len(m.files()) != 1:
4603 if m.anypats() or len(m.files()) != 1:
4604 raise util.Abort(_('can only specify an explicit filename'))
4604 raise util.Abort(_('can only specify an explicit filename'))
4605 file_ = m.files()[0]
4605 file_ = m.files()[0]
4606 filenodes = []
4606 filenodes = []
4607 for cp in ctx.parents():
4607 for cp in ctx.parents():
4608 if not cp:
4608 if not cp:
4609 continue
4609 continue
4610 try:
4610 try:
4611 filenodes.append(cp.filenode(file_))
4611 filenodes.append(cp.filenode(file_))
4612 except error.LookupError:
4612 except error.LookupError:
4613 pass
4613 pass
4614 if not filenodes:
4614 if not filenodes:
4615 raise util.Abort(_("'%s' not found in manifest!") % file_)
4615 raise util.Abort(_("'%s' not found in manifest!") % file_)
4616 p = []
4616 p = []
4617 for fn in filenodes:
4617 for fn in filenodes:
4618 fctx = repo.filectx(file_, fileid=fn)
4618 fctx = repo.filectx(file_, fileid=fn)
4619 p.append(fctx.node())
4619 p.append(fctx.node())
4620 else:
4620 else:
4621 p = [cp.node() for cp in ctx.parents()]
4621 p = [cp.node() for cp in ctx.parents()]
4622
4622
4623 displayer = cmdutil.show_changeset(ui, repo, opts)
4623 displayer = cmdutil.show_changeset(ui, repo, opts)
4624 for n in p:
4624 for n in p:
4625 if n != nullid:
4625 if n != nullid:
4626 displayer.show(repo[n])
4626 displayer.show(repo[n])
4627 displayer.close()
4627 displayer.close()
4628
4628
4629 @command('paths', [], _('[NAME]'), optionalrepo=True)
4629 @command('paths', [], _('[NAME]'), optionalrepo=True)
4630 def paths(ui, repo, search=None):
4630 def paths(ui, repo, search=None):
4631 """show aliases for remote repositories
4631 """show aliases for remote repositories
4632
4632
4633 Show definition of symbolic path name NAME. If no name is given,
4633 Show definition of symbolic path name NAME. If no name is given,
4634 show definition of all available names.
4634 show definition of all available names.
4635
4635
4636 Option -q/--quiet suppresses all output when searching for NAME
4636 Option -q/--quiet suppresses all output when searching for NAME
4637 and shows only the path names when listing all definitions.
4637 and shows only the path names when listing all definitions.
4638
4638
4639 Path names are defined in the [paths] section of your
4639 Path names are defined in the [paths] section of your
4640 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4640 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4641 repository, ``.hg/hgrc`` is used, too.
4641 repository, ``.hg/hgrc`` is used, too.
4642
4642
4643 The path names ``default`` and ``default-push`` have a special
4643 The path names ``default`` and ``default-push`` have a special
4644 meaning. When performing a push or pull operation, they are used
4644 meaning. When performing a push or pull operation, they are used
4645 as fallbacks if no location is specified on the command-line.
4645 as fallbacks if no location is specified on the command-line.
4646 When ``default-push`` is set, it will be used for push and
4646 When ``default-push`` is set, it will be used for push and
4647 ``default`` will be used for pull; otherwise ``default`` is used
4647 ``default`` will be used for pull; otherwise ``default`` is used
4648 as the fallback for both. When cloning a repository, the clone
4648 as the fallback for both. When cloning a repository, the clone
4649 source is written as ``default`` in ``.hg/hgrc``. Note that
4649 source is written as ``default`` in ``.hg/hgrc``. Note that
4650 ``default`` and ``default-push`` apply to all inbound (e.g.
4650 ``default`` and ``default-push`` apply to all inbound (e.g.
4651 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4651 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4652 :hg:`bundle`) operations.
4652 :hg:`bundle`) operations.
4653
4653
4654 See :hg:`help urls` for more information.
4654 See :hg:`help urls` for more information.
4655
4655
4656 Returns 0 on success.
4656 Returns 0 on success.
4657 """
4657 """
4658 if search:
4658 if search:
4659 for name, path in ui.configitems("paths"):
4659 for name, path in ui.configitems("paths"):
4660 if name == search:
4660 if name == search:
4661 ui.status("%s\n" % util.hidepassword(path))
4661 ui.status("%s\n" % util.hidepassword(path))
4662 return
4662 return
4663 if not ui.quiet:
4663 if not ui.quiet:
4664 ui.warn(_("not found!\n"))
4664 ui.warn(_("not found!\n"))
4665 return 1
4665 return 1
4666 else:
4666 else:
4667 for name, path in ui.configitems("paths"):
4667 for name, path in ui.configitems("paths"):
4668 if ui.quiet:
4668 if ui.quiet:
4669 ui.write("%s\n" % name)
4669 ui.write("%s\n" % name)
4670 else:
4670 else:
4671 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4671 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4672
4672
4673 @command('phase',
4673 @command('phase',
4674 [('p', 'public', False, _('set changeset phase to public')),
4674 [('p', 'public', False, _('set changeset phase to public')),
4675 ('d', 'draft', False, _('set changeset phase to draft')),
4675 ('d', 'draft', False, _('set changeset phase to draft')),
4676 ('s', 'secret', False, _('set changeset phase to secret')),
4676 ('s', 'secret', False, _('set changeset phase to secret')),
4677 ('f', 'force', False, _('allow to move boundary backward')),
4677 ('f', 'force', False, _('allow to move boundary backward')),
4678 ('r', 'rev', [], _('target revision'), _('REV')),
4678 ('r', 'rev', [], _('target revision'), _('REV')),
4679 ],
4679 ],
4680 _('[-p|-d|-s] [-f] [-r] REV...'))
4680 _('[-p|-d|-s] [-f] [-r] REV...'))
4681 def phase(ui, repo, *revs, **opts):
4681 def phase(ui, repo, *revs, **opts):
4682 """set or show the current phase name
4682 """set or show the current phase name
4683
4683
4684 With no argument, show the phase name of specified revisions.
4684 With no argument, show the phase name of specified revisions.
4685
4685
4686 With one of -p/--public, -d/--draft or -s/--secret, change the
4686 With one of -p/--public, -d/--draft or -s/--secret, change the
4687 phase value of the specified revisions.
4687 phase value of the specified revisions.
4688
4688
4689 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4689 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4690 lower phase to an higher phase. Phases are ordered as follows::
4690 lower phase to an higher phase. Phases are ordered as follows::
4691
4691
4692 public < draft < secret
4692 public < draft < secret
4693
4693
4694 Returns 0 on success, 1 if no phases were changed or some could not
4694 Returns 0 on success, 1 if no phases were changed or some could not
4695 be changed.
4695 be changed.
4696 """
4696 """
4697 # search for a unique phase argument
4697 # search for a unique phase argument
4698 targetphase = None
4698 targetphase = None
4699 for idx, name in enumerate(phases.phasenames):
4699 for idx, name in enumerate(phases.phasenames):
4700 if opts[name]:
4700 if opts[name]:
4701 if targetphase is not None:
4701 if targetphase is not None:
4702 raise util.Abort(_('only one phase can be specified'))
4702 raise util.Abort(_('only one phase can be specified'))
4703 targetphase = idx
4703 targetphase = idx
4704
4704
4705 # look for specified revision
4705 # look for specified revision
4706 revs = list(revs)
4706 revs = list(revs)
4707 revs.extend(opts['rev'])
4707 revs.extend(opts['rev'])
4708 if not revs:
4708 if not revs:
4709 raise util.Abort(_('no revisions specified'))
4709 raise util.Abort(_('no revisions specified'))
4710
4710
4711 revs = scmutil.revrange(repo, revs)
4711 revs = scmutil.revrange(repo, revs)
4712
4712
4713 lock = None
4713 lock = None
4714 ret = 0
4714 ret = 0
4715 if targetphase is None:
4715 if targetphase is None:
4716 # display
4716 # display
4717 for r in revs:
4717 for r in revs:
4718 ctx = repo[r]
4718 ctx = repo[r]
4719 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4719 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4720 else:
4720 else:
4721 tr = None
4721 tr = None
4722 lock = repo.lock()
4722 lock = repo.lock()
4723 try:
4723 try:
4724 tr = repo.transaction("phase")
4724 tr = repo.transaction("phase")
4725 # set phase
4725 # set phase
4726 if not revs:
4726 if not revs:
4727 raise util.Abort(_('empty revision set'))
4727 raise util.Abort(_('empty revision set'))
4728 nodes = [repo[r].node() for r in revs]
4728 nodes = [repo[r].node() for r in revs]
4729 olddata = repo._phasecache.getphaserevs(repo)[:]
4729 olddata = repo._phasecache.getphaserevs(repo)[:]
4730 phases.advanceboundary(repo, tr, targetphase, nodes)
4730 phases.advanceboundary(repo, tr, targetphase, nodes)
4731 if opts['force']:
4731 if opts['force']:
4732 phases.retractboundary(repo, tr, targetphase, nodes)
4732 phases.retractboundary(repo, tr, targetphase, nodes)
4733 tr.close()
4733 tr.close()
4734 finally:
4734 finally:
4735 if tr is not None:
4735 if tr is not None:
4736 tr.release()
4736 tr.release()
4737 lock.release()
4737 lock.release()
4738 # moving revision from public to draft may hide them
4738 # moving revision from public to draft may hide them
4739 # We have to check result on an unfiltered repository
4739 # We have to check result on an unfiltered repository
4740 unfi = repo.unfiltered()
4740 unfi = repo.unfiltered()
4741 newdata = repo._phasecache.getphaserevs(unfi)
4741 newdata = repo._phasecache.getphaserevs(unfi)
4742 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4742 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4743 cl = unfi.changelog
4743 cl = unfi.changelog
4744 rejected = [n for n in nodes
4744 rejected = [n for n in nodes
4745 if newdata[cl.rev(n)] < targetphase]
4745 if newdata[cl.rev(n)] < targetphase]
4746 if rejected:
4746 if rejected:
4747 ui.warn(_('cannot move %i changesets to a higher '
4747 ui.warn(_('cannot move %i changesets to a higher '
4748 'phase, use --force\n') % len(rejected))
4748 'phase, use --force\n') % len(rejected))
4749 ret = 1
4749 ret = 1
4750 if changes:
4750 if changes:
4751 msg = _('phase changed for %i changesets\n') % changes
4751 msg = _('phase changed for %i changesets\n') % changes
4752 if ret:
4752 if ret:
4753 ui.status(msg)
4753 ui.status(msg)
4754 else:
4754 else:
4755 ui.note(msg)
4755 ui.note(msg)
4756 else:
4756 else:
4757 ui.warn(_('no phases changed\n'))
4757 ui.warn(_('no phases changed\n'))
4758 ret = 1
4758 ret = 1
4759 return ret
4759 return ret
4760
4760
4761 def postincoming(ui, repo, modheads, optupdate, checkout):
4761 def postincoming(ui, repo, modheads, optupdate, checkout):
4762 if modheads == 0:
4762 if modheads == 0:
4763 return
4763 return
4764 if optupdate:
4764 if optupdate:
4765 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4765 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4766 try:
4766 try:
4767 ret = hg.update(repo, checkout)
4767 ret = hg.update(repo, checkout)
4768 except util.Abort, inst:
4768 except util.Abort, inst:
4769 ui.warn(_("not updating: %s\n") % str(inst))
4769 ui.warn(_("not updating: %s\n") % str(inst))
4770 if inst.hint:
4770 if inst.hint:
4771 ui.warn(_("(%s)\n") % inst.hint)
4771 ui.warn(_("(%s)\n") % inst.hint)
4772 return 0
4772 return 0
4773 if not ret and not checkout:
4773 if not ret and not checkout:
4774 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4774 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4775 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4775 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4776 return ret
4776 return ret
4777 if modheads > 1:
4777 if modheads > 1:
4778 currentbranchheads = len(repo.branchheads())
4778 currentbranchheads = len(repo.branchheads())
4779 if currentbranchheads == modheads:
4779 if currentbranchheads == modheads:
4780 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4780 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4781 elif currentbranchheads > 1:
4781 elif currentbranchheads > 1:
4782 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4782 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4783 "merge)\n"))
4783 "merge)\n"))
4784 else:
4784 else:
4785 ui.status(_("(run 'hg heads' to see heads)\n"))
4785 ui.status(_("(run 'hg heads' to see heads)\n"))
4786 else:
4786 else:
4787 ui.status(_("(run 'hg update' to get a working copy)\n"))
4787 ui.status(_("(run 'hg update' to get a working copy)\n"))
4788
4788
4789 @command('^pull',
4789 @command('^pull',
4790 [('u', 'update', None,
4790 [('u', 'update', None,
4791 _('update to new branch head if changesets were pulled')),
4791 _('update to new branch head if changesets were pulled')),
4792 ('f', 'force', None, _('run even when remote repository is unrelated')),
4792 ('f', 'force', None, _('run even when remote repository is unrelated')),
4793 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4793 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4794 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4794 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4795 ('b', 'branch', [], _('a specific branch you would like to pull'),
4795 ('b', 'branch', [], _('a specific branch you would like to pull'),
4796 _('BRANCH')),
4796 _('BRANCH')),
4797 ] + remoteopts,
4797 ] + remoteopts,
4798 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4798 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4799 def pull(ui, repo, source="default", **opts):
4799 def pull(ui, repo, source="default", **opts):
4800 """pull changes from the specified source
4800 """pull changes from the specified source
4801
4801
4802 Pull changes from a remote repository to a local one.
4802 Pull changes from a remote repository to a local one.
4803
4803
4804 This finds all changes from the repository at the specified path
4804 This finds all changes from the repository at the specified path
4805 or URL and adds them to a local repository (the current one unless
4805 or URL and adds them to a local repository (the current one unless
4806 -R is specified). By default, this does not update the copy of the
4806 -R is specified). By default, this does not update the copy of the
4807 project in the working directory.
4807 project in the working directory.
4808
4808
4809 Use :hg:`incoming` if you want to see what would have been added
4809 Use :hg:`incoming` if you want to see what would have been added
4810 by a pull at the time you issued this command. If you then decide
4810 by a pull at the time you issued this command. If you then decide
4811 to add those changes to the repository, you should use :hg:`pull
4811 to add those changes to the repository, you should use :hg:`pull
4812 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4812 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4813
4813
4814 If SOURCE is omitted, the 'default' path will be used.
4814 If SOURCE is omitted, the 'default' path will be used.
4815 See :hg:`help urls` for more information.
4815 See :hg:`help urls` for more information.
4816
4816
4817 Returns 0 on success, 1 if an update had unresolved files.
4817 Returns 0 on success, 1 if an update had unresolved files.
4818 """
4818 """
4819 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4819 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4820 other = hg.peer(repo, opts, source)
4820 other = hg.peer(repo, opts, source)
4821 try:
4821 try:
4822 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4822 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4823 revs, checkout = hg.addbranchrevs(repo, other, branches,
4823 revs, checkout = hg.addbranchrevs(repo, other, branches,
4824 opts.get('rev'))
4824 opts.get('rev'))
4825
4825
4826 remotebookmarks = other.listkeys('bookmarks')
4826 remotebookmarks = other.listkeys('bookmarks')
4827
4827
4828 if opts.get('bookmark'):
4828 if opts.get('bookmark'):
4829 if not revs:
4829 if not revs:
4830 revs = []
4830 revs = []
4831 for b in opts['bookmark']:
4831 for b in opts['bookmark']:
4832 if b not in remotebookmarks:
4832 if b not in remotebookmarks:
4833 raise util.Abort(_('remote bookmark %s not found!') % b)
4833 raise util.Abort(_('remote bookmark %s not found!') % b)
4834 revs.append(remotebookmarks[b])
4834 revs.append(remotebookmarks[b])
4835
4835
4836 if revs:
4836 if revs:
4837 try:
4837 try:
4838 revs = [other.lookup(rev) for rev in revs]
4838 revs = [other.lookup(rev) for rev in revs]
4839 except error.CapabilityError:
4839 except error.CapabilityError:
4840 err = _("other repository doesn't support revision lookup, "
4840 err = _("other repository doesn't support revision lookup, "
4841 "so a rev cannot be specified.")
4841 "so a rev cannot be specified.")
4842 raise util.Abort(err)
4842 raise util.Abort(err)
4843
4843
4844 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4844 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4845 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4845 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4846 if checkout:
4846 if checkout:
4847 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4847 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4848 repo._subtoppath = source
4848 repo._subtoppath = source
4849 try:
4849 try:
4850 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4850 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4851
4851
4852 finally:
4852 finally:
4853 del repo._subtoppath
4853 del repo._subtoppath
4854
4854
4855 # update specified bookmarks
4855 # update specified bookmarks
4856 if opts.get('bookmark'):
4856 if opts.get('bookmark'):
4857 marks = repo._bookmarks
4857 marks = repo._bookmarks
4858 for b in opts['bookmark']:
4858 for b in opts['bookmark']:
4859 # explicit pull overrides local bookmark if any
4859 # explicit pull overrides local bookmark if any
4860 ui.status(_("importing bookmark %s\n") % b)
4860 ui.status(_("importing bookmark %s\n") % b)
4861 marks[b] = repo[remotebookmarks[b]].node()
4861 marks[b] = repo[remotebookmarks[b]].node()
4862 marks.write()
4862 marks.write()
4863 finally:
4863 finally:
4864 other.close()
4864 other.close()
4865 return ret
4865 return ret
4866
4866
4867 @command('^push',
4867 @command('^push',
4868 [('f', 'force', None, _('force push')),
4868 [('f', 'force', None, _('force push')),
4869 ('r', 'rev', [],
4869 ('r', 'rev', [],
4870 _('a changeset intended to be included in the destination'),
4870 _('a changeset intended to be included in the destination'),
4871 _('REV')),
4871 _('REV')),
4872 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4872 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4873 ('b', 'branch', [],
4873 ('b', 'branch', [],
4874 _('a specific branch you would like to push'), _('BRANCH')),
4874 _('a specific branch you would like to push'), _('BRANCH')),
4875 ('', 'new-branch', False, _('allow pushing a new branch')),
4875 ('', 'new-branch', False, _('allow pushing a new branch')),
4876 ] + remoteopts,
4876 ] + remoteopts,
4877 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4877 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4878 def push(ui, repo, dest=None, **opts):
4878 def push(ui, repo, dest=None, **opts):
4879 """push changes to the specified destination
4879 """push changes to the specified destination
4880
4880
4881 Push changesets from the local repository to the specified
4881 Push changesets from the local repository to the specified
4882 destination.
4882 destination.
4883
4883
4884 This operation is symmetrical to pull: it is identical to a pull
4884 This operation is symmetrical to pull: it is identical to a pull
4885 in the destination repository from the current one.
4885 in the destination repository from the current one.
4886
4886
4887 By default, push will not allow creation of new heads at the
4887 By default, push will not allow creation of new heads at the
4888 destination, since multiple heads would make it unclear which head
4888 destination, since multiple heads would make it unclear which head
4889 to use. In this situation, it is recommended to pull and merge
4889 to use. In this situation, it is recommended to pull and merge
4890 before pushing.
4890 before pushing.
4891
4891
4892 Use --new-branch if you want to allow push to create a new named
4892 Use --new-branch if you want to allow push to create a new named
4893 branch that is not present at the destination. This allows you to
4893 branch that is not present at the destination. This allows you to
4894 only create a new branch without forcing other changes.
4894 only create a new branch without forcing other changes.
4895
4895
4896 .. note::
4896 .. note::
4897
4897
4898 Extra care should be taken with the -f/--force option,
4898 Extra care should be taken with the -f/--force option,
4899 which will push all new heads on all branches, an action which will
4899 which will push all new heads on all branches, an action which will
4900 almost always cause confusion for collaborators.
4900 almost always cause confusion for collaborators.
4901
4901
4902 If -r/--rev is used, the specified revision and all its ancestors
4902 If -r/--rev is used, the specified revision and all its ancestors
4903 will be pushed to the remote repository.
4903 will be pushed to the remote repository.
4904
4904
4905 If -B/--bookmark is used, the specified bookmarked revision, its
4905 If -B/--bookmark is used, the specified bookmarked revision, its
4906 ancestors, and the bookmark will be pushed to the remote
4906 ancestors, and the bookmark will be pushed to the remote
4907 repository.
4907 repository.
4908
4908
4909 Please see :hg:`help urls` for important details about ``ssh://``
4909 Please see :hg:`help urls` for important details about ``ssh://``
4910 URLs. If DESTINATION is omitted, a default path will be used.
4910 URLs. If DESTINATION is omitted, a default path will be used.
4911
4911
4912 Returns 0 if push was successful, 1 if nothing to push.
4912 Returns 0 if push was successful, 1 if nothing to push.
4913 """
4913 """
4914
4914
4915 if opts.get('bookmark'):
4915 if opts.get('bookmark'):
4916 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4916 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4917 for b in opts['bookmark']:
4917 for b in opts['bookmark']:
4918 # translate -B options to -r so changesets get pushed
4918 # translate -B options to -r so changesets get pushed
4919 if b in repo._bookmarks:
4919 if b in repo._bookmarks:
4920 opts.setdefault('rev', []).append(b)
4920 opts.setdefault('rev', []).append(b)
4921 else:
4921 else:
4922 # if we try to push a deleted bookmark, translate it to null
4922 # if we try to push a deleted bookmark, translate it to null
4923 # this lets simultaneous -r, -b options continue working
4923 # this lets simultaneous -r, -b options continue working
4924 opts.setdefault('rev', []).append("null")
4924 opts.setdefault('rev', []).append("null")
4925
4925
4926 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4926 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4927 dest, branches = hg.parseurl(dest, opts.get('branch'))
4927 dest, branches = hg.parseurl(dest, opts.get('branch'))
4928 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4928 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4929 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4929 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4930 try:
4930 try:
4931 other = hg.peer(repo, opts, dest)
4931 other = hg.peer(repo, opts, dest)
4932 except error.RepoError:
4932 except error.RepoError:
4933 if dest == "default-push":
4933 if dest == "default-push":
4934 raise util.Abort(_("default repository not configured!"),
4934 raise util.Abort(_("default repository not configured!"),
4935 hint=_('see the "path" section in "hg help config"'))
4935 hint=_('see the "path" section in "hg help config"'))
4936 else:
4936 else:
4937 raise
4937 raise
4938
4938
4939 if revs:
4939 if revs:
4940 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4940 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4941
4941
4942 repo._subtoppath = dest
4942 repo._subtoppath = dest
4943 try:
4943 try:
4944 # push subrepos depth-first for coherent ordering
4944 # push subrepos depth-first for coherent ordering
4945 c = repo['']
4945 c = repo['']
4946 subs = c.substate # only repos that are committed
4946 subs = c.substate # only repos that are committed
4947 for s in sorted(subs):
4947 for s in sorted(subs):
4948 result = c.sub(s).push(opts)
4948 result = c.sub(s).push(opts)
4949 if result == 0:
4949 if result == 0:
4950 return not result
4950 return not result
4951 finally:
4951 finally:
4952 del repo._subtoppath
4952 del repo._subtoppath
4953 result = repo.push(other, opts.get('force'), revs=revs,
4953 result = repo.push(other, opts.get('force'), revs=revs,
4954 newbranch=opts.get('new_branch'))
4954 newbranch=opts.get('new_branch'))
4955
4955
4956 result = not result
4956 result = not result
4957
4957
4958 if opts.get('bookmark'):
4958 if opts.get('bookmark'):
4959 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4959 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4960 if bresult == 2:
4960 if bresult == 2:
4961 return 2
4961 return 2
4962 if not result and bresult:
4962 if not result and bresult:
4963 result = 2
4963 result = 2
4964
4964
4965 return result
4965 return result
4966
4966
4967 @command('recover', [])
4967 @command('recover', [])
4968 def recover(ui, repo):
4968 def recover(ui, repo):
4969 """roll back an interrupted transaction
4969 """roll back an interrupted transaction
4970
4970
4971 Recover from an interrupted commit or pull.
4971 Recover from an interrupted commit or pull.
4972
4972
4973 This command tries to fix the repository status after an
4973 This command tries to fix the repository status after an
4974 interrupted operation. It should only be necessary when Mercurial
4974 interrupted operation. It should only be necessary when Mercurial
4975 suggests it.
4975 suggests it.
4976
4976
4977 Returns 0 if successful, 1 if nothing to recover or verify fails.
4977 Returns 0 if successful, 1 if nothing to recover or verify fails.
4978 """
4978 """
4979 if repo.recover():
4979 if repo.recover():
4980 return hg.verify(repo)
4980 return hg.verify(repo)
4981 return 1
4981 return 1
4982
4982
4983 @command('^remove|rm',
4983 @command('^remove|rm',
4984 [('A', 'after', None, _('record delete for missing files')),
4984 [('A', 'after', None, _('record delete for missing files')),
4985 ('f', 'force', None,
4985 ('f', 'force', None,
4986 _('remove (and delete) file even if added or modified')),
4986 _('remove (and delete) file even if added or modified')),
4987 ] + walkopts,
4987 ] + walkopts,
4988 _('[OPTION]... FILE...'),
4988 _('[OPTION]... FILE...'),
4989 inferrepo=True)
4989 inferrepo=True)
4990 def remove(ui, repo, *pats, **opts):
4990 def remove(ui, repo, *pats, **opts):
4991 """remove the specified files on the next commit
4991 """remove the specified files on the next commit
4992
4992
4993 Schedule the indicated files for removal from the current branch.
4993 Schedule the indicated files for removal from the current branch.
4994
4994
4995 This command schedules the files to be removed at the next commit.
4995 This command schedules the files to be removed at the next commit.
4996 To undo a remove before that, see :hg:`revert`. To undo added
4996 To undo a remove before that, see :hg:`revert`. To undo added
4997 files, see :hg:`forget`.
4997 files, see :hg:`forget`.
4998
4998
4999 .. container:: verbose
4999 .. container:: verbose
5000
5000
5001 -A/--after can be used to remove only files that have already
5001 -A/--after can be used to remove only files that have already
5002 been deleted, -f/--force can be used to force deletion, and -Af
5002 been deleted, -f/--force can be used to force deletion, and -Af
5003 can be used to remove files from the next revision without
5003 can be used to remove files from the next revision without
5004 deleting them from the working directory.
5004 deleting them from the working directory.
5005
5005
5006 The following table details the behavior of remove for different
5006 The following table details the behavior of remove for different
5007 file states (columns) and option combinations (rows). The file
5007 file states (columns) and option combinations (rows). The file
5008 states are Added [A], Clean [C], Modified [M] and Missing [!]
5008 states are Added [A], Clean [C], Modified [M] and Missing [!]
5009 (as reported by :hg:`status`). The actions are Warn, Remove
5009 (as reported by :hg:`status`). The actions are Warn, Remove
5010 (from branch) and Delete (from disk):
5010 (from branch) and Delete (from disk):
5011
5011
5012 ========= == == == ==
5012 ========= == == == ==
5013 opt/state A C M !
5013 opt/state A C M !
5014 ========= == == == ==
5014 ========= == == == ==
5015 none W RD W R
5015 none W RD W R
5016 -f R RD RD R
5016 -f R RD RD R
5017 -A W W W R
5017 -A W W W R
5018 -Af R R R R
5018 -Af R R R R
5019 ========= == == == ==
5019 ========= == == == ==
5020
5020
5021 Note that remove never deletes files in Added [A] state from the
5021 Note that remove never deletes files in Added [A] state from the
5022 working directory, not even if option --force is specified.
5022 working directory, not even if option --force is specified.
5023
5023
5024 Returns 0 on success, 1 if any warnings encountered.
5024 Returns 0 on success, 1 if any warnings encountered.
5025 """
5025 """
5026
5026
5027 ret = 0
5027 ret = 0
5028 after, force = opts.get('after'), opts.get('force')
5028 after, force = opts.get('after'), opts.get('force')
5029 if not pats and not after:
5029 if not pats and not after:
5030 raise util.Abort(_('no files specified'))
5030 raise util.Abort(_('no files specified'))
5031
5031
5032 m = scmutil.match(repo[None], pats, opts)
5032 m = scmutil.match(repo[None], pats, opts)
5033 s = repo.status(match=m, clean=True)
5033 s = repo.status(match=m, clean=True)
5034 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
5034 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
5035
5035
5036 # warn about failure to delete explicit files/dirs
5036 # warn about failure to delete explicit files/dirs
5037 wctx = repo[None]
5037 wctx = repo[None]
5038 for f in m.files():
5038 for f in m.files():
5039 if f in repo.dirstate or f in wctx.dirs():
5039 if f in repo.dirstate or f in wctx.dirs():
5040 continue
5040 continue
5041 if os.path.exists(m.rel(f)):
5041 if os.path.exists(m.rel(f)):
5042 if os.path.isdir(m.rel(f)):
5042 if os.path.isdir(m.rel(f)):
5043 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
5043 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
5044 else:
5044 else:
5045 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
5045 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
5046 # missing files will generate a warning elsewhere
5046 # missing files will generate a warning elsewhere
5047 ret = 1
5047 ret = 1
5048
5048
5049 if force:
5049 if force:
5050 list = modified + deleted + clean + added
5050 list = modified + deleted + clean + added
5051 elif after:
5051 elif after:
5052 list = deleted
5052 list = deleted
5053 for f in modified + added + clean:
5053 for f in modified + added + clean:
5054 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
5054 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
5055 ret = 1
5055 ret = 1
5056 else:
5056 else:
5057 list = deleted + clean
5057 list = deleted + clean
5058 for f in modified:
5058 for f in modified:
5059 ui.warn(_('not removing %s: file is modified (use -f'
5059 ui.warn(_('not removing %s: file is modified (use -f'
5060 ' to force removal)\n') % m.rel(f))
5060 ' to force removal)\n') % m.rel(f))
5061 ret = 1
5061 ret = 1
5062 for f in added:
5062 for f in added:
5063 ui.warn(_('not removing %s: file has been marked for add'
5063 ui.warn(_('not removing %s: file has been marked for add'
5064 ' (use forget to undo)\n') % m.rel(f))
5064 ' (use forget to undo)\n') % m.rel(f))
5065 ret = 1
5065 ret = 1
5066
5066
5067 for f in sorted(list):
5067 for f in sorted(list):
5068 if ui.verbose or not m.exact(f):
5068 if ui.verbose or not m.exact(f):
5069 ui.status(_('removing %s\n') % m.rel(f))
5069 ui.status(_('removing %s\n') % m.rel(f))
5070
5070
5071 wlock = repo.wlock()
5071 wlock = repo.wlock()
5072 try:
5072 try:
5073 if not after:
5073 if not after:
5074 for f in list:
5074 for f in list:
5075 if f in added:
5075 if f in added:
5076 continue # we never unlink added files on remove
5076 continue # we never unlink added files on remove
5077 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
5077 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
5078 repo[None].forget(list)
5078 repo[None].forget(list)
5079 finally:
5079 finally:
5080 wlock.release()
5080 wlock.release()
5081
5081
5082 return ret
5082 return ret
5083
5083
5084 @command('rename|move|mv',
5084 @command('rename|move|mv',
5085 [('A', 'after', None, _('record a rename that has already occurred')),
5085 [('A', 'after', None, _('record a rename that has already occurred')),
5086 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5086 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5087 ] + walkopts + dryrunopts,
5087 ] + walkopts + dryrunopts,
5088 _('[OPTION]... SOURCE... DEST'))
5088 _('[OPTION]... SOURCE... DEST'))
5089 def rename(ui, repo, *pats, **opts):
5089 def rename(ui, repo, *pats, **opts):
5090 """rename files; equivalent of copy + remove
5090 """rename files; equivalent of copy + remove
5091
5091
5092 Mark dest as copies of sources; mark sources for deletion. If dest
5092 Mark dest as copies of sources; mark sources for deletion. If dest
5093 is a directory, copies are put in that directory. If dest is a
5093 is a directory, copies are put in that directory. If dest is a
5094 file, there can only be one source.
5094 file, there can only be one source.
5095
5095
5096 By default, this command copies the contents of files as they
5096 By default, this command copies the contents of files as they
5097 exist in the working directory. If invoked with -A/--after, the
5097 exist in the working directory. If invoked with -A/--after, the
5098 operation is recorded, but no copying is performed.
5098 operation is recorded, but no copying is performed.
5099
5099
5100 This command takes effect at the next commit. To undo a rename
5100 This command takes effect at the next commit. To undo a rename
5101 before that, see :hg:`revert`.
5101 before that, see :hg:`revert`.
5102
5102
5103 Returns 0 on success, 1 if errors are encountered.
5103 Returns 0 on success, 1 if errors are encountered.
5104 """
5104 """
5105 wlock = repo.wlock(False)
5105 wlock = repo.wlock(False)
5106 try:
5106 try:
5107 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5107 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5108 finally:
5108 finally:
5109 wlock.release()
5109 wlock.release()
5110
5110
5111 @command('resolve',
5111 @command('resolve',
5112 [('a', 'all', None, _('select all unresolved files')),
5112 [('a', 'all', None, _('select all unresolved files')),
5113 ('l', 'list', None, _('list state of files needing merge')),
5113 ('l', 'list', None, _('list state of files needing merge')),
5114 ('m', 'mark', None, _('mark files as resolved')),
5114 ('m', 'mark', None, _('mark files as resolved')),
5115 ('u', 'unmark', None, _('mark files as unresolved')),
5115 ('u', 'unmark', None, _('mark files as unresolved')),
5116 ('n', 'no-status', None, _('hide status prefix'))]
5116 ('n', 'no-status', None, _('hide status prefix'))]
5117 + mergetoolopts + walkopts,
5117 + mergetoolopts + walkopts,
5118 _('[OPTION]... [FILE]...'),
5118 _('[OPTION]... [FILE]...'),
5119 inferrepo=True)
5119 inferrepo=True)
5120 def resolve(ui, repo, *pats, **opts):
5120 def resolve(ui, repo, *pats, **opts):
5121 """redo merges or set/view the merge status of files
5121 """redo merges or set/view the merge status of files
5122
5122
5123 Merges with unresolved conflicts are often the result of
5123 Merges with unresolved conflicts are often the result of
5124 non-interactive merging using the ``internal:merge`` configuration
5124 non-interactive merging using the ``internal:merge`` configuration
5125 setting, or a command-line merge tool like ``diff3``. The resolve
5125 setting, or a command-line merge tool like ``diff3``. The resolve
5126 command is used to manage the files involved in a merge, after
5126 command is used to manage the files involved in a merge, after
5127 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5127 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5128 working directory must have two parents). See :hg:`help
5128 working directory must have two parents). See :hg:`help
5129 merge-tools` for information on configuring merge tools.
5129 merge-tools` for information on configuring merge tools.
5130
5130
5131 The resolve command can be used in the following ways:
5131 The resolve command can be used in the following ways:
5132
5132
5133 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5133 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5134 files, discarding any previous merge attempts. Re-merging is not
5134 files, discarding any previous merge attempts. Re-merging is not
5135 performed for files already marked as resolved. Use ``--all/-a``
5135 performed for files already marked as resolved. Use ``--all/-a``
5136 to select all unresolved files. ``--tool`` can be used to specify
5136 to select all unresolved files. ``--tool`` can be used to specify
5137 the merge tool used for the given files. It overrides the HGMERGE
5137 the merge tool used for the given files. It overrides the HGMERGE
5138 environment variable and your configuration files. Previous file
5138 environment variable and your configuration files. Previous file
5139 contents are saved with a ``.orig`` suffix.
5139 contents are saved with a ``.orig`` suffix.
5140
5140
5141 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5141 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5142 (e.g. after having manually fixed-up the files). The default is
5142 (e.g. after having manually fixed-up the files). The default is
5143 to mark all unresolved files.
5143 to mark all unresolved files.
5144
5144
5145 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5145 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5146 default is to mark all resolved files.
5146 default is to mark all resolved files.
5147
5147
5148 - :hg:`resolve -l`: list files which had or still have conflicts.
5148 - :hg:`resolve -l`: list files which had or still have conflicts.
5149 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5149 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5150
5150
5151 Note that Mercurial will not let you commit files with unresolved
5151 Note that Mercurial will not let you commit files with unresolved
5152 merge conflicts. You must use :hg:`resolve -m ...` before you can
5152 merge conflicts. You must use :hg:`resolve -m ...` before you can
5153 commit after a conflicting merge.
5153 commit after a conflicting merge.
5154
5154
5155 Returns 0 on success, 1 if any files fail a resolve attempt.
5155 Returns 0 on success, 1 if any files fail a resolve attempt.
5156 """
5156 """
5157
5157
5158 all, mark, unmark, show, nostatus = \
5158 all, mark, unmark, show, nostatus = \
5159 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5159 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5160
5160
5161 if (show and (mark or unmark)) or (mark and unmark):
5161 if (show and (mark or unmark)) or (mark and unmark):
5162 raise util.Abort(_("too many options specified"))
5162 raise util.Abort(_("too many options specified"))
5163 if pats and all:
5163 if pats and all:
5164 raise util.Abort(_("can't specify --all and patterns"))
5164 raise util.Abort(_("can't specify --all and patterns"))
5165 if not (all or pats or show or mark or unmark):
5165 if not (all or pats or show or mark or unmark):
5166 raise util.Abort(_('no files or directories specified'),
5166 raise util.Abort(_('no files or directories specified'),
5167 hint=('use --all to remerge all files'))
5167 hint=('use --all to remerge all files'))
5168
5168
5169 wlock = repo.wlock()
5169 wlock = repo.wlock()
5170 try:
5170 try:
5171 ms = mergemod.mergestate(repo)
5171 ms = mergemod.mergestate(repo)
5172
5172
5173 if not ms.active() and not show:
5173 if not ms.active() and not show:
5174 raise util.Abort(
5174 raise util.Abort(
5175 _('resolve command not applicable when not merging'))
5175 _('resolve command not applicable when not merging'))
5176
5176
5177 m = scmutil.match(repo[None], pats, opts)
5177 m = scmutil.match(repo[None], pats, opts)
5178 ret = 0
5178 ret = 0
5179 didwork = False
5179 didwork = False
5180
5180
5181 for f in ms:
5181 for f in ms:
5182 if not m(f):
5182 if not m(f):
5183 continue
5183 continue
5184
5184
5185 didwork = True
5185 didwork = True
5186
5186
5187 if show:
5187 if show:
5188 if nostatus:
5188 if nostatus:
5189 ui.write("%s\n" % f)
5189 ui.write("%s\n" % f)
5190 else:
5190 else:
5191 ui.write("%s %s\n" % (ms[f].upper(), f),
5191 ui.write("%s %s\n" % (ms[f].upper(), f),
5192 label='resolve.' +
5192 label='resolve.' +
5193 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5193 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5194 elif mark:
5194 elif mark:
5195 ms.mark(f, "r")
5195 ms.mark(f, "r")
5196 elif unmark:
5196 elif unmark:
5197 ms.mark(f, "u")
5197 ms.mark(f, "u")
5198 else:
5198 else:
5199 wctx = repo[None]
5199 wctx = repo[None]
5200
5200
5201 # backup pre-resolve (merge uses .orig for its own purposes)
5201 # backup pre-resolve (merge uses .orig for its own purposes)
5202 a = repo.wjoin(f)
5202 a = repo.wjoin(f)
5203 util.copyfile(a, a + ".resolve")
5203 util.copyfile(a, a + ".resolve")
5204
5204
5205 try:
5205 try:
5206 # resolve file
5206 # resolve file
5207 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5207 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5208 'resolve')
5208 'resolve')
5209 if ms.resolve(f, wctx):
5209 if ms.resolve(f, wctx):
5210 ret = 1
5210 ret = 1
5211 finally:
5211 finally:
5212 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5212 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5213 ms.commit()
5213 ms.commit()
5214
5214
5215 # replace filemerge's .orig file with our resolve file
5215 # replace filemerge's .orig file with our resolve file
5216 util.rename(a + ".resolve", a + ".orig")
5216 util.rename(a + ".resolve", a + ".orig")
5217
5217
5218 ms.commit()
5218 ms.commit()
5219
5219
5220 if not didwork and pats:
5220 if not didwork and pats:
5221 ui.warn(_("arguments do not match paths that need resolving\n"))
5221 ui.warn(_("arguments do not match paths that need resolving\n"))
5222
5222
5223 finally:
5223 finally:
5224 wlock.release()
5224 wlock.release()
5225
5225
5226 # Nudge users into finishing an unfinished operation. We don't print
5226 # Nudge users into finishing an unfinished operation. We don't print
5227 # this with the list/show operation because we want list/show to remain
5227 # this with the list/show operation because we want list/show to remain
5228 # machine readable.
5228 # machine readable.
5229 if not list(ms.unresolved()) and not show:
5229 if not list(ms.unresolved()) and not show:
5230 ui.status(_('(no more unresolved files)\n'))
5230 ui.status(_('(no more unresolved files)\n'))
5231
5231
5232 return ret
5232 return ret
5233
5233
5234 @command('revert',
5234 @command('revert',
5235 [('a', 'all', None, _('revert all changes when no arguments given')),
5235 [('a', 'all', None, _('revert all changes when no arguments given')),
5236 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5236 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5237 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5237 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5238 ('C', 'no-backup', None, _('do not save backup copies of files')),
5238 ('C', 'no-backup', None, _('do not save backup copies of files')),
5239 ] + walkopts + dryrunopts,
5239 ] + walkopts + dryrunopts,
5240 _('[OPTION]... [-r REV] [NAME]...'))
5240 _('[OPTION]... [-r REV] [NAME]...'))
5241 def revert(ui, repo, *pats, **opts):
5241 def revert(ui, repo, *pats, **opts):
5242 """restore files to their checkout state
5242 """restore files to their checkout state
5243
5243
5244 .. note::
5244 .. note::
5245
5245
5246 To check out earlier revisions, you should use :hg:`update REV`.
5246 To check out earlier revisions, you should use :hg:`update REV`.
5247 To cancel an uncommitted merge (and lose your changes),
5247 To cancel an uncommitted merge (and lose your changes),
5248 use :hg:`update --clean .`.
5248 use :hg:`update --clean .`.
5249
5249
5250 With no revision specified, revert the specified files or directories
5250 With no revision specified, revert the specified files or directories
5251 to the contents they had in the parent of the working directory.
5251 to the contents they had in the parent of the working directory.
5252 This restores the contents of files to an unmodified
5252 This restores the contents of files to an unmodified
5253 state and unschedules adds, removes, copies, and renames. If the
5253 state and unschedules adds, removes, copies, and renames. If the
5254 working directory has two parents, you must explicitly specify a
5254 working directory has two parents, you must explicitly specify a
5255 revision.
5255 revision.
5256
5256
5257 Using the -r/--rev or -d/--date options, revert the given files or
5257 Using the -r/--rev or -d/--date options, revert the given files or
5258 directories to their states as of a specific revision. Because
5258 directories to their states as of a specific revision. Because
5259 revert does not change the working directory parents, this will
5259 revert does not change the working directory parents, this will
5260 cause these files to appear modified. This can be helpful to "back
5260 cause these files to appear modified. This can be helpful to "back
5261 out" some or all of an earlier change. See :hg:`backout` for a
5261 out" some or all of an earlier change. See :hg:`backout` for a
5262 related method.
5262 related method.
5263
5263
5264 Modified files are saved with a .orig suffix before reverting.
5264 Modified files are saved with a .orig suffix before reverting.
5265 To disable these backups, use --no-backup.
5265 To disable these backups, use --no-backup.
5266
5266
5267 See :hg:`help dates` for a list of formats valid for -d/--date.
5267 See :hg:`help dates` for a list of formats valid for -d/--date.
5268
5268
5269 Returns 0 on success.
5269 Returns 0 on success.
5270 """
5270 """
5271
5271
5272 if opts.get("date"):
5272 if opts.get("date"):
5273 if opts.get("rev"):
5273 if opts.get("rev"):
5274 raise util.Abort(_("you can't specify a revision and a date"))
5274 raise util.Abort(_("you can't specify a revision and a date"))
5275 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5275 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5276
5276
5277 parent, p2 = repo.dirstate.parents()
5277 parent, p2 = repo.dirstate.parents()
5278 if not opts.get('rev') and p2 != nullid:
5278 if not opts.get('rev') and p2 != nullid:
5279 # revert after merge is a trap for new users (issue2915)
5279 # revert after merge is a trap for new users (issue2915)
5280 raise util.Abort(_('uncommitted merge with no revision specified'),
5280 raise util.Abort(_('uncommitted merge with no revision specified'),
5281 hint=_('use "hg update" or see "hg help revert"'))
5281 hint=_('use "hg update" or see "hg help revert"'))
5282
5282
5283 ctx = scmutil.revsingle(repo, opts.get('rev'))
5283 ctx = scmutil.revsingle(repo, opts.get('rev'))
5284
5284
5285 if not pats and not opts.get('all'):
5285 if not pats and not opts.get('all'):
5286 msg = _("no files or directories specified")
5286 msg = _("no files or directories specified")
5287 if p2 != nullid:
5287 if p2 != nullid:
5288 hint = _("uncommitted merge, use --all to discard all changes,"
5288 hint = _("uncommitted merge, use --all to discard all changes,"
5289 " or 'hg update -C .' to abort the merge")
5289 " or 'hg update -C .' to abort the merge")
5290 raise util.Abort(msg, hint=hint)
5290 raise util.Abort(msg, hint=hint)
5291 dirty = util.any(repo.status())
5291 dirty = util.any(repo.status())
5292 node = ctx.node()
5292 node = ctx.node()
5293 if node != parent:
5293 if node != parent:
5294 if dirty:
5294 if dirty:
5295 hint = _("uncommitted changes, use --all to discard all"
5295 hint = _("uncommitted changes, use --all to discard all"
5296 " changes, or 'hg update %s' to update") % ctx.rev()
5296 " changes, or 'hg update %s' to update") % ctx.rev()
5297 else:
5297 else:
5298 hint = _("use --all to revert all files,"
5298 hint = _("use --all to revert all files,"
5299 " or 'hg update %s' to update") % ctx.rev()
5299 " or 'hg update %s' to update") % ctx.rev()
5300 elif dirty:
5300 elif dirty:
5301 hint = _("uncommitted changes, use --all to discard all changes")
5301 hint = _("uncommitted changes, use --all to discard all changes")
5302 else:
5302 else:
5303 hint = _("use --all to revert all files")
5303 hint = _("use --all to revert all files")
5304 raise util.Abort(msg, hint=hint)
5304 raise util.Abort(msg, hint=hint)
5305
5305
5306 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5306 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5307
5307
5308 @command('rollback', dryrunopts +
5308 @command('rollback', dryrunopts +
5309 [('f', 'force', False, _('ignore safety measures'))])
5309 [('f', 'force', False, _('ignore safety measures'))])
5310 def rollback(ui, repo, **opts):
5310 def rollback(ui, repo, **opts):
5311 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5311 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5312
5312
5313 Please use :hg:`commit --amend` instead of rollback to correct
5313 Please use :hg:`commit --amend` instead of rollback to correct
5314 mistakes in the last commit.
5314 mistakes in the last commit.
5315
5315
5316 This command should be used with care. There is only one level of
5316 This command should be used with care. There is only one level of
5317 rollback, and there is no way to undo a rollback. It will also
5317 rollback, and there is no way to undo a rollback. It will also
5318 restore the dirstate at the time of the last transaction, losing
5318 restore the dirstate at the time of the last transaction, losing
5319 any dirstate changes since that time. This command does not alter
5319 any dirstate changes since that time. This command does not alter
5320 the working directory.
5320 the working directory.
5321
5321
5322 Transactions are used to encapsulate the effects of all commands
5322 Transactions are used to encapsulate the effects of all commands
5323 that create new changesets or propagate existing changesets into a
5323 that create new changesets or propagate existing changesets into a
5324 repository.
5324 repository.
5325
5325
5326 .. container:: verbose
5326 .. container:: verbose
5327
5327
5328 For example, the following commands are transactional, and their
5328 For example, the following commands are transactional, and their
5329 effects can be rolled back:
5329 effects can be rolled back:
5330
5330
5331 - commit
5331 - commit
5332 - import
5332 - import
5333 - pull
5333 - pull
5334 - push (with this repository as the destination)
5334 - push (with this repository as the destination)
5335 - unbundle
5335 - unbundle
5336
5336
5337 To avoid permanent data loss, rollback will refuse to rollback a
5337 To avoid permanent data loss, rollback will refuse to rollback a
5338 commit transaction if it isn't checked out. Use --force to
5338 commit transaction if it isn't checked out. Use --force to
5339 override this protection.
5339 override this protection.
5340
5340
5341 This command is not intended for use on public repositories. Once
5341 This command is not intended for use on public repositories. Once
5342 changes are visible for pull by other users, rolling a transaction
5342 changes are visible for pull by other users, rolling a transaction
5343 back locally is ineffective (someone else may already have pulled
5343 back locally is ineffective (someone else may already have pulled
5344 the changes). Furthermore, a race is possible with readers of the
5344 the changes). Furthermore, a race is possible with readers of the
5345 repository; for example an in-progress pull from the repository
5345 repository; for example an in-progress pull from the repository
5346 may fail if a rollback is performed.
5346 may fail if a rollback is performed.
5347
5347
5348 Returns 0 on success, 1 if no rollback data is available.
5348 Returns 0 on success, 1 if no rollback data is available.
5349 """
5349 """
5350 return repo.rollback(dryrun=opts.get('dry_run'),
5350 return repo.rollback(dryrun=opts.get('dry_run'),
5351 force=opts.get('force'))
5351 force=opts.get('force'))
5352
5352
5353 @command('root', [])
5353 @command('root', [])
5354 def root(ui, repo):
5354 def root(ui, repo):
5355 """print the root (top) of the current working directory
5355 """print the root (top) of the current working directory
5356
5356
5357 Print the root directory of the current repository.
5357 Print the root directory of the current repository.
5358
5358
5359 Returns 0 on success.
5359 Returns 0 on success.
5360 """
5360 """
5361 ui.write(repo.root + "\n")
5361 ui.write(repo.root + "\n")
5362
5362
5363 @command('^serve',
5363 @command('^serve',
5364 [('A', 'accesslog', '', _('name of access log file to write to'),
5364 [('A', 'accesslog', '', _('name of access log file to write to'),
5365 _('FILE')),
5365 _('FILE')),
5366 ('d', 'daemon', None, _('run server in background')),
5366 ('d', 'daemon', None, _('run server in background')),
5367 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5367 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5368 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5368 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5369 # use string type, then we can check if something was passed
5369 # use string type, then we can check if something was passed
5370 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5370 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5371 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5371 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5372 _('ADDR')),
5372 _('ADDR')),
5373 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5373 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5374 _('PREFIX')),
5374 _('PREFIX')),
5375 ('n', 'name', '',
5375 ('n', 'name', '',
5376 _('name to show in web pages (default: working directory)'), _('NAME')),
5376 _('name to show in web pages (default: working directory)'), _('NAME')),
5377 ('', 'web-conf', '',
5377 ('', 'web-conf', '',
5378 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5378 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5379 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5379 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5380 _('FILE')),
5380 _('FILE')),
5381 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5381 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5382 ('', 'stdio', None, _('for remote clients')),
5382 ('', 'stdio', None, _('for remote clients')),
5383 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5383 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5384 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5384 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5385 ('', 'style', '', _('template style to use'), _('STYLE')),
5385 ('', 'style', '', _('template style to use'), _('STYLE')),
5386 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5386 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5387 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5387 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5388 _('[OPTION]...'),
5388 _('[OPTION]...'),
5389 optionalrepo=True)
5389 optionalrepo=True)
5390 def serve(ui, repo, **opts):
5390 def serve(ui, repo, **opts):
5391 """start stand-alone webserver
5391 """start stand-alone webserver
5392
5392
5393 Start a local HTTP repository browser and pull server. You can use
5393 Start a local HTTP repository browser and pull server. You can use
5394 this for ad-hoc sharing and browsing of repositories. It is
5394 this for ad-hoc sharing and browsing of repositories. It is
5395 recommended to use a real web server to serve a repository for
5395 recommended to use a real web server to serve a repository for
5396 longer periods of time.
5396 longer periods of time.
5397
5397
5398 Please note that the server does not implement access control.
5398 Please note that the server does not implement access control.
5399 This means that, by default, anybody can read from the server and
5399 This means that, by default, anybody can read from the server and
5400 nobody can write to it by default. Set the ``web.allow_push``
5400 nobody can write to it by default. Set the ``web.allow_push``
5401 option to ``*`` to allow everybody to push to the server. You
5401 option to ``*`` to allow everybody to push to the server. You
5402 should use a real web server if you need to authenticate users.
5402 should use a real web server if you need to authenticate users.
5403
5403
5404 By default, the server logs accesses to stdout and errors to
5404 By default, the server logs accesses to stdout and errors to
5405 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5405 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5406 files.
5406 files.
5407
5407
5408 To have the server choose a free port number to listen on, specify
5408 To have the server choose a free port number to listen on, specify
5409 a port number of 0; in this case, the server will print the port
5409 a port number of 0; in this case, the server will print the port
5410 number it uses.
5410 number it uses.
5411
5411
5412 Returns 0 on success.
5412 Returns 0 on success.
5413 """
5413 """
5414
5414
5415 if opts["stdio"] and opts["cmdserver"]:
5415 if opts["stdio"] and opts["cmdserver"]:
5416 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5416 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5417
5417
5418 if opts["stdio"]:
5418 if opts["stdio"]:
5419 if repo is None:
5419 if repo is None:
5420 raise error.RepoError(_("there is no Mercurial repository here"
5420 raise error.RepoError(_("there is no Mercurial repository here"
5421 " (.hg not found)"))
5421 " (.hg not found)"))
5422 s = sshserver.sshserver(ui, repo)
5422 s = sshserver.sshserver(ui, repo)
5423 s.serve_forever()
5423 s.serve_forever()
5424
5424
5425 if opts["cmdserver"]:
5425 if opts["cmdserver"]:
5426 s = commandserver.server(ui, repo, opts["cmdserver"])
5426 s = commandserver.server(ui, repo, opts["cmdserver"])
5427 return s.serve()
5427 return s.serve()
5428
5428
5429 # this way we can check if something was given in the command-line
5429 # this way we can check if something was given in the command-line
5430 if opts.get('port'):
5430 if opts.get('port'):
5431 opts['port'] = util.getport(opts.get('port'))
5431 opts['port'] = util.getport(opts.get('port'))
5432
5432
5433 baseui = repo and repo.baseui or ui
5433 baseui = repo and repo.baseui or ui
5434 optlist = ("name templates style address port prefix ipv6"
5434 optlist = ("name templates style address port prefix ipv6"
5435 " accesslog errorlog certificate encoding")
5435 " accesslog errorlog certificate encoding")
5436 for o in optlist.split():
5436 for o in optlist.split():
5437 val = opts.get(o, '')
5437 val = opts.get(o, '')
5438 if val in (None, ''): # should check against default options instead
5438 if val in (None, ''): # should check against default options instead
5439 continue
5439 continue
5440 baseui.setconfig("web", o, val, 'serve')
5440 baseui.setconfig("web", o, val, 'serve')
5441 if repo and repo.ui != baseui:
5441 if repo and repo.ui != baseui:
5442 repo.ui.setconfig("web", o, val, 'serve')
5442 repo.ui.setconfig("web", o, val, 'serve')
5443
5443
5444 o = opts.get('web_conf') or opts.get('webdir_conf')
5444 o = opts.get('web_conf') or opts.get('webdir_conf')
5445 if not o:
5445 if not o:
5446 if not repo:
5446 if not repo:
5447 raise error.RepoError(_("there is no Mercurial repository"
5447 raise error.RepoError(_("there is no Mercurial repository"
5448 " here (.hg not found)"))
5448 " here (.hg not found)"))
5449 o = repo
5449 o = repo
5450
5450
5451 app = hgweb.hgweb(o, baseui=baseui)
5451 app = hgweb.hgweb(o, baseui=baseui)
5452 service = httpservice(ui, app, opts)
5452 service = httpservice(ui, app, opts)
5453 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5453 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5454
5454
5455 class httpservice(object):
5455 class httpservice(object):
5456 def __init__(self, ui, app, opts):
5456 def __init__(self, ui, app, opts):
5457 self.ui = ui
5457 self.ui = ui
5458 self.app = app
5458 self.app = app
5459 self.opts = opts
5459 self.opts = opts
5460
5460
5461 def init(self):
5461 def init(self):
5462 util.setsignalhandler()
5462 util.setsignalhandler()
5463 self.httpd = hgweb_server.create_server(self.ui, self.app)
5463 self.httpd = hgweb_server.create_server(self.ui, self.app)
5464
5464
5465 if self.opts['port'] and not self.ui.verbose:
5465 if self.opts['port'] and not self.ui.verbose:
5466 return
5466 return
5467
5467
5468 if self.httpd.prefix:
5468 if self.httpd.prefix:
5469 prefix = self.httpd.prefix.strip('/') + '/'
5469 prefix = self.httpd.prefix.strip('/') + '/'
5470 else:
5470 else:
5471 prefix = ''
5471 prefix = ''
5472
5472
5473 port = ':%d' % self.httpd.port
5473 port = ':%d' % self.httpd.port
5474 if port == ':80':
5474 if port == ':80':
5475 port = ''
5475 port = ''
5476
5476
5477 bindaddr = self.httpd.addr
5477 bindaddr = self.httpd.addr
5478 if bindaddr == '0.0.0.0':
5478 if bindaddr == '0.0.0.0':
5479 bindaddr = '*'
5479 bindaddr = '*'
5480 elif ':' in bindaddr: # IPv6
5480 elif ':' in bindaddr: # IPv6
5481 bindaddr = '[%s]' % bindaddr
5481 bindaddr = '[%s]' % bindaddr
5482
5482
5483 fqaddr = self.httpd.fqaddr
5483 fqaddr = self.httpd.fqaddr
5484 if ':' in fqaddr:
5484 if ':' in fqaddr:
5485 fqaddr = '[%s]' % fqaddr
5485 fqaddr = '[%s]' % fqaddr
5486 if self.opts['port']:
5486 if self.opts['port']:
5487 write = self.ui.status
5487 write = self.ui.status
5488 else:
5488 else:
5489 write = self.ui.write
5489 write = self.ui.write
5490 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5490 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5491 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5491 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5492 self.ui.flush() # avoid buffering of status message
5492 self.ui.flush() # avoid buffering of status message
5493
5493
5494 def run(self):
5494 def run(self):
5495 self.httpd.serve_forever()
5495 self.httpd.serve_forever()
5496
5496
5497
5497
5498 @command('^status|st',
5498 @command('^status|st',
5499 [('A', 'all', None, _('show status of all files')),
5499 [('A', 'all', None, _('show status of all files')),
5500 ('m', 'modified', None, _('show only modified files')),
5500 ('m', 'modified', None, _('show only modified files')),
5501 ('a', 'added', None, _('show only added files')),
5501 ('a', 'added', None, _('show only added files')),
5502 ('r', 'removed', None, _('show only removed files')),
5502 ('r', 'removed', None, _('show only removed files')),
5503 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5503 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5504 ('c', 'clean', None, _('show only files without changes')),
5504 ('c', 'clean', None, _('show only files without changes')),
5505 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5505 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5506 ('i', 'ignored', None, _('show only ignored files')),
5506 ('i', 'ignored', None, _('show only ignored files')),
5507 ('n', 'no-status', None, _('hide status prefix')),
5507 ('n', 'no-status', None, _('hide status prefix')),
5508 ('C', 'copies', None, _('show source of copied files')),
5508 ('C', 'copies', None, _('show source of copied files')),
5509 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5509 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5510 ('', 'rev', [], _('show difference from revision'), _('REV')),
5510 ('', 'rev', [], _('show difference from revision'), _('REV')),
5511 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5511 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5512 ] + walkopts + subrepoopts + formatteropts,
5512 ] + walkopts + subrepoopts + formatteropts,
5513 _('[OPTION]... [FILE]...'),
5513 _('[OPTION]... [FILE]...'),
5514 inferrepo=True)
5514 inferrepo=True)
5515 def status(ui, repo, *pats, **opts):
5515 def status(ui, repo, *pats, **opts):
5516 """show changed files in the working directory
5516 """show changed files in the working directory
5517
5517
5518 Show status of files in the repository. If names are given, only
5518 Show status of files in the repository. If names are given, only
5519 files that match are shown. Files that are clean or ignored or
5519 files that match are shown. Files that are clean or ignored or
5520 the source of a copy/move operation, are not listed unless
5520 the source of a copy/move operation, are not listed unless
5521 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5521 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5522 Unless options described with "show only ..." are given, the
5522 Unless options described with "show only ..." are given, the
5523 options -mardu are used.
5523 options -mardu are used.
5524
5524
5525 Option -q/--quiet hides untracked (unknown and ignored) files
5525 Option -q/--quiet hides untracked (unknown and ignored) files
5526 unless explicitly requested with -u/--unknown or -i/--ignored.
5526 unless explicitly requested with -u/--unknown or -i/--ignored.
5527
5527
5528 .. note::
5528 .. note::
5529
5529
5530 status may appear to disagree with diff if permissions have
5530 status may appear to disagree with diff if permissions have
5531 changed or a merge has occurred. The standard diff format does
5531 changed or a merge has occurred. The standard diff format does
5532 not report permission changes and diff only reports changes
5532 not report permission changes and diff only reports changes
5533 relative to one merge parent.
5533 relative to one merge parent.
5534
5534
5535 If one revision is given, it is used as the base revision.
5535 If one revision is given, it is used as the base revision.
5536 If two revisions are given, the differences between them are
5536 If two revisions are given, the differences between them are
5537 shown. The --change option can also be used as a shortcut to list
5537 shown. The --change option can also be used as a shortcut to list
5538 the changed files of a revision from its first parent.
5538 the changed files of a revision from its first parent.
5539
5539
5540 The codes used to show the status of files are::
5540 The codes used to show the status of files are::
5541
5541
5542 M = modified
5542 M = modified
5543 A = added
5543 A = added
5544 R = removed
5544 R = removed
5545 C = clean
5545 C = clean
5546 ! = missing (deleted by non-hg command, but still tracked)
5546 ! = missing (deleted by non-hg command, but still tracked)
5547 ? = not tracked
5547 ? = not tracked
5548 I = ignored
5548 I = ignored
5549 = origin of the previous file (with --copies)
5549 = origin of the previous file (with --copies)
5550
5550
5551 .. container:: verbose
5551 .. container:: verbose
5552
5552
5553 Examples:
5553 Examples:
5554
5554
5555 - show changes in the working directory relative to a
5555 - show changes in the working directory relative to a
5556 changeset::
5556 changeset::
5557
5557
5558 hg status --rev 9353
5558 hg status --rev 9353
5559
5559
5560 - show all changes including copies in an existing changeset::
5560 - show all changes including copies in an existing changeset::
5561
5561
5562 hg status --copies --change 9353
5562 hg status --copies --change 9353
5563
5563
5564 - get a NUL separated list of added files, suitable for xargs::
5564 - get a NUL separated list of added files, suitable for xargs::
5565
5565
5566 hg status -an0
5566 hg status -an0
5567
5567
5568 Returns 0 on success.
5568 Returns 0 on success.
5569 """
5569 """
5570
5570
5571 revs = opts.get('rev')
5571 revs = opts.get('rev')
5572 change = opts.get('change')
5572 change = opts.get('change')
5573
5573
5574 if revs and change:
5574 if revs and change:
5575 msg = _('cannot specify --rev and --change at the same time')
5575 msg = _('cannot specify --rev and --change at the same time')
5576 raise util.Abort(msg)
5576 raise util.Abort(msg)
5577 elif change:
5577 elif change:
5578 node2 = scmutil.revsingle(repo, change, None).node()
5578 node2 = scmutil.revsingle(repo, change, None).node()
5579 node1 = repo[node2].p1().node()
5579 node1 = repo[node2].p1().node()
5580 else:
5580 else:
5581 node1, node2 = scmutil.revpair(repo, revs)
5581 node1, node2 = scmutil.revpair(repo, revs)
5582
5582
5583 cwd = (pats and repo.getcwd()) or ''
5583 cwd = (pats and repo.getcwd()) or ''
5584 end = opts.get('print0') and '\0' or '\n'
5584 end = opts.get('print0') and '\0' or '\n'
5585 copy = {}
5585 copy = {}
5586 states = 'modified added removed deleted unknown ignored clean'.split()
5586 states = 'modified added removed deleted unknown ignored clean'.split()
5587 show = [k for k in states if opts.get(k)]
5587 show = [k for k in states if opts.get(k)]
5588 if opts.get('all'):
5588 if opts.get('all'):
5589 show += ui.quiet and (states[:4] + ['clean']) or states
5589 show += ui.quiet and (states[:4] + ['clean']) or states
5590 if not show:
5590 if not show:
5591 show = ui.quiet and states[:4] or states[:5]
5591 show = ui.quiet and states[:4] or states[:5]
5592
5592
5593 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5593 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5594 'ignored' in show, 'clean' in show, 'unknown' in show,
5594 'ignored' in show, 'clean' in show, 'unknown' in show,
5595 opts.get('subrepos'))
5595 opts.get('subrepos'))
5596 changestates = zip(states, 'MAR!?IC', stat)
5596 changestates = zip(states, 'MAR!?IC', stat)
5597
5597
5598 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5598 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5599 copy = copies.pathcopies(repo[node1], repo[node2])
5599 copy = copies.pathcopies(repo[node1], repo[node2])
5600
5600
5601 fm = ui.formatter('status', opts)
5601 fm = ui.formatter('status', opts)
5602 fmt = '%s' + end
5602 fmt = '%s' + end
5603 showchar = not opts.get('no_status')
5603 showchar = not opts.get('no_status')
5604
5604
5605 for state, char, files in changestates:
5605 for state, char, files in changestates:
5606 if state in show:
5606 if state in show:
5607 label = 'status.' + state
5607 label = 'status.' + state
5608 for f in files:
5608 for f in files:
5609 fm.startitem()
5609 fm.startitem()
5610 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5610 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5611 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5611 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5612 if f in copy:
5612 if f in copy:
5613 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5613 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5614 label='status.copied')
5614 label='status.copied')
5615 fm.end()
5615 fm.end()
5616
5616
5617 @command('^summary|sum',
5617 @command('^summary|sum',
5618 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5618 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5619 def summary(ui, repo, **opts):
5619 def summary(ui, repo, **opts):
5620 """summarize working directory state
5620 """summarize working directory state
5621
5621
5622 This generates a brief summary of the working directory state,
5622 This generates a brief summary of the working directory state,
5623 including parents, branch, commit status, and available updates.
5623 including parents, branch, commit status, and available updates.
5624
5624
5625 With the --remote option, this will check the default paths for
5625 With the --remote option, this will check the default paths for
5626 incoming and outgoing changes. This can be time-consuming.
5626 incoming and outgoing changes. This can be time-consuming.
5627
5627
5628 Returns 0 on success.
5628 Returns 0 on success.
5629 """
5629 """
5630
5630
5631 ctx = repo[None]
5631 ctx = repo[None]
5632 parents = ctx.parents()
5632 parents = ctx.parents()
5633 pnode = parents[0].node()
5633 pnode = parents[0].node()
5634 marks = []
5634 marks = []
5635
5635
5636 for p in parents:
5636 for p in parents:
5637 # label with log.changeset (instead of log.parent) since this
5637 # label with log.changeset (instead of log.parent) since this
5638 # shows a working directory parent *changeset*:
5638 # shows a working directory parent *changeset*:
5639 # i18n: column positioning for "hg summary"
5639 # i18n: column positioning for "hg summary"
5640 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5640 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5641 label='log.changeset changeset.%s' % p.phasestr())
5641 label='log.changeset changeset.%s' % p.phasestr())
5642 ui.write(' '.join(p.tags()), label='log.tag')
5642 ui.write(' '.join(p.tags()), label='log.tag')
5643 if p.bookmarks():
5643 if p.bookmarks():
5644 marks.extend(p.bookmarks())
5644 marks.extend(p.bookmarks())
5645 if p.rev() == -1:
5645 if p.rev() == -1:
5646 if not len(repo):
5646 if not len(repo):
5647 ui.write(_(' (empty repository)'))
5647 ui.write(_(' (empty repository)'))
5648 else:
5648 else:
5649 ui.write(_(' (no revision checked out)'))
5649 ui.write(_(' (no revision checked out)'))
5650 ui.write('\n')
5650 ui.write('\n')
5651 if p.description():
5651 if p.description():
5652 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5652 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5653 label='log.summary')
5653 label='log.summary')
5654
5654
5655 branch = ctx.branch()
5655 branch = ctx.branch()
5656 bheads = repo.branchheads(branch)
5656 bheads = repo.branchheads(branch)
5657 # i18n: column positioning for "hg summary"
5657 # i18n: column positioning for "hg summary"
5658 m = _('branch: %s\n') % branch
5658 m = _('branch: %s\n') % branch
5659 if branch != 'default':
5659 if branch != 'default':
5660 ui.write(m, label='log.branch')
5660 ui.write(m, label='log.branch')
5661 else:
5661 else:
5662 ui.status(m, label='log.branch')
5662 ui.status(m, label='log.branch')
5663
5663
5664 if marks:
5664 if marks:
5665 current = repo._bookmarkcurrent
5665 current = repo._bookmarkcurrent
5666 # i18n: column positioning for "hg summary"
5666 # i18n: column positioning for "hg summary"
5667 ui.write(_('bookmarks:'), label='log.bookmark')
5667 ui.write(_('bookmarks:'), label='log.bookmark')
5668 if current is not None:
5668 if current is not None:
5669 if current in marks:
5669 if current in marks:
5670 ui.write(' *' + current, label='bookmarks.current')
5670 ui.write(' *' + current, label='bookmarks.current')
5671 marks.remove(current)
5671 marks.remove(current)
5672 else:
5672 else:
5673 ui.write(' [%s]' % current, label='bookmarks.current')
5673 ui.write(' [%s]' % current, label='bookmarks.current')
5674 for m in marks:
5674 for m in marks:
5675 ui.write(' ' + m, label='log.bookmark')
5675 ui.write(' ' + m, label='log.bookmark')
5676 ui.write('\n', label='log.bookmark')
5676 ui.write('\n', label='log.bookmark')
5677
5677
5678 st = list(repo.status(unknown=True))[:6]
5678 st = list(repo.status(unknown=True))[:6]
5679
5679
5680 c = repo.dirstate.copies()
5680 c = repo.dirstate.copies()
5681 copied, renamed = [], []
5681 copied, renamed = [], []
5682 for d, s in c.iteritems():
5682 for d, s in c.iteritems():
5683 if s in st[2]:
5683 if s in st[2]:
5684 st[2].remove(s)
5684 st[2].remove(s)
5685 renamed.append(d)
5685 renamed.append(d)
5686 else:
5686 else:
5687 copied.append(d)
5687 copied.append(d)
5688 if d in st[1]:
5688 if d in st[1]:
5689 st[1].remove(d)
5689 st[1].remove(d)
5690 st.insert(3, renamed)
5690 st.insert(3, renamed)
5691 st.insert(4, copied)
5691 st.insert(4, copied)
5692
5692
5693 ms = mergemod.mergestate(repo)
5693 ms = mergemod.mergestate(repo)
5694 st.append([f for f in ms if ms[f] == 'u'])
5694 st.append([f for f in ms if ms[f] == 'u'])
5695
5695
5696 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5696 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5697 st.append(subs)
5697 st.append(subs)
5698
5698
5699 labels = [ui.label(_('%d modified'), 'status.modified'),
5699 labels = [ui.label(_('%d modified'), 'status.modified'),
5700 ui.label(_('%d added'), 'status.added'),
5700 ui.label(_('%d added'), 'status.added'),
5701 ui.label(_('%d removed'), 'status.removed'),
5701 ui.label(_('%d removed'), 'status.removed'),
5702 ui.label(_('%d renamed'), 'status.copied'),
5702 ui.label(_('%d renamed'), 'status.copied'),
5703 ui.label(_('%d copied'), 'status.copied'),
5703 ui.label(_('%d copied'), 'status.copied'),
5704 ui.label(_('%d deleted'), 'status.deleted'),
5704 ui.label(_('%d deleted'), 'status.deleted'),
5705 ui.label(_('%d unknown'), 'status.unknown'),
5705 ui.label(_('%d unknown'), 'status.unknown'),
5706 ui.label(_('%d ignored'), 'status.ignored'),
5706 ui.label(_('%d ignored'), 'status.ignored'),
5707 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5707 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5708 ui.label(_('%d subrepos'), 'status.modified')]
5708 ui.label(_('%d subrepos'), 'status.modified')]
5709 t = []
5709 t = []
5710 for s, l in zip(st, labels):
5710 for s, l in zip(st, labels):
5711 if s:
5711 if s:
5712 t.append(l % len(s))
5712 t.append(l % len(s))
5713
5713
5714 t = ', '.join(t)
5714 t = ', '.join(t)
5715 cleanworkdir = False
5715 cleanworkdir = False
5716
5716
5717 if repo.vfs.exists('updatestate'):
5717 if repo.vfs.exists('updatestate'):
5718 t += _(' (interrupted update)')
5718 t += _(' (interrupted update)')
5719 elif len(parents) > 1:
5719 elif len(parents) > 1:
5720 t += _(' (merge)')
5720 t += _(' (merge)')
5721 elif branch != parents[0].branch():
5721 elif branch != parents[0].branch():
5722 t += _(' (new branch)')
5722 t += _(' (new branch)')
5723 elif (parents[0].closesbranch() and
5723 elif (parents[0].closesbranch() and
5724 pnode in repo.branchheads(branch, closed=True)):
5724 pnode in repo.branchheads(branch, closed=True)):
5725 t += _(' (head closed)')
5725 t += _(' (head closed)')
5726 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5726 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5727 t += _(' (clean)')
5727 t += _(' (clean)')
5728 cleanworkdir = True
5728 cleanworkdir = True
5729 elif pnode not in bheads:
5729 elif pnode not in bheads:
5730 t += _(' (new branch head)')
5730 t += _(' (new branch head)')
5731
5731
5732 if cleanworkdir:
5732 if cleanworkdir:
5733 # i18n: column positioning for "hg summary"
5733 # i18n: column positioning for "hg summary"
5734 ui.status(_('commit: %s\n') % t.strip())
5734 ui.status(_('commit: %s\n') % t.strip())
5735 else:
5735 else:
5736 # i18n: column positioning for "hg summary"
5736 # i18n: column positioning for "hg summary"
5737 ui.write(_('commit: %s\n') % t.strip())
5737 ui.write(_('commit: %s\n') % t.strip())
5738
5738
5739 # all ancestors of branch heads - all ancestors of parent = new csets
5739 # all ancestors of branch heads - all ancestors of parent = new csets
5740 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5740 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5741 bheads))
5741 bheads))
5742
5742
5743 if new == 0:
5743 if new == 0:
5744 # i18n: column positioning for "hg summary"
5744 # i18n: column positioning for "hg summary"
5745 ui.status(_('update: (current)\n'))
5745 ui.status(_('update: (current)\n'))
5746 elif pnode not in bheads:
5746 elif pnode not in bheads:
5747 # i18n: column positioning for "hg summary"
5747 # i18n: column positioning for "hg summary"
5748 ui.write(_('update: %d new changesets (update)\n') % new)
5748 ui.write(_('update: %d new changesets (update)\n') % new)
5749 else:
5749 else:
5750 # i18n: column positioning for "hg summary"
5750 # i18n: column positioning for "hg summary"
5751 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5751 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5752 (new, len(bheads)))
5752 (new, len(bheads)))
5753
5753
5754 cmdutil.summaryhooks(ui, repo)
5754 cmdutil.summaryhooks(ui, repo)
5755
5755
5756 if opts.get('remote'):
5756 if opts.get('remote'):
5757 needsincoming, needsoutgoing = True, True
5757 needsincoming, needsoutgoing = True, True
5758 else:
5758 else:
5759 needsincoming, needsoutgoing = False, False
5759 needsincoming, needsoutgoing = False, False
5760 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5760 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5761 if i:
5761 if i:
5762 needsincoming = True
5762 needsincoming = True
5763 if o:
5763 if o:
5764 needsoutgoing = True
5764 needsoutgoing = True
5765 if not needsincoming and not needsoutgoing:
5765 if not needsincoming and not needsoutgoing:
5766 return
5766 return
5767
5767
5768 def getincoming():
5768 def getincoming():
5769 source, branches = hg.parseurl(ui.expandpath('default'))
5769 source, branches = hg.parseurl(ui.expandpath('default'))
5770 sbranch = branches[0]
5770 sbranch = branches[0]
5771 try:
5771 try:
5772 other = hg.peer(repo, {}, source)
5772 other = hg.peer(repo, {}, source)
5773 except error.RepoError:
5773 except error.RepoError:
5774 if opts.get('remote'):
5774 if opts.get('remote'):
5775 raise
5775 raise
5776 return source, sbranch, None, None, None
5776 return source, sbranch, None, None, None
5777 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5777 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5778 if revs:
5778 if revs:
5779 revs = [other.lookup(rev) for rev in revs]
5779 revs = [other.lookup(rev) for rev in revs]
5780 ui.debug('comparing with %s\n' % util.hidepassword(source))
5780 ui.debug('comparing with %s\n' % util.hidepassword(source))
5781 repo.ui.pushbuffer()
5781 repo.ui.pushbuffer()
5782 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5782 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5783 repo.ui.popbuffer()
5783 repo.ui.popbuffer()
5784 return source, sbranch, other, commoninc, commoninc[1]
5784 return source, sbranch, other, commoninc, commoninc[1]
5785
5785
5786 if needsincoming:
5786 if needsincoming:
5787 source, sbranch, sother, commoninc, incoming = getincoming()
5787 source, sbranch, sother, commoninc, incoming = getincoming()
5788 else:
5788 else:
5789 source = sbranch = sother = commoninc = incoming = None
5789 source = sbranch = sother = commoninc = incoming = None
5790
5790
5791 def getoutgoing():
5791 def getoutgoing():
5792 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5792 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5793 dbranch = branches[0]
5793 dbranch = branches[0]
5794 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5794 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5795 if source != dest:
5795 if source != dest:
5796 try:
5796 try:
5797 dother = hg.peer(repo, {}, dest)
5797 dother = hg.peer(repo, {}, dest)
5798 except error.RepoError:
5798 except error.RepoError:
5799 if opts.get('remote'):
5799 if opts.get('remote'):
5800 raise
5800 raise
5801 return dest, dbranch, None, None
5801 return dest, dbranch, None, None
5802 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5802 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5803 elif sother is None:
5803 elif sother is None:
5804 # there is no explicit destination peer, but source one is invalid
5804 # there is no explicit destination peer, but source one is invalid
5805 return dest, dbranch, None, None
5805 return dest, dbranch, None, None
5806 else:
5806 else:
5807 dother = sother
5807 dother = sother
5808 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5808 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5809 common = None
5809 common = None
5810 else:
5810 else:
5811 common = commoninc
5811 common = commoninc
5812 if revs:
5812 if revs:
5813 revs = [repo.lookup(rev) for rev in revs]
5813 revs = [repo.lookup(rev) for rev in revs]
5814 repo.ui.pushbuffer()
5814 repo.ui.pushbuffer()
5815 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5815 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5816 commoninc=common)
5816 commoninc=common)
5817 repo.ui.popbuffer()
5817 repo.ui.popbuffer()
5818 return dest, dbranch, dother, outgoing
5818 return dest, dbranch, dother, outgoing
5819
5819
5820 if needsoutgoing:
5820 if needsoutgoing:
5821 dest, dbranch, dother, outgoing = getoutgoing()
5821 dest, dbranch, dother, outgoing = getoutgoing()
5822 else:
5822 else:
5823 dest = dbranch = dother = outgoing = None
5823 dest = dbranch = dother = outgoing = None
5824
5824
5825 if opts.get('remote'):
5825 if opts.get('remote'):
5826 t = []
5826 t = []
5827 if incoming:
5827 if incoming:
5828 t.append(_('1 or more incoming'))
5828 t.append(_('1 or more incoming'))
5829 o = outgoing.missing
5829 o = outgoing.missing
5830 if o:
5830 if o:
5831 t.append(_('%d outgoing') % len(o))
5831 t.append(_('%d outgoing') % len(o))
5832 other = dother or sother
5832 other = dother or sother
5833 if 'bookmarks' in other.listkeys('namespaces'):
5833 if 'bookmarks' in other.listkeys('namespaces'):
5834 lmarks = repo.listkeys('bookmarks')
5834 lmarks = repo.listkeys('bookmarks')
5835 rmarks = other.listkeys('bookmarks')
5835 rmarks = other.listkeys('bookmarks')
5836 diff = set(rmarks) - set(lmarks)
5836 diff = set(rmarks) - set(lmarks)
5837 if len(diff) > 0:
5837 if len(diff) > 0:
5838 t.append(_('%d incoming bookmarks') % len(diff))
5838 t.append(_('%d incoming bookmarks') % len(diff))
5839 diff = set(lmarks) - set(rmarks)
5839 diff = set(lmarks) - set(rmarks)
5840 if len(diff) > 0:
5840 if len(diff) > 0:
5841 t.append(_('%d outgoing bookmarks') % len(diff))
5841 t.append(_('%d outgoing bookmarks') % len(diff))
5842
5842
5843 if t:
5843 if t:
5844 # i18n: column positioning for "hg summary"
5844 # i18n: column positioning for "hg summary"
5845 ui.write(_('remote: %s\n') % (', '.join(t)))
5845 ui.write(_('remote: %s\n') % (', '.join(t)))
5846 else:
5846 else:
5847 # i18n: column positioning for "hg summary"
5847 # i18n: column positioning for "hg summary"
5848 ui.status(_('remote: (synced)\n'))
5848 ui.status(_('remote: (synced)\n'))
5849
5849
5850 cmdutil.summaryremotehooks(ui, repo, opts,
5850 cmdutil.summaryremotehooks(ui, repo, opts,
5851 ((source, sbranch, sother, commoninc),
5851 ((source, sbranch, sother, commoninc),
5852 (dest, dbranch, dother, outgoing)))
5852 (dest, dbranch, dother, outgoing)))
5853
5853
5854 @command('tag',
5854 @command('tag',
5855 [('f', 'force', None, _('force tag')),
5855 [('f', 'force', None, _('force tag')),
5856 ('l', 'local', None, _('make the tag local')),
5856 ('l', 'local', None, _('make the tag local')),
5857 ('r', 'rev', '', _('revision to tag'), _('REV')),
5857 ('r', 'rev', '', _('revision to tag'), _('REV')),
5858 ('', 'remove', None, _('remove a tag')),
5858 ('', 'remove', None, _('remove a tag')),
5859 # -l/--local is already there, commitopts cannot be used
5859 # -l/--local is already there, commitopts cannot be used
5860 ('e', 'edit', None, _('invoke editor on commit messages')),
5860 ('e', 'edit', None, _('invoke editor on commit messages')),
5861 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5861 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5862 ] + commitopts2,
5862 ] + commitopts2,
5863 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5863 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5864 def tag(ui, repo, name1, *names, **opts):
5864 def tag(ui, repo, name1, *names, **opts):
5865 """add one or more tags for the current or given revision
5865 """add one or more tags for the current or given revision
5866
5866
5867 Name a particular revision using <name>.
5867 Name a particular revision using <name>.
5868
5868
5869 Tags are used to name particular revisions of the repository and are
5869 Tags are used to name particular revisions of the repository and are
5870 very useful to compare different revisions, to go back to significant
5870 very useful to compare different revisions, to go back to significant
5871 earlier versions or to mark branch points as releases, etc. Changing
5871 earlier versions or to mark branch points as releases, etc. Changing
5872 an existing tag is normally disallowed; use -f/--force to override.
5872 an existing tag is normally disallowed; use -f/--force to override.
5873
5873
5874 If no revision is given, the parent of the working directory is
5874 If no revision is given, the parent of the working directory is
5875 used.
5875 used.
5876
5876
5877 To facilitate version control, distribution, and merging of tags,
5877 To facilitate version control, distribution, and merging of tags,
5878 they are stored as a file named ".hgtags" which is managed similarly
5878 they are stored as a file named ".hgtags" which is managed similarly
5879 to other project files and can be hand-edited if necessary. This
5879 to other project files and can be hand-edited if necessary. This
5880 also means that tagging creates a new commit. The file
5880 also means that tagging creates a new commit. The file
5881 ".hg/localtags" is used for local tags (not shared among
5881 ".hg/localtags" is used for local tags (not shared among
5882 repositories).
5882 repositories).
5883
5883
5884 Tag commits are usually made at the head of a branch. If the parent
5884 Tag commits are usually made at the head of a branch. If the parent
5885 of the working directory is not a branch head, :hg:`tag` aborts; use
5885 of the working directory is not a branch head, :hg:`tag` aborts; use
5886 -f/--force to force the tag commit to be based on a non-head
5886 -f/--force to force the tag commit to be based on a non-head
5887 changeset.
5887 changeset.
5888
5888
5889 See :hg:`help dates` for a list of formats valid for -d/--date.
5889 See :hg:`help dates` for a list of formats valid for -d/--date.
5890
5890
5891 Since tag names have priority over branch names during revision
5891 Since tag names have priority over branch names during revision
5892 lookup, using an existing branch name as a tag name is discouraged.
5892 lookup, using an existing branch name as a tag name is discouraged.
5893
5893
5894 Returns 0 on success.
5894 Returns 0 on success.
5895 """
5895 """
5896 wlock = lock = None
5896 wlock = lock = None
5897 try:
5897 try:
5898 wlock = repo.wlock()
5898 wlock = repo.wlock()
5899 lock = repo.lock()
5899 lock = repo.lock()
5900 rev_ = "."
5900 rev_ = "."
5901 names = [t.strip() for t in (name1,) + names]
5901 names = [t.strip() for t in (name1,) + names]
5902 if len(names) != len(set(names)):
5902 if len(names) != len(set(names)):
5903 raise util.Abort(_('tag names must be unique'))
5903 raise util.Abort(_('tag names must be unique'))
5904 for n in names:
5904 for n in names:
5905 scmutil.checknewlabel(repo, n, 'tag')
5905 scmutil.checknewlabel(repo, n, 'tag')
5906 if not n:
5906 if not n:
5907 raise util.Abort(_('tag names cannot consist entirely of '
5907 raise util.Abort(_('tag names cannot consist entirely of '
5908 'whitespace'))
5908 'whitespace'))
5909 if opts.get('rev') and opts.get('remove'):
5909 if opts.get('rev') and opts.get('remove'):
5910 raise util.Abort(_("--rev and --remove are incompatible"))
5910 raise util.Abort(_("--rev and --remove are incompatible"))
5911 if opts.get('rev'):
5911 if opts.get('rev'):
5912 rev_ = opts['rev']
5912 rev_ = opts['rev']
5913 message = opts.get('message')
5913 message = opts.get('message')
5914 if opts.get('remove'):
5914 if opts.get('remove'):
5915 expectedtype = opts.get('local') and 'local' or 'global'
5915 expectedtype = opts.get('local') and 'local' or 'global'
5916 for n in names:
5916 for n in names:
5917 if not repo.tagtype(n):
5917 if not repo.tagtype(n):
5918 raise util.Abort(_("tag '%s' does not exist") % n)
5918 raise util.Abort(_("tag '%s' does not exist") % n)
5919 if repo.tagtype(n) != expectedtype:
5919 if repo.tagtype(n) != expectedtype:
5920 if expectedtype == 'global':
5920 if expectedtype == 'global':
5921 raise util.Abort(_("tag '%s' is not a global tag") % n)
5921 raise util.Abort(_("tag '%s' is not a global tag") % n)
5922 else:
5922 else:
5923 raise util.Abort(_("tag '%s' is not a local tag") % n)
5923 raise util.Abort(_("tag '%s' is not a local tag") % n)
5924 rev_ = nullid
5924 rev_ = nullid
5925 if not message:
5925 if not message:
5926 # we don't translate commit messages
5926 # we don't translate commit messages
5927 message = 'Removed tag %s' % ', '.join(names)
5927 message = 'Removed tag %s' % ', '.join(names)
5928 elif not opts.get('force'):
5928 elif not opts.get('force'):
5929 for n in names:
5929 for n in names:
5930 if n in repo.tags():
5930 if n in repo.tags():
5931 raise util.Abort(_("tag '%s' already exists "
5931 raise util.Abort(_("tag '%s' already exists "
5932 "(use -f to force)") % n)
5932 "(use -f to force)") % n)
5933 if not opts.get('local'):
5933 if not opts.get('local'):
5934 p1, p2 = repo.dirstate.parents()
5934 p1, p2 = repo.dirstate.parents()
5935 if p2 != nullid:
5935 if p2 != nullid:
5936 raise util.Abort(_('uncommitted merge'))
5936 raise util.Abort(_('uncommitted merge'))
5937 bheads = repo.branchheads()
5937 bheads = repo.branchheads()
5938 if not opts.get('force') and bheads and p1 not in bheads:
5938 if not opts.get('force') and bheads and p1 not in bheads:
5939 raise util.Abort(_('not at a branch head (use -f to force)'))
5939 raise util.Abort(_('not at a branch head (use -f to force)'))
5940 r = scmutil.revsingle(repo, rev_).node()
5940 r = scmutil.revsingle(repo, rev_).node()
5941
5941
5942 if not message:
5942 if not message:
5943 # we don't translate commit messages
5943 # we don't translate commit messages
5944 message = ('Added tag %s for changeset %s' %
5944 message = ('Added tag %s for changeset %s' %
5945 (', '.join(names), short(r)))
5945 (', '.join(names), short(r)))
5946
5946
5947 date = opts.get('date')
5947 date = opts.get('date')
5948 if date:
5948 if date:
5949 date = util.parsedate(date)
5949 date = util.parsedate(date)
5950
5950
5951 if opts.get('remove'):
5951 if opts.get('remove'):
5952 editform = 'tag.remove'
5952 editform = 'tag.remove'
5953 else:
5953 else:
5954 editform = 'tag.add'
5954 editform = 'tag.add'
5955 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5955 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5956
5956
5957 # don't allow tagging the null rev
5957 # don't allow tagging the null rev
5958 if (not opts.get('remove') and
5958 if (not opts.get('remove') and
5959 scmutil.revsingle(repo, rev_).rev() == nullrev):
5959 scmutil.revsingle(repo, rev_).rev() == nullrev):
5960 raise util.Abort(_("cannot tag null revision"))
5960 raise util.Abort(_("cannot tag null revision"))
5961
5961
5962 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5962 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5963 editor=editor)
5963 editor=editor)
5964 finally:
5964 finally:
5965 release(lock, wlock)
5965 release(lock, wlock)
5966
5966
5967 @command('tags', formatteropts, '')
5967 @command('tags', formatteropts, '')
5968 def tags(ui, repo, **opts):
5968 def tags(ui, repo, **opts):
5969 """list repository tags
5969 """list repository tags
5970
5970
5971 This lists both regular and local tags. When the -v/--verbose
5971 This lists both regular and local tags. When the -v/--verbose
5972 switch is used, a third column "local" is printed for local tags.
5972 switch is used, a third column "local" is printed for local tags.
5973
5973
5974 Returns 0 on success.
5974 Returns 0 on success.
5975 """
5975 """
5976
5976
5977 fm = ui.formatter('tags', opts)
5977 fm = ui.formatter('tags', opts)
5978 hexfunc = ui.debugflag and hex or short
5978 hexfunc = ui.debugflag and hex or short
5979 tagtype = ""
5979 tagtype = ""
5980
5980
5981 for t, n in reversed(repo.tagslist()):
5981 for t, n in reversed(repo.tagslist()):
5982 hn = hexfunc(n)
5982 hn = hexfunc(n)
5983 label = 'tags.normal'
5983 label = 'tags.normal'
5984 tagtype = ''
5984 tagtype = ''
5985 if repo.tagtype(t) == 'local':
5985 if repo.tagtype(t) == 'local':
5986 label = 'tags.local'
5986 label = 'tags.local'
5987 tagtype = 'local'
5987 tagtype = 'local'
5988
5988
5989 fm.startitem()
5989 fm.startitem()
5990 fm.write('tag', '%s', t, label=label)
5990 fm.write('tag', '%s', t, label=label)
5991 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5991 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5992 fm.condwrite(not ui.quiet, 'rev id', fmt,
5992 fm.condwrite(not ui.quiet, 'rev id', fmt,
5993 repo.changelog.rev(n), hn, label=label)
5993 repo.changelog.rev(n), hn, label=label)
5994 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5994 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5995 tagtype, label=label)
5995 tagtype, label=label)
5996 fm.plain('\n')
5996 fm.plain('\n')
5997 fm.end()
5997 fm.end()
5998
5998
5999 @command('tip',
5999 @command('tip',
6000 [('p', 'patch', None, _('show patch')),
6000 [('p', 'patch', None, _('show patch')),
6001 ('g', 'git', None, _('use git extended diff format')),
6001 ('g', 'git', None, _('use git extended diff format')),
6002 ] + templateopts,
6002 ] + templateopts,
6003 _('[-p] [-g]'))
6003 _('[-p] [-g]'))
6004 def tip(ui, repo, **opts):
6004 def tip(ui, repo, **opts):
6005 """show the tip revision (DEPRECATED)
6005 """show the tip revision (DEPRECATED)
6006
6006
6007 The tip revision (usually just called the tip) is the changeset
6007 The tip revision (usually just called the tip) is the changeset
6008 most recently added to the repository (and therefore the most
6008 most recently added to the repository (and therefore the most
6009 recently changed head).
6009 recently changed head).
6010
6010
6011 If you have just made a commit, that commit will be the tip. If
6011 If you have just made a commit, that commit will be the tip. If
6012 you have just pulled changes from another repository, the tip of
6012 you have just pulled changes from another repository, the tip of
6013 that repository becomes the current tip. The "tip" tag is special
6013 that repository becomes the current tip. The "tip" tag is special
6014 and cannot be renamed or assigned to a different changeset.
6014 and cannot be renamed or assigned to a different changeset.
6015
6015
6016 This command is deprecated, please use :hg:`heads` instead.
6016 This command is deprecated, please use :hg:`heads` instead.
6017
6017
6018 Returns 0 on success.
6018 Returns 0 on success.
6019 """
6019 """
6020 displayer = cmdutil.show_changeset(ui, repo, opts)
6020 displayer = cmdutil.show_changeset(ui, repo, opts)
6021 displayer.show(repo['tip'])
6021 displayer.show(repo['tip'])
6022 displayer.close()
6022 displayer.close()
6023
6023
6024 @command('unbundle',
6024 @command('unbundle',
6025 [('u', 'update', None,
6025 [('u', 'update', None,
6026 _('update to new branch head if changesets were unbundled'))],
6026 _('update to new branch head if changesets were unbundled'))],
6027 _('[-u] FILE...'))
6027 _('[-u] FILE...'))
6028 def unbundle(ui, repo, fname1, *fnames, **opts):
6028 def unbundle(ui, repo, fname1, *fnames, **opts):
6029 """apply one or more changegroup files
6029 """apply one or more changegroup files
6030
6030
6031 Apply one or more compressed changegroup files generated by the
6031 Apply one or more compressed changegroup files generated by the
6032 bundle command.
6032 bundle command.
6033
6033
6034 Returns 0 on success, 1 if an update has unresolved files.
6034 Returns 0 on success, 1 if an update has unresolved files.
6035 """
6035 """
6036 fnames = (fname1,) + fnames
6036 fnames = (fname1,) + fnames
6037
6037
6038 lock = repo.lock()
6038 lock = repo.lock()
6039 try:
6039 try:
6040 for fname in fnames:
6040 for fname in fnames:
6041 f = hg.openpath(ui, fname)
6041 f = hg.openpath(ui, fname)
6042 gen = exchange.readbundle(ui, f, fname)
6042 gen = exchange.readbundle(ui, f, fname)
6043 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6043 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6044 'bundle:' + fname)
6044 'bundle:' + fname)
6045 finally:
6045 finally:
6046 lock.release()
6046 lock.release()
6047
6047
6048 return postincoming(ui, repo, modheads, opts.get('update'), None)
6048 return postincoming(ui, repo, modheads, opts.get('update'), None)
6049
6049
6050 @command('^update|up|checkout|co',
6050 @command('^update|up|checkout|co',
6051 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6051 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6052 ('c', 'check', None,
6052 ('c', 'check', None,
6053 _('update across branches if no uncommitted changes')),
6053 _('update across branches if no uncommitted changes')),
6054 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6054 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6055 ('r', 'rev', '', _('revision'), _('REV'))
6055 ('r', 'rev', '', _('revision'), _('REV'))
6056 ] + mergetoolopts,
6056 ] + mergetoolopts,
6057 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6057 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6058 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6058 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6059 tool=None):
6059 tool=None):
6060 """update working directory (or switch revisions)
6060 """update working directory (or switch revisions)
6061
6061
6062 Update the repository's working directory to the specified
6062 Update the repository's working directory to the specified
6063 changeset. If no changeset is specified, update to the tip of the
6063 changeset. If no changeset is specified, update to the tip of the
6064 current named branch and move the current bookmark (see :hg:`help
6064 current named branch and move the current bookmark (see :hg:`help
6065 bookmarks`).
6065 bookmarks`).
6066
6066
6067 Update sets the working directory's parent revision to the specified
6067 Update sets the working directory's parent revision to the specified
6068 changeset (see :hg:`help parents`).
6068 changeset (see :hg:`help parents`).
6069
6069
6070 If the changeset is not a descendant or ancestor of the working
6070 If the changeset is not a descendant or ancestor of the working
6071 directory's parent, the update is aborted. With the -c/--check
6071 directory's parent, the update is aborted. With the -c/--check
6072 option, the working directory is checked for uncommitted changes; if
6072 option, the working directory is checked for uncommitted changes; if
6073 none are found, the working directory is updated to the specified
6073 none are found, the working directory is updated to the specified
6074 changeset.
6074 changeset.
6075
6075
6076 .. container:: verbose
6076 .. container:: verbose
6077
6077
6078 The following rules apply when the working directory contains
6078 The following rules apply when the working directory contains
6079 uncommitted changes:
6079 uncommitted changes:
6080
6080
6081 1. If neither -c/--check nor -C/--clean is specified, and if
6081 1. If neither -c/--check nor -C/--clean is specified, and if
6082 the requested changeset is an ancestor or descendant of
6082 the requested changeset is an ancestor or descendant of
6083 the working directory's parent, the uncommitted changes
6083 the working directory's parent, the uncommitted changes
6084 are merged into the requested changeset and the merged
6084 are merged into the requested changeset and the merged
6085 result is left uncommitted. If the requested changeset is
6085 result is left uncommitted. If the requested changeset is
6086 not an ancestor or descendant (that is, it is on another
6086 not an ancestor or descendant (that is, it is on another
6087 branch), the update is aborted and the uncommitted changes
6087 branch), the update is aborted and the uncommitted changes
6088 are preserved.
6088 are preserved.
6089
6089
6090 2. With the -c/--check option, the update is aborted and the
6090 2. With the -c/--check option, the update is aborted and the
6091 uncommitted changes are preserved.
6091 uncommitted changes are preserved.
6092
6092
6093 3. With the -C/--clean option, uncommitted changes are discarded and
6093 3. With the -C/--clean option, uncommitted changes are discarded and
6094 the working directory is updated to the requested changeset.
6094 the working directory is updated to the requested changeset.
6095
6095
6096 To cancel an uncommitted merge (and lose your changes), use
6096 To cancel an uncommitted merge (and lose your changes), use
6097 :hg:`update --clean .`.
6097 :hg:`update --clean .`.
6098
6098
6099 Use null as the changeset to remove the working directory (like
6099 Use null as the changeset to remove the working directory (like
6100 :hg:`clone -U`).
6100 :hg:`clone -U`).
6101
6101
6102 If you want to revert just one file to an older revision, use
6102 If you want to revert just one file to an older revision, use
6103 :hg:`revert [-r REV] NAME`.
6103 :hg:`revert [-r REV] NAME`.
6104
6104
6105 See :hg:`help dates` for a list of formats valid for -d/--date.
6105 See :hg:`help dates` for a list of formats valid for -d/--date.
6106
6106
6107 Returns 0 on success, 1 if there are unresolved files.
6107 Returns 0 on success, 1 if there are unresolved files.
6108 """
6108 """
6109 if rev and node:
6109 if rev and node:
6110 raise util.Abort(_("please specify just one revision"))
6110 raise util.Abort(_("please specify just one revision"))
6111
6111
6112 if rev is None or rev == '':
6112 if rev is None or rev == '':
6113 rev = node
6113 rev = node
6114
6114
6115 cmdutil.clearunfinished(repo)
6115 cmdutil.clearunfinished(repo)
6116
6116
6117 # with no argument, we also move the current bookmark, if any
6117 # with no argument, we also move the current bookmark, if any
6118 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6118 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6119
6119
6120 # if we defined a bookmark, we have to remember the original bookmark name
6120 # if we defined a bookmark, we have to remember the original bookmark name
6121 brev = rev
6121 brev = rev
6122 rev = scmutil.revsingle(repo, rev, rev).rev()
6122 rev = scmutil.revsingle(repo, rev, rev).rev()
6123
6123
6124 if check and clean:
6124 if check and clean:
6125 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6125 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6126
6126
6127 if date:
6127 if date:
6128 if rev is not None:
6128 if rev is not None:
6129 raise util.Abort(_("you can't specify a revision and a date"))
6129 raise util.Abort(_("you can't specify a revision and a date"))
6130 rev = cmdutil.finddate(ui, repo, date)
6130 rev = cmdutil.finddate(ui, repo, date)
6131
6131
6132 if check:
6132 if check:
6133 c = repo[None]
6133 c = repo[None]
6134 if c.dirty(merge=False, branch=False, missing=True):
6134 if c.dirty(merge=False, branch=False, missing=True):
6135 raise util.Abort(_("uncommitted changes"))
6135 raise util.Abort(_("uncommitted changes"))
6136 if rev is None:
6136 if rev is None:
6137 rev = repo[repo[None].branch()].rev()
6137 rev = repo[repo[None].branch()].rev()
6138 mergemod._checkunknown(repo, repo[None], repo[rev])
6138 mergemod._checkunknown(repo, repo[None], repo[rev])
6139
6139
6140 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6140 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6141
6141
6142 if clean:
6142 if clean:
6143 ret = hg.clean(repo, rev)
6143 ret = hg.clean(repo, rev)
6144 else:
6144 else:
6145 ret = hg.update(repo, rev)
6145 ret = hg.update(repo, rev)
6146
6146
6147 if not ret and movemarkfrom:
6147 if not ret and movemarkfrom:
6148 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6148 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6149 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6149 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6150 elif brev in repo._bookmarks:
6150 elif brev in repo._bookmarks:
6151 bookmarks.setcurrent(repo, brev)
6151 bookmarks.setcurrent(repo, brev)
6152 ui.status(_("(activating bookmark %s)\n") % brev)
6152 ui.status(_("(activating bookmark %s)\n") % brev)
6153 elif brev:
6153 elif brev:
6154 if repo._bookmarkcurrent:
6154 if repo._bookmarkcurrent:
6155 ui.status(_("(leaving bookmark %s)\n") %
6155 ui.status(_("(leaving bookmark %s)\n") %
6156 repo._bookmarkcurrent)
6156 repo._bookmarkcurrent)
6157 bookmarks.unsetcurrent(repo)
6157 bookmarks.unsetcurrent(repo)
6158
6158
6159 return ret
6159 return ret
6160
6160
6161 @command('verify', [])
6161 @command('verify', [])
6162 def verify(ui, repo):
6162 def verify(ui, repo):
6163 """verify the integrity of the repository
6163 """verify the integrity of the repository
6164
6164
6165 Verify the integrity of the current repository.
6165 Verify the integrity of the current repository.
6166
6166
6167 This will perform an extensive check of the repository's
6167 This will perform an extensive check of the repository's
6168 integrity, validating the hashes and checksums of each entry in
6168 integrity, validating the hashes and checksums of each entry in
6169 the changelog, manifest, and tracked files, as well as the
6169 the changelog, manifest, and tracked files, as well as the
6170 integrity of their crosslinks and indices.
6170 integrity of their crosslinks and indices.
6171
6171
6172 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6172 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6173 for more information about recovery from corruption of the
6173 for more information about recovery from corruption of the
6174 repository.
6174 repository.
6175
6175
6176 Returns 0 on success, 1 if errors are encountered.
6176 Returns 0 on success, 1 if errors are encountered.
6177 """
6177 """
6178 return hg.verify(repo)
6178 return hg.verify(repo)
6179
6179
6180 @command('version', [], norepo=True)
6180 @command('version', [], norepo=True)
6181 def version_(ui):
6181 def version_(ui):
6182 """output version and copyright information"""
6182 """output version and copyright information"""
6183 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6183 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6184 % util.version())
6184 % util.version())
6185 ui.status(_(
6185 ui.status(_(
6186 "(see http://mercurial.selenic.com for more information)\n"
6186 "(see http://mercurial.selenic.com for more information)\n"
6187 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
6187 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
6188 "This is free software; see the source for copying conditions. "
6188 "This is free software; see the source for copying conditions. "
6189 "There is NO\nwarranty; "
6189 "There is NO\nwarranty; "
6190 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6190 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6191 ))
6191 ))
6192
6192
6193 ui.note(_("\nEnabled extensions:\n\n"))
6193 ui.note(_("\nEnabled extensions:\n\n"))
6194 if ui.verbose:
6194 if ui.verbose:
6195 # format names and versions into columns
6195 # format names and versions into columns
6196 names = []
6196 names = []
6197 vers = []
6197 vers = []
6198 for name, module in extensions.extensions():
6198 for name, module in extensions.extensions():
6199 names.append(name)
6199 names.append(name)
6200 vers.append(extensions.moduleversion(module))
6200 vers.append(extensions.moduleversion(module))
6201 if names:
6201 if names:
6202 maxnamelen = max(len(n) for n in names)
6202 maxnamelen = max(len(n) for n in names)
6203 for i, name in enumerate(names):
6203 for i, name in enumerate(names):
6204 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
6204 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
General Comments 0
You need to be logged in to leave comments. Login now