##// END OF EJS Templates
completion: add a debugpathcomplete command...
Bryan O'Sullivan -
r18792:10669e24 default
parent child Browse files
Show More
@@ -1,5757 +1,5824 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _
10 from i18n import _
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, copies, error, bookmarks
12 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import patch, help, encoding, templatekw, discovery
13 import patch, help, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge, graphmod
18 import dagparser, context, simplemerge, graphmod
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
20 import phases, obsolete
20 import phases, obsolete
21
21
22 table = {}
22 table = {}
23
23
24 command = cmdutil.command(table)
24 command = cmdutil.command(table)
25
25
26 # common command options
26 # common command options
27
27
28 globalopts = [
28 globalopts = [
29 ('R', 'repository', '',
29 ('R', 'repository', '',
30 _('repository root directory or name of overlay bundle file'),
30 _('repository root directory or name of overlay bundle file'),
31 _('REPO')),
31 _('REPO')),
32 ('', 'cwd', '',
32 ('', 'cwd', '',
33 _('change working directory'), _('DIR')),
33 _('change working directory'), _('DIR')),
34 ('y', 'noninteractive', None,
34 ('y', 'noninteractive', None,
35 _('do not prompt, automatically pick the first choice for all prompts')),
35 _('do not prompt, automatically pick the first choice for all prompts')),
36 ('q', 'quiet', None, _('suppress output')),
36 ('q', 'quiet', None, _('suppress output')),
37 ('v', 'verbose', None, _('enable additional output')),
37 ('v', 'verbose', None, _('enable additional output')),
38 ('', 'config', [],
38 ('', 'config', [],
39 _('set/override config option (use \'section.name=value\')'),
39 _('set/override config option (use \'section.name=value\')'),
40 _('CONFIG')),
40 _('CONFIG')),
41 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debug', None, _('enable debugging output')),
42 ('', 'debugger', None, _('start debugger')),
42 ('', 'debugger', None, _('start debugger')),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
44 _('ENCODE')),
44 _('ENCODE')),
45 ('', 'encodingmode', encoding.encodingmode,
45 ('', 'encodingmode', encoding.encodingmode,
46 _('set the charset encoding mode'), _('MODE')),
46 _('set the charset encoding mode'), _('MODE')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
48 ('', 'time', None, _('time how long the command takes')),
48 ('', 'time', None, _('time how long the command takes')),
49 ('', 'profile', None, _('print command execution profile')),
49 ('', 'profile', None, _('print command execution profile')),
50 ('', 'version', None, _('output version information and exit')),
50 ('', 'version', None, _('output version information and exit')),
51 ('h', 'help', None, _('display help and exit')),
51 ('h', 'help', None, _('display help and exit')),
52 ('', 'hidden', False, _('consider hidden changesets')),
52 ('', 'hidden', False, _('consider hidden changesets')),
53 ]
53 ]
54
54
55 dryrunopts = [('n', 'dry-run', None,
55 dryrunopts = [('n', 'dry-run', None,
56 _('do not perform actions, just print output'))]
56 _('do not perform actions, just print output'))]
57
57
58 remoteopts = [
58 remoteopts = [
59 ('e', 'ssh', '',
59 ('e', 'ssh', '',
60 _('specify ssh command to use'), _('CMD')),
60 _('specify ssh command to use'), _('CMD')),
61 ('', 'remotecmd', '',
61 ('', 'remotecmd', '',
62 _('specify hg command to run on the remote side'), _('CMD')),
62 _('specify hg command to run on the remote side'), _('CMD')),
63 ('', 'insecure', None,
63 ('', 'insecure', None,
64 _('do not verify server certificate (ignoring web.cacerts config)')),
64 _('do not verify server certificate (ignoring web.cacerts config)')),
65 ]
65 ]
66
66
67 walkopts = [
67 walkopts = [
68 ('I', 'include', [],
68 ('I', 'include', [],
69 _('include names matching the given patterns'), _('PATTERN')),
69 _('include names matching the given patterns'), _('PATTERN')),
70 ('X', 'exclude', [],
70 ('X', 'exclude', [],
71 _('exclude names matching the given patterns'), _('PATTERN')),
71 _('exclude names matching the given patterns'), _('PATTERN')),
72 ]
72 ]
73
73
74 commitopts = [
74 commitopts = [
75 ('m', 'message', '',
75 ('m', 'message', '',
76 _('use text as commit message'), _('TEXT')),
76 _('use text as commit message'), _('TEXT')),
77 ('l', 'logfile', '',
77 ('l', 'logfile', '',
78 _('read commit message from file'), _('FILE')),
78 _('read commit message from file'), _('FILE')),
79 ]
79 ]
80
80
81 commitopts2 = [
81 commitopts2 = [
82 ('d', 'date', '',
82 ('d', 'date', '',
83 _('record the specified date as commit date'), _('DATE')),
83 _('record the specified date as commit date'), _('DATE')),
84 ('u', 'user', '',
84 ('u', 'user', '',
85 _('record the specified user as committer'), _('USER')),
85 _('record the specified user as committer'), _('USER')),
86 ]
86 ]
87
87
88 templateopts = [
88 templateopts = [
89 ('', 'style', '',
89 ('', 'style', '',
90 _('display using template map file'), _('STYLE')),
90 _('display using template map file'), _('STYLE')),
91 ('', 'template', '',
91 ('', 'template', '',
92 _('display with template'), _('TEMPLATE')),
92 _('display with template'), _('TEMPLATE')),
93 ]
93 ]
94
94
95 logopts = [
95 logopts = [
96 ('p', 'patch', None, _('show patch')),
96 ('p', 'patch', None, _('show patch')),
97 ('g', 'git', None, _('use git extended diff format')),
97 ('g', 'git', None, _('use git extended diff format')),
98 ('l', 'limit', '',
98 ('l', 'limit', '',
99 _('limit number of changes displayed'), _('NUM')),
99 _('limit number of changes displayed'), _('NUM')),
100 ('M', 'no-merges', None, _('do not show merges')),
100 ('M', 'no-merges', None, _('do not show merges')),
101 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 ('', 'stat', None, _('output diffstat-style summary of changes')),
102 ('G', 'graph', None, _("show the revision DAG")),
102 ('G', 'graph', None, _("show the revision DAG")),
103 ] + templateopts
103 ] + templateopts
104
104
105 diffopts = [
105 diffopts = [
106 ('a', 'text', None, _('treat all files as text')),
106 ('a', 'text', None, _('treat all files as text')),
107 ('g', 'git', None, _('use git extended diff format')),
107 ('g', 'git', None, _('use git extended diff format')),
108 ('', 'nodates', None, _('omit dates from diff headers'))
108 ('', 'nodates', None, _('omit dates from diff headers'))
109 ]
109 ]
110
110
111 diffwsopts = [
111 diffwsopts = [
112 ('w', 'ignore-all-space', None,
112 ('w', 'ignore-all-space', None,
113 _('ignore white space when comparing lines')),
113 _('ignore white space when comparing lines')),
114 ('b', 'ignore-space-change', None,
114 ('b', 'ignore-space-change', None,
115 _('ignore changes in the amount of white space')),
115 _('ignore changes in the amount of white space')),
116 ('B', 'ignore-blank-lines', None,
116 ('B', 'ignore-blank-lines', None,
117 _('ignore changes whose lines are all blank')),
117 _('ignore changes whose lines are all blank')),
118 ]
118 ]
119
119
120 diffopts2 = [
120 diffopts2 = [
121 ('p', 'show-function', None, _('show which function each change is in')),
121 ('p', 'show-function', None, _('show which function each change is in')),
122 ('', 'reverse', None, _('produce a diff that undoes the changes')),
122 ('', 'reverse', None, _('produce a diff that undoes the changes')),
123 ] + diffwsopts + [
123 ] + diffwsopts + [
124 ('U', 'unified', '',
124 ('U', 'unified', '',
125 _('number of lines of context to show'), _('NUM')),
125 _('number of lines of context to show'), _('NUM')),
126 ('', 'stat', None, _('output diffstat-style summary of changes')),
126 ('', 'stat', None, _('output diffstat-style summary of changes')),
127 ]
127 ]
128
128
129 mergetoolopts = [
129 mergetoolopts = [
130 ('t', 'tool', '', _('specify merge tool')),
130 ('t', 'tool', '', _('specify merge tool')),
131 ]
131 ]
132
132
133 similarityopts = [
133 similarityopts = [
134 ('s', 'similarity', '',
134 ('s', 'similarity', '',
135 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
135 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
136 ]
136 ]
137
137
138 subrepoopts = [
138 subrepoopts = [
139 ('S', 'subrepos', None,
139 ('S', 'subrepos', None,
140 _('recurse into subrepositories'))
140 _('recurse into subrepositories'))
141 ]
141 ]
142
142
143 # Commands start here, listed alphabetically
143 # Commands start here, listed alphabetically
144
144
145 @command('^add',
145 @command('^add',
146 walkopts + subrepoopts + dryrunopts,
146 walkopts + subrepoopts + dryrunopts,
147 _('[OPTION]... [FILE]...'))
147 _('[OPTION]... [FILE]...'))
148 def add(ui, repo, *pats, **opts):
148 def add(ui, repo, *pats, **opts):
149 """add the specified files on the next commit
149 """add the specified files on the next commit
150
150
151 Schedule files to be version controlled and added to the
151 Schedule files to be version controlled and added to the
152 repository.
152 repository.
153
153
154 The files will be added to the repository at the next commit. To
154 The files will be added to the repository at the next commit. To
155 undo an add before that, see :hg:`forget`.
155 undo an add before that, see :hg:`forget`.
156
156
157 If no names are given, add all files to the repository.
157 If no names are given, add all files to the repository.
158
158
159 .. container:: verbose
159 .. container:: verbose
160
160
161 An example showing how new (unknown) files are added
161 An example showing how new (unknown) files are added
162 automatically by :hg:`add`::
162 automatically by :hg:`add`::
163
163
164 $ ls
164 $ ls
165 foo.c
165 foo.c
166 $ hg status
166 $ hg status
167 ? foo.c
167 ? foo.c
168 $ hg add
168 $ hg add
169 adding foo.c
169 adding foo.c
170 $ hg status
170 $ hg status
171 A foo.c
171 A foo.c
172
172
173 Returns 0 if all files are successfully added.
173 Returns 0 if all files are successfully added.
174 """
174 """
175
175
176 m = scmutil.match(repo[None], pats, opts)
176 m = scmutil.match(repo[None], pats, opts)
177 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
177 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
178 opts.get('subrepos'), prefix="", explicitonly=False)
178 opts.get('subrepos'), prefix="", explicitonly=False)
179 return rejected and 1 or 0
179 return rejected and 1 or 0
180
180
181 @command('addremove',
181 @command('addremove',
182 similarityopts + walkopts + dryrunopts,
182 similarityopts + walkopts + dryrunopts,
183 _('[OPTION]... [FILE]...'))
183 _('[OPTION]... [FILE]...'))
184 def addremove(ui, repo, *pats, **opts):
184 def addremove(ui, repo, *pats, **opts):
185 """add all new files, delete all missing files
185 """add all new files, delete all missing files
186
186
187 Add all new files and remove all missing files from the
187 Add all new files and remove all missing files from the
188 repository.
188 repository.
189
189
190 New files are ignored if they match any of the patterns in
190 New files are ignored if they match any of the patterns in
191 ``.hgignore``. As with add, these changes take effect at the next
191 ``.hgignore``. As with add, these changes take effect at the next
192 commit.
192 commit.
193
193
194 Use the -s/--similarity option to detect renamed files. This
194 Use the -s/--similarity option to detect renamed files. This
195 option takes a percentage between 0 (disabled) and 100 (files must
195 option takes a percentage between 0 (disabled) and 100 (files must
196 be identical) as its parameter. With a parameter greater than 0,
196 be identical) as its parameter. With a parameter greater than 0,
197 this compares every removed file with every added file and records
197 this compares every removed file with every added file and records
198 those similar enough as renames. Detecting renamed files this way
198 those similar enough as renames. Detecting renamed files this way
199 can be expensive. After using this option, :hg:`status -C` can be
199 can be expensive. After using this option, :hg:`status -C` can be
200 used to check which files were identified as moved or renamed. If
200 used to check which files were identified as moved or renamed. If
201 not specified, -s/--similarity defaults to 100 and only renames of
201 not specified, -s/--similarity defaults to 100 and only renames of
202 identical files are detected.
202 identical files are detected.
203
203
204 Returns 0 if all files are successfully added.
204 Returns 0 if all files are successfully added.
205 """
205 """
206 try:
206 try:
207 sim = float(opts.get('similarity') or 100)
207 sim = float(opts.get('similarity') or 100)
208 except ValueError:
208 except ValueError:
209 raise util.Abort(_('similarity must be a number'))
209 raise util.Abort(_('similarity must be a number'))
210 if sim < 0 or sim > 100:
210 if sim < 0 or sim > 100:
211 raise util.Abort(_('similarity must be between 0 and 100'))
211 raise util.Abort(_('similarity must be between 0 and 100'))
212 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
212 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
213
213
214 @command('^annotate|blame',
214 @command('^annotate|blame',
215 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
215 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
216 ('', 'follow', None,
216 ('', 'follow', None,
217 _('follow copies/renames and list the filename (DEPRECATED)')),
217 _('follow copies/renames and list the filename (DEPRECATED)')),
218 ('', 'no-follow', None, _("don't follow copies and renames")),
218 ('', 'no-follow', None, _("don't follow copies and renames")),
219 ('a', 'text', None, _('treat all files as text')),
219 ('a', 'text', None, _('treat all files as text')),
220 ('u', 'user', None, _('list the author (long with -v)')),
220 ('u', 'user', None, _('list the author (long with -v)')),
221 ('f', 'file', None, _('list the filename')),
221 ('f', 'file', None, _('list the filename')),
222 ('d', 'date', None, _('list the date (short with -q)')),
222 ('d', 'date', None, _('list the date (short with -q)')),
223 ('n', 'number', None, _('list the revision number (default)')),
223 ('n', 'number', None, _('list the revision number (default)')),
224 ('c', 'changeset', None, _('list the changeset')),
224 ('c', 'changeset', None, _('list the changeset')),
225 ('l', 'line-number', None, _('show line number at the first appearance'))
225 ('l', 'line-number', None, _('show line number at the first appearance'))
226 ] + diffwsopts + walkopts,
226 ] + diffwsopts + walkopts,
227 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
227 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
228 def annotate(ui, repo, *pats, **opts):
228 def annotate(ui, repo, *pats, **opts):
229 """show changeset information by line for each file
229 """show changeset information by line for each file
230
230
231 List changes in files, showing the revision id responsible for
231 List changes in files, showing the revision id responsible for
232 each line
232 each line
233
233
234 This command is useful for discovering when a change was made and
234 This command is useful for discovering when a change was made and
235 by whom.
235 by whom.
236
236
237 Without the -a/--text option, annotate will avoid processing files
237 Without the -a/--text option, annotate will avoid processing files
238 it detects as binary. With -a, annotate will annotate the file
238 it detects as binary. With -a, annotate will annotate the file
239 anyway, although the results will probably be neither useful
239 anyway, although the results will probably be neither useful
240 nor desirable.
240 nor desirable.
241
241
242 Returns 0 on success.
242 Returns 0 on success.
243 """
243 """
244 if opts.get('follow'):
244 if opts.get('follow'):
245 # --follow is deprecated and now just an alias for -f/--file
245 # --follow is deprecated and now just an alias for -f/--file
246 # to mimic the behavior of Mercurial before version 1.5
246 # to mimic the behavior of Mercurial before version 1.5
247 opts['file'] = True
247 opts['file'] = True
248
248
249 datefunc = ui.quiet and util.shortdate or util.datestr
249 datefunc = ui.quiet and util.shortdate or util.datestr
250 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
250 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
251
251
252 if not pats:
252 if not pats:
253 raise util.Abort(_('at least one filename or pattern is required'))
253 raise util.Abort(_('at least one filename or pattern is required'))
254
254
255 hexfn = ui.debugflag and hex or short
255 hexfn = ui.debugflag and hex or short
256
256
257 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
257 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
258 ('number', ' ', lambda x: str(x[0].rev())),
258 ('number', ' ', lambda x: str(x[0].rev())),
259 ('changeset', ' ', lambda x: hexfn(x[0].node())),
259 ('changeset', ' ', lambda x: hexfn(x[0].node())),
260 ('date', ' ', getdate),
260 ('date', ' ', getdate),
261 ('file', ' ', lambda x: x[0].path()),
261 ('file', ' ', lambda x: x[0].path()),
262 ('line_number', ':', lambda x: str(x[1])),
262 ('line_number', ':', lambda x: str(x[1])),
263 ]
263 ]
264
264
265 if (not opts.get('user') and not opts.get('changeset')
265 if (not opts.get('user') and not opts.get('changeset')
266 and not opts.get('date') and not opts.get('file')):
266 and not opts.get('date') and not opts.get('file')):
267 opts['number'] = True
267 opts['number'] = True
268
268
269 linenumber = opts.get('line_number') is not None
269 linenumber = opts.get('line_number') is not None
270 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
270 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
271 raise util.Abort(_('at least one of -n/-c is required for -l'))
271 raise util.Abort(_('at least one of -n/-c is required for -l'))
272
272
273 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
273 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
274 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
274 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
275
275
276 def bad(x, y):
276 def bad(x, y):
277 raise util.Abort("%s: %s" % (x, y))
277 raise util.Abort("%s: %s" % (x, y))
278
278
279 ctx = scmutil.revsingle(repo, opts.get('rev'))
279 ctx = scmutil.revsingle(repo, opts.get('rev'))
280 m = scmutil.match(ctx, pats, opts)
280 m = scmutil.match(ctx, pats, opts)
281 m.bad = bad
281 m.bad = bad
282 follow = not opts.get('no_follow')
282 follow = not opts.get('no_follow')
283 diffopts = patch.diffopts(ui, opts, section='annotate')
283 diffopts = patch.diffopts(ui, opts, section='annotate')
284 for abs in ctx.walk(m):
284 for abs in ctx.walk(m):
285 fctx = ctx[abs]
285 fctx = ctx[abs]
286 if not opts.get('text') and util.binary(fctx.data()):
286 if not opts.get('text') and util.binary(fctx.data()):
287 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
287 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
288 continue
288 continue
289
289
290 lines = fctx.annotate(follow=follow, linenumber=linenumber,
290 lines = fctx.annotate(follow=follow, linenumber=linenumber,
291 diffopts=diffopts)
291 diffopts=diffopts)
292 pieces = []
292 pieces = []
293
293
294 for f, sep in funcmap:
294 for f, sep in funcmap:
295 l = [f(n) for n, dummy in lines]
295 l = [f(n) for n, dummy in lines]
296 if l:
296 if l:
297 sized = [(x, encoding.colwidth(x)) for x in l]
297 sized = [(x, encoding.colwidth(x)) for x in l]
298 ml = max([w for x, w in sized])
298 ml = max([w for x, w in sized])
299 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
299 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
300 for x, w in sized])
300 for x, w in sized])
301
301
302 if pieces:
302 if pieces:
303 for p, l in zip(zip(*pieces), lines):
303 for p, l in zip(zip(*pieces), lines):
304 ui.write("%s: %s" % ("".join(p), l[1]))
304 ui.write("%s: %s" % ("".join(p), l[1]))
305
305
306 if lines and not lines[-1][1].endswith('\n'):
306 if lines and not lines[-1][1].endswith('\n'):
307 ui.write('\n')
307 ui.write('\n')
308
308
309 @command('archive',
309 @command('archive',
310 [('', 'no-decode', None, _('do not pass files through decoders')),
310 [('', 'no-decode', None, _('do not pass files through decoders')),
311 ('p', 'prefix', '', _('directory prefix for files in archive'),
311 ('p', 'prefix', '', _('directory prefix for files in archive'),
312 _('PREFIX')),
312 _('PREFIX')),
313 ('r', 'rev', '', _('revision to distribute'), _('REV')),
313 ('r', 'rev', '', _('revision to distribute'), _('REV')),
314 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
314 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
315 ] + subrepoopts + walkopts,
315 ] + subrepoopts + walkopts,
316 _('[OPTION]... DEST'))
316 _('[OPTION]... DEST'))
317 def archive(ui, repo, dest, **opts):
317 def archive(ui, repo, dest, **opts):
318 '''create an unversioned archive of a repository revision
318 '''create an unversioned archive of a repository revision
319
319
320 By default, the revision used is the parent of the working
320 By default, the revision used is the parent of the working
321 directory; use -r/--rev to specify a different revision.
321 directory; use -r/--rev to specify a different revision.
322
322
323 The archive type is automatically detected based on file
323 The archive type is automatically detected based on file
324 extension (or override using -t/--type).
324 extension (or override using -t/--type).
325
325
326 .. container:: verbose
326 .. container:: verbose
327
327
328 Examples:
328 Examples:
329
329
330 - create a zip file containing the 1.0 release::
330 - create a zip file containing the 1.0 release::
331
331
332 hg archive -r 1.0 project-1.0.zip
332 hg archive -r 1.0 project-1.0.zip
333
333
334 - create a tarball excluding .hg files::
334 - create a tarball excluding .hg files::
335
335
336 hg archive project.tar.gz -X ".hg*"
336 hg archive project.tar.gz -X ".hg*"
337
337
338 Valid types are:
338 Valid types are:
339
339
340 :``files``: a directory full of files (default)
340 :``files``: a directory full of files (default)
341 :``tar``: tar archive, uncompressed
341 :``tar``: tar archive, uncompressed
342 :``tbz2``: tar archive, compressed using bzip2
342 :``tbz2``: tar archive, compressed using bzip2
343 :``tgz``: tar archive, compressed using gzip
343 :``tgz``: tar archive, compressed using gzip
344 :``uzip``: zip archive, uncompressed
344 :``uzip``: zip archive, uncompressed
345 :``zip``: zip archive, compressed using deflate
345 :``zip``: zip archive, compressed using deflate
346
346
347 The exact name of the destination archive or directory is given
347 The exact name of the destination archive or directory is given
348 using a format string; see :hg:`help export` for details.
348 using a format string; see :hg:`help export` for details.
349
349
350 Each member added to an archive file has a directory prefix
350 Each member added to an archive file has a directory prefix
351 prepended. Use -p/--prefix to specify a format string for the
351 prepended. Use -p/--prefix to specify a format string for the
352 prefix. The default is the basename of the archive, with suffixes
352 prefix. The default is the basename of the archive, with suffixes
353 removed.
353 removed.
354
354
355 Returns 0 on success.
355 Returns 0 on success.
356 '''
356 '''
357
357
358 ctx = scmutil.revsingle(repo, opts.get('rev'))
358 ctx = scmutil.revsingle(repo, opts.get('rev'))
359 if not ctx:
359 if not ctx:
360 raise util.Abort(_('no working directory: please specify a revision'))
360 raise util.Abort(_('no working directory: please specify a revision'))
361 node = ctx.node()
361 node = ctx.node()
362 dest = cmdutil.makefilename(repo, dest, node)
362 dest = cmdutil.makefilename(repo, dest, node)
363 if os.path.realpath(dest) == repo.root:
363 if os.path.realpath(dest) == repo.root:
364 raise util.Abort(_('repository root cannot be destination'))
364 raise util.Abort(_('repository root cannot be destination'))
365
365
366 kind = opts.get('type') or archival.guesskind(dest) or 'files'
366 kind = opts.get('type') or archival.guesskind(dest) or 'files'
367 prefix = opts.get('prefix')
367 prefix = opts.get('prefix')
368
368
369 if dest == '-':
369 if dest == '-':
370 if kind == 'files':
370 if kind == 'files':
371 raise util.Abort(_('cannot archive plain files to stdout'))
371 raise util.Abort(_('cannot archive plain files to stdout'))
372 dest = cmdutil.makefileobj(repo, dest)
372 dest = cmdutil.makefileobj(repo, dest)
373 if not prefix:
373 if not prefix:
374 prefix = os.path.basename(repo.root) + '-%h'
374 prefix = os.path.basename(repo.root) + '-%h'
375
375
376 prefix = cmdutil.makefilename(repo, prefix, node)
376 prefix = cmdutil.makefilename(repo, prefix, node)
377 matchfn = scmutil.match(ctx, [], opts)
377 matchfn = scmutil.match(ctx, [], opts)
378 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
378 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
379 matchfn, prefix, subrepos=opts.get('subrepos'))
379 matchfn, prefix, subrepos=opts.get('subrepos'))
380
380
381 @command('backout',
381 @command('backout',
382 [('', 'merge', None, _('merge with old dirstate parent after backout')),
382 [('', 'merge', None, _('merge with old dirstate parent after backout')),
383 ('', 'parent', '',
383 ('', 'parent', '',
384 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
384 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
385 ('r', 'rev', '', _('revision to backout'), _('REV')),
385 ('r', 'rev', '', _('revision to backout'), _('REV')),
386 ] + mergetoolopts + walkopts + commitopts + commitopts2,
386 ] + mergetoolopts + walkopts + commitopts + commitopts2,
387 _('[OPTION]... [-r] REV'))
387 _('[OPTION]... [-r] REV'))
388 def backout(ui, repo, node=None, rev=None, **opts):
388 def backout(ui, repo, node=None, rev=None, **opts):
389 '''reverse effect of earlier changeset
389 '''reverse effect of earlier changeset
390
390
391 Prepare a new changeset with the effect of REV undone in the
391 Prepare a new changeset with the effect of REV undone in the
392 current working directory.
392 current working directory.
393
393
394 If REV is the parent of the working directory, then this new changeset
394 If REV is the parent of the working directory, then this new changeset
395 is committed automatically. Otherwise, hg needs to merge the
395 is committed automatically. Otherwise, hg needs to merge the
396 changes and the merged result is left uncommitted.
396 changes and the merged result is left uncommitted.
397
397
398 .. note::
398 .. note::
399 backout cannot be used to fix either an unwanted or
399 backout cannot be used to fix either an unwanted or
400 incorrect merge.
400 incorrect merge.
401
401
402 .. container:: verbose
402 .. container:: verbose
403
403
404 By default, the pending changeset will have one parent,
404 By default, the pending changeset will have one parent,
405 maintaining a linear history. With --merge, the pending
405 maintaining a linear history. With --merge, the pending
406 changeset will instead have two parents: the old parent of the
406 changeset will instead have two parents: the old parent of the
407 working directory and a new child of REV that simply undoes REV.
407 working directory and a new child of REV that simply undoes REV.
408
408
409 Before version 1.7, the behavior without --merge was equivalent
409 Before version 1.7, the behavior without --merge was equivalent
410 to specifying --merge followed by :hg:`update --clean .` to
410 to specifying --merge followed by :hg:`update --clean .` to
411 cancel the merge and leave the child of REV as a head to be
411 cancel the merge and leave the child of REV as a head to be
412 merged separately.
412 merged separately.
413
413
414 See :hg:`help dates` for a list of formats valid for -d/--date.
414 See :hg:`help dates` for a list of formats valid for -d/--date.
415
415
416 Returns 0 on success.
416 Returns 0 on success.
417 '''
417 '''
418 if rev and node:
418 if rev and node:
419 raise util.Abort(_("please specify just one revision"))
419 raise util.Abort(_("please specify just one revision"))
420
420
421 if not rev:
421 if not rev:
422 rev = node
422 rev = node
423
423
424 if not rev:
424 if not rev:
425 raise util.Abort(_("please specify a revision to backout"))
425 raise util.Abort(_("please specify a revision to backout"))
426
426
427 date = opts.get('date')
427 date = opts.get('date')
428 if date:
428 if date:
429 opts['date'] = util.parsedate(date)
429 opts['date'] = util.parsedate(date)
430
430
431 cmdutil.bailifchanged(repo)
431 cmdutil.bailifchanged(repo)
432 node = scmutil.revsingle(repo, rev).node()
432 node = scmutil.revsingle(repo, rev).node()
433
433
434 op1, op2 = repo.dirstate.parents()
434 op1, op2 = repo.dirstate.parents()
435 a = repo.changelog.ancestor(op1, node)
435 a = repo.changelog.ancestor(op1, node)
436 if a != node:
436 if a != node:
437 raise util.Abort(_('cannot backout change on a different branch'))
437 raise util.Abort(_('cannot backout change on a different branch'))
438
438
439 p1, p2 = repo.changelog.parents(node)
439 p1, p2 = repo.changelog.parents(node)
440 if p1 == nullid:
440 if p1 == nullid:
441 raise util.Abort(_('cannot backout a change with no parents'))
441 raise util.Abort(_('cannot backout a change with no parents'))
442 if p2 != nullid:
442 if p2 != nullid:
443 if not opts.get('parent'):
443 if not opts.get('parent'):
444 raise util.Abort(_('cannot backout a merge changeset'))
444 raise util.Abort(_('cannot backout a merge changeset'))
445 p = repo.lookup(opts['parent'])
445 p = repo.lookup(opts['parent'])
446 if p not in (p1, p2):
446 if p not in (p1, p2):
447 raise util.Abort(_('%s is not a parent of %s') %
447 raise util.Abort(_('%s is not a parent of %s') %
448 (short(p), short(node)))
448 (short(p), short(node)))
449 parent = p
449 parent = p
450 else:
450 else:
451 if opts.get('parent'):
451 if opts.get('parent'):
452 raise util.Abort(_('cannot use --parent on non-merge changeset'))
452 raise util.Abort(_('cannot use --parent on non-merge changeset'))
453 parent = p1
453 parent = p1
454
454
455 # the backout should appear on the same branch
455 # the backout should appear on the same branch
456 wlock = repo.wlock()
456 wlock = repo.wlock()
457 try:
457 try:
458 branch = repo.dirstate.branch()
458 branch = repo.dirstate.branch()
459 bheads = repo.branchheads(branch)
459 bheads = repo.branchheads(branch)
460 hg.clean(repo, node, show_stats=False)
460 hg.clean(repo, node, show_stats=False)
461 repo.dirstate.setbranch(branch)
461 repo.dirstate.setbranch(branch)
462 rctx = scmutil.revsingle(repo, hex(parent))
462 rctx = scmutil.revsingle(repo, hex(parent))
463 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
463 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
464 if not opts.get('merge') and op1 != node:
464 if not opts.get('merge') and op1 != node:
465 try:
465 try:
466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
467 return hg.update(repo, op1)
467 return hg.update(repo, op1)
468 finally:
468 finally:
469 ui.setconfig('ui', 'forcemerge', '')
469 ui.setconfig('ui', 'forcemerge', '')
470
470
471 e = cmdutil.commiteditor
471 e = cmdutil.commiteditor
472 if not opts['message'] and not opts['logfile']:
472 if not opts['message'] and not opts['logfile']:
473 # we don't translate commit messages
473 # we don't translate commit messages
474 opts['message'] = "Backed out changeset %s" % short(node)
474 opts['message'] = "Backed out changeset %s" % short(node)
475 e = cmdutil.commitforceeditor
475 e = cmdutil.commitforceeditor
476
476
477 def commitfunc(ui, repo, message, match, opts):
477 def commitfunc(ui, repo, message, match, opts):
478 return repo.commit(message, opts.get('user'), opts.get('date'),
478 return repo.commit(message, opts.get('user'), opts.get('date'),
479 match, editor=e)
479 match, editor=e)
480 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
480 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
481 cmdutil.commitstatus(repo, newnode, branch, bheads)
481 cmdutil.commitstatus(repo, newnode, branch, bheads)
482
482
483 def nice(node):
483 def nice(node):
484 return '%d:%s' % (repo.changelog.rev(node), short(node))
484 return '%d:%s' % (repo.changelog.rev(node), short(node))
485 ui.status(_('changeset %s backs out changeset %s\n') %
485 ui.status(_('changeset %s backs out changeset %s\n') %
486 (nice(repo.changelog.tip()), nice(node)))
486 (nice(repo.changelog.tip()), nice(node)))
487 if opts.get('merge') and op1 != node:
487 if opts.get('merge') and op1 != node:
488 hg.clean(repo, op1, show_stats=False)
488 hg.clean(repo, op1, show_stats=False)
489 ui.status(_('merging with changeset %s\n')
489 ui.status(_('merging with changeset %s\n')
490 % nice(repo.changelog.tip()))
490 % nice(repo.changelog.tip()))
491 try:
491 try:
492 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
492 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
493 return hg.merge(repo, hex(repo.changelog.tip()))
493 return hg.merge(repo, hex(repo.changelog.tip()))
494 finally:
494 finally:
495 ui.setconfig('ui', 'forcemerge', '')
495 ui.setconfig('ui', 'forcemerge', '')
496 finally:
496 finally:
497 wlock.release()
497 wlock.release()
498 return 0
498 return 0
499
499
500 @command('bisect',
500 @command('bisect',
501 [('r', 'reset', False, _('reset bisect state')),
501 [('r', 'reset', False, _('reset bisect state')),
502 ('g', 'good', False, _('mark changeset good')),
502 ('g', 'good', False, _('mark changeset good')),
503 ('b', 'bad', False, _('mark changeset bad')),
503 ('b', 'bad', False, _('mark changeset bad')),
504 ('s', 'skip', False, _('skip testing changeset')),
504 ('s', 'skip', False, _('skip testing changeset')),
505 ('e', 'extend', False, _('extend the bisect range')),
505 ('e', 'extend', False, _('extend the bisect range')),
506 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
506 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
507 ('U', 'noupdate', False, _('do not update to target'))],
507 ('U', 'noupdate', False, _('do not update to target'))],
508 _("[-gbsr] [-U] [-c CMD] [REV]"))
508 _("[-gbsr] [-U] [-c CMD] [REV]"))
509 def bisect(ui, repo, rev=None, extra=None, command=None,
509 def bisect(ui, repo, rev=None, extra=None, command=None,
510 reset=None, good=None, bad=None, skip=None, extend=None,
510 reset=None, good=None, bad=None, skip=None, extend=None,
511 noupdate=None):
511 noupdate=None):
512 """subdivision search of changesets
512 """subdivision search of changesets
513
513
514 This command helps to find changesets which introduce problems. To
514 This command helps to find changesets which introduce problems. To
515 use, mark the earliest changeset you know exhibits the problem as
515 use, mark the earliest changeset you know exhibits the problem as
516 bad, then mark the latest changeset which is free from the problem
516 bad, then mark the latest changeset which is free from the problem
517 as good. Bisect will update your working directory to a revision
517 as good. Bisect will update your working directory to a revision
518 for testing (unless the -U/--noupdate option is specified). Once
518 for testing (unless the -U/--noupdate option is specified). Once
519 you have performed tests, mark the working directory as good or
519 you have performed tests, mark the working directory as good or
520 bad, and bisect will either update to another candidate changeset
520 bad, and bisect will either update to another candidate changeset
521 or announce that it has found the bad revision.
521 or announce that it has found the bad revision.
522
522
523 As a shortcut, you can also use the revision argument to mark a
523 As a shortcut, you can also use the revision argument to mark a
524 revision as good or bad without checking it out first.
524 revision as good or bad without checking it out first.
525
525
526 If you supply a command, it will be used for automatic bisection.
526 If you supply a command, it will be used for automatic bisection.
527 The environment variable HG_NODE will contain the ID of the
527 The environment variable HG_NODE will contain the ID of the
528 changeset being tested. The exit status of the command will be
528 changeset being tested. The exit status of the command will be
529 used to mark revisions as good or bad: status 0 means good, 125
529 used to mark revisions as good or bad: status 0 means good, 125
530 means to skip the revision, 127 (command not found) will abort the
530 means to skip the revision, 127 (command not found) will abort the
531 bisection, and any other non-zero exit status means the revision
531 bisection, and any other non-zero exit status means the revision
532 is bad.
532 is bad.
533
533
534 .. container:: verbose
534 .. container:: verbose
535
535
536 Some examples:
536 Some examples:
537
537
538 - start a bisection with known bad revision 12, and good revision 34::
538 - start a bisection with known bad revision 12, and good revision 34::
539
539
540 hg bisect --bad 34
540 hg bisect --bad 34
541 hg bisect --good 12
541 hg bisect --good 12
542
542
543 - advance the current bisection by marking current revision as good or
543 - advance the current bisection by marking current revision as good or
544 bad::
544 bad::
545
545
546 hg bisect --good
546 hg bisect --good
547 hg bisect --bad
547 hg bisect --bad
548
548
549 - mark the current revision, or a known revision, to be skipped (e.g. if
549 - mark the current revision, or a known revision, to be skipped (e.g. if
550 that revision is not usable because of another issue)::
550 that revision is not usable because of another issue)::
551
551
552 hg bisect --skip
552 hg bisect --skip
553 hg bisect --skip 23
553 hg bisect --skip 23
554
554
555 - skip all revisions that do not touch directories ``foo`` or ``bar``
555 - skip all revisions that do not touch directories ``foo`` or ``bar``
556
556
557 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
557 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
558
558
559 - forget the current bisection::
559 - forget the current bisection::
560
560
561 hg bisect --reset
561 hg bisect --reset
562
562
563 - use 'make && make tests' to automatically find the first broken
563 - use 'make && make tests' to automatically find the first broken
564 revision::
564 revision::
565
565
566 hg bisect --reset
566 hg bisect --reset
567 hg bisect --bad 34
567 hg bisect --bad 34
568 hg bisect --good 12
568 hg bisect --good 12
569 hg bisect --command 'make && make tests'
569 hg bisect --command 'make && make tests'
570
570
571 - see all changesets whose states are already known in the current
571 - see all changesets whose states are already known in the current
572 bisection::
572 bisection::
573
573
574 hg log -r "bisect(pruned)"
574 hg log -r "bisect(pruned)"
575
575
576 - see the changeset currently being bisected (especially useful
576 - see the changeset currently being bisected (especially useful
577 if running with -U/--noupdate)::
577 if running with -U/--noupdate)::
578
578
579 hg log -r "bisect(current)"
579 hg log -r "bisect(current)"
580
580
581 - see all changesets that took part in the current bisection::
581 - see all changesets that took part in the current bisection::
582
582
583 hg log -r "bisect(range)"
583 hg log -r "bisect(range)"
584
584
585 - with the graphlog extension, you can even get a nice graph::
585 - with the graphlog extension, you can even get a nice graph::
586
586
587 hg log --graph -r "bisect(range)"
587 hg log --graph -r "bisect(range)"
588
588
589 See :hg:`help revsets` for more about the `bisect()` keyword.
589 See :hg:`help revsets` for more about the `bisect()` keyword.
590
590
591 Returns 0 on success.
591 Returns 0 on success.
592 """
592 """
593 def extendbisectrange(nodes, good):
593 def extendbisectrange(nodes, good):
594 # bisect is incomplete when it ends on a merge node and
594 # bisect is incomplete when it ends on a merge node and
595 # one of the parent was not checked.
595 # one of the parent was not checked.
596 parents = repo[nodes[0]].parents()
596 parents = repo[nodes[0]].parents()
597 if len(parents) > 1:
597 if len(parents) > 1:
598 side = good and state['bad'] or state['good']
598 side = good and state['bad'] or state['good']
599 num = len(set(i.node() for i in parents) & set(side))
599 num = len(set(i.node() for i in parents) & set(side))
600 if num == 1:
600 if num == 1:
601 return parents[0].ancestor(parents[1])
601 return parents[0].ancestor(parents[1])
602 return None
602 return None
603
603
604 def print_result(nodes, good):
604 def print_result(nodes, good):
605 displayer = cmdutil.show_changeset(ui, repo, {})
605 displayer = cmdutil.show_changeset(ui, repo, {})
606 if len(nodes) == 1:
606 if len(nodes) == 1:
607 # narrowed it down to a single revision
607 # narrowed it down to a single revision
608 if good:
608 if good:
609 ui.write(_("The first good revision is:\n"))
609 ui.write(_("The first good revision is:\n"))
610 else:
610 else:
611 ui.write(_("The first bad revision is:\n"))
611 ui.write(_("The first bad revision is:\n"))
612 displayer.show(repo[nodes[0]])
612 displayer.show(repo[nodes[0]])
613 extendnode = extendbisectrange(nodes, good)
613 extendnode = extendbisectrange(nodes, good)
614 if extendnode is not None:
614 if extendnode is not None:
615 ui.write(_('Not all ancestors of this changeset have been'
615 ui.write(_('Not all ancestors of this changeset have been'
616 ' checked.\nUse bisect --extend to continue the '
616 ' checked.\nUse bisect --extend to continue the '
617 'bisection from\nthe common ancestor, %s.\n')
617 'bisection from\nthe common ancestor, %s.\n')
618 % extendnode)
618 % extendnode)
619 else:
619 else:
620 # multiple possible revisions
620 # multiple possible revisions
621 if good:
621 if good:
622 ui.write(_("Due to skipped revisions, the first "
622 ui.write(_("Due to skipped revisions, the first "
623 "good revision could be any of:\n"))
623 "good revision could be any of:\n"))
624 else:
624 else:
625 ui.write(_("Due to skipped revisions, the first "
625 ui.write(_("Due to skipped revisions, the first "
626 "bad revision could be any of:\n"))
626 "bad revision could be any of:\n"))
627 for n in nodes:
627 for n in nodes:
628 displayer.show(repo[n])
628 displayer.show(repo[n])
629 displayer.close()
629 displayer.close()
630
630
631 def check_state(state, interactive=True):
631 def check_state(state, interactive=True):
632 if not state['good'] or not state['bad']:
632 if not state['good'] or not state['bad']:
633 if (good or bad or skip or reset) and interactive:
633 if (good or bad or skip or reset) and interactive:
634 return
634 return
635 if not state['good']:
635 if not state['good']:
636 raise util.Abort(_('cannot bisect (no known good revisions)'))
636 raise util.Abort(_('cannot bisect (no known good revisions)'))
637 else:
637 else:
638 raise util.Abort(_('cannot bisect (no known bad revisions)'))
638 raise util.Abort(_('cannot bisect (no known bad revisions)'))
639 return True
639 return True
640
640
641 # backward compatibility
641 # backward compatibility
642 if rev in "good bad reset init".split():
642 if rev in "good bad reset init".split():
643 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
643 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
644 cmd, rev, extra = rev, extra, None
644 cmd, rev, extra = rev, extra, None
645 if cmd == "good":
645 if cmd == "good":
646 good = True
646 good = True
647 elif cmd == "bad":
647 elif cmd == "bad":
648 bad = True
648 bad = True
649 else:
649 else:
650 reset = True
650 reset = True
651 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
651 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
652 raise util.Abort(_('incompatible arguments'))
652 raise util.Abort(_('incompatible arguments'))
653
653
654 if reset:
654 if reset:
655 p = repo.join("bisect.state")
655 p = repo.join("bisect.state")
656 if os.path.exists(p):
656 if os.path.exists(p):
657 os.unlink(p)
657 os.unlink(p)
658 return
658 return
659
659
660 state = hbisect.load_state(repo)
660 state = hbisect.load_state(repo)
661
661
662 if command:
662 if command:
663 changesets = 1
663 changesets = 1
664 try:
664 try:
665 node = state['current'][0]
665 node = state['current'][0]
666 except LookupError:
666 except LookupError:
667 if noupdate:
667 if noupdate:
668 raise util.Abort(_('current bisect revision is unknown - '
668 raise util.Abort(_('current bisect revision is unknown - '
669 'start a new bisect to fix'))
669 'start a new bisect to fix'))
670 node, p2 = repo.dirstate.parents()
670 node, p2 = repo.dirstate.parents()
671 if p2 != nullid:
671 if p2 != nullid:
672 raise util.Abort(_('current bisect revision is a merge'))
672 raise util.Abort(_('current bisect revision is a merge'))
673 try:
673 try:
674 while changesets:
674 while changesets:
675 # update state
675 # update state
676 state['current'] = [node]
676 state['current'] = [node]
677 hbisect.save_state(repo, state)
677 hbisect.save_state(repo, state)
678 status = util.system(command,
678 status = util.system(command,
679 environ={'HG_NODE': hex(node)},
679 environ={'HG_NODE': hex(node)},
680 out=ui.fout)
680 out=ui.fout)
681 if status == 125:
681 if status == 125:
682 transition = "skip"
682 transition = "skip"
683 elif status == 0:
683 elif status == 0:
684 transition = "good"
684 transition = "good"
685 # status < 0 means process was killed
685 # status < 0 means process was killed
686 elif status == 127:
686 elif status == 127:
687 raise util.Abort(_("failed to execute %s") % command)
687 raise util.Abort(_("failed to execute %s") % command)
688 elif status < 0:
688 elif status < 0:
689 raise util.Abort(_("%s killed") % command)
689 raise util.Abort(_("%s killed") % command)
690 else:
690 else:
691 transition = "bad"
691 transition = "bad"
692 ctx = scmutil.revsingle(repo, rev, node)
692 ctx = scmutil.revsingle(repo, rev, node)
693 rev = None # clear for future iterations
693 rev = None # clear for future iterations
694 state[transition].append(ctx.node())
694 state[transition].append(ctx.node())
695 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
695 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
696 check_state(state, interactive=False)
696 check_state(state, interactive=False)
697 # bisect
697 # bisect
698 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
698 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
699 # update to next check
699 # update to next check
700 node = nodes[0]
700 node = nodes[0]
701 if not noupdate:
701 if not noupdate:
702 cmdutil.bailifchanged(repo)
702 cmdutil.bailifchanged(repo)
703 hg.clean(repo, node, show_stats=False)
703 hg.clean(repo, node, show_stats=False)
704 finally:
704 finally:
705 state['current'] = [node]
705 state['current'] = [node]
706 hbisect.save_state(repo, state)
706 hbisect.save_state(repo, state)
707 print_result(nodes, good)
707 print_result(nodes, good)
708 return
708 return
709
709
710 # update state
710 # update state
711
711
712 if rev:
712 if rev:
713 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
713 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
714 else:
714 else:
715 nodes = [repo.lookup('.')]
715 nodes = [repo.lookup('.')]
716
716
717 if good or bad or skip:
717 if good or bad or skip:
718 if good:
718 if good:
719 state['good'] += nodes
719 state['good'] += nodes
720 elif bad:
720 elif bad:
721 state['bad'] += nodes
721 state['bad'] += nodes
722 elif skip:
722 elif skip:
723 state['skip'] += nodes
723 state['skip'] += nodes
724 hbisect.save_state(repo, state)
724 hbisect.save_state(repo, state)
725
725
726 if not check_state(state):
726 if not check_state(state):
727 return
727 return
728
728
729 # actually bisect
729 # actually bisect
730 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
730 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
731 if extend:
731 if extend:
732 if not changesets:
732 if not changesets:
733 extendnode = extendbisectrange(nodes, good)
733 extendnode = extendbisectrange(nodes, good)
734 if extendnode is not None:
734 if extendnode is not None:
735 ui.write(_("Extending search to changeset %d:%s\n"
735 ui.write(_("Extending search to changeset %d:%s\n"
736 % (extendnode.rev(), extendnode)))
736 % (extendnode.rev(), extendnode)))
737 state['current'] = [extendnode.node()]
737 state['current'] = [extendnode.node()]
738 hbisect.save_state(repo, state)
738 hbisect.save_state(repo, state)
739 if noupdate:
739 if noupdate:
740 return
740 return
741 cmdutil.bailifchanged(repo)
741 cmdutil.bailifchanged(repo)
742 return hg.clean(repo, extendnode.node())
742 return hg.clean(repo, extendnode.node())
743 raise util.Abort(_("nothing to extend"))
743 raise util.Abort(_("nothing to extend"))
744
744
745 if changesets == 0:
745 if changesets == 0:
746 print_result(nodes, good)
746 print_result(nodes, good)
747 else:
747 else:
748 assert len(nodes) == 1 # only a single node can be tested next
748 assert len(nodes) == 1 # only a single node can be tested next
749 node = nodes[0]
749 node = nodes[0]
750 # compute the approximate number of remaining tests
750 # compute the approximate number of remaining tests
751 tests, size = 0, 2
751 tests, size = 0, 2
752 while size <= changesets:
752 while size <= changesets:
753 tests, size = tests + 1, size * 2
753 tests, size = tests + 1, size * 2
754 rev = repo.changelog.rev(node)
754 rev = repo.changelog.rev(node)
755 ui.write(_("Testing changeset %d:%s "
755 ui.write(_("Testing changeset %d:%s "
756 "(%d changesets remaining, ~%d tests)\n")
756 "(%d changesets remaining, ~%d tests)\n")
757 % (rev, short(node), changesets, tests))
757 % (rev, short(node), changesets, tests))
758 state['current'] = [node]
758 state['current'] = [node]
759 hbisect.save_state(repo, state)
759 hbisect.save_state(repo, state)
760 if not noupdate:
760 if not noupdate:
761 cmdutil.bailifchanged(repo)
761 cmdutil.bailifchanged(repo)
762 return hg.clean(repo, node)
762 return hg.clean(repo, node)
763
763
764 @command('bookmarks|bookmark',
764 @command('bookmarks|bookmark',
765 [('f', 'force', False, _('force')),
765 [('f', 'force', False, _('force')),
766 ('r', 'rev', '', _('revision'), _('REV')),
766 ('r', 'rev', '', _('revision'), _('REV')),
767 ('d', 'delete', False, _('delete a given bookmark')),
767 ('d', 'delete', False, _('delete a given bookmark')),
768 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
768 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
769 ('i', 'inactive', False, _('mark a bookmark inactive'))],
769 ('i', 'inactive', False, _('mark a bookmark inactive'))],
770 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
770 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
771 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
771 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
772 rename=None, inactive=False):
772 rename=None, inactive=False):
773 '''track a line of development with movable markers
773 '''track a line of development with movable markers
774
774
775 Bookmarks are pointers to certain commits that move when committing.
775 Bookmarks are pointers to certain commits that move when committing.
776 Bookmarks are local. They can be renamed, copied and deleted. It is
776 Bookmarks are local. They can be renamed, copied and deleted. It is
777 possible to use :hg:`merge NAME` to merge from a given bookmark, and
777 possible to use :hg:`merge NAME` to merge from a given bookmark, and
778 :hg:`update NAME` to update to a given bookmark.
778 :hg:`update NAME` to update to a given bookmark.
779
779
780 You can use :hg:`bookmark NAME` to set a bookmark on the working
780 You can use :hg:`bookmark NAME` to set a bookmark on the working
781 directory's parent revision with the given name. If you specify
781 directory's parent revision with the given name. If you specify
782 a revision using -r REV (where REV may be an existing bookmark),
782 a revision using -r REV (where REV may be an existing bookmark),
783 the bookmark is assigned to that revision.
783 the bookmark is assigned to that revision.
784
784
785 Bookmarks can be pushed and pulled between repositories (see :hg:`help
785 Bookmarks can be pushed and pulled between repositories (see :hg:`help
786 push` and :hg:`help pull`). This requires both the local and remote
786 push` and :hg:`help pull`). This requires both the local and remote
787 repositories to support bookmarks. For versions prior to 1.8, this means
787 repositories to support bookmarks. For versions prior to 1.8, this means
788 the bookmarks extension must be enabled.
788 the bookmarks extension must be enabled.
789
789
790 If you set a bookmark called '@', new clones of the repository will
790 If you set a bookmark called '@', new clones of the repository will
791 have that revision checked out (and the bookmark made active) by
791 have that revision checked out (and the bookmark made active) by
792 default.
792 default.
793
793
794 With -i/--inactive, the new bookmark will not be made the active
794 With -i/--inactive, the new bookmark will not be made the active
795 bookmark. If -r/--rev is given, the new bookmark will not be made
795 bookmark. If -r/--rev is given, the new bookmark will not be made
796 active even if -i/--inactive is not given. If no NAME is given, the
796 active even if -i/--inactive is not given. If no NAME is given, the
797 current active bookmark will be marked inactive.
797 current active bookmark will be marked inactive.
798 '''
798 '''
799 hexfn = ui.debugflag and hex or short
799 hexfn = ui.debugflag and hex or short
800 marks = repo._bookmarks
800 marks = repo._bookmarks
801 cur = repo.changectx('.').node()
801 cur = repo.changectx('.').node()
802
802
803 def checkformat(mark):
803 def checkformat(mark):
804 mark = mark.strip()
804 mark = mark.strip()
805 if not mark:
805 if not mark:
806 raise util.Abort(_("bookmark names cannot consist entirely of "
806 raise util.Abort(_("bookmark names cannot consist entirely of "
807 "whitespace"))
807 "whitespace"))
808 scmutil.checknewlabel(repo, mark, 'bookmark')
808 scmutil.checknewlabel(repo, mark, 'bookmark')
809 return mark
809 return mark
810
810
811 def checkconflict(repo, mark, force=False, target=None):
811 def checkconflict(repo, mark, force=False, target=None):
812 if mark in marks and not force:
812 if mark in marks and not force:
813 if target:
813 if target:
814 if marks[mark] == target and target == cur:
814 if marks[mark] == target and target == cur:
815 # re-activating a bookmark
815 # re-activating a bookmark
816 return
816 return
817 anc = repo.changelog.ancestors([repo[target].rev()])
817 anc = repo.changelog.ancestors([repo[target].rev()])
818 bmctx = repo[marks[mark]]
818 bmctx = repo[marks[mark]]
819 if bmctx.rev() in anc:
819 if bmctx.rev() in anc:
820 ui.status(_("moving bookmark '%s' forward from %s\n") %
820 ui.status(_("moving bookmark '%s' forward from %s\n") %
821 (mark, short(bmctx.node())))
821 (mark, short(bmctx.node())))
822 return
822 return
823 raise util.Abort(_("bookmark '%s' already exists "
823 raise util.Abort(_("bookmark '%s' already exists "
824 "(use -f to force)") % mark)
824 "(use -f to force)") % mark)
825 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
825 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
826 and not force):
826 and not force):
827 raise util.Abort(
827 raise util.Abort(
828 _("a bookmark cannot have the name of an existing branch"))
828 _("a bookmark cannot have the name of an existing branch"))
829
829
830 if delete and rename:
830 if delete and rename:
831 raise util.Abort(_("--delete and --rename are incompatible"))
831 raise util.Abort(_("--delete and --rename are incompatible"))
832 if delete and rev:
832 if delete and rev:
833 raise util.Abort(_("--rev is incompatible with --delete"))
833 raise util.Abort(_("--rev is incompatible with --delete"))
834 if rename and rev:
834 if rename and rev:
835 raise util.Abort(_("--rev is incompatible with --rename"))
835 raise util.Abort(_("--rev is incompatible with --rename"))
836 if mark is None and (delete or rev):
836 if mark is None and (delete or rev):
837 raise util.Abort(_("bookmark name required"))
837 raise util.Abort(_("bookmark name required"))
838
838
839 if delete:
839 if delete:
840 if mark not in marks:
840 if mark not in marks:
841 raise util.Abort(_("bookmark '%s' does not exist") % mark)
841 raise util.Abort(_("bookmark '%s' does not exist") % mark)
842 if mark == repo._bookmarkcurrent:
842 if mark == repo._bookmarkcurrent:
843 bookmarks.setcurrent(repo, None)
843 bookmarks.setcurrent(repo, None)
844 del marks[mark]
844 del marks[mark]
845 marks.write()
845 marks.write()
846
846
847 elif rename:
847 elif rename:
848 if mark is None:
848 if mark is None:
849 raise util.Abort(_("new bookmark name required"))
849 raise util.Abort(_("new bookmark name required"))
850 mark = checkformat(mark)
850 mark = checkformat(mark)
851 if rename not in marks:
851 if rename not in marks:
852 raise util.Abort(_("bookmark '%s' does not exist") % rename)
852 raise util.Abort(_("bookmark '%s' does not exist") % rename)
853 checkconflict(repo, mark, force)
853 checkconflict(repo, mark, force)
854 marks[mark] = marks[rename]
854 marks[mark] = marks[rename]
855 if repo._bookmarkcurrent == rename and not inactive:
855 if repo._bookmarkcurrent == rename and not inactive:
856 bookmarks.setcurrent(repo, mark)
856 bookmarks.setcurrent(repo, mark)
857 del marks[rename]
857 del marks[rename]
858 marks.write()
858 marks.write()
859
859
860 elif mark is not None:
860 elif mark is not None:
861 mark = checkformat(mark)
861 mark = checkformat(mark)
862 if inactive and mark == repo._bookmarkcurrent:
862 if inactive and mark == repo._bookmarkcurrent:
863 bookmarks.setcurrent(repo, None)
863 bookmarks.setcurrent(repo, None)
864 return
864 return
865 tgt = cur
865 tgt = cur
866 if rev:
866 if rev:
867 tgt = scmutil.revsingle(repo, rev).node()
867 tgt = scmutil.revsingle(repo, rev).node()
868 checkconflict(repo, mark, force, tgt)
868 checkconflict(repo, mark, force, tgt)
869 marks[mark] = tgt
869 marks[mark] = tgt
870 if not inactive and cur == marks[mark]:
870 if not inactive and cur == marks[mark]:
871 bookmarks.setcurrent(repo, mark)
871 bookmarks.setcurrent(repo, mark)
872 elif cur != tgt and mark == repo._bookmarkcurrent:
872 elif cur != tgt and mark == repo._bookmarkcurrent:
873 bookmarks.setcurrent(repo, None)
873 bookmarks.setcurrent(repo, None)
874 marks.write()
874 marks.write()
875
875
876 # Same message whether trying to deactivate the current bookmark (-i
876 # Same message whether trying to deactivate the current bookmark (-i
877 # with no NAME) or listing bookmarks
877 # with no NAME) or listing bookmarks
878 elif len(marks) == 0:
878 elif len(marks) == 0:
879 ui.status(_("no bookmarks set\n"))
879 ui.status(_("no bookmarks set\n"))
880
880
881 elif inactive:
881 elif inactive:
882 if not repo._bookmarkcurrent:
882 if not repo._bookmarkcurrent:
883 ui.status(_("no active bookmark\n"))
883 ui.status(_("no active bookmark\n"))
884 else:
884 else:
885 bookmarks.setcurrent(repo, None)
885 bookmarks.setcurrent(repo, None)
886
886
887 else: # show bookmarks
887 else: # show bookmarks
888 for bmark, n in sorted(marks.iteritems()):
888 for bmark, n in sorted(marks.iteritems()):
889 current = repo._bookmarkcurrent
889 current = repo._bookmarkcurrent
890 if bmark == current:
890 if bmark == current:
891 prefix, label = '*', 'bookmarks.current'
891 prefix, label = '*', 'bookmarks.current'
892 else:
892 else:
893 prefix, label = ' ', ''
893 prefix, label = ' ', ''
894
894
895 if ui.quiet:
895 if ui.quiet:
896 ui.write("%s\n" % bmark, label=label)
896 ui.write("%s\n" % bmark, label=label)
897 else:
897 else:
898 ui.write(" %s %-25s %d:%s\n" % (
898 ui.write(" %s %-25s %d:%s\n" % (
899 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
899 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
900 label=label)
900 label=label)
901
901
902 @command('branch',
902 @command('branch',
903 [('f', 'force', None,
903 [('f', 'force', None,
904 _('set branch name even if it shadows an existing branch')),
904 _('set branch name even if it shadows an existing branch')),
905 ('C', 'clean', None, _('reset branch name to parent branch name'))],
905 ('C', 'clean', None, _('reset branch name to parent branch name'))],
906 _('[-fC] [NAME]'))
906 _('[-fC] [NAME]'))
907 def branch(ui, repo, label=None, **opts):
907 def branch(ui, repo, label=None, **opts):
908 """set or show the current branch name
908 """set or show the current branch name
909
909
910 .. note::
910 .. note::
911 Branch names are permanent and global. Use :hg:`bookmark` to create a
911 Branch names are permanent and global. Use :hg:`bookmark` to create a
912 light-weight bookmark instead. See :hg:`help glossary` for more
912 light-weight bookmark instead. See :hg:`help glossary` for more
913 information about named branches and bookmarks.
913 information about named branches and bookmarks.
914
914
915 With no argument, show the current branch name. With one argument,
915 With no argument, show the current branch name. With one argument,
916 set the working directory branch name (the branch will not exist
916 set the working directory branch name (the branch will not exist
917 in the repository until the next commit). Standard practice
917 in the repository until the next commit). Standard practice
918 recommends that primary development take place on the 'default'
918 recommends that primary development take place on the 'default'
919 branch.
919 branch.
920
920
921 Unless -f/--force is specified, branch will not let you set a
921 Unless -f/--force is specified, branch will not let you set a
922 branch name that already exists, even if it's inactive.
922 branch name that already exists, even if it's inactive.
923
923
924 Use -C/--clean to reset the working directory branch to that of
924 Use -C/--clean to reset the working directory branch to that of
925 the parent of the working directory, negating a previous branch
925 the parent of the working directory, negating a previous branch
926 change.
926 change.
927
927
928 Use the command :hg:`update` to switch to an existing branch. Use
928 Use the command :hg:`update` to switch to an existing branch. Use
929 :hg:`commit --close-branch` to mark this branch as closed.
929 :hg:`commit --close-branch` to mark this branch as closed.
930
930
931 Returns 0 on success.
931 Returns 0 on success.
932 """
932 """
933 if not opts.get('clean') and not label:
933 if not opts.get('clean') and not label:
934 ui.write("%s\n" % repo.dirstate.branch())
934 ui.write("%s\n" % repo.dirstate.branch())
935 return
935 return
936
936
937 wlock = repo.wlock()
937 wlock = repo.wlock()
938 try:
938 try:
939 if opts.get('clean'):
939 if opts.get('clean'):
940 label = repo[None].p1().branch()
940 label = repo[None].p1().branch()
941 repo.dirstate.setbranch(label)
941 repo.dirstate.setbranch(label)
942 ui.status(_('reset working directory to branch %s\n') % label)
942 ui.status(_('reset working directory to branch %s\n') % label)
943 elif label:
943 elif label:
944 if not opts.get('force') and label in repo.branchmap():
944 if not opts.get('force') and label in repo.branchmap():
945 if label not in [p.branch() for p in repo.parents()]:
945 if label not in [p.branch() for p in repo.parents()]:
946 raise util.Abort(_('a branch of the same name already'
946 raise util.Abort(_('a branch of the same name already'
947 ' exists'),
947 ' exists'),
948 # i18n: "it" refers to an existing branch
948 # i18n: "it" refers to an existing branch
949 hint=_("use 'hg update' to switch to it"))
949 hint=_("use 'hg update' to switch to it"))
950 scmutil.checknewlabel(repo, label, 'branch')
950 scmutil.checknewlabel(repo, label, 'branch')
951 repo.dirstate.setbranch(label)
951 repo.dirstate.setbranch(label)
952 ui.status(_('marked working directory as branch %s\n') % label)
952 ui.status(_('marked working directory as branch %s\n') % label)
953 ui.status(_('(branches are permanent and global, '
953 ui.status(_('(branches are permanent and global, '
954 'did you want a bookmark?)\n'))
954 'did you want a bookmark?)\n'))
955 finally:
955 finally:
956 wlock.release()
956 wlock.release()
957
957
958 @command('branches',
958 @command('branches',
959 [('a', 'active', False, _('show only branches that have unmerged heads')),
959 [('a', 'active', False, _('show only branches that have unmerged heads')),
960 ('c', 'closed', False, _('show normal and closed branches'))],
960 ('c', 'closed', False, _('show normal and closed branches'))],
961 _('[-ac]'))
961 _('[-ac]'))
962 def branches(ui, repo, active=False, closed=False):
962 def branches(ui, repo, active=False, closed=False):
963 """list repository named branches
963 """list repository named branches
964
964
965 List the repository's named branches, indicating which ones are
965 List the repository's named branches, indicating which ones are
966 inactive. If -c/--closed is specified, also list branches which have
966 inactive. If -c/--closed is specified, also list branches which have
967 been marked closed (see :hg:`commit --close-branch`).
967 been marked closed (see :hg:`commit --close-branch`).
968
968
969 If -a/--active is specified, only show active branches. A branch
969 If -a/--active is specified, only show active branches. A branch
970 is considered active if it contains repository heads.
970 is considered active if it contains repository heads.
971
971
972 Use the command :hg:`update` to switch to an existing branch.
972 Use the command :hg:`update` to switch to an existing branch.
973
973
974 Returns 0.
974 Returns 0.
975 """
975 """
976
976
977 hexfunc = ui.debugflag and hex or short
977 hexfunc = ui.debugflag and hex or short
978
978
979 activebranches = set([repo[n].branch() for n in repo.heads()])
979 activebranches = set([repo[n].branch() for n in repo.heads()])
980 branches = []
980 branches = []
981 for tag, heads in repo.branchmap().iteritems():
981 for tag, heads in repo.branchmap().iteritems():
982 for h in reversed(heads):
982 for h in reversed(heads):
983 ctx = repo[h]
983 ctx = repo[h]
984 isopen = not ctx.closesbranch()
984 isopen = not ctx.closesbranch()
985 if isopen:
985 if isopen:
986 tip = ctx
986 tip = ctx
987 break
987 break
988 else:
988 else:
989 tip = repo[heads[-1]]
989 tip = repo[heads[-1]]
990 isactive = tag in activebranches and isopen
990 isactive = tag in activebranches and isopen
991 branches.append((tip, isactive, isopen))
991 branches.append((tip, isactive, isopen))
992 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
992 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
993 reverse=True)
993 reverse=True)
994
994
995 for ctx, isactive, isopen in branches:
995 for ctx, isactive, isopen in branches:
996 if (not active) or isactive:
996 if (not active) or isactive:
997 if isactive:
997 if isactive:
998 label = 'branches.active'
998 label = 'branches.active'
999 notice = ''
999 notice = ''
1000 elif not isopen:
1000 elif not isopen:
1001 if not closed:
1001 if not closed:
1002 continue
1002 continue
1003 label = 'branches.closed'
1003 label = 'branches.closed'
1004 notice = _(' (closed)')
1004 notice = _(' (closed)')
1005 else:
1005 else:
1006 label = 'branches.inactive'
1006 label = 'branches.inactive'
1007 notice = _(' (inactive)')
1007 notice = _(' (inactive)')
1008 if ctx.branch() == repo.dirstate.branch():
1008 if ctx.branch() == repo.dirstate.branch():
1009 label = 'branches.current'
1009 label = 'branches.current'
1010 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
1010 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
1011 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1011 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1012 'log.changeset changeset.%s' % ctx.phasestr())
1012 'log.changeset changeset.%s' % ctx.phasestr())
1013 tag = ui.label(ctx.branch(), label)
1013 tag = ui.label(ctx.branch(), label)
1014 if ui.quiet:
1014 if ui.quiet:
1015 ui.write("%s\n" % tag)
1015 ui.write("%s\n" % tag)
1016 else:
1016 else:
1017 ui.write("%s %s%s\n" % (tag, rev, notice))
1017 ui.write("%s %s%s\n" % (tag, rev, notice))
1018
1018
1019 @command('bundle',
1019 @command('bundle',
1020 [('f', 'force', None, _('run even when the destination is unrelated')),
1020 [('f', 'force', None, _('run even when the destination is unrelated')),
1021 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1021 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1022 _('REV')),
1022 _('REV')),
1023 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1023 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1024 _('BRANCH')),
1024 _('BRANCH')),
1025 ('', 'base', [],
1025 ('', 'base', [],
1026 _('a base changeset assumed to be available at the destination'),
1026 _('a base changeset assumed to be available at the destination'),
1027 _('REV')),
1027 _('REV')),
1028 ('a', 'all', None, _('bundle all changesets in the repository')),
1028 ('a', 'all', None, _('bundle all changesets in the repository')),
1029 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1029 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1030 ] + remoteopts,
1030 ] + remoteopts,
1031 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1031 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1032 def bundle(ui, repo, fname, dest=None, **opts):
1032 def bundle(ui, repo, fname, dest=None, **opts):
1033 """create a changegroup file
1033 """create a changegroup file
1034
1034
1035 Generate a compressed changegroup file collecting changesets not
1035 Generate a compressed changegroup file collecting changesets not
1036 known to be in another repository.
1036 known to be in another repository.
1037
1037
1038 If you omit the destination repository, then hg assumes the
1038 If you omit the destination repository, then hg assumes the
1039 destination will have all the nodes you specify with --base
1039 destination will have all the nodes you specify with --base
1040 parameters. To create a bundle containing all changesets, use
1040 parameters. To create a bundle containing all changesets, use
1041 -a/--all (or --base null).
1041 -a/--all (or --base null).
1042
1042
1043 You can change compression method with the -t/--type option.
1043 You can change compression method with the -t/--type option.
1044 The available compression methods are: none, bzip2, and
1044 The available compression methods are: none, bzip2, and
1045 gzip (by default, bundles are compressed using bzip2).
1045 gzip (by default, bundles are compressed using bzip2).
1046
1046
1047 The bundle file can then be transferred using conventional means
1047 The bundle file can then be transferred using conventional means
1048 and applied to another repository with the unbundle or pull
1048 and applied to another repository with the unbundle or pull
1049 command. This is useful when direct push and pull are not
1049 command. This is useful when direct push and pull are not
1050 available or when exporting an entire repository is undesirable.
1050 available or when exporting an entire repository is undesirable.
1051
1051
1052 Applying bundles preserves all changeset contents including
1052 Applying bundles preserves all changeset contents including
1053 permissions, copy/rename information, and revision history.
1053 permissions, copy/rename information, and revision history.
1054
1054
1055 Returns 0 on success, 1 if no changes found.
1055 Returns 0 on success, 1 if no changes found.
1056 """
1056 """
1057 revs = None
1057 revs = None
1058 if 'rev' in opts:
1058 if 'rev' in opts:
1059 revs = scmutil.revrange(repo, opts['rev'])
1059 revs = scmutil.revrange(repo, opts['rev'])
1060
1060
1061 bundletype = opts.get('type', 'bzip2').lower()
1061 bundletype = opts.get('type', 'bzip2').lower()
1062 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1062 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1063 bundletype = btypes.get(bundletype)
1063 bundletype = btypes.get(bundletype)
1064 if bundletype not in changegroup.bundletypes:
1064 if bundletype not in changegroup.bundletypes:
1065 raise util.Abort(_('unknown bundle type specified with --type'))
1065 raise util.Abort(_('unknown bundle type specified with --type'))
1066
1066
1067 if opts.get('all'):
1067 if opts.get('all'):
1068 base = ['null']
1068 base = ['null']
1069 else:
1069 else:
1070 base = scmutil.revrange(repo, opts.get('base'))
1070 base = scmutil.revrange(repo, opts.get('base'))
1071 if base:
1071 if base:
1072 if dest:
1072 if dest:
1073 raise util.Abort(_("--base is incompatible with specifying "
1073 raise util.Abort(_("--base is incompatible with specifying "
1074 "a destination"))
1074 "a destination"))
1075 common = [repo.lookup(rev) for rev in base]
1075 common = [repo.lookup(rev) for rev in base]
1076 heads = revs and map(repo.lookup, revs) or revs
1076 heads = revs and map(repo.lookup, revs) or revs
1077 cg = repo.getbundle('bundle', heads=heads, common=common)
1077 cg = repo.getbundle('bundle', heads=heads, common=common)
1078 outgoing = None
1078 outgoing = None
1079 else:
1079 else:
1080 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1080 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1081 dest, branches = hg.parseurl(dest, opts.get('branch'))
1081 dest, branches = hg.parseurl(dest, opts.get('branch'))
1082 other = hg.peer(repo, opts, dest)
1082 other = hg.peer(repo, opts, dest)
1083 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1083 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1084 heads = revs and map(repo.lookup, revs) or revs
1084 heads = revs and map(repo.lookup, revs) or revs
1085 outgoing = discovery.findcommonoutgoing(repo, other,
1085 outgoing = discovery.findcommonoutgoing(repo, other,
1086 onlyheads=heads,
1086 onlyheads=heads,
1087 force=opts.get('force'),
1087 force=opts.get('force'),
1088 portable=True)
1088 portable=True)
1089 cg = repo.getlocalbundle('bundle', outgoing)
1089 cg = repo.getlocalbundle('bundle', outgoing)
1090 if not cg:
1090 if not cg:
1091 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1091 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1092 return 1
1092 return 1
1093
1093
1094 changegroup.writebundle(cg, fname, bundletype)
1094 changegroup.writebundle(cg, fname, bundletype)
1095
1095
1096 @command('cat',
1096 @command('cat',
1097 [('o', 'output', '',
1097 [('o', 'output', '',
1098 _('print output to file with formatted name'), _('FORMAT')),
1098 _('print output to file with formatted name'), _('FORMAT')),
1099 ('r', 'rev', '', _('print the given revision'), _('REV')),
1099 ('r', 'rev', '', _('print the given revision'), _('REV')),
1100 ('', 'decode', None, _('apply any matching decode filter')),
1100 ('', 'decode', None, _('apply any matching decode filter')),
1101 ] + walkopts,
1101 ] + walkopts,
1102 _('[OPTION]... FILE...'))
1102 _('[OPTION]... FILE...'))
1103 def cat(ui, repo, file1, *pats, **opts):
1103 def cat(ui, repo, file1, *pats, **opts):
1104 """output the current or given revision of files
1104 """output the current or given revision of files
1105
1105
1106 Print the specified files as they were at the given revision. If
1106 Print the specified files as they were at the given revision. If
1107 no revision is given, the parent of the working directory is used,
1107 no revision is given, the parent of the working directory is used,
1108 or tip if no revision is checked out.
1108 or tip if no revision is checked out.
1109
1109
1110 Output may be to a file, in which case the name of the file is
1110 Output may be to a file, in which case the name of the file is
1111 given using a format string. The formatting rules are the same as
1111 given using a format string. The formatting rules are the same as
1112 for the export command, with the following additions:
1112 for the export command, with the following additions:
1113
1113
1114 :``%s``: basename of file being printed
1114 :``%s``: basename of file being printed
1115 :``%d``: dirname of file being printed, or '.' if in repository root
1115 :``%d``: dirname of file being printed, or '.' if in repository root
1116 :``%p``: root-relative path name of file being printed
1116 :``%p``: root-relative path name of file being printed
1117
1117
1118 Returns 0 on success.
1118 Returns 0 on success.
1119 """
1119 """
1120 ctx = scmutil.revsingle(repo, opts.get('rev'))
1120 ctx = scmutil.revsingle(repo, opts.get('rev'))
1121 err = 1
1121 err = 1
1122 m = scmutil.match(ctx, (file1,) + pats, opts)
1122 m = scmutil.match(ctx, (file1,) + pats, opts)
1123 for abs in ctx.walk(m):
1123 for abs in ctx.walk(m):
1124 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1124 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1125 pathname=abs)
1125 pathname=abs)
1126 data = ctx[abs].data()
1126 data = ctx[abs].data()
1127 if opts.get('decode'):
1127 if opts.get('decode'):
1128 data = repo.wwritedata(abs, data)
1128 data = repo.wwritedata(abs, data)
1129 fp.write(data)
1129 fp.write(data)
1130 fp.close()
1130 fp.close()
1131 err = 0
1131 err = 0
1132 return err
1132 return err
1133
1133
1134 @command('^clone',
1134 @command('^clone',
1135 [('U', 'noupdate', None,
1135 [('U', 'noupdate', None,
1136 _('the clone will include an empty working copy (only a repository)')),
1136 _('the clone will include an empty working copy (only a repository)')),
1137 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1137 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1138 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1138 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1139 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1139 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1140 ('', 'pull', None, _('use pull protocol to copy metadata')),
1140 ('', 'pull', None, _('use pull protocol to copy metadata')),
1141 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1141 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1142 ] + remoteopts,
1142 ] + remoteopts,
1143 _('[OPTION]... SOURCE [DEST]'))
1143 _('[OPTION]... SOURCE [DEST]'))
1144 def clone(ui, source, dest=None, **opts):
1144 def clone(ui, source, dest=None, **opts):
1145 """make a copy of an existing repository
1145 """make a copy of an existing repository
1146
1146
1147 Create a copy of an existing repository in a new directory.
1147 Create a copy of an existing repository in a new directory.
1148
1148
1149 If no destination directory name is specified, it defaults to the
1149 If no destination directory name is specified, it defaults to the
1150 basename of the source.
1150 basename of the source.
1151
1151
1152 The location of the source is added to the new repository's
1152 The location of the source is added to the new repository's
1153 ``.hg/hgrc`` file, as the default to be used for future pulls.
1153 ``.hg/hgrc`` file, as the default to be used for future pulls.
1154
1154
1155 Only local paths and ``ssh://`` URLs are supported as
1155 Only local paths and ``ssh://`` URLs are supported as
1156 destinations. For ``ssh://`` destinations, no working directory or
1156 destinations. For ``ssh://`` destinations, no working directory or
1157 ``.hg/hgrc`` will be created on the remote side.
1157 ``.hg/hgrc`` will be created on the remote side.
1158
1158
1159 To pull only a subset of changesets, specify one or more revisions
1159 To pull only a subset of changesets, specify one or more revisions
1160 identifiers with -r/--rev or branches with -b/--branch. The
1160 identifiers with -r/--rev or branches with -b/--branch. The
1161 resulting clone will contain only the specified changesets and
1161 resulting clone will contain only the specified changesets and
1162 their ancestors. These options (or 'clone src#rev dest') imply
1162 their ancestors. These options (or 'clone src#rev dest') imply
1163 --pull, even for local source repositories. Note that specifying a
1163 --pull, even for local source repositories. Note that specifying a
1164 tag will include the tagged changeset but not the changeset
1164 tag will include the tagged changeset but not the changeset
1165 containing the tag.
1165 containing the tag.
1166
1166
1167 If the source repository has a bookmark called '@' set, that
1167 If the source repository has a bookmark called '@' set, that
1168 revision will be checked out in the new repository by default.
1168 revision will be checked out in the new repository by default.
1169
1169
1170 To check out a particular version, use -u/--update, or
1170 To check out a particular version, use -u/--update, or
1171 -U/--noupdate to create a clone with no working directory.
1171 -U/--noupdate to create a clone with no working directory.
1172
1172
1173 .. container:: verbose
1173 .. container:: verbose
1174
1174
1175 For efficiency, hardlinks are used for cloning whenever the
1175 For efficiency, hardlinks are used for cloning whenever the
1176 source and destination are on the same filesystem (note this
1176 source and destination are on the same filesystem (note this
1177 applies only to the repository data, not to the working
1177 applies only to the repository data, not to the working
1178 directory). Some filesystems, such as AFS, implement hardlinking
1178 directory). Some filesystems, such as AFS, implement hardlinking
1179 incorrectly, but do not report errors. In these cases, use the
1179 incorrectly, but do not report errors. In these cases, use the
1180 --pull option to avoid hardlinking.
1180 --pull option to avoid hardlinking.
1181
1181
1182 In some cases, you can clone repositories and the working
1182 In some cases, you can clone repositories and the working
1183 directory using full hardlinks with ::
1183 directory using full hardlinks with ::
1184
1184
1185 $ cp -al REPO REPOCLONE
1185 $ cp -al REPO REPOCLONE
1186
1186
1187 This is the fastest way to clone, but it is not always safe. The
1187 This is the fastest way to clone, but it is not always safe. The
1188 operation is not atomic (making sure REPO is not modified during
1188 operation is not atomic (making sure REPO is not modified during
1189 the operation is up to you) and you have to make sure your
1189 the operation is up to you) and you have to make sure your
1190 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1190 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1191 so). Also, this is not compatible with certain extensions that
1191 so). Also, this is not compatible with certain extensions that
1192 place their metadata under the .hg directory, such as mq.
1192 place their metadata under the .hg directory, such as mq.
1193
1193
1194 Mercurial will update the working directory to the first applicable
1194 Mercurial will update the working directory to the first applicable
1195 revision from this list:
1195 revision from this list:
1196
1196
1197 a) null if -U or the source repository has no changesets
1197 a) null if -U or the source repository has no changesets
1198 b) if -u . and the source repository is local, the first parent of
1198 b) if -u . and the source repository is local, the first parent of
1199 the source repository's working directory
1199 the source repository's working directory
1200 c) the changeset specified with -u (if a branch name, this means the
1200 c) the changeset specified with -u (if a branch name, this means the
1201 latest head of that branch)
1201 latest head of that branch)
1202 d) the changeset specified with -r
1202 d) the changeset specified with -r
1203 e) the tipmost head specified with -b
1203 e) the tipmost head specified with -b
1204 f) the tipmost head specified with the url#branch source syntax
1204 f) the tipmost head specified with the url#branch source syntax
1205 g) the revision marked with the '@' bookmark, if present
1205 g) the revision marked with the '@' bookmark, if present
1206 h) the tipmost head of the default branch
1206 h) the tipmost head of the default branch
1207 i) tip
1207 i) tip
1208
1208
1209 Examples:
1209 Examples:
1210
1210
1211 - clone a remote repository to a new directory named hg/::
1211 - clone a remote repository to a new directory named hg/::
1212
1212
1213 hg clone http://selenic.com/hg
1213 hg clone http://selenic.com/hg
1214
1214
1215 - create a lightweight local clone::
1215 - create a lightweight local clone::
1216
1216
1217 hg clone project/ project-feature/
1217 hg clone project/ project-feature/
1218
1218
1219 - clone from an absolute path on an ssh server (note double-slash)::
1219 - clone from an absolute path on an ssh server (note double-slash)::
1220
1220
1221 hg clone ssh://user@server//home/projects/alpha/
1221 hg clone ssh://user@server//home/projects/alpha/
1222
1222
1223 - do a high-speed clone over a LAN while checking out a
1223 - do a high-speed clone over a LAN while checking out a
1224 specified version::
1224 specified version::
1225
1225
1226 hg clone --uncompressed http://server/repo -u 1.5
1226 hg clone --uncompressed http://server/repo -u 1.5
1227
1227
1228 - create a repository without changesets after a particular revision::
1228 - create a repository without changesets after a particular revision::
1229
1229
1230 hg clone -r 04e544 experimental/ good/
1230 hg clone -r 04e544 experimental/ good/
1231
1231
1232 - clone (and track) a particular named branch::
1232 - clone (and track) a particular named branch::
1233
1233
1234 hg clone http://selenic.com/hg#stable
1234 hg clone http://selenic.com/hg#stable
1235
1235
1236 See :hg:`help urls` for details on specifying URLs.
1236 See :hg:`help urls` for details on specifying URLs.
1237
1237
1238 Returns 0 on success.
1238 Returns 0 on success.
1239 """
1239 """
1240 if opts.get('noupdate') and opts.get('updaterev'):
1240 if opts.get('noupdate') and opts.get('updaterev'):
1241 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1241 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1242
1242
1243 r = hg.clone(ui, opts, source, dest,
1243 r = hg.clone(ui, opts, source, dest,
1244 pull=opts.get('pull'),
1244 pull=opts.get('pull'),
1245 stream=opts.get('uncompressed'),
1245 stream=opts.get('uncompressed'),
1246 rev=opts.get('rev'),
1246 rev=opts.get('rev'),
1247 update=opts.get('updaterev') or not opts.get('noupdate'),
1247 update=opts.get('updaterev') or not opts.get('noupdate'),
1248 branch=opts.get('branch'))
1248 branch=opts.get('branch'))
1249
1249
1250 return r is None
1250 return r is None
1251
1251
1252 @command('^commit|ci',
1252 @command('^commit|ci',
1253 [('A', 'addremove', None,
1253 [('A', 'addremove', None,
1254 _('mark new/missing files as added/removed before committing')),
1254 _('mark new/missing files as added/removed before committing')),
1255 ('', 'close-branch', None,
1255 ('', 'close-branch', None,
1256 _('mark a branch as closed, hiding it from the branch list')),
1256 _('mark a branch as closed, hiding it from the branch list')),
1257 ('', 'amend', None, _('amend the parent of the working dir')),
1257 ('', 'amend', None, _('amend the parent of the working dir')),
1258 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1258 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1259 _('[OPTION]... [FILE]...'))
1259 _('[OPTION]... [FILE]...'))
1260 def commit(ui, repo, *pats, **opts):
1260 def commit(ui, repo, *pats, **opts):
1261 """commit the specified files or all outstanding changes
1261 """commit the specified files or all outstanding changes
1262
1262
1263 Commit changes to the given files into the repository. Unlike a
1263 Commit changes to the given files into the repository. Unlike a
1264 centralized SCM, this operation is a local operation. See
1264 centralized SCM, this operation is a local operation. See
1265 :hg:`push` for a way to actively distribute your changes.
1265 :hg:`push` for a way to actively distribute your changes.
1266
1266
1267 If a list of files is omitted, all changes reported by :hg:`status`
1267 If a list of files is omitted, all changes reported by :hg:`status`
1268 will be committed.
1268 will be committed.
1269
1269
1270 If you are committing the result of a merge, do not provide any
1270 If you are committing the result of a merge, do not provide any
1271 filenames or -I/-X filters.
1271 filenames or -I/-X filters.
1272
1272
1273 If no commit message is specified, Mercurial starts your
1273 If no commit message is specified, Mercurial starts your
1274 configured editor where you can enter a message. In case your
1274 configured editor where you can enter a message. In case your
1275 commit fails, you will find a backup of your message in
1275 commit fails, you will find a backup of your message in
1276 ``.hg/last-message.txt``.
1276 ``.hg/last-message.txt``.
1277
1277
1278 The --amend flag can be used to amend the parent of the
1278 The --amend flag can be used to amend the parent of the
1279 working directory with a new commit that contains the changes
1279 working directory with a new commit that contains the changes
1280 in the parent in addition to those currently reported by :hg:`status`,
1280 in the parent in addition to those currently reported by :hg:`status`,
1281 if there are any. The old commit is stored in a backup bundle in
1281 if there are any. The old commit is stored in a backup bundle in
1282 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1282 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1283 on how to restore it).
1283 on how to restore it).
1284
1284
1285 Message, user and date are taken from the amended commit unless
1285 Message, user and date are taken from the amended commit unless
1286 specified. When a message isn't specified on the command line,
1286 specified. When a message isn't specified on the command line,
1287 the editor will open with the message of the amended commit.
1287 the editor will open with the message of the amended commit.
1288
1288
1289 It is not possible to amend public changesets (see :hg:`help phases`)
1289 It is not possible to amend public changesets (see :hg:`help phases`)
1290 or changesets that have children.
1290 or changesets that have children.
1291
1291
1292 See :hg:`help dates` for a list of formats valid for -d/--date.
1292 See :hg:`help dates` for a list of formats valid for -d/--date.
1293
1293
1294 Returns 0 on success, 1 if nothing changed.
1294 Returns 0 on success, 1 if nothing changed.
1295 """
1295 """
1296 if opts.get('subrepos'):
1296 if opts.get('subrepos'):
1297 # Let --subrepos on the command line override config setting.
1297 # Let --subrepos on the command line override config setting.
1298 ui.setconfig('ui', 'commitsubrepos', True)
1298 ui.setconfig('ui', 'commitsubrepos', True)
1299
1299
1300 extra = {}
1300 extra = {}
1301 if opts.get('close_branch'):
1301 if opts.get('close_branch'):
1302 if repo['.'].node() not in repo.branchheads():
1302 if repo['.'].node() not in repo.branchheads():
1303 # The topo heads set is included in the branch heads set of the
1303 # The topo heads set is included in the branch heads set of the
1304 # current branch, so it's sufficient to test branchheads
1304 # current branch, so it's sufficient to test branchheads
1305 raise util.Abort(_('can only close branch heads'))
1305 raise util.Abort(_('can only close branch heads'))
1306 extra['close'] = 1
1306 extra['close'] = 1
1307
1307
1308 branch = repo[None].branch()
1308 branch = repo[None].branch()
1309 bheads = repo.branchheads(branch)
1309 bheads = repo.branchheads(branch)
1310
1310
1311 if opts.get('amend'):
1311 if opts.get('amend'):
1312 if ui.configbool('ui', 'commitsubrepos'):
1312 if ui.configbool('ui', 'commitsubrepos'):
1313 raise util.Abort(_('cannot amend recursively'))
1313 raise util.Abort(_('cannot amend recursively'))
1314
1314
1315 old = repo['.']
1315 old = repo['.']
1316 if old.phase() == phases.public:
1316 if old.phase() == phases.public:
1317 raise util.Abort(_('cannot amend public changesets'))
1317 raise util.Abort(_('cannot amend public changesets'))
1318 if len(old.parents()) > 1:
1318 if len(old.parents()) > 1:
1319 raise util.Abort(_('cannot amend merge changesets'))
1319 raise util.Abort(_('cannot amend merge changesets'))
1320 if len(repo[None].parents()) > 1:
1320 if len(repo[None].parents()) > 1:
1321 raise util.Abort(_('cannot amend while merging'))
1321 raise util.Abort(_('cannot amend while merging'))
1322 if (not obsolete._enabled) and old.children():
1322 if (not obsolete._enabled) and old.children():
1323 raise util.Abort(_('cannot amend changeset with children'))
1323 raise util.Abort(_('cannot amend changeset with children'))
1324
1324
1325 e = cmdutil.commiteditor
1325 e = cmdutil.commiteditor
1326 if opts.get('force_editor'):
1326 if opts.get('force_editor'):
1327 e = cmdutil.commitforceeditor
1327 e = cmdutil.commitforceeditor
1328
1328
1329 def commitfunc(ui, repo, message, match, opts):
1329 def commitfunc(ui, repo, message, match, opts):
1330 editor = e
1330 editor = e
1331 # message contains text from -m or -l, if it's empty,
1331 # message contains text from -m or -l, if it's empty,
1332 # open the editor with the old message
1332 # open the editor with the old message
1333 if not message:
1333 if not message:
1334 message = old.description()
1334 message = old.description()
1335 editor = cmdutil.commitforceeditor
1335 editor = cmdutil.commitforceeditor
1336 return repo.commit(message,
1336 return repo.commit(message,
1337 opts.get('user') or old.user(),
1337 opts.get('user') or old.user(),
1338 opts.get('date') or old.date(),
1338 opts.get('date') or old.date(),
1339 match,
1339 match,
1340 editor=editor,
1340 editor=editor,
1341 extra=extra)
1341 extra=extra)
1342
1342
1343 current = repo._bookmarkcurrent
1343 current = repo._bookmarkcurrent
1344 marks = old.bookmarks()
1344 marks = old.bookmarks()
1345 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1345 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1346 if node == old.node():
1346 if node == old.node():
1347 ui.status(_("nothing changed\n"))
1347 ui.status(_("nothing changed\n"))
1348 return 1
1348 return 1
1349 elif marks:
1349 elif marks:
1350 ui.debug('moving bookmarks %r from %s to %s\n' %
1350 ui.debug('moving bookmarks %r from %s to %s\n' %
1351 (marks, old.hex(), hex(node)))
1351 (marks, old.hex(), hex(node)))
1352 newmarks = repo._bookmarks
1352 newmarks = repo._bookmarks
1353 for bm in marks:
1353 for bm in marks:
1354 newmarks[bm] = node
1354 newmarks[bm] = node
1355 if bm == current:
1355 if bm == current:
1356 bookmarks.setcurrent(repo, bm)
1356 bookmarks.setcurrent(repo, bm)
1357 newmarks.write()
1357 newmarks.write()
1358 else:
1358 else:
1359 e = cmdutil.commiteditor
1359 e = cmdutil.commiteditor
1360 if opts.get('force_editor'):
1360 if opts.get('force_editor'):
1361 e = cmdutil.commitforceeditor
1361 e = cmdutil.commitforceeditor
1362
1362
1363 def commitfunc(ui, repo, message, match, opts):
1363 def commitfunc(ui, repo, message, match, opts):
1364 return repo.commit(message, opts.get('user'), opts.get('date'),
1364 return repo.commit(message, opts.get('user'), opts.get('date'),
1365 match, editor=e, extra=extra)
1365 match, editor=e, extra=extra)
1366
1366
1367 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1367 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1368
1368
1369 if not node:
1369 if not node:
1370 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1370 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1371 if stat[3]:
1371 if stat[3]:
1372 ui.status(_("nothing changed (%d missing files, see "
1372 ui.status(_("nothing changed (%d missing files, see "
1373 "'hg status')\n") % len(stat[3]))
1373 "'hg status')\n") % len(stat[3]))
1374 else:
1374 else:
1375 ui.status(_("nothing changed\n"))
1375 ui.status(_("nothing changed\n"))
1376 return 1
1376 return 1
1377
1377
1378 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1378 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1379
1379
1380 @command('copy|cp',
1380 @command('copy|cp',
1381 [('A', 'after', None, _('record a copy that has already occurred')),
1381 [('A', 'after', None, _('record a copy that has already occurred')),
1382 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1382 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1383 ] + walkopts + dryrunopts,
1383 ] + walkopts + dryrunopts,
1384 _('[OPTION]... [SOURCE]... DEST'))
1384 _('[OPTION]... [SOURCE]... DEST'))
1385 def copy(ui, repo, *pats, **opts):
1385 def copy(ui, repo, *pats, **opts):
1386 """mark files as copied for the next commit
1386 """mark files as copied for the next commit
1387
1387
1388 Mark dest as having copies of source files. If dest is a
1388 Mark dest as having copies of source files. If dest is a
1389 directory, copies are put in that directory. If dest is a file,
1389 directory, copies are put in that directory. If dest is a file,
1390 the source must be a single file.
1390 the source must be a single file.
1391
1391
1392 By default, this command copies the contents of files as they
1392 By default, this command copies the contents of files as they
1393 exist in the working directory. If invoked with -A/--after, the
1393 exist in the working directory. If invoked with -A/--after, the
1394 operation is recorded, but no copying is performed.
1394 operation is recorded, but no copying is performed.
1395
1395
1396 This command takes effect with the next commit. To undo a copy
1396 This command takes effect with the next commit. To undo a copy
1397 before that, see :hg:`revert`.
1397 before that, see :hg:`revert`.
1398
1398
1399 Returns 0 on success, 1 if errors are encountered.
1399 Returns 0 on success, 1 if errors are encountered.
1400 """
1400 """
1401 wlock = repo.wlock(False)
1401 wlock = repo.wlock(False)
1402 try:
1402 try:
1403 return cmdutil.copy(ui, repo, pats, opts)
1403 return cmdutil.copy(ui, repo, pats, opts)
1404 finally:
1404 finally:
1405 wlock.release()
1405 wlock.release()
1406
1406
1407 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1407 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1408 def debugancestor(ui, repo, *args):
1408 def debugancestor(ui, repo, *args):
1409 """find the ancestor revision of two revisions in a given index"""
1409 """find the ancestor revision of two revisions in a given index"""
1410 if len(args) == 3:
1410 if len(args) == 3:
1411 index, rev1, rev2 = args
1411 index, rev1, rev2 = args
1412 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1412 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1413 lookup = r.lookup
1413 lookup = r.lookup
1414 elif len(args) == 2:
1414 elif len(args) == 2:
1415 if not repo:
1415 if not repo:
1416 raise util.Abort(_("there is no Mercurial repository here "
1416 raise util.Abort(_("there is no Mercurial repository here "
1417 "(.hg not found)"))
1417 "(.hg not found)"))
1418 rev1, rev2 = args
1418 rev1, rev2 = args
1419 r = repo.changelog
1419 r = repo.changelog
1420 lookup = repo.lookup
1420 lookup = repo.lookup
1421 else:
1421 else:
1422 raise util.Abort(_('either two or three arguments required'))
1422 raise util.Abort(_('either two or three arguments required'))
1423 a = r.ancestor(lookup(rev1), lookup(rev2))
1423 a = r.ancestor(lookup(rev1), lookup(rev2))
1424 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1424 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1425
1425
1426 @command('debugbuilddag',
1426 @command('debugbuilddag',
1427 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1427 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1428 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1428 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1429 ('n', 'new-file', None, _('add new file at each rev'))],
1429 ('n', 'new-file', None, _('add new file at each rev'))],
1430 _('[OPTION]... [TEXT]'))
1430 _('[OPTION]... [TEXT]'))
1431 def debugbuilddag(ui, repo, text=None,
1431 def debugbuilddag(ui, repo, text=None,
1432 mergeable_file=False,
1432 mergeable_file=False,
1433 overwritten_file=False,
1433 overwritten_file=False,
1434 new_file=False):
1434 new_file=False):
1435 """builds a repo with a given DAG from scratch in the current empty repo
1435 """builds a repo with a given DAG from scratch in the current empty repo
1436
1436
1437 The description of the DAG is read from stdin if not given on the
1437 The description of the DAG is read from stdin if not given on the
1438 command line.
1438 command line.
1439
1439
1440 Elements:
1440 Elements:
1441
1441
1442 - "+n" is a linear run of n nodes based on the current default parent
1442 - "+n" is a linear run of n nodes based on the current default parent
1443 - "." is a single node based on the current default parent
1443 - "." is a single node based on the current default parent
1444 - "$" resets the default parent to null (implied at the start);
1444 - "$" resets the default parent to null (implied at the start);
1445 otherwise the default parent is always the last node created
1445 otherwise the default parent is always the last node created
1446 - "<p" sets the default parent to the backref p
1446 - "<p" sets the default parent to the backref p
1447 - "*p" is a fork at parent p, which is a backref
1447 - "*p" is a fork at parent p, which is a backref
1448 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1448 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1449 - "/p2" is a merge of the preceding node and p2
1449 - "/p2" is a merge of the preceding node and p2
1450 - ":tag" defines a local tag for the preceding node
1450 - ":tag" defines a local tag for the preceding node
1451 - "@branch" sets the named branch for subsequent nodes
1451 - "@branch" sets the named branch for subsequent nodes
1452 - "#...\\n" is a comment up to the end of the line
1452 - "#...\\n" is a comment up to the end of the line
1453
1453
1454 Whitespace between the above elements is ignored.
1454 Whitespace between the above elements is ignored.
1455
1455
1456 A backref is either
1456 A backref is either
1457
1457
1458 - a number n, which references the node curr-n, where curr is the current
1458 - a number n, which references the node curr-n, where curr is the current
1459 node, or
1459 node, or
1460 - the name of a local tag you placed earlier using ":tag", or
1460 - the name of a local tag you placed earlier using ":tag", or
1461 - empty to denote the default parent.
1461 - empty to denote the default parent.
1462
1462
1463 All string valued-elements are either strictly alphanumeric, or must
1463 All string valued-elements are either strictly alphanumeric, or must
1464 be enclosed in double quotes ("..."), with "\\" as escape character.
1464 be enclosed in double quotes ("..."), with "\\" as escape character.
1465 """
1465 """
1466
1466
1467 if text is None:
1467 if text is None:
1468 ui.status(_("reading DAG from stdin\n"))
1468 ui.status(_("reading DAG from stdin\n"))
1469 text = ui.fin.read()
1469 text = ui.fin.read()
1470
1470
1471 cl = repo.changelog
1471 cl = repo.changelog
1472 if len(cl) > 0:
1472 if len(cl) > 0:
1473 raise util.Abort(_('repository is not empty'))
1473 raise util.Abort(_('repository is not empty'))
1474
1474
1475 # determine number of revs in DAG
1475 # determine number of revs in DAG
1476 total = 0
1476 total = 0
1477 for type, data in dagparser.parsedag(text):
1477 for type, data in dagparser.parsedag(text):
1478 if type == 'n':
1478 if type == 'n':
1479 total += 1
1479 total += 1
1480
1480
1481 if mergeable_file:
1481 if mergeable_file:
1482 linesperrev = 2
1482 linesperrev = 2
1483 # make a file with k lines per rev
1483 # make a file with k lines per rev
1484 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1484 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1485 initialmergedlines.append("")
1485 initialmergedlines.append("")
1486
1486
1487 tags = []
1487 tags = []
1488
1488
1489 lock = tr = None
1489 lock = tr = None
1490 try:
1490 try:
1491 lock = repo.lock()
1491 lock = repo.lock()
1492 tr = repo.transaction("builddag")
1492 tr = repo.transaction("builddag")
1493
1493
1494 at = -1
1494 at = -1
1495 atbranch = 'default'
1495 atbranch = 'default'
1496 nodeids = []
1496 nodeids = []
1497 id = 0
1497 id = 0
1498 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1498 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1499 for type, data in dagparser.parsedag(text):
1499 for type, data in dagparser.parsedag(text):
1500 if type == 'n':
1500 if type == 'n':
1501 ui.note(('node %s\n' % str(data)))
1501 ui.note(('node %s\n' % str(data)))
1502 id, ps = data
1502 id, ps = data
1503
1503
1504 files = []
1504 files = []
1505 fctxs = {}
1505 fctxs = {}
1506
1506
1507 p2 = None
1507 p2 = None
1508 if mergeable_file:
1508 if mergeable_file:
1509 fn = "mf"
1509 fn = "mf"
1510 p1 = repo[ps[0]]
1510 p1 = repo[ps[0]]
1511 if len(ps) > 1:
1511 if len(ps) > 1:
1512 p2 = repo[ps[1]]
1512 p2 = repo[ps[1]]
1513 pa = p1.ancestor(p2)
1513 pa = p1.ancestor(p2)
1514 base, local, other = [x[fn].data() for x in (pa, p1,
1514 base, local, other = [x[fn].data() for x in (pa, p1,
1515 p2)]
1515 p2)]
1516 m3 = simplemerge.Merge3Text(base, local, other)
1516 m3 = simplemerge.Merge3Text(base, local, other)
1517 ml = [l.strip() for l in m3.merge_lines()]
1517 ml = [l.strip() for l in m3.merge_lines()]
1518 ml.append("")
1518 ml.append("")
1519 elif at > 0:
1519 elif at > 0:
1520 ml = p1[fn].data().split("\n")
1520 ml = p1[fn].data().split("\n")
1521 else:
1521 else:
1522 ml = initialmergedlines
1522 ml = initialmergedlines
1523 ml[id * linesperrev] += " r%i" % id
1523 ml[id * linesperrev] += " r%i" % id
1524 mergedtext = "\n".join(ml)
1524 mergedtext = "\n".join(ml)
1525 files.append(fn)
1525 files.append(fn)
1526 fctxs[fn] = context.memfilectx(fn, mergedtext)
1526 fctxs[fn] = context.memfilectx(fn, mergedtext)
1527
1527
1528 if overwritten_file:
1528 if overwritten_file:
1529 fn = "of"
1529 fn = "of"
1530 files.append(fn)
1530 files.append(fn)
1531 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1531 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1532
1532
1533 if new_file:
1533 if new_file:
1534 fn = "nf%i" % id
1534 fn = "nf%i" % id
1535 files.append(fn)
1535 files.append(fn)
1536 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1536 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1537 if len(ps) > 1:
1537 if len(ps) > 1:
1538 if not p2:
1538 if not p2:
1539 p2 = repo[ps[1]]
1539 p2 = repo[ps[1]]
1540 for fn in p2:
1540 for fn in p2:
1541 if fn.startswith("nf"):
1541 if fn.startswith("nf"):
1542 files.append(fn)
1542 files.append(fn)
1543 fctxs[fn] = p2[fn]
1543 fctxs[fn] = p2[fn]
1544
1544
1545 def fctxfn(repo, cx, path):
1545 def fctxfn(repo, cx, path):
1546 return fctxs.get(path)
1546 return fctxs.get(path)
1547
1547
1548 if len(ps) == 0 or ps[0] < 0:
1548 if len(ps) == 0 or ps[0] < 0:
1549 pars = [None, None]
1549 pars = [None, None]
1550 elif len(ps) == 1:
1550 elif len(ps) == 1:
1551 pars = [nodeids[ps[0]], None]
1551 pars = [nodeids[ps[0]], None]
1552 else:
1552 else:
1553 pars = [nodeids[p] for p in ps]
1553 pars = [nodeids[p] for p in ps]
1554 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1554 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1555 date=(id, 0),
1555 date=(id, 0),
1556 user="debugbuilddag",
1556 user="debugbuilddag",
1557 extra={'branch': atbranch})
1557 extra={'branch': atbranch})
1558 nodeid = repo.commitctx(cx)
1558 nodeid = repo.commitctx(cx)
1559 nodeids.append(nodeid)
1559 nodeids.append(nodeid)
1560 at = id
1560 at = id
1561 elif type == 'l':
1561 elif type == 'l':
1562 id, name = data
1562 id, name = data
1563 ui.note(('tag %s\n' % name))
1563 ui.note(('tag %s\n' % name))
1564 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1564 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1565 elif type == 'a':
1565 elif type == 'a':
1566 ui.note(('branch %s\n' % data))
1566 ui.note(('branch %s\n' % data))
1567 atbranch = data
1567 atbranch = data
1568 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1568 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1569 tr.close()
1569 tr.close()
1570
1570
1571 if tags:
1571 if tags:
1572 repo.opener.write("localtags", "".join(tags))
1572 repo.opener.write("localtags", "".join(tags))
1573 finally:
1573 finally:
1574 ui.progress(_('building'), None)
1574 ui.progress(_('building'), None)
1575 release(tr, lock)
1575 release(tr, lock)
1576
1576
1577 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1577 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1578 def debugbundle(ui, bundlepath, all=None, **opts):
1578 def debugbundle(ui, bundlepath, all=None, **opts):
1579 """lists the contents of a bundle"""
1579 """lists the contents of a bundle"""
1580 f = hg.openpath(ui, bundlepath)
1580 f = hg.openpath(ui, bundlepath)
1581 try:
1581 try:
1582 gen = changegroup.readbundle(f, bundlepath)
1582 gen = changegroup.readbundle(f, bundlepath)
1583 if all:
1583 if all:
1584 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1584 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1585
1585
1586 def showchunks(named):
1586 def showchunks(named):
1587 ui.write("\n%s\n" % named)
1587 ui.write("\n%s\n" % named)
1588 chain = None
1588 chain = None
1589 while True:
1589 while True:
1590 chunkdata = gen.deltachunk(chain)
1590 chunkdata = gen.deltachunk(chain)
1591 if not chunkdata:
1591 if not chunkdata:
1592 break
1592 break
1593 node = chunkdata['node']
1593 node = chunkdata['node']
1594 p1 = chunkdata['p1']
1594 p1 = chunkdata['p1']
1595 p2 = chunkdata['p2']
1595 p2 = chunkdata['p2']
1596 cs = chunkdata['cs']
1596 cs = chunkdata['cs']
1597 deltabase = chunkdata['deltabase']
1597 deltabase = chunkdata['deltabase']
1598 delta = chunkdata['delta']
1598 delta = chunkdata['delta']
1599 ui.write("%s %s %s %s %s %s\n" %
1599 ui.write("%s %s %s %s %s %s\n" %
1600 (hex(node), hex(p1), hex(p2),
1600 (hex(node), hex(p1), hex(p2),
1601 hex(cs), hex(deltabase), len(delta)))
1601 hex(cs), hex(deltabase), len(delta)))
1602 chain = node
1602 chain = node
1603
1603
1604 chunkdata = gen.changelogheader()
1604 chunkdata = gen.changelogheader()
1605 showchunks("changelog")
1605 showchunks("changelog")
1606 chunkdata = gen.manifestheader()
1606 chunkdata = gen.manifestheader()
1607 showchunks("manifest")
1607 showchunks("manifest")
1608 while True:
1608 while True:
1609 chunkdata = gen.filelogheader()
1609 chunkdata = gen.filelogheader()
1610 if not chunkdata:
1610 if not chunkdata:
1611 break
1611 break
1612 fname = chunkdata['filename']
1612 fname = chunkdata['filename']
1613 showchunks(fname)
1613 showchunks(fname)
1614 else:
1614 else:
1615 chunkdata = gen.changelogheader()
1615 chunkdata = gen.changelogheader()
1616 chain = None
1616 chain = None
1617 while True:
1617 while True:
1618 chunkdata = gen.deltachunk(chain)
1618 chunkdata = gen.deltachunk(chain)
1619 if not chunkdata:
1619 if not chunkdata:
1620 break
1620 break
1621 node = chunkdata['node']
1621 node = chunkdata['node']
1622 ui.write("%s\n" % hex(node))
1622 ui.write("%s\n" % hex(node))
1623 chain = node
1623 chain = node
1624 finally:
1624 finally:
1625 f.close()
1625 f.close()
1626
1626
1627 @command('debugcheckstate', [], '')
1627 @command('debugcheckstate', [], '')
1628 def debugcheckstate(ui, repo):
1628 def debugcheckstate(ui, repo):
1629 """validate the correctness of the current dirstate"""
1629 """validate the correctness of the current dirstate"""
1630 parent1, parent2 = repo.dirstate.parents()
1630 parent1, parent2 = repo.dirstate.parents()
1631 m1 = repo[parent1].manifest()
1631 m1 = repo[parent1].manifest()
1632 m2 = repo[parent2].manifest()
1632 m2 = repo[parent2].manifest()
1633 errors = 0
1633 errors = 0
1634 for f in repo.dirstate:
1634 for f in repo.dirstate:
1635 state = repo.dirstate[f]
1635 state = repo.dirstate[f]
1636 if state in "nr" and f not in m1:
1636 if state in "nr" and f not in m1:
1637 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1637 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1638 errors += 1
1638 errors += 1
1639 if state in "a" and f in m1:
1639 if state in "a" and f in m1:
1640 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1640 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1641 errors += 1
1641 errors += 1
1642 if state in "m" and f not in m1 and f not in m2:
1642 if state in "m" and f not in m1 and f not in m2:
1643 ui.warn(_("%s in state %s, but not in either manifest\n") %
1643 ui.warn(_("%s in state %s, but not in either manifest\n") %
1644 (f, state))
1644 (f, state))
1645 errors += 1
1645 errors += 1
1646 for f in m1:
1646 for f in m1:
1647 state = repo.dirstate[f]
1647 state = repo.dirstate[f]
1648 if state not in "nrm":
1648 if state not in "nrm":
1649 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1649 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1650 errors += 1
1650 errors += 1
1651 if errors:
1651 if errors:
1652 error = _(".hg/dirstate inconsistent with current parent's manifest")
1652 error = _(".hg/dirstate inconsistent with current parent's manifest")
1653 raise util.Abort(error)
1653 raise util.Abort(error)
1654
1654
1655 @command('debugcommands', [], _('[COMMAND]'))
1655 @command('debugcommands', [], _('[COMMAND]'))
1656 def debugcommands(ui, cmd='', *args):
1656 def debugcommands(ui, cmd='', *args):
1657 """list all available commands and options"""
1657 """list all available commands and options"""
1658 for cmd, vals in sorted(table.iteritems()):
1658 for cmd, vals in sorted(table.iteritems()):
1659 cmd = cmd.split('|')[0].strip('^')
1659 cmd = cmd.split('|')[0].strip('^')
1660 opts = ', '.join([i[1] for i in vals[1]])
1660 opts = ', '.join([i[1] for i in vals[1]])
1661 ui.write('%s: %s\n' % (cmd, opts))
1661 ui.write('%s: %s\n' % (cmd, opts))
1662
1662
1663 @command('debugcomplete',
1663 @command('debugcomplete',
1664 [('o', 'options', None, _('show the command options'))],
1664 [('o', 'options', None, _('show the command options'))],
1665 _('[-o] CMD'))
1665 _('[-o] CMD'))
1666 def debugcomplete(ui, cmd='', **opts):
1666 def debugcomplete(ui, cmd='', **opts):
1667 """returns the completion list associated with the given command"""
1667 """returns the completion list associated with the given command"""
1668
1668
1669 if opts.get('options'):
1669 if opts.get('options'):
1670 options = []
1670 options = []
1671 otables = [globalopts]
1671 otables = [globalopts]
1672 if cmd:
1672 if cmd:
1673 aliases, entry = cmdutil.findcmd(cmd, table, False)
1673 aliases, entry = cmdutil.findcmd(cmd, table, False)
1674 otables.append(entry[1])
1674 otables.append(entry[1])
1675 for t in otables:
1675 for t in otables:
1676 for o in t:
1676 for o in t:
1677 if "(DEPRECATED)" in o[3]:
1677 if "(DEPRECATED)" in o[3]:
1678 continue
1678 continue
1679 if o[0]:
1679 if o[0]:
1680 options.append('-%s' % o[0])
1680 options.append('-%s' % o[0])
1681 options.append('--%s' % o[1])
1681 options.append('--%s' % o[1])
1682 ui.write("%s\n" % "\n".join(options))
1682 ui.write("%s\n" % "\n".join(options))
1683 return
1683 return
1684
1684
1685 cmdlist = cmdutil.findpossible(cmd, table)
1685 cmdlist = cmdutil.findpossible(cmd, table)
1686 if ui.verbose:
1686 if ui.verbose:
1687 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1687 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1688 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1688 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1689
1689
1690 @command('debugdag',
1690 @command('debugdag',
1691 [('t', 'tags', None, _('use tags as labels')),
1691 [('t', 'tags', None, _('use tags as labels')),
1692 ('b', 'branches', None, _('annotate with branch names')),
1692 ('b', 'branches', None, _('annotate with branch names')),
1693 ('', 'dots', None, _('use dots for runs')),
1693 ('', 'dots', None, _('use dots for runs')),
1694 ('s', 'spaces', None, _('separate elements by spaces'))],
1694 ('s', 'spaces', None, _('separate elements by spaces'))],
1695 _('[OPTION]... [FILE [REV]...]'))
1695 _('[OPTION]... [FILE [REV]...]'))
1696 def debugdag(ui, repo, file_=None, *revs, **opts):
1696 def debugdag(ui, repo, file_=None, *revs, **opts):
1697 """format the changelog or an index DAG as a concise textual description
1697 """format the changelog or an index DAG as a concise textual description
1698
1698
1699 If you pass a revlog index, the revlog's DAG is emitted. If you list
1699 If you pass a revlog index, the revlog's DAG is emitted. If you list
1700 revision numbers, they get labeled in the output as rN.
1700 revision numbers, they get labeled in the output as rN.
1701
1701
1702 Otherwise, the changelog DAG of the current repo is emitted.
1702 Otherwise, the changelog DAG of the current repo is emitted.
1703 """
1703 """
1704 spaces = opts.get('spaces')
1704 spaces = opts.get('spaces')
1705 dots = opts.get('dots')
1705 dots = opts.get('dots')
1706 if file_:
1706 if file_:
1707 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1707 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1708 revs = set((int(r) for r in revs))
1708 revs = set((int(r) for r in revs))
1709 def events():
1709 def events():
1710 for r in rlog:
1710 for r in rlog:
1711 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1711 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1712 if p != -1)))
1712 if p != -1)))
1713 if r in revs:
1713 if r in revs:
1714 yield 'l', (r, "r%i" % r)
1714 yield 'l', (r, "r%i" % r)
1715 elif repo:
1715 elif repo:
1716 cl = repo.changelog
1716 cl = repo.changelog
1717 tags = opts.get('tags')
1717 tags = opts.get('tags')
1718 branches = opts.get('branches')
1718 branches = opts.get('branches')
1719 if tags:
1719 if tags:
1720 labels = {}
1720 labels = {}
1721 for l, n in repo.tags().items():
1721 for l, n in repo.tags().items():
1722 labels.setdefault(cl.rev(n), []).append(l)
1722 labels.setdefault(cl.rev(n), []).append(l)
1723 def events():
1723 def events():
1724 b = "default"
1724 b = "default"
1725 for r in cl:
1725 for r in cl:
1726 if branches:
1726 if branches:
1727 newb = cl.read(cl.node(r))[5]['branch']
1727 newb = cl.read(cl.node(r))[5]['branch']
1728 if newb != b:
1728 if newb != b:
1729 yield 'a', newb
1729 yield 'a', newb
1730 b = newb
1730 b = newb
1731 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1731 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1732 if p != -1)))
1732 if p != -1)))
1733 if tags:
1733 if tags:
1734 ls = labels.get(r)
1734 ls = labels.get(r)
1735 if ls:
1735 if ls:
1736 for l in ls:
1736 for l in ls:
1737 yield 'l', (r, l)
1737 yield 'l', (r, l)
1738 else:
1738 else:
1739 raise util.Abort(_('need repo for changelog dag'))
1739 raise util.Abort(_('need repo for changelog dag'))
1740
1740
1741 for line in dagparser.dagtextlines(events(),
1741 for line in dagparser.dagtextlines(events(),
1742 addspaces=spaces,
1742 addspaces=spaces,
1743 wraplabels=True,
1743 wraplabels=True,
1744 wrapannotations=True,
1744 wrapannotations=True,
1745 wrapnonlinear=dots,
1745 wrapnonlinear=dots,
1746 usedots=dots,
1746 usedots=dots,
1747 maxlinewidth=70):
1747 maxlinewidth=70):
1748 ui.write(line)
1748 ui.write(line)
1749 ui.write("\n")
1749 ui.write("\n")
1750
1750
1751 @command('debugdata',
1751 @command('debugdata',
1752 [('c', 'changelog', False, _('open changelog')),
1752 [('c', 'changelog', False, _('open changelog')),
1753 ('m', 'manifest', False, _('open manifest'))],
1753 ('m', 'manifest', False, _('open manifest'))],
1754 _('-c|-m|FILE REV'))
1754 _('-c|-m|FILE REV'))
1755 def debugdata(ui, repo, file_, rev = None, **opts):
1755 def debugdata(ui, repo, file_, rev = None, **opts):
1756 """dump the contents of a data file revision"""
1756 """dump the contents of a data file revision"""
1757 if opts.get('changelog') or opts.get('manifest'):
1757 if opts.get('changelog') or opts.get('manifest'):
1758 file_, rev = None, file_
1758 file_, rev = None, file_
1759 elif rev is None:
1759 elif rev is None:
1760 raise error.CommandError('debugdata', _('invalid arguments'))
1760 raise error.CommandError('debugdata', _('invalid arguments'))
1761 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1761 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1762 try:
1762 try:
1763 ui.write(r.revision(r.lookup(rev)))
1763 ui.write(r.revision(r.lookup(rev)))
1764 except KeyError:
1764 except KeyError:
1765 raise util.Abort(_('invalid revision identifier %s') % rev)
1765 raise util.Abort(_('invalid revision identifier %s') % rev)
1766
1766
1767 @command('debugdate',
1767 @command('debugdate',
1768 [('e', 'extended', None, _('try extended date formats'))],
1768 [('e', 'extended', None, _('try extended date formats'))],
1769 _('[-e] DATE [RANGE]'))
1769 _('[-e] DATE [RANGE]'))
1770 def debugdate(ui, date, range=None, **opts):
1770 def debugdate(ui, date, range=None, **opts):
1771 """parse and display a date"""
1771 """parse and display a date"""
1772 if opts["extended"]:
1772 if opts["extended"]:
1773 d = util.parsedate(date, util.extendeddateformats)
1773 d = util.parsedate(date, util.extendeddateformats)
1774 else:
1774 else:
1775 d = util.parsedate(date)
1775 d = util.parsedate(date)
1776 ui.write(("internal: %s %s\n") % d)
1776 ui.write(("internal: %s %s\n") % d)
1777 ui.write(("standard: %s\n") % util.datestr(d))
1777 ui.write(("standard: %s\n") % util.datestr(d))
1778 if range:
1778 if range:
1779 m = util.matchdate(range)
1779 m = util.matchdate(range)
1780 ui.write(("match: %s\n") % m(d[0]))
1780 ui.write(("match: %s\n") % m(d[0]))
1781
1781
1782 @command('debugdiscovery',
1782 @command('debugdiscovery',
1783 [('', 'old', None, _('use old-style discovery')),
1783 [('', 'old', None, _('use old-style discovery')),
1784 ('', 'nonheads', None,
1784 ('', 'nonheads', None,
1785 _('use old-style discovery with non-heads included')),
1785 _('use old-style discovery with non-heads included')),
1786 ] + remoteopts,
1786 ] + remoteopts,
1787 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1787 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1788 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1788 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1789 """runs the changeset discovery protocol in isolation"""
1789 """runs the changeset discovery protocol in isolation"""
1790 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1790 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1791 opts.get('branch'))
1791 opts.get('branch'))
1792 remote = hg.peer(repo, opts, remoteurl)
1792 remote = hg.peer(repo, opts, remoteurl)
1793 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1793 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1794
1794
1795 # make sure tests are repeatable
1795 # make sure tests are repeatable
1796 random.seed(12323)
1796 random.seed(12323)
1797
1797
1798 def doit(localheads, remoteheads, remote=remote):
1798 def doit(localheads, remoteheads, remote=remote):
1799 if opts.get('old'):
1799 if opts.get('old'):
1800 if localheads:
1800 if localheads:
1801 raise util.Abort('cannot use localheads with old style '
1801 raise util.Abort('cannot use localheads with old style '
1802 'discovery')
1802 'discovery')
1803 if not util.safehasattr(remote, 'branches'):
1803 if not util.safehasattr(remote, 'branches'):
1804 # enable in-client legacy support
1804 # enable in-client legacy support
1805 remote = localrepo.locallegacypeer(remote.local())
1805 remote = localrepo.locallegacypeer(remote.local())
1806 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1806 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1807 force=True)
1807 force=True)
1808 common = set(common)
1808 common = set(common)
1809 if not opts.get('nonheads'):
1809 if not opts.get('nonheads'):
1810 ui.write(("unpruned common: %s\n") %
1810 ui.write(("unpruned common: %s\n") %
1811 " ".join(sorted(short(n) for n in common)))
1811 " ".join(sorted(short(n) for n in common)))
1812 dag = dagutil.revlogdag(repo.changelog)
1812 dag = dagutil.revlogdag(repo.changelog)
1813 all = dag.ancestorset(dag.internalizeall(common))
1813 all = dag.ancestorset(dag.internalizeall(common))
1814 common = dag.externalizeall(dag.headsetofconnecteds(all))
1814 common = dag.externalizeall(dag.headsetofconnecteds(all))
1815 else:
1815 else:
1816 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1816 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1817 common = set(common)
1817 common = set(common)
1818 rheads = set(hds)
1818 rheads = set(hds)
1819 lheads = set(repo.heads())
1819 lheads = set(repo.heads())
1820 ui.write(("common heads: %s\n") %
1820 ui.write(("common heads: %s\n") %
1821 " ".join(sorted(short(n) for n in common)))
1821 " ".join(sorted(short(n) for n in common)))
1822 if lheads <= common:
1822 if lheads <= common:
1823 ui.write(("local is subset\n"))
1823 ui.write(("local is subset\n"))
1824 elif rheads <= common:
1824 elif rheads <= common:
1825 ui.write(("remote is subset\n"))
1825 ui.write(("remote is subset\n"))
1826
1826
1827 serverlogs = opts.get('serverlog')
1827 serverlogs = opts.get('serverlog')
1828 if serverlogs:
1828 if serverlogs:
1829 for filename in serverlogs:
1829 for filename in serverlogs:
1830 logfile = open(filename, 'r')
1830 logfile = open(filename, 'r')
1831 try:
1831 try:
1832 line = logfile.readline()
1832 line = logfile.readline()
1833 while line:
1833 while line:
1834 parts = line.strip().split(';')
1834 parts = line.strip().split(';')
1835 op = parts[1]
1835 op = parts[1]
1836 if op == 'cg':
1836 if op == 'cg':
1837 pass
1837 pass
1838 elif op == 'cgss':
1838 elif op == 'cgss':
1839 doit(parts[2].split(' '), parts[3].split(' '))
1839 doit(parts[2].split(' '), parts[3].split(' '))
1840 elif op == 'unb':
1840 elif op == 'unb':
1841 doit(parts[3].split(' '), parts[2].split(' '))
1841 doit(parts[3].split(' '), parts[2].split(' '))
1842 line = logfile.readline()
1842 line = logfile.readline()
1843 finally:
1843 finally:
1844 logfile.close()
1844 logfile.close()
1845
1845
1846 else:
1846 else:
1847 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1847 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1848 opts.get('remote_head'))
1848 opts.get('remote_head'))
1849 localrevs = opts.get('local_head')
1849 localrevs = opts.get('local_head')
1850 doit(localrevs, remoterevs)
1850 doit(localrevs, remoterevs)
1851
1851
1852 @command('debugfileset',
1852 @command('debugfileset',
1853 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1853 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1854 _('[-r REV] FILESPEC'))
1854 _('[-r REV] FILESPEC'))
1855 def debugfileset(ui, repo, expr, **opts):
1855 def debugfileset(ui, repo, expr, **opts):
1856 '''parse and apply a fileset specification'''
1856 '''parse and apply a fileset specification'''
1857 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1857 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1858 if ui.verbose:
1858 if ui.verbose:
1859 tree = fileset.parse(expr)[0]
1859 tree = fileset.parse(expr)[0]
1860 ui.note(tree, "\n")
1860 ui.note(tree, "\n")
1861
1861
1862 for f in fileset.getfileset(ctx, expr):
1862 for f in fileset.getfileset(ctx, expr):
1863 ui.write("%s\n" % f)
1863 ui.write("%s\n" % f)
1864
1864
1865 @command('debugfsinfo', [], _('[PATH]'))
1865 @command('debugfsinfo', [], _('[PATH]'))
1866 def debugfsinfo(ui, path = "."):
1866 def debugfsinfo(ui, path = "."):
1867 """show information detected about current filesystem"""
1867 """show information detected about current filesystem"""
1868 util.writefile('.debugfsinfo', '')
1868 util.writefile('.debugfsinfo', '')
1869 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1869 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1870 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1870 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1871 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1871 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1872 and 'yes' or 'no'))
1872 and 'yes' or 'no'))
1873 os.unlink('.debugfsinfo')
1873 os.unlink('.debugfsinfo')
1874
1874
1875 @command('debuggetbundle',
1875 @command('debuggetbundle',
1876 [('H', 'head', [], _('id of head node'), _('ID')),
1876 [('H', 'head', [], _('id of head node'), _('ID')),
1877 ('C', 'common', [], _('id of common node'), _('ID')),
1877 ('C', 'common', [], _('id of common node'), _('ID')),
1878 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1878 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1879 _('REPO FILE [-H|-C ID]...'))
1879 _('REPO FILE [-H|-C ID]...'))
1880 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1880 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1881 """retrieves a bundle from a repo
1881 """retrieves a bundle from a repo
1882
1882
1883 Every ID must be a full-length hex node id string. Saves the bundle to the
1883 Every ID must be a full-length hex node id string. Saves the bundle to the
1884 given file.
1884 given file.
1885 """
1885 """
1886 repo = hg.peer(ui, opts, repopath)
1886 repo = hg.peer(ui, opts, repopath)
1887 if not repo.capable('getbundle'):
1887 if not repo.capable('getbundle'):
1888 raise util.Abort("getbundle() not supported by target repository")
1888 raise util.Abort("getbundle() not supported by target repository")
1889 args = {}
1889 args = {}
1890 if common:
1890 if common:
1891 args['common'] = [bin(s) for s in common]
1891 args['common'] = [bin(s) for s in common]
1892 if head:
1892 if head:
1893 args['heads'] = [bin(s) for s in head]
1893 args['heads'] = [bin(s) for s in head]
1894 bundle = repo.getbundle('debug', **args)
1894 bundle = repo.getbundle('debug', **args)
1895
1895
1896 bundletype = opts.get('type', 'bzip2').lower()
1896 bundletype = opts.get('type', 'bzip2').lower()
1897 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1897 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1898 bundletype = btypes.get(bundletype)
1898 bundletype = btypes.get(bundletype)
1899 if bundletype not in changegroup.bundletypes:
1899 if bundletype not in changegroup.bundletypes:
1900 raise util.Abort(_('unknown bundle type specified with --type'))
1900 raise util.Abort(_('unknown bundle type specified with --type'))
1901 changegroup.writebundle(bundle, bundlepath, bundletype)
1901 changegroup.writebundle(bundle, bundlepath, bundletype)
1902
1902
1903 @command('debugignore', [], '')
1903 @command('debugignore', [], '')
1904 def debugignore(ui, repo, *values, **opts):
1904 def debugignore(ui, repo, *values, **opts):
1905 """display the combined ignore pattern"""
1905 """display the combined ignore pattern"""
1906 ignore = repo.dirstate._ignore
1906 ignore = repo.dirstate._ignore
1907 includepat = getattr(ignore, 'includepat', None)
1907 includepat = getattr(ignore, 'includepat', None)
1908 if includepat is not None:
1908 if includepat is not None:
1909 ui.write("%s\n" % includepat)
1909 ui.write("%s\n" % includepat)
1910 else:
1910 else:
1911 raise util.Abort(_("no ignore patterns found"))
1911 raise util.Abort(_("no ignore patterns found"))
1912
1912
1913 @command('debugindex',
1913 @command('debugindex',
1914 [('c', 'changelog', False, _('open changelog')),
1914 [('c', 'changelog', False, _('open changelog')),
1915 ('m', 'manifest', False, _('open manifest')),
1915 ('m', 'manifest', False, _('open manifest')),
1916 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1916 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1917 _('[-f FORMAT] -c|-m|FILE'))
1917 _('[-f FORMAT] -c|-m|FILE'))
1918 def debugindex(ui, repo, file_ = None, **opts):
1918 def debugindex(ui, repo, file_ = None, **opts):
1919 """dump the contents of an index file"""
1919 """dump the contents of an index file"""
1920 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1920 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1921 format = opts.get('format', 0)
1921 format = opts.get('format', 0)
1922 if format not in (0, 1):
1922 if format not in (0, 1):
1923 raise util.Abort(_("unknown format %d") % format)
1923 raise util.Abort(_("unknown format %d") % format)
1924
1924
1925 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1925 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1926 if generaldelta:
1926 if generaldelta:
1927 basehdr = ' delta'
1927 basehdr = ' delta'
1928 else:
1928 else:
1929 basehdr = ' base'
1929 basehdr = ' base'
1930
1930
1931 if format == 0:
1931 if format == 0:
1932 ui.write(" rev offset length " + basehdr + " linkrev"
1932 ui.write(" rev offset length " + basehdr + " linkrev"
1933 " nodeid p1 p2\n")
1933 " nodeid p1 p2\n")
1934 elif format == 1:
1934 elif format == 1:
1935 ui.write(" rev flag offset length"
1935 ui.write(" rev flag offset length"
1936 " size " + basehdr + " link p1 p2"
1936 " size " + basehdr + " link p1 p2"
1937 " nodeid\n")
1937 " nodeid\n")
1938
1938
1939 for i in r:
1939 for i in r:
1940 node = r.node(i)
1940 node = r.node(i)
1941 if generaldelta:
1941 if generaldelta:
1942 base = r.deltaparent(i)
1942 base = r.deltaparent(i)
1943 else:
1943 else:
1944 base = r.chainbase(i)
1944 base = r.chainbase(i)
1945 if format == 0:
1945 if format == 0:
1946 try:
1946 try:
1947 pp = r.parents(node)
1947 pp = r.parents(node)
1948 except Exception:
1948 except Exception:
1949 pp = [nullid, nullid]
1949 pp = [nullid, nullid]
1950 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1950 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1951 i, r.start(i), r.length(i), base, r.linkrev(i),
1951 i, r.start(i), r.length(i), base, r.linkrev(i),
1952 short(node), short(pp[0]), short(pp[1])))
1952 short(node), short(pp[0]), short(pp[1])))
1953 elif format == 1:
1953 elif format == 1:
1954 pr = r.parentrevs(i)
1954 pr = r.parentrevs(i)
1955 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1955 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1956 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1956 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1957 base, r.linkrev(i), pr[0], pr[1], short(node)))
1957 base, r.linkrev(i), pr[0], pr[1], short(node)))
1958
1958
1959 @command('debugindexdot', [], _('FILE'))
1959 @command('debugindexdot', [], _('FILE'))
1960 def debugindexdot(ui, repo, file_):
1960 def debugindexdot(ui, repo, file_):
1961 """dump an index DAG as a graphviz dot file"""
1961 """dump an index DAG as a graphviz dot file"""
1962 r = None
1962 r = None
1963 if repo:
1963 if repo:
1964 filelog = repo.file(file_)
1964 filelog = repo.file(file_)
1965 if len(filelog):
1965 if len(filelog):
1966 r = filelog
1966 r = filelog
1967 if not r:
1967 if not r:
1968 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1968 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1969 ui.write(("digraph G {\n"))
1969 ui.write(("digraph G {\n"))
1970 for i in r:
1970 for i in r:
1971 node = r.node(i)
1971 node = r.node(i)
1972 pp = r.parents(node)
1972 pp = r.parents(node)
1973 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1973 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1974 if pp[1] != nullid:
1974 if pp[1] != nullid:
1975 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1975 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1976 ui.write("}\n")
1976 ui.write("}\n")
1977
1977
1978 @command('debuginstall', [], '')
1978 @command('debuginstall', [], '')
1979 def debuginstall(ui):
1979 def debuginstall(ui):
1980 '''test Mercurial installation
1980 '''test Mercurial installation
1981
1981
1982 Returns 0 on success.
1982 Returns 0 on success.
1983 '''
1983 '''
1984
1984
1985 def writetemp(contents):
1985 def writetemp(contents):
1986 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1986 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1987 f = os.fdopen(fd, "wb")
1987 f = os.fdopen(fd, "wb")
1988 f.write(contents)
1988 f.write(contents)
1989 f.close()
1989 f.close()
1990 return name
1990 return name
1991
1991
1992 problems = 0
1992 problems = 0
1993
1993
1994 # encoding
1994 # encoding
1995 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
1995 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
1996 try:
1996 try:
1997 encoding.fromlocal("test")
1997 encoding.fromlocal("test")
1998 except util.Abort, inst:
1998 except util.Abort, inst:
1999 ui.write(" %s\n" % inst)
1999 ui.write(" %s\n" % inst)
2000 ui.write(_(" (check that your locale is properly set)\n"))
2000 ui.write(_(" (check that your locale is properly set)\n"))
2001 problems += 1
2001 problems += 1
2002
2002
2003 # Python lib
2003 # Python lib
2004 ui.status(_("checking Python lib (%s)...\n")
2004 ui.status(_("checking Python lib (%s)...\n")
2005 % os.path.dirname(os.__file__))
2005 % os.path.dirname(os.__file__))
2006
2006
2007 # compiled modules
2007 # compiled modules
2008 ui.status(_("checking installed modules (%s)...\n")
2008 ui.status(_("checking installed modules (%s)...\n")
2009 % os.path.dirname(__file__))
2009 % os.path.dirname(__file__))
2010 try:
2010 try:
2011 import bdiff, mpatch, base85, osutil
2011 import bdiff, mpatch, base85, osutil
2012 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2012 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2013 except Exception, inst:
2013 except Exception, inst:
2014 ui.write(" %s\n" % inst)
2014 ui.write(" %s\n" % inst)
2015 ui.write(_(" One or more extensions could not be found"))
2015 ui.write(_(" One or more extensions could not be found"))
2016 ui.write(_(" (check that you compiled the extensions)\n"))
2016 ui.write(_(" (check that you compiled the extensions)\n"))
2017 problems += 1
2017 problems += 1
2018
2018
2019 # templates
2019 # templates
2020 import templater
2020 import templater
2021 p = templater.templatepath()
2021 p = templater.templatepath()
2022 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2022 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2023 try:
2023 try:
2024 templater.templater(templater.templatepath("map-cmdline.default"))
2024 templater.templater(templater.templatepath("map-cmdline.default"))
2025 except Exception, inst:
2025 except Exception, inst:
2026 ui.write(" %s\n" % inst)
2026 ui.write(" %s\n" % inst)
2027 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2027 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2028 problems += 1
2028 problems += 1
2029
2029
2030 # editor
2030 # editor
2031 ui.status(_("checking commit editor...\n"))
2031 ui.status(_("checking commit editor...\n"))
2032 editor = ui.geteditor()
2032 editor = ui.geteditor()
2033 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2033 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2034 if not cmdpath:
2034 if not cmdpath:
2035 if editor == 'vi':
2035 if editor == 'vi':
2036 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2036 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2037 ui.write(_(" (specify a commit editor in your configuration"
2037 ui.write(_(" (specify a commit editor in your configuration"
2038 " file)\n"))
2038 " file)\n"))
2039 else:
2039 else:
2040 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2040 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2041 ui.write(_(" (specify a commit editor in your configuration"
2041 ui.write(_(" (specify a commit editor in your configuration"
2042 " file)\n"))
2042 " file)\n"))
2043 problems += 1
2043 problems += 1
2044
2044
2045 # check username
2045 # check username
2046 ui.status(_("checking username...\n"))
2046 ui.status(_("checking username...\n"))
2047 try:
2047 try:
2048 ui.username()
2048 ui.username()
2049 except util.Abort, e:
2049 except util.Abort, e:
2050 ui.write(" %s\n" % e)
2050 ui.write(" %s\n" % e)
2051 ui.write(_(" (specify a username in your configuration file)\n"))
2051 ui.write(_(" (specify a username in your configuration file)\n"))
2052 problems += 1
2052 problems += 1
2053
2053
2054 if not problems:
2054 if not problems:
2055 ui.status(_("no problems detected\n"))
2055 ui.status(_("no problems detected\n"))
2056 else:
2056 else:
2057 ui.write(_("%s problems detected,"
2057 ui.write(_("%s problems detected,"
2058 " please check your install!\n") % problems)
2058 " please check your install!\n") % problems)
2059
2059
2060 return problems
2060 return problems
2061
2061
2062 @command('debugknown', [], _('REPO ID...'))
2062 @command('debugknown', [], _('REPO ID...'))
2063 def debugknown(ui, repopath, *ids, **opts):
2063 def debugknown(ui, repopath, *ids, **opts):
2064 """test whether node ids are known to a repo
2064 """test whether node ids are known to a repo
2065
2065
2066 Every ID must be a full-length hex node id string. Returns a list of 0s
2066 Every ID must be a full-length hex node id string. Returns a list of 0s
2067 and 1s indicating unknown/known.
2067 and 1s indicating unknown/known.
2068 """
2068 """
2069 repo = hg.peer(ui, opts, repopath)
2069 repo = hg.peer(ui, opts, repopath)
2070 if not repo.capable('known'):
2070 if not repo.capable('known'):
2071 raise util.Abort("known() not supported by target repository")
2071 raise util.Abort("known() not supported by target repository")
2072 flags = repo.known([bin(s) for s in ids])
2072 flags = repo.known([bin(s) for s in ids])
2073 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2073 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2074
2074
2075 @command('debuglabelcomplete', [], _('LABEL...'))
2075 @command('debuglabelcomplete', [], _('LABEL...'))
2076 def debuglabelcomplete(ui, repo, *args):
2076 def debuglabelcomplete(ui, repo, *args):
2077 '''complete "labels" - tags, open branch names, bookmark names'''
2077 '''complete "labels" - tags, open branch names, bookmark names'''
2078
2078
2079 labels = set()
2079 labels = set()
2080 labels.update(t[0] for t in repo.tagslist())
2080 labels.update(t[0] for t in repo.tagslist())
2081 labels.update(repo[n].branch() for n in repo.heads())
2081 labels.update(repo[n].branch() for n in repo.heads())
2082 labels.update(repo._bookmarks.keys())
2082 labels.update(repo._bookmarks.keys())
2083 completions = set()
2083 completions = set()
2084 if not args:
2084 if not args:
2085 args = ['']
2085 args = ['']
2086 for a in args:
2086 for a in args:
2087 completions.update(l for l in labels if l.startswith(a))
2087 completions.update(l for l in labels if l.startswith(a))
2088 ui.write('\n'.join(sorted(completions)))
2088 ui.write('\n'.join(sorted(completions)))
2089 ui.write('\n')
2089 ui.write('\n')
2090
2090
2091 @command('debugobsolete',
2091 @command('debugobsolete',
2092 [('', 'flags', 0, _('markers flag')),
2092 [('', 'flags', 0, _('markers flag')),
2093 ] + commitopts2,
2093 ] + commitopts2,
2094 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2094 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2095 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2095 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2096 """create arbitrary obsolete marker
2096 """create arbitrary obsolete marker
2097
2097
2098 With no arguments it it display the list obsolescence marker."""
2098 With no arguments it it display the list obsolescence marker."""
2099 def parsenodeid(s):
2099 def parsenodeid(s):
2100 try:
2100 try:
2101 # We do not use revsingle/revrange functions here to accept
2101 # We do not use revsingle/revrange functions here to accept
2102 # arbitrary node identifiers, possibly not present in the
2102 # arbitrary node identifiers, possibly not present in the
2103 # local repository.
2103 # local repository.
2104 n = bin(s)
2104 n = bin(s)
2105 if len(n) != len(nullid):
2105 if len(n) != len(nullid):
2106 raise TypeError()
2106 raise TypeError()
2107 return n
2107 return n
2108 except TypeError:
2108 except TypeError:
2109 raise util.Abort('changeset references must be full hexadecimal '
2109 raise util.Abort('changeset references must be full hexadecimal '
2110 'node identifiers')
2110 'node identifiers')
2111
2111
2112 if precursor is not None:
2112 if precursor is not None:
2113 metadata = {}
2113 metadata = {}
2114 if 'date' in opts:
2114 if 'date' in opts:
2115 metadata['date'] = opts['date']
2115 metadata['date'] = opts['date']
2116 metadata['user'] = opts['user'] or ui.username()
2116 metadata['user'] = opts['user'] or ui.username()
2117 succs = tuple(parsenodeid(succ) for succ in successors)
2117 succs = tuple(parsenodeid(succ) for succ in successors)
2118 l = repo.lock()
2118 l = repo.lock()
2119 try:
2119 try:
2120 tr = repo.transaction('debugobsolete')
2120 tr = repo.transaction('debugobsolete')
2121 try:
2121 try:
2122 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2122 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2123 opts['flags'], metadata)
2123 opts['flags'], metadata)
2124 tr.close()
2124 tr.close()
2125 finally:
2125 finally:
2126 tr.release()
2126 tr.release()
2127 finally:
2127 finally:
2128 l.release()
2128 l.release()
2129 else:
2129 else:
2130 for m in obsolete.allmarkers(repo):
2130 for m in obsolete.allmarkers(repo):
2131 ui.write(hex(m.precnode()))
2131 ui.write(hex(m.precnode()))
2132 for repl in m.succnodes():
2132 for repl in m.succnodes():
2133 ui.write(' ')
2133 ui.write(' ')
2134 ui.write(hex(repl))
2134 ui.write(hex(repl))
2135 ui.write(' %X ' % m._data[2])
2135 ui.write(' %X ' % m._data[2])
2136 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2136 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2137 sorted(m.metadata().items()))))
2137 sorted(m.metadata().items()))))
2138 ui.write('\n')
2138 ui.write('\n')
2139
2139
2140 @command('debugpathcomplete',
2141 [('f', 'full', None, _('complete an entire path')),
2142 ('n', 'normal', None, _('show only normal files')),
2143 ('a', 'added', None, _('show only added files')),
2144 ('r', 'removed', None, _('show only removed files'))],
2145 _('FILESPEC...'))
2146 def debugpathcomplete(ui, repo, *specs, **opts):
2147 '''complete part or all of a tracked path
2148
2149 This command supports shells that offer path name completion. It
2150 currently completes only files already known to the dirstate.
2151
2152 Completion extends only to the next path segment unless
2153 --full is specified, in which case entire paths are used.'''
2154
2155 def complete(path, acceptable):
2156 dirstate = repo.dirstate
2157 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2158 rootdir = repo.root + os.sep
2159 if spec != repo.root and not spec.startswith(rootdir):
2160 return [], []
2161 if os.path.isdir(spec):
2162 spec += '/'
2163 spec = spec[len(rootdir):]
2164 fixpaths = os.sep != '/'
2165 if fixpaths:
2166 spec = spec.replace(os.sep, '/')
2167 speclen = len(spec)
2168 fullpaths = opts['full']
2169 files, dirs = set(), set()
2170 adddir, addfile = dirs.add, files.add
2171 for f, st in dirstate.iteritems():
2172 if f.startswith(spec) and st[0] in acceptable:
2173 if fixpaths:
2174 f = f.replace('/', os.sep)
2175 if fullpaths:
2176 addfile(f)
2177 continue
2178 s = f.find(os.sep, speclen)
2179 if s >= 0:
2180 adddir(f[:s+1])
2181 else:
2182 addfile(f)
2183 return files, dirs
2184
2185 acceptable = ''
2186 if opts['normal']:
2187 acceptable += 'nm'
2188 if opts['added']:
2189 acceptable += 'a'
2190 if opts['removed']:
2191 acceptable += 'r'
2192 cwd = repo.getcwd()
2193 if not specs:
2194 specs = ['.']
2195
2196 files, dirs = set(), set()
2197 for spec in specs:
2198 f, d = complete(spec, acceptable or 'nmar')
2199 files.update(f)
2200 dirs.update(d)
2201 for d in dirs:
2202 files.add(d + 'a')
2203 files.add(d + 'b')
2204 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2205 ui.write('\n')
2206
2140 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2207 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2141 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2208 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2142 '''access the pushkey key/value protocol
2209 '''access the pushkey key/value protocol
2143
2210
2144 With two args, list the keys in the given namespace.
2211 With two args, list the keys in the given namespace.
2145
2212
2146 With five args, set a key to new if it currently is set to old.
2213 With five args, set a key to new if it currently is set to old.
2147 Reports success or failure.
2214 Reports success or failure.
2148 '''
2215 '''
2149
2216
2150 target = hg.peer(ui, {}, repopath)
2217 target = hg.peer(ui, {}, repopath)
2151 if keyinfo:
2218 if keyinfo:
2152 key, old, new = keyinfo
2219 key, old, new = keyinfo
2153 r = target.pushkey(namespace, key, old, new)
2220 r = target.pushkey(namespace, key, old, new)
2154 ui.status(str(r) + '\n')
2221 ui.status(str(r) + '\n')
2155 return not r
2222 return not r
2156 else:
2223 else:
2157 for k, v in sorted(target.listkeys(namespace).iteritems()):
2224 for k, v in sorted(target.listkeys(namespace).iteritems()):
2158 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2225 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2159 v.encode('string-escape')))
2226 v.encode('string-escape')))
2160
2227
2161 @command('debugpvec', [], _('A B'))
2228 @command('debugpvec', [], _('A B'))
2162 def debugpvec(ui, repo, a, b=None):
2229 def debugpvec(ui, repo, a, b=None):
2163 ca = scmutil.revsingle(repo, a)
2230 ca = scmutil.revsingle(repo, a)
2164 cb = scmutil.revsingle(repo, b)
2231 cb = scmutil.revsingle(repo, b)
2165 pa = pvec.ctxpvec(ca)
2232 pa = pvec.ctxpvec(ca)
2166 pb = pvec.ctxpvec(cb)
2233 pb = pvec.ctxpvec(cb)
2167 if pa == pb:
2234 if pa == pb:
2168 rel = "="
2235 rel = "="
2169 elif pa > pb:
2236 elif pa > pb:
2170 rel = ">"
2237 rel = ">"
2171 elif pa < pb:
2238 elif pa < pb:
2172 rel = "<"
2239 rel = "<"
2173 elif pa | pb:
2240 elif pa | pb:
2174 rel = "|"
2241 rel = "|"
2175 ui.write(_("a: %s\n") % pa)
2242 ui.write(_("a: %s\n") % pa)
2176 ui.write(_("b: %s\n") % pb)
2243 ui.write(_("b: %s\n") % pb)
2177 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2244 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2178 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2245 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2179 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2246 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2180 pa.distance(pb), rel))
2247 pa.distance(pb), rel))
2181
2248
2182 @command('debugrebuildstate',
2249 @command('debugrebuildstate',
2183 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2250 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2184 _('[-r REV] [REV]'))
2251 _('[-r REV] [REV]'))
2185 def debugrebuildstate(ui, repo, rev="tip"):
2252 def debugrebuildstate(ui, repo, rev="tip"):
2186 """rebuild the dirstate as it would look like for the given revision"""
2253 """rebuild the dirstate as it would look like for the given revision"""
2187 ctx = scmutil.revsingle(repo, rev)
2254 ctx = scmutil.revsingle(repo, rev)
2188 wlock = repo.wlock()
2255 wlock = repo.wlock()
2189 try:
2256 try:
2190 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2257 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2191 finally:
2258 finally:
2192 wlock.release()
2259 wlock.release()
2193
2260
2194 @command('debugrename',
2261 @command('debugrename',
2195 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2262 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2196 _('[-r REV] FILE'))
2263 _('[-r REV] FILE'))
2197 def debugrename(ui, repo, file1, *pats, **opts):
2264 def debugrename(ui, repo, file1, *pats, **opts):
2198 """dump rename information"""
2265 """dump rename information"""
2199
2266
2200 ctx = scmutil.revsingle(repo, opts.get('rev'))
2267 ctx = scmutil.revsingle(repo, opts.get('rev'))
2201 m = scmutil.match(ctx, (file1,) + pats, opts)
2268 m = scmutil.match(ctx, (file1,) + pats, opts)
2202 for abs in ctx.walk(m):
2269 for abs in ctx.walk(m):
2203 fctx = ctx[abs]
2270 fctx = ctx[abs]
2204 o = fctx.filelog().renamed(fctx.filenode())
2271 o = fctx.filelog().renamed(fctx.filenode())
2205 rel = m.rel(abs)
2272 rel = m.rel(abs)
2206 if o:
2273 if o:
2207 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2274 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2208 else:
2275 else:
2209 ui.write(_("%s not renamed\n") % rel)
2276 ui.write(_("%s not renamed\n") % rel)
2210
2277
2211 @command('debugrevlog',
2278 @command('debugrevlog',
2212 [('c', 'changelog', False, _('open changelog')),
2279 [('c', 'changelog', False, _('open changelog')),
2213 ('m', 'manifest', False, _('open manifest')),
2280 ('m', 'manifest', False, _('open manifest')),
2214 ('d', 'dump', False, _('dump index data'))],
2281 ('d', 'dump', False, _('dump index data'))],
2215 _('-c|-m|FILE'))
2282 _('-c|-m|FILE'))
2216 def debugrevlog(ui, repo, file_ = None, **opts):
2283 def debugrevlog(ui, repo, file_ = None, **opts):
2217 """show data and statistics about a revlog"""
2284 """show data and statistics about a revlog"""
2218 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2285 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2219
2286
2220 if opts.get("dump"):
2287 if opts.get("dump"):
2221 numrevs = len(r)
2288 numrevs = len(r)
2222 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2289 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2223 " rawsize totalsize compression heads\n")
2290 " rawsize totalsize compression heads\n")
2224 ts = 0
2291 ts = 0
2225 heads = set()
2292 heads = set()
2226 for rev in xrange(numrevs):
2293 for rev in xrange(numrevs):
2227 dbase = r.deltaparent(rev)
2294 dbase = r.deltaparent(rev)
2228 if dbase == -1:
2295 if dbase == -1:
2229 dbase = rev
2296 dbase = rev
2230 cbase = r.chainbase(rev)
2297 cbase = r.chainbase(rev)
2231 p1, p2 = r.parentrevs(rev)
2298 p1, p2 = r.parentrevs(rev)
2232 rs = r.rawsize(rev)
2299 rs = r.rawsize(rev)
2233 ts = ts + rs
2300 ts = ts + rs
2234 heads -= set(r.parentrevs(rev))
2301 heads -= set(r.parentrevs(rev))
2235 heads.add(rev)
2302 heads.add(rev)
2236 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2303 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2237 (rev, p1, p2, r.start(rev), r.end(rev),
2304 (rev, p1, p2, r.start(rev), r.end(rev),
2238 r.start(dbase), r.start(cbase),
2305 r.start(dbase), r.start(cbase),
2239 r.start(p1), r.start(p2),
2306 r.start(p1), r.start(p2),
2240 rs, ts, ts / r.end(rev), len(heads)))
2307 rs, ts, ts / r.end(rev), len(heads)))
2241 return 0
2308 return 0
2242
2309
2243 v = r.version
2310 v = r.version
2244 format = v & 0xFFFF
2311 format = v & 0xFFFF
2245 flags = []
2312 flags = []
2246 gdelta = False
2313 gdelta = False
2247 if v & revlog.REVLOGNGINLINEDATA:
2314 if v & revlog.REVLOGNGINLINEDATA:
2248 flags.append('inline')
2315 flags.append('inline')
2249 if v & revlog.REVLOGGENERALDELTA:
2316 if v & revlog.REVLOGGENERALDELTA:
2250 gdelta = True
2317 gdelta = True
2251 flags.append('generaldelta')
2318 flags.append('generaldelta')
2252 if not flags:
2319 if not flags:
2253 flags = ['(none)']
2320 flags = ['(none)']
2254
2321
2255 nummerges = 0
2322 nummerges = 0
2256 numfull = 0
2323 numfull = 0
2257 numprev = 0
2324 numprev = 0
2258 nump1 = 0
2325 nump1 = 0
2259 nump2 = 0
2326 nump2 = 0
2260 numother = 0
2327 numother = 0
2261 nump1prev = 0
2328 nump1prev = 0
2262 nump2prev = 0
2329 nump2prev = 0
2263 chainlengths = []
2330 chainlengths = []
2264
2331
2265 datasize = [None, 0, 0L]
2332 datasize = [None, 0, 0L]
2266 fullsize = [None, 0, 0L]
2333 fullsize = [None, 0, 0L]
2267 deltasize = [None, 0, 0L]
2334 deltasize = [None, 0, 0L]
2268
2335
2269 def addsize(size, l):
2336 def addsize(size, l):
2270 if l[0] is None or size < l[0]:
2337 if l[0] is None or size < l[0]:
2271 l[0] = size
2338 l[0] = size
2272 if size > l[1]:
2339 if size > l[1]:
2273 l[1] = size
2340 l[1] = size
2274 l[2] += size
2341 l[2] += size
2275
2342
2276 numrevs = len(r)
2343 numrevs = len(r)
2277 for rev in xrange(numrevs):
2344 for rev in xrange(numrevs):
2278 p1, p2 = r.parentrevs(rev)
2345 p1, p2 = r.parentrevs(rev)
2279 delta = r.deltaparent(rev)
2346 delta = r.deltaparent(rev)
2280 if format > 0:
2347 if format > 0:
2281 addsize(r.rawsize(rev), datasize)
2348 addsize(r.rawsize(rev), datasize)
2282 if p2 != nullrev:
2349 if p2 != nullrev:
2283 nummerges += 1
2350 nummerges += 1
2284 size = r.length(rev)
2351 size = r.length(rev)
2285 if delta == nullrev:
2352 if delta == nullrev:
2286 chainlengths.append(0)
2353 chainlengths.append(0)
2287 numfull += 1
2354 numfull += 1
2288 addsize(size, fullsize)
2355 addsize(size, fullsize)
2289 else:
2356 else:
2290 chainlengths.append(chainlengths[delta] + 1)
2357 chainlengths.append(chainlengths[delta] + 1)
2291 addsize(size, deltasize)
2358 addsize(size, deltasize)
2292 if delta == rev - 1:
2359 if delta == rev - 1:
2293 numprev += 1
2360 numprev += 1
2294 if delta == p1:
2361 if delta == p1:
2295 nump1prev += 1
2362 nump1prev += 1
2296 elif delta == p2:
2363 elif delta == p2:
2297 nump2prev += 1
2364 nump2prev += 1
2298 elif delta == p1:
2365 elif delta == p1:
2299 nump1 += 1
2366 nump1 += 1
2300 elif delta == p2:
2367 elif delta == p2:
2301 nump2 += 1
2368 nump2 += 1
2302 elif delta != nullrev:
2369 elif delta != nullrev:
2303 numother += 1
2370 numother += 1
2304
2371
2305 # Adjust size min value for empty cases
2372 # Adjust size min value for empty cases
2306 for size in (datasize, fullsize, deltasize):
2373 for size in (datasize, fullsize, deltasize):
2307 if size[0] is None:
2374 if size[0] is None:
2308 size[0] = 0
2375 size[0] = 0
2309
2376
2310 numdeltas = numrevs - numfull
2377 numdeltas = numrevs - numfull
2311 numoprev = numprev - nump1prev - nump2prev
2378 numoprev = numprev - nump1prev - nump2prev
2312 totalrawsize = datasize[2]
2379 totalrawsize = datasize[2]
2313 datasize[2] /= numrevs
2380 datasize[2] /= numrevs
2314 fulltotal = fullsize[2]
2381 fulltotal = fullsize[2]
2315 fullsize[2] /= numfull
2382 fullsize[2] /= numfull
2316 deltatotal = deltasize[2]
2383 deltatotal = deltasize[2]
2317 if numrevs - numfull > 0:
2384 if numrevs - numfull > 0:
2318 deltasize[2] /= numrevs - numfull
2385 deltasize[2] /= numrevs - numfull
2319 totalsize = fulltotal + deltatotal
2386 totalsize = fulltotal + deltatotal
2320 avgchainlen = sum(chainlengths) / numrevs
2387 avgchainlen = sum(chainlengths) / numrevs
2321 compratio = totalrawsize / totalsize
2388 compratio = totalrawsize / totalsize
2322
2389
2323 basedfmtstr = '%%%dd\n'
2390 basedfmtstr = '%%%dd\n'
2324 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2391 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2325
2392
2326 def dfmtstr(max):
2393 def dfmtstr(max):
2327 return basedfmtstr % len(str(max))
2394 return basedfmtstr % len(str(max))
2328 def pcfmtstr(max, padding=0):
2395 def pcfmtstr(max, padding=0):
2329 return basepcfmtstr % (len(str(max)), ' ' * padding)
2396 return basepcfmtstr % (len(str(max)), ' ' * padding)
2330
2397
2331 def pcfmt(value, total):
2398 def pcfmt(value, total):
2332 return (value, 100 * float(value) / total)
2399 return (value, 100 * float(value) / total)
2333
2400
2334 ui.write(('format : %d\n') % format)
2401 ui.write(('format : %d\n') % format)
2335 ui.write(('flags : %s\n') % ', '.join(flags))
2402 ui.write(('flags : %s\n') % ', '.join(flags))
2336
2403
2337 ui.write('\n')
2404 ui.write('\n')
2338 fmt = pcfmtstr(totalsize)
2405 fmt = pcfmtstr(totalsize)
2339 fmt2 = dfmtstr(totalsize)
2406 fmt2 = dfmtstr(totalsize)
2340 ui.write(('revisions : ') + fmt2 % numrevs)
2407 ui.write(('revisions : ') + fmt2 % numrevs)
2341 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2408 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2342 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2409 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2343 ui.write(('revisions : ') + fmt2 % numrevs)
2410 ui.write(('revisions : ') + fmt2 % numrevs)
2344 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2411 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2345 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2412 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2346 ui.write(('revision size : ') + fmt2 % totalsize)
2413 ui.write(('revision size : ') + fmt2 % totalsize)
2347 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2414 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2348 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2415 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2349
2416
2350 ui.write('\n')
2417 ui.write('\n')
2351 fmt = dfmtstr(max(avgchainlen, compratio))
2418 fmt = dfmtstr(max(avgchainlen, compratio))
2352 ui.write(('avg chain length : ') + fmt % avgchainlen)
2419 ui.write(('avg chain length : ') + fmt % avgchainlen)
2353 ui.write(('compression ratio : ') + fmt % compratio)
2420 ui.write(('compression ratio : ') + fmt % compratio)
2354
2421
2355 if format > 0:
2422 if format > 0:
2356 ui.write('\n')
2423 ui.write('\n')
2357 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2424 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2358 % tuple(datasize))
2425 % tuple(datasize))
2359 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2426 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2360 % tuple(fullsize))
2427 % tuple(fullsize))
2361 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2428 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2362 % tuple(deltasize))
2429 % tuple(deltasize))
2363
2430
2364 if numdeltas > 0:
2431 if numdeltas > 0:
2365 ui.write('\n')
2432 ui.write('\n')
2366 fmt = pcfmtstr(numdeltas)
2433 fmt = pcfmtstr(numdeltas)
2367 fmt2 = pcfmtstr(numdeltas, 4)
2434 fmt2 = pcfmtstr(numdeltas, 4)
2368 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2435 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2369 if numprev > 0:
2436 if numprev > 0:
2370 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2437 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2371 numprev))
2438 numprev))
2372 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2439 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2373 numprev))
2440 numprev))
2374 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2441 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2375 numprev))
2442 numprev))
2376 if gdelta:
2443 if gdelta:
2377 ui.write(('deltas against p1 : ')
2444 ui.write(('deltas against p1 : ')
2378 + fmt % pcfmt(nump1, numdeltas))
2445 + fmt % pcfmt(nump1, numdeltas))
2379 ui.write(('deltas against p2 : ')
2446 ui.write(('deltas against p2 : ')
2380 + fmt % pcfmt(nump2, numdeltas))
2447 + fmt % pcfmt(nump2, numdeltas))
2381 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2448 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2382 numdeltas))
2449 numdeltas))
2383
2450
2384 @command('debugrevspec', [], ('REVSPEC'))
2451 @command('debugrevspec', [], ('REVSPEC'))
2385 def debugrevspec(ui, repo, expr):
2452 def debugrevspec(ui, repo, expr):
2386 """parse and apply a revision specification
2453 """parse and apply a revision specification
2387
2454
2388 Use --verbose to print the parsed tree before and after aliases
2455 Use --verbose to print the parsed tree before and after aliases
2389 expansion.
2456 expansion.
2390 """
2457 """
2391 if ui.verbose:
2458 if ui.verbose:
2392 tree = revset.parse(expr)[0]
2459 tree = revset.parse(expr)[0]
2393 ui.note(revset.prettyformat(tree), "\n")
2460 ui.note(revset.prettyformat(tree), "\n")
2394 newtree = revset.findaliases(ui, tree)
2461 newtree = revset.findaliases(ui, tree)
2395 if newtree != tree:
2462 if newtree != tree:
2396 ui.note(revset.prettyformat(newtree), "\n")
2463 ui.note(revset.prettyformat(newtree), "\n")
2397 func = revset.match(ui, expr)
2464 func = revset.match(ui, expr)
2398 for c in func(repo, range(len(repo))):
2465 for c in func(repo, range(len(repo))):
2399 ui.write("%s\n" % c)
2466 ui.write("%s\n" % c)
2400
2467
2401 @command('debugsetparents', [], _('REV1 [REV2]'))
2468 @command('debugsetparents', [], _('REV1 [REV2]'))
2402 def debugsetparents(ui, repo, rev1, rev2=None):
2469 def debugsetparents(ui, repo, rev1, rev2=None):
2403 """manually set the parents of the current working directory
2470 """manually set the parents of the current working directory
2404
2471
2405 This is useful for writing repository conversion tools, but should
2472 This is useful for writing repository conversion tools, but should
2406 be used with care.
2473 be used with care.
2407
2474
2408 Returns 0 on success.
2475 Returns 0 on success.
2409 """
2476 """
2410
2477
2411 r1 = scmutil.revsingle(repo, rev1).node()
2478 r1 = scmutil.revsingle(repo, rev1).node()
2412 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2479 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2413
2480
2414 wlock = repo.wlock()
2481 wlock = repo.wlock()
2415 try:
2482 try:
2416 repo.setparents(r1, r2)
2483 repo.setparents(r1, r2)
2417 finally:
2484 finally:
2418 wlock.release()
2485 wlock.release()
2419
2486
2420 @command('debugstate',
2487 @command('debugstate',
2421 [('', 'nodates', None, _('do not display the saved mtime')),
2488 [('', 'nodates', None, _('do not display the saved mtime')),
2422 ('', 'datesort', None, _('sort by saved mtime'))],
2489 ('', 'datesort', None, _('sort by saved mtime'))],
2423 _('[OPTION]...'))
2490 _('[OPTION]...'))
2424 def debugstate(ui, repo, nodates=None, datesort=None):
2491 def debugstate(ui, repo, nodates=None, datesort=None):
2425 """show the contents of the current dirstate"""
2492 """show the contents of the current dirstate"""
2426 timestr = ""
2493 timestr = ""
2427 showdate = not nodates
2494 showdate = not nodates
2428 if datesort:
2495 if datesort:
2429 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2496 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2430 else:
2497 else:
2431 keyfunc = None # sort by filename
2498 keyfunc = None # sort by filename
2432 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2499 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2433 if showdate:
2500 if showdate:
2434 if ent[3] == -1:
2501 if ent[3] == -1:
2435 # Pad or slice to locale representation
2502 # Pad or slice to locale representation
2436 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2503 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2437 time.localtime(0)))
2504 time.localtime(0)))
2438 timestr = 'unset'
2505 timestr = 'unset'
2439 timestr = (timestr[:locale_len] +
2506 timestr = (timestr[:locale_len] +
2440 ' ' * (locale_len - len(timestr)))
2507 ' ' * (locale_len - len(timestr)))
2441 else:
2508 else:
2442 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2509 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2443 time.localtime(ent[3]))
2510 time.localtime(ent[3]))
2444 if ent[1] & 020000:
2511 if ent[1] & 020000:
2445 mode = 'lnk'
2512 mode = 'lnk'
2446 else:
2513 else:
2447 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2514 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2448 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2515 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2449 for f in repo.dirstate.copies():
2516 for f in repo.dirstate.copies():
2450 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2517 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2451
2518
2452 @command('debugsub',
2519 @command('debugsub',
2453 [('r', 'rev', '',
2520 [('r', 'rev', '',
2454 _('revision to check'), _('REV'))],
2521 _('revision to check'), _('REV'))],
2455 _('[-r REV] [REV]'))
2522 _('[-r REV] [REV]'))
2456 def debugsub(ui, repo, rev=None):
2523 def debugsub(ui, repo, rev=None):
2457 ctx = scmutil.revsingle(repo, rev, None)
2524 ctx = scmutil.revsingle(repo, rev, None)
2458 for k, v in sorted(ctx.substate.items()):
2525 for k, v in sorted(ctx.substate.items()):
2459 ui.write(('path %s\n') % k)
2526 ui.write(('path %s\n') % k)
2460 ui.write((' source %s\n') % v[0])
2527 ui.write((' source %s\n') % v[0])
2461 ui.write((' revision %s\n') % v[1])
2528 ui.write((' revision %s\n') % v[1])
2462
2529
2463 @command('debugsuccessorssets',
2530 @command('debugsuccessorssets',
2464 [],
2531 [],
2465 _('[REV]'))
2532 _('[REV]'))
2466 def debugsuccessorssets(ui, repo, *revs):
2533 def debugsuccessorssets(ui, repo, *revs):
2467 """show set of successors for revision
2534 """show set of successors for revision
2468
2535
2469 A successors set of changeset A is a consistent group of revisions that
2536 A successors set of changeset A is a consistent group of revisions that
2470 succeed A. It contains non-obsolete changesets only.
2537 succeed A. It contains non-obsolete changesets only.
2471
2538
2472 In most cases a changeset A has a single successors set containing a single
2539 In most cases a changeset A has a single successors set containing a single
2473 successor (changeset A replaced by A').
2540 successor (changeset A replaced by A').
2474
2541
2475 A changeset that is made obsolete with no successors are called "pruned".
2542 A changeset that is made obsolete with no successors are called "pruned".
2476 Such changesets have no successors sets at all.
2543 Such changesets have no successors sets at all.
2477
2544
2478 A changeset that has been "split" will have a successors set containing
2545 A changeset that has been "split" will have a successors set containing
2479 more than one successor.
2546 more than one successor.
2480
2547
2481 A changeset that has been rewritten in multiple different ways is called
2548 A changeset that has been rewritten in multiple different ways is called
2482 "divergent". Such changesets have multiple successor sets (each of which
2549 "divergent". Such changesets have multiple successor sets (each of which
2483 may also be split, i.e. have multiple successors).
2550 may also be split, i.e. have multiple successors).
2484
2551
2485 Results are displayed as follows::
2552 Results are displayed as follows::
2486
2553
2487 <rev1>
2554 <rev1>
2488 <successors-1A>
2555 <successors-1A>
2489 <rev2>
2556 <rev2>
2490 <successors-2A>
2557 <successors-2A>
2491 <successors-2B1> <successors-2B2> <successors-2B3>
2558 <successors-2B1> <successors-2B2> <successors-2B3>
2492
2559
2493 Here rev2 has two possible (i.e. divergent) successors sets. The first
2560 Here rev2 has two possible (i.e. divergent) successors sets. The first
2494 holds one element, whereas the second holds three (i.e. the changeset has
2561 holds one element, whereas the second holds three (i.e. the changeset has
2495 been split).
2562 been split).
2496 """
2563 """
2497 # passed to successorssets caching computation from one call to another
2564 # passed to successorssets caching computation from one call to another
2498 cache = {}
2565 cache = {}
2499 ctx2str = str
2566 ctx2str = str
2500 node2str = short
2567 node2str = short
2501 if ui.debug():
2568 if ui.debug():
2502 def ctx2str(ctx):
2569 def ctx2str(ctx):
2503 return ctx.hex()
2570 return ctx.hex()
2504 node2str = hex
2571 node2str = hex
2505 for rev in scmutil.revrange(repo, revs):
2572 for rev in scmutil.revrange(repo, revs):
2506 ctx = repo[rev]
2573 ctx = repo[rev]
2507 ui.write('%s\n'% ctx2str(ctx))
2574 ui.write('%s\n'% ctx2str(ctx))
2508 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2575 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2509 if succsset:
2576 if succsset:
2510 ui.write(' ')
2577 ui.write(' ')
2511 ui.write(node2str(succsset[0]))
2578 ui.write(node2str(succsset[0]))
2512 for node in succsset[1:]:
2579 for node in succsset[1:]:
2513 ui.write(' ')
2580 ui.write(' ')
2514 ui.write(node2str(node))
2581 ui.write(node2str(node))
2515 ui.write('\n')
2582 ui.write('\n')
2516
2583
2517 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2584 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2518 def debugwalk(ui, repo, *pats, **opts):
2585 def debugwalk(ui, repo, *pats, **opts):
2519 """show how files match on given patterns"""
2586 """show how files match on given patterns"""
2520 m = scmutil.match(repo[None], pats, opts)
2587 m = scmutil.match(repo[None], pats, opts)
2521 items = list(repo.walk(m))
2588 items = list(repo.walk(m))
2522 if not items:
2589 if not items:
2523 return
2590 return
2524 f = lambda fn: fn
2591 f = lambda fn: fn
2525 if ui.configbool('ui', 'slash') and os.sep != '/':
2592 if ui.configbool('ui', 'slash') and os.sep != '/':
2526 f = lambda fn: util.normpath(fn)
2593 f = lambda fn: util.normpath(fn)
2527 fmt = 'f %%-%ds %%-%ds %%s' % (
2594 fmt = 'f %%-%ds %%-%ds %%s' % (
2528 max([len(abs) for abs in items]),
2595 max([len(abs) for abs in items]),
2529 max([len(m.rel(abs)) for abs in items]))
2596 max([len(m.rel(abs)) for abs in items]))
2530 for abs in items:
2597 for abs in items:
2531 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2598 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2532 ui.write("%s\n" % line.rstrip())
2599 ui.write("%s\n" % line.rstrip())
2533
2600
2534 @command('debugwireargs',
2601 @command('debugwireargs',
2535 [('', 'three', '', 'three'),
2602 [('', 'three', '', 'three'),
2536 ('', 'four', '', 'four'),
2603 ('', 'four', '', 'four'),
2537 ('', 'five', '', 'five'),
2604 ('', 'five', '', 'five'),
2538 ] + remoteopts,
2605 ] + remoteopts,
2539 _('REPO [OPTIONS]... [ONE [TWO]]'))
2606 _('REPO [OPTIONS]... [ONE [TWO]]'))
2540 def debugwireargs(ui, repopath, *vals, **opts):
2607 def debugwireargs(ui, repopath, *vals, **opts):
2541 repo = hg.peer(ui, opts, repopath)
2608 repo = hg.peer(ui, opts, repopath)
2542 for opt in remoteopts:
2609 for opt in remoteopts:
2543 del opts[opt[1]]
2610 del opts[opt[1]]
2544 args = {}
2611 args = {}
2545 for k, v in opts.iteritems():
2612 for k, v in opts.iteritems():
2546 if v:
2613 if v:
2547 args[k] = v
2614 args[k] = v
2548 # run twice to check that we don't mess up the stream for the next command
2615 # run twice to check that we don't mess up the stream for the next command
2549 res1 = repo.debugwireargs(*vals, **args)
2616 res1 = repo.debugwireargs(*vals, **args)
2550 res2 = repo.debugwireargs(*vals, **args)
2617 res2 = repo.debugwireargs(*vals, **args)
2551 ui.write("%s\n" % res1)
2618 ui.write("%s\n" % res1)
2552 if res1 != res2:
2619 if res1 != res2:
2553 ui.warn("%s\n" % res2)
2620 ui.warn("%s\n" % res2)
2554
2621
2555 @command('^diff',
2622 @command('^diff',
2556 [('r', 'rev', [], _('revision'), _('REV')),
2623 [('r', 'rev', [], _('revision'), _('REV')),
2557 ('c', 'change', '', _('change made by revision'), _('REV'))
2624 ('c', 'change', '', _('change made by revision'), _('REV'))
2558 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2625 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2559 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2626 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2560 def diff(ui, repo, *pats, **opts):
2627 def diff(ui, repo, *pats, **opts):
2561 """diff repository (or selected files)
2628 """diff repository (or selected files)
2562
2629
2563 Show differences between revisions for the specified files.
2630 Show differences between revisions for the specified files.
2564
2631
2565 Differences between files are shown using the unified diff format.
2632 Differences between files are shown using the unified diff format.
2566
2633
2567 .. note::
2634 .. note::
2568 diff may generate unexpected results for merges, as it will
2635 diff may generate unexpected results for merges, as it will
2569 default to comparing against the working directory's first
2636 default to comparing against the working directory's first
2570 parent changeset if no revisions are specified.
2637 parent changeset if no revisions are specified.
2571
2638
2572 When two revision arguments are given, then changes are shown
2639 When two revision arguments are given, then changes are shown
2573 between those revisions. If only one revision is specified then
2640 between those revisions. If only one revision is specified then
2574 that revision is compared to the working directory, and, when no
2641 that revision is compared to the working directory, and, when no
2575 revisions are specified, the working directory files are compared
2642 revisions are specified, the working directory files are compared
2576 to its parent.
2643 to its parent.
2577
2644
2578 Alternatively you can specify -c/--change with a revision to see
2645 Alternatively you can specify -c/--change with a revision to see
2579 the changes in that changeset relative to its first parent.
2646 the changes in that changeset relative to its first parent.
2580
2647
2581 Without the -a/--text option, diff will avoid generating diffs of
2648 Without the -a/--text option, diff will avoid generating diffs of
2582 files it detects as binary. With -a, diff will generate a diff
2649 files it detects as binary. With -a, diff will generate a diff
2583 anyway, probably with undesirable results.
2650 anyway, probably with undesirable results.
2584
2651
2585 Use the -g/--git option to generate diffs in the git extended diff
2652 Use the -g/--git option to generate diffs in the git extended diff
2586 format. For more information, read :hg:`help diffs`.
2653 format. For more information, read :hg:`help diffs`.
2587
2654
2588 .. container:: verbose
2655 .. container:: verbose
2589
2656
2590 Examples:
2657 Examples:
2591
2658
2592 - compare a file in the current working directory to its parent::
2659 - compare a file in the current working directory to its parent::
2593
2660
2594 hg diff foo.c
2661 hg diff foo.c
2595
2662
2596 - compare two historical versions of a directory, with rename info::
2663 - compare two historical versions of a directory, with rename info::
2597
2664
2598 hg diff --git -r 1.0:1.2 lib/
2665 hg diff --git -r 1.0:1.2 lib/
2599
2666
2600 - get change stats relative to the last change on some date::
2667 - get change stats relative to the last change on some date::
2601
2668
2602 hg diff --stat -r "date('may 2')"
2669 hg diff --stat -r "date('may 2')"
2603
2670
2604 - diff all newly-added files that contain a keyword::
2671 - diff all newly-added files that contain a keyword::
2605
2672
2606 hg diff "set:added() and grep(GNU)"
2673 hg diff "set:added() and grep(GNU)"
2607
2674
2608 - compare a revision and its parents::
2675 - compare a revision and its parents::
2609
2676
2610 hg diff -c 9353 # compare against first parent
2677 hg diff -c 9353 # compare against first parent
2611 hg diff -r 9353^:9353 # same using revset syntax
2678 hg diff -r 9353^:9353 # same using revset syntax
2612 hg diff -r 9353^2:9353 # compare against the second parent
2679 hg diff -r 9353^2:9353 # compare against the second parent
2613
2680
2614 Returns 0 on success.
2681 Returns 0 on success.
2615 """
2682 """
2616
2683
2617 revs = opts.get('rev')
2684 revs = opts.get('rev')
2618 change = opts.get('change')
2685 change = opts.get('change')
2619 stat = opts.get('stat')
2686 stat = opts.get('stat')
2620 reverse = opts.get('reverse')
2687 reverse = opts.get('reverse')
2621
2688
2622 if revs and change:
2689 if revs and change:
2623 msg = _('cannot specify --rev and --change at the same time')
2690 msg = _('cannot specify --rev and --change at the same time')
2624 raise util.Abort(msg)
2691 raise util.Abort(msg)
2625 elif change:
2692 elif change:
2626 node2 = scmutil.revsingle(repo, change, None).node()
2693 node2 = scmutil.revsingle(repo, change, None).node()
2627 node1 = repo[node2].p1().node()
2694 node1 = repo[node2].p1().node()
2628 else:
2695 else:
2629 node1, node2 = scmutil.revpair(repo, revs)
2696 node1, node2 = scmutil.revpair(repo, revs)
2630
2697
2631 if reverse:
2698 if reverse:
2632 node1, node2 = node2, node1
2699 node1, node2 = node2, node1
2633
2700
2634 diffopts = patch.diffopts(ui, opts)
2701 diffopts = patch.diffopts(ui, opts)
2635 m = scmutil.match(repo[node2], pats, opts)
2702 m = scmutil.match(repo[node2], pats, opts)
2636 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2703 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2637 listsubrepos=opts.get('subrepos'))
2704 listsubrepos=opts.get('subrepos'))
2638
2705
2639 @command('^export',
2706 @command('^export',
2640 [('o', 'output', '',
2707 [('o', 'output', '',
2641 _('print output to file with formatted name'), _('FORMAT')),
2708 _('print output to file with formatted name'), _('FORMAT')),
2642 ('', 'switch-parent', None, _('diff against the second parent')),
2709 ('', 'switch-parent', None, _('diff against the second parent')),
2643 ('r', 'rev', [], _('revisions to export'), _('REV')),
2710 ('r', 'rev', [], _('revisions to export'), _('REV')),
2644 ] + diffopts,
2711 ] + diffopts,
2645 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2712 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2646 def export(ui, repo, *changesets, **opts):
2713 def export(ui, repo, *changesets, **opts):
2647 """dump the header and diffs for one or more changesets
2714 """dump the header and diffs for one or more changesets
2648
2715
2649 Print the changeset header and diffs for one or more revisions.
2716 Print the changeset header and diffs for one or more revisions.
2650
2717
2651 The information shown in the changeset header is: author, date,
2718 The information shown in the changeset header is: author, date,
2652 branch name (if non-default), changeset hash, parent(s) and commit
2719 branch name (if non-default), changeset hash, parent(s) and commit
2653 comment.
2720 comment.
2654
2721
2655 .. note::
2722 .. note::
2656 export may generate unexpected diff output for merge
2723 export may generate unexpected diff output for merge
2657 changesets, as it will compare the merge changeset against its
2724 changesets, as it will compare the merge changeset against its
2658 first parent only.
2725 first parent only.
2659
2726
2660 Output may be to a file, in which case the name of the file is
2727 Output may be to a file, in which case the name of the file is
2661 given using a format string. The formatting rules are as follows:
2728 given using a format string. The formatting rules are as follows:
2662
2729
2663 :``%%``: literal "%" character
2730 :``%%``: literal "%" character
2664 :``%H``: changeset hash (40 hexadecimal digits)
2731 :``%H``: changeset hash (40 hexadecimal digits)
2665 :``%N``: number of patches being generated
2732 :``%N``: number of patches being generated
2666 :``%R``: changeset revision number
2733 :``%R``: changeset revision number
2667 :``%b``: basename of the exporting repository
2734 :``%b``: basename of the exporting repository
2668 :``%h``: short-form changeset hash (12 hexadecimal digits)
2735 :``%h``: short-form changeset hash (12 hexadecimal digits)
2669 :``%m``: first line of the commit message (only alphanumeric characters)
2736 :``%m``: first line of the commit message (only alphanumeric characters)
2670 :``%n``: zero-padded sequence number, starting at 1
2737 :``%n``: zero-padded sequence number, starting at 1
2671 :``%r``: zero-padded changeset revision number
2738 :``%r``: zero-padded changeset revision number
2672
2739
2673 Without the -a/--text option, export will avoid generating diffs
2740 Without the -a/--text option, export will avoid generating diffs
2674 of files it detects as binary. With -a, export will generate a
2741 of files it detects as binary. With -a, export will generate a
2675 diff anyway, probably with undesirable results.
2742 diff anyway, probably with undesirable results.
2676
2743
2677 Use the -g/--git option to generate diffs in the git extended diff
2744 Use the -g/--git option to generate diffs in the git extended diff
2678 format. See :hg:`help diffs` for more information.
2745 format. See :hg:`help diffs` for more information.
2679
2746
2680 With the --switch-parent option, the diff will be against the
2747 With the --switch-parent option, the diff will be against the
2681 second parent. It can be useful to review a merge.
2748 second parent. It can be useful to review a merge.
2682
2749
2683 .. container:: verbose
2750 .. container:: verbose
2684
2751
2685 Examples:
2752 Examples:
2686
2753
2687 - use export and import to transplant a bugfix to the current
2754 - use export and import to transplant a bugfix to the current
2688 branch::
2755 branch::
2689
2756
2690 hg export -r 9353 | hg import -
2757 hg export -r 9353 | hg import -
2691
2758
2692 - export all the changesets between two revisions to a file with
2759 - export all the changesets between two revisions to a file with
2693 rename information::
2760 rename information::
2694
2761
2695 hg export --git -r 123:150 > changes.txt
2762 hg export --git -r 123:150 > changes.txt
2696
2763
2697 - split outgoing changes into a series of patches with
2764 - split outgoing changes into a series of patches with
2698 descriptive names::
2765 descriptive names::
2699
2766
2700 hg export -r "outgoing()" -o "%n-%m.patch"
2767 hg export -r "outgoing()" -o "%n-%m.patch"
2701
2768
2702 Returns 0 on success.
2769 Returns 0 on success.
2703 """
2770 """
2704 changesets += tuple(opts.get('rev', []))
2771 changesets += tuple(opts.get('rev', []))
2705 revs = scmutil.revrange(repo, changesets)
2772 revs = scmutil.revrange(repo, changesets)
2706 if not revs:
2773 if not revs:
2707 raise util.Abort(_("export requires at least one changeset"))
2774 raise util.Abort(_("export requires at least one changeset"))
2708 if len(revs) > 1:
2775 if len(revs) > 1:
2709 ui.note(_('exporting patches:\n'))
2776 ui.note(_('exporting patches:\n'))
2710 else:
2777 else:
2711 ui.note(_('exporting patch:\n'))
2778 ui.note(_('exporting patch:\n'))
2712 cmdutil.export(repo, revs, template=opts.get('output'),
2779 cmdutil.export(repo, revs, template=opts.get('output'),
2713 switch_parent=opts.get('switch_parent'),
2780 switch_parent=opts.get('switch_parent'),
2714 opts=patch.diffopts(ui, opts))
2781 opts=patch.diffopts(ui, opts))
2715
2782
2716 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2783 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2717 def forget(ui, repo, *pats, **opts):
2784 def forget(ui, repo, *pats, **opts):
2718 """forget the specified files on the next commit
2785 """forget the specified files on the next commit
2719
2786
2720 Mark the specified files so they will no longer be tracked
2787 Mark the specified files so they will no longer be tracked
2721 after the next commit.
2788 after the next commit.
2722
2789
2723 This only removes files from the current branch, not from the
2790 This only removes files from the current branch, not from the
2724 entire project history, and it does not delete them from the
2791 entire project history, and it does not delete them from the
2725 working directory.
2792 working directory.
2726
2793
2727 To undo a forget before the next commit, see :hg:`add`.
2794 To undo a forget before the next commit, see :hg:`add`.
2728
2795
2729 .. container:: verbose
2796 .. container:: verbose
2730
2797
2731 Examples:
2798 Examples:
2732
2799
2733 - forget newly-added binary files::
2800 - forget newly-added binary files::
2734
2801
2735 hg forget "set:added() and binary()"
2802 hg forget "set:added() and binary()"
2736
2803
2737 - forget files that would be excluded by .hgignore::
2804 - forget files that would be excluded by .hgignore::
2738
2805
2739 hg forget "set:hgignore()"
2806 hg forget "set:hgignore()"
2740
2807
2741 Returns 0 on success.
2808 Returns 0 on success.
2742 """
2809 """
2743
2810
2744 if not pats:
2811 if not pats:
2745 raise util.Abort(_('no files specified'))
2812 raise util.Abort(_('no files specified'))
2746
2813
2747 m = scmutil.match(repo[None], pats, opts)
2814 m = scmutil.match(repo[None], pats, opts)
2748 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2815 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2749 return rejected and 1 or 0
2816 return rejected and 1 or 0
2750
2817
2751 @command(
2818 @command(
2752 'graft',
2819 'graft',
2753 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2820 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2754 ('c', 'continue', False, _('resume interrupted graft')),
2821 ('c', 'continue', False, _('resume interrupted graft')),
2755 ('e', 'edit', False, _('invoke editor on commit messages')),
2822 ('e', 'edit', False, _('invoke editor on commit messages')),
2756 ('', 'log', None, _('append graft info to log message')),
2823 ('', 'log', None, _('append graft info to log message')),
2757 ('D', 'currentdate', False,
2824 ('D', 'currentdate', False,
2758 _('record the current date as commit date')),
2825 _('record the current date as commit date')),
2759 ('U', 'currentuser', False,
2826 ('U', 'currentuser', False,
2760 _('record the current user as committer'), _('DATE'))]
2827 _('record the current user as committer'), _('DATE'))]
2761 + commitopts2 + mergetoolopts + dryrunopts,
2828 + commitopts2 + mergetoolopts + dryrunopts,
2762 _('[OPTION]... [-r] REV...'))
2829 _('[OPTION]... [-r] REV...'))
2763 def graft(ui, repo, *revs, **opts):
2830 def graft(ui, repo, *revs, **opts):
2764 '''copy changes from other branches onto the current branch
2831 '''copy changes from other branches onto the current branch
2765
2832
2766 This command uses Mercurial's merge logic to copy individual
2833 This command uses Mercurial's merge logic to copy individual
2767 changes from other branches without merging branches in the
2834 changes from other branches without merging branches in the
2768 history graph. This is sometimes known as 'backporting' or
2835 history graph. This is sometimes known as 'backporting' or
2769 'cherry-picking'. By default, graft will copy user, date, and
2836 'cherry-picking'. By default, graft will copy user, date, and
2770 description from the source changesets.
2837 description from the source changesets.
2771
2838
2772 Changesets that are ancestors of the current revision, that have
2839 Changesets that are ancestors of the current revision, that have
2773 already been grafted, or that are merges will be skipped.
2840 already been grafted, or that are merges will be skipped.
2774
2841
2775 If --log is specified, log messages will have a comment appended
2842 If --log is specified, log messages will have a comment appended
2776 of the form::
2843 of the form::
2777
2844
2778 (grafted from CHANGESETHASH)
2845 (grafted from CHANGESETHASH)
2779
2846
2780 If a graft merge results in conflicts, the graft process is
2847 If a graft merge results in conflicts, the graft process is
2781 interrupted so that the current merge can be manually resolved.
2848 interrupted so that the current merge can be manually resolved.
2782 Once all conflicts are addressed, the graft process can be
2849 Once all conflicts are addressed, the graft process can be
2783 continued with the -c/--continue option.
2850 continued with the -c/--continue option.
2784
2851
2785 .. note::
2852 .. note::
2786 The -c/--continue option does not reapply earlier options.
2853 The -c/--continue option does not reapply earlier options.
2787
2854
2788 .. container:: verbose
2855 .. container:: verbose
2789
2856
2790 Examples:
2857 Examples:
2791
2858
2792 - copy a single change to the stable branch and edit its description::
2859 - copy a single change to the stable branch and edit its description::
2793
2860
2794 hg update stable
2861 hg update stable
2795 hg graft --edit 9393
2862 hg graft --edit 9393
2796
2863
2797 - graft a range of changesets with one exception, updating dates::
2864 - graft a range of changesets with one exception, updating dates::
2798
2865
2799 hg graft -D "2085::2093 and not 2091"
2866 hg graft -D "2085::2093 and not 2091"
2800
2867
2801 - continue a graft after resolving conflicts::
2868 - continue a graft after resolving conflicts::
2802
2869
2803 hg graft -c
2870 hg graft -c
2804
2871
2805 - show the source of a grafted changeset::
2872 - show the source of a grafted changeset::
2806
2873
2807 hg log --debug -r tip
2874 hg log --debug -r tip
2808
2875
2809 Returns 0 on successful completion.
2876 Returns 0 on successful completion.
2810 '''
2877 '''
2811
2878
2812 revs = list(revs)
2879 revs = list(revs)
2813 revs.extend(opts['rev'])
2880 revs.extend(opts['rev'])
2814
2881
2815 if not opts.get('user') and opts.get('currentuser'):
2882 if not opts.get('user') and opts.get('currentuser'):
2816 opts['user'] = ui.username()
2883 opts['user'] = ui.username()
2817 if not opts.get('date') and opts.get('currentdate'):
2884 if not opts.get('date') and opts.get('currentdate'):
2818 opts['date'] = "%d %d" % util.makedate()
2885 opts['date'] = "%d %d" % util.makedate()
2819
2886
2820 editor = None
2887 editor = None
2821 if opts.get('edit'):
2888 if opts.get('edit'):
2822 editor = cmdutil.commitforceeditor
2889 editor = cmdutil.commitforceeditor
2823
2890
2824 cont = False
2891 cont = False
2825 if opts['continue']:
2892 if opts['continue']:
2826 cont = True
2893 cont = True
2827 if revs:
2894 if revs:
2828 raise util.Abort(_("can't specify --continue and revisions"))
2895 raise util.Abort(_("can't specify --continue and revisions"))
2829 # read in unfinished revisions
2896 # read in unfinished revisions
2830 try:
2897 try:
2831 nodes = repo.opener.read('graftstate').splitlines()
2898 nodes = repo.opener.read('graftstate').splitlines()
2832 revs = [repo[node].rev() for node in nodes]
2899 revs = [repo[node].rev() for node in nodes]
2833 except IOError, inst:
2900 except IOError, inst:
2834 if inst.errno != errno.ENOENT:
2901 if inst.errno != errno.ENOENT:
2835 raise
2902 raise
2836 raise util.Abort(_("no graft state found, can't continue"))
2903 raise util.Abort(_("no graft state found, can't continue"))
2837 else:
2904 else:
2838 cmdutil.bailifchanged(repo)
2905 cmdutil.bailifchanged(repo)
2839 if not revs:
2906 if not revs:
2840 raise util.Abort(_('no revisions specified'))
2907 raise util.Abort(_('no revisions specified'))
2841 revs = scmutil.revrange(repo, revs)
2908 revs = scmutil.revrange(repo, revs)
2842
2909
2843 # check for merges
2910 # check for merges
2844 for rev in repo.revs('%ld and merge()', revs):
2911 for rev in repo.revs('%ld and merge()', revs):
2845 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2912 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2846 revs.remove(rev)
2913 revs.remove(rev)
2847 if not revs:
2914 if not revs:
2848 return -1
2915 return -1
2849
2916
2850 # check for ancestors of dest branch
2917 # check for ancestors of dest branch
2851 for rev in repo.revs('::. and %ld', revs):
2918 for rev in repo.revs('::. and %ld', revs):
2852 ui.warn(_('skipping ancestor revision %s\n') % rev)
2919 ui.warn(_('skipping ancestor revision %s\n') % rev)
2853 revs.remove(rev)
2920 revs.remove(rev)
2854 if not revs:
2921 if not revs:
2855 return -1
2922 return -1
2856
2923
2857 # analyze revs for earlier grafts
2924 # analyze revs for earlier grafts
2858 ids = {}
2925 ids = {}
2859 for ctx in repo.set("%ld", revs):
2926 for ctx in repo.set("%ld", revs):
2860 ids[ctx.hex()] = ctx.rev()
2927 ids[ctx.hex()] = ctx.rev()
2861 n = ctx.extra().get('source')
2928 n = ctx.extra().get('source')
2862 if n:
2929 if n:
2863 ids[n] = ctx.rev()
2930 ids[n] = ctx.rev()
2864
2931
2865 # check ancestors for earlier grafts
2932 # check ancestors for earlier grafts
2866 ui.debug('scanning for duplicate grafts\n')
2933 ui.debug('scanning for duplicate grafts\n')
2867 for ctx in repo.set("::. - ::%ld", revs):
2934 for ctx in repo.set("::. - ::%ld", revs):
2868 n = ctx.extra().get('source')
2935 n = ctx.extra().get('source')
2869 if n in ids:
2936 if n in ids:
2870 r = repo[n].rev()
2937 r = repo[n].rev()
2871 if r in revs:
2938 if r in revs:
2872 ui.warn(_('skipping already grafted revision %s\n') % r)
2939 ui.warn(_('skipping already grafted revision %s\n') % r)
2873 revs.remove(r)
2940 revs.remove(r)
2874 elif ids[n] in revs:
2941 elif ids[n] in revs:
2875 ui.warn(_('skipping already grafted revision %s '
2942 ui.warn(_('skipping already grafted revision %s '
2876 '(same origin %d)\n') % (ids[n], r))
2943 '(same origin %d)\n') % (ids[n], r))
2877 revs.remove(ids[n])
2944 revs.remove(ids[n])
2878 elif ctx.hex() in ids:
2945 elif ctx.hex() in ids:
2879 r = ids[ctx.hex()]
2946 r = ids[ctx.hex()]
2880 ui.warn(_('skipping already grafted revision %s '
2947 ui.warn(_('skipping already grafted revision %s '
2881 '(was grafted from %d)\n') % (r, ctx.rev()))
2948 '(was grafted from %d)\n') % (r, ctx.rev()))
2882 revs.remove(r)
2949 revs.remove(r)
2883 if not revs:
2950 if not revs:
2884 return -1
2951 return -1
2885
2952
2886 wlock = repo.wlock()
2953 wlock = repo.wlock()
2887 try:
2954 try:
2888 current = repo['.']
2955 current = repo['.']
2889 for pos, ctx in enumerate(repo.set("%ld", revs)):
2956 for pos, ctx in enumerate(repo.set("%ld", revs)):
2890
2957
2891 ui.status(_('grafting revision %s\n') % ctx.rev())
2958 ui.status(_('grafting revision %s\n') % ctx.rev())
2892 if opts.get('dry_run'):
2959 if opts.get('dry_run'):
2893 continue
2960 continue
2894
2961
2895 source = ctx.extra().get('source')
2962 source = ctx.extra().get('source')
2896 if not source:
2963 if not source:
2897 source = ctx.hex()
2964 source = ctx.hex()
2898 extra = {'source': source}
2965 extra = {'source': source}
2899 user = ctx.user()
2966 user = ctx.user()
2900 if opts.get('user'):
2967 if opts.get('user'):
2901 user = opts['user']
2968 user = opts['user']
2902 date = ctx.date()
2969 date = ctx.date()
2903 if opts.get('date'):
2970 if opts.get('date'):
2904 date = opts['date']
2971 date = opts['date']
2905 message = ctx.description()
2972 message = ctx.description()
2906 if opts.get('log'):
2973 if opts.get('log'):
2907 message += '\n(grafted from %s)' % ctx.hex()
2974 message += '\n(grafted from %s)' % ctx.hex()
2908
2975
2909 # we don't merge the first commit when continuing
2976 # we don't merge the first commit when continuing
2910 if not cont:
2977 if not cont:
2911 # perform the graft merge with p1(rev) as 'ancestor'
2978 # perform the graft merge with p1(rev) as 'ancestor'
2912 try:
2979 try:
2913 # ui.forcemerge is an internal variable, do not document
2980 # ui.forcemerge is an internal variable, do not document
2914 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2981 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2915 stats = mergemod.update(repo, ctx.node(), True, True, False,
2982 stats = mergemod.update(repo, ctx.node(), True, True, False,
2916 ctx.p1().node())
2983 ctx.p1().node())
2917 finally:
2984 finally:
2918 repo.ui.setconfig('ui', 'forcemerge', '')
2985 repo.ui.setconfig('ui', 'forcemerge', '')
2919 # report any conflicts
2986 # report any conflicts
2920 if stats and stats[3] > 0:
2987 if stats and stats[3] > 0:
2921 # write out state for --continue
2988 # write out state for --continue
2922 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2989 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2923 repo.opener.write('graftstate', ''.join(nodelines))
2990 repo.opener.write('graftstate', ''.join(nodelines))
2924 raise util.Abort(
2991 raise util.Abort(
2925 _("unresolved conflicts, can't continue"),
2992 _("unresolved conflicts, can't continue"),
2926 hint=_('use hg resolve and hg graft --continue'))
2993 hint=_('use hg resolve and hg graft --continue'))
2927 else:
2994 else:
2928 cont = False
2995 cont = False
2929
2996
2930 # drop the second merge parent
2997 # drop the second merge parent
2931 repo.setparents(current.node(), nullid)
2998 repo.setparents(current.node(), nullid)
2932 repo.dirstate.write()
2999 repo.dirstate.write()
2933 # fix up dirstate for copies and renames
3000 # fix up dirstate for copies and renames
2934 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3001 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2935
3002
2936 # commit
3003 # commit
2937 node = repo.commit(text=message, user=user,
3004 node = repo.commit(text=message, user=user,
2938 date=date, extra=extra, editor=editor)
3005 date=date, extra=extra, editor=editor)
2939 if node is None:
3006 if node is None:
2940 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3007 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2941 else:
3008 else:
2942 current = repo[node]
3009 current = repo[node]
2943 finally:
3010 finally:
2944 wlock.release()
3011 wlock.release()
2945
3012
2946 # remove state when we complete successfully
3013 # remove state when we complete successfully
2947 if not opts.get('dry_run'):
3014 if not opts.get('dry_run'):
2948 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3015 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2949
3016
2950 return 0
3017 return 0
2951
3018
2952 @command('grep',
3019 @command('grep',
2953 [('0', 'print0', None, _('end fields with NUL')),
3020 [('0', 'print0', None, _('end fields with NUL')),
2954 ('', 'all', None, _('print all revisions that match')),
3021 ('', 'all', None, _('print all revisions that match')),
2955 ('a', 'text', None, _('treat all files as text')),
3022 ('a', 'text', None, _('treat all files as text')),
2956 ('f', 'follow', None,
3023 ('f', 'follow', None,
2957 _('follow changeset history,'
3024 _('follow changeset history,'
2958 ' or file history across copies and renames')),
3025 ' or file history across copies and renames')),
2959 ('i', 'ignore-case', None, _('ignore case when matching')),
3026 ('i', 'ignore-case', None, _('ignore case when matching')),
2960 ('l', 'files-with-matches', None,
3027 ('l', 'files-with-matches', None,
2961 _('print only filenames and revisions that match')),
3028 _('print only filenames and revisions that match')),
2962 ('n', 'line-number', None, _('print matching line numbers')),
3029 ('n', 'line-number', None, _('print matching line numbers')),
2963 ('r', 'rev', [],
3030 ('r', 'rev', [],
2964 _('only search files changed within revision range'), _('REV')),
3031 _('only search files changed within revision range'), _('REV')),
2965 ('u', 'user', None, _('list the author (long with -v)')),
3032 ('u', 'user', None, _('list the author (long with -v)')),
2966 ('d', 'date', None, _('list the date (short with -q)')),
3033 ('d', 'date', None, _('list the date (short with -q)')),
2967 ] + walkopts,
3034 ] + walkopts,
2968 _('[OPTION]... PATTERN [FILE]...'))
3035 _('[OPTION]... PATTERN [FILE]...'))
2969 def grep(ui, repo, pattern, *pats, **opts):
3036 def grep(ui, repo, pattern, *pats, **opts):
2970 """search for a pattern in specified files and revisions
3037 """search for a pattern in specified files and revisions
2971
3038
2972 Search revisions of files for a regular expression.
3039 Search revisions of files for a regular expression.
2973
3040
2974 This command behaves differently than Unix grep. It only accepts
3041 This command behaves differently than Unix grep. It only accepts
2975 Python/Perl regexps. It searches repository history, not the
3042 Python/Perl regexps. It searches repository history, not the
2976 working directory. It always prints the revision number in which a
3043 working directory. It always prints the revision number in which a
2977 match appears.
3044 match appears.
2978
3045
2979 By default, grep only prints output for the first revision of a
3046 By default, grep only prints output for the first revision of a
2980 file in which it finds a match. To get it to print every revision
3047 file in which it finds a match. To get it to print every revision
2981 that contains a change in match status ("-" for a match that
3048 that contains a change in match status ("-" for a match that
2982 becomes a non-match, or "+" for a non-match that becomes a match),
3049 becomes a non-match, or "+" for a non-match that becomes a match),
2983 use the --all flag.
3050 use the --all flag.
2984
3051
2985 Returns 0 if a match is found, 1 otherwise.
3052 Returns 0 if a match is found, 1 otherwise.
2986 """
3053 """
2987 reflags = re.M
3054 reflags = re.M
2988 if opts.get('ignore_case'):
3055 if opts.get('ignore_case'):
2989 reflags |= re.I
3056 reflags |= re.I
2990 try:
3057 try:
2991 regexp = util.compilere(pattern, reflags)
3058 regexp = util.compilere(pattern, reflags)
2992 except re.error, inst:
3059 except re.error, inst:
2993 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3060 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2994 return 1
3061 return 1
2995 sep, eol = ':', '\n'
3062 sep, eol = ':', '\n'
2996 if opts.get('print0'):
3063 if opts.get('print0'):
2997 sep = eol = '\0'
3064 sep = eol = '\0'
2998
3065
2999 getfile = util.lrucachefunc(repo.file)
3066 getfile = util.lrucachefunc(repo.file)
3000
3067
3001 def matchlines(body):
3068 def matchlines(body):
3002 begin = 0
3069 begin = 0
3003 linenum = 0
3070 linenum = 0
3004 while begin < len(body):
3071 while begin < len(body):
3005 match = regexp.search(body, begin)
3072 match = regexp.search(body, begin)
3006 if not match:
3073 if not match:
3007 break
3074 break
3008 mstart, mend = match.span()
3075 mstart, mend = match.span()
3009 linenum += body.count('\n', begin, mstart) + 1
3076 linenum += body.count('\n', begin, mstart) + 1
3010 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3077 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3011 begin = body.find('\n', mend) + 1 or len(body) + 1
3078 begin = body.find('\n', mend) + 1 or len(body) + 1
3012 lend = begin - 1
3079 lend = begin - 1
3013 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3080 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3014
3081
3015 class linestate(object):
3082 class linestate(object):
3016 def __init__(self, line, linenum, colstart, colend):
3083 def __init__(self, line, linenum, colstart, colend):
3017 self.line = line
3084 self.line = line
3018 self.linenum = linenum
3085 self.linenum = linenum
3019 self.colstart = colstart
3086 self.colstart = colstart
3020 self.colend = colend
3087 self.colend = colend
3021
3088
3022 def __hash__(self):
3089 def __hash__(self):
3023 return hash((self.linenum, self.line))
3090 return hash((self.linenum, self.line))
3024
3091
3025 def __eq__(self, other):
3092 def __eq__(self, other):
3026 return self.line == other.line
3093 return self.line == other.line
3027
3094
3028 matches = {}
3095 matches = {}
3029 copies = {}
3096 copies = {}
3030 def grepbody(fn, rev, body):
3097 def grepbody(fn, rev, body):
3031 matches[rev].setdefault(fn, [])
3098 matches[rev].setdefault(fn, [])
3032 m = matches[rev][fn]
3099 m = matches[rev][fn]
3033 for lnum, cstart, cend, line in matchlines(body):
3100 for lnum, cstart, cend, line in matchlines(body):
3034 s = linestate(line, lnum, cstart, cend)
3101 s = linestate(line, lnum, cstart, cend)
3035 m.append(s)
3102 m.append(s)
3036
3103
3037 def difflinestates(a, b):
3104 def difflinestates(a, b):
3038 sm = difflib.SequenceMatcher(None, a, b)
3105 sm = difflib.SequenceMatcher(None, a, b)
3039 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3106 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3040 if tag == 'insert':
3107 if tag == 'insert':
3041 for i in xrange(blo, bhi):
3108 for i in xrange(blo, bhi):
3042 yield ('+', b[i])
3109 yield ('+', b[i])
3043 elif tag == 'delete':
3110 elif tag == 'delete':
3044 for i in xrange(alo, ahi):
3111 for i in xrange(alo, ahi):
3045 yield ('-', a[i])
3112 yield ('-', a[i])
3046 elif tag == 'replace':
3113 elif tag == 'replace':
3047 for i in xrange(alo, ahi):
3114 for i in xrange(alo, ahi):
3048 yield ('-', a[i])
3115 yield ('-', a[i])
3049 for i in xrange(blo, bhi):
3116 for i in xrange(blo, bhi):
3050 yield ('+', b[i])
3117 yield ('+', b[i])
3051
3118
3052 def display(fn, ctx, pstates, states):
3119 def display(fn, ctx, pstates, states):
3053 rev = ctx.rev()
3120 rev = ctx.rev()
3054 datefunc = ui.quiet and util.shortdate or util.datestr
3121 datefunc = ui.quiet and util.shortdate or util.datestr
3055 found = False
3122 found = False
3056 filerevmatches = {}
3123 filerevmatches = {}
3057 def binary():
3124 def binary():
3058 flog = getfile(fn)
3125 flog = getfile(fn)
3059 return util.binary(flog.read(ctx.filenode(fn)))
3126 return util.binary(flog.read(ctx.filenode(fn)))
3060
3127
3061 if opts.get('all'):
3128 if opts.get('all'):
3062 iter = difflinestates(pstates, states)
3129 iter = difflinestates(pstates, states)
3063 else:
3130 else:
3064 iter = [('', l) for l in states]
3131 iter = [('', l) for l in states]
3065 for change, l in iter:
3132 for change, l in iter:
3066 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3133 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3067 before, match, after = None, None, None
3134 before, match, after = None, None, None
3068
3135
3069 if opts.get('line_number'):
3136 if opts.get('line_number'):
3070 cols.append((str(l.linenum), 'grep.linenumber'))
3137 cols.append((str(l.linenum), 'grep.linenumber'))
3071 if opts.get('all'):
3138 if opts.get('all'):
3072 cols.append((change, 'grep.change'))
3139 cols.append((change, 'grep.change'))
3073 if opts.get('user'):
3140 if opts.get('user'):
3074 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3141 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3075 if opts.get('date'):
3142 if opts.get('date'):
3076 cols.append((datefunc(ctx.date()), 'grep.date'))
3143 cols.append((datefunc(ctx.date()), 'grep.date'))
3077 if opts.get('files_with_matches'):
3144 if opts.get('files_with_matches'):
3078 c = (fn, rev)
3145 c = (fn, rev)
3079 if c in filerevmatches:
3146 if c in filerevmatches:
3080 continue
3147 continue
3081 filerevmatches[c] = 1
3148 filerevmatches[c] = 1
3082 else:
3149 else:
3083 before = l.line[:l.colstart]
3150 before = l.line[:l.colstart]
3084 match = l.line[l.colstart:l.colend]
3151 match = l.line[l.colstart:l.colend]
3085 after = l.line[l.colend:]
3152 after = l.line[l.colend:]
3086 for col, label in cols[:-1]:
3153 for col, label in cols[:-1]:
3087 ui.write(col, label=label)
3154 ui.write(col, label=label)
3088 ui.write(sep, label='grep.sep')
3155 ui.write(sep, label='grep.sep')
3089 ui.write(cols[-1][0], label=cols[-1][1])
3156 ui.write(cols[-1][0], label=cols[-1][1])
3090 if before is not None:
3157 if before is not None:
3091 ui.write(sep, label='grep.sep')
3158 ui.write(sep, label='grep.sep')
3092 if not opts.get('text') and binary():
3159 if not opts.get('text') and binary():
3093 ui.write(" Binary file matches")
3160 ui.write(" Binary file matches")
3094 else:
3161 else:
3095 ui.write(before)
3162 ui.write(before)
3096 ui.write(match, label='grep.match')
3163 ui.write(match, label='grep.match')
3097 ui.write(after)
3164 ui.write(after)
3098 ui.write(eol)
3165 ui.write(eol)
3099 found = True
3166 found = True
3100 return found
3167 return found
3101
3168
3102 skip = {}
3169 skip = {}
3103 revfiles = {}
3170 revfiles = {}
3104 matchfn = scmutil.match(repo[None], pats, opts)
3171 matchfn = scmutil.match(repo[None], pats, opts)
3105 found = False
3172 found = False
3106 follow = opts.get('follow')
3173 follow = opts.get('follow')
3107
3174
3108 def prep(ctx, fns):
3175 def prep(ctx, fns):
3109 rev = ctx.rev()
3176 rev = ctx.rev()
3110 pctx = ctx.p1()
3177 pctx = ctx.p1()
3111 parent = pctx.rev()
3178 parent = pctx.rev()
3112 matches.setdefault(rev, {})
3179 matches.setdefault(rev, {})
3113 matches.setdefault(parent, {})
3180 matches.setdefault(parent, {})
3114 files = revfiles.setdefault(rev, [])
3181 files = revfiles.setdefault(rev, [])
3115 for fn in fns:
3182 for fn in fns:
3116 flog = getfile(fn)
3183 flog = getfile(fn)
3117 try:
3184 try:
3118 fnode = ctx.filenode(fn)
3185 fnode = ctx.filenode(fn)
3119 except error.LookupError:
3186 except error.LookupError:
3120 continue
3187 continue
3121
3188
3122 copied = flog.renamed(fnode)
3189 copied = flog.renamed(fnode)
3123 copy = follow and copied and copied[0]
3190 copy = follow and copied and copied[0]
3124 if copy:
3191 if copy:
3125 copies.setdefault(rev, {})[fn] = copy
3192 copies.setdefault(rev, {})[fn] = copy
3126 if fn in skip:
3193 if fn in skip:
3127 if copy:
3194 if copy:
3128 skip[copy] = True
3195 skip[copy] = True
3129 continue
3196 continue
3130 files.append(fn)
3197 files.append(fn)
3131
3198
3132 if fn not in matches[rev]:
3199 if fn not in matches[rev]:
3133 grepbody(fn, rev, flog.read(fnode))
3200 grepbody(fn, rev, flog.read(fnode))
3134
3201
3135 pfn = copy or fn
3202 pfn = copy or fn
3136 if pfn not in matches[parent]:
3203 if pfn not in matches[parent]:
3137 try:
3204 try:
3138 fnode = pctx.filenode(pfn)
3205 fnode = pctx.filenode(pfn)
3139 grepbody(pfn, parent, flog.read(fnode))
3206 grepbody(pfn, parent, flog.read(fnode))
3140 except error.LookupError:
3207 except error.LookupError:
3141 pass
3208 pass
3142
3209
3143 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3210 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3144 rev = ctx.rev()
3211 rev = ctx.rev()
3145 parent = ctx.p1().rev()
3212 parent = ctx.p1().rev()
3146 for fn in sorted(revfiles.get(rev, [])):
3213 for fn in sorted(revfiles.get(rev, [])):
3147 states = matches[rev][fn]
3214 states = matches[rev][fn]
3148 copy = copies.get(rev, {}).get(fn)
3215 copy = copies.get(rev, {}).get(fn)
3149 if fn in skip:
3216 if fn in skip:
3150 if copy:
3217 if copy:
3151 skip[copy] = True
3218 skip[copy] = True
3152 continue
3219 continue
3153 pstates = matches.get(parent, {}).get(copy or fn, [])
3220 pstates = matches.get(parent, {}).get(copy or fn, [])
3154 if pstates or states:
3221 if pstates or states:
3155 r = display(fn, ctx, pstates, states)
3222 r = display(fn, ctx, pstates, states)
3156 found = found or r
3223 found = found or r
3157 if r and not opts.get('all'):
3224 if r and not opts.get('all'):
3158 skip[fn] = True
3225 skip[fn] = True
3159 if copy:
3226 if copy:
3160 skip[copy] = True
3227 skip[copy] = True
3161 del matches[rev]
3228 del matches[rev]
3162 del revfiles[rev]
3229 del revfiles[rev]
3163
3230
3164 return not found
3231 return not found
3165
3232
3166 @command('heads',
3233 @command('heads',
3167 [('r', 'rev', '',
3234 [('r', 'rev', '',
3168 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3235 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3169 ('t', 'topo', False, _('show topological heads only')),
3236 ('t', 'topo', False, _('show topological heads only')),
3170 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3237 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3171 ('c', 'closed', False, _('show normal and closed branch heads')),
3238 ('c', 'closed', False, _('show normal and closed branch heads')),
3172 ] + templateopts,
3239 ] + templateopts,
3173 _('[-ct] [-r STARTREV] [REV]...'))
3240 _('[-ct] [-r STARTREV] [REV]...'))
3174 def heads(ui, repo, *branchrevs, **opts):
3241 def heads(ui, repo, *branchrevs, **opts):
3175 """show current repository heads or show branch heads
3242 """show current repository heads or show branch heads
3176
3243
3177 With no arguments, show all repository branch heads.
3244 With no arguments, show all repository branch heads.
3178
3245
3179 Repository "heads" are changesets with no child changesets. They are
3246 Repository "heads" are changesets with no child changesets. They are
3180 where development generally takes place and are the usual targets
3247 where development generally takes place and are the usual targets
3181 for update and merge operations. Branch heads are changesets that have
3248 for update and merge operations. Branch heads are changesets that have
3182 no child changeset on the same branch.
3249 no child changeset on the same branch.
3183
3250
3184 If one or more REVs are given, only branch heads on the branches
3251 If one or more REVs are given, only branch heads on the branches
3185 associated with the specified changesets are shown. This means
3252 associated with the specified changesets are shown. This means
3186 that you can use :hg:`heads foo` to see the heads on a branch
3253 that you can use :hg:`heads foo` to see the heads on a branch
3187 named ``foo``.
3254 named ``foo``.
3188
3255
3189 If -c/--closed is specified, also show branch heads marked closed
3256 If -c/--closed is specified, also show branch heads marked closed
3190 (see :hg:`commit --close-branch`).
3257 (see :hg:`commit --close-branch`).
3191
3258
3192 If STARTREV is specified, only those heads that are descendants of
3259 If STARTREV is specified, only those heads that are descendants of
3193 STARTREV will be displayed.
3260 STARTREV will be displayed.
3194
3261
3195 If -t/--topo is specified, named branch mechanics will be ignored and only
3262 If -t/--topo is specified, named branch mechanics will be ignored and only
3196 changesets without children will be shown.
3263 changesets without children will be shown.
3197
3264
3198 Returns 0 if matching heads are found, 1 if not.
3265 Returns 0 if matching heads are found, 1 if not.
3199 """
3266 """
3200
3267
3201 start = None
3268 start = None
3202 if 'rev' in opts:
3269 if 'rev' in opts:
3203 start = scmutil.revsingle(repo, opts['rev'], None).node()
3270 start = scmutil.revsingle(repo, opts['rev'], None).node()
3204
3271
3205 if opts.get('topo'):
3272 if opts.get('topo'):
3206 heads = [repo[h] for h in repo.heads(start)]
3273 heads = [repo[h] for h in repo.heads(start)]
3207 else:
3274 else:
3208 heads = []
3275 heads = []
3209 for branch in repo.branchmap():
3276 for branch in repo.branchmap():
3210 heads += repo.branchheads(branch, start, opts.get('closed'))
3277 heads += repo.branchheads(branch, start, opts.get('closed'))
3211 heads = [repo[h] for h in heads]
3278 heads = [repo[h] for h in heads]
3212
3279
3213 if branchrevs:
3280 if branchrevs:
3214 branches = set(repo[br].branch() for br in branchrevs)
3281 branches = set(repo[br].branch() for br in branchrevs)
3215 heads = [h for h in heads if h.branch() in branches]
3282 heads = [h for h in heads if h.branch() in branches]
3216
3283
3217 if opts.get('active') and branchrevs:
3284 if opts.get('active') and branchrevs:
3218 dagheads = repo.heads(start)
3285 dagheads = repo.heads(start)
3219 heads = [h for h in heads if h.node() in dagheads]
3286 heads = [h for h in heads if h.node() in dagheads]
3220
3287
3221 if branchrevs:
3288 if branchrevs:
3222 haveheads = set(h.branch() for h in heads)
3289 haveheads = set(h.branch() for h in heads)
3223 if branches - haveheads:
3290 if branches - haveheads:
3224 headless = ', '.join(b for b in branches - haveheads)
3291 headless = ', '.join(b for b in branches - haveheads)
3225 msg = _('no open branch heads found on branches %s')
3292 msg = _('no open branch heads found on branches %s')
3226 if opts.get('rev'):
3293 if opts.get('rev'):
3227 msg += _(' (started at %s)') % opts['rev']
3294 msg += _(' (started at %s)') % opts['rev']
3228 ui.warn((msg + '\n') % headless)
3295 ui.warn((msg + '\n') % headless)
3229
3296
3230 if not heads:
3297 if not heads:
3231 return 1
3298 return 1
3232
3299
3233 heads = sorted(heads, key=lambda x: -x.rev())
3300 heads = sorted(heads, key=lambda x: -x.rev())
3234 displayer = cmdutil.show_changeset(ui, repo, opts)
3301 displayer = cmdutil.show_changeset(ui, repo, opts)
3235 for ctx in heads:
3302 for ctx in heads:
3236 displayer.show(ctx)
3303 displayer.show(ctx)
3237 displayer.close()
3304 displayer.close()
3238
3305
3239 @command('help',
3306 @command('help',
3240 [('e', 'extension', None, _('show only help for extensions')),
3307 [('e', 'extension', None, _('show only help for extensions')),
3241 ('c', 'command', None, _('show only help for commands')),
3308 ('c', 'command', None, _('show only help for commands')),
3242 ('k', 'keyword', '', _('show topics matching keyword')),
3309 ('k', 'keyword', '', _('show topics matching keyword')),
3243 ],
3310 ],
3244 _('[-ec] [TOPIC]'))
3311 _('[-ec] [TOPIC]'))
3245 def help_(ui, name=None, **opts):
3312 def help_(ui, name=None, **opts):
3246 """show help for a given topic or a help overview
3313 """show help for a given topic or a help overview
3247
3314
3248 With no arguments, print a list of commands with short help messages.
3315 With no arguments, print a list of commands with short help messages.
3249
3316
3250 Given a topic, extension, or command name, print help for that
3317 Given a topic, extension, or command name, print help for that
3251 topic.
3318 topic.
3252
3319
3253 Returns 0 if successful.
3320 Returns 0 if successful.
3254 """
3321 """
3255
3322
3256 textwidth = min(ui.termwidth(), 80) - 2
3323 textwidth = min(ui.termwidth(), 80) - 2
3257
3324
3258 keep = ui.verbose and ['verbose'] or []
3325 keep = ui.verbose and ['verbose'] or []
3259 text = help.help_(ui, name, **opts)
3326 text = help.help_(ui, name, **opts)
3260
3327
3261 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3328 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3262 if 'verbose' in pruned:
3329 if 'verbose' in pruned:
3263 keep.append('omitted')
3330 keep.append('omitted')
3264 else:
3331 else:
3265 keep.append('notomitted')
3332 keep.append('notomitted')
3266 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3333 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3267 ui.write(formatted)
3334 ui.write(formatted)
3268
3335
3269
3336
3270 @command('identify|id',
3337 @command('identify|id',
3271 [('r', 'rev', '',
3338 [('r', 'rev', '',
3272 _('identify the specified revision'), _('REV')),
3339 _('identify the specified revision'), _('REV')),
3273 ('n', 'num', None, _('show local revision number')),
3340 ('n', 'num', None, _('show local revision number')),
3274 ('i', 'id', None, _('show global revision id')),
3341 ('i', 'id', None, _('show global revision id')),
3275 ('b', 'branch', None, _('show branch')),
3342 ('b', 'branch', None, _('show branch')),
3276 ('t', 'tags', None, _('show tags')),
3343 ('t', 'tags', None, _('show tags')),
3277 ('B', 'bookmarks', None, _('show bookmarks')),
3344 ('B', 'bookmarks', None, _('show bookmarks')),
3278 ] + remoteopts,
3345 ] + remoteopts,
3279 _('[-nibtB] [-r REV] [SOURCE]'))
3346 _('[-nibtB] [-r REV] [SOURCE]'))
3280 def identify(ui, repo, source=None, rev=None,
3347 def identify(ui, repo, source=None, rev=None,
3281 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3348 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3282 """identify the working copy or specified revision
3349 """identify the working copy or specified revision
3283
3350
3284 Print a summary identifying the repository state at REV using one or
3351 Print a summary identifying the repository state at REV using one or
3285 two parent hash identifiers, followed by a "+" if the working
3352 two parent hash identifiers, followed by a "+" if the working
3286 directory has uncommitted changes, the branch name (if not default),
3353 directory has uncommitted changes, the branch name (if not default),
3287 a list of tags, and a list of bookmarks.
3354 a list of tags, and a list of bookmarks.
3288
3355
3289 When REV is not given, print a summary of the current state of the
3356 When REV is not given, print a summary of the current state of the
3290 repository.
3357 repository.
3291
3358
3292 Specifying a path to a repository root or Mercurial bundle will
3359 Specifying a path to a repository root or Mercurial bundle will
3293 cause lookup to operate on that repository/bundle.
3360 cause lookup to operate on that repository/bundle.
3294
3361
3295 .. container:: verbose
3362 .. container:: verbose
3296
3363
3297 Examples:
3364 Examples:
3298
3365
3299 - generate a build identifier for the working directory::
3366 - generate a build identifier for the working directory::
3300
3367
3301 hg id --id > build-id.dat
3368 hg id --id > build-id.dat
3302
3369
3303 - find the revision corresponding to a tag::
3370 - find the revision corresponding to a tag::
3304
3371
3305 hg id -n -r 1.3
3372 hg id -n -r 1.3
3306
3373
3307 - check the most recent revision of a remote repository::
3374 - check the most recent revision of a remote repository::
3308
3375
3309 hg id -r tip http://selenic.com/hg/
3376 hg id -r tip http://selenic.com/hg/
3310
3377
3311 Returns 0 if successful.
3378 Returns 0 if successful.
3312 """
3379 """
3313
3380
3314 if not repo and not source:
3381 if not repo and not source:
3315 raise util.Abort(_("there is no Mercurial repository here "
3382 raise util.Abort(_("there is no Mercurial repository here "
3316 "(.hg not found)"))
3383 "(.hg not found)"))
3317
3384
3318 hexfunc = ui.debugflag and hex or short
3385 hexfunc = ui.debugflag and hex or short
3319 default = not (num or id or branch or tags or bookmarks)
3386 default = not (num or id or branch or tags or bookmarks)
3320 output = []
3387 output = []
3321 revs = []
3388 revs = []
3322
3389
3323 if source:
3390 if source:
3324 source, branches = hg.parseurl(ui.expandpath(source))
3391 source, branches = hg.parseurl(ui.expandpath(source))
3325 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3392 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3326 repo = peer.local()
3393 repo = peer.local()
3327 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3394 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3328
3395
3329 if not repo:
3396 if not repo:
3330 if num or branch or tags:
3397 if num or branch or tags:
3331 raise util.Abort(
3398 raise util.Abort(
3332 _("can't query remote revision number, branch, or tags"))
3399 _("can't query remote revision number, branch, or tags"))
3333 if not rev and revs:
3400 if not rev and revs:
3334 rev = revs[0]
3401 rev = revs[0]
3335 if not rev:
3402 if not rev:
3336 rev = "tip"
3403 rev = "tip"
3337
3404
3338 remoterev = peer.lookup(rev)
3405 remoterev = peer.lookup(rev)
3339 if default or id:
3406 if default or id:
3340 output = [hexfunc(remoterev)]
3407 output = [hexfunc(remoterev)]
3341
3408
3342 def getbms():
3409 def getbms():
3343 bms = []
3410 bms = []
3344
3411
3345 if 'bookmarks' in peer.listkeys('namespaces'):
3412 if 'bookmarks' in peer.listkeys('namespaces'):
3346 hexremoterev = hex(remoterev)
3413 hexremoterev = hex(remoterev)
3347 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3414 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3348 if bmr == hexremoterev]
3415 if bmr == hexremoterev]
3349
3416
3350 return sorted(bms)
3417 return sorted(bms)
3351
3418
3352 if bookmarks:
3419 if bookmarks:
3353 output.extend(getbms())
3420 output.extend(getbms())
3354 elif default and not ui.quiet:
3421 elif default and not ui.quiet:
3355 # multiple bookmarks for a single parent separated by '/'
3422 # multiple bookmarks for a single parent separated by '/'
3356 bm = '/'.join(getbms())
3423 bm = '/'.join(getbms())
3357 if bm:
3424 if bm:
3358 output.append(bm)
3425 output.append(bm)
3359 else:
3426 else:
3360 if not rev:
3427 if not rev:
3361 ctx = repo[None]
3428 ctx = repo[None]
3362 parents = ctx.parents()
3429 parents = ctx.parents()
3363 changed = ""
3430 changed = ""
3364 if default or id or num:
3431 if default or id or num:
3365 if (util.any(repo.status())
3432 if (util.any(repo.status())
3366 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3433 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3367 changed = '+'
3434 changed = '+'
3368 if default or id:
3435 if default or id:
3369 output = ["%s%s" %
3436 output = ["%s%s" %
3370 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3437 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3371 if num:
3438 if num:
3372 output.append("%s%s" %
3439 output.append("%s%s" %
3373 ('+'.join([str(p.rev()) for p in parents]), changed))
3440 ('+'.join([str(p.rev()) for p in parents]), changed))
3374 else:
3441 else:
3375 ctx = scmutil.revsingle(repo, rev)
3442 ctx = scmutil.revsingle(repo, rev)
3376 if default or id:
3443 if default or id:
3377 output = [hexfunc(ctx.node())]
3444 output = [hexfunc(ctx.node())]
3378 if num:
3445 if num:
3379 output.append(str(ctx.rev()))
3446 output.append(str(ctx.rev()))
3380
3447
3381 if default and not ui.quiet:
3448 if default and not ui.quiet:
3382 b = ctx.branch()
3449 b = ctx.branch()
3383 if b != 'default':
3450 if b != 'default':
3384 output.append("(%s)" % b)
3451 output.append("(%s)" % b)
3385
3452
3386 # multiple tags for a single parent separated by '/'
3453 # multiple tags for a single parent separated by '/'
3387 t = '/'.join(ctx.tags())
3454 t = '/'.join(ctx.tags())
3388 if t:
3455 if t:
3389 output.append(t)
3456 output.append(t)
3390
3457
3391 # multiple bookmarks for a single parent separated by '/'
3458 # multiple bookmarks for a single parent separated by '/'
3392 bm = '/'.join(ctx.bookmarks())
3459 bm = '/'.join(ctx.bookmarks())
3393 if bm:
3460 if bm:
3394 output.append(bm)
3461 output.append(bm)
3395 else:
3462 else:
3396 if branch:
3463 if branch:
3397 output.append(ctx.branch())
3464 output.append(ctx.branch())
3398
3465
3399 if tags:
3466 if tags:
3400 output.extend(ctx.tags())
3467 output.extend(ctx.tags())
3401
3468
3402 if bookmarks:
3469 if bookmarks:
3403 output.extend(ctx.bookmarks())
3470 output.extend(ctx.bookmarks())
3404
3471
3405 ui.write("%s\n" % ' '.join(output))
3472 ui.write("%s\n" % ' '.join(output))
3406
3473
3407 @command('import|patch',
3474 @command('import|patch',
3408 [('p', 'strip', 1,
3475 [('p', 'strip', 1,
3409 _('directory strip option for patch. This has the same '
3476 _('directory strip option for patch. This has the same '
3410 'meaning as the corresponding patch option'), _('NUM')),
3477 'meaning as the corresponding patch option'), _('NUM')),
3411 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3478 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3412 ('e', 'edit', False, _('invoke editor on commit messages')),
3479 ('e', 'edit', False, _('invoke editor on commit messages')),
3413 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3480 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3414 ('', 'no-commit', None,
3481 ('', 'no-commit', None,
3415 _("don't commit, just update the working directory")),
3482 _("don't commit, just update the working directory")),
3416 ('', 'bypass', None,
3483 ('', 'bypass', None,
3417 _("apply patch without touching the working directory")),
3484 _("apply patch without touching the working directory")),
3418 ('', 'exact', None,
3485 ('', 'exact', None,
3419 _('apply patch to the nodes from which it was generated')),
3486 _('apply patch to the nodes from which it was generated')),
3420 ('', 'import-branch', None,
3487 ('', 'import-branch', None,
3421 _('use any branch information in patch (implied by --exact)'))] +
3488 _('use any branch information in patch (implied by --exact)'))] +
3422 commitopts + commitopts2 + similarityopts,
3489 commitopts + commitopts2 + similarityopts,
3423 _('[OPTION]... PATCH...'))
3490 _('[OPTION]... PATCH...'))
3424 def import_(ui, repo, patch1=None, *patches, **opts):
3491 def import_(ui, repo, patch1=None, *patches, **opts):
3425 """import an ordered set of patches
3492 """import an ordered set of patches
3426
3493
3427 Import a list of patches and commit them individually (unless
3494 Import a list of patches and commit them individually (unless
3428 --no-commit is specified).
3495 --no-commit is specified).
3429
3496
3430 If there are outstanding changes in the working directory, import
3497 If there are outstanding changes in the working directory, import
3431 will abort unless given the -f/--force flag.
3498 will abort unless given the -f/--force flag.
3432
3499
3433 You can import a patch straight from a mail message. Even patches
3500 You can import a patch straight from a mail message. Even patches
3434 as attachments work (to use the body part, it must have type
3501 as attachments work (to use the body part, it must have type
3435 text/plain or text/x-patch). From and Subject headers of email
3502 text/plain or text/x-patch). From and Subject headers of email
3436 message are used as default committer and commit message. All
3503 message are used as default committer and commit message. All
3437 text/plain body parts before first diff are added to commit
3504 text/plain body parts before first diff are added to commit
3438 message.
3505 message.
3439
3506
3440 If the imported patch was generated by :hg:`export`, user and
3507 If the imported patch was generated by :hg:`export`, user and
3441 description from patch override values from message headers and
3508 description from patch override values from message headers and
3442 body. Values given on command line with -m/--message and -u/--user
3509 body. Values given on command line with -m/--message and -u/--user
3443 override these.
3510 override these.
3444
3511
3445 If --exact is specified, import will set the working directory to
3512 If --exact is specified, import will set the working directory to
3446 the parent of each patch before applying it, and will abort if the
3513 the parent of each patch before applying it, and will abort if the
3447 resulting changeset has a different ID than the one recorded in
3514 resulting changeset has a different ID than the one recorded in
3448 the patch. This may happen due to character set problems or other
3515 the patch. This may happen due to character set problems or other
3449 deficiencies in the text patch format.
3516 deficiencies in the text patch format.
3450
3517
3451 Use --bypass to apply and commit patches directly to the
3518 Use --bypass to apply and commit patches directly to the
3452 repository, not touching the working directory. Without --exact,
3519 repository, not touching the working directory. Without --exact,
3453 patches will be applied on top of the working directory parent
3520 patches will be applied on top of the working directory parent
3454 revision.
3521 revision.
3455
3522
3456 With -s/--similarity, hg will attempt to discover renames and
3523 With -s/--similarity, hg will attempt to discover renames and
3457 copies in the patch in the same way as :hg:`addremove`.
3524 copies in the patch in the same way as :hg:`addremove`.
3458
3525
3459 To read a patch from standard input, use "-" as the patch name. If
3526 To read a patch from standard input, use "-" as the patch name. If
3460 a URL is specified, the patch will be downloaded from it.
3527 a URL is specified, the patch will be downloaded from it.
3461 See :hg:`help dates` for a list of formats valid for -d/--date.
3528 See :hg:`help dates` for a list of formats valid for -d/--date.
3462
3529
3463 .. container:: verbose
3530 .. container:: verbose
3464
3531
3465 Examples:
3532 Examples:
3466
3533
3467 - import a traditional patch from a website and detect renames::
3534 - import a traditional patch from a website and detect renames::
3468
3535
3469 hg import -s 80 http://example.com/bugfix.patch
3536 hg import -s 80 http://example.com/bugfix.patch
3470
3537
3471 - import a changeset from an hgweb server::
3538 - import a changeset from an hgweb server::
3472
3539
3473 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3540 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3474
3541
3475 - import all the patches in an Unix-style mbox::
3542 - import all the patches in an Unix-style mbox::
3476
3543
3477 hg import incoming-patches.mbox
3544 hg import incoming-patches.mbox
3478
3545
3479 - attempt to exactly restore an exported changeset (not always
3546 - attempt to exactly restore an exported changeset (not always
3480 possible)::
3547 possible)::
3481
3548
3482 hg import --exact proposed-fix.patch
3549 hg import --exact proposed-fix.patch
3483
3550
3484 Returns 0 on success.
3551 Returns 0 on success.
3485 """
3552 """
3486
3553
3487 if not patch1:
3554 if not patch1:
3488 raise util.Abort(_('need at least one patch to import'))
3555 raise util.Abort(_('need at least one patch to import'))
3489
3556
3490 patches = (patch1,) + patches
3557 patches = (patch1,) + patches
3491
3558
3492 date = opts.get('date')
3559 date = opts.get('date')
3493 if date:
3560 if date:
3494 opts['date'] = util.parsedate(date)
3561 opts['date'] = util.parsedate(date)
3495
3562
3496 editor = cmdutil.commiteditor
3563 editor = cmdutil.commiteditor
3497 if opts.get('edit'):
3564 if opts.get('edit'):
3498 editor = cmdutil.commitforceeditor
3565 editor = cmdutil.commitforceeditor
3499
3566
3500 update = not opts.get('bypass')
3567 update = not opts.get('bypass')
3501 if not update and opts.get('no_commit'):
3568 if not update and opts.get('no_commit'):
3502 raise util.Abort(_('cannot use --no-commit with --bypass'))
3569 raise util.Abort(_('cannot use --no-commit with --bypass'))
3503 try:
3570 try:
3504 sim = float(opts.get('similarity') or 0)
3571 sim = float(opts.get('similarity') or 0)
3505 except ValueError:
3572 except ValueError:
3506 raise util.Abort(_('similarity must be a number'))
3573 raise util.Abort(_('similarity must be a number'))
3507 if sim < 0 or sim > 100:
3574 if sim < 0 or sim > 100:
3508 raise util.Abort(_('similarity must be between 0 and 100'))
3575 raise util.Abort(_('similarity must be between 0 and 100'))
3509 if sim and not update:
3576 if sim and not update:
3510 raise util.Abort(_('cannot use --similarity with --bypass'))
3577 raise util.Abort(_('cannot use --similarity with --bypass'))
3511
3578
3512 if (opts.get('exact') or not opts.get('force')) and update:
3579 if (opts.get('exact') or not opts.get('force')) and update:
3513 cmdutil.bailifchanged(repo)
3580 cmdutil.bailifchanged(repo)
3514
3581
3515 base = opts["base"]
3582 base = opts["base"]
3516 strip = opts["strip"]
3583 strip = opts["strip"]
3517 wlock = lock = tr = None
3584 wlock = lock = tr = None
3518 msgs = []
3585 msgs = []
3519
3586
3520 def checkexact(repo, n, nodeid):
3587 def checkexact(repo, n, nodeid):
3521 if opts.get('exact') and hex(n) != nodeid:
3588 if opts.get('exact') and hex(n) != nodeid:
3522 raise util.Abort(_('patch is damaged or loses information'))
3589 raise util.Abort(_('patch is damaged or loses information'))
3523
3590
3524 def tryone(ui, hunk, parents):
3591 def tryone(ui, hunk, parents):
3525 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3592 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3526 patch.extract(ui, hunk)
3593 patch.extract(ui, hunk)
3527
3594
3528 if not tmpname:
3595 if not tmpname:
3529 return (None, None)
3596 return (None, None)
3530 msg = _('applied to working directory')
3597 msg = _('applied to working directory')
3531
3598
3532 try:
3599 try:
3533 cmdline_message = cmdutil.logmessage(ui, opts)
3600 cmdline_message = cmdutil.logmessage(ui, opts)
3534 if cmdline_message:
3601 if cmdline_message:
3535 # pickup the cmdline msg
3602 # pickup the cmdline msg
3536 message = cmdline_message
3603 message = cmdline_message
3537 elif message:
3604 elif message:
3538 # pickup the patch msg
3605 # pickup the patch msg
3539 message = message.strip()
3606 message = message.strip()
3540 else:
3607 else:
3541 # launch the editor
3608 # launch the editor
3542 message = None
3609 message = None
3543 ui.debug('message:\n%s\n' % message)
3610 ui.debug('message:\n%s\n' % message)
3544
3611
3545 if len(parents) == 1:
3612 if len(parents) == 1:
3546 parents.append(repo[nullid])
3613 parents.append(repo[nullid])
3547 if opts.get('exact'):
3614 if opts.get('exact'):
3548 if not nodeid or not p1:
3615 if not nodeid or not p1:
3549 raise util.Abort(_('not a Mercurial patch'))
3616 raise util.Abort(_('not a Mercurial patch'))
3550 p1 = repo[p1]
3617 p1 = repo[p1]
3551 p2 = repo[p2 or nullid]
3618 p2 = repo[p2 or nullid]
3552 elif p2:
3619 elif p2:
3553 try:
3620 try:
3554 p1 = repo[p1]
3621 p1 = repo[p1]
3555 p2 = repo[p2]
3622 p2 = repo[p2]
3556 # Without any options, consider p2 only if the
3623 # Without any options, consider p2 only if the
3557 # patch is being applied on top of the recorded
3624 # patch is being applied on top of the recorded
3558 # first parent.
3625 # first parent.
3559 if p1 != parents[0]:
3626 if p1 != parents[0]:
3560 p1 = parents[0]
3627 p1 = parents[0]
3561 p2 = repo[nullid]
3628 p2 = repo[nullid]
3562 except error.RepoError:
3629 except error.RepoError:
3563 p1, p2 = parents
3630 p1, p2 = parents
3564 else:
3631 else:
3565 p1, p2 = parents
3632 p1, p2 = parents
3566
3633
3567 n = None
3634 n = None
3568 if update:
3635 if update:
3569 if p1 != parents[0]:
3636 if p1 != parents[0]:
3570 hg.clean(repo, p1.node())
3637 hg.clean(repo, p1.node())
3571 if p2 != parents[1]:
3638 if p2 != parents[1]:
3572 repo.setparents(p1.node(), p2.node())
3639 repo.setparents(p1.node(), p2.node())
3573
3640
3574 if opts.get('exact') or opts.get('import_branch'):
3641 if opts.get('exact') or opts.get('import_branch'):
3575 repo.dirstate.setbranch(branch or 'default')
3642 repo.dirstate.setbranch(branch or 'default')
3576
3643
3577 files = set()
3644 files = set()
3578 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3645 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3579 eolmode=None, similarity=sim / 100.0)
3646 eolmode=None, similarity=sim / 100.0)
3580 files = list(files)
3647 files = list(files)
3581 if opts.get('no_commit'):
3648 if opts.get('no_commit'):
3582 if message:
3649 if message:
3583 msgs.append(message)
3650 msgs.append(message)
3584 else:
3651 else:
3585 if opts.get('exact') or p2:
3652 if opts.get('exact') or p2:
3586 # If you got here, you either use --force and know what
3653 # If you got here, you either use --force and know what
3587 # you are doing or used --exact or a merge patch while
3654 # you are doing or used --exact or a merge patch while
3588 # being updated to its first parent.
3655 # being updated to its first parent.
3589 m = None
3656 m = None
3590 else:
3657 else:
3591 m = scmutil.matchfiles(repo, files or [])
3658 m = scmutil.matchfiles(repo, files or [])
3592 n = repo.commit(message, opts.get('user') or user,
3659 n = repo.commit(message, opts.get('user') or user,
3593 opts.get('date') or date, match=m,
3660 opts.get('date') or date, match=m,
3594 editor=editor)
3661 editor=editor)
3595 checkexact(repo, n, nodeid)
3662 checkexact(repo, n, nodeid)
3596 else:
3663 else:
3597 if opts.get('exact') or opts.get('import_branch'):
3664 if opts.get('exact') or opts.get('import_branch'):
3598 branch = branch or 'default'
3665 branch = branch or 'default'
3599 else:
3666 else:
3600 branch = p1.branch()
3667 branch = p1.branch()
3601 store = patch.filestore()
3668 store = patch.filestore()
3602 try:
3669 try:
3603 files = set()
3670 files = set()
3604 try:
3671 try:
3605 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3672 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3606 files, eolmode=None)
3673 files, eolmode=None)
3607 except patch.PatchError, e:
3674 except patch.PatchError, e:
3608 raise util.Abort(str(e))
3675 raise util.Abort(str(e))
3609 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3676 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3610 message,
3677 message,
3611 opts.get('user') or user,
3678 opts.get('user') or user,
3612 opts.get('date') or date,
3679 opts.get('date') or date,
3613 branch, files, store,
3680 branch, files, store,
3614 editor=cmdutil.commiteditor)
3681 editor=cmdutil.commiteditor)
3615 repo.savecommitmessage(memctx.description())
3682 repo.savecommitmessage(memctx.description())
3616 n = memctx.commit()
3683 n = memctx.commit()
3617 checkexact(repo, n, nodeid)
3684 checkexact(repo, n, nodeid)
3618 finally:
3685 finally:
3619 store.close()
3686 store.close()
3620 if n:
3687 if n:
3621 # i18n: refers to a short changeset id
3688 # i18n: refers to a short changeset id
3622 msg = _('created %s') % short(n)
3689 msg = _('created %s') % short(n)
3623 return (msg, n)
3690 return (msg, n)
3624 finally:
3691 finally:
3625 os.unlink(tmpname)
3692 os.unlink(tmpname)
3626
3693
3627 try:
3694 try:
3628 try:
3695 try:
3629 wlock = repo.wlock()
3696 wlock = repo.wlock()
3630 if not opts.get('no_commit'):
3697 if not opts.get('no_commit'):
3631 lock = repo.lock()
3698 lock = repo.lock()
3632 tr = repo.transaction('import')
3699 tr = repo.transaction('import')
3633 parents = repo.parents()
3700 parents = repo.parents()
3634 for patchurl in patches:
3701 for patchurl in patches:
3635 if patchurl == '-':
3702 if patchurl == '-':
3636 ui.status(_('applying patch from stdin\n'))
3703 ui.status(_('applying patch from stdin\n'))
3637 patchfile = ui.fin
3704 patchfile = ui.fin
3638 patchurl = 'stdin' # for error message
3705 patchurl = 'stdin' # for error message
3639 else:
3706 else:
3640 patchurl = os.path.join(base, patchurl)
3707 patchurl = os.path.join(base, patchurl)
3641 ui.status(_('applying %s\n') % patchurl)
3708 ui.status(_('applying %s\n') % patchurl)
3642 patchfile = hg.openpath(ui, patchurl)
3709 patchfile = hg.openpath(ui, patchurl)
3643
3710
3644 haspatch = False
3711 haspatch = False
3645 for hunk in patch.split(patchfile):
3712 for hunk in patch.split(patchfile):
3646 (msg, node) = tryone(ui, hunk, parents)
3713 (msg, node) = tryone(ui, hunk, parents)
3647 if msg:
3714 if msg:
3648 haspatch = True
3715 haspatch = True
3649 ui.note(msg + '\n')
3716 ui.note(msg + '\n')
3650 if update or opts.get('exact'):
3717 if update or opts.get('exact'):
3651 parents = repo.parents()
3718 parents = repo.parents()
3652 else:
3719 else:
3653 parents = [repo[node]]
3720 parents = [repo[node]]
3654
3721
3655 if not haspatch:
3722 if not haspatch:
3656 raise util.Abort(_('%s: no diffs found') % patchurl)
3723 raise util.Abort(_('%s: no diffs found') % patchurl)
3657
3724
3658 if tr:
3725 if tr:
3659 tr.close()
3726 tr.close()
3660 if msgs:
3727 if msgs:
3661 repo.savecommitmessage('\n* * *\n'.join(msgs))
3728 repo.savecommitmessage('\n* * *\n'.join(msgs))
3662 except: # re-raises
3729 except: # re-raises
3663 # wlock.release() indirectly calls dirstate.write(): since
3730 # wlock.release() indirectly calls dirstate.write(): since
3664 # we're crashing, we do not want to change the working dir
3731 # we're crashing, we do not want to change the working dir
3665 # parent after all, so make sure it writes nothing
3732 # parent after all, so make sure it writes nothing
3666 repo.dirstate.invalidate()
3733 repo.dirstate.invalidate()
3667 raise
3734 raise
3668 finally:
3735 finally:
3669 if tr:
3736 if tr:
3670 tr.release()
3737 tr.release()
3671 release(lock, wlock)
3738 release(lock, wlock)
3672
3739
3673 @command('incoming|in',
3740 @command('incoming|in',
3674 [('f', 'force', None,
3741 [('f', 'force', None,
3675 _('run even if remote repository is unrelated')),
3742 _('run even if remote repository is unrelated')),
3676 ('n', 'newest-first', None, _('show newest record first')),
3743 ('n', 'newest-first', None, _('show newest record first')),
3677 ('', 'bundle', '',
3744 ('', 'bundle', '',
3678 _('file to store the bundles into'), _('FILE')),
3745 _('file to store the bundles into'), _('FILE')),
3679 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3746 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3680 ('B', 'bookmarks', False, _("compare bookmarks")),
3747 ('B', 'bookmarks', False, _("compare bookmarks")),
3681 ('b', 'branch', [],
3748 ('b', 'branch', [],
3682 _('a specific branch you would like to pull'), _('BRANCH')),
3749 _('a specific branch you would like to pull'), _('BRANCH')),
3683 ] + logopts + remoteopts + subrepoopts,
3750 ] + logopts + remoteopts + subrepoopts,
3684 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3751 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3685 def incoming(ui, repo, source="default", **opts):
3752 def incoming(ui, repo, source="default", **opts):
3686 """show new changesets found in source
3753 """show new changesets found in source
3687
3754
3688 Show new changesets found in the specified path/URL or the default
3755 Show new changesets found in the specified path/URL or the default
3689 pull location. These are the changesets that would have been pulled
3756 pull location. These are the changesets that would have been pulled
3690 if a pull at the time you issued this command.
3757 if a pull at the time you issued this command.
3691
3758
3692 For remote repository, using --bundle avoids downloading the
3759 For remote repository, using --bundle avoids downloading the
3693 changesets twice if the incoming is followed by a pull.
3760 changesets twice if the incoming is followed by a pull.
3694
3761
3695 See pull for valid source format details.
3762 See pull for valid source format details.
3696
3763
3697 Returns 0 if there are incoming changes, 1 otherwise.
3764 Returns 0 if there are incoming changes, 1 otherwise.
3698 """
3765 """
3699 if opts.get('graph'):
3766 if opts.get('graph'):
3700 cmdutil.checkunsupportedgraphflags([], opts)
3767 cmdutil.checkunsupportedgraphflags([], opts)
3701 def display(other, chlist, displayer):
3768 def display(other, chlist, displayer):
3702 revdag = cmdutil.graphrevs(other, chlist, opts)
3769 revdag = cmdutil.graphrevs(other, chlist, opts)
3703 showparents = [ctx.node() for ctx in repo[None].parents()]
3770 showparents = [ctx.node() for ctx in repo[None].parents()]
3704 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3771 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3705 graphmod.asciiedges)
3772 graphmod.asciiedges)
3706
3773
3707 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3774 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3708 return 0
3775 return 0
3709
3776
3710 if opts.get('bundle') and opts.get('subrepos'):
3777 if opts.get('bundle') and opts.get('subrepos'):
3711 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3778 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3712
3779
3713 if opts.get('bookmarks'):
3780 if opts.get('bookmarks'):
3714 source, branches = hg.parseurl(ui.expandpath(source),
3781 source, branches = hg.parseurl(ui.expandpath(source),
3715 opts.get('branch'))
3782 opts.get('branch'))
3716 other = hg.peer(repo, opts, source)
3783 other = hg.peer(repo, opts, source)
3717 if 'bookmarks' not in other.listkeys('namespaces'):
3784 if 'bookmarks' not in other.listkeys('namespaces'):
3718 ui.warn(_("remote doesn't support bookmarks\n"))
3785 ui.warn(_("remote doesn't support bookmarks\n"))
3719 return 0
3786 return 0
3720 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3787 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3721 return bookmarks.diff(ui, repo, other)
3788 return bookmarks.diff(ui, repo, other)
3722
3789
3723 repo._subtoppath = ui.expandpath(source)
3790 repo._subtoppath = ui.expandpath(source)
3724 try:
3791 try:
3725 return hg.incoming(ui, repo, source, opts)
3792 return hg.incoming(ui, repo, source, opts)
3726 finally:
3793 finally:
3727 del repo._subtoppath
3794 del repo._subtoppath
3728
3795
3729
3796
3730 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3797 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3731 def init(ui, dest=".", **opts):
3798 def init(ui, dest=".", **opts):
3732 """create a new repository in the given directory
3799 """create a new repository in the given directory
3733
3800
3734 Initialize a new repository in the given directory. If the given
3801 Initialize a new repository in the given directory. If the given
3735 directory does not exist, it will be created.
3802 directory does not exist, it will be created.
3736
3803
3737 If no directory is given, the current directory is used.
3804 If no directory is given, the current directory is used.
3738
3805
3739 It is possible to specify an ``ssh://`` URL as the destination.
3806 It is possible to specify an ``ssh://`` URL as the destination.
3740 See :hg:`help urls` for more information.
3807 See :hg:`help urls` for more information.
3741
3808
3742 Returns 0 on success.
3809 Returns 0 on success.
3743 """
3810 """
3744 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3811 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3745
3812
3746 @command('locate',
3813 @command('locate',
3747 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3814 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3748 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3815 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3749 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3816 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3750 ] + walkopts,
3817 ] + walkopts,
3751 _('[OPTION]... [PATTERN]...'))
3818 _('[OPTION]... [PATTERN]...'))
3752 def locate(ui, repo, *pats, **opts):
3819 def locate(ui, repo, *pats, **opts):
3753 """locate files matching specific patterns
3820 """locate files matching specific patterns
3754
3821
3755 Print files under Mercurial control in the working directory whose
3822 Print files under Mercurial control in the working directory whose
3756 names match the given patterns.
3823 names match the given patterns.
3757
3824
3758 By default, this command searches all directories in the working
3825 By default, this command searches all directories in the working
3759 directory. To search just the current directory and its
3826 directory. To search just the current directory and its
3760 subdirectories, use "--include .".
3827 subdirectories, use "--include .".
3761
3828
3762 If no patterns are given to match, this command prints the names
3829 If no patterns are given to match, this command prints the names
3763 of all files under Mercurial control in the working directory.
3830 of all files under Mercurial control in the working directory.
3764
3831
3765 If you want to feed the output of this command into the "xargs"
3832 If you want to feed the output of this command into the "xargs"
3766 command, use the -0 option to both this command and "xargs". This
3833 command, use the -0 option to both this command and "xargs". This
3767 will avoid the problem of "xargs" treating single filenames that
3834 will avoid the problem of "xargs" treating single filenames that
3768 contain whitespace as multiple filenames.
3835 contain whitespace as multiple filenames.
3769
3836
3770 Returns 0 if a match is found, 1 otherwise.
3837 Returns 0 if a match is found, 1 otherwise.
3771 """
3838 """
3772 end = opts.get('print0') and '\0' or '\n'
3839 end = opts.get('print0') and '\0' or '\n'
3773 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3840 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3774
3841
3775 ret = 1
3842 ret = 1
3776 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3843 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3777 m.bad = lambda x, y: False
3844 m.bad = lambda x, y: False
3778 for abs in repo[rev].walk(m):
3845 for abs in repo[rev].walk(m):
3779 if not rev and abs not in repo.dirstate:
3846 if not rev and abs not in repo.dirstate:
3780 continue
3847 continue
3781 if opts.get('fullpath'):
3848 if opts.get('fullpath'):
3782 ui.write(repo.wjoin(abs), end)
3849 ui.write(repo.wjoin(abs), end)
3783 else:
3850 else:
3784 ui.write(((pats and m.rel(abs)) or abs), end)
3851 ui.write(((pats and m.rel(abs)) or abs), end)
3785 ret = 0
3852 ret = 0
3786
3853
3787 return ret
3854 return ret
3788
3855
3789 @command('^log|history',
3856 @command('^log|history',
3790 [('f', 'follow', None,
3857 [('f', 'follow', None,
3791 _('follow changeset history, or file history across copies and renames')),
3858 _('follow changeset history, or file history across copies and renames')),
3792 ('', 'follow-first', None,
3859 ('', 'follow-first', None,
3793 _('only follow the first parent of merge changesets (DEPRECATED)')),
3860 _('only follow the first parent of merge changesets (DEPRECATED)')),
3794 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3861 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3795 ('C', 'copies', None, _('show copied files')),
3862 ('C', 'copies', None, _('show copied files')),
3796 ('k', 'keyword', [],
3863 ('k', 'keyword', [],
3797 _('do case-insensitive search for a given text'), _('TEXT')),
3864 _('do case-insensitive search for a given text'), _('TEXT')),
3798 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3865 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3799 ('', 'removed', None, _('include revisions where files were removed')),
3866 ('', 'removed', None, _('include revisions where files were removed')),
3800 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3867 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3801 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3868 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3802 ('', 'only-branch', [],
3869 ('', 'only-branch', [],
3803 _('show only changesets within the given named branch (DEPRECATED)'),
3870 _('show only changesets within the given named branch (DEPRECATED)'),
3804 _('BRANCH')),
3871 _('BRANCH')),
3805 ('b', 'branch', [],
3872 ('b', 'branch', [],
3806 _('show changesets within the given named branch'), _('BRANCH')),
3873 _('show changesets within the given named branch'), _('BRANCH')),
3807 ('P', 'prune', [],
3874 ('P', 'prune', [],
3808 _('do not display revision or any of its ancestors'), _('REV')),
3875 _('do not display revision or any of its ancestors'), _('REV')),
3809 ] + logopts + walkopts,
3876 ] + logopts + walkopts,
3810 _('[OPTION]... [FILE]'))
3877 _('[OPTION]... [FILE]'))
3811 def log(ui, repo, *pats, **opts):
3878 def log(ui, repo, *pats, **opts):
3812 """show revision history of entire repository or files
3879 """show revision history of entire repository or files
3813
3880
3814 Print the revision history of the specified files or the entire
3881 Print the revision history of the specified files or the entire
3815 project.
3882 project.
3816
3883
3817 If no revision range is specified, the default is ``tip:0`` unless
3884 If no revision range is specified, the default is ``tip:0`` unless
3818 --follow is set, in which case the working directory parent is
3885 --follow is set, in which case the working directory parent is
3819 used as the starting revision.
3886 used as the starting revision.
3820
3887
3821 File history is shown without following rename or copy history of
3888 File history is shown without following rename or copy history of
3822 files. Use -f/--follow with a filename to follow history across
3889 files. Use -f/--follow with a filename to follow history across
3823 renames and copies. --follow without a filename will only show
3890 renames and copies. --follow without a filename will only show
3824 ancestors or descendants of the starting revision.
3891 ancestors or descendants of the starting revision.
3825
3892
3826 By default this command prints revision number and changeset id,
3893 By default this command prints revision number and changeset id,
3827 tags, non-trivial parents, user, date and time, and a summary for
3894 tags, non-trivial parents, user, date and time, and a summary for
3828 each commit. When the -v/--verbose switch is used, the list of
3895 each commit. When the -v/--verbose switch is used, the list of
3829 changed files and full commit message are shown.
3896 changed files and full commit message are shown.
3830
3897
3831 .. note::
3898 .. note::
3832 log -p/--patch may generate unexpected diff output for merge
3899 log -p/--patch may generate unexpected diff output for merge
3833 changesets, as it will only compare the merge changeset against
3900 changesets, as it will only compare the merge changeset against
3834 its first parent. Also, only files different from BOTH parents
3901 its first parent. Also, only files different from BOTH parents
3835 will appear in files:.
3902 will appear in files:.
3836
3903
3837 .. note::
3904 .. note::
3838 for performance reasons, log FILE may omit duplicate changes
3905 for performance reasons, log FILE may omit duplicate changes
3839 made on branches and will not show deletions. To see all
3906 made on branches and will not show deletions. To see all
3840 changes including duplicates and deletions, use the --removed
3907 changes including duplicates and deletions, use the --removed
3841 switch.
3908 switch.
3842
3909
3843 .. container:: verbose
3910 .. container:: verbose
3844
3911
3845 Some examples:
3912 Some examples:
3846
3913
3847 - changesets with full descriptions and file lists::
3914 - changesets with full descriptions and file lists::
3848
3915
3849 hg log -v
3916 hg log -v
3850
3917
3851 - changesets ancestral to the working directory::
3918 - changesets ancestral to the working directory::
3852
3919
3853 hg log -f
3920 hg log -f
3854
3921
3855 - last 10 commits on the current branch::
3922 - last 10 commits on the current branch::
3856
3923
3857 hg log -l 10 -b .
3924 hg log -l 10 -b .
3858
3925
3859 - changesets showing all modifications of a file, including removals::
3926 - changesets showing all modifications of a file, including removals::
3860
3927
3861 hg log --removed file.c
3928 hg log --removed file.c
3862
3929
3863 - all changesets that touch a directory, with diffs, excluding merges::
3930 - all changesets that touch a directory, with diffs, excluding merges::
3864
3931
3865 hg log -Mp lib/
3932 hg log -Mp lib/
3866
3933
3867 - all revision numbers that match a keyword::
3934 - all revision numbers that match a keyword::
3868
3935
3869 hg log -k bug --template "{rev}\\n"
3936 hg log -k bug --template "{rev}\\n"
3870
3937
3871 - check if a given changeset is included is a tagged release::
3938 - check if a given changeset is included is a tagged release::
3872
3939
3873 hg log -r "a21ccf and ancestor(1.9)"
3940 hg log -r "a21ccf and ancestor(1.9)"
3874
3941
3875 - find all changesets by some user in a date range::
3942 - find all changesets by some user in a date range::
3876
3943
3877 hg log -k alice -d "may 2008 to jul 2008"
3944 hg log -k alice -d "may 2008 to jul 2008"
3878
3945
3879 - summary of all changesets after the last tag::
3946 - summary of all changesets after the last tag::
3880
3947
3881 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3948 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3882
3949
3883 See :hg:`help dates` for a list of formats valid for -d/--date.
3950 See :hg:`help dates` for a list of formats valid for -d/--date.
3884
3951
3885 See :hg:`help revisions` and :hg:`help revsets` for more about
3952 See :hg:`help revisions` and :hg:`help revsets` for more about
3886 specifying revisions.
3953 specifying revisions.
3887
3954
3888 See :hg:`help templates` for more about pre-packaged styles and
3955 See :hg:`help templates` for more about pre-packaged styles and
3889 specifying custom templates.
3956 specifying custom templates.
3890
3957
3891 Returns 0 on success.
3958 Returns 0 on success.
3892 """
3959 """
3893 if opts.get('graph'):
3960 if opts.get('graph'):
3894 return cmdutil.graphlog(ui, repo, *pats, **opts)
3961 return cmdutil.graphlog(ui, repo, *pats, **opts)
3895
3962
3896 matchfn = scmutil.match(repo[None], pats, opts)
3963 matchfn = scmutil.match(repo[None], pats, opts)
3897 limit = cmdutil.loglimit(opts)
3964 limit = cmdutil.loglimit(opts)
3898 count = 0
3965 count = 0
3899
3966
3900 getrenamed, endrev = None, None
3967 getrenamed, endrev = None, None
3901 if opts.get('copies'):
3968 if opts.get('copies'):
3902 if opts.get('rev'):
3969 if opts.get('rev'):
3903 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3970 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3904 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3971 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3905
3972
3906 df = False
3973 df = False
3907 if opts.get("date"):
3974 if opts.get("date"):
3908 df = util.matchdate(opts["date"])
3975 df = util.matchdate(opts["date"])
3909
3976
3910 branches = opts.get('branch', []) + opts.get('only_branch', [])
3977 branches = opts.get('branch', []) + opts.get('only_branch', [])
3911 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3978 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3912
3979
3913 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3980 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3914 def prep(ctx, fns):
3981 def prep(ctx, fns):
3915 rev = ctx.rev()
3982 rev = ctx.rev()
3916 parents = [p for p in repo.changelog.parentrevs(rev)
3983 parents = [p for p in repo.changelog.parentrevs(rev)
3917 if p != nullrev]
3984 if p != nullrev]
3918 if opts.get('no_merges') and len(parents) == 2:
3985 if opts.get('no_merges') and len(parents) == 2:
3919 return
3986 return
3920 if opts.get('only_merges') and len(parents) != 2:
3987 if opts.get('only_merges') and len(parents) != 2:
3921 return
3988 return
3922 if opts.get('branch') and ctx.branch() not in opts['branch']:
3989 if opts.get('branch') and ctx.branch() not in opts['branch']:
3923 return
3990 return
3924 if df and not df(ctx.date()[0]):
3991 if df and not df(ctx.date()[0]):
3925 return
3992 return
3926
3993
3927 lower = encoding.lower
3994 lower = encoding.lower
3928 if opts.get('user'):
3995 if opts.get('user'):
3929 luser = lower(ctx.user())
3996 luser = lower(ctx.user())
3930 for k in [lower(x) for x in opts['user']]:
3997 for k in [lower(x) for x in opts['user']]:
3931 if (k in luser):
3998 if (k in luser):
3932 break
3999 break
3933 else:
4000 else:
3934 return
4001 return
3935 if opts.get('keyword'):
4002 if opts.get('keyword'):
3936 luser = lower(ctx.user())
4003 luser = lower(ctx.user())
3937 ldesc = lower(ctx.description())
4004 ldesc = lower(ctx.description())
3938 lfiles = lower(" ".join(ctx.files()))
4005 lfiles = lower(" ".join(ctx.files()))
3939 for k in [lower(x) for x in opts['keyword']]:
4006 for k in [lower(x) for x in opts['keyword']]:
3940 if (k in luser or k in ldesc or k in lfiles):
4007 if (k in luser or k in ldesc or k in lfiles):
3941 break
4008 break
3942 else:
4009 else:
3943 return
4010 return
3944
4011
3945 copies = None
4012 copies = None
3946 if getrenamed is not None and rev:
4013 if getrenamed is not None and rev:
3947 copies = []
4014 copies = []
3948 for fn in ctx.files():
4015 for fn in ctx.files():
3949 rename = getrenamed(fn, rev)
4016 rename = getrenamed(fn, rev)
3950 if rename:
4017 if rename:
3951 copies.append((fn, rename[0]))
4018 copies.append((fn, rename[0]))
3952
4019
3953 revmatchfn = None
4020 revmatchfn = None
3954 if opts.get('patch') or opts.get('stat'):
4021 if opts.get('patch') or opts.get('stat'):
3955 if opts.get('follow') or opts.get('follow_first'):
4022 if opts.get('follow') or opts.get('follow_first'):
3956 # note: this might be wrong when following through merges
4023 # note: this might be wrong when following through merges
3957 revmatchfn = scmutil.match(repo[None], fns, default='path')
4024 revmatchfn = scmutil.match(repo[None], fns, default='path')
3958 else:
4025 else:
3959 revmatchfn = matchfn
4026 revmatchfn = matchfn
3960
4027
3961 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4028 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3962
4029
3963 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4030 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3964 if displayer.flush(ctx.rev()):
4031 if displayer.flush(ctx.rev()):
3965 count += 1
4032 count += 1
3966 if count == limit:
4033 if count == limit:
3967 break
4034 break
3968 displayer.close()
4035 displayer.close()
3969
4036
3970 @command('manifest',
4037 @command('manifest',
3971 [('r', 'rev', '', _('revision to display'), _('REV')),
4038 [('r', 'rev', '', _('revision to display'), _('REV')),
3972 ('', 'all', False, _("list files from all revisions"))],
4039 ('', 'all', False, _("list files from all revisions"))],
3973 _('[-r REV]'))
4040 _('[-r REV]'))
3974 def manifest(ui, repo, node=None, rev=None, **opts):
4041 def manifest(ui, repo, node=None, rev=None, **opts):
3975 """output the current or given revision of the project manifest
4042 """output the current or given revision of the project manifest
3976
4043
3977 Print a list of version controlled files for the given revision.
4044 Print a list of version controlled files for the given revision.
3978 If no revision is given, the first parent of the working directory
4045 If no revision is given, the first parent of the working directory
3979 is used, or the null revision if no revision is checked out.
4046 is used, or the null revision if no revision is checked out.
3980
4047
3981 With -v, print file permissions, symlink and executable bits.
4048 With -v, print file permissions, symlink and executable bits.
3982 With --debug, print file revision hashes.
4049 With --debug, print file revision hashes.
3983
4050
3984 If option --all is specified, the list of all files from all revisions
4051 If option --all is specified, the list of all files from all revisions
3985 is printed. This includes deleted and renamed files.
4052 is printed. This includes deleted and renamed files.
3986
4053
3987 Returns 0 on success.
4054 Returns 0 on success.
3988 """
4055 """
3989
4056
3990 fm = ui.formatter('manifest', opts)
4057 fm = ui.formatter('manifest', opts)
3991
4058
3992 if opts.get('all'):
4059 if opts.get('all'):
3993 if rev or node:
4060 if rev or node:
3994 raise util.Abort(_("can't specify a revision with --all"))
4061 raise util.Abort(_("can't specify a revision with --all"))
3995
4062
3996 res = []
4063 res = []
3997 prefix = "data/"
4064 prefix = "data/"
3998 suffix = ".i"
4065 suffix = ".i"
3999 plen = len(prefix)
4066 plen = len(prefix)
4000 slen = len(suffix)
4067 slen = len(suffix)
4001 lock = repo.lock()
4068 lock = repo.lock()
4002 try:
4069 try:
4003 for fn, b, size in repo.store.datafiles():
4070 for fn, b, size in repo.store.datafiles():
4004 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4071 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4005 res.append(fn[plen:-slen])
4072 res.append(fn[plen:-slen])
4006 finally:
4073 finally:
4007 lock.release()
4074 lock.release()
4008 for f in res:
4075 for f in res:
4009 fm.startitem()
4076 fm.startitem()
4010 fm.write("path", '%s\n', f)
4077 fm.write("path", '%s\n', f)
4011 fm.end()
4078 fm.end()
4012 return
4079 return
4013
4080
4014 if rev and node:
4081 if rev and node:
4015 raise util.Abort(_("please specify just one revision"))
4082 raise util.Abort(_("please specify just one revision"))
4016
4083
4017 if not node:
4084 if not node:
4018 node = rev
4085 node = rev
4019
4086
4020 char = {'l': '@', 'x': '*', '': ''}
4087 char = {'l': '@', 'x': '*', '': ''}
4021 mode = {'l': '644', 'x': '755', '': '644'}
4088 mode = {'l': '644', 'x': '755', '': '644'}
4022 ctx = scmutil.revsingle(repo, node)
4089 ctx = scmutil.revsingle(repo, node)
4023 mf = ctx.manifest()
4090 mf = ctx.manifest()
4024 for f in ctx:
4091 for f in ctx:
4025 fm.startitem()
4092 fm.startitem()
4026 fl = ctx[f].flags()
4093 fl = ctx[f].flags()
4027 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4094 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4028 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4095 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4029 fm.write('path', '%s\n', f)
4096 fm.write('path', '%s\n', f)
4030 fm.end()
4097 fm.end()
4031
4098
4032 @command('^merge',
4099 @command('^merge',
4033 [('f', 'force', None, _('force a merge with outstanding changes')),
4100 [('f', 'force', None, _('force a merge with outstanding changes')),
4034 ('r', 'rev', '', _('revision to merge'), _('REV')),
4101 ('r', 'rev', '', _('revision to merge'), _('REV')),
4035 ('P', 'preview', None,
4102 ('P', 'preview', None,
4036 _('review revisions to merge (no merge is performed)'))
4103 _('review revisions to merge (no merge is performed)'))
4037 ] + mergetoolopts,
4104 ] + mergetoolopts,
4038 _('[-P] [-f] [[-r] REV]'))
4105 _('[-P] [-f] [[-r] REV]'))
4039 def merge(ui, repo, node=None, **opts):
4106 def merge(ui, repo, node=None, **opts):
4040 """merge working directory with another revision
4107 """merge working directory with another revision
4041
4108
4042 The current working directory is updated with all changes made in
4109 The current working directory is updated with all changes made in
4043 the requested revision since the last common predecessor revision.
4110 the requested revision since the last common predecessor revision.
4044
4111
4045 Files that changed between either parent are marked as changed for
4112 Files that changed between either parent are marked as changed for
4046 the next commit and a commit must be performed before any further
4113 the next commit and a commit must be performed before any further
4047 updates to the repository are allowed. The next commit will have
4114 updates to the repository are allowed. The next commit will have
4048 two parents.
4115 two parents.
4049
4116
4050 ``--tool`` can be used to specify the merge tool used for file
4117 ``--tool`` can be used to specify the merge tool used for file
4051 merges. It overrides the HGMERGE environment variable and your
4118 merges. It overrides the HGMERGE environment variable and your
4052 configuration files. See :hg:`help merge-tools` for options.
4119 configuration files. See :hg:`help merge-tools` for options.
4053
4120
4054 If no revision is specified, the working directory's parent is a
4121 If no revision is specified, the working directory's parent is a
4055 head revision, and the current branch contains exactly one other
4122 head revision, and the current branch contains exactly one other
4056 head, the other head is merged with by default. Otherwise, an
4123 head, the other head is merged with by default. Otherwise, an
4057 explicit revision with which to merge with must be provided.
4124 explicit revision with which to merge with must be provided.
4058
4125
4059 :hg:`resolve` must be used to resolve unresolved files.
4126 :hg:`resolve` must be used to resolve unresolved files.
4060
4127
4061 To undo an uncommitted merge, use :hg:`update --clean .` which
4128 To undo an uncommitted merge, use :hg:`update --clean .` which
4062 will check out a clean copy of the original merge parent, losing
4129 will check out a clean copy of the original merge parent, losing
4063 all changes.
4130 all changes.
4064
4131
4065 Returns 0 on success, 1 if there are unresolved files.
4132 Returns 0 on success, 1 if there are unresolved files.
4066 """
4133 """
4067
4134
4068 if opts.get('rev') and node:
4135 if opts.get('rev') and node:
4069 raise util.Abort(_("please specify just one revision"))
4136 raise util.Abort(_("please specify just one revision"))
4070 if not node:
4137 if not node:
4071 node = opts.get('rev')
4138 node = opts.get('rev')
4072
4139
4073 if node:
4140 if node:
4074 node = scmutil.revsingle(repo, node).node()
4141 node = scmutil.revsingle(repo, node).node()
4075
4142
4076 if not node and repo._bookmarkcurrent:
4143 if not node and repo._bookmarkcurrent:
4077 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4144 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4078 curhead = repo[repo._bookmarkcurrent].node()
4145 curhead = repo[repo._bookmarkcurrent].node()
4079 if len(bmheads) == 2:
4146 if len(bmheads) == 2:
4080 if curhead == bmheads[0]:
4147 if curhead == bmheads[0]:
4081 node = bmheads[1]
4148 node = bmheads[1]
4082 else:
4149 else:
4083 node = bmheads[0]
4150 node = bmheads[0]
4084 elif len(bmheads) > 2:
4151 elif len(bmheads) > 2:
4085 raise util.Abort(_("multiple matching bookmarks to merge - "
4152 raise util.Abort(_("multiple matching bookmarks to merge - "
4086 "please merge with an explicit rev or bookmark"),
4153 "please merge with an explicit rev or bookmark"),
4087 hint=_("run 'hg heads' to see all heads"))
4154 hint=_("run 'hg heads' to see all heads"))
4088 elif len(bmheads) <= 1:
4155 elif len(bmheads) <= 1:
4089 raise util.Abort(_("no matching bookmark to merge - "
4156 raise util.Abort(_("no matching bookmark to merge - "
4090 "please merge with an explicit rev or bookmark"),
4157 "please merge with an explicit rev or bookmark"),
4091 hint=_("run 'hg heads' to see all heads"))
4158 hint=_("run 'hg heads' to see all heads"))
4092
4159
4093 if not node and not repo._bookmarkcurrent:
4160 if not node and not repo._bookmarkcurrent:
4094 branch = repo[None].branch()
4161 branch = repo[None].branch()
4095 bheads = repo.branchheads(branch)
4162 bheads = repo.branchheads(branch)
4096 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4163 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4097
4164
4098 if len(nbhs) > 2:
4165 if len(nbhs) > 2:
4099 raise util.Abort(_("branch '%s' has %d heads - "
4166 raise util.Abort(_("branch '%s' has %d heads - "
4100 "please merge with an explicit rev")
4167 "please merge with an explicit rev")
4101 % (branch, len(bheads)),
4168 % (branch, len(bheads)),
4102 hint=_("run 'hg heads .' to see heads"))
4169 hint=_("run 'hg heads .' to see heads"))
4103
4170
4104 parent = repo.dirstate.p1()
4171 parent = repo.dirstate.p1()
4105 if len(nbhs) <= 1:
4172 if len(nbhs) <= 1:
4106 if len(bheads) > 1:
4173 if len(bheads) > 1:
4107 raise util.Abort(_("heads are bookmarked - "
4174 raise util.Abort(_("heads are bookmarked - "
4108 "please merge with an explicit rev"),
4175 "please merge with an explicit rev"),
4109 hint=_("run 'hg heads' to see all heads"))
4176 hint=_("run 'hg heads' to see all heads"))
4110 if len(repo.heads()) > 1:
4177 if len(repo.heads()) > 1:
4111 raise util.Abort(_("branch '%s' has one head - "
4178 raise util.Abort(_("branch '%s' has one head - "
4112 "please merge with an explicit rev")
4179 "please merge with an explicit rev")
4113 % branch,
4180 % branch,
4114 hint=_("run 'hg heads' to see all heads"))
4181 hint=_("run 'hg heads' to see all heads"))
4115 msg, hint = _('nothing to merge'), None
4182 msg, hint = _('nothing to merge'), None
4116 if parent != repo.lookup(branch):
4183 if parent != repo.lookup(branch):
4117 hint = _("use 'hg update' instead")
4184 hint = _("use 'hg update' instead")
4118 raise util.Abort(msg, hint=hint)
4185 raise util.Abort(msg, hint=hint)
4119
4186
4120 if parent not in bheads:
4187 if parent not in bheads:
4121 raise util.Abort(_('working directory not at a head revision'),
4188 raise util.Abort(_('working directory not at a head revision'),
4122 hint=_("use 'hg update' or merge with an "
4189 hint=_("use 'hg update' or merge with an "
4123 "explicit revision"))
4190 "explicit revision"))
4124 if parent == nbhs[0]:
4191 if parent == nbhs[0]:
4125 node = nbhs[-1]
4192 node = nbhs[-1]
4126 else:
4193 else:
4127 node = nbhs[0]
4194 node = nbhs[0]
4128
4195
4129 if opts.get('preview'):
4196 if opts.get('preview'):
4130 # find nodes that are ancestors of p2 but not of p1
4197 # find nodes that are ancestors of p2 but not of p1
4131 p1 = repo.lookup('.')
4198 p1 = repo.lookup('.')
4132 p2 = repo.lookup(node)
4199 p2 = repo.lookup(node)
4133 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4200 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4134
4201
4135 displayer = cmdutil.show_changeset(ui, repo, opts)
4202 displayer = cmdutil.show_changeset(ui, repo, opts)
4136 for node in nodes:
4203 for node in nodes:
4137 displayer.show(repo[node])
4204 displayer.show(repo[node])
4138 displayer.close()
4205 displayer.close()
4139 return 0
4206 return 0
4140
4207
4141 try:
4208 try:
4142 # ui.forcemerge is an internal variable, do not document
4209 # ui.forcemerge is an internal variable, do not document
4143 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4210 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4144 return hg.merge(repo, node, force=opts.get('force'))
4211 return hg.merge(repo, node, force=opts.get('force'))
4145 finally:
4212 finally:
4146 ui.setconfig('ui', 'forcemerge', '')
4213 ui.setconfig('ui', 'forcemerge', '')
4147
4214
4148 @command('outgoing|out',
4215 @command('outgoing|out',
4149 [('f', 'force', None, _('run even when the destination is unrelated')),
4216 [('f', 'force', None, _('run even when the destination is unrelated')),
4150 ('r', 'rev', [],
4217 ('r', 'rev', [],
4151 _('a changeset intended to be included in the destination'), _('REV')),
4218 _('a changeset intended to be included in the destination'), _('REV')),
4152 ('n', 'newest-first', None, _('show newest record first')),
4219 ('n', 'newest-first', None, _('show newest record first')),
4153 ('B', 'bookmarks', False, _('compare bookmarks')),
4220 ('B', 'bookmarks', False, _('compare bookmarks')),
4154 ('b', 'branch', [], _('a specific branch you would like to push'),
4221 ('b', 'branch', [], _('a specific branch you would like to push'),
4155 _('BRANCH')),
4222 _('BRANCH')),
4156 ] + logopts + remoteopts + subrepoopts,
4223 ] + logopts + remoteopts + subrepoopts,
4157 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4224 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4158 def outgoing(ui, repo, dest=None, **opts):
4225 def outgoing(ui, repo, dest=None, **opts):
4159 """show changesets not found in the destination
4226 """show changesets not found in the destination
4160
4227
4161 Show changesets not found in the specified destination repository
4228 Show changesets not found in the specified destination repository
4162 or the default push location. These are the changesets that would
4229 or the default push location. These are the changesets that would
4163 be pushed if a push was requested.
4230 be pushed if a push was requested.
4164
4231
4165 See pull for details of valid destination formats.
4232 See pull for details of valid destination formats.
4166
4233
4167 Returns 0 if there are outgoing changes, 1 otherwise.
4234 Returns 0 if there are outgoing changes, 1 otherwise.
4168 """
4235 """
4169 if opts.get('graph'):
4236 if opts.get('graph'):
4170 cmdutil.checkunsupportedgraphflags([], opts)
4237 cmdutil.checkunsupportedgraphflags([], opts)
4171 o = hg._outgoing(ui, repo, dest, opts)
4238 o = hg._outgoing(ui, repo, dest, opts)
4172 if o is None:
4239 if o is None:
4173 return
4240 return
4174
4241
4175 revdag = cmdutil.graphrevs(repo, o, opts)
4242 revdag = cmdutil.graphrevs(repo, o, opts)
4176 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4243 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4177 showparents = [ctx.node() for ctx in repo[None].parents()]
4244 showparents = [ctx.node() for ctx in repo[None].parents()]
4178 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4245 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4179 graphmod.asciiedges)
4246 graphmod.asciiedges)
4180 return 0
4247 return 0
4181
4248
4182 if opts.get('bookmarks'):
4249 if opts.get('bookmarks'):
4183 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4250 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4184 dest, branches = hg.parseurl(dest, opts.get('branch'))
4251 dest, branches = hg.parseurl(dest, opts.get('branch'))
4185 other = hg.peer(repo, opts, dest)
4252 other = hg.peer(repo, opts, dest)
4186 if 'bookmarks' not in other.listkeys('namespaces'):
4253 if 'bookmarks' not in other.listkeys('namespaces'):
4187 ui.warn(_("remote doesn't support bookmarks\n"))
4254 ui.warn(_("remote doesn't support bookmarks\n"))
4188 return 0
4255 return 0
4189 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4256 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4190 return bookmarks.diff(ui, other, repo)
4257 return bookmarks.diff(ui, other, repo)
4191
4258
4192 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4259 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4193 try:
4260 try:
4194 return hg.outgoing(ui, repo, dest, opts)
4261 return hg.outgoing(ui, repo, dest, opts)
4195 finally:
4262 finally:
4196 del repo._subtoppath
4263 del repo._subtoppath
4197
4264
4198 @command('parents',
4265 @command('parents',
4199 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4266 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4200 ] + templateopts,
4267 ] + templateopts,
4201 _('[-r REV] [FILE]'))
4268 _('[-r REV] [FILE]'))
4202 def parents(ui, repo, file_=None, **opts):
4269 def parents(ui, repo, file_=None, **opts):
4203 """show the parents of the working directory or revision
4270 """show the parents of the working directory or revision
4204
4271
4205 Print the working directory's parent revisions. If a revision is
4272 Print the working directory's parent revisions. If a revision is
4206 given via -r/--rev, the parent of that revision will be printed.
4273 given via -r/--rev, the parent of that revision will be printed.
4207 If a file argument is given, the revision in which the file was
4274 If a file argument is given, the revision in which the file was
4208 last changed (before the working directory revision or the
4275 last changed (before the working directory revision or the
4209 argument to --rev if given) is printed.
4276 argument to --rev if given) is printed.
4210
4277
4211 Returns 0 on success.
4278 Returns 0 on success.
4212 """
4279 """
4213
4280
4214 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4281 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4215
4282
4216 if file_:
4283 if file_:
4217 m = scmutil.match(ctx, (file_,), opts)
4284 m = scmutil.match(ctx, (file_,), opts)
4218 if m.anypats() or len(m.files()) != 1:
4285 if m.anypats() or len(m.files()) != 1:
4219 raise util.Abort(_('can only specify an explicit filename'))
4286 raise util.Abort(_('can only specify an explicit filename'))
4220 file_ = m.files()[0]
4287 file_ = m.files()[0]
4221 filenodes = []
4288 filenodes = []
4222 for cp in ctx.parents():
4289 for cp in ctx.parents():
4223 if not cp:
4290 if not cp:
4224 continue
4291 continue
4225 try:
4292 try:
4226 filenodes.append(cp.filenode(file_))
4293 filenodes.append(cp.filenode(file_))
4227 except error.LookupError:
4294 except error.LookupError:
4228 pass
4295 pass
4229 if not filenodes:
4296 if not filenodes:
4230 raise util.Abort(_("'%s' not found in manifest!") % file_)
4297 raise util.Abort(_("'%s' not found in manifest!") % file_)
4231 fl = repo.file(file_)
4298 fl = repo.file(file_)
4232 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4299 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4233 else:
4300 else:
4234 p = [cp.node() for cp in ctx.parents()]
4301 p = [cp.node() for cp in ctx.parents()]
4235
4302
4236 displayer = cmdutil.show_changeset(ui, repo, opts)
4303 displayer = cmdutil.show_changeset(ui, repo, opts)
4237 for n in p:
4304 for n in p:
4238 if n != nullid:
4305 if n != nullid:
4239 displayer.show(repo[n])
4306 displayer.show(repo[n])
4240 displayer.close()
4307 displayer.close()
4241
4308
4242 @command('paths', [], _('[NAME]'))
4309 @command('paths', [], _('[NAME]'))
4243 def paths(ui, repo, search=None):
4310 def paths(ui, repo, search=None):
4244 """show aliases for remote repositories
4311 """show aliases for remote repositories
4245
4312
4246 Show definition of symbolic path name NAME. If no name is given,
4313 Show definition of symbolic path name NAME. If no name is given,
4247 show definition of all available names.
4314 show definition of all available names.
4248
4315
4249 Option -q/--quiet suppresses all output when searching for NAME
4316 Option -q/--quiet suppresses all output when searching for NAME
4250 and shows only the path names when listing all definitions.
4317 and shows only the path names when listing all definitions.
4251
4318
4252 Path names are defined in the [paths] section of your
4319 Path names are defined in the [paths] section of your
4253 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4320 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4254 repository, ``.hg/hgrc`` is used, too.
4321 repository, ``.hg/hgrc`` is used, too.
4255
4322
4256 The path names ``default`` and ``default-push`` have a special
4323 The path names ``default`` and ``default-push`` have a special
4257 meaning. When performing a push or pull operation, they are used
4324 meaning. When performing a push or pull operation, they are used
4258 as fallbacks if no location is specified on the command-line.
4325 as fallbacks if no location is specified on the command-line.
4259 When ``default-push`` is set, it will be used for push and
4326 When ``default-push`` is set, it will be used for push and
4260 ``default`` will be used for pull; otherwise ``default`` is used
4327 ``default`` will be used for pull; otherwise ``default`` is used
4261 as the fallback for both. When cloning a repository, the clone
4328 as the fallback for both. When cloning a repository, the clone
4262 source is written as ``default`` in ``.hg/hgrc``. Note that
4329 source is written as ``default`` in ``.hg/hgrc``. Note that
4263 ``default`` and ``default-push`` apply to all inbound (e.g.
4330 ``default`` and ``default-push`` apply to all inbound (e.g.
4264 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4331 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4265 :hg:`bundle`) operations.
4332 :hg:`bundle`) operations.
4266
4333
4267 See :hg:`help urls` for more information.
4334 See :hg:`help urls` for more information.
4268
4335
4269 Returns 0 on success.
4336 Returns 0 on success.
4270 """
4337 """
4271 if search:
4338 if search:
4272 for name, path in ui.configitems("paths"):
4339 for name, path in ui.configitems("paths"):
4273 if name == search:
4340 if name == search:
4274 ui.status("%s\n" % util.hidepassword(path))
4341 ui.status("%s\n" % util.hidepassword(path))
4275 return
4342 return
4276 if not ui.quiet:
4343 if not ui.quiet:
4277 ui.warn(_("not found!\n"))
4344 ui.warn(_("not found!\n"))
4278 return 1
4345 return 1
4279 else:
4346 else:
4280 for name, path in ui.configitems("paths"):
4347 for name, path in ui.configitems("paths"):
4281 if ui.quiet:
4348 if ui.quiet:
4282 ui.write("%s\n" % name)
4349 ui.write("%s\n" % name)
4283 else:
4350 else:
4284 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4351 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4285
4352
4286 @command('phase',
4353 @command('phase',
4287 [('p', 'public', False, _('set changeset phase to public')),
4354 [('p', 'public', False, _('set changeset phase to public')),
4288 ('d', 'draft', False, _('set changeset phase to draft')),
4355 ('d', 'draft', False, _('set changeset phase to draft')),
4289 ('s', 'secret', False, _('set changeset phase to secret')),
4356 ('s', 'secret', False, _('set changeset phase to secret')),
4290 ('f', 'force', False, _('allow to move boundary backward')),
4357 ('f', 'force', False, _('allow to move boundary backward')),
4291 ('r', 'rev', [], _('target revision'), _('REV')),
4358 ('r', 'rev', [], _('target revision'), _('REV')),
4292 ],
4359 ],
4293 _('[-p|-d|-s] [-f] [-r] REV...'))
4360 _('[-p|-d|-s] [-f] [-r] REV...'))
4294 def phase(ui, repo, *revs, **opts):
4361 def phase(ui, repo, *revs, **opts):
4295 """set or show the current phase name
4362 """set or show the current phase name
4296
4363
4297 With no argument, show the phase name of specified revisions.
4364 With no argument, show the phase name of specified revisions.
4298
4365
4299 With one of -p/--public, -d/--draft or -s/--secret, change the
4366 With one of -p/--public, -d/--draft or -s/--secret, change the
4300 phase value of the specified revisions.
4367 phase value of the specified revisions.
4301
4368
4302 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4369 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4303 lower phase to an higher phase. Phases are ordered as follows::
4370 lower phase to an higher phase. Phases are ordered as follows::
4304
4371
4305 public < draft < secret
4372 public < draft < secret
4306
4373
4307 Return 0 on success, 1 if no phases were changed or some could not
4374 Return 0 on success, 1 if no phases were changed or some could not
4308 be changed.
4375 be changed.
4309 """
4376 """
4310 # search for a unique phase argument
4377 # search for a unique phase argument
4311 targetphase = None
4378 targetphase = None
4312 for idx, name in enumerate(phases.phasenames):
4379 for idx, name in enumerate(phases.phasenames):
4313 if opts[name]:
4380 if opts[name]:
4314 if targetphase is not None:
4381 if targetphase is not None:
4315 raise util.Abort(_('only one phase can be specified'))
4382 raise util.Abort(_('only one phase can be specified'))
4316 targetphase = idx
4383 targetphase = idx
4317
4384
4318 # look for specified revision
4385 # look for specified revision
4319 revs = list(revs)
4386 revs = list(revs)
4320 revs.extend(opts['rev'])
4387 revs.extend(opts['rev'])
4321 if not revs:
4388 if not revs:
4322 raise util.Abort(_('no revisions specified'))
4389 raise util.Abort(_('no revisions specified'))
4323
4390
4324 revs = scmutil.revrange(repo, revs)
4391 revs = scmutil.revrange(repo, revs)
4325
4392
4326 lock = None
4393 lock = None
4327 ret = 0
4394 ret = 0
4328 if targetphase is None:
4395 if targetphase is None:
4329 # display
4396 # display
4330 for r in revs:
4397 for r in revs:
4331 ctx = repo[r]
4398 ctx = repo[r]
4332 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4399 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4333 else:
4400 else:
4334 lock = repo.lock()
4401 lock = repo.lock()
4335 try:
4402 try:
4336 # set phase
4403 # set phase
4337 if not revs:
4404 if not revs:
4338 raise util.Abort(_('empty revision set'))
4405 raise util.Abort(_('empty revision set'))
4339 nodes = [repo[r].node() for r in revs]
4406 nodes = [repo[r].node() for r in revs]
4340 olddata = repo._phasecache.getphaserevs(repo)[:]
4407 olddata = repo._phasecache.getphaserevs(repo)[:]
4341 phases.advanceboundary(repo, targetphase, nodes)
4408 phases.advanceboundary(repo, targetphase, nodes)
4342 if opts['force']:
4409 if opts['force']:
4343 phases.retractboundary(repo, targetphase, nodes)
4410 phases.retractboundary(repo, targetphase, nodes)
4344 finally:
4411 finally:
4345 lock.release()
4412 lock.release()
4346 # moving revision from public to draft may hide them
4413 # moving revision from public to draft may hide them
4347 # We have to check result on an unfiltered repository
4414 # We have to check result on an unfiltered repository
4348 unfi = repo.unfiltered()
4415 unfi = repo.unfiltered()
4349 newdata = repo._phasecache.getphaserevs(unfi)
4416 newdata = repo._phasecache.getphaserevs(unfi)
4350 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4417 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4351 cl = unfi.changelog
4418 cl = unfi.changelog
4352 rejected = [n for n in nodes
4419 rejected = [n for n in nodes
4353 if newdata[cl.rev(n)] < targetphase]
4420 if newdata[cl.rev(n)] < targetphase]
4354 if rejected:
4421 if rejected:
4355 ui.warn(_('cannot move %i changesets to a more permissive '
4422 ui.warn(_('cannot move %i changesets to a more permissive '
4356 'phase, use --force\n') % len(rejected))
4423 'phase, use --force\n') % len(rejected))
4357 ret = 1
4424 ret = 1
4358 if changes:
4425 if changes:
4359 msg = _('phase changed for %i changesets\n') % changes
4426 msg = _('phase changed for %i changesets\n') % changes
4360 if ret:
4427 if ret:
4361 ui.status(msg)
4428 ui.status(msg)
4362 else:
4429 else:
4363 ui.note(msg)
4430 ui.note(msg)
4364 else:
4431 else:
4365 ui.warn(_('no phases changed\n'))
4432 ui.warn(_('no phases changed\n'))
4366 ret = 1
4433 ret = 1
4367 return ret
4434 return ret
4368
4435
4369 def postincoming(ui, repo, modheads, optupdate, checkout):
4436 def postincoming(ui, repo, modheads, optupdate, checkout):
4370 if modheads == 0:
4437 if modheads == 0:
4371 return
4438 return
4372 if optupdate:
4439 if optupdate:
4373 movemarkfrom = repo['.'].node()
4440 movemarkfrom = repo['.'].node()
4374 try:
4441 try:
4375 ret = hg.update(repo, checkout)
4442 ret = hg.update(repo, checkout)
4376 except util.Abort, inst:
4443 except util.Abort, inst:
4377 ui.warn(_("not updating: %s\n") % str(inst))
4444 ui.warn(_("not updating: %s\n") % str(inst))
4378 return 0
4445 return 0
4379 if not ret and not checkout:
4446 if not ret and not checkout:
4380 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4447 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4381 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4448 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4382 return ret
4449 return ret
4383 if modheads > 1:
4450 if modheads > 1:
4384 currentbranchheads = len(repo.branchheads())
4451 currentbranchheads = len(repo.branchheads())
4385 if currentbranchheads == modheads:
4452 if currentbranchheads == modheads:
4386 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4453 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4387 elif currentbranchheads > 1:
4454 elif currentbranchheads > 1:
4388 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4455 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4389 "merge)\n"))
4456 "merge)\n"))
4390 else:
4457 else:
4391 ui.status(_("(run 'hg heads' to see heads)\n"))
4458 ui.status(_("(run 'hg heads' to see heads)\n"))
4392 else:
4459 else:
4393 ui.status(_("(run 'hg update' to get a working copy)\n"))
4460 ui.status(_("(run 'hg update' to get a working copy)\n"))
4394
4461
4395 @command('^pull',
4462 @command('^pull',
4396 [('u', 'update', None,
4463 [('u', 'update', None,
4397 _('update to new branch head if changesets were pulled')),
4464 _('update to new branch head if changesets were pulled')),
4398 ('f', 'force', None, _('run even when remote repository is unrelated')),
4465 ('f', 'force', None, _('run even when remote repository is unrelated')),
4399 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4466 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4400 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4467 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4401 ('b', 'branch', [], _('a specific branch you would like to pull'),
4468 ('b', 'branch', [], _('a specific branch you would like to pull'),
4402 _('BRANCH')),
4469 _('BRANCH')),
4403 ] + remoteopts,
4470 ] + remoteopts,
4404 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4471 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4405 def pull(ui, repo, source="default", **opts):
4472 def pull(ui, repo, source="default", **opts):
4406 """pull changes from the specified source
4473 """pull changes from the specified source
4407
4474
4408 Pull changes from a remote repository to a local one.
4475 Pull changes from a remote repository to a local one.
4409
4476
4410 This finds all changes from the repository at the specified path
4477 This finds all changes from the repository at the specified path
4411 or URL and adds them to a local repository (the current one unless
4478 or URL and adds them to a local repository (the current one unless
4412 -R is specified). By default, this does not update the copy of the
4479 -R is specified). By default, this does not update the copy of the
4413 project in the working directory.
4480 project in the working directory.
4414
4481
4415 Use :hg:`incoming` if you want to see what would have been added
4482 Use :hg:`incoming` if you want to see what would have been added
4416 by a pull at the time you issued this command. If you then decide
4483 by a pull at the time you issued this command. If you then decide
4417 to add those changes to the repository, you should use :hg:`pull
4484 to add those changes to the repository, you should use :hg:`pull
4418 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4485 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4419
4486
4420 If SOURCE is omitted, the 'default' path will be used.
4487 If SOURCE is omitted, the 'default' path will be used.
4421 See :hg:`help urls` for more information.
4488 See :hg:`help urls` for more information.
4422
4489
4423 Returns 0 on success, 1 if an update had unresolved files.
4490 Returns 0 on success, 1 if an update had unresolved files.
4424 """
4491 """
4425 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4492 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4426 other = hg.peer(repo, opts, source)
4493 other = hg.peer(repo, opts, source)
4427 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4494 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4428 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4495 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4429
4496
4430 if opts.get('bookmark'):
4497 if opts.get('bookmark'):
4431 if not revs:
4498 if not revs:
4432 revs = []
4499 revs = []
4433 rb = other.listkeys('bookmarks')
4500 rb = other.listkeys('bookmarks')
4434 for b in opts['bookmark']:
4501 for b in opts['bookmark']:
4435 if b not in rb:
4502 if b not in rb:
4436 raise util.Abort(_('remote bookmark %s not found!') % b)
4503 raise util.Abort(_('remote bookmark %s not found!') % b)
4437 revs.append(rb[b])
4504 revs.append(rb[b])
4438
4505
4439 if revs:
4506 if revs:
4440 try:
4507 try:
4441 revs = [other.lookup(rev) for rev in revs]
4508 revs = [other.lookup(rev) for rev in revs]
4442 except error.CapabilityError:
4509 except error.CapabilityError:
4443 err = _("other repository doesn't support revision lookup, "
4510 err = _("other repository doesn't support revision lookup, "
4444 "so a rev cannot be specified.")
4511 "so a rev cannot be specified.")
4445 raise util.Abort(err)
4512 raise util.Abort(err)
4446
4513
4447 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4514 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4448 bookmarks.updatefromremote(ui, repo, other, source)
4515 bookmarks.updatefromremote(ui, repo, other, source)
4449 if checkout:
4516 if checkout:
4450 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4517 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4451 repo._subtoppath = source
4518 repo._subtoppath = source
4452 try:
4519 try:
4453 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4520 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4454
4521
4455 finally:
4522 finally:
4456 del repo._subtoppath
4523 del repo._subtoppath
4457
4524
4458 # update specified bookmarks
4525 # update specified bookmarks
4459 if opts.get('bookmark'):
4526 if opts.get('bookmark'):
4460 marks = repo._bookmarks
4527 marks = repo._bookmarks
4461 for b in opts['bookmark']:
4528 for b in opts['bookmark']:
4462 # explicit pull overrides local bookmark if any
4529 # explicit pull overrides local bookmark if any
4463 ui.status(_("importing bookmark %s\n") % b)
4530 ui.status(_("importing bookmark %s\n") % b)
4464 marks[b] = repo[rb[b]].node()
4531 marks[b] = repo[rb[b]].node()
4465 marks.write()
4532 marks.write()
4466
4533
4467 return ret
4534 return ret
4468
4535
4469 @command('^push',
4536 @command('^push',
4470 [('f', 'force', None, _('force push')),
4537 [('f', 'force', None, _('force push')),
4471 ('r', 'rev', [],
4538 ('r', 'rev', [],
4472 _('a changeset intended to be included in the destination'),
4539 _('a changeset intended to be included in the destination'),
4473 _('REV')),
4540 _('REV')),
4474 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4541 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4475 ('b', 'branch', [],
4542 ('b', 'branch', [],
4476 _('a specific branch you would like to push'), _('BRANCH')),
4543 _('a specific branch you would like to push'), _('BRANCH')),
4477 ('', 'new-branch', False, _('allow pushing a new branch')),
4544 ('', 'new-branch', False, _('allow pushing a new branch')),
4478 ] + remoteopts,
4545 ] + remoteopts,
4479 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4546 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4480 def push(ui, repo, dest=None, **opts):
4547 def push(ui, repo, dest=None, **opts):
4481 """push changes to the specified destination
4548 """push changes to the specified destination
4482
4549
4483 Push changesets from the local repository to the specified
4550 Push changesets from the local repository to the specified
4484 destination.
4551 destination.
4485
4552
4486 This operation is symmetrical to pull: it is identical to a pull
4553 This operation is symmetrical to pull: it is identical to a pull
4487 in the destination repository from the current one.
4554 in the destination repository from the current one.
4488
4555
4489 By default, push will not allow creation of new heads at the
4556 By default, push will not allow creation of new heads at the
4490 destination, since multiple heads would make it unclear which head
4557 destination, since multiple heads would make it unclear which head
4491 to use. In this situation, it is recommended to pull and merge
4558 to use. In this situation, it is recommended to pull and merge
4492 before pushing.
4559 before pushing.
4493
4560
4494 Use --new-branch if you want to allow push to create a new named
4561 Use --new-branch if you want to allow push to create a new named
4495 branch that is not present at the destination. This allows you to
4562 branch that is not present at the destination. This allows you to
4496 only create a new branch without forcing other changes.
4563 only create a new branch without forcing other changes.
4497
4564
4498 Use -f/--force to override the default behavior and push all
4565 Use -f/--force to override the default behavior and push all
4499 changesets on all branches.
4566 changesets on all branches.
4500
4567
4501 If -r/--rev is used, the specified revision and all its ancestors
4568 If -r/--rev is used, the specified revision and all its ancestors
4502 will be pushed to the remote repository.
4569 will be pushed to the remote repository.
4503
4570
4504 If -B/--bookmark is used, the specified bookmarked revision, its
4571 If -B/--bookmark is used, the specified bookmarked revision, its
4505 ancestors, and the bookmark will be pushed to the remote
4572 ancestors, and the bookmark will be pushed to the remote
4506 repository.
4573 repository.
4507
4574
4508 Please see :hg:`help urls` for important details about ``ssh://``
4575 Please see :hg:`help urls` for important details about ``ssh://``
4509 URLs. If DESTINATION is omitted, a default path will be used.
4576 URLs. If DESTINATION is omitted, a default path will be used.
4510
4577
4511 Returns 0 if push was successful, 1 if nothing to push.
4578 Returns 0 if push was successful, 1 if nothing to push.
4512 """
4579 """
4513
4580
4514 if opts.get('bookmark'):
4581 if opts.get('bookmark'):
4515 for b in opts['bookmark']:
4582 for b in opts['bookmark']:
4516 # translate -B options to -r so changesets get pushed
4583 # translate -B options to -r so changesets get pushed
4517 if b in repo._bookmarks:
4584 if b in repo._bookmarks:
4518 opts.setdefault('rev', []).append(b)
4585 opts.setdefault('rev', []).append(b)
4519 else:
4586 else:
4520 # if we try to push a deleted bookmark, translate it to null
4587 # if we try to push a deleted bookmark, translate it to null
4521 # this lets simultaneous -r, -b options continue working
4588 # this lets simultaneous -r, -b options continue working
4522 opts.setdefault('rev', []).append("null")
4589 opts.setdefault('rev', []).append("null")
4523
4590
4524 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4591 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4525 dest, branches = hg.parseurl(dest, opts.get('branch'))
4592 dest, branches = hg.parseurl(dest, opts.get('branch'))
4526 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4593 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4527 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4594 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4528 other = hg.peer(repo, opts, dest)
4595 other = hg.peer(repo, opts, dest)
4529 if revs:
4596 if revs:
4530 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4597 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4531
4598
4532 repo._subtoppath = dest
4599 repo._subtoppath = dest
4533 try:
4600 try:
4534 # push subrepos depth-first for coherent ordering
4601 # push subrepos depth-first for coherent ordering
4535 c = repo['']
4602 c = repo['']
4536 subs = c.substate # only repos that are committed
4603 subs = c.substate # only repos that are committed
4537 for s in sorted(subs):
4604 for s in sorted(subs):
4538 if c.sub(s).push(opts) == 0:
4605 if c.sub(s).push(opts) == 0:
4539 return False
4606 return False
4540 finally:
4607 finally:
4541 del repo._subtoppath
4608 del repo._subtoppath
4542 result = repo.push(other, opts.get('force'), revs=revs,
4609 result = repo.push(other, opts.get('force'), revs=revs,
4543 newbranch=opts.get('new_branch'))
4610 newbranch=opts.get('new_branch'))
4544
4611
4545 result = not result
4612 result = not result
4546
4613
4547 if opts.get('bookmark'):
4614 if opts.get('bookmark'):
4548 rb = other.listkeys('bookmarks')
4615 rb = other.listkeys('bookmarks')
4549 for b in opts['bookmark']:
4616 for b in opts['bookmark']:
4550 # explicit push overrides remote bookmark if any
4617 # explicit push overrides remote bookmark if any
4551 if b in repo._bookmarks:
4618 if b in repo._bookmarks:
4552 ui.status(_("exporting bookmark %s\n") % b)
4619 ui.status(_("exporting bookmark %s\n") % b)
4553 new = repo[b].hex()
4620 new = repo[b].hex()
4554 elif b in rb:
4621 elif b in rb:
4555 ui.status(_("deleting remote bookmark %s\n") % b)
4622 ui.status(_("deleting remote bookmark %s\n") % b)
4556 new = '' # delete
4623 new = '' # delete
4557 else:
4624 else:
4558 ui.warn(_('bookmark %s does not exist on the local '
4625 ui.warn(_('bookmark %s does not exist on the local '
4559 'or remote repository!\n') % b)
4626 'or remote repository!\n') % b)
4560 return 2
4627 return 2
4561 old = rb.get(b, '')
4628 old = rb.get(b, '')
4562 r = other.pushkey('bookmarks', b, old, new)
4629 r = other.pushkey('bookmarks', b, old, new)
4563 if not r:
4630 if not r:
4564 ui.warn(_('updating bookmark %s failed!\n') % b)
4631 ui.warn(_('updating bookmark %s failed!\n') % b)
4565 if not result:
4632 if not result:
4566 result = 2
4633 result = 2
4567
4634
4568 return result
4635 return result
4569
4636
4570 @command('recover', [])
4637 @command('recover', [])
4571 def recover(ui, repo):
4638 def recover(ui, repo):
4572 """roll back an interrupted transaction
4639 """roll back an interrupted transaction
4573
4640
4574 Recover from an interrupted commit or pull.
4641 Recover from an interrupted commit or pull.
4575
4642
4576 This command tries to fix the repository status after an
4643 This command tries to fix the repository status after an
4577 interrupted operation. It should only be necessary when Mercurial
4644 interrupted operation. It should only be necessary when Mercurial
4578 suggests it.
4645 suggests it.
4579
4646
4580 Returns 0 if successful, 1 if nothing to recover or verify fails.
4647 Returns 0 if successful, 1 if nothing to recover or verify fails.
4581 """
4648 """
4582 if repo.recover():
4649 if repo.recover():
4583 return hg.verify(repo)
4650 return hg.verify(repo)
4584 return 1
4651 return 1
4585
4652
4586 @command('^remove|rm',
4653 @command('^remove|rm',
4587 [('A', 'after', None, _('record delete for missing files')),
4654 [('A', 'after', None, _('record delete for missing files')),
4588 ('f', 'force', None,
4655 ('f', 'force', None,
4589 _('remove (and delete) file even if added or modified')),
4656 _('remove (and delete) file even if added or modified')),
4590 ] + walkopts,
4657 ] + walkopts,
4591 _('[OPTION]... FILE...'))
4658 _('[OPTION]... FILE...'))
4592 def remove(ui, repo, *pats, **opts):
4659 def remove(ui, repo, *pats, **opts):
4593 """remove the specified files on the next commit
4660 """remove the specified files on the next commit
4594
4661
4595 Schedule the indicated files for removal from the current branch.
4662 Schedule the indicated files for removal from the current branch.
4596
4663
4597 This command schedules the files to be removed at the next commit.
4664 This command schedules the files to be removed at the next commit.
4598 To undo a remove before that, see :hg:`revert`. To undo added
4665 To undo a remove before that, see :hg:`revert`. To undo added
4599 files, see :hg:`forget`.
4666 files, see :hg:`forget`.
4600
4667
4601 .. container:: verbose
4668 .. container:: verbose
4602
4669
4603 -A/--after can be used to remove only files that have already
4670 -A/--after can be used to remove only files that have already
4604 been deleted, -f/--force can be used to force deletion, and -Af
4671 been deleted, -f/--force can be used to force deletion, and -Af
4605 can be used to remove files from the next revision without
4672 can be used to remove files from the next revision without
4606 deleting them from the working directory.
4673 deleting them from the working directory.
4607
4674
4608 The following table details the behavior of remove for different
4675 The following table details the behavior of remove for different
4609 file states (columns) and option combinations (rows). The file
4676 file states (columns) and option combinations (rows). The file
4610 states are Added [A], Clean [C], Modified [M] and Missing [!]
4677 states are Added [A], Clean [C], Modified [M] and Missing [!]
4611 (as reported by :hg:`status`). The actions are Warn, Remove
4678 (as reported by :hg:`status`). The actions are Warn, Remove
4612 (from branch) and Delete (from disk):
4679 (from branch) and Delete (from disk):
4613
4680
4614 ======= == == == ==
4681 ======= == == == ==
4615 A C M !
4682 A C M !
4616 ======= == == == ==
4683 ======= == == == ==
4617 none W RD W R
4684 none W RD W R
4618 -f R RD RD R
4685 -f R RD RD R
4619 -A W W W R
4686 -A W W W R
4620 -Af R R R R
4687 -Af R R R R
4621 ======= == == == ==
4688 ======= == == == ==
4622
4689
4623 Note that remove never deletes files in Added [A] state from the
4690 Note that remove never deletes files in Added [A] state from the
4624 working directory, not even if option --force is specified.
4691 working directory, not even if option --force is specified.
4625
4692
4626 Returns 0 on success, 1 if any warnings encountered.
4693 Returns 0 on success, 1 if any warnings encountered.
4627 """
4694 """
4628
4695
4629 ret = 0
4696 ret = 0
4630 after, force = opts.get('after'), opts.get('force')
4697 after, force = opts.get('after'), opts.get('force')
4631 if not pats and not after:
4698 if not pats and not after:
4632 raise util.Abort(_('no files specified'))
4699 raise util.Abort(_('no files specified'))
4633
4700
4634 m = scmutil.match(repo[None], pats, opts)
4701 m = scmutil.match(repo[None], pats, opts)
4635 s = repo.status(match=m, clean=True)
4702 s = repo.status(match=m, clean=True)
4636 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4703 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4637
4704
4638 # warn about failure to delete explicit files/dirs
4705 # warn about failure to delete explicit files/dirs
4639 wctx = repo[None]
4706 wctx = repo[None]
4640 for f in m.files():
4707 for f in m.files():
4641 if f in repo.dirstate or f in wctx.dirs():
4708 if f in repo.dirstate or f in wctx.dirs():
4642 continue
4709 continue
4643 if os.path.exists(m.rel(f)):
4710 if os.path.exists(m.rel(f)):
4644 if os.path.isdir(m.rel(f)):
4711 if os.path.isdir(m.rel(f)):
4645 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4712 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4646 else:
4713 else:
4647 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4714 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4648 # missing files will generate a warning elsewhere
4715 # missing files will generate a warning elsewhere
4649 ret = 1
4716 ret = 1
4650
4717
4651 if force:
4718 if force:
4652 list = modified + deleted + clean + added
4719 list = modified + deleted + clean + added
4653 elif after:
4720 elif after:
4654 list = deleted
4721 list = deleted
4655 for f in modified + added + clean:
4722 for f in modified + added + clean:
4656 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4723 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4657 ret = 1
4724 ret = 1
4658 else:
4725 else:
4659 list = deleted + clean
4726 list = deleted + clean
4660 for f in modified:
4727 for f in modified:
4661 ui.warn(_('not removing %s: file is modified (use -f'
4728 ui.warn(_('not removing %s: file is modified (use -f'
4662 ' to force removal)\n') % m.rel(f))
4729 ' to force removal)\n') % m.rel(f))
4663 ret = 1
4730 ret = 1
4664 for f in added:
4731 for f in added:
4665 ui.warn(_('not removing %s: file has been marked for add'
4732 ui.warn(_('not removing %s: file has been marked for add'
4666 ' (use forget to undo)\n') % m.rel(f))
4733 ' (use forget to undo)\n') % m.rel(f))
4667 ret = 1
4734 ret = 1
4668
4735
4669 for f in sorted(list):
4736 for f in sorted(list):
4670 if ui.verbose or not m.exact(f):
4737 if ui.verbose or not m.exact(f):
4671 ui.status(_('removing %s\n') % m.rel(f))
4738 ui.status(_('removing %s\n') % m.rel(f))
4672
4739
4673 wlock = repo.wlock()
4740 wlock = repo.wlock()
4674 try:
4741 try:
4675 if not after:
4742 if not after:
4676 for f in list:
4743 for f in list:
4677 if f in added:
4744 if f in added:
4678 continue # we never unlink added files on remove
4745 continue # we never unlink added files on remove
4679 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4746 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4680 repo[None].forget(list)
4747 repo[None].forget(list)
4681 finally:
4748 finally:
4682 wlock.release()
4749 wlock.release()
4683
4750
4684 return ret
4751 return ret
4685
4752
4686 @command('rename|move|mv',
4753 @command('rename|move|mv',
4687 [('A', 'after', None, _('record a rename that has already occurred')),
4754 [('A', 'after', None, _('record a rename that has already occurred')),
4688 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4755 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4689 ] + walkopts + dryrunopts,
4756 ] + walkopts + dryrunopts,
4690 _('[OPTION]... SOURCE... DEST'))
4757 _('[OPTION]... SOURCE... DEST'))
4691 def rename(ui, repo, *pats, **opts):
4758 def rename(ui, repo, *pats, **opts):
4692 """rename files; equivalent of copy + remove
4759 """rename files; equivalent of copy + remove
4693
4760
4694 Mark dest as copies of sources; mark sources for deletion. If dest
4761 Mark dest as copies of sources; mark sources for deletion. If dest
4695 is a directory, copies are put in that directory. If dest is a
4762 is a directory, copies are put in that directory. If dest is a
4696 file, there can only be one source.
4763 file, there can only be one source.
4697
4764
4698 By default, this command copies the contents of files as they
4765 By default, this command copies the contents of files as they
4699 exist in the working directory. If invoked with -A/--after, the
4766 exist in the working directory. If invoked with -A/--after, the
4700 operation is recorded, but no copying is performed.
4767 operation is recorded, but no copying is performed.
4701
4768
4702 This command takes effect at the next commit. To undo a rename
4769 This command takes effect at the next commit. To undo a rename
4703 before that, see :hg:`revert`.
4770 before that, see :hg:`revert`.
4704
4771
4705 Returns 0 on success, 1 if errors are encountered.
4772 Returns 0 on success, 1 if errors are encountered.
4706 """
4773 """
4707 wlock = repo.wlock(False)
4774 wlock = repo.wlock(False)
4708 try:
4775 try:
4709 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4776 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4710 finally:
4777 finally:
4711 wlock.release()
4778 wlock.release()
4712
4779
4713 @command('resolve',
4780 @command('resolve',
4714 [('a', 'all', None, _('select all unresolved files')),
4781 [('a', 'all', None, _('select all unresolved files')),
4715 ('l', 'list', None, _('list state of files needing merge')),
4782 ('l', 'list', None, _('list state of files needing merge')),
4716 ('m', 'mark', None, _('mark files as resolved')),
4783 ('m', 'mark', None, _('mark files as resolved')),
4717 ('u', 'unmark', None, _('mark files as unresolved')),
4784 ('u', 'unmark', None, _('mark files as unresolved')),
4718 ('n', 'no-status', None, _('hide status prefix'))]
4785 ('n', 'no-status', None, _('hide status prefix'))]
4719 + mergetoolopts + walkopts,
4786 + mergetoolopts + walkopts,
4720 _('[OPTION]... [FILE]...'))
4787 _('[OPTION]... [FILE]...'))
4721 def resolve(ui, repo, *pats, **opts):
4788 def resolve(ui, repo, *pats, **opts):
4722 """redo merges or set/view the merge status of files
4789 """redo merges or set/view the merge status of files
4723
4790
4724 Merges with unresolved conflicts are often the result of
4791 Merges with unresolved conflicts are often the result of
4725 non-interactive merging using the ``internal:merge`` configuration
4792 non-interactive merging using the ``internal:merge`` configuration
4726 setting, or a command-line merge tool like ``diff3``. The resolve
4793 setting, or a command-line merge tool like ``diff3``. The resolve
4727 command is used to manage the files involved in a merge, after
4794 command is used to manage the files involved in a merge, after
4728 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4795 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4729 working directory must have two parents). See :hg:`help
4796 working directory must have two parents). See :hg:`help
4730 merge-tools` for information on configuring merge tools.
4797 merge-tools` for information on configuring merge tools.
4731
4798
4732 The resolve command can be used in the following ways:
4799 The resolve command can be used in the following ways:
4733
4800
4734 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4801 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4735 files, discarding any previous merge attempts. Re-merging is not
4802 files, discarding any previous merge attempts. Re-merging is not
4736 performed for files already marked as resolved. Use ``--all/-a``
4803 performed for files already marked as resolved. Use ``--all/-a``
4737 to select all unresolved files. ``--tool`` can be used to specify
4804 to select all unresolved files. ``--tool`` can be used to specify
4738 the merge tool used for the given files. It overrides the HGMERGE
4805 the merge tool used for the given files. It overrides the HGMERGE
4739 environment variable and your configuration files. Previous file
4806 environment variable and your configuration files. Previous file
4740 contents are saved with a ``.orig`` suffix.
4807 contents are saved with a ``.orig`` suffix.
4741
4808
4742 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4809 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4743 (e.g. after having manually fixed-up the files). The default is
4810 (e.g. after having manually fixed-up the files). The default is
4744 to mark all unresolved files.
4811 to mark all unresolved files.
4745
4812
4746 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4813 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4747 default is to mark all resolved files.
4814 default is to mark all resolved files.
4748
4815
4749 - :hg:`resolve -l`: list files which had or still have conflicts.
4816 - :hg:`resolve -l`: list files which had or still have conflicts.
4750 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4817 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4751
4818
4752 Note that Mercurial will not let you commit files with unresolved
4819 Note that Mercurial will not let you commit files with unresolved
4753 merge conflicts. You must use :hg:`resolve -m ...` before you can
4820 merge conflicts. You must use :hg:`resolve -m ...` before you can
4754 commit after a conflicting merge.
4821 commit after a conflicting merge.
4755
4822
4756 Returns 0 on success, 1 if any files fail a resolve attempt.
4823 Returns 0 on success, 1 if any files fail a resolve attempt.
4757 """
4824 """
4758
4825
4759 all, mark, unmark, show, nostatus = \
4826 all, mark, unmark, show, nostatus = \
4760 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4827 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4761
4828
4762 if (show and (mark or unmark)) or (mark and unmark):
4829 if (show and (mark or unmark)) or (mark and unmark):
4763 raise util.Abort(_("too many options specified"))
4830 raise util.Abort(_("too many options specified"))
4764 if pats and all:
4831 if pats and all:
4765 raise util.Abort(_("can't specify --all and patterns"))
4832 raise util.Abort(_("can't specify --all and patterns"))
4766 if not (all or pats or show or mark or unmark):
4833 if not (all or pats or show or mark or unmark):
4767 raise util.Abort(_('no files or directories specified; '
4834 raise util.Abort(_('no files or directories specified; '
4768 'use --all to remerge all files'))
4835 'use --all to remerge all files'))
4769
4836
4770 ms = mergemod.mergestate(repo)
4837 ms = mergemod.mergestate(repo)
4771 m = scmutil.match(repo[None], pats, opts)
4838 m = scmutil.match(repo[None], pats, opts)
4772 ret = 0
4839 ret = 0
4773
4840
4774 for f in ms:
4841 for f in ms:
4775 if m(f):
4842 if m(f):
4776 if show:
4843 if show:
4777 if nostatus:
4844 if nostatus:
4778 ui.write("%s\n" % f)
4845 ui.write("%s\n" % f)
4779 else:
4846 else:
4780 ui.write("%s %s\n" % (ms[f].upper(), f),
4847 ui.write("%s %s\n" % (ms[f].upper(), f),
4781 label='resolve.' +
4848 label='resolve.' +
4782 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4849 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4783 elif mark:
4850 elif mark:
4784 ms.mark(f, "r")
4851 ms.mark(f, "r")
4785 elif unmark:
4852 elif unmark:
4786 ms.mark(f, "u")
4853 ms.mark(f, "u")
4787 else:
4854 else:
4788 wctx = repo[None]
4855 wctx = repo[None]
4789 mctx = wctx.parents()[-1]
4856 mctx = wctx.parents()[-1]
4790
4857
4791 # backup pre-resolve (merge uses .orig for its own purposes)
4858 # backup pre-resolve (merge uses .orig for its own purposes)
4792 a = repo.wjoin(f)
4859 a = repo.wjoin(f)
4793 util.copyfile(a, a + ".resolve")
4860 util.copyfile(a, a + ".resolve")
4794
4861
4795 try:
4862 try:
4796 # resolve file
4863 # resolve file
4797 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4864 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4798 if ms.resolve(f, wctx, mctx):
4865 if ms.resolve(f, wctx, mctx):
4799 ret = 1
4866 ret = 1
4800 finally:
4867 finally:
4801 ui.setconfig('ui', 'forcemerge', '')
4868 ui.setconfig('ui', 'forcemerge', '')
4802 ms.commit()
4869 ms.commit()
4803
4870
4804 # replace filemerge's .orig file with our resolve file
4871 # replace filemerge's .orig file with our resolve file
4805 util.rename(a + ".resolve", a + ".orig")
4872 util.rename(a + ".resolve", a + ".orig")
4806
4873
4807 ms.commit()
4874 ms.commit()
4808 return ret
4875 return ret
4809
4876
4810 @command('revert',
4877 @command('revert',
4811 [('a', 'all', None, _('revert all changes when no arguments given')),
4878 [('a', 'all', None, _('revert all changes when no arguments given')),
4812 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4879 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4813 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4880 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4814 ('C', 'no-backup', None, _('do not save backup copies of files')),
4881 ('C', 'no-backup', None, _('do not save backup copies of files')),
4815 ] + walkopts + dryrunopts,
4882 ] + walkopts + dryrunopts,
4816 _('[OPTION]... [-r REV] [NAME]...'))
4883 _('[OPTION]... [-r REV] [NAME]...'))
4817 def revert(ui, repo, *pats, **opts):
4884 def revert(ui, repo, *pats, **opts):
4818 """restore files to their checkout state
4885 """restore files to their checkout state
4819
4886
4820 .. note::
4887 .. note::
4821
4888
4822 To check out earlier revisions, you should use :hg:`update REV`.
4889 To check out earlier revisions, you should use :hg:`update REV`.
4823 To cancel an uncommitted merge (and lose your changes), use
4890 To cancel an uncommitted merge (and lose your changes), use
4824 :hg:`update --clean .`.
4891 :hg:`update --clean .`.
4825
4892
4826 With no revision specified, revert the specified files or directories
4893 With no revision specified, revert the specified files or directories
4827 to the contents they had in the parent of the working directory.
4894 to the contents they had in the parent of the working directory.
4828 This restores the contents of files to an unmodified
4895 This restores the contents of files to an unmodified
4829 state and unschedules adds, removes, copies, and renames. If the
4896 state and unschedules adds, removes, copies, and renames. If the
4830 working directory has two parents, you must explicitly specify a
4897 working directory has two parents, you must explicitly specify a
4831 revision.
4898 revision.
4832
4899
4833 Using the -r/--rev or -d/--date options, revert the given files or
4900 Using the -r/--rev or -d/--date options, revert the given files or
4834 directories to their states as of a specific revision. Because
4901 directories to their states as of a specific revision. Because
4835 revert does not change the working directory parents, this will
4902 revert does not change the working directory parents, this will
4836 cause these files to appear modified. This can be helpful to "back
4903 cause these files to appear modified. This can be helpful to "back
4837 out" some or all of an earlier change. See :hg:`backout` for a
4904 out" some or all of an earlier change. See :hg:`backout` for a
4838 related method.
4905 related method.
4839
4906
4840 Modified files are saved with a .orig suffix before reverting.
4907 Modified files are saved with a .orig suffix before reverting.
4841 To disable these backups, use --no-backup.
4908 To disable these backups, use --no-backup.
4842
4909
4843 See :hg:`help dates` for a list of formats valid for -d/--date.
4910 See :hg:`help dates` for a list of formats valid for -d/--date.
4844
4911
4845 Returns 0 on success.
4912 Returns 0 on success.
4846 """
4913 """
4847
4914
4848 if opts.get("date"):
4915 if opts.get("date"):
4849 if opts.get("rev"):
4916 if opts.get("rev"):
4850 raise util.Abort(_("you can't specify a revision and a date"))
4917 raise util.Abort(_("you can't specify a revision and a date"))
4851 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4918 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4852
4919
4853 parent, p2 = repo.dirstate.parents()
4920 parent, p2 = repo.dirstate.parents()
4854 if not opts.get('rev') and p2 != nullid:
4921 if not opts.get('rev') and p2 != nullid:
4855 # revert after merge is a trap for new users (issue2915)
4922 # revert after merge is a trap for new users (issue2915)
4856 raise util.Abort(_('uncommitted merge with no revision specified'),
4923 raise util.Abort(_('uncommitted merge with no revision specified'),
4857 hint=_('use "hg update" or see "hg help revert"'))
4924 hint=_('use "hg update" or see "hg help revert"'))
4858
4925
4859 ctx = scmutil.revsingle(repo, opts.get('rev'))
4926 ctx = scmutil.revsingle(repo, opts.get('rev'))
4860
4927
4861 if not pats and not opts.get('all'):
4928 if not pats and not opts.get('all'):
4862 msg = _("no files or directories specified")
4929 msg = _("no files or directories specified")
4863 if p2 != nullid:
4930 if p2 != nullid:
4864 hint = _("uncommitted merge, use --all to discard all changes,"
4931 hint = _("uncommitted merge, use --all to discard all changes,"
4865 " or 'hg update -C .' to abort the merge")
4932 " or 'hg update -C .' to abort the merge")
4866 raise util.Abort(msg, hint=hint)
4933 raise util.Abort(msg, hint=hint)
4867 dirty = util.any(repo.status())
4934 dirty = util.any(repo.status())
4868 node = ctx.node()
4935 node = ctx.node()
4869 if node != parent:
4936 if node != parent:
4870 if dirty:
4937 if dirty:
4871 hint = _("uncommitted changes, use --all to discard all"
4938 hint = _("uncommitted changes, use --all to discard all"
4872 " changes, or 'hg update %s' to update") % ctx.rev()
4939 " changes, or 'hg update %s' to update") % ctx.rev()
4873 else:
4940 else:
4874 hint = _("use --all to revert all files,"
4941 hint = _("use --all to revert all files,"
4875 " or 'hg update %s' to update") % ctx.rev()
4942 " or 'hg update %s' to update") % ctx.rev()
4876 elif dirty:
4943 elif dirty:
4877 hint = _("uncommitted changes, use --all to discard all changes")
4944 hint = _("uncommitted changes, use --all to discard all changes")
4878 else:
4945 else:
4879 hint = _("use --all to revert all files")
4946 hint = _("use --all to revert all files")
4880 raise util.Abort(msg, hint=hint)
4947 raise util.Abort(msg, hint=hint)
4881
4948
4882 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4949 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4883
4950
4884 @command('rollback', dryrunopts +
4951 @command('rollback', dryrunopts +
4885 [('f', 'force', False, _('ignore safety measures'))])
4952 [('f', 'force', False, _('ignore safety measures'))])
4886 def rollback(ui, repo, **opts):
4953 def rollback(ui, repo, **opts):
4887 """roll back the last transaction (dangerous)
4954 """roll back the last transaction (dangerous)
4888
4955
4889 This command should be used with care. There is only one level of
4956 This command should be used with care. There is only one level of
4890 rollback, and there is no way to undo a rollback. It will also
4957 rollback, and there is no way to undo a rollback. It will also
4891 restore the dirstate at the time of the last transaction, losing
4958 restore the dirstate at the time of the last transaction, losing
4892 any dirstate changes since that time. This command does not alter
4959 any dirstate changes since that time. This command does not alter
4893 the working directory.
4960 the working directory.
4894
4961
4895 Transactions are used to encapsulate the effects of all commands
4962 Transactions are used to encapsulate the effects of all commands
4896 that create new changesets or propagate existing changesets into a
4963 that create new changesets or propagate existing changesets into a
4897 repository.
4964 repository.
4898
4965
4899 .. container:: verbose
4966 .. container:: verbose
4900
4967
4901 For example, the following commands are transactional, and their
4968 For example, the following commands are transactional, and their
4902 effects can be rolled back:
4969 effects can be rolled back:
4903
4970
4904 - commit
4971 - commit
4905 - import
4972 - import
4906 - pull
4973 - pull
4907 - push (with this repository as the destination)
4974 - push (with this repository as the destination)
4908 - unbundle
4975 - unbundle
4909
4976
4910 To avoid permanent data loss, rollback will refuse to rollback a
4977 To avoid permanent data loss, rollback will refuse to rollback a
4911 commit transaction if it isn't checked out. Use --force to
4978 commit transaction if it isn't checked out. Use --force to
4912 override this protection.
4979 override this protection.
4913
4980
4914 This command is not intended for use on public repositories. Once
4981 This command is not intended for use on public repositories. Once
4915 changes are visible for pull by other users, rolling a transaction
4982 changes are visible for pull by other users, rolling a transaction
4916 back locally is ineffective (someone else may already have pulled
4983 back locally is ineffective (someone else may already have pulled
4917 the changes). Furthermore, a race is possible with readers of the
4984 the changes). Furthermore, a race is possible with readers of the
4918 repository; for example an in-progress pull from the repository
4985 repository; for example an in-progress pull from the repository
4919 may fail if a rollback is performed.
4986 may fail if a rollback is performed.
4920
4987
4921 Returns 0 on success, 1 if no rollback data is available.
4988 Returns 0 on success, 1 if no rollback data is available.
4922 """
4989 """
4923 return repo.rollback(dryrun=opts.get('dry_run'),
4990 return repo.rollback(dryrun=opts.get('dry_run'),
4924 force=opts.get('force'))
4991 force=opts.get('force'))
4925
4992
4926 @command('root', [])
4993 @command('root', [])
4927 def root(ui, repo):
4994 def root(ui, repo):
4928 """print the root (top) of the current working directory
4995 """print the root (top) of the current working directory
4929
4996
4930 Print the root directory of the current repository.
4997 Print the root directory of the current repository.
4931
4998
4932 Returns 0 on success.
4999 Returns 0 on success.
4933 """
5000 """
4934 ui.write(repo.root + "\n")
5001 ui.write(repo.root + "\n")
4935
5002
4936 @command('^serve',
5003 @command('^serve',
4937 [('A', 'accesslog', '', _('name of access log file to write to'),
5004 [('A', 'accesslog', '', _('name of access log file to write to'),
4938 _('FILE')),
5005 _('FILE')),
4939 ('d', 'daemon', None, _('run server in background')),
5006 ('d', 'daemon', None, _('run server in background')),
4940 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5007 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4941 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5008 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4942 # use string type, then we can check if something was passed
5009 # use string type, then we can check if something was passed
4943 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5010 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4944 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5011 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4945 _('ADDR')),
5012 _('ADDR')),
4946 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5013 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4947 _('PREFIX')),
5014 _('PREFIX')),
4948 ('n', 'name', '',
5015 ('n', 'name', '',
4949 _('name to show in web pages (default: working directory)'), _('NAME')),
5016 _('name to show in web pages (default: working directory)'), _('NAME')),
4950 ('', 'web-conf', '',
5017 ('', 'web-conf', '',
4951 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5018 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4952 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5019 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4953 _('FILE')),
5020 _('FILE')),
4954 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5021 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4955 ('', 'stdio', None, _('for remote clients')),
5022 ('', 'stdio', None, _('for remote clients')),
4956 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5023 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4957 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5024 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4958 ('', 'style', '', _('template style to use'), _('STYLE')),
5025 ('', 'style', '', _('template style to use'), _('STYLE')),
4959 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5026 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4960 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5027 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4961 _('[OPTION]...'))
5028 _('[OPTION]...'))
4962 def serve(ui, repo, **opts):
5029 def serve(ui, repo, **opts):
4963 """start stand-alone webserver
5030 """start stand-alone webserver
4964
5031
4965 Start a local HTTP repository browser and pull server. You can use
5032 Start a local HTTP repository browser and pull server. You can use
4966 this for ad-hoc sharing and browsing of repositories. It is
5033 this for ad-hoc sharing and browsing of repositories. It is
4967 recommended to use a real web server to serve a repository for
5034 recommended to use a real web server to serve a repository for
4968 longer periods of time.
5035 longer periods of time.
4969
5036
4970 Please note that the server does not implement access control.
5037 Please note that the server does not implement access control.
4971 This means that, by default, anybody can read from the server and
5038 This means that, by default, anybody can read from the server and
4972 nobody can write to it by default. Set the ``web.allow_push``
5039 nobody can write to it by default. Set the ``web.allow_push``
4973 option to ``*`` to allow everybody to push to the server. You
5040 option to ``*`` to allow everybody to push to the server. You
4974 should use a real web server if you need to authenticate users.
5041 should use a real web server if you need to authenticate users.
4975
5042
4976 By default, the server logs accesses to stdout and errors to
5043 By default, the server logs accesses to stdout and errors to
4977 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5044 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4978 files.
5045 files.
4979
5046
4980 To have the server choose a free port number to listen on, specify
5047 To have the server choose a free port number to listen on, specify
4981 a port number of 0; in this case, the server will print the port
5048 a port number of 0; in this case, the server will print the port
4982 number it uses.
5049 number it uses.
4983
5050
4984 Returns 0 on success.
5051 Returns 0 on success.
4985 """
5052 """
4986
5053
4987 if opts["stdio"] and opts["cmdserver"]:
5054 if opts["stdio"] and opts["cmdserver"]:
4988 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5055 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4989
5056
4990 def checkrepo():
5057 def checkrepo():
4991 if repo is None:
5058 if repo is None:
4992 raise error.RepoError(_("there is no Mercurial repository here"
5059 raise error.RepoError(_("there is no Mercurial repository here"
4993 " (.hg not found)"))
5060 " (.hg not found)"))
4994
5061
4995 if opts["stdio"]:
5062 if opts["stdio"]:
4996 checkrepo()
5063 checkrepo()
4997 s = sshserver.sshserver(ui, repo)
5064 s = sshserver.sshserver(ui, repo)
4998 s.serve_forever()
5065 s.serve_forever()
4999
5066
5000 if opts["cmdserver"]:
5067 if opts["cmdserver"]:
5001 checkrepo()
5068 checkrepo()
5002 s = commandserver.server(ui, repo, opts["cmdserver"])
5069 s = commandserver.server(ui, repo, opts["cmdserver"])
5003 return s.serve()
5070 return s.serve()
5004
5071
5005 # this way we can check if something was given in the command-line
5072 # this way we can check if something was given in the command-line
5006 if opts.get('port'):
5073 if opts.get('port'):
5007 opts['port'] = util.getport(opts.get('port'))
5074 opts['port'] = util.getport(opts.get('port'))
5008
5075
5009 baseui = repo and repo.baseui or ui
5076 baseui = repo and repo.baseui or ui
5010 optlist = ("name templates style address port prefix ipv6"
5077 optlist = ("name templates style address port prefix ipv6"
5011 " accesslog errorlog certificate encoding")
5078 " accesslog errorlog certificate encoding")
5012 for o in optlist.split():
5079 for o in optlist.split():
5013 val = opts.get(o, '')
5080 val = opts.get(o, '')
5014 if val in (None, ''): # should check against default options instead
5081 if val in (None, ''): # should check against default options instead
5015 continue
5082 continue
5016 baseui.setconfig("web", o, val)
5083 baseui.setconfig("web", o, val)
5017 if repo and repo.ui != baseui:
5084 if repo and repo.ui != baseui:
5018 repo.ui.setconfig("web", o, val)
5085 repo.ui.setconfig("web", o, val)
5019
5086
5020 o = opts.get('web_conf') or opts.get('webdir_conf')
5087 o = opts.get('web_conf') or opts.get('webdir_conf')
5021 if not o:
5088 if not o:
5022 if not repo:
5089 if not repo:
5023 raise error.RepoError(_("there is no Mercurial repository"
5090 raise error.RepoError(_("there is no Mercurial repository"
5024 " here (.hg not found)"))
5091 " here (.hg not found)"))
5025 o = repo.root
5092 o = repo.root
5026
5093
5027 app = hgweb.hgweb(o, baseui=ui)
5094 app = hgweb.hgweb(o, baseui=ui)
5028
5095
5029 class service(object):
5096 class service(object):
5030 def init(self):
5097 def init(self):
5031 util.setsignalhandler()
5098 util.setsignalhandler()
5032 self.httpd = hgweb.server.create_server(ui, app)
5099 self.httpd = hgweb.server.create_server(ui, app)
5033
5100
5034 if opts['port'] and not ui.verbose:
5101 if opts['port'] and not ui.verbose:
5035 return
5102 return
5036
5103
5037 if self.httpd.prefix:
5104 if self.httpd.prefix:
5038 prefix = self.httpd.prefix.strip('/') + '/'
5105 prefix = self.httpd.prefix.strip('/') + '/'
5039 else:
5106 else:
5040 prefix = ''
5107 prefix = ''
5041
5108
5042 port = ':%d' % self.httpd.port
5109 port = ':%d' % self.httpd.port
5043 if port == ':80':
5110 if port == ':80':
5044 port = ''
5111 port = ''
5045
5112
5046 bindaddr = self.httpd.addr
5113 bindaddr = self.httpd.addr
5047 if bindaddr == '0.0.0.0':
5114 if bindaddr == '0.0.0.0':
5048 bindaddr = '*'
5115 bindaddr = '*'
5049 elif ':' in bindaddr: # IPv6
5116 elif ':' in bindaddr: # IPv6
5050 bindaddr = '[%s]' % bindaddr
5117 bindaddr = '[%s]' % bindaddr
5051
5118
5052 fqaddr = self.httpd.fqaddr
5119 fqaddr = self.httpd.fqaddr
5053 if ':' in fqaddr:
5120 if ':' in fqaddr:
5054 fqaddr = '[%s]' % fqaddr
5121 fqaddr = '[%s]' % fqaddr
5055 if opts['port']:
5122 if opts['port']:
5056 write = ui.status
5123 write = ui.status
5057 else:
5124 else:
5058 write = ui.write
5125 write = ui.write
5059 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5126 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5060 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5127 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5061
5128
5062 def run(self):
5129 def run(self):
5063 self.httpd.serve_forever()
5130 self.httpd.serve_forever()
5064
5131
5065 service = service()
5132 service = service()
5066
5133
5067 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5134 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5068
5135
5069 @command('showconfig|debugconfig',
5136 @command('showconfig|debugconfig',
5070 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5137 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5071 _('[-u] [NAME]...'))
5138 _('[-u] [NAME]...'))
5072 def showconfig(ui, repo, *values, **opts):
5139 def showconfig(ui, repo, *values, **opts):
5073 """show combined config settings from all hgrc files
5140 """show combined config settings from all hgrc files
5074
5141
5075 With no arguments, print names and values of all config items.
5142 With no arguments, print names and values of all config items.
5076
5143
5077 With one argument of the form section.name, print just the value
5144 With one argument of the form section.name, print just the value
5078 of that config item.
5145 of that config item.
5079
5146
5080 With multiple arguments, print names and values of all config
5147 With multiple arguments, print names and values of all config
5081 items with matching section names.
5148 items with matching section names.
5082
5149
5083 With --debug, the source (filename and line number) is printed
5150 With --debug, the source (filename and line number) is printed
5084 for each config item.
5151 for each config item.
5085
5152
5086 Returns 0 on success.
5153 Returns 0 on success.
5087 """
5154 """
5088
5155
5089 for f in scmutil.rcpath():
5156 for f in scmutil.rcpath():
5090 ui.debug('read config from: %s\n' % f)
5157 ui.debug('read config from: %s\n' % f)
5091 untrusted = bool(opts.get('untrusted'))
5158 untrusted = bool(opts.get('untrusted'))
5092 if values:
5159 if values:
5093 sections = [v for v in values if '.' not in v]
5160 sections = [v for v in values if '.' not in v]
5094 items = [v for v in values if '.' in v]
5161 items = [v for v in values if '.' in v]
5095 if len(items) > 1 or items and sections:
5162 if len(items) > 1 or items and sections:
5096 raise util.Abort(_('only one config item permitted'))
5163 raise util.Abort(_('only one config item permitted'))
5097 for section, name, value in ui.walkconfig(untrusted=untrusted):
5164 for section, name, value in ui.walkconfig(untrusted=untrusted):
5098 value = str(value).replace('\n', '\\n')
5165 value = str(value).replace('\n', '\\n')
5099 sectname = section + '.' + name
5166 sectname = section + '.' + name
5100 if values:
5167 if values:
5101 for v in values:
5168 for v in values:
5102 if v == section:
5169 if v == section:
5103 ui.debug('%s: ' %
5170 ui.debug('%s: ' %
5104 ui.configsource(section, name, untrusted))
5171 ui.configsource(section, name, untrusted))
5105 ui.write('%s=%s\n' % (sectname, value))
5172 ui.write('%s=%s\n' % (sectname, value))
5106 elif v == sectname:
5173 elif v == sectname:
5107 ui.debug('%s: ' %
5174 ui.debug('%s: ' %
5108 ui.configsource(section, name, untrusted))
5175 ui.configsource(section, name, untrusted))
5109 ui.write(value, '\n')
5176 ui.write(value, '\n')
5110 else:
5177 else:
5111 ui.debug('%s: ' %
5178 ui.debug('%s: ' %
5112 ui.configsource(section, name, untrusted))
5179 ui.configsource(section, name, untrusted))
5113 ui.write('%s=%s\n' % (sectname, value))
5180 ui.write('%s=%s\n' % (sectname, value))
5114
5181
5115 @command('^status|st',
5182 @command('^status|st',
5116 [('A', 'all', None, _('show status of all files')),
5183 [('A', 'all', None, _('show status of all files')),
5117 ('m', 'modified', None, _('show only modified files')),
5184 ('m', 'modified', None, _('show only modified files')),
5118 ('a', 'added', None, _('show only added files')),
5185 ('a', 'added', None, _('show only added files')),
5119 ('r', 'removed', None, _('show only removed files')),
5186 ('r', 'removed', None, _('show only removed files')),
5120 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5187 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5121 ('c', 'clean', None, _('show only files without changes')),
5188 ('c', 'clean', None, _('show only files without changes')),
5122 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5189 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5123 ('i', 'ignored', None, _('show only ignored files')),
5190 ('i', 'ignored', None, _('show only ignored files')),
5124 ('n', 'no-status', None, _('hide status prefix')),
5191 ('n', 'no-status', None, _('hide status prefix')),
5125 ('C', 'copies', None, _('show source of copied files')),
5192 ('C', 'copies', None, _('show source of copied files')),
5126 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5193 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5127 ('', 'rev', [], _('show difference from revision'), _('REV')),
5194 ('', 'rev', [], _('show difference from revision'), _('REV')),
5128 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5195 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5129 ] + walkopts + subrepoopts,
5196 ] + walkopts + subrepoopts,
5130 _('[OPTION]... [FILE]...'))
5197 _('[OPTION]... [FILE]...'))
5131 def status(ui, repo, *pats, **opts):
5198 def status(ui, repo, *pats, **opts):
5132 """show changed files in the working directory
5199 """show changed files in the working directory
5133
5200
5134 Show status of files in the repository. If names are given, only
5201 Show status of files in the repository. If names are given, only
5135 files that match are shown. Files that are clean or ignored or
5202 files that match are shown. Files that are clean or ignored or
5136 the source of a copy/move operation, are not listed unless
5203 the source of a copy/move operation, are not listed unless
5137 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5204 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5138 Unless options described with "show only ..." are given, the
5205 Unless options described with "show only ..." are given, the
5139 options -mardu are used.
5206 options -mardu are used.
5140
5207
5141 Option -q/--quiet hides untracked (unknown and ignored) files
5208 Option -q/--quiet hides untracked (unknown and ignored) files
5142 unless explicitly requested with -u/--unknown or -i/--ignored.
5209 unless explicitly requested with -u/--unknown or -i/--ignored.
5143
5210
5144 .. note::
5211 .. note::
5145 status may appear to disagree with diff if permissions have
5212 status may appear to disagree with diff if permissions have
5146 changed or a merge has occurred. The standard diff format does
5213 changed or a merge has occurred. The standard diff format does
5147 not report permission changes and diff only reports changes
5214 not report permission changes and diff only reports changes
5148 relative to one merge parent.
5215 relative to one merge parent.
5149
5216
5150 If one revision is given, it is used as the base revision.
5217 If one revision is given, it is used as the base revision.
5151 If two revisions are given, the differences between them are
5218 If two revisions are given, the differences between them are
5152 shown. The --change option can also be used as a shortcut to list
5219 shown. The --change option can also be used as a shortcut to list
5153 the changed files of a revision from its first parent.
5220 the changed files of a revision from its first parent.
5154
5221
5155 The codes used to show the status of files are::
5222 The codes used to show the status of files are::
5156
5223
5157 M = modified
5224 M = modified
5158 A = added
5225 A = added
5159 R = removed
5226 R = removed
5160 C = clean
5227 C = clean
5161 ! = missing (deleted by non-hg command, but still tracked)
5228 ! = missing (deleted by non-hg command, but still tracked)
5162 ? = not tracked
5229 ? = not tracked
5163 I = ignored
5230 I = ignored
5164 = origin of the previous file listed as A (added)
5231 = origin of the previous file listed as A (added)
5165
5232
5166 .. container:: verbose
5233 .. container:: verbose
5167
5234
5168 Examples:
5235 Examples:
5169
5236
5170 - show changes in the working directory relative to a
5237 - show changes in the working directory relative to a
5171 changeset::
5238 changeset::
5172
5239
5173 hg status --rev 9353
5240 hg status --rev 9353
5174
5241
5175 - show all changes including copies in an existing changeset::
5242 - show all changes including copies in an existing changeset::
5176
5243
5177 hg status --copies --change 9353
5244 hg status --copies --change 9353
5178
5245
5179 - get a NUL separated list of added files, suitable for xargs::
5246 - get a NUL separated list of added files, suitable for xargs::
5180
5247
5181 hg status -an0
5248 hg status -an0
5182
5249
5183 Returns 0 on success.
5250 Returns 0 on success.
5184 """
5251 """
5185
5252
5186 revs = opts.get('rev')
5253 revs = opts.get('rev')
5187 change = opts.get('change')
5254 change = opts.get('change')
5188
5255
5189 if revs and change:
5256 if revs and change:
5190 msg = _('cannot specify --rev and --change at the same time')
5257 msg = _('cannot specify --rev and --change at the same time')
5191 raise util.Abort(msg)
5258 raise util.Abort(msg)
5192 elif change:
5259 elif change:
5193 node2 = scmutil.revsingle(repo, change, None).node()
5260 node2 = scmutil.revsingle(repo, change, None).node()
5194 node1 = repo[node2].p1().node()
5261 node1 = repo[node2].p1().node()
5195 else:
5262 else:
5196 node1, node2 = scmutil.revpair(repo, revs)
5263 node1, node2 = scmutil.revpair(repo, revs)
5197
5264
5198 cwd = (pats and repo.getcwd()) or ''
5265 cwd = (pats and repo.getcwd()) or ''
5199 end = opts.get('print0') and '\0' or '\n'
5266 end = opts.get('print0') and '\0' or '\n'
5200 copy = {}
5267 copy = {}
5201 states = 'modified added removed deleted unknown ignored clean'.split()
5268 states = 'modified added removed deleted unknown ignored clean'.split()
5202 show = [k for k in states if opts.get(k)]
5269 show = [k for k in states if opts.get(k)]
5203 if opts.get('all'):
5270 if opts.get('all'):
5204 show += ui.quiet and (states[:4] + ['clean']) or states
5271 show += ui.quiet and (states[:4] + ['clean']) or states
5205 if not show:
5272 if not show:
5206 show = ui.quiet and states[:4] or states[:5]
5273 show = ui.quiet and states[:4] or states[:5]
5207
5274
5208 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5275 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5209 'ignored' in show, 'clean' in show, 'unknown' in show,
5276 'ignored' in show, 'clean' in show, 'unknown' in show,
5210 opts.get('subrepos'))
5277 opts.get('subrepos'))
5211 changestates = zip(states, 'MAR!?IC', stat)
5278 changestates = zip(states, 'MAR!?IC', stat)
5212
5279
5213 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5280 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5214 copy = copies.pathcopies(repo[node1], repo[node2])
5281 copy = copies.pathcopies(repo[node1], repo[node2])
5215
5282
5216 fm = ui.formatter('status', opts)
5283 fm = ui.formatter('status', opts)
5217 fmt = '%s' + end
5284 fmt = '%s' + end
5218 showchar = not opts.get('no_status')
5285 showchar = not opts.get('no_status')
5219
5286
5220 for state, char, files in changestates:
5287 for state, char, files in changestates:
5221 if state in show:
5288 if state in show:
5222 label = 'status.' + state
5289 label = 'status.' + state
5223 for f in files:
5290 for f in files:
5224 fm.startitem()
5291 fm.startitem()
5225 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5292 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5226 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5293 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5227 if f in copy:
5294 if f in copy:
5228 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5295 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5229 label='status.copied')
5296 label='status.copied')
5230 fm.end()
5297 fm.end()
5231
5298
5232 @command('^summary|sum',
5299 @command('^summary|sum',
5233 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5300 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5234 def summary(ui, repo, **opts):
5301 def summary(ui, repo, **opts):
5235 """summarize working directory state
5302 """summarize working directory state
5236
5303
5237 This generates a brief summary of the working directory state,
5304 This generates a brief summary of the working directory state,
5238 including parents, branch, commit status, and available updates.
5305 including parents, branch, commit status, and available updates.
5239
5306
5240 With the --remote option, this will check the default paths for
5307 With the --remote option, this will check the default paths for
5241 incoming and outgoing changes. This can be time-consuming.
5308 incoming and outgoing changes. This can be time-consuming.
5242
5309
5243 Returns 0 on success.
5310 Returns 0 on success.
5244 """
5311 """
5245
5312
5246 ctx = repo[None]
5313 ctx = repo[None]
5247 parents = ctx.parents()
5314 parents = ctx.parents()
5248 pnode = parents[0].node()
5315 pnode = parents[0].node()
5249 marks = []
5316 marks = []
5250
5317
5251 for p in parents:
5318 for p in parents:
5252 # label with log.changeset (instead of log.parent) since this
5319 # label with log.changeset (instead of log.parent) since this
5253 # shows a working directory parent *changeset*:
5320 # shows a working directory parent *changeset*:
5254 # i18n: column positioning for "hg summary"
5321 # i18n: column positioning for "hg summary"
5255 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5322 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5256 label='log.changeset changeset.%s' % p.phasestr())
5323 label='log.changeset changeset.%s' % p.phasestr())
5257 ui.write(' '.join(p.tags()), label='log.tag')
5324 ui.write(' '.join(p.tags()), label='log.tag')
5258 if p.bookmarks():
5325 if p.bookmarks():
5259 marks.extend(p.bookmarks())
5326 marks.extend(p.bookmarks())
5260 if p.rev() == -1:
5327 if p.rev() == -1:
5261 if not len(repo):
5328 if not len(repo):
5262 ui.write(_(' (empty repository)'))
5329 ui.write(_(' (empty repository)'))
5263 else:
5330 else:
5264 ui.write(_(' (no revision checked out)'))
5331 ui.write(_(' (no revision checked out)'))
5265 ui.write('\n')
5332 ui.write('\n')
5266 if p.description():
5333 if p.description():
5267 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5334 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5268 label='log.summary')
5335 label='log.summary')
5269
5336
5270 branch = ctx.branch()
5337 branch = ctx.branch()
5271 bheads = repo.branchheads(branch)
5338 bheads = repo.branchheads(branch)
5272 # i18n: column positioning for "hg summary"
5339 # i18n: column positioning for "hg summary"
5273 m = _('branch: %s\n') % branch
5340 m = _('branch: %s\n') % branch
5274 if branch != 'default':
5341 if branch != 'default':
5275 ui.write(m, label='log.branch')
5342 ui.write(m, label='log.branch')
5276 else:
5343 else:
5277 ui.status(m, label='log.branch')
5344 ui.status(m, label='log.branch')
5278
5345
5279 if marks:
5346 if marks:
5280 current = repo._bookmarkcurrent
5347 current = repo._bookmarkcurrent
5281 # i18n: column positioning for "hg summary"
5348 # i18n: column positioning for "hg summary"
5282 ui.write(_('bookmarks:'), label='log.bookmark')
5349 ui.write(_('bookmarks:'), label='log.bookmark')
5283 if current is not None:
5350 if current is not None:
5284 if current in marks:
5351 if current in marks:
5285 ui.write(' *' + current, label='bookmarks.current')
5352 ui.write(' *' + current, label='bookmarks.current')
5286 marks.remove(current)
5353 marks.remove(current)
5287 else:
5354 else:
5288 ui.write(' [%s]' % current, label='bookmarks.current')
5355 ui.write(' [%s]' % current, label='bookmarks.current')
5289 for m in marks:
5356 for m in marks:
5290 ui.write(' ' + m, label='log.bookmark')
5357 ui.write(' ' + m, label='log.bookmark')
5291 ui.write('\n', label='log.bookmark')
5358 ui.write('\n', label='log.bookmark')
5292
5359
5293 st = list(repo.status(unknown=True))[:6]
5360 st = list(repo.status(unknown=True))[:6]
5294
5361
5295 c = repo.dirstate.copies()
5362 c = repo.dirstate.copies()
5296 copied, renamed = [], []
5363 copied, renamed = [], []
5297 for d, s in c.iteritems():
5364 for d, s in c.iteritems():
5298 if s in st[2]:
5365 if s in st[2]:
5299 st[2].remove(s)
5366 st[2].remove(s)
5300 renamed.append(d)
5367 renamed.append(d)
5301 else:
5368 else:
5302 copied.append(d)
5369 copied.append(d)
5303 if d in st[1]:
5370 if d in st[1]:
5304 st[1].remove(d)
5371 st[1].remove(d)
5305 st.insert(3, renamed)
5372 st.insert(3, renamed)
5306 st.insert(4, copied)
5373 st.insert(4, copied)
5307
5374
5308 ms = mergemod.mergestate(repo)
5375 ms = mergemod.mergestate(repo)
5309 st.append([f for f in ms if ms[f] == 'u'])
5376 st.append([f for f in ms if ms[f] == 'u'])
5310
5377
5311 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5378 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5312 st.append(subs)
5379 st.append(subs)
5313
5380
5314 labels = [ui.label(_('%d modified'), 'status.modified'),
5381 labels = [ui.label(_('%d modified'), 'status.modified'),
5315 ui.label(_('%d added'), 'status.added'),
5382 ui.label(_('%d added'), 'status.added'),
5316 ui.label(_('%d removed'), 'status.removed'),
5383 ui.label(_('%d removed'), 'status.removed'),
5317 ui.label(_('%d renamed'), 'status.copied'),
5384 ui.label(_('%d renamed'), 'status.copied'),
5318 ui.label(_('%d copied'), 'status.copied'),
5385 ui.label(_('%d copied'), 'status.copied'),
5319 ui.label(_('%d deleted'), 'status.deleted'),
5386 ui.label(_('%d deleted'), 'status.deleted'),
5320 ui.label(_('%d unknown'), 'status.unknown'),
5387 ui.label(_('%d unknown'), 'status.unknown'),
5321 ui.label(_('%d ignored'), 'status.ignored'),
5388 ui.label(_('%d ignored'), 'status.ignored'),
5322 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5389 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5323 ui.label(_('%d subrepos'), 'status.modified')]
5390 ui.label(_('%d subrepos'), 'status.modified')]
5324 t = []
5391 t = []
5325 for s, l in zip(st, labels):
5392 for s, l in zip(st, labels):
5326 if s:
5393 if s:
5327 t.append(l % len(s))
5394 t.append(l % len(s))
5328
5395
5329 t = ', '.join(t)
5396 t = ', '.join(t)
5330 cleanworkdir = False
5397 cleanworkdir = False
5331
5398
5332 if len(parents) > 1:
5399 if len(parents) > 1:
5333 t += _(' (merge)')
5400 t += _(' (merge)')
5334 elif branch != parents[0].branch():
5401 elif branch != parents[0].branch():
5335 t += _(' (new branch)')
5402 t += _(' (new branch)')
5336 elif (parents[0].closesbranch() and
5403 elif (parents[0].closesbranch() and
5337 pnode in repo.branchheads(branch, closed=True)):
5404 pnode in repo.branchheads(branch, closed=True)):
5338 t += _(' (head closed)')
5405 t += _(' (head closed)')
5339 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5406 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5340 t += _(' (clean)')
5407 t += _(' (clean)')
5341 cleanworkdir = True
5408 cleanworkdir = True
5342 elif pnode not in bheads:
5409 elif pnode not in bheads:
5343 t += _(' (new branch head)')
5410 t += _(' (new branch head)')
5344
5411
5345 if cleanworkdir:
5412 if cleanworkdir:
5346 # i18n: column positioning for "hg summary"
5413 # i18n: column positioning for "hg summary"
5347 ui.status(_('commit: %s\n') % t.strip())
5414 ui.status(_('commit: %s\n') % t.strip())
5348 else:
5415 else:
5349 # i18n: column positioning for "hg summary"
5416 # i18n: column positioning for "hg summary"
5350 ui.write(_('commit: %s\n') % t.strip())
5417 ui.write(_('commit: %s\n') % t.strip())
5351
5418
5352 # all ancestors of branch heads - all ancestors of parent = new csets
5419 # all ancestors of branch heads - all ancestors of parent = new csets
5353 new = [0] * len(repo)
5420 new = [0] * len(repo)
5354 cl = repo.changelog
5421 cl = repo.changelog
5355 for a in [cl.rev(n) for n in bheads]:
5422 for a in [cl.rev(n) for n in bheads]:
5356 new[a] = 1
5423 new[a] = 1
5357 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5424 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5358 new[a] = 1
5425 new[a] = 1
5359 for a in [p.rev() for p in parents]:
5426 for a in [p.rev() for p in parents]:
5360 if a >= 0:
5427 if a >= 0:
5361 new[a] = 0
5428 new[a] = 0
5362 for a in cl.ancestors([p.rev() for p in parents]):
5429 for a in cl.ancestors([p.rev() for p in parents]):
5363 new[a] = 0
5430 new[a] = 0
5364 new = sum(new)
5431 new = sum(new)
5365
5432
5366 if new == 0:
5433 if new == 0:
5367 # i18n: column positioning for "hg summary"
5434 # i18n: column positioning for "hg summary"
5368 ui.status(_('update: (current)\n'))
5435 ui.status(_('update: (current)\n'))
5369 elif pnode not in bheads:
5436 elif pnode not in bheads:
5370 # i18n: column positioning for "hg summary"
5437 # i18n: column positioning for "hg summary"
5371 ui.write(_('update: %d new changesets (update)\n') % new)
5438 ui.write(_('update: %d new changesets (update)\n') % new)
5372 else:
5439 else:
5373 # i18n: column positioning for "hg summary"
5440 # i18n: column positioning for "hg summary"
5374 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5441 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5375 (new, len(bheads)))
5442 (new, len(bheads)))
5376
5443
5377 if opts.get('remote'):
5444 if opts.get('remote'):
5378 t = []
5445 t = []
5379 source, branches = hg.parseurl(ui.expandpath('default'))
5446 source, branches = hg.parseurl(ui.expandpath('default'))
5380 other = hg.peer(repo, {}, source)
5447 other = hg.peer(repo, {}, source)
5381 revs, checkout = hg.addbranchrevs(repo, other, branches,
5448 revs, checkout = hg.addbranchrevs(repo, other, branches,
5382 opts.get('rev'))
5449 opts.get('rev'))
5383 ui.debug('comparing with %s\n' % util.hidepassword(source))
5450 ui.debug('comparing with %s\n' % util.hidepassword(source))
5384 repo.ui.pushbuffer()
5451 repo.ui.pushbuffer()
5385 commoninc = discovery.findcommonincoming(repo, other)
5452 commoninc = discovery.findcommonincoming(repo, other)
5386 _common, incoming, _rheads = commoninc
5453 _common, incoming, _rheads = commoninc
5387 repo.ui.popbuffer()
5454 repo.ui.popbuffer()
5388 if incoming:
5455 if incoming:
5389 t.append(_('1 or more incoming'))
5456 t.append(_('1 or more incoming'))
5390
5457
5391 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5458 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5392 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5459 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5393 if source != dest:
5460 if source != dest:
5394 other = hg.peer(repo, {}, dest)
5461 other = hg.peer(repo, {}, dest)
5395 commoninc = None
5462 commoninc = None
5396 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5463 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5397 repo.ui.pushbuffer()
5464 repo.ui.pushbuffer()
5398 outgoing = discovery.findcommonoutgoing(repo, other,
5465 outgoing = discovery.findcommonoutgoing(repo, other,
5399 commoninc=commoninc)
5466 commoninc=commoninc)
5400 repo.ui.popbuffer()
5467 repo.ui.popbuffer()
5401 o = outgoing.missing
5468 o = outgoing.missing
5402 if o:
5469 if o:
5403 t.append(_('%d outgoing') % len(o))
5470 t.append(_('%d outgoing') % len(o))
5404 if 'bookmarks' in other.listkeys('namespaces'):
5471 if 'bookmarks' in other.listkeys('namespaces'):
5405 lmarks = repo.listkeys('bookmarks')
5472 lmarks = repo.listkeys('bookmarks')
5406 rmarks = other.listkeys('bookmarks')
5473 rmarks = other.listkeys('bookmarks')
5407 diff = set(rmarks) - set(lmarks)
5474 diff = set(rmarks) - set(lmarks)
5408 if len(diff) > 0:
5475 if len(diff) > 0:
5409 t.append(_('%d incoming bookmarks') % len(diff))
5476 t.append(_('%d incoming bookmarks') % len(diff))
5410 diff = set(lmarks) - set(rmarks)
5477 diff = set(lmarks) - set(rmarks)
5411 if len(diff) > 0:
5478 if len(diff) > 0:
5412 t.append(_('%d outgoing bookmarks') % len(diff))
5479 t.append(_('%d outgoing bookmarks') % len(diff))
5413
5480
5414 if t:
5481 if t:
5415 # i18n: column positioning for "hg summary"
5482 # i18n: column positioning for "hg summary"
5416 ui.write(_('remote: %s\n') % (', '.join(t)))
5483 ui.write(_('remote: %s\n') % (', '.join(t)))
5417 else:
5484 else:
5418 # i18n: column positioning for "hg summary"
5485 # i18n: column positioning for "hg summary"
5419 ui.status(_('remote: (synced)\n'))
5486 ui.status(_('remote: (synced)\n'))
5420
5487
5421 @command('tag',
5488 @command('tag',
5422 [('f', 'force', None, _('force tag')),
5489 [('f', 'force', None, _('force tag')),
5423 ('l', 'local', None, _('make the tag local')),
5490 ('l', 'local', None, _('make the tag local')),
5424 ('r', 'rev', '', _('revision to tag'), _('REV')),
5491 ('r', 'rev', '', _('revision to tag'), _('REV')),
5425 ('', 'remove', None, _('remove a tag')),
5492 ('', 'remove', None, _('remove a tag')),
5426 # -l/--local is already there, commitopts cannot be used
5493 # -l/--local is already there, commitopts cannot be used
5427 ('e', 'edit', None, _('edit commit message')),
5494 ('e', 'edit', None, _('edit commit message')),
5428 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5495 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5429 ] + commitopts2,
5496 ] + commitopts2,
5430 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5497 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5431 def tag(ui, repo, name1, *names, **opts):
5498 def tag(ui, repo, name1, *names, **opts):
5432 """add one or more tags for the current or given revision
5499 """add one or more tags for the current or given revision
5433
5500
5434 Name a particular revision using <name>.
5501 Name a particular revision using <name>.
5435
5502
5436 Tags are used to name particular revisions of the repository and are
5503 Tags are used to name particular revisions of the repository and are
5437 very useful to compare different revisions, to go back to significant
5504 very useful to compare different revisions, to go back to significant
5438 earlier versions or to mark branch points as releases, etc. Changing
5505 earlier versions or to mark branch points as releases, etc. Changing
5439 an existing tag is normally disallowed; use -f/--force to override.
5506 an existing tag is normally disallowed; use -f/--force to override.
5440
5507
5441 If no revision is given, the parent of the working directory is
5508 If no revision is given, the parent of the working directory is
5442 used, or tip if no revision is checked out.
5509 used, or tip if no revision is checked out.
5443
5510
5444 To facilitate version control, distribution, and merging of tags,
5511 To facilitate version control, distribution, and merging of tags,
5445 they are stored as a file named ".hgtags" which is managed similarly
5512 they are stored as a file named ".hgtags" which is managed similarly
5446 to other project files and can be hand-edited if necessary. This
5513 to other project files and can be hand-edited if necessary. This
5447 also means that tagging creates a new commit. The file
5514 also means that tagging creates a new commit. The file
5448 ".hg/localtags" is used for local tags (not shared among
5515 ".hg/localtags" is used for local tags (not shared among
5449 repositories).
5516 repositories).
5450
5517
5451 Tag commits are usually made at the head of a branch. If the parent
5518 Tag commits are usually made at the head of a branch. If the parent
5452 of the working directory is not a branch head, :hg:`tag` aborts; use
5519 of the working directory is not a branch head, :hg:`tag` aborts; use
5453 -f/--force to force the tag commit to be based on a non-head
5520 -f/--force to force the tag commit to be based on a non-head
5454 changeset.
5521 changeset.
5455
5522
5456 See :hg:`help dates` for a list of formats valid for -d/--date.
5523 See :hg:`help dates` for a list of formats valid for -d/--date.
5457
5524
5458 Since tag names have priority over branch names during revision
5525 Since tag names have priority over branch names during revision
5459 lookup, using an existing branch name as a tag name is discouraged.
5526 lookup, using an existing branch name as a tag name is discouraged.
5460
5527
5461 Returns 0 on success.
5528 Returns 0 on success.
5462 """
5529 """
5463 wlock = lock = None
5530 wlock = lock = None
5464 try:
5531 try:
5465 wlock = repo.wlock()
5532 wlock = repo.wlock()
5466 lock = repo.lock()
5533 lock = repo.lock()
5467 rev_ = "."
5534 rev_ = "."
5468 names = [t.strip() for t in (name1,) + names]
5535 names = [t.strip() for t in (name1,) + names]
5469 if len(names) != len(set(names)):
5536 if len(names) != len(set(names)):
5470 raise util.Abort(_('tag names must be unique'))
5537 raise util.Abort(_('tag names must be unique'))
5471 for n in names:
5538 for n in names:
5472 scmutil.checknewlabel(repo, n, 'tag')
5539 scmutil.checknewlabel(repo, n, 'tag')
5473 if not n:
5540 if not n:
5474 raise util.Abort(_('tag names cannot consist entirely of '
5541 raise util.Abort(_('tag names cannot consist entirely of '
5475 'whitespace'))
5542 'whitespace'))
5476 if opts.get('rev') and opts.get('remove'):
5543 if opts.get('rev') and opts.get('remove'):
5477 raise util.Abort(_("--rev and --remove are incompatible"))
5544 raise util.Abort(_("--rev and --remove are incompatible"))
5478 if opts.get('rev'):
5545 if opts.get('rev'):
5479 rev_ = opts['rev']
5546 rev_ = opts['rev']
5480 message = opts.get('message')
5547 message = opts.get('message')
5481 if opts.get('remove'):
5548 if opts.get('remove'):
5482 expectedtype = opts.get('local') and 'local' or 'global'
5549 expectedtype = opts.get('local') and 'local' or 'global'
5483 for n in names:
5550 for n in names:
5484 if not repo.tagtype(n):
5551 if not repo.tagtype(n):
5485 raise util.Abort(_("tag '%s' does not exist") % n)
5552 raise util.Abort(_("tag '%s' does not exist") % n)
5486 if repo.tagtype(n) != expectedtype:
5553 if repo.tagtype(n) != expectedtype:
5487 if expectedtype == 'global':
5554 if expectedtype == 'global':
5488 raise util.Abort(_("tag '%s' is not a global tag") % n)
5555 raise util.Abort(_("tag '%s' is not a global tag") % n)
5489 else:
5556 else:
5490 raise util.Abort(_("tag '%s' is not a local tag") % n)
5557 raise util.Abort(_("tag '%s' is not a local tag") % n)
5491 rev_ = nullid
5558 rev_ = nullid
5492 if not message:
5559 if not message:
5493 # we don't translate commit messages
5560 # we don't translate commit messages
5494 message = 'Removed tag %s' % ', '.join(names)
5561 message = 'Removed tag %s' % ', '.join(names)
5495 elif not opts.get('force'):
5562 elif not opts.get('force'):
5496 for n in names:
5563 for n in names:
5497 if n in repo.tags():
5564 if n in repo.tags():
5498 raise util.Abort(_("tag '%s' already exists "
5565 raise util.Abort(_("tag '%s' already exists "
5499 "(use -f to force)") % n)
5566 "(use -f to force)") % n)
5500 if not opts.get('local'):
5567 if not opts.get('local'):
5501 p1, p2 = repo.dirstate.parents()
5568 p1, p2 = repo.dirstate.parents()
5502 if p2 != nullid:
5569 if p2 != nullid:
5503 raise util.Abort(_('uncommitted merge'))
5570 raise util.Abort(_('uncommitted merge'))
5504 bheads = repo.branchheads()
5571 bheads = repo.branchheads()
5505 if not opts.get('force') and bheads and p1 not in bheads:
5572 if not opts.get('force') and bheads and p1 not in bheads:
5506 raise util.Abort(_('not at a branch head (use -f to force)'))
5573 raise util.Abort(_('not at a branch head (use -f to force)'))
5507 r = scmutil.revsingle(repo, rev_).node()
5574 r = scmutil.revsingle(repo, rev_).node()
5508
5575
5509 if not message:
5576 if not message:
5510 # we don't translate commit messages
5577 # we don't translate commit messages
5511 message = ('Added tag %s for changeset %s' %
5578 message = ('Added tag %s for changeset %s' %
5512 (', '.join(names), short(r)))
5579 (', '.join(names), short(r)))
5513
5580
5514 date = opts.get('date')
5581 date = opts.get('date')
5515 if date:
5582 if date:
5516 date = util.parsedate(date)
5583 date = util.parsedate(date)
5517
5584
5518 if opts.get('edit'):
5585 if opts.get('edit'):
5519 message = ui.edit(message, ui.username())
5586 message = ui.edit(message, ui.username())
5520
5587
5521 # don't allow tagging the null rev
5588 # don't allow tagging the null rev
5522 if (not opts.get('remove') and
5589 if (not opts.get('remove') and
5523 scmutil.revsingle(repo, rev_).rev() == nullrev):
5590 scmutil.revsingle(repo, rev_).rev() == nullrev):
5524 raise util.Abort(_("null revision specified"))
5591 raise util.Abort(_("null revision specified"))
5525
5592
5526 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5593 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5527 finally:
5594 finally:
5528 release(lock, wlock)
5595 release(lock, wlock)
5529
5596
5530 @command('tags', [], '')
5597 @command('tags', [], '')
5531 def tags(ui, repo, **opts):
5598 def tags(ui, repo, **opts):
5532 """list repository tags
5599 """list repository tags
5533
5600
5534 This lists both regular and local tags. When the -v/--verbose
5601 This lists both regular and local tags. When the -v/--verbose
5535 switch is used, a third column "local" is printed for local tags.
5602 switch is used, a third column "local" is printed for local tags.
5536
5603
5537 Returns 0 on success.
5604 Returns 0 on success.
5538 """
5605 """
5539
5606
5540 fm = ui.formatter('tags', opts)
5607 fm = ui.formatter('tags', opts)
5541 hexfunc = ui.debugflag and hex or short
5608 hexfunc = ui.debugflag and hex or short
5542 tagtype = ""
5609 tagtype = ""
5543
5610
5544 for t, n in reversed(repo.tagslist()):
5611 for t, n in reversed(repo.tagslist()):
5545 hn = hexfunc(n)
5612 hn = hexfunc(n)
5546 label = 'tags.normal'
5613 label = 'tags.normal'
5547 tagtype = ''
5614 tagtype = ''
5548 if repo.tagtype(t) == 'local':
5615 if repo.tagtype(t) == 'local':
5549 label = 'tags.local'
5616 label = 'tags.local'
5550 tagtype = 'local'
5617 tagtype = 'local'
5551
5618
5552 fm.startitem()
5619 fm.startitem()
5553 fm.write('tag', '%s', t, label=label)
5620 fm.write('tag', '%s', t, label=label)
5554 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5621 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5555 fm.condwrite(not ui.quiet, 'rev id', fmt,
5622 fm.condwrite(not ui.quiet, 'rev id', fmt,
5556 repo.changelog.rev(n), hn, label=label)
5623 repo.changelog.rev(n), hn, label=label)
5557 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5624 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5558 tagtype, label=label)
5625 tagtype, label=label)
5559 fm.plain('\n')
5626 fm.plain('\n')
5560 fm.end()
5627 fm.end()
5561
5628
5562 @command('tip',
5629 @command('tip',
5563 [('p', 'patch', None, _('show patch')),
5630 [('p', 'patch', None, _('show patch')),
5564 ('g', 'git', None, _('use git extended diff format')),
5631 ('g', 'git', None, _('use git extended diff format')),
5565 ] + templateopts,
5632 ] + templateopts,
5566 _('[-p] [-g]'))
5633 _('[-p] [-g]'))
5567 def tip(ui, repo, **opts):
5634 def tip(ui, repo, **opts):
5568 """show the tip revision
5635 """show the tip revision
5569
5636
5570 The tip revision (usually just called the tip) is the changeset
5637 The tip revision (usually just called the tip) is the changeset
5571 most recently added to the repository (and therefore the most
5638 most recently added to the repository (and therefore the most
5572 recently changed head).
5639 recently changed head).
5573
5640
5574 If you have just made a commit, that commit will be the tip. If
5641 If you have just made a commit, that commit will be the tip. If
5575 you have just pulled changes from another repository, the tip of
5642 you have just pulled changes from another repository, the tip of
5576 that repository becomes the current tip. The "tip" tag is special
5643 that repository becomes the current tip. The "tip" tag is special
5577 and cannot be renamed or assigned to a different changeset.
5644 and cannot be renamed or assigned to a different changeset.
5578
5645
5579 Returns 0 on success.
5646 Returns 0 on success.
5580 """
5647 """
5581 displayer = cmdutil.show_changeset(ui, repo, opts)
5648 displayer = cmdutil.show_changeset(ui, repo, opts)
5582 displayer.show(repo['tip'])
5649 displayer.show(repo['tip'])
5583 displayer.close()
5650 displayer.close()
5584
5651
5585 @command('unbundle',
5652 @command('unbundle',
5586 [('u', 'update', None,
5653 [('u', 'update', None,
5587 _('update to new branch head if changesets were unbundled'))],
5654 _('update to new branch head if changesets were unbundled'))],
5588 _('[-u] FILE...'))
5655 _('[-u] FILE...'))
5589 def unbundle(ui, repo, fname1, *fnames, **opts):
5656 def unbundle(ui, repo, fname1, *fnames, **opts):
5590 """apply one or more changegroup files
5657 """apply one or more changegroup files
5591
5658
5592 Apply one or more compressed changegroup files generated by the
5659 Apply one or more compressed changegroup files generated by the
5593 bundle command.
5660 bundle command.
5594
5661
5595 Returns 0 on success, 1 if an update has unresolved files.
5662 Returns 0 on success, 1 if an update has unresolved files.
5596 """
5663 """
5597 fnames = (fname1,) + fnames
5664 fnames = (fname1,) + fnames
5598
5665
5599 lock = repo.lock()
5666 lock = repo.lock()
5600 wc = repo['.']
5667 wc = repo['.']
5601 try:
5668 try:
5602 for fname in fnames:
5669 for fname in fnames:
5603 f = hg.openpath(ui, fname)
5670 f = hg.openpath(ui, fname)
5604 gen = changegroup.readbundle(f, fname)
5671 gen = changegroup.readbundle(f, fname)
5605 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5672 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5606 finally:
5673 finally:
5607 lock.release()
5674 lock.release()
5608 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5675 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5609 return postincoming(ui, repo, modheads, opts.get('update'), None)
5676 return postincoming(ui, repo, modheads, opts.get('update'), None)
5610
5677
5611 @command('^update|up|checkout|co',
5678 @command('^update|up|checkout|co',
5612 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5679 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5613 ('c', 'check', None,
5680 ('c', 'check', None,
5614 _('update across branches if no uncommitted changes')),
5681 _('update across branches if no uncommitted changes')),
5615 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5682 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5616 ('r', 'rev', '', _('revision'), _('REV'))],
5683 ('r', 'rev', '', _('revision'), _('REV'))],
5617 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5684 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5618 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5685 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5619 """update working directory (or switch revisions)
5686 """update working directory (or switch revisions)
5620
5687
5621 Update the repository's working directory to the specified
5688 Update the repository's working directory to the specified
5622 changeset. If no changeset is specified, update to the tip of the
5689 changeset. If no changeset is specified, update to the tip of the
5623 current named branch and move the current bookmark (see :hg:`help
5690 current named branch and move the current bookmark (see :hg:`help
5624 bookmarks`).
5691 bookmarks`).
5625
5692
5626 Update sets the working directory's parent revision to the specified
5693 Update sets the working directory's parent revision to the specified
5627 changeset (see :hg:`help parents`).
5694 changeset (see :hg:`help parents`).
5628
5695
5629 If the changeset is not a descendant or ancestor of the working
5696 If the changeset is not a descendant or ancestor of the working
5630 directory's parent, the update is aborted. With the -c/--check
5697 directory's parent, the update is aborted. With the -c/--check
5631 option, the working directory is checked for uncommitted changes; if
5698 option, the working directory is checked for uncommitted changes; if
5632 none are found, the working directory is updated to the specified
5699 none are found, the working directory is updated to the specified
5633 changeset.
5700 changeset.
5634
5701
5635 .. container:: verbose
5702 .. container:: verbose
5636
5703
5637 The following rules apply when the working directory contains
5704 The following rules apply when the working directory contains
5638 uncommitted changes:
5705 uncommitted changes:
5639
5706
5640 1. If neither -c/--check nor -C/--clean is specified, and if
5707 1. If neither -c/--check nor -C/--clean is specified, and if
5641 the requested changeset is an ancestor or descendant of
5708 the requested changeset is an ancestor or descendant of
5642 the working directory's parent, the uncommitted changes
5709 the working directory's parent, the uncommitted changes
5643 are merged into the requested changeset and the merged
5710 are merged into the requested changeset and the merged
5644 result is left uncommitted. If the requested changeset is
5711 result is left uncommitted. If the requested changeset is
5645 not an ancestor or descendant (that is, it is on another
5712 not an ancestor or descendant (that is, it is on another
5646 branch), the update is aborted and the uncommitted changes
5713 branch), the update is aborted and the uncommitted changes
5647 are preserved.
5714 are preserved.
5648
5715
5649 2. With the -c/--check option, the update is aborted and the
5716 2. With the -c/--check option, the update is aborted and the
5650 uncommitted changes are preserved.
5717 uncommitted changes are preserved.
5651
5718
5652 3. With the -C/--clean option, uncommitted changes are discarded and
5719 3. With the -C/--clean option, uncommitted changes are discarded and
5653 the working directory is updated to the requested changeset.
5720 the working directory is updated to the requested changeset.
5654
5721
5655 To cancel an uncommitted merge (and lose your changes), use
5722 To cancel an uncommitted merge (and lose your changes), use
5656 :hg:`update --clean .`.
5723 :hg:`update --clean .`.
5657
5724
5658 Use null as the changeset to remove the working directory (like
5725 Use null as the changeset to remove the working directory (like
5659 :hg:`clone -U`).
5726 :hg:`clone -U`).
5660
5727
5661 If you want to revert just one file to an older revision, use
5728 If you want to revert just one file to an older revision, use
5662 :hg:`revert [-r REV] NAME`.
5729 :hg:`revert [-r REV] NAME`.
5663
5730
5664 See :hg:`help dates` for a list of formats valid for -d/--date.
5731 See :hg:`help dates` for a list of formats valid for -d/--date.
5665
5732
5666 Returns 0 on success, 1 if there are unresolved files.
5733 Returns 0 on success, 1 if there are unresolved files.
5667 """
5734 """
5668 if rev and node:
5735 if rev and node:
5669 raise util.Abort(_("please specify just one revision"))
5736 raise util.Abort(_("please specify just one revision"))
5670
5737
5671 if rev is None or rev == '':
5738 if rev is None or rev == '':
5672 rev = node
5739 rev = node
5673
5740
5674 # with no argument, we also move the current bookmark, if any
5741 # with no argument, we also move the current bookmark, if any
5675 movemarkfrom = None
5742 movemarkfrom = None
5676 if rev is None:
5743 if rev is None:
5677 curmark = repo._bookmarkcurrent
5744 curmark = repo._bookmarkcurrent
5678 if bookmarks.iscurrent(repo):
5745 if bookmarks.iscurrent(repo):
5679 movemarkfrom = repo['.'].node()
5746 movemarkfrom = repo['.'].node()
5680 elif curmark:
5747 elif curmark:
5681 ui.status(_("updating to active bookmark %s\n") % curmark)
5748 ui.status(_("updating to active bookmark %s\n") % curmark)
5682 rev = curmark
5749 rev = curmark
5683
5750
5684 # if we defined a bookmark, we have to remember the original bookmark name
5751 # if we defined a bookmark, we have to remember the original bookmark name
5685 brev = rev
5752 brev = rev
5686 rev = scmutil.revsingle(repo, rev, rev).rev()
5753 rev = scmutil.revsingle(repo, rev, rev).rev()
5687
5754
5688 if check and clean:
5755 if check and clean:
5689 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5756 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5690
5757
5691 if date:
5758 if date:
5692 if rev is not None:
5759 if rev is not None:
5693 raise util.Abort(_("you can't specify a revision and a date"))
5760 raise util.Abort(_("you can't specify a revision and a date"))
5694 rev = cmdutil.finddate(ui, repo, date)
5761 rev = cmdutil.finddate(ui, repo, date)
5695
5762
5696 if check:
5763 if check:
5697 c = repo[None]
5764 c = repo[None]
5698 if c.dirty(merge=False, branch=False, missing=True):
5765 if c.dirty(merge=False, branch=False, missing=True):
5699 raise util.Abort(_("uncommitted local changes"))
5766 raise util.Abort(_("uncommitted local changes"))
5700 if rev is None:
5767 if rev is None:
5701 rev = repo[repo[None].branch()].rev()
5768 rev = repo[repo[None].branch()].rev()
5702 mergemod._checkunknown(repo, repo[None], repo[rev])
5769 mergemod._checkunknown(repo, repo[None], repo[rev])
5703
5770
5704 if clean:
5771 if clean:
5705 ret = hg.clean(repo, rev)
5772 ret = hg.clean(repo, rev)
5706 else:
5773 else:
5707 ret = hg.update(repo, rev)
5774 ret = hg.update(repo, rev)
5708
5775
5709 if not ret and movemarkfrom:
5776 if not ret and movemarkfrom:
5710 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5777 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5711 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5778 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5712 elif brev in repo._bookmarks:
5779 elif brev in repo._bookmarks:
5713 bookmarks.setcurrent(repo, brev)
5780 bookmarks.setcurrent(repo, brev)
5714 elif brev:
5781 elif brev:
5715 bookmarks.unsetcurrent(repo)
5782 bookmarks.unsetcurrent(repo)
5716
5783
5717 return ret
5784 return ret
5718
5785
5719 @command('verify', [])
5786 @command('verify', [])
5720 def verify(ui, repo):
5787 def verify(ui, repo):
5721 """verify the integrity of the repository
5788 """verify the integrity of the repository
5722
5789
5723 Verify the integrity of the current repository.
5790 Verify the integrity of the current repository.
5724
5791
5725 This will perform an extensive check of the repository's
5792 This will perform an extensive check of the repository's
5726 integrity, validating the hashes and checksums of each entry in
5793 integrity, validating the hashes and checksums of each entry in
5727 the changelog, manifest, and tracked files, as well as the
5794 the changelog, manifest, and tracked files, as well as the
5728 integrity of their crosslinks and indices.
5795 integrity of their crosslinks and indices.
5729
5796
5730 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5797 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5731 for more information about recovery from corruption of the
5798 for more information about recovery from corruption of the
5732 repository.
5799 repository.
5733
5800
5734 Returns 0 on success, 1 if errors are encountered.
5801 Returns 0 on success, 1 if errors are encountered.
5735 """
5802 """
5736 return hg.verify(repo)
5803 return hg.verify(repo)
5737
5804
5738 @command('version', [])
5805 @command('version', [])
5739 def version_(ui):
5806 def version_(ui):
5740 """output version and copyright information"""
5807 """output version and copyright information"""
5741 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5808 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5742 % util.version())
5809 % util.version())
5743 ui.status(_(
5810 ui.status(_(
5744 "(see http://mercurial.selenic.com for more information)\n"
5811 "(see http://mercurial.selenic.com for more information)\n"
5745 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5812 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5746 "This is free software; see the source for copying conditions. "
5813 "This is free software; see the source for copying conditions. "
5747 "There is NO\nwarranty; "
5814 "There is NO\nwarranty; "
5748 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5815 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5749 ))
5816 ))
5750
5817
5751 norepo = ("clone init version help debugcommands debugcomplete"
5818 norepo = ("clone init version help debugcommands debugcomplete"
5752 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5819 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5753 " debugknown debuggetbundle debugbundle")
5820 " debugknown debuggetbundle debugbundle")
5754 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5821 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5755 " debugdata debugindex debugindexdot debugrevlog")
5822 " debugdata debugindex debugindexdot debugrevlog")
5756 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5823 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5757 " remove resolve status debugwalk")
5824 " remove resolve status debugwalk")
@@ -1,825 +1,828 b''
1 # dirstate.py - working directory tracking for mercurial
1 # dirstate.py - working directory tracking 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 import errno
7 import errno
8
8
9 from node import nullid
9 from node import nullid
10 from i18n import _
10 from i18n import _
11 import scmutil, util, ignore, osutil, parsers, encoding
11 import scmutil, util, ignore, osutil, parsers, encoding
12 import os, stat, errno, gc
12 import os, stat, errno, gc
13
13
14 propertycache = util.propertycache
14 propertycache = util.propertycache
15 filecache = scmutil.filecache
15 filecache = scmutil.filecache
16 _rangemask = 0x7fffffff
16 _rangemask = 0x7fffffff
17
17
18 class repocache(filecache):
18 class repocache(filecache):
19 """filecache for files in .hg/"""
19 """filecache for files in .hg/"""
20 def join(self, obj, fname):
20 def join(self, obj, fname):
21 return obj._opener.join(fname)
21 return obj._opener.join(fname)
22
22
23 class rootcache(filecache):
23 class rootcache(filecache):
24 """filecache for files in the repository root"""
24 """filecache for files in the repository root"""
25 def join(self, obj, fname):
25 def join(self, obj, fname):
26 return obj._join(fname)
26 return obj._join(fname)
27
27
28 def _finddirs(path):
28 def _finddirs(path):
29 pos = path.rfind('/')
29 pos = path.rfind('/')
30 while pos != -1:
30 while pos != -1:
31 yield path[:pos]
31 yield path[:pos]
32 pos = path.rfind('/', 0, pos)
32 pos = path.rfind('/', 0, pos)
33
33
34 def _incdirs(dirs, path):
34 def _incdirs(dirs, path):
35 for base in _finddirs(path):
35 for base in _finddirs(path):
36 if base in dirs:
36 if base in dirs:
37 dirs[base] += 1
37 dirs[base] += 1
38 return
38 return
39 dirs[base] = 1
39 dirs[base] = 1
40
40
41 def _decdirs(dirs, path):
41 def _decdirs(dirs, path):
42 for base in _finddirs(path):
42 for base in _finddirs(path):
43 if dirs[base] > 1:
43 if dirs[base] > 1:
44 dirs[base] -= 1
44 dirs[base] -= 1
45 return
45 return
46 del dirs[base]
46 del dirs[base]
47
47
48 class dirstate(object):
48 class dirstate(object):
49
49
50 def __init__(self, opener, ui, root, validate):
50 def __init__(self, opener, ui, root, validate):
51 '''Create a new dirstate object.
51 '''Create a new dirstate object.
52
52
53 opener is an open()-like callable that can be used to open the
53 opener is an open()-like callable that can be used to open the
54 dirstate file; root is the root of the directory tracked by
54 dirstate file; root is the root of the directory tracked by
55 the dirstate.
55 the dirstate.
56 '''
56 '''
57 self._opener = opener
57 self._opener = opener
58 self._validate = validate
58 self._validate = validate
59 self._root = root
59 self._root = root
60 self._rootdir = os.path.join(root, '')
60 self._rootdir = os.path.join(root, '')
61 self._dirty = False
61 self._dirty = False
62 self._dirtypl = False
62 self._dirtypl = False
63 self._lastnormaltime = 0
63 self._lastnormaltime = 0
64 self._ui = ui
64 self._ui = ui
65 self._filecache = {}
65 self._filecache = {}
66
66
67 @propertycache
67 @propertycache
68 def _map(self):
68 def _map(self):
69 '''Return the dirstate contents as a map from filename to
69 '''Return the dirstate contents as a map from filename to
70 (state, mode, size, time).'''
70 (state, mode, size, time).'''
71 self._read()
71 self._read()
72 return self._map
72 return self._map
73
73
74 @propertycache
74 @propertycache
75 def _copymap(self):
75 def _copymap(self):
76 self._read()
76 self._read()
77 return self._copymap
77 return self._copymap
78
78
79 @propertycache
79 @propertycache
80 def _foldmap(self):
80 def _foldmap(self):
81 f = {}
81 f = {}
82 for name in self._map:
82 for name in self._map:
83 f[util.normcase(name)] = name
83 f[util.normcase(name)] = name
84 for name in self._dirs:
84 for name in self._dirs:
85 f[util.normcase(name)] = name
85 f[util.normcase(name)] = name
86 f['.'] = '.' # prevents useless util.fspath() invocation
86 f['.'] = '.' # prevents useless util.fspath() invocation
87 return f
87 return f
88
88
89 @repocache('branch')
89 @repocache('branch')
90 def _branch(self):
90 def _branch(self):
91 try:
91 try:
92 return self._opener.read("branch").strip() or "default"
92 return self._opener.read("branch").strip() or "default"
93 except IOError, inst:
93 except IOError, inst:
94 if inst.errno != errno.ENOENT:
94 if inst.errno != errno.ENOENT:
95 raise
95 raise
96 return "default"
96 return "default"
97
97
98 @propertycache
98 @propertycache
99 def _pl(self):
99 def _pl(self):
100 try:
100 try:
101 fp = self._opener("dirstate")
101 fp = self._opener("dirstate")
102 st = fp.read(40)
102 st = fp.read(40)
103 fp.close()
103 fp.close()
104 l = len(st)
104 l = len(st)
105 if l == 40:
105 if l == 40:
106 return st[:20], st[20:40]
106 return st[:20], st[20:40]
107 elif l > 0 and l < 40:
107 elif l > 0 and l < 40:
108 raise util.Abort(_('working directory state appears damaged!'))
108 raise util.Abort(_('working directory state appears damaged!'))
109 except IOError, err:
109 except IOError, err:
110 if err.errno != errno.ENOENT:
110 if err.errno != errno.ENOENT:
111 raise
111 raise
112 return [nullid, nullid]
112 return [nullid, nullid]
113
113
114 @propertycache
114 @propertycache
115 def _dirs(self):
115 def _dirs(self):
116 dirs = {}
116 dirs = {}
117 for f, s in self._map.iteritems():
117 for f, s in self._map.iteritems():
118 if s[0] != 'r':
118 if s[0] != 'r':
119 _incdirs(dirs, f)
119 _incdirs(dirs, f)
120 return dirs
120 return dirs
121
121
122 def dirs(self):
122 def dirs(self):
123 return self._dirs
123 return self._dirs
124
124
125 @rootcache('.hgignore')
125 @rootcache('.hgignore')
126 def _ignore(self):
126 def _ignore(self):
127 files = [self._join('.hgignore')]
127 files = [self._join('.hgignore')]
128 for name, path in self._ui.configitems("ui"):
128 for name, path in self._ui.configitems("ui"):
129 if name == 'ignore' or name.startswith('ignore.'):
129 if name == 'ignore' or name.startswith('ignore.'):
130 files.append(util.expandpath(path))
130 files.append(util.expandpath(path))
131 return ignore.ignore(self._root, files, self._ui.warn)
131 return ignore.ignore(self._root, files, self._ui.warn)
132
132
133 @propertycache
133 @propertycache
134 def _slash(self):
134 def _slash(self):
135 return self._ui.configbool('ui', 'slash') and os.sep != '/'
135 return self._ui.configbool('ui', 'slash') and os.sep != '/'
136
136
137 @propertycache
137 @propertycache
138 def _checklink(self):
138 def _checklink(self):
139 return util.checklink(self._root)
139 return util.checklink(self._root)
140
140
141 @propertycache
141 @propertycache
142 def _checkexec(self):
142 def _checkexec(self):
143 return util.checkexec(self._root)
143 return util.checkexec(self._root)
144
144
145 @propertycache
145 @propertycache
146 def _checkcase(self):
146 def _checkcase(self):
147 return not util.checkcase(self._join('.hg'))
147 return not util.checkcase(self._join('.hg'))
148
148
149 def _join(self, f):
149 def _join(self, f):
150 # much faster than os.path.join()
150 # much faster than os.path.join()
151 # it's safe because f is always a relative path
151 # it's safe because f is always a relative path
152 return self._rootdir + f
152 return self._rootdir + f
153
153
154 def flagfunc(self, buildfallback):
154 def flagfunc(self, buildfallback):
155 if self._checklink and self._checkexec:
155 if self._checklink and self._checkexec:
156 def f(x):
156 def f(x):
157 p = self._join(x)
157 p = self._join(x)
158 if os.path.islink(p):
158 if os.path.islink(p):
159 return 'l'
159 return 'l'
160 if util.isexec(p):
160 if util.isexec(p):
161 return 'x'
161 return 'x'
162 return ''
162 return ''
163 return f
163 return f
164
164
165 fallback = buildfallback()
165 fallback = buildfallback()
166 if self._checklink:
166 if self._checklink:
167 def f(x):
167 def f(x):
168 if os.path.islink(self._join(x)):
168 if os.path.islink(self._join(x)):
169 return 'l'
169 return 'l'
170 if 'x' in fallback(x):
170 if 'x' in fallback(x):
171 return 'x'
171 return 'x'
172 return ''
172 return ''
173 return f
173 return f
174 if self._checkexec:
174 if self._checkexec:
175 def f(x):
175 def f(x):
176 if 'l' in fallback(x):
176 if 'l' in fallback(x):
177 return 'l'
177 return 'l'
178 if util.isexec(self._join(x)):
178 if util.isexec(self._join(x)):
179 return 'x'
179 return 'x'
180 return ''
180 return ''
181 return f
181 return f
182 else:
182 else:
183 return fallback
183 return fallback
184
184
185 def getcwd(self):
185 def getcwd(self):
186 cwd = os.getcwd()
186 cwd = os.getcwd()
187 if cwd == self._root:
187 if cwd == self._root:
188 return ''
188 return ''
189 # self._root ends with a path separator if self._root is '/' or 'C:\'
189 # self._root ends with a path separator if self._root is '/' or 'C:\'
190 rootsep = self._root
190 rootsep = self._root
191 if not util.endswithsep(rootsep):
191 if not util.endswithsep(rootsep):
192 rootsep += os.sep
192 rootsep += os.sep
193 if cwd.startswith(rootsep):
193 if cwd.startswith(rootsep):
194 return cwd[len(rootsep):]
194 return cwd[len(rootsep):]
195 else:
195 else:
196 # we're outside the repo. return an absolute path.
196 # we're outside the repo. return an absolute path.
197 return cwd
197 return cwd
198
198
199 def pathto(self, f, cwd=None):
199 def pathto(self, f, cwd=None):
200 if cwd is None:
200 if cwd is None:
201 cwd = self.getcwd()
201 cwd = self.getcwd()
202 path = util.pathto(self._root, cwd, f)
202 path = util.pathto(self._root, cwd, f)
203 if self._slash:
203 if self._slash:
204 return util.normpath(path)
204 return util.normpath(path)
205 return path
205 return path
206
206
207 def __getitem__(self, key):
207 def __getitem__(self, key):
208 '''Return the current state of key (a filename) in the dirstate.
208 '''Return the current state of key (a filename) in the dirstate.
209
209
210 States are:
210 States are:
211 n normal
211 n normal
212 m needs merging
212 m needs merging
213 r marked for removal
213 r marked for removal
214 a marked for addition
214 a marked for addition
215 ? not tracked
215 ? not tracked
216 '''
216 '''
217 return self._map.get(key, ("?",))[0]
217 return self._map.get(key, ("?",))[0]
218
218
219 def __contains__(self, key):
219 def __contains__(self, key):
220 return key in self._map
220 return key in self._map
221
221
222 def __iter__(self):
222 def __iter__(self):
223 for x in sorted(self._map):
223 for x in sorted(self._map):
224 yield x
224 yield x
225
225
226 def iteritems(self):
227 return self._map.iteritems()
228
226 def parents(self):
229 def parents(self):
227 return [self._validate(p) for p in self._pl]
230 return [self._validate(p) for p in self._pl]
228
231
229 def p1(self):
232 def p1(self):
230 return self._validate(self._pl[0])
233 return self._validate(self._pl[0])
231
234
232 def p2(self):
235 def p2(self):
233 return self._validate(self._pl[1])
236 return self._validate(self._pl[1])
234
237
235 def branch(self):
238 def branch(self):
236 return encoding.tolocal(self._branch)
239 return encoding.tolocal(self._branch)
237
240
238 def setparents(self, p1, p2=nullid):
241 def setparents(self, p1, p2=nullid):
239 """Set dirstate parents to p1 and p2.
242 """Set dirstate parents to p1 and p2.
240
243
241 When moving from two parents to one, 'm' merged entries a
244 When moving from two parents to one, 'm' merged entries a
242 adjusted to normal and previous copy records discarded and
245 adjusted to normal and previous copy records discarded and
243 returned by the call.
246 returned by the call.
244
247
245 See localrepo.setparents()
248 See localrepo.setparents()
246 """
249 """
247 self._dirty = self._dirtypl = True
250 self._dirty = self._dirtypl = True
248 oldp2 = self._pl[1]
251 oldp2 = self._pl[1]
249 self._pl = p1, p2
252 self._pl = p1, p2
250 copies = {}
253 copies = {}
251 if oldp2 != nullid and p2 == nullid:
254 if oldp2 != nullid and p2 == nullid:
252 # Discard 'm' markers when moving away from a merge state
255 # Discard 'm' markers when moving away from a merge state
253 for f, s in self._map.iteritems():
256 for f, s in self._map.iteritems():
254 if s[0] == 'm':
257 if s[0] == 'm':
255 if f in self._copymap:
258 if f in self._copymap:
256 copies[f] = self._copymap[f]
259 copies[f] = self._copymap[f]
257 self.normallookup(f)
260 self.normallookup(f)
258 return copies
261 return copies
259
262
260 def setbranch(self, branch):
263 def setbranch(self, branch):
261 self._branch = encoding.fromlocal(branch)
264 self._branch = encoding.fromlocal(branch)
262 f = self._opener('branch', 'w', atomictemp=True)
265 f = self._opener('branch', 'w', atomictemp=True)
263 try:
266 try:
264 f.write(self._branch + '\n')
267 f.write(self._branch + '\n')
265 f.close()
268 f.close()
266
269
267 # make sure filecache has the correct stat info for _branch after
270 # make sure filecache has the correct stat info for _branch after
268 # replacing the underlying file
271 # replacing the underlying file
269 ce = self._filecache['_branch']
272 ce = self._filecache['_branch']
270 if ce:
273 if ce:
271 ce.refresh()
274 ce.refresh()
272 except: # re-raises
275 except: # re-raises
273 f.discard()
276 f.discard()
274 raise
277 raise
275
278
276 def _read(self):
279 def _read(self):
277 self._map = {}
280 self._map = {}
278 self._copymap = {}
281 self._copymap = {}
279 try:
282 try:
280 st = self._opener.read("dirstate")
283 st = self._opener.read("dirstate")
281 except IOError, err:
284 except IOError, err:
282 if err.errno != errno.ENOENT:
285 if err.errno != errno.ENOENT:
283 raise
286 raise
284 return
287 return
285 if not st:
288 if not st:
286 return
289 return
287
290
288 # Python's garbage collector triggers a GC each time a certain number
291 # Python's garbage collector triggers a GC each time a certain number
289 # of container objects (the number being defined by
292 # of container objects (the number being defined by
290 # gc.get_threshold()) are allocated. parse_dirstate creates a tuple
293 # gc.get_threshold()) are allocated. parse_dirstate creates a tuple
291 # for each file in the dirstate. The C version then immediately marks
294 # for each file in the dirstate. The C version then immediately marks
292 # them as not to be tracked by the collector. However, this has no
295 # them as not to be tracked by the collector. However, this has no
293 # effect on when GCs are triggered, only on what objects the GC looks
296 # effect on when GCs are triggered, only on what objects the GC looks
294 # into. This means that O(number of files) GCs are unavoidable.
297 # into. This means that O(number of files) GCs are unavoidable.
295 # Depending on when in the process's lifetime the dirstate is parsed,
298 # Depending on when in the process's lifetime the dirstate is parsed,
296 # this can get very expensive. As a workaround, disable GC while
299 # this can get very expensive. As a workaround, disable GC while
297 # parsing the dirstate.
300 # parsing the dirstate.
298 gcenabled = gc.isenabled()
301 gcenabled = gc.isenabled()
299 gc.disable()
302 gc.disable()
300 try:
303 try:
301 p = parsers.parse_dirstate(self._map, self._copymap, st)
304 p = parsers.parse_dirstate(self._map, self._copymap, st)
302 finally:
305 finally:
303 if gcenabled:
306 if gcenabled:
304 gc.enable()
307 gc.enable()
305 if not self._dirtypl:
308 if not self._dirtypl:
306 self._pl = p
309 self._pl = p
307
310
308 def invalidate(self):
311 def invalidate(self):
309 for a in ("_map", "_copymap", "_foldmap", "_branch", "_pl", "_dirs",
312 for a in ("_map", "_copymap", "_foldmap", "_branch", "_pl", "_dirs",
310 "_ignore"):
313 "_ignore"):
311 if a in self.__dict__:
314 if a in self.__dict__:
312 delattr(self, a)
315 delattr(self, a)
313 self._lastnormaltime = 0
316 self._lastnormaltime = 0
314 self._dirty = False
317 self._dirty = False
315
318
316 def copy(self, source, dest):
319 def copy(self, source, dest):
317 """Mark dest as a copy of source. Unmark dest if source is None."""
320 """Mark dest as a copy of source. Unmark dest if source is None."""
318 if source == dest:
321 if source == dest:
319 return
322 return
320 self._dirty = True
323 self._dirty = True
321 if source is not None:
324 if source is not None:
322 self._copymap[dest] = source
325 self._copymap[dest] = source
323 elif dest in self._copymap:
326 elif dest in self._copymap:
324 del self._copymap[dest]
327 del self._copymap[dest]
325
328
326 def copied(self, file):
329 def copied(self, file):
327 return self._copymap.get(file, None)
330 return self._copymap.get(file, None)
328
331
329 def copies(self):
332 def copies(self):
330 return self._copymap
333 return self._copymap
331
334
332 def _droppath(self, f):
335 def _droppath(self, f):
333 if self[f] not in "?r" and "_dirs" in self.__dict__:
336 if self[f] not in "?r" and "_dirs" in self.__dict__:
334 _decdirs(self._dirs, f)
337 _decdirs(self._dirs, f)
335
338
336 def _addpath(self, f, state, mode, size, mtime):
339 def _addpath(self, f, state, mode, size, mtime):
337 oldstate = self[f]
340 oldstate = self[f]
338 if state == 'a' or oldstate == 'r':
341 if state == 'a' or oldstate == 'r':
339 scmutil.checkfilename(f)
342 scmutil.checkfilename(f)
340 if f in self._dirs:
343 if f in self._dirs:
341 raise util.Abort(_('directory %r already in dirstate') % f)
344 raise util.Abort(_('directory %r already in dirstate') % f)
342 # shadows
345 # shadows
343 for d in _finddirs(f):
346 for d in _finddirs(f):
344 if d in self._dirs:
347 if d in self._dirs:
345 break
348 break
346 if d in self._map and self[d] != 'r':
349 if d in self._map and self[d] != 'r':
347 raise util.Abort(
350 raise util.Abort(
348 _('file %r in dirstate clashes with %r') % (d, f))
351 _('file %r in dirstate clashes with %r') % (d, f))
349 if oldstate in "?r" and "_dirs" in self.__dict__:
352 if oldstate in "?r" and "_dirs" in self.__dict__:
350 _incdirs(self._dirs, f)
353 _incdirs(self._dirs, f)
351 self._dirty = True
354 self._dirty = True
352 self._map[f] = (state, mode, size, mtime)
355 self._map[f] = (state, mode, size, mtime)
353
356
354 def normal(self, f):
357 def normal(self, f):
355 '''Mark a file normal and clean.'''
358 '''Mark a file normal and clean.'''
356 s = os.lstat(self._join(f))
359 s = os.lstat(self._join(f))
357 mtime = int(s.st_mtime)
360 mtime = int(s.st_mtime)
358 self._addpath(f, 'n', s.st_mode,
361 self._addpath(f, 'n', s.st_mode,
359 s.st_size & _rangemask, mtime & _rangemask)
362 s.st_size & _rangemask, mtime & _rangemask)
360 if f in self._copymap:
363 if f in self._copymap:
361 del self._copymap[f]
364 del self._copymap[f]
362 if mtime > self._lastnormaltime:
365 if mtime > self._lastnormaltime:
363 # Remember the most recent modification timeslot for status(),
366 # Remember the most recent modification timeslot for status(),
364 # to make sure we won't miss future size-preserving file content
367 # to make sure we won't miss future size-preserving file content
365 # modifications that happen within the same timeslot.
368 # modifications that happen within the same timeslot.
366 self._lastnormaltime = mtime
369 self._lastnormaltime = mtime
367
370
368 def normallookup(self, f):
371 def normallookup(self, f):
369 '''Mark a file normal, but possibly dirty.'''
372 '''Mark a file normal, but possibly dirty.'''
370 if self._pl[1] != nullid and f in self._map:
373 if self._pl[1] != nullid and f in self._map:
371 # if there is a merge going on and the file was either
374 # if there is a merge going on and the file was either
372 # in state 'm' (-1) or coming from other parent (-2) before
375 # in state 'm' (-1) or coming from other parent (-2) before
373 # being removed, restore that state.
376 # being removed, restore that state.
374 entry = self._map[f]
377 entry = self._map[f]
375 if entry[0] == 'r' and entry[2] in (-1, -2):
378 if entry[0] == 'r' and entry[2] in (-1, -2):
376 source = self._copymap.get(f)
379 source = self._copymap.get(f)
377 if entry[2] == -1:
380 if entry[2] == -1:
378 self.merge(f)
381 self.merge(f)
379 elif entry[2] == -2:
382 elif entry[2] == -2:
380 self.otherparent(f)
383 self.otherparent(f)
381 if source:
384 if source:
382 self.copy(source, f)
385 self.copy(source, f)
383 return
386 return
384 if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
387 if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
385 return
388 return
386 self._addpath(f, 'n', 0, -1, -1)
389 self._addpath(f, 'n', 0, -1, -1)
387 if f in self._copymap:
390 if f in self._copymap:
388 del self._copymap[f]
391 del self._copymap[f]
389
392
390 def otherparent(self, f):
393 def otherparent(self, f):
391 '''Mark as coming from the other parent, always dirty.'''
394 '''Mark as coming from the other parent, always dirty.'''
392 if self._pl[1] == nullid:
395 if self._pl[1] == nullid:
393 raise util.Abort(_("setting %r to other parent "
396 raise util.Abort(_("setting %r to other parent "
394 "only allowed in merges") % f)
397 "only allowed in merges") % f)
395 self._addpath(f, 'n', 0, -2, -1)
398 self._addpath(f, 'n', 0, -2, -1)
396 if f in self._copymap:
399 if f in self._copymap:
397 del self._copymap[f]
400 del self._copymap[f]
398
401
399 def add(self, f):
402 def add(self, f):
400 '''Mark a file added.'''
403 '''Mark a file added.'''
401 self._addpath(f, 'a', 0, -1, -1)
404 self._addpath(f, 'a', 0, -1, -1)
402 if f in self._copymap:
405 if f in self._copymap:
403 del self._copymap[f]
406 del self._copymap[f]
404
407
405 def remove(self, f):
408 def remove(self, f):
406 '''Mark a file removed.'''
409 '''Mark a file removed.'''
407 self._dirty = True
410 self._dirty = True
408 self._droppath(f)
411 self._droppath(f)
409 size = 0
412 size = 0
410 if self._pl[1] != nullid and f in self._map:
413 if self._pl[1] != nullid and f in self._map:
411 # backup the previous state
414 # backup the previous state
412 entry = self._map[f]
415 entry = self._map[f]
413 if entry[0] == 'm': # merge
416 if entry[0] == 'm': # merge
414 size = -1
417 size = -1
415 elif entry[0] == 'n' and entry[2] == -2: # other parent
418 elif entry[0] == 'n' and entry[2] == -2: # other parent
416 size = -2
419 size = -2
417 self._map[f] = ('r', 0, size, 0)
420 self._map[f] = ('r', 0, size, 0)
418 if size == 0 and f in self._copymap:
421 if size == 0 and f in self._copymap:
419 del self._copymap[f]
422 del self._copymap[f]
420
423
421 def merge(self, f):
424 def merge(self, f):
422 '''Mark a file merged.'''
425 '''Mark a file merged.'''
423 if self._pl[1] == nullid:
426 if self._pl[1] == nullid:
424 return self.normallookup(f)
427 return self.normallookup(f)
425 s = os.lstat(self._join(f))
428 s = os.lstat(self._join(f))
426 self._addpath(f, 'm', s.st_mode,
429 self._addpath(f, 'm', s.st_mode,
427 s.st_size & _rangemask, int(s.st_mtime) & _rangemask)
430 s.st_size & _rangemask, int(s.st_mtime) & _rangemask)
428 if f in self._copymap:
431 if f in self._copymap:
429 del self._copymap[f]
432 del self._copymap[f]
430
433
431 def drop(self, f):
434 def drop(self, f):
432 '''Drop a file from the dirstate'''
435 '''Drop a file from the dirstate'''
433 if f in self._map:
436 if f in self._map:
434 self._dirty = True
437 self._dirty = True
435 self._droppath(f)
438 self._droppath(f)
436 del self._map[f]
439 del self._map[f]
437
440
438 def _normalize(self, path, isknown, ignoremissing=False, exists=None):
441 def _normalize(self, path, isknown, ignoremissing=False, exists=None):
439 normed = util.normcase(path)
442 normed = util.normcase(path)
440 folded = self._foldmap.get(normed, None)
443 folded = self._foldmap.get(normed, None)
441 if folded is None:
444 if folded is None:
442 if isknown:
445 if isknown:
443 folded = path
446 folded = path
444 else:
447 else:
445 if exists is None:
448 if exists is None:
446 exists = os.path.lexists(os.path.join(self._root, path))
449 exists = os.path.lexists(os.path.join(self._root, path))
447 if not exists:
450 if not exists:
448 # Maybe a path component exists
451 # Maybe a path component exists
449 if not ignoremissing and '/' in path:
452 if not ignoremissing and '/' in path:
450 d, f = path.rsplit('/', 1)
453 d, f = path.rsplit('/', 1)
451 d = self._normalize(d, isknown, ignoremissing, None)
454 d = self._normalize(d, isknown, ignoremissing, None)
452 folded = d + "/" + f
455 folded = d + "/" + f
453 else:
456 else:
454 # No path components, preserve original case
457 # No path components, preserve original case
455 folded = path
458 folded = path
456 else:
459 else:
457 # recursively normalize leading directory components
460 # recursively normalize leading directory components
458 # against dirstate
461 # against dirstate
459 if '/' in normed:
462 if '/' in normed:
460 d, f = normed.rsplit('/', 1)
463 d, f = normed.rsplit('/', 1)
461 d = self._normalize(d, isknown, ignoremissing, True)
464 d = self._normalize(d, isknown, ignoremissing, True)
462 r = self._root + "/" + d
465 r = self._root + "/" + d
463 folded = d + "/" + util.fspath(f, r)
466 folded = d + "/" + util.fspath(f, r)
464 else:
467 else:
465 folded = util.fspath(normed, self._root)
468 folded = util.fspath(normed, self._root)
466 self._foldmap[normed] = folded
469 self._foldmap[normed] = folded
467
470
468 return folded
471 return folded
469
472
470 def normalize(self, path, isknown=False, ignoremissing=False):
473 def normalize(self, path, isknown=False, ignoremissing=False):
471 '''
474 '''
472 normalize the case of a pathname when on a casefolding filesystem
475 normalize the case of a pathname when on a casefolding filesystem
473
476
474 isknown specifies whether the filename came from walking the
477 isknown specifies whether the filename came from walking the
475 disk, to avoid extra filesystem access.
478 disk, to avoid extra filesystem access.
476
479
477 If ignoremissing is True, missing path are returned
480 If ignoremissing is True, missing path are returned
478 unchanged. Otherwise, we try harder to normalize possibly
481 unchanged. Otherwise, we try harder to normalize possibly
479 existing path components.
482 existing path components.
480
483
481 The normalized case is determined based on the following precedence:
484 The normalized case is determined based on the following precedence:
482
485
483 - version of name already stored in the dirstate
486 - version of name already stored in the dirstate
484 - version of name stored on disk
487 - version of name stored on disk
485 - version provided via command arguments
488 - version provided via command arguments
486 '''
489 '''
487
490
488 if self._checkcase:
491 if self._checkcase:
489 return self._normalize(path, isknown, ignoremissing)
492 return self._normalize(path, isknown, ignoremissing)
490 return path
493 return path
491
494
492 def clear(self):
495 def clear(self):
493 self._map = {}
496 self._map = {}
494 if "_dirs" in self.__dict__:
497 if "_dirs" in self.__dict__:
495 delattr(self, "_dirs")
498 delattr(self, "_dirs")
496 self._copymap = {}
499 self._copymap = {}
497 self._pl = [nullid, nullid]
500 self._pl = [nullid, nullid]
498 self._lastnormaltime = 0
501 self._lastnormaltime = 0
499 self._dirty = True
502 self._dirty = True
500
503
501 def rebuild(self, parent, allfiles, changedfiles=None):
504 def rebuild(self, parent, allfiles, changedfiles=None):
502 changedfiles = changedfiles or allfiles
505 changedfiles = changedfiles or allfiles
503 oldmap = self._map
506 oldmap = self._map
504 self.clear()
507 self.clear()
505 for f in allfiles:
508 for f in allfiles:
506 if f not in changedfiles:
509 if f not in changedfiles:
507 self._map[f] = oldmap[f]
510 self._map[f] = oldmap[f]
508 else:
511 else:
509 if 'x' in allfiles.flags(f):
512 if 'x' in allfiles.flags(f):
510 self._map[f] = ('n', 0777, -1, 0)
513 self._map[f] = ('n', 0777, -1, 0)
511 else:
514 else:
512 self._map[f] = ('n', 0666, -1, 0)
515 self._map[f] = ('n', 0666, -1, 0)
513 self._pl = (parent, nullid)
516 self._pl = (parent, nullid)
514 self._dirty = True
517 self._dirty = True
515
518
516 def write(self):
519 def write(self):
517 if not self._dirty:
520 if not self._dirty:
518 return
521 return
519 st = self._opener("dirstate", "w", atomictemp=True)
522 st = self._opener("dirstate", "w", atomictemp=True)
520
523
521 def finish(s):
524 def finish(s):
522 st.write(s)
525 st.write(s)
523 st.close()
526 st.close()
524 self._lastnormaltime = 0
527 self._lastnormaltime = 0
525 self._dirty = self._dirtypl = False
528 self._dirty = self._dirtypl = False
526
529
527 # use the modification time of the newly created temporary file as the
530 # use the modification time of the newly created temporary file as the
528 # filesystem's notion of 'now'
531 # filesystem's notion of 'now'
529 now = util.fstat(st).st_mtime
532 now = util.fstat(st).st_mtime
530 finish(parsers.pack_dirstate(self._map, self._copymap, self._pl, now))
533 finish(parsers.pack_dirstate(self._map, self._copymap, self._pl, now))
531
534
532 def _dirignore(self, f):
535 def _dirignore(self, f):
533 if f == '.':
536 if f == '.':
534 return False
537 return False
535 if self._ignore(f):
538 if self._ignore(f):
536 return True
539 return True
537 for p in _finddirs(f):
540 for p in _finddirs(f):
538 if self._ignore(p):
541 if self._ignore(p):
539 return True
542 return True
540 return False
543 return False
541
544
542 def walk(self, match, subrepos, unknown, ignored):
545 def walk(self, match, subrepos, unknown, ignored):
543 '''
546 '''
544 Walk recursively through the directory tree, finding all files
547 Walk recursively through the directory tree, finding all files
545 matched by match.
548 matched by match.
546
549
547 Return a dict mapping filename to stat-like object (either
550 Return a dict mapping filename to stat-like object (either
548 mercurial.osutil.stat instance or return value of os.stat()).
551 mercurial.osutil.stat instance or return value of os.stat()).
549 '''
552 '''
550
553
551 def fwarn(f, msg):
554 def fwarn(f, msg):
552 self._ui.warn('%s: %s\n' % (self.pathto(f), msg))
555 self._ui.warn('%s: %s\n' % (self.pathto(f), msg))
553 return False
556 return False
554
557
555 def badtype(mode):
558 def badtype(mode):
556 kind = _('unknown')
559 kind = _('unknown')
557 if stat.S_ISCHR(mode):
560 if stat.S_ISCHR(mode):
558 kind = _('character device')
561 kind = _('character device')
559 elif stat.S_ISBLK(mode):
562 elif stat.S_ISBLK(mode):
560 kind = _('block device')
563 kind = _('block device')
561 elif stat.S_ISFIFO(mode):
564 elif stat.S_ISFIFO(mode):
562 kind = _('fifo')
565 kind = _('fifo')
563 elif stat.S_ISSOCK(mode):
566 elif stat.S_ISSOCK(mode):
564 kind = _('socket')
567 kind = _('socket')
565 elif stat.S_ISDIR(mode):
568 elif stat.S_ISDIR(mode):
566 kind = _('directory')
569 kind = _('directory')
567 return _('unsupported file type (type is %s)') % kind
570 return _('unsupported file type (type is %s)') % kind
568
571
569 ignore = self._ignore
572 ignore = self._ignore
570 dirignore = self._dirignore
573 dirignore = self._dirignore
571 if ignored:
574 if ignored:
572 ignore = util.never
575 ignore = util.never
573 dirignore = util.never
576 dirignore = util.never
574 elif not unknown:
577 elif not unknown:
575 # if unknown and ignored are False, skip step 2
578 # if unknown and ignored are False, skip step 2
576 ignore = util.always
579 ignore = util.always
577 dirignore = util.always
580 dirignore = util.always
578
581
579 matchfn = match.matchfn
582 matchfn = match.matchfn
580 badfn = match.bad
583 badfn = match.bad
581 dmap = self._map
584 dmap = self._map
582 normpath = util.normpath
585 normpath = util.normpath
583 listdir = osutil.listdir
586 listdir = osutil.listdir
584 lstat = os.lstat
587 lstat = os.lstat
585 getkind = stat.S_IFMT
588 getkind = stat.S_IFMT
586 dirkind = stat.S_IFDIR
589 dirkind = stat.S_IFDIR
587 regkind = stat.S_IFREG
590 regkind = stat.S_IFREG
588 lnkkind = stat.S_IFLNK
591 lnkkind = stat.S_IFLNK
589 join = self._join
592 join = self._join
590 work = []
593 work = []
591 wadd = work.append
594 wadd = work.append
592
595
593 exact = skipstep3 = False
596 exact = skipstep3 = False
594 if matchfn == match.exact: # match.exact
597 if matchfn == match.exact: # match.exact
595 exact = True
598 exact = True
596 dirignore = util.always # skip step 2
599 dirignore = util.always # skip step 2
597 elif match.files() and not match.anypats(): # match.match, no patterns
600 elif match.files() and not match.anypats(): # match.match, no patterns
598 skipstep3 = True
601 skipstep3 = True
599
602
600 if not exact and self._checkcase:
603 if not exact and self._checkcase:
601 normalize = self._normalize
604 normalize = self._normalize
602 skipstep3 = False
605 skipstep3 = False
603 else:
606 else:
604 normalize = None
607 normalize = None
605
608
606 files = sorted(match.files())
609 files = sorted(match.files())
607 subrepos.sort()
610 subrepos.sort()
608 i, j = 0, 0
611 i, j = 0, 0
609 while i < len(files) and j < len(subrepos):
612 while i < len(files) and j < len(subrepos):
610 subpath = subrepos[j] + "/"
613 subpath = subrepos[j] + "/"
611 if files[i] < subpath:
614 if files[i] < subpath:
612 i += 1
615 i += 1
613 continue
616 continue
614 while i < len(files) and files[i].startswith(subpath):
617 while i < len(files) and files[i].startswith(subpath):
615 del files[i]
618 del files[i]
616 j += 1
619 j += 1
617
620
618 if not files or '.' in files:
621 if not files or '.' in files:
619 files = ['']
622 files = ['']
620 results = dict.fromkeys(subrepos)
623 results = dict.fromkeys(subrepos)
621 results['.hg'] = None
624 results['.hg'] = None
622
625
623 # step 1: find all explicit files
626 # step 1: find all explicit files
624 for ff in files:
627 for ff in files:
625 if normalize:
628 if normalize:
626 nf = normalize(normpath(ff), False, True)
629 nf = normalize(normpath(ff), False, True)
627 else:
630 else:
628 nf = normpath(ff)
631 nf = normpath(ff)
629 if nf in results:
632 if nf in results:
630 continue
633 continue
631
634
632 try:
635 try:
633 st = lstat(join(nf))
636 st = lstat(join(nf))
634 kind = getkind(st.st_mode)
637 kind = getkind(st.st_mode)
635 if kind == dirkind:
638 if kind == dirkind:
636 skipstep3 = False
639 skipstep3 = False
637 if nf in dmap:
640 if nf in dmap:
638 #file deleted on disk but still in dirstate
641 #file deleted on disk but still in dirstate
639 results[nf] = None
642 results[nf] = None
640 match.dir(nf)
643 match.dir(nf)
641 if not dirignore(nf):
644 if not dirignore(nf):
642 wadd(nf)
645 wadd(nf)
643 elif kind == regkind or kind == lnkkind:
646 elif kind == regkind or kind == lnkkind:
644 results[nf] = st
647 results[nf] = st
645 else:
648 else:
646 badfn(ff, badtype(kind))
649 badfn(ff, badtype(kind))
647 if nf in dmap:
650 if nf in dmap:
648 results[nf] = None
651 results[nf] = None
649 except OSError, inst:
652 except OSError, inst:
650 if nf in dmap: # does it exactly match a file?
653 if nf in dmap: # does it exactly match a file?
651 results[nf] = None
654 results[nf] = None
652 else: # does it match a directory?
655 else: # does it match a directory?
653 prefix = nf + "/"
656 prefix = nf + "/"
654 for fn in dmap:
657 for fn in dmap:
655 if fn.startswith(prefix):
658 if fn.startswith(prefix):
656 match.dir(nf)
659 match.dir(nf)
657 skipstep3 = False
660 skipstep3 = False
658 break
661 break
659 else:
662 else:
660 badfn(ff, inst.strerror)
663 badfn(ff, inst.strerror)
661
664
662 # step 2: visit subdirectories
665 # step 2: visit subdirectories
663 while work:
666 while work:
664 nd = work.pop()
667 nd = work.pop()
665 skip = None
668 skip = None
666 if nd == '.':
669 if nd == '.':
667 nd = ''
670 nd = ''
668 else:
671 else:
669 skip = '.hg'
672 skip = '.hg'
670 try:
673 try:
671 entries = listdir(join(nd), stat=True, skip=skip)
674 entries = listdir(join(nd), stat=True, skip=skip)
672 except OSError, inst:
675 except OSError, inst:
673 if inst.errno in (errno.EACCES, errno.ENOENT):
676 if inst.errno in (errno.EACCES, errno.ENOENT):
674 fwarn(nd, inst.strerror)
677 fwarn(nd, inst.strerror)
675 continue
678 continue
676 raise
679 raise
677 for f, kind, st in entries:
680 for f, kind, st in entries:
678 if normalize:
681 if normalize:
679 nf = normalize(nd and (nd + "/" + f) or f, True, True)
682 nf = normalize(nd and (nd + "/" + f) or f, True, True)
680 else:
683 else:
681 nf = nd and (nd + "/" + f) or f
684 nf = nd and (nd + "/" + f) or f
682 if nf not in results:
685 if nf not in results:
683 if kind == dirkind:
686 if kind == dirkind:
684 if not ignore(nf):
687 if not ignore(nf):
685 match.dir(nf)
688 match.dir(nf)
686 wadd(nf)
689 wadd(nf)
687 if nf in dmap and matchfn(nf):
690 if nf in dmap and matchfn(nf):
688 results[nf] = None
691 results[nf] = None
689 elif kind == regkind or kind == lnkkind:
692 elif kind == regkind or kind == lnkkind:
690 if nf in dmap:
693 if nf in dmap:
691 if matchfn(nf):
694 if matchfn(nf):
692 results[nf] = st
695 results[nf] = st
693 elif matchfn(nf) and not ignore(nf):
696 elif matchfn(nf) and not ignore(nf):
694 results[nf] = st
697 results[nf] = st
695 elif nf in dmap and matchfn(nf):
698 elif nf in dmap and matchfn(nf):
696 results[nf] = None
699 results[nf] = None
697
700
698 # step 3: report unseen items in the dmap hash
701 # step 3: report unseen items in the dmap hash
699 if not skipstep3 and not exact:
702 if not skipstep3 and not exact:
700 visit = sorted([f for f in dmap if f not in results and matchfn(f)])
703 visit = sorted([f for f in dmap if f not in results and matchfn(f)])
701 if unknown:
704 if unknown:
702 # unknown == True means we walked the full directory tree above.
705 # unknown == True means we walked the full directory tree above.
703 # So if a file is not seen it was either a) not matching matchfn
706 # So if a file is not seen it was either a) not matching matchfn
704 # b) ignored, c) missing, or d) under a symlink directory.
707 # b) ignored, c) missing, or d) under a symlink directory.
705 audit_path = scmutil.pathauditor(self._root)
708 audit_path = scmutil.pathauditor(self._root)
706
709
707 for nf in iter(visit):
710 for nf in iter(visit):
708 # Report ignored items in the dmap as long as they are not
711 # Report ignored items in the dmap as long as they are not
709 # under a symlink directory.
712 # under a symlink directory.
710 if ignore(nf) and audit_path.check(nf):
713 if ignore(nf) and audit_path.check(nf):
711 try:
714 try:
712 results[nf] = lstat(join(nf))
715 results[nf] = lstat(join(nf))
713 except OSError:
716 except OSError:
714 # file doesn't exist
717 # file doesn't exist
715 results[nf] = None
718 results[nf] = None
716 else:
719 else:
717 # It's either missing or under a symlink directory
720 # It's either missing or under a symlink directory
718 results[nf] = None
721 results[nf] = None
719 else:
722 else:
720 # We may not have walked the full directory tree above,
723 # We may not have walked the full directory tree above,
721 # so stat everything we missed.
724 # so stat everything we missed.
722 nf = iter(visit).next
725 nf = iter(visit).next
723 for st in util.statfiles([join(i) for i in visit]):
726 for st in util.statfiles([join(i) for i in visit]):
724 results[nf()] = st
727 results[nf()] = st
725 for s in subrepos:
728 for s in subrepos:
726 del results[s]
729 del results[s]
727 del results['.hg']
730 del results['.hg']
728 return results
731 return results
729
732
730 def status(self, match, subrepos, ignored, clean, unknown):
733 def status(self, match, subrepos, ignored, clean, unknown):
731 '''Determine the status of the working copy relative to the
734 '''Determine the status of the working copy relative to the
732 dirstate and return a tuple of lists (unsure, modified, added,
735 dirstate and return a tuple of lists (unsure, modified, added,
733 removed, deleted, unknown, ignored, clean), where:
736 removed, deleted, unknown, ignored, clean), where:
734
737
735 unsure:
738 unsure:
736 files that might have been modified since the dirstate was
739 files that might have been modified since the dirstate was
737 written, but need to be read to be sure (size is the same
740 written, but need to be read to be sure (size is the same
738 but mtime differs)
741 but mtime differs)
739 modified:
742 modified:
740 files that have definitely been modified since the dirstate
743 files that have definitely been modified since the dirstate
741 was written (different size or mode)
744 was written (different size or mode)
742 added:
745 added:
743 files that have been explicitly added with hg add
746 files that have been explicitly added with hg add
744 removed:
747 removed:
745 files that have been explicitly removed with hg remove
748 files that have been explicitly removed with hg remove
746 deleted:
749 deleted:
747 files that have been deleted through other means ("missing")
750 files that have been deleted through other means ("missing")
748 unknown:
751 unknown:
749 files not in the dirstate that are not ignored
752 files not in the dirstate that are not ignored
750 ignored:
753 ignored:
751 files not in the dirstate that are ignored
754 files not in the dirstate that are ignored
752 (by _dirignore())
755 (by _dirignore())
753 clean:
756 clean:
754 files that have definitely not been modified since the
757 files that have definitely not been modified since the
755 dirstate was written
758 dirstate was written
756 '''
759 '''
757 listignored, listclean, listunknown = ignored, clean, unknown
760 listignored, listclean, listunknown = ignored, clean, unknown
758 lookup, modified, added, unknown, ignored = [], [], [], [], []
761 lookup, modified, added, unknown, ignored = [], [], [], [], []
759 removed, deleted, clean = [], [], []
762 removed, deleted, clean = [], [], []
760
763
761 dmap = self._map
764 dmap = self._map
762 ladd = lookup.append # aka "unsure"
765 ladd = lookup.append # aka "unsure"
763 madd = modified.append
766 madd = modified.append
764 aadd = added.append
767 aadd = added.append
765 uadd = unknown.append
768 uadd = unknown.append
766 iadd = ignored.append
769 iadd = ignored.append
767 radd = removed.append
770 radd = removed.append
768 dadd = deleted.append
771 dadd = deleted.append
769 cadd = clean.append
772 cadd = clean.append
770 mexact = match.exact
773 mexact = match.exact
771 dirignore = self._dirignore
774 dirignore = self._dirignore
772 checkexec = self._checkexec
775 checkexec = self._checkexec
773 checklink = self._checklink
776 checklink = self._checklink
774 copymap = self._copymap
777 copymap = self._copymap
775 lastnormaltime = self._lastnormaltime
778 lastnormaltime = self._lastnormaltime
776
779
777 lnkkind = stat.S_IFLNK
780 lnkkind = stat.S_IFLNK
778
781
779 for fn, st in self.walk(match, subrepos, listunknown,
782 for fn, st in self.walk(match, subrepos, listunknown,
780 listignored).iteritems():
783 listignored).iteritems():
781 if fn not in dmap:
784 if fn not in dmap:
782 if (listignored or mexact(fn)) and dirignore(fn):
785 if (listignored or mexact(fn)) and dirignore(fn):
783 if listignored:
786 if listignored:
784 iadd(fn)
787 iadd(fn)
785 elif listunknown:
788 elif listunknown:
786 uadd(fn)
789 uadd(fn)
787 continue
790 continue
788
791
789 state, mode, size, time = dmap[fn]
792 state, mode, size, time = dmap[fn]
790
793
791 if not st and state in "nma":
794 if not st and state in "nma":
792 dadd(fn)
795 dadd(fn)
793 elif state == 'n':
796 elif state == 'n':
794 # The "mode & lnkkind != lnkkind or self._checklink"
797 # The "mode & lnkkind != lnkkind or self._checklink"
795 # lines are an expansion of "islink => checklink"
798 # lines are an expansion of "islink => checklink"
796 # where islink means "is this a link?" and checklink
799 # where islink means "is this a link?" and checklink
797 # means "can we check links?".
800 # means "can we check links?".
798 mtime = int(st.st_mtime)
801 mtime = int(st.st_mtime)
799 if (size >= 0 and
802 if (size >= 0 and
800 ((size != st.st_size and size != st.st_size & _rangemask)
803 ((size != st.st_size and size != st.st_size & _rangemask)
801 or ((mode ^ st.st_mode) & 0100 and checkexec))
804 or ((mode ^ st.st_mode) & 0100 and checkexec))
802 and (mode & lnkkind != lnkkind or checklink)
805 and (mode & lnkkind != lnkkind or checklink)
803 or size == -2 # other parent
806 or size == -2 # other parent
804 or fn in copymap):
807 or fn in copymap):
805 madd(fn)
808 madd(fn)
806 elif ((time != mtime and time != mtime & _rangemask)
809 elif ((time != mtime and time != mtime & _rangemask)
807 and (mode & lnkkind != lnkkind or checklink)):
810 and (mode & lnkkind != lnkkind or checklink)):
808 ladd(fn)
811 ladd(fn)
809 elif mtime == lastnormaltime:
812 elif mtime == lastnormaltime:
810 # fn may have been changed in the same timeslot without
813 # fn may have been changed in the same timeslot without
811 # changing its size. This can happen if we quickly do
814 # changing its size. This can happen if we quickly do
812 # multiple commits in a single transaction.
815 # multiple commits in a single transaction.
813 # Force lookup, so we don't miss such a racy file change.
816 # Force lookup, so we don't miss such a racy file change.
814 ladd(fn)
817 ladd(fn)
815 elif listclean:
818 elif listclean:
816 cadd(fn)
819 cadd(fn)
817 elif state == 'm':
820 elif state == 'm':
818 madd(fn)
821 madd(fn)
819 elif state == 'a':
822 elif state == 'a':
820 aadd(fn)
823 aadd(fn)
821 elif state == 'r':
824 elif state == 'r':
822 radd(fn)
825 radd(fn)
823
826
824 return (lookup, modified, added, removed, deleted, unknown, ignored,
827 return (lookup, modified, added, removed, deleted, unknown, ignored,
825 clean)
828 clean)
General Comments 0
You need to be logged in to leave comments. Login now