##// END OF EJS Templates
bisect: --command without --noupdate should flag the parent rev it tested...
Mads Kiilerich -
r20237:0d32dd60 default
parent child Browse files
Show More
@@ -1,5908 +1,5909 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, commandserver
15 import sshserver, hgweb, commandserver
16 from hgweb import server as hgweb_server
16 from hgweb import server as hgweb_server
17 import merge as mergemod
17 import merge as mergemod
18 import minirst, revset, fileset
18 import minirst, revset, fileset
19 import dagparser, context, simplemerge, graphmod
19 import dagparser, context, simplemerge, graphmod
20 import random
20 import random
21 import setdiscovery, treediscovery, dagutil, pvec, localrepo
21 import setdiscovery, treediscovery, dagutil, pvec, localrepo
22 import phases, obsolete
22 import phases, obsolete
23
23
24 table = {}
24 table = {}
25
25
26 command = cmdutil.command(table)
26 command = cmdutil.command(table)
27
27
28 # common command options
28 # common command options
29
29
30 globalopts = [
30 globalopts = [
31 ('R', 'repository', '',
31 ('R', 'repository', '',
32 _('repository root directory or name of overlay bundle file'),
32 _('repository root directory or name of overlay bundle file'),
33 _('REPO')),
33 _('REPO')),
34 ('', 'cwd', '',
34 ('', 'cwd', '',
35 _('change working directory'), _('DIR')),
35 _('change working directory'), _('DIR')),
36 ('y', 'noninteractive', None,
36 ('y', 'noninteractive', None,
37 _('do not prompt, automatically pick the first choice for all prompts')),
37 _('do not prompt, automatically pick the first choice for all prompts')),
38 ('q', 'quiet', None, _('suppress output')),
38 ('q', 'quiet', None, _('suppress output')),
39 ('v', 'verbose', None, _('enable additional output')),
39 ('v', 'verbose', None, _('enable additional output')),
40 ('', 'config', [],
40 ('', 'config', [],
41 _('set/override config option (use \'section.name=value\')'),
41 _('set/override config option (use \'section.name=value\')'),
42 _('CONFIG')),
42 _('CONFIG')),
43 ('', 'debug', None, _('enable debugging output')),
43 ('', 'debug', None, _('enable debugging output')),
44 ('', 'debugger', None, _('start debugger')),
44 ('', 'debugger', None, _('start debugger')),
45 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
45 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
46 _('ENCODE')),
46 _('ENCODE')),
47 ('', 'encodingmode', encoding.encodingmode,
47 ('', 'encodingmode', encoding.encodingmode,
48 _('set the charset encoding mode'), _('MODE')),
48 _('set the charset encoding mode'), _('MODE')),
49 ('', 'traceback', None, _('always print a traceback on exception')),
49 ('', 'traceback', None, _('always print a traceback on exception')),
50 ('', 'time', None, _('time how long the command takes')),
50 ('', 'time', None, _('time how long the command takes')),
51 ('', 'profile', None, _('print command execution profile')),
51 ('', 'profile', None, _('print command execution profile')),
52 ('', 'version', None, _('output version information and exit')),
52 ('', 'version', None, _('output version information and exit')),
53 ('h', 'help', None, _('display help and exit')),
53 ('h', 'help', None, _('display help and exit')),
54 ('', 'hidden', False, _('consider hidden changesets')),
54 ('', 'hidden', False, _('consider hidden changesets')),
55 ]
55 ]
56
56
57 dryrunopts = [('n', 'dry-run', None,
57 dryrunopts = [('n', 'dry-run', None,
58 _('do not perform actions, just print output'))]
58 _('do not perform actions, just print output'))]
59
59
60 remoteopts = [
60 remoteopts = [
61 ('e', 'ssh', '',
61 ('e', 'ssh', '',
62 _('specify ssh command to use'), _('CMD')),
62 _('specify ssh command to use'), _('CMD')),
63 ('', 'remotecmd', '',
63 ('', 'remotecmd', '',
64 _('specify hg command to run on the remote side'), _('CMD')),
64 _('specify hg command to run on the remote side'), _('CMD')),
65 ('', 'insecure', None,
65 ('', 'insecure', None,
66 _('do not verify server certificate (ignoring web.cacerts config)')),
66 _('do not verify server certificate (ignoring web.cacerts config)')),
67 ]
67 ]
68
68
69 walkopts = [
69 walkopts = [
70 ('I', 'include', [],
70 ('I', 'include', [],
71 _('include names matching the given patterns'), _('PATTERN')),
71 _('include names matching the given patterns'), _('PATTERN')),
72 ('X', 'exclude', [],
72 ('X', 'exclude', [],
73 _('exclude names matching the given patterns'), _('PATTERN')),
73 _('exclude names matching the given patterns'), _('PATTERN')),
74 ]
74 ]
75
75
76 commitopts = [
76 commitopts = [
77 ('m', 'message', '',
77 ('m', 'message', '',
78 _('use text as commit message'), _('TEXT')),
78 _('use text as commit message'), _('TEXT')),
79 ('l', 'logfile', '',
79 ('l', 'logfile', '',
80 _('read commit message from file'), _('FILE')),
80 _('read commit message from file'), _('FILE')),
81 ]
81 ]
82
82
83 commitopts2 = [
83 commitopts2 = [
84 ('d', 'date', '',
84 ('d', 'date', '',
85 _('record the specified date as commit date'), _('DATE')),
85 _('record the specified date as commit date'), _('DATE')),
86 ('u', 'user', '',
86 ('u', 'user', '',
87 _('record the specified user as committer'), _('USER')),
87 _('record the specified user as committer'), _('USER')),
88 ]
88 ]
89
89
90 templateopts = [
90 templateopts = [
91 ('', 'style', '',
91 ('', 'style', '',
92 _('display using template map file'), _('STYLE')),
92 _('display using template map file'), _('STYLE')),
93 ('', 'template', '',
93 ('', 'template', '',
94 _('display with template'), _('TEMPLATE')),
94 _('display with template'), _('TEMPLATE')),
95 ]
95 ]
96
96
97 logopts = [
97 logopts = [
98 ('p', 'patch', None, _('show patch')),
98 ('p', 'patch', None, _('show patch')),
99 ('g', 'git', None, _('use git extended diff format')),
99 ('g', 'git', None, _('use git extended diff format')),
100 ('l', 'limit', '',
100 ('l', 'limit', '',
101 _('limit number of changes displayed'), _('NUM')),
101 _('limit number of changes displayed'), _('NUM')),
102 ('M', 'no-merges', None, _('do not show merges')),
102 ('M', 'no-merges', None, _('do not show merges')),
103 ('', 'stat', None, _('output diffstat-style summary of changes')),
103 ('', 'stat', None, _('output diffstat-style summary of changes')),
104 ('G', 'graph', None, _("show the revision DAG")),
104 ('G', 'graph', None, _("show the revision DAG")),
105 ] + templateopts
105 ] + templateopts
106
106
107 diffopts = [
107 diffopts = [
108 ('a', 'text', None, _('treat all files as text')),
108 ('a', 'text', None, _('treat all files as text')),
109 ('g', 'git', None, _('use git extended diff format')),
109 ('g', 'git', None, _('use git extended diff format')),
110 ('', 'nodates', None, _('omit dates from diff headers'))
110 ('', 'nodates', None, _('omit dates from diff headers'))
111 ]
111 ]
112
112
113 diffwsopts = [
113 diffwsopts = [
114 ('w', 'ignore-all-space', None,
114 ('w', 'ignore-all-space', None,
115 _('ignore white space when comparing lines')),
115 _('ignore white space when comparing lines')),
116 ('b', 'ignore-space-change', None,
116 ('b', 'ignore-space-change', None,
117 _('ignore changes in the amount of white space')),
117 _('ignore changes in the amount of white space')),
118 ('B', 'ignore-blank-lines', None,
118 ('B', 'ignore-blank-lines', None,
119 _('ignore changes whose lines are all blank')),
119 _('ignore changes whose lines are all blank')),
120 ]
120 ]
121
121
122 diffopts2 = [
122 diffopts2 = [
123 ('p', 'show-function', None, _('show which function each change is in')),
123 ('p', 'show-function', None, _('show which function each change is in')),
124 ('', 'reverse', None, _('produce a diff that undoes the changes')),
124 ('', 'reverse', None, _('produce a diff that undoes the changes')),
125 ] + diffwsopts + [
125 ] + diffwsopts + [
126 ('U', 'unified', '',
126 ('U', 'unified', '',
127 _('number of lines of context to show'), _('NUM')),
127 _('number of lines of context to show'), _('NUM')),
128 ('', 'stat', None, _('output diffstat-style summary of changes')),
128 ('', 'stat', None, _('output diffstat-style summary of changes')),
129 ]
129 ]
130
130
131 mergetoolopts = [
131 mergetoolopts = [
132 ('t', 'tool', '', _('specify merge tool')),
132 ('t', 'tool', '', _('specify merge tool')),
133 ]
133 ]
134
134
135 similarityopts = [
135 similarityopts = [
136 ('s', 'similarity', '',
136 ('s', 'similarity', '',
137 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
137 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
138 ]
138 ]
139
139
140 subrepoopts = [
140 subrepoopts = [
141 ('S', 'subrepos', None,
141 ('S', 'subrepos', None,
142 _('recurse into subrepositories'))
142 _('recurse into subrepositories'))
143 ]
143 ]
144
144
145 # Commands start here, listed alphabetically
145 # Commands start here, listed alphabetically
146
146
147 @command('^add',
147 @command('^add',
148 walkopts + subrepoopts + dryrunopts,
148 walkopts + subrepoopts + dryrunopts,
149 _('[OPTION]... [FILE]...'))
149 _('[OPTION]... [FILE]...'))
150 def add(ui, repo, *pats, **opts):
150 def add(ui, repo, *pats, **opts):
151 """add the specified files on the next commit
151 """add the specified files on the next commit
152
152
153 Schedule files to be version controlled and added to the
153 Schedule files to be version controlled and added to the
154 repository.
154 repository.
155
155
156 The files will be added to the repository at the next commit. To
156 The files will be added to the repository at the next commit. To
157 undo an add before that, see :hg:`forget`.
157 undo an add before that, see :hg:`forget`.
158
158
159 If no names are given, add all files to the repository.
159 If no names are given, add all files to the repository.
160
160
161 .. container:: verbose
161 .. container:: verbose
162
162
163 An example showing how new (unknown) files are added
163 An example showing how new (unknown) files are added
164 automatically by :hg:`add`::
164 automatically by :hg:`add`::
165
165
166 $ ls
166 $ ls
167 foo.c
167 foo.c
168 $ hg status
168 $ hg status
169 ? foo.c
169 ? foo.c
170 $ hg add
170 $ hg add
171 adding foo.c
171 adding foo.c
172 $ hg status
172 $ hg status
173 A foo.c
173 A foo.c
174
174
175 Returns 0 if all files are successfully added.
175 Returns 0 if all files are successfully added.
176 """
176 """
177
177
178 m = scmutil.match(repo[None], pats, opts)
178 m = scmutil.match(repo[None], pats, opts)
179 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
179 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
180 opts.get('subrepos'), prefix="", explicitonly=False)
180 opts.get('subrepos'), prefix="", explicitonly=False)
181 return rejected and 1 or 0
181 return rejected and 1 or 0
182
182
183 @command('addremove',
183 @command('addremove',
184 similarityopts + walkopts + dryrunopts,
184 similarityopts + walkopts + dryrunopts,
185 _('[OPTION]... [FILE]...'))
185 _('[OPTION]... [FILE]...'))
186 def addremove(ui, repo, *pats, **opts):
186 def addremove(ui, repo, *pats, **opts):
187 """add all new files, delete all missing files
187 """add all new files, delete all missing files
188
188
189 Add all new files and remove all missing files from the
189 Add all new files and remove all missing files from the
190 repository.
190 repository.
191
191
192 New files are ignored if they match any of the patterns in
192 New files are ignored if they match any of the patterns in
193 ``.hgignore``. As with add, these changes take effect at the next
193 ``.hgignore``. As with add, these changes take effect at the next
194 commit.
194 commit.
195
195
196 Use the -s/--similarity option to detect renamed files. This
196 Use the -s/--similarity option to detect renamed files. This
197 option takes a percentage between 0 (disabled) and 100 (files must
197 option takes a percentage between 0 (disabled) and 100 (files must
198 be identical) as its parameter. With a parameter greater than 0,
198 be identical) as its parameter. With a parameter greater than 0,
199 this compares every removed file with every added file and records
199 this compares every removed file with every added file and records
200 those similar enough as renames. Detecting renamed files this way
200 those similar enough as renames. Detecting renamed files this way
201 can be expensive. After using this option, :hg:`status -C` can be
201 can be expensive. After using this option, :hg:`status -C` can be
202 used to check which files were identified as moved or renamed. If
202 used to check which files were identified as moved or renamed. If
203 not specified, -s/--similarity defaults to 100 and only renames of
203 not specified, -s/--similarity defaults to 100 and only renames of
204 identical files are detected.
204 identical files are detected.
205
205
206 Returns 0 if all files are successfully added.
206 Returns 0 if all files are successfully added.
207 """
207 """
208 try:
208 try:
209 sim = float(opts.get('similarity') or 100)
209 sim = float(opts.get('similarity') or 100)
210 except ValueError:
210 except ValueError:
211 raise util.Abort(_('similarity must be a number'))
211 raise util.Abort(_('similarity must be a number'))
212 if sim < 0 or sim > 100:
212 if sim < 0 or sim > 100:
213 raise util.Abort(_('similarity must be between 0 and 100'))
213 raise util.Abort(_('similarity must be between 0 and 100'))
214 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
214 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
215
215
216 @command('^annotate|blame',
216 @command('^annotate|blame',
217 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
217 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
218 ('', 'follow', None,
218 ('', 'follow', None,
219 _('follow copies/renames and list the filename (DEPRECATED)')),
219 _('follow copies/renames and list the filename (DEPRECATED)')),
220 ('', 'no-follow', None, _("don't follow copies and renames")),
220 ('', 'no-follow', None, _("don't follow copies and renames")),
221 ('a', 'text', None, _('treat all files as text')),
221 ('a', 'text', None, _('treat all files as text')),
222 ('u', 'user', None, _('list the author (long with -v)')),
222 ('u', 'user', None, _('list the author (long with -v)')),
223 ('f', 'file', None, _('list the filename')),
223 ('f', 'file', None, _('list the filename')),
224 ('d', 'date', None, _('list the date (short with -q)')),
224 ('d', 'date', None, _('list the date (short with -q)')),
225 ('n', 'number', None, _('list the revision number (default)')),
225 ('n', 'number', None, _('list the revision number (default)')),
226 ('c', 'changeset', None, _('list the changeset')),
226 ('c', 'changeset', None, _('list the changeset')),
227 ('l', 'line-number', None, _('show line number at the first appearance'))
227 ('l', 'line-number', None, _('show line number at the first appearance'))
228 ] + diffwsopts + walkopts,
228 ] + diffwsopts + walkopts,
229 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
229 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
230 def annotate(ui, repo, *pats, **opts):
230 def annotate(ui, repo, *pats, **opts):
231 """show changeset information by line for each file
231 """show changeset information by line for each file
232
232
233 List changes in files, showing the revision id responsible for
233 List changes in files, showing the revision id responsible for
234 each line
234 each line
235
235
236 This command is useful for discovering when a change was made and
236 This command is useful for discovering when a change was made and
237 by whom.
237 by whom.
238
238
239 Without the -a/--text option, annotate will avoid processing files
239 Without the -a/--text option, annotate will avoid processing files
240 it detects as binary. With -a, annotate will annotate the file
240 it detects as binary. With -a, annotate will annotate the file
241 anyway, although the results will probably be neither useful
241 anyway, although the results will probably be neither useful
242 nor desirable.
242 nor desirable.
243
243
244 Returns 0 on success.
244 Returns 0 on success.
245 """
245 """
246 if opts.get('follow'):
246 if opts.get('follow'):
247 # --follow is deprecated and now just an alias for -f/--file
247 # --follow is deprecated and now just an alias for -f/--file
248 # to mimic the behavior of Mercurial before version 1.5
248 # to mimic the behavior of Mercurial before version 1.5
249 opts['file'] = True
249 opts['file'] = True
250
250
251 datefunc = ui.quiet and util.shortdate or util.datestr
251 datefunc = ui.quiet and util.shortdate or util.datestr
252 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
252 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
253
253
254 if not pats:
254 if not pats:
255 raise util.Abort(_('at least one filename or pattern is required'))
255 raise util.Abort(_('at least one filename or pattern is required'))
256
256
257 hexfn = ui.debugflag and hex or short
257 hexfn = ui.debugflag and hex or short
258
258
259 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
259 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
260 ('number', ' ', lambda x: str(x[0].rev())),
260 ('number', ' ', lambda x: str(x[0].rev())),
261 ('changeset', ' ', lambda x: hexfn(x[0].node())),
261 ('changeset', ' ', lambda x: hexfn(x[0].node())),
262 ('date', ' ', getdate),
262 ('date', ' ', getdate),
263 ('file', ' ', lambda x: x[0].path()),
263 ('file', ' ', lambda x: x[0].path()),
264 ('line_number', ':', lambda x: str(x[1])),
264 ('line_number', ':', lambda x: str(x[1])),
265 ]
265 ]
266
266
267 if (not opts.get('user') and not opts.get('changeset')
267 if (not opts.get('user') and not opts.get('changeset')
268 and not opts.get('date') and not opts.get('file')):
268 and not opts.get('date') and not opts.get('file')):
269 opts['number'] = True
269 opts['number'] = True
270
270
271 linenumber = opts.get('line_number') is not None
271 linenumber = opts.get('line_number') is not None
272 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
272 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
273 raise util.Abort(_('at least one of -n/-c is required for -l'))
273 raise util.Abort(_('at least one of -n/-c is required for -l'))
274
274
275 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
275 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
276 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
276 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
277
277
278 def bad(x, y):
278 def bad(x, y):
279 raise util.Abort("%s: %s" % (x, y))
279 raise util.Abort("%s: %s" % (x, y))
280
280
281 ctx = scmutil.revsingle(repo, opts.get('rev'))
281 ctx = scmutil.revsingle(repo, opts.get('rev'))
282 m = scmutil.match(ctx, pats, opts)
282 m = scmutil.match(ctx, pats, opts)
283 m.bad = bad
283 m.bad = bad
284 follow = not opts.get('no_follow')
284 follow = not opts.get('no_follow')
285 diffopts = patch.diffopts(ui, opts, section='annotate')
285 diffopts = patch.diffopts(ui, opts, section='annotate')
286 for abs in ctx.walk(m):
286 for abs in ctx.walk(m):
287 fctx = ctx[abs]
287 fctx = ctx[abs]
288 if not opts.get('text') and util.binary(fctx.data()):
288 if not opts.get('text') and util.binary(fctx.data()):
289 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
289 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
290 continue
290 continue
291
291
292 lines = fctx.annotate(follow=follow, linenumber=linenumber,
292 lines = fctx.annotate(follow=follow, linenumber=linenumber,
293 diffopts=diffopts)
293 diffopts=diffopts)
294 pieces = []
294 pieces = []
295
295
296 for f, sep in funcmap:
296 for f, sep in funcmap:
297 l = [f(n) for n, dummy in lines]
297 l = [f(n) for n, dummy in lines]
298 if l:
298 if l:
299 sized = [(x, encoding.colwidth(x)) for x in l]
299 sized = [(x, encoding.colwidth(x)) for x in l]
300 ml = max([w for x, w in sized])
300 ml = max([w for x, w in sized])
301 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
301 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
302 for x, w in sized])
302 for x, w in sized])
303
303
304 if pieces:
304 if pieces:
305 for p, l in zip(zip(*pieces), lines):
305 for p, l in zip(zip(*pieces), lines):
306 ui.write("%s: %s" % ("".join(p), l[1]))
306 ui.write("%s: %s" % ("".join(p), l[1]))
307
307
308 if lines and not lines[-1][1].endswith('\n'):
308 if lines and not lines[-1][1].endswith('\n'):
309 ui.write('\n')
309 ui.write('\n')
310
310
311 @command('archive',
311 @command('archive',
312 [('', 'no-decode', None, _('do not pass files through decoders')),
312 [('', 'no-decode', None, _('do not pass files through decoders')),
313 ('p', 'prefix', '', _('directory prefix for files in archive'),
313 ('p', 'prefix', '', _('directory prefix for files in archive'),
314 _('PREFIX')),
314 _('PREFIX')),
315 ('r', 'rev', '', _('revision to distribute'), _('REV')),
315 ('r', 'rev', '', _('revision to distribute'), _('REV')),
316 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
316 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
317 ] + subrepoopts + walkopts,
317 ] + subrepoopts + walkopts,
318 _('[OPTION]... DEST'))
318 _('[OPTION]... DEST'))
319 def archive(ui, repo, dest, **opts):
319 def archive(ui, repo, dest, **opts):
320 '''create an unversioned archive of a repository revision
320 '''create an unversioned archive of a repository revision
321
321
322 By default, the revision used is the parent of the working
322 By default, the revision used is the parent of the working
323 directory; use -r/--rev to specify a different revision.
323 directory; use -r/--rev to specify a different revision.
324
324
325 The archive type is automatically detected based on file
325 The archive type is automatically detected based on file
326 extension (or override using -t/--type).
326 extension (or override using -t/--type).
327
327
328 .. container:: verbose
328 .. container:: verbose
329
329
330 Examples:
330 Examples:
331
331
332 - create a zip file containing the 1.0 release::
332 - create a zip file containing the 1.0 release::
333
333
334 hg archive -r 1.0 project-1.0.zip
334 hg archive -r 1.0 project-1.0.zip
335
335
336 - create a tarball excluding .hg files::
336 - create a tarball excluding .hg files::
337
337
338 hg archive project.tar.gz -X ".hg*"
338 hg archive project.tar.gz -X ".hg*"
339
339
340 Valid types are:
340 Valid types are:
341
341
342 :``files``: a directory full of files (default)
342 :``files``: a directory full of files (default)
343 :``tar``: tar archive, uncompressed
343 :``tar``: tar archive, uncompressed
344 :``tbz2``: tar archive, compressed using bzip2
344 :``tbz2``: tar archive, compressed using bzip2
345 :``tgz``: tar archive, compressed using gzip
345 :``tgz``: tar archive, compressed using gzip
346 :``uzip``: zip archive, uncompressed
346 :``uzip``: zip archive, uncompressed
347 :``zip``: zip archive, compressed using deflate
347 :``zip``: zip archive, compressed using deflate
348
348
349 The exact name of the destination archive or directory is given
349 The exact name of the destination archive or directory is given
350 using a format string; see :hg:`help export` for details.
350 using a format string; see :hg:`help export` for details.
351
351
352 Each member added to an archive file has a directory prefix
352 Each member added to an archive file has a directory prefix
353 prepended. Use -p/--prefix to specify a format string for the
353 prepended. Use -p/--prefix to specify a format string for the
354 prefix. The default is the basename of the archive, with suffixes
354 prefix. The default is the basename of the archive, with suffixes
355 removed.
355 removed.
356
356
357 Returns 0 on success.
357 Returns 0 on success.
358 '''
358 '''
359
359
360 ctx = scmutil.revsingle(repo, opts.get('rev'))
360 ctx = scmutil.revsingle(repo, opts.get('rev'))
361 if not ctx:
361 if not ctx:
362 raise util.Abort(_('no working directory: please specify a revision'))
362 raise util.Abort(_('no working directory: please specify a revision'))
363 node = ctx.node()
363 node = ctx.node()
364 dest = cmdutil.makefilename(repo, dest, node)
364 dest = cmdutil.makefilename(repo, dest, node)
365 if os.path.realpath(dest) == repo.root:
365 if os.path.realpath(dest) == repo.root:
366 raise util.Abort(_('repository root cannot be destination'))
366 raise util.Abort(_('repository root cannot be destination'))
367
367
368 kind = opts.get('type') or archival.guesskind(dest) or 'files'
368 kind = opts.get('type') or archival.guesskind(dest) or 'files'
369 prefix = opts.get('prefix')
369 prefix = opts.get('prefix')
370
370
371 if dest == '-':
371 if dest == '-':
372 if kind == 'files':
372 if kind == 'files':
373 raise util.Abort(_('cannot archive plain files to stdout'))
373 raise util.Abort(_('cannot archive plain files to stdout'))
374 dest = cmdutil.makefileobj(repo, dest)
374 dest = cmdutil.makefileobj(repo, dest)
375 if not prefix:
375 if not prefix:
376 prefix = os.path.basename(repo.root) + '-%h'
376 prefix = os.path.basename(repo.root) + '-%h'
377
377
378 prefix = cmdutil.makefilename(repo, prefix, node)
378 prefix = cmdutil.makefilename(repo, prefix, node)
379 matchfn = scmutil.match(ctx, [], opts)
379 matchfn = scmutil.match(ctx, [], opts)
380 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
380 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
381 matchfn, prefix, subrepos=opts.get('subrepos'))
381 matchfn, prefix, subrepos=opts.get('subrepos'))
382
382
383 @command('backout',
383 @command('backout',
384 [('', 'merge', None, _('merge with old dirstate parent after backout')),
384 [('', 'merge', None, _('merge with old dirstate parent after backout')),
385 ('', 'parent', '',
385 ('', 'parent', '',
386 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
386 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
387 ('r', 'rev', '', _('revision to backout'), _('REV')),
387 ('r', 'rev', '', _('revision to backout'), _('REV')),
388 ] + mergetoolopts + walkopts + commitopts + commitopts2,
388 ] + mergetoolopts + walkopts + commitopts + commitopts2,
389 _('[OPTION]... [-r] REV'))
389 _('[OPTION]... [-r] REV'))
390 def backout(ui, repo, node=None, rev=None, **opts):
390 def backout(ui, repo, node=None, rev=None, **opts):
391 '''reverse effect of earlier changeset
391 '''reverse effect of earlier changeset
392
392
393 Prepare a new changeset with the effect of REV undone in the
393 Prepare a new changeset with the effect of REV undone in the
394 current working directory.
394 current working directory.
395
395
396 If REV is the parent of the working directory, then this new changeset
396 If REV is the parent of the working directory, then this new changeset
397 is committed automatically. Otherwise, hg needs to merge the
397 is committed automatically. Otherwise, hg needs to merge the
398 changes and the merged result is left uncommitted.
398 changes and the merged result is left uncommitted.
399
399
400 .. note::
400 .. note::
401
401
402 backout cannot be used to fix either an unwanted or
402 backout cannot be used to fix either an unwanted or
403 incorrect merge.
403 incorrect merge.
404
404
405 .. container:: verbose
405 .. container:: verbose
406
406
407 By default, the pending changeset will have one parent,
407 By default, the pending changeset will have one parent,
408 maintaining a linear history. With --merge, the pending
408 maintaining a linear history. With --merge, the pending
409 changeset will instead have two parents: the old parent of the
409 changeset will instead have two parents: the old parent of the
410 working directory and a new child of REV that simply undoes REV.
410 working directory and a new child of REV that simply undoes REV.
411
411
412 Before version 1.7, the behavior without --merge was equivalent
412 Before version 1.7, the behavior without --merge was equivalent
413 to specifying --merge followed by :hg:`update --clean .` to
413 to specifying --merge followed by :hg:`update --clean .` to
414 cancel the merge and leave the child of REV as a head to be
414 cancel the merge and leave the child of REV as a head to be
415 merged separately.
415 merged separately.
416
416
417 See :hg:`help dates` for a list of formats valid for -d/--date.
417 See :hg:`help dates` for a list of formats valid for -d/--date.
418
418
419 Returns 0 on success.
419 Returns 0 on success.
420 '''
420 '''
421 if rev and node:
421 if rev and node:
422 raise util.Abort(_("please specify just one revision"))
422 raise util.Abort(_("please specify just one revision"))
423
423
424 if not rev:
424 if not rev:
425 rev = node
425 rev = node
426
426
427 if not rev:
427 if not rev:
428 raise util.Abort(_("please specify a revision to backout"))
428 raise util.Abort(_("please specify a revision to backout"))
429
429
430 date = opts.get('date')
430 date = opts.get('date')
431 if date:
431 if date:
432 opts['date'] = util.parsedate(date)
432 opts['date'] = util.parsedate(date)
433
433
434 cmdutil.checkunfinished(repo)
434 cmdutil.checkunfinished(repo)
435 cmdutil.bailifchanged(repo)
435 cmdutil.bailifchanged(repo)
436 node = scmutil.revsingle(repo, rev).node()
436 node = scmutil.revsingle(repo, rev).node()
437
437
438 op1, op2 = repo.dirstate.parents()
438 op1, op2 = repo.dirstate.parents()
439 a = repo.changelog.ancestor(op1, node)
439 a = repo.changelog.ancestor(op1, node)
440 if a != node:
440 if a != node:
441 raise util.Abort(_('cannot backout change on a different branch'))
441 raise util.Abort(_('cannot backout change on a different branch'))
442
442
443 p1, p2 = repo.changelog.parents(node)
443 p1, p2 = repo.changelog.parents(node)
444 if p1 == nullid:
444 if p1 == nullid:
445 raise util.Abort(_('cannot backout a change with no parents'))
445 raise util.Abort(_('cannot backout a change with no parents'))
446 if p2 != nullid:
446 if p2 != nullid:
447 if not opts.get('parent'):
447 if not opts.get('parent'):
448 raise util.Abort(_('cannot backout a merge changeset'))
448 raise util.Abort(_('cannot backout a merge changeset'))
449 p = repo.lookup(opts['parent'])
449 p = repo.lookup(opts['parent'])
450 if p not in (p1, p2):
450 if p not in (p1, p2):
451 raise util.Abort(_('%s is not a parent of %s') %
451 raise util.Abort(_('%s is not a parent of %s') %
452 (short(p), short(node)))
452 (short(p), short(node)))
453 parent = p
453 parent = p
454 else:
454 else:
455 if opts.get('parent'):
455 if opts.get('parent'):
456 raise util.Abort(_('cannot use --parent on non-merge changeset'))
456 raise util.Abort(_('cannot use --parent on non-merge changeset'))
457 parent = p1
457 parent = p1
458
458
459 # the backout should appear on the same branch
459 # the backout should appear on the same branch
460 wlock = repo.wlock()
460 wlock = repo.wlock()
461 try:
461 try:
462 branch = repo.dirstate.branch()
462 branch = repo.dirstate.branch()
463 bheads = repo.branchheads(branch)
463 bheads = repo.branchheads(branch)
464 hg.clean(repo, node, show_stats=False)
464 hg.clean(repo, node, show_stats=False)
465 repo.dirstate.setbranch(branch)
465 repo.dirstate.setbranch(branch)
466 rctx = scmutil.revsingle(repo, hex(parent))
466 rctx = scmutil.revsingle(repo, hex(parent))
467 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
467 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
468 if not opts.get('merge') and op1 != node:
468 if not opts.get('merge') and op1 != node:
469 try:
469 try:
470 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
470 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
471 return hg.update(repo, op1)
471 return hg.update(repo, op1)
472 finally:
472 finally:
473 ui.setconfig('ui', 'forcemerge', '')
473 ui.setconfig('ui', 'forcemerge', '')
474
474
475 e = cmdutil.commiteditor
475 e = cmdutil.commiteditor
476 if not opts['message'] and not opts['logfile']:
476 if not opts['message'] and not opts['logfile']:
477 # we don't translate commit messages
477 # we don't translate commit messages
478 opts['message'] = "Backed out changeset %s" % short(node)
478 opts['message'] = "Backed out changeset %s" % short(node)
479 e = cmdutil.commitforceeditor
479 e = cmdutil.commitforceeditor
480
480
481 def commitfunc(ui, repo, message, match, opts):
481 def commitfunc(ui, repo, message, match, opts):
482 return repo.commit(message, opts.get('user'), opts.get('date'),
482 return repo.commit(message, opts.get('user'), opts.get('date'),
483 match, editor=e)
483 match, editor=e)
484 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
484 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
485 cmdutil.commitstatus(repo, newnode, branch, bheads)
485 cmdutil.commitstatus(repo, newnode, branch, bheads)
486
486
487 def nice(node):
487 def nice(node):
488 return '%d:%s' % (repo.changelog.rev(node), short(node))
488 return '%d:%s' % (repo.changelog.rev(node), short(node))
489 ui.status(_('changeset %s backs out changeset %s\n') %
489 ui.status(_('changeset %s backs out changeset %s\n') %
490 (nice(repo.changelog.tip()), nice(node)))
490 (nice(repo.changelog.tip()), nice(node)))
491 if opts.get('merge') and op1 != node:
491 if opts.get('merge') and op1 != node:
492 hg.clean(repo, op1, show_stats=False)
492 hg.clean(repo, op1, show_stats=False)
493 ui.status(_('merging with changeset %s\n')
493 ui.status(_('merging with changeset %s\n')
494 % nice(repo.changelog.tip()))
494 % nice(repo.changelog.tip()))
495 try:
495 try:
496 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
496 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
497 return hg.merge(repo, hex(repo.changelog.tip()))
497 return hg.merge(repo, hex(repo.changelog.tip()))
498 finally:
498 finally:
499 ui.setconfig('ui', 'forcemerge', '')
499 ui.setconfig('ui', 'forcemerge', '')
500 finally:
500 finally:
501 wlock.release()
501 wlock.release()
502 return 0
502 return 0
503
503
504 @command('bisect',
504 @command('bisect',
505 [('r', 'reset', False, _('reset bisect state')),
505 [('r', 'reset', False, _('reset bisect state')),
506 ('g', 'good', False, _('mark changeset good')),
506 ('g', 'good', False, _('mark changeset good')),
507 ('b', 'bad', False, _('mark changeset bad')),
507 ('b', 'bad', False, _('mark changeset bad')),
508 ('s', 'skip', False, _('skip testing changeset')),
508 ('s', 'skip', False, _('skip testing changeset')),
509 ('e', 'extend', False, _('extend the bisect range')),
509 ('e', 'extend', False, _('extend the bisect range')),
510 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
510 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
511 ('U', 'noupdate', False, _('do not update to target'))],
511 ('U', 'noupdate', False, _('do not update to target'))],
512 _("[-gbsr] [-U] [-c CMD] [REV]"))
512 _("[-gbsr] [-U] [-c CMD] [REV]"))
513 def bisect(ui, repo, rev=None, extra=None, command=None,
513 def bisect(ui, repo, rev=None, extra=None, command=None,
514 reset=None, good=None, bad=None, skip=None, extend=None,
514 reset=None, good=None, bad=None, skip=None, extend=None,
515 noupdate=None):
515 noupdate=None):
516 """subdivision search of changesets
516 """subdivision search of changesets
517
517
518 This command helps to find changesets which introduce problems. To
518 This command helps to find changesets which introduce problems. To
519 use, mark the earliest changeset you know exhibits the problem as
519 use, mark the earliest changeset you know exhibits the problem as
520 bad, then mark the latest changeset which is free from the problem
520 bad, then mark the latest changeset which is free from the problem
521 as good. Bisect will update your working directory to a revision
521 as good. Bisect will update your working directory to a revision
522 for testing (unless the -U/--noupdate option is specified). Once
522 for testing (unless the -U/--noupdate option is specified). Once
523 you have performed tests, mark the working directory as good or
523 you have performed tests, mark the working directory as good or
524 bad, and bisect will either update to another candidate changeset
524 bad, and bisect will either update to another candidate changeset
525 or announce that it has found the bad revision.
525 or announce that it has found the bad revision.
526
526
527 As a shortcut, you can also use the revision argument to mark a
527 As a shortcut, you can also use the revision argument to mark a
528 revision as good or bad without checking it out first.
528 revision as good or bad without checking it out first.
529
529
530 If you supply a command, it will be used for automatic bisection.
530 If you supply a command, it will be used for automatic bisection.
531 The environment variable HG_NODE will contain the ID of the
531 The environment variable HG_NODE will contain the ID of the
532 changeset being tested. The exit status of the command will be
532 changeset being tested. The exit status of the command will be
533 used to mark revisions as good or bad: status 0 means good, 125
533 used to mark revisions as good or bad: status 0 means good, 125
534 means to skip the revision, 127 (command not found) will abort the
534 means to skip the revision, 127 (command not found) will abort the
535 bisection, and any other non-zero exit status means the revision
535 bisection, and any other non-zero exit status means the revision
536 is bad.
536 is bad.
537
537
538 .. container:: verbose
538 .. container:: verbose
539
539
540 Some examples:
540 Some examples:
541
541
542 - start a bisection with known bad revision 34, and good revision 12::
542 - start a bisection with known bad revision 34, and good revision 12::
543
543
544 hg bisect --bad 34
544 hg bisect --bad 34
545 hg bisect --good 12
545 hg bisect --good 12
546
546
547 - advance the current bisection by marking current revision as good or
547 - advance the current bisection by marking current revision as good or
548 bad::
548 bad::
549
549
550 hg bisect --good
550 hg bisect --good
551 hg bisect --bad
551 hg bisect --bad
552
552
553 - mark the current revision, or a known revision, to be skipped (e.g. if
553 - mark the current revision, or a known revision, to be skipped (e.g. if
554 that revision is not usable because of another issue)::
554 that revision is not usable because of another issue)::
555
555
556 hg bisect --skip
556 hg bisect --skip
557 hg bisect --skip 23
557 hg bisect --skip 23
558
558
559 - skip all revisions that do not touch directories ``foo`` or ``bar``::
559 - skip all revisions that do not touch directories ``foo`` or ``bar``::
560
560
561 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
561 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
562
562
563 - forget the current bisection::
563 - forget the current bisection::
564
564
565 hg bisect --reset
565 hg bisect --reset
566
566
567 - use 'make && make tests' to automatically find the first broken
567 - use 'make && make tests' to automatically find the first broken
568 revision::
568 revision::
569
569
570 hg bisect --reset
570 hg bisect --reset
571 hg bisect --bad 34
571 hg bisect --bad 34
572 hg bisect --good 12
572 hg bisect --good 12
573 hg bisect --command "make && make tests"
573 hg bisect --command "make && make tests"
574
574
575 - see all changesets whose states are already known in the current
575 - see all changesets whose states are already known in the current
576 bisection::
576 bisection::
577
577
578 hg log -r "bisect(pruned)"
578 hg log -r "bisect(pruned)"
579
579
580 - see the changeset currently being bisected (especially useful
580 - see the changeset currently being bisected (especially useful
581 if running with -U/--noupdate)::
581 if running with -U/--noupdate)::
582
582
583 hg log -r "bisect(current)"
583 hg log -r "bisect(current)"
584
584
585 - see all changesets that took part in the current bisection::
585 - see all changesets that took part in the current bisection::
586
586
587 hg log -r "bisect(range)"
587 hg log -r "bisect(range)"
588
588
589 - you can even get a nice graph::
589 - you can even get a nice graph::
590
590
591 hg log --graph -r "bisect(range)"
591 hg log --graph -r "bisect(range)"
592
592
593 See :hg:`help revsets` for more about the `bisect()` keyword.
593 See :hg:`help revsets` for more about the `bisect()` keyword.
594
594
595 Returns 0 on success.
595 Returns 0 on success.
596 """
596 """
597 def extendbisectrange(nodes, good):
597 def extendbisectrange(nodes, good):
598 # bisect is incomplete when it ends on a merge node and
598 # bisect is incomplete when it ends on a merge node and
599 # one of the parent was not checked.
599 # one of the parent was not checked.
600 parents = repo[nodes[0]].parents()
600 parents = repo[nodes[0]].parents()
601 if len(parents) > 1:
601 if len(parents) > 1:
602 side = good and state['bad'] or state['good']
602 side = good and state['bad'] or state['good']
603 num = len(set(i.node() for i in parents) & set(side))
603 num = len(set(i.node() for i in parents) & set(side))
604 if num == 1:
604 if num == 1:
605 return parents[0].ancestor(parents[1])
605 return parents[0].ancestor(parents[1])
606 return None
606 return None
607
607
608 def print_result(nodes, good):
608 def print_result(nodes, good):
609 displayer = cmdutil.show_changeset(ui, repo, {})
609 displayer = cmdutil.show_changeset(ui, repo, {})
610 if len(nodes) == 1:
610 if len(nodes) == 1:
611 # narrowed it down to a single revision
611 # narrowed it down to a single revision
612 if good:
612 if good:
613 ui.write(_("The first good revision is:\n"))
613 ui.write(_("The first good revision is:\n"))
614 else:
614 else:
615 ui.write(_("The first bad revision is:\n"))
615 ui.write(_("The first bad revision is:\n"))
616 displayer.show(repo[nodes[0]])
616 displayer.show(repo[nodes[0]])
617 extendnode = extendbisectrange(nodes, good)
617 extendnode = extendbisectrange(nodes, good)
618 if extendnode is not None:
618 if extendnode is not None:
619 ui.write(_('Not all ancestors of this changeset have been'
619 ui.write(_('Not all ancestors of this changeset have been'
620 ' checked.\nUse bisect --extend to continue the '
620 ' checked.\nUse bisect --extend to continue the '
621 'bisection from\nthe common ancestor, %s.\n')
621 'bisection from\nthe common ancestor, %s.\n')
622 % extendnode)
622 % extendnode)
623 else:
623 else:
624 # multiple possible revisions
624 # multiple possible revisions
625 if good:
625 if good:
626 ui.write(_("Due to skipped revisions, the first "
626 ui.write(_("Due to skipped revisions, the first "
627 "good revision could be any of:\n"))
627 "good revision could be any of:\n"))
628 else:
628 else:
629 ui.write(_("Due to skipped revisions, the first "
629 ui.write(_("Due to skipped revisions, the first "
630 "bad revision could be any of:\n"))
630 "bad revision could be any of:\n"))
631 for n in nodes:
631 for n in nodes:
632 displayer.show(repo[n])
632 displayer.show(repo[n])
633 displayer.close()
633 displayer.close()
634
634
635 def check_state(state, interactive=True):
635 def check_state(state, interactive=True):
636 if not state['good'] or not state['bad']:
636 if not state['good'] or not state['bad']:
637 if (good or bad or skip or reset) and interactive:
637 if (good or bad or skip or reset) and interactive:
638 return
638 return
639 if not state['good']:
639 if not state['good']:
640 raise util.Abort(_('cannot bisect (no known good revisions)'))
640 raise util.Abort(_('cannot bisect (no known good revisions)'))
641 else:
641 else:
642 raise util.Abort(_('cannot bisect (no known bad revisions)'))
642 raise util.Abort(_('cannot bisect (no known bad revisions)'))
643 return True
643 return True
644
644
645 # backward compatibility
645 # backward compatibility
646 if rev in "good bad reset init".split():
646 if rev in "good bad reset init".split():
647 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
647 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
648 cmd, rev, extra = rev, extra, None
648 cmd, rev, extra = rev, extra, None
649 if cmd == "good":
649 if cmd == "good":
650 good = True
650 good = True
651 elif cmd == "bad":
651 elif cmd == "bad":
652 bad = True
652 bad = True
653 else:
653 else:
654 reset = True
654 reset = True
655 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
655 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
656 raise util.Abort(_('incompatible arguments'))
656 raise util.Abort(_('incompatible arguments'))
657
657
658 cmdutil.checkunfinished(repo)
658 cmdutil.checkunfinished(repo)
659
659
660 if reset:
660 if reset:
661 p = repo.join("bisect.state")
661 p = repo.join("bisect.state")
662 if os.path.exists(p):
662 if os.path.exists(p):
663 os.unlink(p)
663 os.unlink(p)
664 return
664 return
665
665
666 state = hbisect.load_state(repo)
666 state = hbisect.load_state(repo)
667
667
668 if command:
668 if command:
669 changesets = 1
669 changesets = 1
670 try:
670 if noupdate:
671 node = state['current'][0]
671 try:
672 except LookupError:
672 node = state['current'][0]
673 if noupdate:
673 except LookupError:
674 raise util.Abort(_('current bisect revision is unknown - '
674 raise util.Abort(_('current bisect revision is unknown - '
675 'start a new bisect to fix'))
675 'start a new bisect to fix'))
676 else:
676 node, p2 = repo.dirstate.parents()
677 node, p2 = repo.dirstate.parents()
677 if p2 != nullid:
678 if p2 != nullid:
678 raise util.Abort(_('current bisect revision is a merge'))
679 raise util.Abort(_('current bisect revision is a merge'))
679 try:
680 try:
680 while changesets:
681 while changesets:
681 # update state
682 # update state
682 state['current'] = [node]
683 state['current'] = [node]
683 hbisect.save_state(repo, state)
684 hbisect.save_state(repo, state)
684 status = util.system(command,
685 status = util.system(command,
685 environ={'HG_NODE': hex(node)},
686 environ={'HG_NODE': hex(node)},
686 out=ui.fout)
687 out=ui.fout)
687 if status == 125:
688 if status == 125:
688 transition = "skip"
689 transition = "skip"
689 elif status == 0:
690 elif status == 0:
690 transition = "good"
691 transition = "good"
691 # status < 0 means process was killed
692 # status < 0 means process was killed
692 elif status == 127:
693 elif status == 127:
693 raise util.Abort(_("failed to execute %s") % command)
694 raise util.Abort(_("failed to execute %s") % command)
694 elif status < 0:
695 elif status < 0:
695 raise util.Abort(_("%s killed") % command)
696 raise util.Abort(_("%s killed") % command)
696 else:
697 else:
697 transition = "bad"
698 transition = "bad"
698 ctx = scmutil.revsingle(repo, rev, node)
699 ctx = scmutil.revsingle(repo, rev, node)
699 rev = None # clear for future iterations
700 rev = None # clear for future iterations
700 state[transition].append(ctx.node())
701 state[transition].append(ctx.node())
701 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
702 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
702 check_state(state, interactive=False)
703 check_state(state, interactive=False)
703 # bisect
704 # bisect
704 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
705 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
705 # update to next check
706 # update to next check
706 node = nodes[0]
707 node = nodes[0]
707 if not noupdate:
708 if not noupdate:
708 cmdutil.bailifchanged(repo)
709 cmdutil.bailifchanged(repo)
709 hg.clean(repo, node, show_stats=False)
710 hg.clean(repo, node, show_stats=False)
710 finally:
711 finally:
711 state['current'] = [node]
712 state['current'] = [node]
712 hbisect.save_state(repo, state)
713 hbisect.save_state(repo, state)
713 print_result(nodes, bgood)
714 print_result(nodes, bgood)
714 return
715 return
715
716
716 # update state
717 # update state
717
718
718 if rev:
719 if rev:
719 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
720 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
720 else:
721 else:
721 nodes = [repo.lookup('.')]
722 nodes = [repo.lookup('.')]
722
723
723 if good or bad or skip:
724 if good or bad or skip:
724 if good:
725 if good:
725 state['good'] += nodes
726 state['good'] += nodes
726 elif bad:
727 elif bad:
727 state['bad'] += nodes
728 state['bad'] += nodes
728 elif skip:
729 elif skip:
729 state['skip'] += nodes
730 state['skip'] += nodes
730 hbisect.save_state(repo, state)
731 hbisect.save_state(repo, state)
731
732
732 if not check_state(state):
733 if not check_state(state):
733 return
734 return
734
735
735 # actually bisect
736 # actually bisect
736 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
737 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
737 if extend:
738 if extend:
738 if not changesets:
739 if not changesets:
739 extendnode = extendbisectrange(nodes, good)
740 extendnode = extendbisectrange(nodes, good)
740 if extendnode is not None:
741 if extendnode is not None:
741 ui.write(_("Extending search to changeset %d:%s\n"
742 ui.write(_("Extending search to changeset %d:%s\n"
742 % (extendnode.rev(), extendnode)))
743 % (extendnode.rev(), extendnode)))
743 state['current'] = [extendnode.node()]
744 state['current'] = [extendnode.node()]
744 hbisect.save_state(repo, state)
745 hbisect.save_state(repo, state)
745 if noupdate:
746 if noupdate:
746 return
747 return
747 cmdutil.bailifchanged(repo)
748 cmdutil.bailifchanged(repo)
748 return hg.clean(repo, extendnode.node())
749 return hg.clean(repo, extendnode.node())
749 raise util.Abort(_("nothing to extend"))
750 raise util.Abort(_("nothing to extend"))
750
751
751 if changesets == 0:
752 if changesets == 0:
752 print_result(nodes, good)
753 print_result(nodes, good)
753 else:
754 else:
754 assert len(nodes) == 1 # only a single node can be tested next
755 assert len(nodes) == 1 # only a single node can be tested next
755 node = nodes[0]
756 node = nodes[0]
756 # compute the approximate number of remaining tests
757 # compute the approximate number of remaining tests
757 tests, size = 0, 2
758 tests, size = 0, 2
758 while size <= changesets:
759 while size <= changesets:
759 tests, size = tests + 1, size * 2
760 tests, size = tests + 1, size * 2
760 rev = repo.changelog.rev(node)
761 rev = repo.changelog.rev(node)
761 ui.write(_("Testing changeset %d:%s "
762 ui.write(_("Testing changeset %d:%s "
762 "(%d changesets remaining, ~%d tests)\n")
763 "(%d changesets remaining, ~%d tests)\n")
763 % (rev, short(node), changesets, tests))
764 % (rev, short(node), changesets, tests))
764 state['current'] = [node]
765 state['current'] = [node]
765 hbisect.save_state(repo, state)
766 hbisect.save_state(repo, state)
766 if not noupdate:
767 if not noupdate:
767 cmdutil.bailifchanged(repo)
768 cmdutil.bailifchanged(repo)
768 return hg.clean(repo, node)
769 return hg.clean(repo, node)
769
770
770 @command('bookmarks|bookmark',
771 @command('bookmarks|bookmark',
771 [('f', 'force', False, _('force')),
772 [('f', 'force', False, _('force')),
772 ('r', 'rev', '', _('revision'), _('REV')),
773 ('r', 'rev', '', _('revision'), _('REV')),
773 ('d', 'delete', False, _('delete a given bookmark')),
774 ('d', 'delete', False, _('delete a given bookmark')),
774 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
775 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
775 ('i', 'inactive', False, _('mark a bookmark inactive'))],
776 ('i', 'inactive', False, _('mark a bookmark inactive'))],
776 _('hg bookmarks [OPTIONS]... [NAME]...'))
777 _('hg bookmarks [OPTIONS]... [NAME]...'))
777 def bookmark(ui, repo, *names, **opts):
778 def bookmark(ui, repo, *names, **opts):
778 '''track a line of development with movable markers
779 '''track a line of development with movable markers
779
780
780 Bookmarks are pointers to certain commits that move when committing.
781 Bookmarks are pointers to certain commits that move when committing.
781 Bookmarks are local. They can be renamed, copied and deleted. It is
782 Bookmarks are local. They can be renamed, copied and deleted. It is
782 possible to use :hg:`merge NAME` to merge from a given bookmark, and
783 possible to use :hg:`merge NAME` to merge from a given bookmark, and
783 :hg:`update NAME` to update to a given bookmark.
784 :hg:`update NAME` to update to a given bookmark.
784
785
785 You can use :hg:`bookmark NAME` to set a bookmark on the working
786 You can use :hg:`bookmark NAME` to set a bookmark on the working
786 directory's parent revision with the given name. If you specify
787 directory's parent revision with the given name. If you specify
787 a revision using -r REV (where REV may be an existing bookmark),
788 a revision using -r REV (where REV may be an existing bookmark),
788 the bookmark is assigned to that revision.
789 the bookmark is assigned to that revision.
789
790
790 Bookmarks can be pushed and pulled between repositories (see :hg:`help
791 Bookmarks can be pushed and pulled between repositories (see :hg:`help
791 push` and :hg:`help pull`). This requires both the local and remote
792 push` and :hg:`help pull`). This requires both the local and remote
792 repositories to support bookmarks. For versions prior to 1.8, this means
793 repositories to support bookmarks. For versions prior to 1.8, this means
793 the bookmarks extension must be enabled.
794 the bookmarks extension must be enabled.
794
795
795 If you set a bookmark called '@', new clones of the repository will
796 If you set a bookmark called '@', new clones of the repository will
796 have that revision checked out (and the bookmark made active) by
797 have that revision checked out (and the bookmark made active) by
797 default.
798 default.
798
799
799 With -i/--inactive, the new bookmark will not be made the active
800 With -i/--inactive, the new bookmark will not be made the active
800 bookmark. If -r/--rev is given, the new bookmark will not be made
801 bookmark. If -r/--rev is given, the new bookmark will not be made
801 active even if -i/--inactive is not given. If no NAME is given, the
802 active even if -i/--inactive is not given. If no NAME is given, the
802 current active bookmark will be marked inactive.
803 current active bookmark will be marked inactive.
803 '''
804 '''
804 force = opts.get('force')
805 force = opts.get('force')
805 rev = opts.get('rev')
806 rev = opts.get('rev')
806 delete = opts.get('delete')
807 delete = opts.get('delete')
807 rename = opts.get('rename')
808 rename = opts.get('rename')
808 inactive = opts.get('inactive')
809 inactive = opts.get('inactive')
809
810
810 def checkformat(mark):
811 def checkformat(mark):
811 mark = mark.strip()
812 mark = mark.strip()
812 if not mark:
813 if not mark:
813 raise util.Abort(_("bookmark names cannot consist entirely of "
814 raise util.Abort(_("bookmark names cannot consist entirely of "
814 "whitespace"))
815 "whitespace"))
815 scmutil.checknewlabel(repo, mark, 'bookmark')
816 scmutil.checknewlabel(repo, mark, 'bookmark')
816 return mark
817 return mark
817
818
818 def checkconflict(repo, mark, cur, force=False, target=None):
819 def checkconflict(repo, mark, cur, force=False, target=None):
819 if mark in marks and not force:
820 if mark in marks and not force:
820 if target:
821 if target:
821 if marks[mark] == target and target == cur:
822 if marks[mark] == target and target == cur:
822 # re-activating a bookmark
823 # re-activating a bookmark
823 return
824 return
824 anc = repo.changelog.ancestors([repo[target].rev()])
825 anc = repo.changelog.ancestors([repo[target].rev()])
825 bmctx = repo[marks[mark]]
826 bmctx = repo[marks[mark]]
826 divs = [repo[b].node() for b in marks
827 divs = [repo[b].node() for b in marks
827 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
828 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
828
829
829 # allow resolving a single divergent bookmark even if moving
830 # allow resolving a single divergent bookmark even if moving
830 # the bookmark across branches when a revision is specified
831 # the bookmark across branches when a revision is specified
831 # that contains a divergent bookmark
832 # that contains a divergent bookmark
832 if bmctx.rev() not in anc and target in divs:
833 if bmctx.rev() not in anc and target in divs:
833 bookmarks.deletedivergent(repo, [target], mark)
834 bookmarks.deletedivergent(repo, [target], mark)
834 return
835 return
835
836
836 # consider successor changesets as well
837 # consider successor changesets as well
837 foreground = obsolete.foreground(repo, [marks[mark]])
838 foreground = obsolete.foreground(repo, [marks[mark]])
838 deletefrom = [b for b in divs
839 deletefrom = [b for b in divs
839 if repo[b].rev() in anc or b == target]
840 if repo[b].rev() in anc or b == target]
840 bookmarks.deletedivergent(repo, deletefrom, mark)
841 bookmarks.deletedivergent(repo, deletefrom, mark)
841 if bmctx.rev() in anc or target in foreground:
842 if bmctx.rev() in anc or target in foreground:
842 ui.status(_("moving bookmark '%s' forward from %s\n") %
843 ui.status(_("moving bookmark '%s' forward from %s\n") %
843 (mark, short(bmctx.node())))
844 (mark, short(bmctx.node())))
844 return
845 return
845 raise util.Abort(_("bookmark '%s' already exists "
846 raise util.Abort(_("bookmark '%s' already exists "
846 "(use -f to force)") % mark)
847 "(use -f to force)") % mark)
847 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
848 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
848 and not force):
849 and not force):
849 raise util.Abort(
850 raise util.Abort(
850 _("a bookmark cannot have the name of an existing branch"))
851 _("a bookmark cannot have the name of an existing branch"))
851
852
852 if delete and rename:
853 if delete and rename:
853 raise util.Abort(_("--delete and --rename are incompatible"))
854 raise util.Abort(_("--delete and --rename are incompatible"))
854 if delete and rev:
855 if delete and rev:
855 raise util.Abort(_("--rev is incompatible with --delete"))
856 raise util.Abort(_("--rev is incompatible with --delete"))
856 if rename and rev:
857 if rename and rev:
857 raise util.Abort(_("--rev is incompatible with --rename"))
858 raise util.Abort(_("--rev is incompatible with --rename"))
858 if not names and (delete or rev):
859 if not names and (delete or rev):
859 raise util.Abort(_("bookmark name required"))
860 raise util.Abort(_("bookmark name required"))
860
861
861 if delete or rename or names or inactive:
862 if delete or rename or names or inactive:
862 wlock = repo.wlock()
863 wlock = repo.wlock()
863 try:
864 try:
864 cur = repo.changectx('.').node()
865 cur = repo.changectx('.').node()
865 marks = repo._bookmarks
866 marks = repo._bookmarks
866 if delete:
867 if delete:
867 for mark in names:
868 for mark in names:
868 if mark not in marks:
869 if mark not in marks:
869 raise util.Abort(_("bookmark '%s' does not exist") %
870 raise util.Abort(_("bookmark '%s' does not exist") %
870 mark)
871 mark)
871 if mark == repo._bookmarkcurrent:
872 if mark == repo._bookmarkcurrent:
872 bookmarks.unsetcurrent(repo)
873 bookmarks.unsetcurrent(repo)
873 del marks[mark]
874 del marks[mark]
874 marks.write()
875 marks.write()
875
876
876 elif rename:
877 elif rename:
877 if not names:
878 if not names:
878 raise util.Abort(_("new bookmark name required"))
879 raise util.Abort(_("new bookmark name required"))
879 elif len(names) > 1:
880 elif len(names) > 1:
880 raise util.Abort(_("only one new bookmark name allowed"))
881 raise util.Abort(_("only one new bookmark name allowed"))
881 mark = checkformat(names[0])
882 mark = checkformat(names[0])
882 if rename not in marks:
883 if rename not in marks:
883 raise util.Abort(_("bookmark '%s' does not exist") % rename)
884 raise util.Abort(_("bookmark '%s' does not exist") % rename)
884 checkconflict(repo, mark, cur, force)
885 checkconflict(repo, mark, cur, force)
885 marks[mark] = marks[rename]
886 marks[mark] = marks[rename]
886 if repo._bookmarkcurrent == rename and not inactive:
887 if repo._bookmarkcurrent == rename and not inactive:
887 bookmarks.setcurrent(repo, mark)
888 bookmarks.setcurrent(repo, mark)
888 del marks[rename]
889 del marks[rename]
889 marks.write()
890 marks.write()
890
891
891 elif names:
892 elif names:
892 newact = None
893 newact = None
893 for mark in names:
894 for mark in names:
894 mark = checkformat(mark)
895 mark = checkformat(mark)
895 if newact is None:
896 if newact is None:
896 newact = mark
897 newact = mark
897 if inactive and mark == repo._bookmarkcurrent:
898 if inactive and mark == repo._bookmarkcurrent:
898 bookmarks.unsetcurrent(repo)
899 bookmarks.unsetcurrent(repo)
899 return
900 return
900 tgt = cur
901 tgt = cur
901 if rev:
902 if rev:
902 tgt = scmutil.revsingle(repo, rev).node()
903 tgt = scmutil.revsingle(repo, rev).node()
903 checkconflict(repo, mark, cur, force, tgt)
904 checkconflict(repo, mark, cur, force, tgt)
904 marks[mark] = tgt
905 marks[mark] = tgt
905 if not inactive and cur == marks[newact] and not rev:
906 if not inactive and cur == marks[newact] and not rev:
906 bookmarks.setcurrent(repo, newact)
907 bookmarks.setcurrent(repo, newact)
907 elif cur != tgt and newact == repo._bookmarkcurrent:
908 elif cur != tgt and newact == repo._bookmarkcurrent:
908 bookmarks.unsetcurrent(repo)
909 bookmarks.unsetcurrent(repo)
909 marks.write()
910 marks.write()
910
911
911 elif inactive:
912 elif inactive:
912 if len(marks) == 0:
913 if len(marks) == 0:
913 ui.status(_("no bookmarks set\n"))
914 ui.status(_("no bookmarks set\n"))
914 elif not repo._bookmarkcurrent:
915 elif not repo._bookmarkcurrent:
915 ui.status(_("no active bookmark\n"))
916 ui.status(_("no active bookmark\n"))
916 else:
917 else:
917 bookmarks.unsetcurrent(repo)
918 bookmarks.unsetcurrent(repo)
918 finally:
919 finally:
919 wlock.release()
920 wlock.release()
920 else: # show bookmarks
921 else: # show bookmarks
921 hexfn = ui.debugflag and hex or short
922 hexfn = ui.debugflag and hex or short
922 marks = repo._bookmarks
923 marks = repo._bookmarks
923 if len(marks) == 0:
924 if len(marks) == 0:
924 ui.status(_("no bookmarks set\n"))
925 ui.status(_("no bookmarks set\n"))
925 else:
926 else:
926 for bmark, n in sorted(marks.iteritems()):
927 for bmark, n in sorted(marks.iteritems()):
927 current = repo._bookmarkcurrent
928 current = repo._bookmarkcurrent
928 if bmark == current:
929 if bmark == current:
929 prefix, label = '*', 'bookmarks.current'
930 prefix, label = '*', 'bookmarks.current'
930 else:
931 else:
931 prefix, label = ' ', ''
932 prefix, label = ' ', ''
932
933
933 if ui.quiet:
934 if ui.quiet:
934 ui.write("%s\n" % bmark, label=label)
935 ui.write("%s\n" % bmark, label=label)
935 else:
936 else:
936 ui.write(" %s %-25s %d:%s\n" % (
937 ui.write(" %s %-25s %d:%s\n" % (
937 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
938 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
938 label=label)
939 label=label)
939
940
940 @command('branch',
941 @command('branch',
941 [('f', 'force', None,
942 [('f', 'force', None,
942 _('set branch name even if it shadows an existing branch')),
943 _('set branch name even if it shadows an existing branch')),
943 ('C', 'clean', None, _('reset branch name to parent branch name'))],
944 ('C', 'clean', None, _('reset branch name to parent branch name'))],
944 _('[-fC] [NAME]'))
945 _('[-fC] [NAME]'))
945 def branch(ui, repo, label=None, **opts):
946 def branch(ui, repo, label=None, **opts):
946 """set or show the current branch name
947 """set or show the current branch name
947
948
948 .. note::
949 .. note::
949
950
950 Branch names are permanent and global. Use :hg:`bookmark` to create a
951 Branch names are permanent and global. Use :hg:`bookmark` to create a
951 light-weight bookmark instead. See :hg:`help glossary` for more
952 light-weight bookmark instead. See :hg:`help glossary` for more
952 information about named branches and bookmarks.
953 information about named branches and bookmarks.
953
954
954 With no argument, show the current branch name. With one argument,
955 With no argument, show the current branch name. With one argument,
955 set the working directory branch name (the branch will not exist
956 set the working directory branch name (the branch will not exist
956 in the repository until the next commit). Standard practice
957 in the repository until the next commit). Standard practice
957 recommends that primary development take place on the 'default'
958 recommends that primary development take place on the 'default'
958 branch.
959 branch.
959
960
960 Unless -f/--force is specified, branch will not let you set a
961 Unless -f/--force is specified, branch will not let you set a
961 branch name that already exists, even if it's inactive.
962 branch name that already exists, even if it's inactive.
962
963
963 Use -C/--clean to reset the working directory branch to that of
964 Use -C/--clean to reset the working directory branch to that of
964 the parent of the working directory, negating a previous branch
965 the parent of the working directory, negating a previous branch
965 change.
966 change.
966
967
967 Use the command :hg:`update` to switch to an existing branch. Use
968 Use the command :hg:`update` to switch to an existing branch. Use
968 :hg:`commit --close-branch` to mark this branch as closed.
969 :hg:`commit --close-branch` to mark this branch as closed.
969
970
970 Returns 0 on success.
971 Returns 0 on success.
971 """
972 """
972 if label:
973 if label:
973 label = label.strip()
974 label = label.strip()
974
975
975 if not opts.get('clean') and not label:
976 if not opts.get('clean') and not label:
976 ui.write("%s\n" % repo.dirstate.branch())
977 ui.write("%s\n" % repo.dirstate.branch())
977 return
978 return
978
979
979 wlock = repo.wlock()
980 wlock = repo.wlock()
980 try:
981 try:
981 if opts.get('clean'):
982 if opts.get('clean'):
982 label = repo[None].p1().branch()
983 label = repo[None].p1().branch()
983 repo.dirstate.setbranch(label)
984 repo.dirstate.setbranch(label)
984 ui.status(_('reset working directory to branch %s\n') % label)
985 ui.status(_('reset working directory to branch %s\n') % label)
985 elif label:
986 elif label:
986 if not opts.get('force') and label in repo.branchmap():
987 if not opts.get('force') and label in repo.branchmap():
987 if label not in [p.branch() for p in repo.parents()]:
988 if label not in [p.branch() for p in repo.parents()]:
988 raise util.Abort(_('a branch of the same name already'
989 raise util.Abort(_('a branch of the same name already'
989 ' exists'),
990 ' exists'),
990 # i18n: "it" refers to an existing branch
991 # i18n: "it" refers to an existing branch
991 hint=_("use 'hg update' to switch to it"))
992 hint=_("use 'hg update' to switch to it"))
992 scmutil.checknewlabel(repo, label, 'branch')
993 scmutil.checknewlabel(repo, label, 'branch')
993 repo.dirstate.setbranch(label)
994 repo.dirstate.setbranch(label)
994 ui.status(_('marked working directory as branch %s\n') % label)
995 ui.status(_('marked working directory as branch %s\n') % label)
995 ui.status(_('(branches are permanent and global, '
996 ui.status(_('(branches are permanent and global, '
996 'did you want a bookmark?)\n'))
997 'did you want a bookmark?)\n'))
997 finally:
998 finally:
998 wlock.release()
999 wlock.release()
999
1000
1000 @command('branches',
1001 @command('branches',
1001 [('a', 'active', False, _('show only branches that have unmerged heads')),
1002 [('a', 'active', False, _('show only branches that have unmerged heads')),
1002 ('c', 'closed', False, _('show normal and closed branches'))],
1003 ('c', 'closed', False, _('show normal and closed branches'))],
1003 _('[-ac]'))
1004 _('[-ac]'))
1004 def branches(ui, repo, active=False, closed=False):
1005 def branches(ui, repo, active=False, closed=False):
1005 """list repository named branches
1006 """list repository named branches
1006
1007
1007 List the repository's named branches, indicating which ones are
1008 List the repository's named branches, indicating which ones are
1008 inactive. If -c/--closed is specified, also list branches which have
1009 inactive. If -c/--closed is specified, also list branches which have
1009 been marked closed (see :hg:`commit --close-branch`).
1010 been marked closed (see :hg:`commit --close-branch`).
1010
1011
1011 If -a/--active is specified, only show active branches. A branch
1012 If -a/--active is specified, only show active branches. A branch
1012 is considered active if it contains repository heads.
1013 is considered active if it contains repository heads.
1013
1014
1014 Use the command :hg:`update` to switch to an existing branch.
1015 Use the command :hg:`update` to switch to an existing branch.
1015
1016
1016 Returns 0.
1017 Returns 0.
1017 """
1018 """
1018
1019
1019 hexfunc = ui.debugflag and hex or short
1020 hexfunc = ui.debugflag and hex or short
1020
1021
1021 allheads = set(repo.heads())
1022 allheads = set(repo.heads())
1022 branches = []
1023 branches = []
1023 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1024 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1024 isactive = not isclosed and bool(set(heads) & allheads)
1025 isactive = not isclosed and bool(set(heads) & allheads)
1025 branches.append((tag, repo[tip], isactive, not isclosed))
1026 branches.append((tag, repo[tip], isactive, not isclosed))
1026 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1027 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1027 reverse=True)
1028 reverse=True)
1028
1029
1029 for tag, ctx, isactive, isopen in branches:
1030 for tag, ctx, isactive, isopen in branches:
1030 if (not active) or isactive:
1031 if (not active) or isactive:
1031 if isactive:
1032 if isactive:
1032 label = 'branches.active'
1033 label = 'branches.active'
1033 notice = ''
1034 notice = ''
1034 elif not isopen:
1035 elif not isopen:
1035 if not closed:
1036 if not closed:
1036 continue
1037 continue
1037 label = 'branches.closed'
1038 label = 'branches.closed'
1038 notice = _(' (closed)')
1039 notice = _(' (closed)')
1039 else:
1040 else:
1040 label = 'branches.inactive'
1041 label = 'branches.inactive'
1041 notice = _(' (inactive)')
1042 notice = _(' (inactive)')
1042 if tag == repo.dirstate.branch():
1043 if tag == repo.dirstate.branch():
1043 label = 'branches.current'
1044 label = 'branches.current'
1044 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(tag))
1045 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(tag))
1045 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1046 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1046 'log.changeset changeset.%s' % ctx.phasestr())
1047 'log.changeset changeset.%s' % ctx.phasestr())
1047 labeledtag = ui.label(tag, label)
1048 labeledtag = ui.label(tag, label)
1048 if ui.quiet:
1049 if ui.quiet:
1049 ui.write("%s\n" % labeledtag)
1050 ui.write("%s\n" % labeledtag)
1050 else:
1051 else:
1051 ui.write("%s %s%s\n" % (labeledtag, rev, notice))
1052 ui.write("%s %s%s\n" % (labeledtag, rev, notice))
1052
1053
1053 @command('bundle',
1054 @command('bundle',
1054 [('f', 'force', None, _('run even when the destination is unrelated')),
1055 [('f', 'force', None, _('run even when the destination is unrelated')),
1055 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1056 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1056 _('REV')),
1057 _('REV')),
1057 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1058 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1058 _('BRANCH')),
1059 _('BRANCH')),
1059 ('', 'base', [],
1060 ('', 'base', [],
1060 _('a base changeset assumed to be available at the destination'),
1061 _('a base changeset assumed to be available at the destination'),
1061 _('REV')),
1062 _('REV')),
1062 ('a', 'all', None, _('bundle all changesets in the repository')),
1063 ('a', 'all', None, _('bundle all changesets in the repository')),
1063 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1064 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1064 ] + remoteopts,
1065 ] + remoteopts,
1065 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1066 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1066 def bundle(ui, repo, fname, dest=None, **opts):
1067 def bundle(ui, repo, fname, dest=None, **opts):
1067 """create a changegroup file
1068 """create a changegroup file
1068
1069
1069 Generate a compressed changegroup file collecting changesets not
1070 Generate a compressed changegroup file collecting changesets not
1070 known to be in another repository.
1071 known to be in another repository.
1071
1072
1072 If you omit the destination repository, then hg assumes the
1073 If you omit the destination repository, then hg assumes the
1073 destination will have all the nodes you specify with --base
1074 destination will have all the nodes you specify with --base
1074 parameters. To create a bundle containing all changesets, use
1075 parameters. To create a bundle containing all changesets, use
1075 -a/--all (or --base null).
1076 -a/--all (or --base null).
1076
1077
1077 You can change compression method with the -t/--type option.
1078 You can change compression method with the -t/--type option.
1078 The available compression methods are: none, bzip2, and
1079 The available compression methods are: none, bzip2, and
1079 gzip (by default, bundles are compressed using bzip2).
1080 gzip (by default, bundles are compressed using bzip2).
1080
1081
1081 The bundle file can then be transferred using conventional means
1082 The bundle file can then be transferred using conventional means
1082 and applied to another repository with the unbundle or pull
1083 and applied to another repository with the unbundle or pull
1083 command. This is useful when direct push and pull are not
1084 command. This is useful when direct push and pull are not
1084 available or when exporting an entire repository is undesirable.
1085 available or when exporting an entire repository is undesirable.
1085
1086
1086 Applying bundles preserves all changeset contents including
1087 Applying bundles preserves all changeset contents including
1087 permissions, copy/rename information, and revision history.
1088 permissions, copy/rename information, and revision history.
1088
1089
1089 Returns 0 on success, 1 if no changes found.
1090 Returns 0 on success, 1 if no changes found.
1090 """
1091 """
1091 revs = None
1092 revs = None
1092 if 'rev' in opts:
1093 if 'rev' in opts:
1093 revs = scmutil.revrange(repo, opts['rev'])
1094 revs = scmutil.revrange(repo, opts['rev'])
1094
1095
1095 bundletype = opts.get('type', 'bzip2').lower()
1096 bundletype = opts.get('type', 'bzip2').lower()
1096 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1097 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1097 bundletype = btypes.get(bundletype)
1098 bundletype = btypes.get(bundletype)
1098 if bundletype not in changegroup.bundletypes:
1099 if bundletype not in changegroup.bundletypes:
1099 raise util.Abort(_('unknown bundle type specified with --type'))
1100 raise util.Abort(_('unknown bundle type specified with --type'))
1100
1101
1101 if opts.get('all'):
1102 if opts.get('all'):
1102 base = ['null']
1103 base = ['null']
1103 else:
1104 else:
1104 base = scmutil.revrange(repo, opts.get('base'))
1105 base = scmutil.revrange(repo, opts.get('base'))
1105 # TODO: get desired bundlecaps from command line.
1106 # TODO: get desired bundlecaps from command line.
1106 bundlecaps = None
1107 bundlecaps = None
1107 if base:
1108 if base:
1108 if dest:
1109 if dest:
1109 raise util.Abort(_("--base is incompatible with specifying "
1110 raise util.Abort(_("--base is incompatible with specifying "
1110 "a destination"))
1111 "a destination"))
1111 common = [repo.lookup(rev) for rev in base]
1112 common = [repo.lookup(rev) for rev in base]
1112 heads = revs and map(repo.lookup, revs) or revs
1113 heads = revs and map(repo.lookup, revs) or revs
1113 cg = repo.getbundle('bundle', heads=heads, common=common,
1114 cg = repo.getbundle('bundle', heads=heads, common=common,
1114 bundlecaps=bundlecaps)
1115 bundlecaps=bundlecaps)
1115 outgoing = None
1116 outgoing = None
1116 else:
1117 else:
1117 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1118 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1118 dest, branches = hg.parseurl(dest, opts.get('branch'))
1119 dest, branches = hg.parseurl(dest, opts.get('branch'))
1119 other = hg.peer(repo, opts, dest)
1120 other = hg.peer(repo, opts, dest)
1120 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1121 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1121 heads = revs and map(repo.lookup, revs) or revs
1122 heads = revs and map(repo.lookup, revs) or revs
1122 outgoing = discovery.findcommonoutgoing(repo, other,
1123 outgoing = discovery.findcommonoutgoing(repo, other,
1123 onlyheads=heads,
1124 onlyheads=heads,
1124 force=opts.get('force'),
1125 force=opts.get('force'),
1125 portable=True)
1126 portable=True)
1126 cg = repo.getlocalbundle('bundle', outgoing, bundlecaps)
1127 cg = repo.getlocalbundle('bundle', outgoing, bundlecaps)
1127 if not cg:
1128 if not cg:
1128 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1129 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1129 return 1
1130 return 1
1130
1131
1131 changegroup.writebundle(cg, fname, bundletype)
1132 changegroup.writebundle(cg, fname, bundletype)
1132
1133
1133 @command('cat',
1134 @command('cat',
1134 [('o', 'output', '',
1135 [('o', 'output', '',
1135 _('print output to file with formatted name'), _('FORMAT')),
1136 _('print output to file with formatted name'), _('FORMAT')),
1136 ('r', 'rev', '', _('print the given revision'), _('REV')),
1137 ('r', 'rev', '', _('print the given revision'), _('REV')),
1137 ('', 'decode', None, _('apply any matching decode filter')),
1138 ('', 'decode', None, _('apply any matching decode filter')),
1138 ] + walkopts,
1139 ] + walkopts,
1139 _('[OPTION]... FILE...'))
1140 _('[OPTION]... FILE...'))
1140 def cat(ui, repo, file1, *pats, **opts):
1141 def cat(ui, repo, file1, *pats, **opts):
1141 """output the current or given revision of files
1142 """output the current or given revision of files
1142
1143
1143 Print the specified files as they were at the given revision. If
1144 Print the specified files as they were at the given revision. If
1144 no revision is given, the parent of the working directory is used.
1145 no revision is given, the parent of the working directory is used.
1145
1146
1146 Output may be to a file, in which case the name of the file is
1147 Output may be to a file, in which case the name of the file is
1147 given using a format string. The formatting rules are the same as
1148 given using a format string. The formatting rules are the same as
1148 for the export command, with the following additions:
1149 for the export command, with the following additions:
1149
1150
1150 :``%s``: basename of file being printed
1151 :``%s``: basename of file being printed
1151 :``%d``: dirname of file being printed, or '.' if in repository root
1152 :``%d``: dirname of file being printed, or '.' if in repository root
1152 :``%p``: root-relative path name of file being printed
1153 :``%p``: root-relative path name of file being printed
1153
1154
1154 Returns 0 on success.
1155 Returns 0 on success.
1155 """
1156 """
1156 ctx = scmutil.revsingle(repo, opts.get('rev'))
1157 ctx = scmutil.revsingle(repo, opts.get('rev'))
1157 err = 1
1158 err = 1
1158 m = scmutil.match(ctx, (file1,) + pats, opts)
1159 m = scmutil.match(ctx, (file1,) + pats, opts)
1159 for abs in ctx.walk(m):
1160 for abs in ctx.walk(m):
1160 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1161 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1161 pathname=abs)
1162 pathname=abs)
1162 data = ctx[abs].data()
1163 data = ctx[abs].data()
1163 if opts.get('decode'):
1164 if opts.get('decode'):
1164 data = repo.wwritedata(abs, data)
1165 data = repo.wwritedata(abs, data)
1165 fp.write(data)
1166 fp.write(data)
1166 fp.close()
1167 fp.close()
1167 err = 0
1168 err = 0
1168 return err
1169 return err
1169
1170
1170 @command('^clone',
1171 @command('^clone',
1171 [('U', 'noupdate', None,
1172 [('U', 'noupdate', None,
1172 _('the clone will include an empty working copy (only a repository)')),
1173 _('the clone will include an empty working copy (only a repository)')),
1173 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1174 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1174 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1175 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1175 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1176 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1176 ('', 'pull', None, _('use pull protocol to copy metadata')),
1177 ('', 'pull', None, _('use pull protocol to copy metadata')),
1177 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1178 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1178 ] + remoteopts,
1179 ] + remoteopts,
1179 _('[OPTION]... SOURCE [DEST]'))
1180 _('[OPTION]... SOURCE [DEST]'))
1180 def clone(ui, source, dest=None, **opts):
1181 def clone(ui, source, dest=None, **opts):
1181 """make a copy of an existing repository
1182 """make a copy of an existing repository
1182
1183
1183 Create a copy of an existing repository in a new directory.
1184 Create a copy of an existing repository in a new directory.
1184
1185
1185 If no destination directory name is specified, it defaults to the
1186 If no destination directory name is specified, it defaults to the
1186 basename of the source.
1187 basename of the source.
1187
1188
1188 The location of the source is added to the new repository's
1189 The location of the source is added to the new repository's
1189 ``.hg/hgrc`` file, as the default to be used for future pulls.
1190 ``.hg/hgrc`` file, as the default to be used for future pulls.
1190
1191
1191 Only local paths and ``ssh://`` URLs are supported as
1192 Only local paths and ``ssh://`` URLs are supported as
1192 destinations. For ``ssh://`` destinations, no working directory or
1193 destinations. For ``ssh://`` destinations, no working directory or
1193 ``.hg/hgrc`` will be created on the remote side.
1194 ``.hg/hgrc`` will be created on the remote side.
1194
1195
1195 To pull only a subset of changesets, specify one or more revisions
1196 To pull only a subset of changesets, specify one or more revisions
1196 identifiers with -r/--rev or branches with -b/--branch. The
1197 identifiers with -r/--rev or branches with -b/--branch. The
1197 resulting clone will contain only the specified changesets and
1198 resulting clone will contain only the specified changesets and
1198 their ancestors. These options (or 'clone src#rev dest') imply
1199 their ancestors. These options (or 'clone src#rev dest') imply
1199 --pull, even for local source repositories. Note that specifying a
1200 --pull, even for local source repositories. Note that specifying a
1200 tag will include the tagged changeset but not the changeset
1201 tag will include the tagged changeset but not the changeset
1201 containing the tag.
1202 containing the tag.
1202
1203
1203 If the source repository has a bookmark called '@' set, that
1204 If the source repository has a bookmark called '@' set, that
1204 revision will be checked out in the new repository by default.
1205 revision will be checked out in the new repository by default.
1205
1206
1206 To check out a particular version, use -u/--update, or
1207 To check out a particular version, use -u/--update, or
1207 -U/--noupdate to create a clone with no working directory.
1208 -U/--noupdate to create a clone with no working directory.
1208
1209
1209 .. container:: verbose
1210 .. container:: verbose
1210
1211
1211 For efficiency, hardlinks are used for cloning whenever the
1212 For efficiency, hardlinks are used for cloning whenever the
1212 source and destination are on the same filesystem (note this
1213 source and destination are on the same filesystem (note this
1213 applies only to the repository data, not to the working
1214 applies only to the repository data, not to the working
1214 directory). Some filesystems, such as AFS, implement hardlinking
1215 directory). Some filesystems, such as AFS, implement hardlinking
1215 incorrectly, but do not report errors. In these cases, use the
1216 incorrectly, but do not report errors. In these cases, use the
1216 --pull option to avoid hardlinking.
1217 --pull option to avoid hardlinking.
1217
1218
1218 In some cases, you can clone repositories and the working
1219 In some cases, you can clone repositories and the working
1219 directory using full hardlinks with ::
1220 directory using full hardlinks with ::
1220
1221
1221 $ cp -al REPO REPOCLONE
1222 $ cp -al REPO REPOCLONE
1222
1223
1223 This is the fastest way to clone, but it is not always safe. The
1224 This is the fastest way to clone, but it is not always safe. The
1224 operation is not atomic (making sure REPO is not modified during
1225 operation is not atomic (making sure REPO is not modified during
1225 the operation is up to you) and you have to make sure your
1226 the operation is up to you) and you have to make sure your
1226 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1227 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1227 so). Also, this is not compatible with certain extensions that
1228 so). Also, this is not compatible with certain extensions that
1228 place their metadata under the .hg directory, such as mq.
1229 place their metadata under the .hg directory, such as mq.
1229
1230
1230 Mercurial will update the working directory to the first applicable
1231 Mercurial will update the working directory to the first applicable
1231 revision from this list:
1232 revision from this list:
1232
1233
1233 a) null if -U or the source repository has no changesets
1234 a) null if -U or the source repository has no changesets
1234 b) if -u . and the source repository is local, the first parent of
1235 b) if -u . and the source repository is local, the first parent of
1235 the source repository's working directory
1236 the source repository's working directory
1236 c) the changeset specified with -u (if a branch name, this means the
1237 c) the changeset specified with -u (if a branch name, this means the
1237 latest head of that branch)
1238 latest head of that branch)
1238 d) the changeset specified with -r
1239 d) the changeset specified with -r
1239 e) the tipmost head specified with -b
1240 e) the tipmost head specified with -b
1240 f) the tipmost head specified with the url#branch source syntax
1241 f) the tipmost head specified with the url#branch source syntax
1241 g) the revision marked with the '@' bookmark, if present
1242 g) the revision marked with the '@' bookmark, if present
1242 h) the tipmost head of the default branch
1243 h) the tipmost head of the default branch
1243 i) tip
1244 i) tip
1244
1245
1245 Examples:
1246 Examples:
1246
1247
1247 - clone a remote repository to a new directory named hg/::
1248 - clone a remote repository to a new directory named hg/::
1248
1249
1249 hg clone http://selenic.com/hg
1250 hg clone http://selenic.com/hg
1250
1251
1251 - create a lightweight local clone::
1252 - create a lightweight local clone::
1252
1253
1253 hg clone project/ project-feature/
1254 hg clone project/ project-feature/
1254
1255
1255 - clone from an absolute path on an ssh server (note double-slash)::
1256 - clone from an absolute path on an ssh server (note double-slash)::
1256
1257
1257 hg clone ssh://user@server//home/projects/alpha/
1258 hg clone ssh://user@server//home/projects/alpha/
1258
1259
1259 - do a high-speed clone over a LAN while checking out a
1260 - do a high-speed clone over a LAN while checking out a
1260 specified version::
1261 specified version::
1261
1262
1262 hg clone --uncompressed http://server/repo -u 1.5
1263 hg clone --uncompressed http://server/repo -u 1.5
1263
1264
1264 - create a repository without changesets after a particular revision::
1265 - create a repository without changesets after a particular revision::
1265
1266
1266 hg clone -r 04e544 experimental/ good/
1267 hg clone -r 04e544 experimental/ good/
1267
1268
1268 - clone (and track) a particular named branch::
1269 - clone (and track) a particular named branch::
1269
1270
1270 hg clone http://selenic.com/hg#stable
1271 hg clone http://selenic.com/hg#stable
1271
1272
1272 See :hg:`help urls` for details on specifying URLs.
1273 See :hg:`help urls` for details on specifying URLs.
1273
1274
1274 Returns 0 on success.
1275 Returns 0 on success.
1275 """
1276 """
1276 if opts.get('noupdate') and opts.get('updaterev'):
1277 if opts.get('noupdate') and opts.get('updaterev'):
1277 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1278 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1278
1279
1279 r = hg.clone(ui, opts, source, dest,
1280 r = hg.clone(ui, opts, source, dest,
1280 pull=opts.get('pull'),
1281 pull=opts.get('pull'),
1281 stream=opts.get('uncompressed'),
1282 stream=opts.get('uncompressed'),
1282 rev=opts.get('rev'),
1283 rev=opts.get('rev'),
1283 update=opts.get('updaterev') or not opts.get('noupdate'),
1284 update=opts.get('updaterev') or not opts.get('noupdate'),
1284 branch=opts.get('branch'))
1285 branch=opts.get('branch'))
1285
1286
1286 return r is None
1287 return r is None
1287
1288
1288 @command('^commit|ci',
1289 @command('^commit|ci',
1289 [('A', 'addremove', None,
1290 [('A', 'addremove', None,
1290 _('mark new/missing files as added/removed before committing')),
1291 _('mark new/missing files as added/removed before committing')),
1291 ('', 'close-branch', None,
1292 ('', 'close-branch', None,
1292 _('mark a branch as closed, hiding it from the branch list')),
1293 _('mark a branch as closed, hiding it from the branch list')),
1293 ('', 'amend', None, _('amend the parent of the working dir')),
1294 ('', 'amend', None, _('amend the parent of the working dir')),
1294 ('s', 'secret', None, _('use the secret phase for committing')),
1295 ('s', 'secret', None, _('use the secret phase for committing')),
1295 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1296 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1296 _('[OPTION]... [FILE]...'))
1297 _('[OPTION]... [FILE]...'))
1297 def commit(ui, repo, *pats, **opts):
1298 def commit(ui, repo, *pats, **opts):
1298 """commit the specified files or all outstanding changes
1299 """commit the specified files or all outstanding changes
1299
1300
1300 Commit changes to the given files into the repository. Unlike a
1301 Commit changes to the given files into the repository. Unlike a
1301 centralized SCM, this operation is a local operation. See
1302 centralized SCM, this operation is a local operation. See
1302 :hg:`push` for a way to actively distribute your changes.
1303 :hg:`push` for a way to actively distribute your changes.
1303
1304
1304 If a list of files is omitted, all changes reported by :hg:`status`
1305 If a list of files is omitted, all changes reported by :hg:`status`
1305 will be committed.
1306 will be committed.
1306
1307
1307 If you are committing the result of a merge, do not provide any
1308 If you are committing the result of a merge, do not provide any
1308 filenames or -I/-X filters.
1309 filenames or -I/-X filters.
1309
1310
1310 If no commit message is specified, Mercurial starts your
1311 If no commit message is specified, Mercurial starts your
1311 configured editor where you can enter a message. In case your
1312 configured editor where you can enter a message. In case your
1312 commit fails, you will find a backup of your message in
1313 commit fails, you will find a backup of your message in
1313 ``.hg/last-message.txt``.
1314 ``.hg/last-message.txt``.
1314
1315
1315 The --amend flag can be used to amend the parent of the
1316 The --amend flag can be used to amend the parent of the
1316 working directory with a new commit that contains the changes
1317 working directory with a new commit that contains the changes
1317 in the parent in addition to those currently reported by :hg:`status`,
1318 in the parent in addition to those currently reported by :hg:`status`,
1318 if there are any. The old commit is stored in a backup bundle in
1319 if there are any. The old commit is stored in a backup bundle in
1319 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1320 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1320 on how to restore it).
1321 on how to restore it).
1321
1322
1322 Message, user and date are taken from the amended commit unless
1323 Message, user and date are taken from the amended commit unless
1323 specified. When a message isn't specified on the command line,
1324 specified. When a message isn't specified on the command line,
1324 the editor will open with the message of the amended commit.
1325 the editor will open with the message of the amended commit.
1325
1326
1326 It is not possible to amend public changesets (see :hg:`help phases`)
1327 It is not possible to amend public changesets (see :hg:`help phases`)
1327 or changesets that have children.
1328 or changesets that have children.
1328
1329
1329 See :hg:`help dates` for a list of formats valid for -d/--date.
1330 See :hg:`help dates` for a list of formats valid for -d/--date.
1330
1331
1331 Returns 0 on success, 1 if nothing changed.
1332 Returns 0 on success, 1 if nothing changed.
1332 """
1333 """
1333 if opts.get('subrepos'):
1334 if opts.get('subrepos'):
1334 if opts.get('amend'):
1335 if opts.get('amend'):
1335 raise util.Abort(_('cannot amend with --subrepos'))
1336 raise util.Abort(_('cannot amend with --subrepos'))
1336 # Let --subrepos on the command line override config setting.
1337 # Let --subrepos on the command line override config setting.
1337 ui.setconfig('ui', 'commitsubrepos', True)
1338 ui.setconfig('ui', 'commitsubrepos', True)
1338
1339
1339 # Save this for restoring it later
1340 # Save this for restoring it later
1340 oldcommitphase = ui.config('phases', 'new-commit')
1341 oldcommitphase = ui.config('phases', 'new-commit')
1341
1342
1342 cmdutil.checkunfinished(repo, commit=True)
1343 cmdutil.checkunfinished(repo, commit=True)
1343
1344
1344 branch = repo[None].branch()
1345 branch = repo[None].branch()
1345 bheads = repo.branchheads(branch)
1346 bheads = repo.branchheads(branch)
1346
1347
1347 extra = {}
1348 extra = {}
1348 if opts.get('close_branch'):
1349 if opts.get('close_branch'):
1349 extra['close'] = 1
1350 extra['close'] = 1
1350
1351
1351 if not bheads:
1352 if not bheads:
1352 raise util.Abort(_('can only close branch heads'))
1353 raise util.Abort(_('can only close branch heads'))
1353 elif opts.get('amend'):
1354 elif opts.get('amend'):
1354 if repo.parents()[0].p1().branch() != branch and \
1355 if repo.parents()[0].p1().branch() != branch and \
1355 repo.parents()[0].p2().branch() != branch:
1356 repo.parents()[0].p2().branch() != branch:
1356 raise util.Abort(_('can only close branch heads'))
1357 raise util.Abort(_('can only close branch heads'))
1357
1358
1358 if opts.get('amend'):
1359 if opts.get('amend'):
1359 if ui.configbool('ui', 'commitsubrepos'):
1360 if ui.configbool('ui', 'commitsubrepos'):
1360 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1361 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1361
1362
1362 old = repo['.']
1363 old = repo['.']
1363 if old.phase() == phases.public:
1364 if old.phase() == phases.public:
1364 raise util.Abort(_('cannot amend public changesets'))
1365 raise util.Abort(_('cannot amend public changesets'))
1365 if len(repo[None].parents()) > 1:
1366 if len(repo[None].parents()) > 1:
1366 raise util.Abort(_('cannot amend while merging'))
1367 raise util.Abort(_('cannot amend while merging'))
1367 if (not obsolete._enabled) and old.children():
1368 if (not obsolete._enabled) and old.children():
1368 raise util.Abort(_('cannot amend changeset with children'))
1369 raise util.Abort(_('cannot amend changeset with children'))
1369
1370
1370 e = cmdutil.commiteditor
1371 e = cmdutil.commiteditor
1371 if opts.get('force_editor'):
1372 if opts.get('force_editor'):
1372 e = cmdutil.commitforceeditor
1373 e = cmdutil.commitforceeditor
1373
1374
1374 def commitfunc(ui, repo, message, match, opts):
1375 def commitfunc(ui, repo, message, match, opts):
1375 editor = e
1376 editor = e
1376 # message contains text from -m or -l, if it's empty,
1377 # message contains text from -m or -l, if it's empty,
1377 # open the editor with the old message
1378 # open the editor with the old message
1378 if not message:
1379 if not message:
1379 message = old.description()
1380 message = old.description()
1380 editor = cmdutil.commitforceeditor
1381 editor = cmdutil.commitforceeditor
1381 try:
1382 try:
1382 if opts.get('secret'):
1383 if opts.get('secret'):
1383 ui.setconfig('phases', 'new-commit', 'secret')
1384 ui.setconfig('phases', 'new-commit', 'secret')
1384
1385
1385 return repo.commit(message,
1386 return repo.commit(message,
1386 opts.get('user') or old.user(),
1387 opts.get('user') or old.user(),
1387 opts.get('date') or old.date(),
1388 opts.get('date') or old.date(),
1388 match,
1389 match,
1389 editor=editor,
1390 editor=editor,
1390 extra=extra)
1391 extra=extra)
1391 finally:
1392 finally:
1392 ui.setconfig('phases', 'new-commit', oldcommitphase)
1393 ui.setconfig('phases', 'new-commit', oldcommitphase)
1393
1394
1394 current = repo._bookmarkcurrent
1395 current = repo._bookmarkcurrent
1395 marks = old.bookmarks()
1396 marks = old.bookmarks()
1396 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1397 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1397 if node == old.node():
1398 if node == old.node():
1398 ui.status(_("nothing changed\n"))
1399 ui.status(_("nothing changed\n"))
1399 return 1
1400 return 1
1400 elif marks:
1401 elif marks:
1401 ui.debug('moving bookmarks %r from %s to %s\n' %
1402 ui.debug('moving bookmarks %r from %s to %s\n' %
1402 (marks, old.hex(), hex(node)))
1403 (marks, old.hex(), hex(node)))
1403 newmarks = repo._bookmarks
1404 newmarks = repo._bookmarks
1404 for bm in marks:
1405 for bm in marks:
1405 newmarks[bm] = node
1406 newmarks[bm] = node
1406 if bm == current:
1407 if bm == current:
1407 bookmarks.setcurrent(repo, bm)
1408 bookmarks.setcurrent(repo, bm)
1408 newmarks.write()
1409 newmarks.write()
1409 else:
1410 else:
1410 e = cmdutil.commiteditor
1411 e = cmdutil.commiteditor
1411 if opts.get('force_editor'):
1412 if opts.get('force_editor'):
1412 e = cmdutil.commitforceeditor
1413 e = cmdutil.commitforceeditor
1413
1414
1414 def commitfunc(ui, repo, message, match, opts):
1415 def commitfunc(ui, repo, message, match, opts):
1415 try:
1416 try:
1416 if opts.get('secret'):
1417 if opts.get('secret'):
1417 ui.setconfig('phases', 'new-commit', 'secret')
1418 ui.setconfig('phases', 'new-commit', 'secret')
1418
1419
1419 return repo.commit(message, opts.get('user'), opts.get('date'),
1420 return repo.commit(message, opts.get('user'), opts.get('date'),
1420 match, editor=e, extra=extra)
1421 match, editor=e, extra=extra)
1421 finally:
1422 finally:
1422 ui.setconfig('phases', 'new-commit', oldcommitphase)
1423 ui.setconfig('phases', 'new-commit', oldcommitphase)
1423
1424
1424
1425
1425 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1426 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1426
1427
1427 if not node:
1428 if not node:
1428 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1429 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1429 if stat[3]:
1430 if stat[3]:
1430 ui.status(_("nothing changed (%d missing files, see "
1431 ui.status(_("nothing changed (%d missing files, see "
1431 "'hg status')\n") % len(stat[3]))
1432 "'hg status')\n") % len(stat[3]))
1432 else:
1433 else:
1433 ui.status(_("nothing changed\n"))
1434 ui.status(_("nothing changed\n"))
1434 return 1
1435 return 1
1435
1436
1436 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1437 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1437
1438
1438 @command('copy|cp',
1439 @command('copy|cp',
1439 [('A', 'after', None, _('record a copy that has already occurred')),
1440 [('A', 'after', None, _('record a copy that has already occurred')),
1440 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1441 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1441 ] + walkopts + dryrunopts,
1442 ] + walkopts + dryrunopts,
1442 _('[OPTION]... [SOURCE]... DEST'))
1443 _('[OPTION]... [SOURCE]... DEST'))
1443 def copy(ui, repo, *pats, **opts):
1444 def copy(ui, repo, *pats, **opts):
1444 """mark files as copied for the next commit
1445 """mark files as copied for the next commit
1445
1446
1446 Mark dest as having copies of source files. If dest is a
1447 Mark dest as having copies of source files. If dest is a
1447 directory, copies are put in that directory. If dest is a file,
1448 directory, copies are put in that directory. If dest is a file,
1448 the source must be a single file.
1449 the source must be a single file.
1449
1450
1450 By default, this command copies the contents of files as they
1451 By default, this command copies the contents of files as they
1451 exist in the working directory. If invoked with -A/--after, the
1452 exist in the working directory. If invoked with -A/--after, the
1452 operation is recorded, but no copying is performed.
1453 operation is recorded, but no copying is performed.
1453
1454
1454 This command takes effect with the next commit. To undo a copy
1455 This command takes effect with the next commit. To undo a copy
1455 before that, see :hg:`revert`.
1456 before that, see :hg:`revert`.
1456
1457
1457 Returns 0 on success, 1 if errors are encountered.
1458 Returns 0 on success, 1 if errors are encountered.
1458 """
1459 """
1459 wlock = repo.wlock(False)
1460 wlock = repo.wlock(False)
1460 try:
1461 try:
1461 return cmdutil.copy(ui, repo, pats, opts)
1462 return cmdutil.copy(ui, repo, pats, opts)
1462 finally:
1463 finally:
1463 wlock.release()
1464 wlock.release()
1464
1465
1465 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1466 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1466 def debugancestor(ui, repo, *args):
1467 def debugancestor(ui, repo, *args):
1467 """find the ancestor revision of two revisions in a given index"""
1468 """find the ancestor revision of two revisions in a given index"""
1468 if len(args) == 3:
1469 if len(args) == 3:
1469 index, rev1, rev2 = args
1470 index, rev1, rev2 = args
1470 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1471 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1471 lookup = r.lookup
1472 lookup = r.lookup
1472 elif len(args) == 2:
1473 elif len(args) == 2:
1473 if not repo:
1474 if not repo:
1474 raise util.Abort(_("there is no Mercurial repository here "
1475 raise util.Abort(_("there is no Mercurial repository here "
1475 "(.hg not found)"))
1476 "(.hg not found)"))
1476 rev1, rev2 = args
1477 rev1, rev2 = args
1477 r = repo.changelog
1478 r = repo.changelog
1478 lookup = repo.lookup
1479 lookup = repo.lookup
1479 else:
1480 else:
1480 raise util.Abort(_('either two or three arguments required'))
1481 raise util.Abort(_('either two or three arguments required'))
1481 a = r.ancestor(lookup(rev1), lookup(rev2))
1482 a = r.ancestor(lookup(rev1), lookup(rev2))
1482 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1483 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1483
1484
1484 @command('debugbuilddag',
1485 @command('debugbuilddag',
1485 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1486 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1486 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1487 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1487 ('n', 'new-file', None, _('add new file at each rev'))],
1488 ('n', 'new-file', None, _('add new file at each rev'))],
1488 _('[OPTION]... [TEXT]'))
1489 _('[OPTION]... [TEXT]'))
1489 def debugbuilddag(ui, repo, text=None,
1490 def debugbuilddag(ui, repo, text=None,
1490 mergeable_file=False,
1491 mergeable_file=False,
1491 overwritten_file=False,
1492 overwritten_file=False,
1492 new_file=False):
1493 new_file=False):
1493 """builds a repo with a given DAG from scratch in the current empty repo
1494 """builds a repo with a given DAG from scratch in the current empty repo
1494
1495
1495 The description of the DAG is read from stdin if not given on the
1496 The description of the DAG is read from stdin if not given on the
1496 command line.
1497 command line.
1497
1498
1498 Elements:
1499 Elements:
1499
1500
1500 - "+n" is a linear run of n nodes based on the current default parent
1501 - "+n" is a linear run of n nodes based on the current default parent
1501 - "." is a single node based on the current default parent
1502 - "." is a single node based on the current default parent
1502 - "$" resets the default parent to null (implied at the start);
1503 - "$" resets the default parent to null (implied at the start);
1503 otherwise the default parent is always the last node created
1504 otherwise the default parent is always the last node created
1504 - "<p" sets the default parent to the backref p
1505 - "<p" sets the default parent to the backref p
1505 - "*p" is a fork at parent p, which is a backref
1506 - "*p" is a fork at parent p, which is a backref
1506 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1507 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1507 - "/p2" is a merge of the preceding node and p2
1508 - "/p2" is a merge of the preceding node and p2
1508 - ":tag" defines a local tag for the preceding node
1509 - ":tag" defines a local tag for the preceding node
1509 - "@branch" sets the named branch for subsequent nodes
1510 - "@branch" sets the named branch for subsequent nodes
1510 - "#...\\n" is a comment up to the end of the line
1511 - "#...\\n" is a comment up to the end of the line
1511
1512
1512 Whitespace between the above elements is ignored.
1513 Whitespace between the above elements is ignored.
1513
1514
1514 A backref is either
1515 A backref is either
1515
1516
1516 - a number n, which references the node curr-n, where curr is the current
1517 - a number n, which references the node curr-n, where curr is the current
1517 node, or
1518 node, or
1518 - the name of a local tag you placed earlier using ":tag", or
1519 - the name of a local tag you placed earlier using ":tag", or
1519 - empty to denote the default parent.
1520 - empty to denote the default parent.
1520
1521
1521 All string valued-elements are either strictly alphanumeric, or must
1522 All string valued-elements are either strictly alphanumeric, or must
1522 be enclosed in double quotes ("..."), with "\\" as escape character.
1523 be enclosed in double quotes ("..."), with "\\" as escape character.
1523 """
1524 """
1524
1525
1525 if text is None:
1526 if text is None:
1526 ui.status(_("reading DAG from stdin\n"))
1527 ui.status(_("reading DAG from stdin\n"))
1527 text = ui.fin.read()
1528 text = ui.fin.read()
1528
1529
1529 cl = repo.changelog
1530 cl = repo.changelog
1530 if len(cl) > 0:
1531 if len(cl) > 0:
1531 raise util.Abort(_('repository is not empty'))
1532 raise util.Abort(_('repository is not empty'))
1532
1533
1533 # determine number of revs in DAG
1534 # determine number of revs in DAG
1534 total = 0
1535 total = 0
1535 for type, data in dagparser.parsedag(text):
1536 for type, data in dagparser.parsedag(text):
1536 if type == 'n':
1537 if type == 'n':
1537 total += 1
1538 total += 1
1538
1539
1539 if mergeable_file:
1540 if mergeable_file:
1540 linesperrev = 2
1541 linesperrev = 2
1541 # make a file with k lines per rev
1542 # make a file with k lines per rev
1542 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1543 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1543 initialmergedlines.append("")
1544 initialmergedlines.append("")
1544
1545
1545 tags = []
1546 tags = []
1546
1547
1547 lock = tr = None
1548 lock = tr = None
1548 try:
1549 try:
1549 lock = repo.lock()
1550 lock = repo.lock()
1550 tr = repo.transaction("builddag")
1551 tr = repo.transaction("builddag")
1551
1552
1552 at = -1
1553 at = -1
1553 atbranch = 'default'
1554 atbranch = 'default'
1554 nodeids = []
1555 nodeids = []
1555 id = 0
1556 id = 0
1556 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1557 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1557 for type, data in dagparser.parsedag(text):
1558 for type, data in dagparser.parsedag(text):
1558 if type == 'n':
1559 if type == 'n':
1559 ui.note(('node %s\n' % str(data)))
1560 ui.note(('node %s\n' % str(data)))
1560 id, ps = data
1561 id, ps = data
1561
1562
1562 files = []
1563 files = []
1563 fctxs = {}
1564 fctxs = {}
1564
1565
1565 p2 = None
1566 p2 = None
1566 if mergeable_file:
1567 if mergeable_file:
1567 fn = "mf"
1568 fn = "mf"
1568 p1 = repo[ps[0]]
1569 p1 = repo[ps[0]]
1569 if len(ps) > 1:
1570 if len(ps) > 1:
1570 p2 = repo[ps[1]]
1571 p2 = repo[ps[1]]
1571 pa = p1.ancestor(p2)
1572 pa = p1.ancestor(p2)
1572 base, local, other = [x[fn].data() for x in (pa, p1,
1573 base, local, other = [x[fn].data() for x in (pa, p1,
1573 p2)]
1574 p2)]
1574 m3 = simplemerge.Merge3Text(base, local, other)
1575 m3 = simplemerge.Merge3Text(base, local, other)
1575 ml = [l.strip() for l in m3.merge_lines()]
1576 ml = [l.strip() for l in m3.merge_lines()]
1576 ml.append("")
1577 ml.append("")
1577 elif at > 0:
1578 elif at > 0:
1578 ml = p1[fn].data().split("\n")
1579 ml = p1[fn].data().split("\n")
1579 else:
1580 else:
1580 ml = initialmergedlines
1581 ml = initialmergedlines
1581 ml[id * linesperrev] += " r%i" % id
1582 ml[id * linesperrev] += " r%i" % id
1582 mergedtext = "\n".join(ml)
1583 mergedtext = "\n".join(ml)
1583 files.append(fn)
1584 files.append(fn)
1584 fctxs[fn] = context.memfilectx(fn, mergedtext)
1585 fctxs[fn] = context.memfilectx(fn, mergedtext)
1585
1586
1586 if overwritten_file:
1587 if overwritten_file:
1587 fn = "of"
1588 fn = "of"
1588 files.append(fn)
1589 files.append(fn)
1589 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1590 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1590
1591
1591 if new_file:
1592 if new_file:
1592 fn = "nf%i" % id
1593 fn = "nf%i" % id
1593 files.append(fn)
1594 files.append(fn)
1594 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1595 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1595 if len(ps) > 1:
1596 if len(ps) > 1:
1596 if not p2:
1597 if not p2:
1597 p2 = repo[ps[1]]
1598 p2 = repo[ps[1]]
1598 for fn in p2:
1599 for fn in p2:
1599 if fn.startswith("nf"):
1600 if fn.startswith("nf"):
1600 files.append(fn)
1601 files.append(fn)
1601 fctxs[fn] = p2[fn]
1602 fctxs[fn] = p2[fn]
1602
1603
1603 def fctxfn(repo, cx, path):
1604 def fctxfn(repo, cx, path):
1604 return fctxs.get(path)
1605 return fctxs.get(path)
1605
1606
1606 if len(ps) == 0 or ps[0] < 0:
1607 if len(ps) == 0 or ps[0] < 0:
1607 pars = [None, None]
1608 pars = [None, None]
1608 elif len(ps) == 1:
1609 elif len(ps) == 1:
1609 pars = [nodeids[ps[0]], None]
1610 pars = [nodeids[ps[0]], None]
1610 else:
1611 else:
1611 pars = [nodeids[p] for p in ps]
1612 pars = [nodeids[p] for p in ps]
1612 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1613 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1613 date=(id, 0),
1614 date=(id, 0),
1614 user="debugbuilddag",
1615 user="debugbuilddag",
1615 extra={'branch': atbranch})
1616 extra={'branch': atbranch})
1616 nodeid = repo.commitctx(cx)
1617 nodeid = repo.commitctx(cx)
1617 nodeids.append(nodeid)
1618 nodeids.append(nodeid)
1618 at = id
1619 at = id
1619 elif type == 'l':
1620 elif type == 'l':
1620 id, name = data
1621 id, name = data
1621 ui.note(('tag %s\n' % name))
1622 ui.note(('tag %s\n' % name))
1622 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1623 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1623 elif type == 'a':
1624 elif type == 'a':
1624 ui.note(('branch %s\n' % data))
1625 ui.note(('branch %s\n' % data))
1625 atbranch = data
1626 atbranch = data
1626 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1627 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1627 tr.close()
1628 tr.close()
1628
1629
1629 if tags:
1630 if tags:
1630 repo.opener.write("localtags", "".join(tags))
1631 repo.opener.write("localtags", "".join(tags))
1631 finally:
1632 finally:
1632 ui.progress(_('building'), None)
1633 ui.progress(_('building'), None)
1633 release(tr, lock)
1634 release(tr, lock)
1634
1635
1635 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1636 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1636 def debugbundle(ui, bundlepath, all=None, **opts):
1637 def debugbundle(ui, bundlepath, all=None, **opts):
1637 """lists the contents of a bundle"""
1638 """lists the contents of a bundle"""
1638 f = hg.openpath(ui, bundlepath)
1639 f = hg.openpath(ui, bundlepath)
1639 try:
1640 try:
1640 gen = changegroup.readbundle(f, bundlepath)
1641 gen = changegroup.readbundle(f, bundlepath)
1641 if all:
1642 if all:
1642 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1643 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1643
1644
1644 def showchunks(named):
1645 def showchunks(named):
1645 ui.write("\n%s\n" % named)
1646 ui.write("\n%s\n" % named)
1646 chain = None
1647 chain = None
1647 while True:
1648 while True:
1648 chunkdata = gen.deltachunk(chain)
1649 chunkdata = gen.deltachunk(chain)
1649 if not chunkdata:
1650 if not chunkdata:
1650 break
1651 break
1651 node = chunkdata['node']
1652 node = chunkdata['node']
1652 p1 = chunkdata['p1']
1653 p1 = chunkdata['p1']
1653 p2 = chunkdata['p2']
1654 p2 = chunkdata['p2']
1654 cs = chunkdata['cs']
1655 cs = chunkdata['cs']
1655 deltabase = chunkdata['deltabase']
1656 deltabase = chunkdata['deltabase']
1656 delta = chunkdata['delta']
1657 delta = chunkdata['delta']
1657 ui.write("%s %s %s %s %s %s\n" %
1658 ui.write("%s %s %s %s %s %s\n" %
1658 (hex(node), hex(p1), hex(p2),
1659 (hex(node), hex(p1), hex(p2),
1659 hex(cs), hex(deltabase), len(delta)))
1660 hex(cs), hex(deltabase), len(delta)))
1660 chain = node
1661 chain = node
1661
1662
1662 chunkdata = gen.changelogheader()
1663 chunkdata = gen.changelogheader()
1663 showchunks("changelog")
1664 showchunks("changelog")
1664 chunkdata = gen.manifestheader()
1665 chunkdata = gen.manifestheader()
1665 showchunks("manifest")
1666 showchunks("manifest")
1666 while True:
1667 while True:
1667 chunkdata = gen.filelogheader()
1668 chunkdata = gen.filelogheader()
1668 if not chunkdata:
1669 if not chunkdata:
1669 break
1670 break
1670 fname = chunkdata['filename']
1671 fname = chunkdata['filename']
1671 showchunks(fname)
1672 showchunks(fname)
1672 else:
1673 else:
1673 chunkdata = gen.changelogheader()
1674 chunkdata = gen.changelogheader()
1674 chain = None
1675 chain = None
1675 while True:
1676 while True:
1676 chunkdata = gen.deltachunk(chain)
1677 chunkdata = gen.deltachunk(chain)
1677 if not chunkdata:
1678 if not chunkdata:
1678 break
1679 break
1679 node = chunkdata['node']
1680 node = chunkdata['node']
1680 ui.write("%s\n" % hex(node))
1681 ui.write("%s\n" % hex(node))
1681 chain = node
1682 chain = node
1682 finally:
1683 finally:
1683 f.close()
1684 f.close()
1684
1685
1685 @command('debugcheckstate', [], '')
1686 @command('debugcheckstate', [], '')
1686 def debugcheckstate(ui, repo):
1687 def debugcheckstate(ui, repo):
1687 """validate the correctness of the current dirstate"""
1688 """validate the correctness of the current dirstate"""
1688 parent1, parent2 = repo.dirstate.parents()
1689 parent1, parent2 = repo.dirstate.parents()
1689 m1 = repo[parent1].manifest()
1690 m1 = repo[parent1].manifest()
1690 m2 = repo[parent2].manifest()
1691 m2 = repo[parent2].manifest()
1691 errors = 0
1692 errors = 0
1692 for f in repo.dirstate:
1693 for f in repo.dirstate:
1693 state = repo.dirstate[f]
1694 state = repo.dirstate[f]
1694 if state in "nr" and f not in m1:
1695 if state in "nr" and f not in m1:
1695 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1696 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1696 errors += 1
1697 errors += 1
1697 if state in "a" and f in m1:
1698 if state in "a" and f in m1:
1698 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1699 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1699 errors += 1
1700 errors += 1
1700 if state in "m" and f not in m1 and f not in m2:
1701 if state in "m" and f not in m1 and f not in m2:
1701 ui.warn(_("%s in state %s, but not in either manifest\n") %
1702 ui.warn(_("%s in state %s, but not in either manifest\n") %
1702 (f, state))
1703 (f, state))
1703 errors += 1
1704 errors += 1
1704 for f in m1:
1705 for f in m1:
1705 state = repo.dirstate[f]
1706 state = repo.dirstate[f]
1706 if state not in "nrm":
1707 if state not in "nrm":
1707 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1708 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1708 errors += 1
1709 errors += 1
1709 if errors:
1710 if errors:
1710 error = _(".hg/dirstate inconsistent with current parent's manifest")
1711 error = _(".hg/dirstate inconsistent with current parent's manifest")
1711 raise util.Abort(error)
1712 raise util.Abort(error)
1712
1713
1713 @command('debugcommands', [], _('[COMMAND]'))
1714 @command('debugcommands', [], _('[COMMAND]'))
1714 def debugcommands(ui, cmd='', *args):
1715 def debugcommands(ui, cmd='', *args):
1715 """list all available commands and options"""
1716 """list all available commands and options"""
1716 for cmd, vals in sorted(table.iteritems()):
1717 for cmd, vals in sorted(table.iteritems()):
1717 cmd = cmd.split('|')[0].strip('^')
1718 cmd = cmd.split('|')[0].strip('^')
1718 opts = ', '.join([i[1] for i in vals[1]])
1719 opts = ', '.join([i[1] for i in vals[1]])
1719 ui.write('%s: %s\n' % (cmd, opts))
1720 ui.write('%s: %s\n' % (cmd, opts))
1720
1721
1721 @command('debugcomplete',
1722 @command('debugcomplete',
1722 [('o', 'options', None, _('show the command options'))],
1723 [('o', 'options', None, _('show the command options'))],
1723 _('[-o] CMD'))
1724 _('[-o] CMD'))
1724 def debugcomplete(ui, cmd='', **opts):
1725 def debugcomplete(ui, cmd='', **opts):
1725 """returns the completion list associated with the given command"""
1726 """returns the completion list associated with the given command"""
1726
1727
1727 if opts.get('options'):
1728 if opts.get('options'):
1728 options = []
1729 options = []
1729 otables = [globalopts]
1730 otables = [globalopts]
1730 if cmd:
1731 if cmd:
1731 aliases, entry = cmdutil.findcmd(cmd, table, False)
1732 aliases, entry = cmdutil.findcmd(cmd, table, False)
1732 otables.append(entry[1])
1733 otables.append(entry[1])
1733 for t in otables:
1734 for t in otables:
1734 for o in t:
1735 for o in t:
1735 if "(DEPRECATED)" in o[3]:
1736 if "(DEPRECATED)" in o[3]:
1736 continue
1737 continue
1737 if o[0]:
1738 if o[0]:
1738 options.append('-%s' % o[0])
1739 options.append('-%s' % o[0])
1739 options.append('--%s' % o[1])
1740 options.append('--%s' % o[1])
1740 ui.write("%s\n" % "\n".join(options))
1741 ui.write("%s\n" % "\n".join(options))
1741 return
1742 return
1742
1743
1743 cmdlist = cmdutil.findpossible(cmd, table)
1744 cmdlist = cmdutil.findpossible(cmd, table)
1744 if ui.verbose:
1745 if ui.verbose:
1745 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1746 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1746 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1747 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1747
1748
1748 @command('debugdag',
1749 @command('debugdag',
1749 [('t', 'tags', None, _('use tags as labels')),
1750 [('t', 'tags', None, _('use tags as labels')),
1750 ('b', 'branches', None, _('annotate with branch names')),
1751 ('b', 'branches', None, _('annotate with branch names')),
1751 ('', 'dots', None, _('use dots for runs')),
1752 ('', 'dots', None, _('use dots for runs')),
1752 ('s', 'spaces', None, _('separate elements by spaces'))],
1753 ('s', 'spaces', None, _('separate elements by spaces'))],
1753 _('[OPTION]... [FILE [REV]...]'))
1754 _('[OPTION]... [FILE [REV]...]'))
1754 def debugdag(ui, repo, file_=None, *revs, **opts):
1755 def debugdag(ui, repo, file_=None, *revs, **opts):
1755 """format the changelog or an index DAG as a concise textual description
1756 """format the changelog or an index DAG as a concise textual description
1756
1757
1757 If you pass a revlog index, the revlog's DAG is emitted. If you list
1758 If you pass a revlog index, the revlog's DAG is emitted. If you list
1758 revision numbers, they get labeled in the output as rN.
1759 revision numbers, they get labeled in the output as rN.
1759
1760
1760 Otherwise, the changelog DAG of the current repo is emitted.
1761 Otherwise, the changelog DAG of the current repo is emitted.
1761 """
1762 """
1762 spaces = opts.get('spaces')
1763 spaces = opts.get('spaces')
1763 dots = opts.get('dots')
1764 dots = opts.get('dots')
1764 if file_:
1765 if file_:
1765 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1766 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1766 revs = set((int(r) for r in revs))
1767 revs = set((int(r) for r in revs))
1767 def events():
1768 def events():
1768 for r in rlog:
1769 for r in rlog:
1769 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1770 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1770 if p != -1)))
1771 if p != -1)))
1771 if r in revs:
1772 if r in revs:
1772 yield 'l', (r, "r%i" % r)
1773 yield 'l', (r, "r%i" % r)
1773 elif repo:
1774 elif repo:
1774 cl = repo.changelog
1775 cl = repo.changelog
1775 tags = opts.get('tags')
1776 tags = opts.get('tags')
1776 branches = opts.get('branches')
1777 branches = opts.get('branches')
1777 if tags:
1778 if tags:
1778 labels = {}
1779 labels = {}
1779 for l, n in repo.tags().items():
1780 for l, n in repo.tags().items():
1780 labels.setdefault(cl.rev(n), []).append(l)
1781 labels.setdefault(cl.rev(n), []).append(l)
1781 def events():
1782 def events():
1782 b = "default"
1783 b = "default"
1783 for r in cl:
1784 for r in cl:
1784 if branches:
1785 if branches:
1785 newb = cl.read(cl.node(r))[5]['branch']
1786 newb = cl.read(cl.node(r))[5]['branch']
1786 if newb != b:
1787 if newb != b:
1787 yield 'a', newb
1788 yield 'a', newb
1788 b = newb
1789 b = newb
1789 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1790 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1790 if p != -1)))
1791 if p != -1)))
1791 if tags:
1792 if tags:
1792 ls = labels.get(r)
1793 ls = labels.get(r)
1793 if ls:
1794 if ls:
1794 for l in ls:
1795 for l in ls:
1795 yield 'l', (r, l)
1796 yield 'l', (r, l)
1796 else:
1797 else:
1797 raise util.Abort(_('need repo for changelog dag'))
1798 raise util.Abort(_('need repo for changelog dag'))
1798
1799
1799 for line in dagparser.dagtextlines(events(),
1800 for line in dagparser.dagtextlines(events(),
1800 addspaces=spaces,
1801 addspaces=spaces,
1801 wraplabels=True,
1802 wraplabels=True,
1802 wrapannotations=True,
1803 wrapannotations=True,
1803 wrapnonlinear=dots,
1804 wrapnonlinear=dots,
1804 usedots=dots,
1805 usedots=dots,
1805 maxlinewidth=70):
1806 maxlinewidth=70):
1806 ui.write(line)
1807 ui.write(line)
1807 ui.write("\n")
1808 ui.write("\n")
1808
1809
1809 @command('debugdata',
1810 @command('debugdata',
1810 [('c', 'changelog', False, _('open changelog')),
1811 [('c', 'changelog', False, _('open changelog')),
1811 ('m', 'manifest', False, _('open manifest'))],
1812 ('m', 'manifest', False, _('open manifest'))],
1812 _('-c|-m|FILE REV'))
1813 _('-c|-m|FILE REV'))
1813 def debugdata(ui, repo, file_, rev=None, **opts):
1814 def debugdata(ui, repo, file_, rev=None, **opts):
1814 """dump the contents of a data file revision"""
1815 """dump the contents of a data file revision"""
1815 if opts.get('changelog') or opts.get('manifest'):
1816 if opts.get('changelog') or opts.get('manifest'):
1816 file_, rev = None, file_
1817 file_, rev = None, file_
1817 elif rev is None:
1818 elif rev is None:
1818 raise error.CommandError('debugdata', _('invalid arguments'))
1819 raise error.CommandError('debugdata', _('invalid arguments'))
1819 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1820 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1820 try:
1821 try:
1821 ui.write(r.revision(r.lookup(rev)))
1822 ui.write(r.revision(r.lookup(rev)))
1822 except KeyError:
1823 except KeyError:
1823 raise util.Abort(_('invalid revision identifier %s') % rev)
1824 raise util.Abort(_('invalid revision identifier %s') % rev)
1824
1825
1825 @command('debugdate',
1826 @command('debugdate',
1826 [('e', 'extended', None, _('try extended date formats'))],
1827 [('e', 'extended', None, _('try extended date formats'))],
1827 _('[-e] DATE [RANGE]'))
1828 _('[-e] DATE [RANGE]'))
1828 def debugdate(ui, date, range=None, **opts):
1829 def debugdate(ui, date, range=None, **opts):
1829 """parse and display a date"""
1830 """parse and display a date"""
1830 if opts["extended"]:
1831 if opts["extended"]:
1831 d = util.parsedate(date, util.extendeddateformats)
1832 d = util.parsedate(date, util.extendeddateformats)
1832 else:
1833 else:
1833 d = util.parsedate(date)
1834 d = util.parsedate(date)
1834 ui.write(("internal: %s %s\n") % d)
1835 ui.write(("internal: %s %s\n") % d)
1835 ui.write(("standard: %s\n") % util.datestr(d))
1836 ui.write(("standard: %s\n") % util.datestr(d))
1836 if range:
1837 if range:
1837 m = util.matchdate(range)
1838 m = util.matchdate(range)
1838 ui.write(("match: %s\n") % m(d[0]))
1839 ui.write(("match: %s\n") % m(d[0]))
1839
1840
1840 @command('debugdiscovery',
1841 @command('debugdiscovery',
1841 [('', 'old', None, _('use old-style discovery')),
1842 [('', 'old', None, _('use old-style discovery')),
1842 ('', 'nonheads', None,
1843 ('', 'nonheads', None,
1843 _('use old-style discovery with non-heads included')),
1844 _('use old-style discovery with non-heads included')),
1844 ] + remoteopts,
1845 ] + remoteopts,
1845 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1846 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1846 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1847 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1847 """runs the changeset discovery protocol in isolation"""
1848 """runs the changeset discovery protocol in isolation"""
1848 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1849 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1849 opts.get('branch'))
1850 opts.get('branch'))
1850 remote = hg.peer(repo, opts, remoteurl)
1851 remote = hg.peer(repo, opts, remoteurl)
1851 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1852 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1852
1853
1853 # make sure tests are repeatable
1854 # make sure tests are repeatable
1854 random.seed(12323)
1855 random.seed(12323)
1855
1856
1856 def doit(localheads, remoteheads, remote=remote):
1857 def doit(localheads, remoteheads, remote=remote):
1857 if opts.get('old'):
1858 if opts.get('old'):
1858 if localheads:
1859 if localheads:
1859 raise util.Abort('cannot use localheads with old style '
1860 raise util.Abort('cannot use localheads with old style '
1860 'discovery')
1861 'discovery')
1861 if not util.safehasattr(remote, 'branches'):
1862 if not util.safehasattr(remote, 'branches'):
1862 # enable in-client legacy support
1863 # enable in-client legacy support
1863 remote = localrepo.locallegacypeer(remote.local())
1864 remote = localrepo.locallegacypeer(remote.local())
1864 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1865 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1865 force=True)
1866 force=True)
1866 common = set(common)
1867 common = set(common)
1867 if not opts.get('nonheads'):
1868 if not opts.get('nonheads'):
1868 ui.write(("unpruned common: %s\n") %
1869 ui.write(("unpruned common: %s\n") %
1869 " ".join(sorted(short(n) for n in common)))
1870 " ".join(sorted(short(n) for n in common)))
1870 dag = dagutil.revlogdag(repo.changelog)
1871 dag = dagutil.revlogdag(repo.changelog)
1871 all = dag.ancestorset(dag.internalizeall(common))
1872 all = dag.ancestorset(dag.internalizeall(common))
1872 common = dag.externalizeall(dag.headsetofconnecteds(all))
1873 common = dag.externalizeall(dag.headsetofconnecteds(all))
1873 else:
1874 else:
1874 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1875 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1875 common = set(common)
1876 common = set(common)
1876 rheads = set(hds)
1877 rheads = set(hds)
1877 lheads = set(repo.heads())
1878 lheads = set(repo.heads())
1878 ui.write(("common heads: %s\n") %
1879 ui.write(("common heads: %s\n") %
1879 " ".join(sorted(short(n) for n in common)))
1880 " ".join(sorted(short(n) for n in common)))
1880 if lheads <= common:
1881 if lheads <= common:
1881 ui.write(("local is subset\n"))
1882 ui.write(("local is subset\n"))
1882 elif rheads <= common:
1883 elif rheads <= common:
1883 ui.write(("remote is subset\n"))
1884 ui.write(("remote is subset\n"))
1884
1885
1885 serverlogs = opts.get('serverlog')
1886 serverlogs = opts.get('serverlog')
1886 if serverlogs:
1887 if serverlogs:
1887 for filename in serverlogs:
1888 for filename in serverlogs:
1888 logfile = open(filename, 'r')
1889 logfile = open(filename, 'r')
1889 try:
1890 try:
1890 line = logfile.readline()
1891 line = logfile.readline()
1891 while line:
1892 while line:
1892 parts = line.strip().split(';')
1893 parts = line.strip().split(';')
1893 op = parts[1]
1894 op = parts[1]
1894 if op == 'cg':
1895 if op == 'cg':
1895 pass
1896 pass
1896 elif op == 'cgss':
1897 elif op == 'cgss':
1897 doit(parts[2].split(' '), parts[3].split(' '))
1898 doit(parts[2].split(' '), parts[3].split(' '))
1898 elif op == 'unb':
1899 elif op == 'unb':
1899 doit(parts[3].split(' '), parts[2].split(' '))
1900 doit(parts[3].split(' '), parts[2].split(' '))
1900 line = logfile.readline()
1901 line = logfile.readline()
1901 finally:
1902 finally:
1902 logfile.close()
1903 logfile.close()
1903
1904
1904 else:
1905 else:
1905 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1906 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1906 opts.get('remote_head'))
1907 opts.get('remote_head'))
1907 localrevs = opts.get('local_head')
1908 localrevs = opts.get('local_head')
1908 doit(localrevs, remoterevs)
1909 doit(localrevs, remoterevs)
1909
1910
1910 @command('debugfileset',
1911 @command('debugfileset',
1911 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1912 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1912 _('[-r REV] FILESPEC'))
1913 _('[-r REV] FILESPEC'))
1913 def debugfileset(ui, repo, expr, **opts):
1914 def debugfileset(ui, repo, expr, **opts):
1914 '''parse and apply a fileset specification'''
1915 '''parse and apply a fileset specification'''
1915 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1916 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1916 if ui.verbose:
1917 if ui.verbose:
1917 tree = fileset.parse(expr)[0]
1918 tree = fileset.parse(expr)[0]
1918 ui.note(tree, "\n")
1919 ui.note(tree, "\n")
1919
1920
1920 for f in fileset.getfileset(ctx, expr):
1921 for f in fileset.getfileset(ctx, expr):
1921 ui.write("%s\n" % f)
1922 ui.write("%s\n" % f)
1922
1923
1923 @command('debugfsinfo', [], _('[PATH]'))
1924 @command('debugfsinfo', [], _('[PATH]'))
1924 def debugfsinfo(ui, path="."):
1925 def debugfsinfo(ui, path="."):
1925 """show information detected about current filesystem"""
1926 """show information detected about current filesystem"""
1926 util.writefile('.debugfsinfo', '')
1927 util.writefile('.debugfsinfo', '')
1927 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1928 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1928 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1929 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1929 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
1930 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
1930 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1931 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1931 and 'yes' or 'no'))
1932 and 'yes' or 'no'))
1932 os.unlink('.debugfsinfo')
1933 os.unlink('.debugfsinfo')
1933
1934
1934 @command('debuggetbundle',
1935 @command('debuggetbundle',
1935 [('H', 'head', [], _('id of head node'), _('ID')),
1936 [('H', 'head', [], _('id of head node'), _('ID')),
1936 ('C', 'common', [], _('id of common node'), _('ID')),
1937 ('C', 'common', [], _('id of common node'), _('ID')),
1937 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1938 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1938 _('REPO FILE [-H|-C ID]...'))
1939 _('REPO FILE [-H|-C ID]...'))
1939 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1940 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1940 """retrieves a bundle from a repo
1941 """retrieves a bundle from a repo
1941
1942
1942 Every ID must be a full-length hex node id string. Saves the bundle to the
1943 Every ID must be a full-length hex node id string. Saves the bundle to the
1943 given file.
1944 given file.
1944 """
1945 """
1945 repo = hg.peer(ui, opts, repopath)
1946 repo = hg.peer(ui, opts, repopath)
1946 if not repo.capable('getbundle'):
1947 if not repo.capable('getbundle'):
1947 raise util.Abort("getbundle() not supported by target repository")
1948 raise util.Abort("getbundle() not supported by target repository")
1948 args = {}
1949 args = {}
1949 if common:
1950 if common:
1950 args['common'] = [bin(s) for s in common]
1951 args['common'] = [bin(s) for s in common]
1951 if head:
1952 if head:
1952 args['heads'] = [bin(s) for s in head]
1953 args['heads'] = [bin(s) for s in head]
1953 # TODO: get desired bundlecaps from command line.
1954 # TODO: get desired bundlecaps from command line.
1954 args['bundlecaps'] = None
1955 args['bundlecaps'] = None
1955 bundle = repo.getbundle('debug', **args)
1956 bundle = repo.getbundle('debug', **args)
1956
1957
1957 bundletype = opts.get('type', 'bzip2').lower()
1958 bundletype = opts.get('type', 'bzip2').lower()
1958 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1959 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1959 bundletype = btypes.get(bundletype)
1960 bundletype = btypes.get(bundletype)
1960 if bundletype not in changegroup.bundletypes:
1961 if bundletype not in changegroup.bundletypes:
1961 raise util.Abort(_('unknown bundle type specified with --type'))
1962 raise util.Abort(_('unknown bundle type specified with --type'))
1962 changegroup.writebundle(bundle, bundlepath, bundletype)
1963 changegroup.writebundle(bundle, bundlepath, bundletype)
1963
1964
1964 @command('debugignore', [], '')
1965 @command('debugignore', [], '')
1965 def debugignore(ui, repo, *values, **opts):
1966 def debugignore(ui, repo, *values, **opts):
1966 """display the combined ignore pattern"""
1967 """display the combined ignore pattern"""
1967 ignore = repo.dirstate._ignore
1968 ignore = repo.dirstate._ignore
1968 includepat = getattr(ignore, 'includepat', None)
1969 includepat = getattr(ignore, 'includepat', None)
1969 if includepat is not None:
1970 if includepat is not None:
1970 ui.write("%s\n" % includepat)
1971 ui.write("%s\n" % includepat)
1971 else:
1972 else:
1972 raise util.Abort(_("no ignore patterns found"))
1973 raise util.Abort(_("no ignore patterns found"))
1973
1974
1974 @command('debugindex',
1975 @command('debugindex',
1975 [('c', 'changelog', False, _('open changelog')),
1976 [('c', 'changelog', False, _('open changelog')),
1976 ('m', 'manifest', False, _('open manifest')),
1977 ('m', 'manifest', False, _('open manifest')),
1977 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1978 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1978 _('[-f FORMAT] -c|-m|FILE'))
1979 _('[-f FORMAT] -c|-m|FILE'))
1979 def debugindex(ui, repo, file_=None, **opts):
1980 def debugindex(ui, repo, file_=None, **opts):
1980 """dump the contents of an index file"""
1981 """dump the contents of an index file"""
1981 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1982 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1982 format = opts.get('format', 0)
1983 format = opts.get('format', 0)
1983 if format not in (0, 1):
1984 if format not in (0, 1):
1984 raise util.Abort(_("unknown format %d") % format)
1985 raise util.Abort(_("unknown format %d") % format)
1985
1986
1986 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1987 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1987 if generaldelta:
1988 if generaldelta:
1988 basehdr = ' delta'
1989 basehdr = ' delta'
1989 else:
1990 else:
1990 basehdr = ' base'
1991 basehdr = ' base'
1991
1992
1992 if format == 0:
1993 if format == 0:
1993 ui.write(" rev offset length " + basehdr + " linkrev"
1994 ui.write(" rev offset length " + basehdr + " linkrev"
1994 " nodeid p1 p2\n")
1995 " nodeid p1 p2\n")
1995 elif format == 1:
1996 elif format == 1:
1996 ui.write(" rev flag offset length"
1997 ui.write(" rev flag offset length"
1997 " size " + basehdr + " link p1 p2"
1998 " size " + basehdr + " link p1 p2"
1998 " nodeid\n")
1999 " nodeid\n")
1999
2000
2000 for i in r:
2001 for i in r:
2001 node = r.node(i)
2002 node = r.node(i)
2002 if generaldelta:
2003 if generaldelta:
2003 base = r.deltaparent(i)
2004 base = r.deltaparent(i)
2004 else:
2005 else:
2005 base = r.chainbase(i)
2006 base = r.chainbase(i)
2006 if format == 0:
2007 if format == 0:
2007 try:
2008 try:
2008 pp = r.parents(node)
2009 pp = r.parents(node)
2009 except Exception:
2010 except Exception:
2010 pp = [nullid, nullid]
2011 pp = [nullid, nullid]
2011 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2012 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2012 i, r.start(i), r.length(i), base, r.linkrev(i),
2013 i, r.start(i), r.length(i), base, r.linkrev(i),
2013 short(node), short(pp[0]), short(pp[1])))
2014 short(node), short(pp[0]), short(pp[1])))
2014 elif format == 1:
2015 elif format == 1:
2015 pr = r.parentrevs(i)
2016 pr = r.parentrevs(i)
2016 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2017 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2017 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2018 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2018 base, r.linkrev(i), pr[0], pr[1], short(node)))
2019 base, r.linkrev(i), pr[0], pr[1], short(node)))
2019
2020
2020 @command('debugindexdot', [], _('FILE'))
2021 @command('debugindexdot', [], _('FILE'))
2021 def debugindexdot(ui, repo, file_):
2022 def debugindexdot(ui, repo, file_):
2022 """dump an index DAG as a graphviz dot file"""
2023 """dump an index DAG as a graphviz dot file"""
2023 r = None
2024 r = None
2024 if repo:
2025 if repo:
2025 filelog = repo.file(file_)
2026 filelog = repo.file(file_)
2026 if len(filelog):
2027 if len(filelog):
2027 r = filelog
2028 r = filelog
2028 if not r:
2029 if not r:
2029 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2030 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2030 ui.write(("digraph G {\n"))
2031 ui.write(("digraph G {\n"))
2031 for i in r:
2032 for i in r:
2032 node = r.node(i)
2033 node = r.node(i)
2033 pp = r.parents(node)
2034 pp = r.parents(node)
2034 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2035 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2035 if pp[1] != nullid:
2036 if pp[1] != nullid:
2036 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2037 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2037 ui.write("}\n")
2038 ui.write("}\n")
2038
2039
2039 @command('debuginstall', [], '')
2040 @command('debuginstall', [], '')
2040 def debuginstall(ui):
2041 def debuginstall(ui):
2041 '''test Mercurial installation
2042 '''test Mercurial installation
2042
2043
2043 Returns 0 on success.
2044 Returns 0 on success.
2044 '''
2045 '''
2045
2046
2046 def writetemp(contents):
2047 def writetemp(contents):
2047 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2048 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2048 f = os.fdopen(fd, "wb")
2049 f = os.fdopen(fd, "wb")
2049 f.write(contents)
2050 f.write(contents)
2050 f.close()
2051 f.close()
2051 return name
2052 return name
2052
2053
2053 problems = 0
2054 problems = 0
2054
2055
2055 # encoding
2056 # encoding
2056 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2057 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2057 try:
2058 try:
2058 encoding.fromlocal("test")
2059 encoding.fromlocal("test")
2059 except util.Abort, inst:
2060 except util.Abort, inst:
2060 ui.write(" %s\n" % inst)
2061 ui.write(" %s\n" % inst)
2061 ui.write(_(" (check that your locale is properly set)\n"))
2062 ui.write(_(" (check that your locale is properly set)\n"))
2062 problems += 1
2063 problems += 1
2063
2064
2064 # Python lib
2065 # Python lib
2065 ui.status(_("checking Python lib (%s)...\n")
2066 ui.status(_("checking Python lib (%s)...\n")
2066 % os.path.dirname(os.__file__))
2067 % os.path.dirname(os.__file__))
2067
2068
2068 # compiled modules
2069 # compiled modules
2069 ui.status(_("checking installed modules (%s)...\n")
2070 ui.status(_("checking installed modules (%s)...\n")
2070 % os.path.dirname(__file__))
2071 % os.path.dirname(__file__))
2071 try:
2072 try:
2072 import bdiff, mpatch, base85, osutil
2073 import bdiff, mpatch, base85, osutil
2073 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2074 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2074 except Exception, inst:
2075 except Exception, inst:
2075 ui.write(" %s\n" % inst)
2076 ui.write(" %s\n" % inst)
2076 ui.write(_(" One or more extensions could not be found"))
2077 ui.write(_(" One or more extensions could not be found"))
2077 ui.write(_(" (check that you compiled the extensions)\n"))
2078 ui.write(_(" (check that you compiled the extensions)\n"))
2078 problems += 1
2079 problems += 1
2079
2080
2080 # templates
2081 # templates
2081 import templater
2082 import templater
2082 p = templater.templatepath()
2083 p = templater.templatepath()
2083 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2084 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2084 try:
2085 try:
2085 templater.templater(templater.templatepath("map-cmdline.default"))
2086 templater.templater(templater.templatepath("map-cmdline.default"))
2086 except Exception, inst:
2087 except Exception, inst:
2087 ui.write(" %s\n" % inst)
2088 ui.write(" %s\n" % inst)
2088 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2089 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2089 problems += 1
2090 problems += 1
2090
2091
2091 # editor
2092 # editor
2092 ui.status(_("checking commit editor...\n"))
2093 ui.status(_("checking commit editor...\n"))
2093 editor = ui.geteditor()
2094 editor = ui.geteditor()
2094 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2095 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2095 if not cmdpath:
2096 if not cmdpath:
2096 if editor == 'vi':
2097 if editor == 'vi':
2097 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2098 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2098 ui.write(_(" (specify a commit editor in your configuration"
2099 ui.write(_(" (specify a commit editor in your configuration"
2099 " file)\n"))
2100 " file)\n"))
2100 else:
2101 else:
2101 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2102 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2102 ui.write(_(" (specify a commit editor in your configuration"
2103 ui.write(_(" (specify a commit editor in your configuration"
2103 " file)\n"))
2104 " file)\n"))
2104 problems += 1
2105 problems += 1
2105
2106
2106 # check username
2107 # check username
2107 ui.status(_("checking username...\n"))
2108 ui.status(_("checking username...\n"))
2108 try:
2109 try:
2109 ui.username()
2110 ui.username()
2110 except util.Abort, e:
2111 except util.Abort, e:
2111 ui.write(" %s\n" % e)
2112 ui.write(" %s\n" % e)
2112 ui.write(_(" (specify a username in your configuration file)\n"))
2113 ui.write(_(" (specify a username in your configuration file)\n"))
2113 problems += 1
2114 problems += 1
2114
2115
2115 if not problems:
2116 if not problems:
2116 ui.status(_("no problems detected\n"))
2117 ui.status(_("no problems detected\n"))
2117 else:
2118 else:
2118 ui.write(_("%s problems detected,"
2119 ui.write(_("%s problems detected,"
2119 " please check your install!\n") % problems)
2120 " please check your install!\n") % problems)
2120
2121
2121 return problems
2122 return problems
2122
2123
2123 @command('debugknown', [], _('REPO ID...'))
2124 @command('debugknown', [], _('REPO ID...'))
2124 def debugknown(ui, repopath, *ids, **opts):
2125 def debugknown(ui, repopath, *ids, **opts):
2125 """test whether node ids are known to a repo
2126 """test whether node ids are known to a repo
2126
2127
2127 Every ID must be a full-length hex node id string. Returns a list of 0s
2128 Every ID must be a full-length hex node id string. Returns a list of 0s
2128 and 1s indicating unknown/known.
2129 and 1s indicating unknown/known.
2129 """
2130 """
2130 repo = hg.peer(ui, opts, repopath)
2131 repo = hg.peer(ui, opts, repopath)
2131 if not repo.capable('known'):
2132 if not repo.capable('known'):
2132 raise util.Abort("known() not supported by target repository")
2133 raise util.Abort("known() not supported by target repository")
2133 flags = repo.known([bin(s) for s in ids])
2134 flags = repo.known([bin(s) for s in ids])
2134 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2135 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2135
2136
2136 @command('debuglabelcomplete', [], _('LABEL...'))
2137 @command('debuglabelcomplete', [], _('LABEL...'))
2137 def debuglabelcomplete(ui, repo, *args):
2138 def debuglabelcomplete(ui, repo, *args):
2138 '''complete "labels" - tags, open branch names, bookmark names'''
2139 '''complete "labels" - tags, open branch names, bookmark names'''
2139
2140
2140 labels = set()
2141 labels = set()
2141 labels.update(t[0] for t in repo.tagslist())
2142 labels.update(t[0] for t in repo.tagslist())
2142 labels.update(repo._bookmarks.keys())
2143 labels.update(repo._bookmarks.keys())
2143 labels.update(tag for (tag, heads, tip, closed)
2144 labels.update(tag for (tag, heads, tip, closed)
2144 in repo.branchmap().iterbranches() if not closed)
2145 in repo.branchmap().iterbranches() if not closed)
2145 completions = set()
2146 completions = set()
2146 if not args:
2147 if not args:
2147 args = ['']
2148 args = ['']
2148 for a in args:
2149 for a in args:
2149 completions.update(l for l in labels if l.startswith(a))
2150 completions.update(l for l in labels if l.startswith(a))
2150 ui.write('\n'.join(sorted(completions)))
2151 ui.write('\n'.join(sorted(completions)))
2151 ui.write('\n')
2152 ui.write('\n')
2152
2153
2153 @command('debugobsolete',
2154 @command('debugobsolete',
2154 [('', 'flags', 0, _('markers flag')),
2155 [('', 'flags', 0, _('markers flag')),
2155 ] + commitopts2,
2156 ] + commitopts2,
2156 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2157 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2157 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2158 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2158 """create arbitrary obsolete marker
2159 """create arbitrary obsolete marker
2159
2160
2160 With no arguments, displays the list of obsolescence markers."""
2161 With no arguments, displays the list of obsolescence markers."""
2161 def parsenodeid(s):
2162 def parsenodeid(s):
2162 try:
2163 try:
2163 # We do not use revsingle/revrange functions here to accept
2164 # We do not use revsingle/revrange functions here to accept
2164 # arbitrary node identifiers, possibly not present in the
2165 # arbitrary node identifiers, possibly not present in the
2165 # local repository.
2166 # local repository.
2166 n = bin(s)
2167 n = bin(s)
2167 if len(n) != len(nullid):
2168 if len(n) != len(nullid):
2168 raise TypeError()
2169 raise TypeError()
2169 return n
2170 return n
2170 except TypeError:
2171 except TypeError:
2171 raise util.Abort('changeset references must be full hexadecimal '
2172 raise util.Abort('changeset references must be full hexadecimal '
2172 'node identifiers')
2173 'node identifiers')
2173
2174
2174 if precursor is not None:
2175 if precursor is not None:
2175 metadata = {}
2176 metadata = {}
2176 if 'date' in opts:
2177 if 'date' in opts:
2177 metadata['date'] = opts['date']
2178 metadata['date'] = opts['date']
2178 metadata['user'] = opts['user'] or ui.username()
2179 metadata['user'] = opts['user'] or ui.username()
2179 succs = tuple(parsenodeid(succ) for succ in successors)
2180 succs = tuple(parsenodeid(succ) for succ in successors)
2180 l = repo.lock()
2181 l = repo.lock()
2181 try:
2182 try:
2182 tr = repo.transaction('debugobsolete')
2183 tr = repo.transaction('debugobsolete')
2183 try:
2184 try:
2184 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2185 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2185 opts['flags'], metadata)
2186 opts['flags'], metadata)
2186 tr.close()
2187 tr.close()
2187 finally:
2188 finally:
2188 tr.release()
2189 tr.release()
2189 finally:
2190 finally:
2190 l.release()
2191 l.release()
2191 else:
2192 else:
2192 for m in obsolete.allmarkers(repo):
2193 for m in obsolete.allmarkers(repo):
2193 ui.write(hex(m.precnode()))
2194 ui.write(hex(m.precnode()))
2194 for repl in m.succnodes():
2195 for repl in m.succnodes():
2195 ui.write(' ')
2196 ui.write(' ')
2196 ui.write(hex(repl))
2197 ui.write(hex(repl))
2197 ui.write(' %X ' % m._data[2])
2198 ui.write(' %X ' % m._data[2])
2198 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2199 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2199 sorted(m.metadata().items()))))
2200 sorted(m.metadata().items()))))
2200 ui.write('\n')
2201 ui.write('\n')
2201
2202
2202 @command('debugpathcomplete',
2203 @command('debugpathcomplete',
2203 [('f', 'full', None, _('complete an entire path')),
2204 [('f', 'full', None, _('complete an entire path')),
2204 ('n', 'normal', None, _('show only normal files')),
2205 ('n', 'normal', None, _('show only normal files')),
2205 ('a', 'added', None, _('show only added files')),
2206 ('a', 'added', None, _('show only added files')),
2206 ('r', 'removed', None, _('show only removed files'))],
2207 ('r', 'removed', None, _('show only removed files'))],
2207 _('FILESPEC...'))
2208 _('FILESPEC...'))
2208 def debugpathcomplete(ui, repo, *specs, **opts):
2209 def debugpathcomplete(ui, repo, *specs, **opts):
2209 '''complete part or all of a tracked path
2210 '''complete part or all of a tracked path
2210
2211
2211 This command supports shells that offer path name completion. It
2212 This command supports shells that offer path name completion. It
2212 currently completes only files already known to the dirstate.
2213 currently completes only files already known to the dirstate.
2213
2214
2214 Completion extends only to the next path segment unless
2215 Completion extends only to the next path segment unless
2215 --full is specified, in which case entire paths are used.'''
2216 --full is specified, in which case entire paths are used.'''
2216
2217
2217 def complete(path, acceptable):
2218 def complete(path, acceptable):
2218 dirstate = repo.dirstate
2219 dirstate = repo.dirstate
2219 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2220 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2220 rootdir = repo.root + os.sep
2221 rootdir = repo.root + os.sep
2221 if spec != repo.root and not spec.startswith(rootdir):
2222 if spec != repo.root and not spec.startswith(rootdir):
2222 return [], []
2223 return [], []
2223 if os.path.isdir(spec):
2224 if os.path.isdir(spec):
2224 spec += '/'
2225 spec += '/'
2225 spec = spec[len(rootdir):]
2226 spec = spec[len(rootdir):]
2226 fixpaths = os.sep != '/'
2227 fixpaths = os.sep != '/'
2227 if fixpaths:
2228 if fixpaths:
2228 spec = spec.replace(os.sep, '/')
2229 spec = spec.replace(os.sep, '/')
2229 speclen = len(spec)
2230 speclen = len(spec)
2230 fullpaths = opts['full']
2231 fullpaths = opts['full']
2231 files, dirs = set(), set()
2232 files, dirs = set(), set()
2232 adddir, addfile = dirs.add, files.add
2233 adddir, addfile = dirs.add, files.add
2233 for f, st in dirstate.iteritems():
2234 for f, st in dirstate.iteritems():
2234 if f.startswith(spec) and st[0] in acceptable:
2235 if f.startswith(spec) and st[0] in acceptable:
2235 if fixpaths:
2236 if fixpaths:
2236 f = f.replace('/', os.sep)
2237 f = f.replace('/', os.sep)
2237 if fullpaths:
2238 if fullpaths:
2238 addfile(f)
2239 addfile(f)
2239 continue
2240 continue
2240 s = f.find(os.sep, speclen)
2241 s = f.find(os.sep, speclen)
2241 if s >= 0:
2242 if s >= 0:
2242 adddir(f[:s])
2243 adddir(f[:s])
2243 else:
2244 else:
2244 addfile(f)
2245 addfile(f)
2245 return files, dirs
2246 return files, dirs
2246
2247
2247 acceptable = ''
2248 acceptable = ''
2248 if opts['normal']:
2249 if opts['normal']:
2249 acceptable += 'nm'
2250 acceptable += 'nm'
2250 if opts['added']:
2251 if opts['added']:
2251 acceptable += 'a'
2252 acceptable += 'a'
2252 if opts['removed']:
2253 if opts['removed']:
2253 acceptable += 'r'
2254 acceptable += 'r'
2254 cwd = repo.getcwd()
2255 cwd = repo.getcwd()
2255 if not specs:
2256 if not specs:
2256 specs = ['.']
2257 specs = ['.']
2257
2258
2258 files, dirs = set(), set()
2259 files, dirs = set(), set()
2259 for spec in specs:
2260 for spec in specs:
2260 f, d = complete(spec, acceptable or 'nmar')
2261 f, d = complete(spec, acceptable or 'nmar')
2261 files.update(f)
2262 files.update(f)
2262 dirs.update(d)
2263 dirs.update(d)
2263 files.update(dirs)
2264 files.update(dirs)
2264 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2265 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2265 ui.write('\n')
2266 ui.write('\n')
2266
2267
2267 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2268 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2268 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2269 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2269 '''access the pushkey key/value protocol
2270 '''access the pushkey key/value protocol
2270
2271
2271 With two args, list the keys in the given namespace.
2272 With two args, list the keys in the given namespace.
2272
2273
2273 With five args, set a key to new if it currently is set to old.
2274 With five args, set a key to new if it currently is set to old.
2274 Reports success or failure.
2275 Reports success or failure.
2275 '''
2276 '''
2276
2277
2277 target = hg.peer(ui, {}, repopath)
2278 target = hg.peer(ui, {}, repopath)
2278 if keyinfo:
2279 if keyinfo:
2279 key, old, new = keyinfo
2280 key, old, new = keyinfo
2280 r = target.pushkey(namespace, key, old, new)
2281 r = target.pushkey(namespace, key, old, new)
2281 ui.status(str(r) + '\n')
2282 ui.status(str(r) + '\n')
2282 return not r
2283 return not r
2283 else:
2284 else:
2284 for k, v in sorted(target.listkeys(namespace).iteritems()):
2285 for k, v in sorted(target.listkeys(namespace).iteritems()):
2285 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2286 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2286 v.encode('string-escape')))
2287 v.encode('string-escape')))
2287
2288
2288 @command('debugpvec', [], _('A B'))
2289 @command('debugpvec', [], _('A B'))
2289 def debugpvec(ui, repo, a, b=None):
2290 def debugpvec(ui, repo, a, b=None):
2290 ca = scmutil.revsingle(repo, a)
2291 ca = scmutil.revsingle(repo, a)
2291 cb = scmutil.revsingle(repo, b)
2292 cb = scmutil.revsingle(repo, b)
2292 pa = pvec.ctxpvec(ca)
2293 pa = pvec.ctxpvec(ca)
2293 pb = pvec.ctxpvec(cb)
2294 pb = pvec.ctxpvec(cb)
2294 if pa == pb:
2295 if pa == pb:
2295 rel = "="
2296 rel = "="
2296 elif pa > pb:
2297 elif pa > pb:
2297 rel = ">"
2298 rel = ">"
2298 elif pa < pb:
2299 elif pa < pb:
2299 rel = "<"
2300 rel = "<"
2300 elif pa | pb:
2301 elif pa | pb:
2301 rel = "|"
2302 rel = "|"
2302 ui.write(_("a: %s\n") % pa)
2303 ui.write(_("a: %s\n") % pa)
2303 ui.write(_("b: %s\n") % pb)
2304 ui.write(_("b: %s\n") % pb)
2304 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2305 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2305 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2306 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2306 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2307 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2307 pa.distance(pb), rel))
2308 pa.distance(pb), rel))
2308
2309
2309 @command('debugrebuilddirstate|debugrebuildstate',
2310 @command('debugrebuilddirstate|debugrebuildstate',
2310 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2311 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2311 _('[-r REV]'))
2312 _('[-r REV]'))
2312 def debugrebuilddirstate(ui, repo, rev):
2313 def debugrebuilddirstate(ui, repo, rev):
2313 """rebuild the dirstate as it would look like for the given revision
2314 """rebuild the dirstate as it would look like for the given revision
2314
2315
2315 If no revision is specified the first current parent will be used.
2316 If no revision is specified the first current parent will be used.
2316
2317
2317 The dirstate will be set to the files of the given revision.
2318 The dirstate will be set to the files of the given revision.
2318 The actual working directory content or existing dirstate
2319 The actual working directory content or existing dirstate
2319 information such as adds or removes is not considered.
2320 information such as adds or removes is not considered.
2320
2321
2321 One use of this command is to make the next :hg:`status` invocation
2322 One use of this command is to make the next :hg:`status` invocation
2322 check the actual file content.
2323 check the actual file content.
2323 """
2324 """
2324 ctx = scmutil.revsingle(repo, rev)
2325 ctx = scmutil.revsingle(repo, rev)
2325 wlock = repo.wlock()
2326 wlock = repo.wlock()
2326 try:
2327 try:
2327 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2328 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2328 finally:
2329 finally:
2329 wlock.release()
2330 wlock.release()
2330
2331
2331 @command('debugrename',
2332 @command('debugrename',
2332 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2333 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2333 _('[-r REV] FILE'))
2334 _('[-r REV] FILE'))
2334 def debugrename(ui, repo, file1, *pats, **opts):
2335 def debugrename(ui, repo, file1, *pats, **opts):
2335 """dump rename information"""
2336 """dump rename information"""
2336
2337
2337 ctx = scmutil.revsingle(repo, opts.get('rev'))
2338 ctx = scmutil.revsingle(repo, opts.get('rev'))
2338 m = scmutil.match(ctx, (file1,) + pats, opts)
2339 m = scmutil.match(ctx, (file1,) + pats, opts)
2339 for abs in ctx.walk(m):
2340 for abs in ctx.walk(m):
2340 fctx = ctx[abs]
2341 fctx = ctx[abs]
2341 o = fctx.filelog().renamed(fctx.filenode())
2342 o = fctx.filelog().renamed(fctx.filenode())
2342 rel = m.rel(abs)
2343 rel = m.rel(abs)
2343 if o:
2344 if o:
2344 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2345 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2345 else:
2346 else:
2346 ui.write(_("%s not renamed\n") % rel)
2347 ui.write(_("%s not renamed\n") % rel)
2347
2348
2348 @command('debugrevlog',
2349 @command('debugrevlog',
2349 [('c', 'changelog', False, _('open changelog')),
2350 [('c', 'changelog', False, _('open changelog')),
2350 ('m', 'manifest', False, _('open manifest')),
2351 ('m', 'manifest', False, _('open manifest')),
2351 ('d', 'dump', False, _('dump index data'))],
2352 ('d', 'dump', False, _('dump index data'))],
2352 _('-c|-m|FILE'))
2353 _('-c|-m|FILE'))
2353 def debugrevlog(ui, repo, file_=None, **opts):
2354 def debugrevlog(ui, repo, file_=None, **opts):
2354 """show data and statistics about a revlog"""
2355 """show data and statistics about a revlog"""
2355 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2356 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2356
2357
2357 if opts.get("dump"):
2358 if opts.get("dump"):
2358 numrevs = len(r)
2359 numrevs = len(r)
2359 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2360 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2360 " rawsize totalsize compression heads\n")
2361 " rawsize totalsize compression heads\n")
2361 ts = 0
2362 ts = 0
2362 heads = set()
2363 heads = set()
2363 for rev in xrange(numrevs):
2364 for rev in xrange(numrevs):
2364 dbase = r.deltaparent(rev)
2365 dbase = r.deltaparent(rev)
2365 if dbase == -1:
2366 if dbase == -1:
2366 dbase = rev
2367 dbase = rev
2367 cbase = r.chainbase(rev)
2368 cbase = r.chainbase(rev)
2368 p1, p2 = r.parentrevs(rev)
2369 p1, p2 = r.parentrevs(rev)
2369 rs = r.rawsize(rev)
2370 rs = r.rawsize(rev)
2370 ts = ts + rs
2371 ts = ts + rs
2371 heads -= set(r.parentrevs(rev))
2372 heads -= set(r.parentrevs(rev))
2372 heads.add(rev)
2373 heads.add(rev)
2373 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2374 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2374 (rev, p1, p2, r.start(rev), r.end(rev),
2375 (rev, p1, p2, r.start(rev), r.end(rev),
2375 r.start(dbase), r.start(cbase),
2376 r.start(dbase), r.start(cbase),
2376 r.start(p1), r.start(p2),
2377 r.start(p1), r.start(p2),
2377 rs, ts, ts / r.end(rev), len(heads)))
2378 rs, ts, ts / r.end(rev), len(heads)))
2378 return 0
2379 return 0
2379
2380
2380 v = r.version
2381 v = r.version
2381 format = v & 0xFFFF
2382 format = v & 0xFFFF
2382 flags = []
2383 flags = []
2383 gdelta = False
2384 gdelta = False
2384 if v & revlog.REVLOGNGINLINEDATA:
2385 if v & revlog.REVLOGNGINLINEDATA:
2385 flags.append('inline')
2386 flags.append('inline')
2386 if v & revlog.REVLOGGENERALDELTA:
2387 if v & revlog.REVLOGGENERALDELTA:
2387 gdelta = True
2388 gdelta = True
2388 flags.append('generaldelta')
2389 flags.append('generaldelta')
2389 if not flags:
2390 if not flags:
2390 flags = ['(none)']
2391 flags = ['(none)']
2391
2392
2392 nummerges = 0
2393 nummerges = 0
2393 numfull = 0
2394 numfull = 0
2394 numprev = 0
2395 numprev = 0
2395 nump1 = 0
2396 nump1 = 0
2396 nump2 = 0
2397 nump2 = 0
2397 numother = 0
2398 numother = 0
2398 nump1prev = 0
2399 nump1prev = 0
2399 nump2prev = 0
2400 nump2prev = 0
2400 chainlengths = []
2401 chainlengths = []
2401
2402
2402 datasize = [None, 0, 0L]
2403 datasize = [None, 0, 0L]
2403 fullsize = [None, 0, 0L]
2404 fullsize = [None, 0, 0L]
2404 deltasize = [None, 0, 0L]
2405 deltasize = [None, 0, 0L]
2405
2406
2406 def addsize(size, l):
2407 def addsize(size, l):
2407 if l[0] is None or size < l[0]:
2408 if l[0] is None or size < l[0]:
2408 l[0] = size
2409 l[0] = size
2409 if size > l[1]:
2410 if size > l[1]:
2410 l[1] = size
2411 l[1] = size
2411 l[2] += size
2412 l[2] += size
2412
2413
2413 numrevs = len(r)
2414 numrevs = len(r)
2414 for rev in xrange(numrevs):
2415 for rev in xrange(numrevs):
2415 p1, p2 = r.parentrevs(rev)
2416 p1, p2 = r.parentrevs(rev)
2416 delta = r.deltaparent(rev)
2417 delta = r.deltaparent(rev)
2417 if format > 0:
2418 if format > 0:
2418 addsize(r.rawsize(rev), datasize)
2419 addsize(r.rawsize(rev), datasize)
2419 if p2 != nullrev:
2420 if p2 != nullrev:
2420 nummerges += 1
2421 nummerges += 1
2421 size = r.length(rev)
2422 size = r.length(rev)
2422 if delta == nullrev:
2423 if delta == nullrev:
2423 chainlengths.append(0)
2424 chainlengths.append(0)
2424 numfull += 1
2425 numfull += 1
2425 addsize(size, fullsize)
2426 addsize(size, fullsize)
2426 else:
2427 else:
2427 chainlengths.append(chainlengths[delta] + 1)
2428 chainlengths.append(chainlengths[delta] + 1)
2428 addsize(size, deltasize)
2429 addsize(size, deltasize)
2429 if delta == rev - 1:
2430 if delta == rev - 1:
2430 numprev += 1
2431 numprev += 1
2431 if delta == p1:
2432 if delta == p1:
2432 nump1prev += 1
2433 nump1prev += 1
2433 elif delta == p2:
2434 elif delta == p2:
2434 nump2prev += 1
2435 nump2prev += 1
2435 elif delta == p1:
2436 elif delta == p1:
2436 nump1 += 1
2437 nump1 += 1
2437 elif delta == p2:
2438 elif delta == p2:
2438 nump2 += 1
2439 nump2 += 1
2439 elif delta != nullrev:
2440 elif delta != nullrev:
2440 numother += 1
2441 numother += 1
2441
2442
2442 # Adjust size min value for empty cases
2443 # Adjust size min value for empty cases
2443 for size in (datasize, fullsize, deltasize):
2444 for size in (datasize, fullsize, deltasize):
2444 if size[0] is None:
2445 if size[0] is None:
2445 size[0] = 0
2446 size[0] = 0
2446
2447
2447 numdeltas = numrevs - numfull
2448 numdeltas = numrevs - numfull
2448 numoprev = numprev - nump1prev - nump2prev
2449 numoprev = numprev - nump1prev - nump2prev
2449 totalrawsize = datasize[2]
2450 totalrawsize = datasize[2]
2450 datasize[2] /= numrevs
2451 datasize[2] /= numrevs
2451 fulltotal = fullsize[2]
2452 fulltotal = fullsize[2]
2452 fullsize[2] /= numfull
2453 fullsize[2] /= numfull
2453 deltatotal = deltasize[2]
2454 deltatotal = deltasize[2]
2454 if numrevs - numfull > 0:
2455 if numrevs - numfull > 0:
2455 deltasize[2] /= numrevs - numfull
2456 deltasize[2] /= numrevs - numfull
2456 totalsize = fulltotal + deltatotal
2457 totalsize = fulltotal + deltatotal
2457 avgchainlen = sum(chainlengths) / numrevs
2458 avgchainlen = sum(chainlengths) / numrevs
2458 compratio = totalrawsize / totalsize
2459 compratio = totalrawsize / totalsize
2459
2460
2460 basedfmtstr = '%%%dd\n'
2461 basedfmtstr = '%%%dd\n'
2461 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2462 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2462
2463
2463 def dfmtstr(max):
2464 def dfmtstr(max):
2464 return basedfmtstr % len(str(max))
2465 return basedfmtstr % len(str(max))
2465 def pcfmtstr(max, padding=0):
2466 def pcfmtstr(max, padding=0):
2466 return basepcfmtstr % (len(str(max)), ' ' * padding)
2467 return basepcfmtstr % (len(str(max)), ' ' * padding)
2467
2468
2468 def pcfmt(value, total):
2469 def pcfmt(value, total):
2469 return (value, 100 * float(value) / total)
2470 return (value, 100 * float(value) / total)
2470
2471
2471 ui.write(('format : %d\n') % format)
2472 ui.write(('format : %d\n') % format)
2472 ui.write(('flags : %s\n') % ', '.join(flags))
2473 ui.write(('flags : %s\n') % ', '.join(flags))
2473
2474
2474 ui.write('\n')
2475 ui.write('\n')
2475 fmt = pcfmtstr(totalsize)
2476 fmt = pcfmtstr(totalsize)
2476 fmt2 = dfmtstr(totalsize)
2477 fmt2 = dfmtstr(totalsize)
2477 ui.write(('revisions : ') + fmt2 % numrevs)
2478 ui.write(('revisions : ') + fmt2 % numrevs)
2478 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2479 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2479 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2480 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2480 ui.write(('revisions : ') + fmt2 % numrevs)
2481 ui.write(('revisions : ') + fmt2 % numrevs)
2481 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2482 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2482 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2483 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2483 ui.write(('revision size : ') + fmt2 % totalsize)
2484 ui.write(('revision size : ') + fmt2 % totalsize)
2484 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2485 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2485 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2486 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2486
2487
2487 ui.write('\n')
2488 ui.write('\n')
2488 fmt = dfmtstr(max(avgchainlen, compratio))
2489 fmt = dfmtstr(max(avgchainlen, compratio))
2489 ui.write(('avg chain length : ') + fmt % avgchainlen)
2490 ui.write(('avg chain length : ') + fmt % avgchainlen)
2490 ui.write(('compression ratio : ') + fmt % compratio)
2491 ui.write(('compression ratio : ') + fmt % compratio)
2491
2492
2492 if format > 0:
2493 if format > 0:
2493 ui.write('\n')
2494 ui.write('\n')
2494 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2495 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2495 % tuple(datasize))
2496 % tuple(datasize))
2496 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2497 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2497 % tuple(fullsize))
2498 % tuple(fullsize))
2498 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2499 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2499 % tuple(deltasize))
2500 % tuple(deltasize))
2500
2501
2501 if numdeltas > 0:
2502 if numdeltas > 0:
2502 ui.write('\n')
2503 ui.write('\n')
2503 fmt = pcfmtstr(numdeltas)
2504 fmt = pcfmtstr(numdeltas)
2504 fmt2 = pcfmtstr(numdeltas, 4)
2505 fmt2 = pcfmtstr(numdeltas, 4)
2505 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2506 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2506 if numprev > 0:
2507 if numprev > 0:
2507 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2508 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2508 numprev))
2509 numprev))
2509 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2510 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2510 numprev))
2511 numprev))
2511 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2512 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2512 numprev))
2513 numprev))
2513 if gdelta:
2514 if gdelta:
2514 ui.write(('deltas against p1 : ')
2515 ui.write(('deltas against p1 : ')
2515 + fmt % pcfmt(nump1, numdeltas))
2516 + fmt % pcfmt(nump1, numdeltas))
2516 ui.write(('deltas against p2 : ')
2517 ui.write(('deltas against p2 : ')
2517 + fmt % pcfmt(nump2, numdeltas))
2518 + fmt % pcfmt(nump2, numdeltas))
2518 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2519 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2519 numdeltas))
2520 numdeltas))
2520
2521
2521 @command('debugrevspec', [], ('REVSPEC'))
2522 @command('debugrevspec', [], ('REVSPEC'))
2522 def debugrevspec(ui, repo, expr):
2523 def debugrevspec(ui, repo, expr):
2523 """parse and apply a revision specification
2524 """parse and apply a revision specification
2524
2525
2525 Use --verbose to print the parsed tree before and after aliases
2526 Use --verbose to print the parsed tree before and after aliases
2526 expansion.
2527 expansion.
2527 """
2528 """
2528 if ui.verbose:
2529 if ui.verbose:
2529 tree = revset.parse(expr)[0]
2530 tree = revset.parse(expr)[0]
2530 ui.note(revset.prettyformat(tree), "\n")
2531 ui.note(revset.prettyformat(tree), "\n")
2531 newtree = revset.findaliases(ui, tree)
2532 newtree = revset.findaliases(ui, tree)
2532 if newtree != tree:
2533 if newtree != tree:
2533 ui.note(revset.prettyformat(newtree), "\n")
2534 ui.note(revset.prettyformat(newtree), "\n")
2534 func = revset.match(ui, expr)
2535 func = revset.match(ui, expr)
2535 for c in func(repo, range(len(repo))):
2536 for c in func(repo, range(len(repo))):
2536 ui.write("%s\n" % c)
2537 ui.write("%s\n" % c)
2537
2538
2538 @command('debugsetparents', [], _('REV1 [REV2]'))
2539 @command('debugsetparents', [], _('REV1 [REV2]'))
2539 def debugsetparents(ui, repo, rev1, rev2=None):
2540 def debugsetparents(ui, repo, rev1, rev2=None):
2540 """manually set the parents of the current working directory
2541 """manually set the parents of the current working directory
2541
2542
2542 This is useful for writing repository conversion tools, but should
2543 This is useful for writing repository conversion tools, but should
2543 be used with care.
2544 be used with care.
2544
2545
2545 Returns 0 on success.
2546 Returns 0 on success.
2546 """
2547 """
2547
2548
2548 r1 = scmutil.revsingle(repo, rev1).node()
2549 r1 = scmutil.revsingle(repo, rev1).node()
2549 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2550 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2550
2551
2551 wlock = repo.wlock()
2552 wlock = repo.wlock()
2552 try:
2553 try:
2553 repo.setparents(r1, r2)
2554 repo.setparents(r1, r2)
2554 finally:
2555 finally:
2555 wlock.release()
2556 wlock.release()
2556
2557
2557 @command('debugdirstate|debugstate',
2558 @command('debugdirstate|debugstate',
2558 [('', 'nodates', None, _('do not display the saved mtime')),
2559 [('', 'nodates', None, _('do not display the saved mtime')),
2559 ('', 'datesort', None, _('sort by saved mtime'))],
2560 ('', 'datesort', None, _('sort by saved mtime'))],
2560 _('[OPTION]...'))
2561 _('[OPTION]...'))
2561 def debugstate(ui, repo, nodates=None, datesort=None):
2562 def debugstate(ui, repo, nodates=None, datesort=None):
2562 """show the contents of the current dirstate"""
2563 """show the contents of the current dirstate"""
2563 timestr = ""
2564 timestr = ""
2564 showdate = not nodates
2565 showdate = not nodates
2565 if datesort:
2566 if datesort:
2566 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2567 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2567 else:
2568 else:
2568 keyfunc = None # sort by filename
2569 keyfunc = None # sort by filename
2569 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2570 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2570 if showdate:
2571 if showdate:
2571 if ent[3] == -1:
2572 if ent[3] == -1:
2572 # Pad or slice to locale representation
2573 # Pad or slice to locale representation
2573 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2574 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2574 time.localtime(0)))
2575 time.localtime(0)))
2575 timestr = 'unset'
2576 timestr = 'unset'
2576 timestr = (timestr[:locale_len] +
2577 timestr = (timestr[:locale_len] +
2577 ' ' * (locale_len - len(timestr)))
2578 ' ' * (locale_len - len(timestr)))
2578 else:
2579 else:
2579 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2580 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2580 time.localtime(ent[3]))
2581 time.localtime(ent[3]))
2581 if ent[1] & 020000:
2582 if ent[1] & 020000:
2582 mode = 'lnk'
2583 mode = 'lnk'
2583 else:
2584 else:
2584 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2585 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2585 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2586 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2586 for f in repo.dirstate.copies():
2587 for f in repo.dirstate.copies():
2587 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2588 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2588
2589
2589 @command('debugsub',
2590 @command('debugsub',
2590 [('r', 'rev', '',
2591 [('r', 'rev', '',
2591 _('revision to check'), _('REV'))],
2592 _('revision to check'), _('REV'))],
2592 _('[-r REV] [REV]'))
2593 _('[-r REV] [REV]'))
2593 def debugsub(ui, repo, rev=None):
2594 def debugsub(ui, repo, rev=None):
2594 ctx = scmutil.revsingle(repo, rev, None)
2595 ctx = scmutil.revsingle(repo, rev, None)
2595 for k, v in sorted(ctx.substate.items()):
2596 for k, v in sorted(ctx.substate.items()):
2596 ui.write(('path %s\n') % k)
2597 ui.write(('path %s\n') % k)
2597 ui.write((' source %s\n') % v[0])
2598 ui.write((' source %s\n') % v[0])
2598 ui.write((' revision %s\n') % v[1])
2599 ui.write((' revision %s\n') % v[1])
2599
2600
2600 @command('debugsuccessorssets',
2601 @command('debugsuccessorssets',
2601 [],
2602 [],
2602 _('[REV]'))
2603 _('[REV]'))
2603 def debugsuccessorssets(ui, repo, *revs):
2604 def debugsuccessorssets(ui, repo, *revs):
2604 """show set of successors for revision
2605 """show set of successors for revision
2605
2606
2606 A successors set of changeset A is a consistent group of revisions that
2607 A successors set of changeset A is a consistent group of revisions that
2607 succeed A. It contains non-obsolete changesets only.
2608 succeed A. It contains non-obsolete changesets only.
2608
2609
2609 In most cases a changeset A has a single successors set containing a single
2610 In most cases a changeset A has a single successors set containing a single
2610 successor (changeset A replaced by A').
2611 successor (changeset A replaced by A').
2611
2612
2612 A changeset that is made obsolete with no successors are called "pruned".
2613 A changeset that is made obsolete with no successors are called "pruned".
2613 Such changesets have no successors sets at all.
2614 Such changesets have no successors sets at all.
2614
2615
2615 A changeset that has been "split" will have a successors set containing
2616 A changeset that has been "split" will have a successors set containing
2616 more than one successor.
2617 more than one successor.
2617
2618
2618 A changeset that has been rewritten in multiple different ways is called
2619 A changeset that has been rewritten in multiple different ways is called
2619 "divergent". Such changesets have multiple successor sets (each of which
2620 "divergent". Such changesets have multiple successor sets (each of which
2620 may also be split, i.e. have multiple successors).
2621 may also be split, i.e. have multiple successors).
2621
2622
2622 Results are displayed as follows::
2623 Results are displayed as follows::
2623
2624
2624 <rev1>
2625 <rev1>
2625 <successors-1A>
2626 <successors-1A>
2626 <rev2>
2627 <rev2>
2627 <successors-2A>
2628 <successors-2A>
2628 <successors-2B1> <successors-2B2> <successors-2B3>
2629 <successors-2B1> <successors-2B2> <successors-2B3>
2629
2630
2630 Here rev2 has two possible (i.e. divergent) successors sets. The first
2631 Here rev2 has two possible (i.e. divergent) successors sets. The first
2631 holds one element, whereas the second holds three (i.e. the changeset has
2632 holds one element, whereas the second holds three (i.e. the changeset has
2632 been split).
2633 been split).
2633 """
2634 """
2634 # passed to successorssets caching computation from one call to another
2635 # passed to successorssets caching computation from one call to another
2635 cache = {}
2636 cache = {}
2636 ctx2str = str
2637 ctx2str = str
2637 node2str = short
2638 node2str = short
2638 if ui.debug():
2639 if ui.debug():
2639 def ctx2str(ctx):
2640 def ctx2str(ctx):
2640 return ctx.hex()
2641 return ctx.hex()
2641 node2str = hex
2642 node2str = hex
2642 for rev in scmutil.revrange(repo, revs):
2643 for rev in scmutil.revrange(repo, revs):
2643 ctx = repo[rev]
2644 ctx = repo[rev]
2644 ui.write('%s\n'% ctx2str(ctx))
2645 ui.write('%s\n'% ctx2str(ctx))
2645 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2646 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2646 if succsset:
2647 if succsset:
2647 ui.write(' ')
2648 ui.write(' ')
2648 ui.write(node2str(succsset[0]))
2649 ui.write(node2str(succsset[0]))
2649 for node in succsset[1:]:
2650 for node in succsset[1:]:
2650 ui.write(' ')
2651 ui.write(' ')
2651 ui.write(node2str(node))
2652 ui.write(node2str(node))
2652 ui.write('\n')
2653 ui.write('\n')
2653
2654
2654 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2655 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2655 def debugwalk(ui, repo, *pats, **opts):
2656 def debugwalk(ui, repo, *pats, **opts):
2656 """show how files match on given patterns"""
2657 """show how files match on given patterns"""
2657 m = scmutil.match(repo[None], pats, opts)
2658 m = scmutil.match(repo[None], pats, opts)
2658 items = list(repo.walk(m))
2659 items = list(repo.walk(m))
2659 if not items:
2660 if not items:
2660 return
2661 return
2661 f = lambda fn: fn
2662 f = lambda fn: fn
2662 if ui.configbool('ui', 'slash') and os.sep != '/':
2663 if ui.configbool('ui', 'slash') and os.sep != '/':
2663 f = lambda fn: util.normpath(fn)
2664 f = lambda fn: util.normpath(fn)
2664 fmt = 'f %%-%ds %%-%ds %%s' % (
2665 fmt = 'f %%-%ds %%-%ds %%s' % (
2665 max([len(abs) for abs in items]),
2666 max([len(abs) for abs in items]),
2666 max([len(m.rel(abs)) for abs in items]))
2667 max([len(m.rel(abs)) for abs in items]))
2667 for abs in items:
2668 for abs in items:
2668 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2669 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2669 ui.write("%s\n" % line.rstrip())
2670 ui.write("%s\n" % line.rstrip())
2670
2671
2671 @command('debugwireargs',
2672 @command('debugwireargs',
2672 [('', 'three', '', 'three'),
2673 [('', 'three', '', 'three'),
2673 ('', 'four', '', 'four'),
2674 ('', 'four', '', 'four'),
2674 ('', 'five', '', 'five'),
2675 ('', 'five', '', 'five'),
2675 ] + remoteopts,
2676 ] + remoteopts,
2676 _('REPO [OPTIONS]... [ONE [TWO]]'))
2677 _('REPO [OPTIONS]... [ONE [TWO]]'))
2677 def debugwireargs(ui, repopath, *vals, **opts):
2678 def debugwireargs(ui, repopath, *vals, **opts):
2678 repo = hg.peer(ui, opts, repopath)
2679 repo = hg.peer(ui, opts, repopath)
2679 for opt in remoteopts:
2680 for opt in remoteopts:
2680 del opts[opt[1]]
2681 del opts[opt[1]]
2681 args = {}
2682 args = {}
2682 for k, v in opts.iteritems():
2683 for k, v in opts.iteritems():
2683 if v:
2684 if v:
2684 args[k] = v
2685 args[k] = v
2685 # run twice to check that we don't mess up the stream for the next command
2686 # run twice to check that we don't mess up the stream for the next command
2686 res1 = repo.debugwireargs(*vals, **args)
2687 res1 = repo.debugwireargs(*vals, **args)
2687 res2 = repo.debugwireargs(*vals, **args)
2688 res2 = repo.debugwireargs(*vals, **args)
2688 ui.write("%s\n" % res1)
2689 ui.write("%s\n" % res1)
2689 if res1 != res2:
2690 if res1 != res2:
2690 ui.warn("%s\n" % res2)
2691 ui.warn("%s\n" % res2)
2691
2692
2692 @command('^diff',
2693 @command('^diff',
2693 [('r', 'rev', [], _('revision'), _('REV')),
2694 [('r', 'rev', [], _('revision'), _('REV')),
2694 ('c', 'change', '', _('change made by revision'), _('REV'))
2695 ('c', 'change', '', _('change made by revision'), _('REV'))
2695 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2696 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2696 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2697 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2697 def diff(ui, repo, *pats, **opts):
2698 def diff(ui, repo, *pats, **opts):
2698 """diff repository (or selected files)
2699 """diff repository (or selected files)
2699
2700
2700 Show differences between revisions for the specified files.
2701 Show differences between revisions for the specified files.
2701
2702
2702 Differences between files are shown using the unified diff format.
2703 Differences between files are shown using the unified diff format.
2703
2704
2704 .. note::
2705 .. note::
2705
2706
2706 diff may generate unexpected results for merges, as it will
2707 diff may generate unexpected results for merges, as it will
2707 default to comparing against the working directory's first
2708 default to comparing against the working directory's first
2708 parent changeset if no revisions are specified.
2709 parent changeset if no revisions are specified.
2709
2710
2710 When two revision arguments are given, then changes are shown
2711 When two revision arguments are given, then changes are shown
2711 between those revisions. If only one revision is specified then
2712 between those revisions. If only one revision is specified then
2712 that revision is compared to the working directory, and, when no
2713 that revision is compared to the working directory, and, when no
2713 revisions are specified, the working directory files are compared
2714 revisions are specified, the working directory files are compared
2714 to its parent.
2715 to its parent.
2715
2716
2716 Alternatively you can specify -c/--change with a revision to see
2717 Alternatively you can specify -c/--change with a revision to see
2717 the changes in that changeset relative to its first parent.
2718 the changes in that changeset relative to its first parent.
2718
2719
2719 Without the -a/--text option, diff will avoid generating diffs of
2720 Without the -a/--text option, diff will avoid generating diffs of
2720 files it detects as binary. With -a, diff will generate a diff
2721 files it detects as binary. With -a, diff will generate a diff
2721 anyway, probably with undesirable results.
2722 anyway, probably with undesirable results.
2722
2723
2723 Use the -g/--git option to generate diffs in the git extended diff
2724 Use the -g/--git option to generate diffs in the git extended diff
2724 format. For more information, read :hg:`help diffs`.
2725 format. For more information, read :hg:`help diffs`.
2725
2726
2726 .. container:: verbose
2727 .. container:: verbose
2727
2728
2728 Examples:
2729 Examples:
2729
2730
2730 - compare a file in the current working directory to its parent::
2731 - compare a file in the current working directory to its parent::
2731
2732
2732 hg diff foo.c
2733 hg diff foo.c
2733
2734
2734 - compare two historical versions of a directory, with rename info::
2735 - compare two historical versions of a directory, with rename info::
2735
2736
2736 hg diff --git -r 1.0:1.2 lib/
2737 hg diff --git -r 1.0:1.2 lib/
2737
2738
2738 - get change stats relative to the last change on some date::
2739 - get change stats relative to the last change on some date::
2739
2740
2740 hg diff --stat -r "date('may 2')"
2741 hg diff --stat -r "date('may 2')"
2741
2742
2742 - diff all newly-added files that contain a keyword::
2743 - diff all newly-added files that contain a keyword::
2743
2744
2744 hg diff "set:added() and grep(GNU)"
2745 hg diff "set:added() and grep(GNU)"
2745
2746
2746 - compare a revision and its parents::
2747 - compare a revision and its parents::
2747
2748
2748 hg diff -c 9353 # compare against first parent
2749 hg diff -c 9353 # compare against first parent
2749 hg diff -r 9353^:9353 # same using revset syntax
2750 hg diff -r 9353^:9353 # same using revset syntax
2750 hg diff -r 9353^2:9353 # compare against the second parent
2751 hg diff -r 9353^2:9353 # compare against the second parent
2751
2752
2752 Returns 0 on success.
2753 Returns 0 on success.
2753 """
2754 """
2754
2755
2755 revs = opts.get('rev')
2756 revs = opts.get('rev')
2756 change = opts.get('change')
2757 change = opts.get('change')
2757 stat = opts.get('stat')
2758 stat = opts.get('stat')
2758 reverse = opts.get('reverse')
2759 reverse = opts.get('reverse')
2759
2760
2760 if revs and change:
2761 if revs and change:
2761 msg = _('cannot specify --rev and --change at the same time')
2762 msg = _('cannot specify --rev and --change at the same time')
2762 raise util.Abort(msg)
2763 raise util.Abort(msg)
2763 elif change:
2764 elif change:
2764 node2 = scmutil.revsingle(repo, change, None).node()
2765 node2 = scmutil.revsingle(repo, change, None).node()
2765 node1 = repo[node2].p1().node()
2766 node1 = repo[node2].p1().node()
2766 else:
2767 else:
2767 node1, node2 = scmutil.revpair(repo, revs)
2768 node1, node2 = scmutil.revpair(repo, revs)
2768
2769
2769 if reverse:
2770 if reverse:
2770 node1, node2 = node2, node1
2771 node1, node2 = node2, node1
2771
2772
2772 diffopts = patch.diffopts(ui, opts)
2773 diffopts = patch.diffopts(ui, opts)
2773 m = scmutil.match(repo[node2], pats, opts)
2774 m = scmutil.match(repo[node2], pats, opts)
2774 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2775 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2775 listsubrepos=opts.get('subrepos'))
2776 listsubrepos=opts.get('subrepos'))
2776
2777
2777 @command('^export',
2778 @command('^export',
2778 [('o', 'output', '',
2779 [('o', 'output', '',
2779 _('print output to file with formatted name'), _('FORMAT')),
2780 _('print output to file with formatted name'), _('FORMAT')),
2780 ('', 'switch-parent', None, _('diff against the second parent')),
2781 ('', 'switch-parent', None, _('diff against the second parent')),
2781 ('r', 'rev', [], _('revisions to export'), _('REV')),
2782 ('r', 'rev', [], _('revisions to export'), _('REV')),
2782 ] + diffopts,
2783 ] + diffopts,
2783 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2784 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2784 def export(ui, repo, *changesets, **opts):
2785 def export(ui, repo, *changesets, **opts):
2785 """dump the header and diffs for one or more changesets
2786 """dump the header and diffs for one or more changesets
2786
2787
2787 Print the changeset header and diffs for one or more revisions.
2788 Print the changeset header and diffs for one or more revisions.
2788 If no revision is given, the parent of the working directory is used.
2789 If no revision is given, the parent of the working directory is used.
2789
2790
2790 The information shown in the changeset header is: author, date,
2791 The information shown in the changeset header is: author, date,
2791 branch name (if non-default), changeset hash, parent(s) and commit
2792 branch name (if non-default), changeset hash, parent(s) and commit
2792 comment.
2793 comment.
2793
2794
2794 .. note::
2795 .. note::
2795
2796
2796 export may generate unexpected diff output for merge
2797 export may generate unexpected diff output for merge
2797 changesets, as it will compare the merge changeset against its
2798 changesets, as it will compare the merge changeset against its
2798 first parent only.
2799 first parent only.
2799
2800
2800 Output may be to a file, in which case the name of the file is
2801 Output may be to a file, in which case the name of the file is
2801 given using a format string. The formatting rules are as follows:
2802 given using a format string. The formatting rules are as follows:
2802
2803
2803 :``%%``: literal "%" character
2804 :``%%``: literal "%" character
2804 :``%H``: changeset hash (40 hexadecimal digits)
2805 :``%H``: changeset hash (40 hexadecimal digits)
2805 :``%N``: number of patches being generated
2806 :``%N``: number of patches being generated
2806 :``%R``: changeset revision number
2807 :``%R``: changeset revision number
2807 :``%b``: basename of the exporting repository
2808 :``%b``: basename of the exporting repository
2808 :``%h``: short-form changeset hash (12 hexadecimal digits)
2809 :``%h``: short-form changeset hash (12 hexadecimal digits)
2809 :``%m``: first line of the commit message (only alphanumeric characters)
2810 :``%m``: first line of the commit message (only alphanumeric characters)
2810 :``%n``: zero-padded sequence number, starting at 1
2811 :``%n``: zero-padded sequence number, starting at 1
2811 :``%r``: zero-padded changeset revision number
2812 :``%r``: zero-padded changeset revision number
2812
2813
2813 Without the -a/--text option, export will avoid generating diffs
2814 Without the -a/--text option, export will avoid generating diffs
2814 of files it detects as binary. With -a, export will generate a
2815 of files it detects as binary. With -a, export will generate a
2815 diff anyway, probably with undesirable results.
2816 diff anyway, probably with undesirable results.
2816
2817
2817 Use the -g/--git option to generate diffs in the git extended diff
2818 Use the -g/--git option to generate diffs in the git extended diff
2818 format. See :hg:`help diffs` for more information.
2819 format. See :hg:`help diffs` for more information.
2819
2820
2820 With the --switch-parent option, the diff will be against the
2821 With the --switch-parent option, the diff will be against the
2821 second parent. It can be useful to review a merge.
2822 second parent. It can be useful to review a merge.
2822
2823
2823 .. container:: verbose
2824 .. container:: verbose
2824
2825
2825 Examples:
2826 Examples:
2826
2827
2827 - use export and import to transplant a bugfix to the current
2828 - use export and import to transplant a bugfix to the current
2828 branch::
2829 branch::
2829
2830
2830 hg export -r 9353 | hg import -
2831 hg export -r 9353 | hg import -
2831
2832
2832 - export all the changesets between two revisions to a file with
2833 - export all the changesets between two revisions to a file with
2833 rename information::
2834 rename information::
2834
2835
2835 hg export --git -r 123:150 > changes.txt
2836 hg export --git -r 123:150 > changes.txt
2836
2837
2837 - split outgoing changes into a series of patches with
2838 - split outgoing changes into a series of patches with
2838 descriptive names::
2839 descriptive names::
2839
2840
2840 hg export -r "outgoing()" -o "%n-%m.patch"
2841 hg export -r "outgoing()" -o "%n-%m.patch"
2841
2842
2842 Returns 0 on success.
2843 Returns 0 on success.
2843 """
2844 """
2844 changesets += tuple(opts.get('rev', []))
2845 changesets += tuple(opts.get('rev', []))
2845 if not changesets:
2846 if not changesets:
2846 changesets = ['.']
2847 changesets = ['.']
2847 revs = scmutil.revrange(repo, changesets)
2848 revs = scmutil.revrange(repo, changesets)
2848 if not revs:
2849 if not revs:
2849 raise util.Abort(_("export requires at least one changeset"))
2850 raise util.Abort(_("export requires at least one changeset"))
2850 if len(revs) > 1:
2851 if len(revs) > 1:
2851 ui.note(_('exporting patches:\n'))
2852 ui.note(_('exporting patches:\n'))
2852 else:
2853 else:
2853 ui.note(_('exporting patch:\n'))
2854 ui.note(_('exporting patch:\n'))
2854 cmdutil.export(repo, revs, template=opts.get('output'),
2855 cmdutil.export(repo, revs, template=opts.get('output'),
2855 switch_parent=opts.get('switch_parent'),
2856 switch_parent=opts.get('switch_parent'),
2856 opts=patch.diffopts(ui, opts))
2857 opts=patch.diffopts(ui, opts))
2857
2858
2858 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2859 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2859 def forget(ui, repo, *pats, **opts):
2860 def forget(ui, repo, *pats, **opts):
2860 """forget the specified files on the next commit
2861 """forget the specified files on the next commit
2861
2862
2862 Mark the specified files so they will no longer be tracked
2863 Mark the specified files so they will no longer be tracked
2863 after the next commit.
2864 after the next commit.
2864
2865
2865 This only removes files from the current branch, not from the
2866 This only removes files from the current branch, not from the
2866 entire project history, and it does not delete them from the
2867 entire project history, and it does not delete them from the
2867 working directory.
2868 working directory.
2868
2869
2869 To undo a forget before the next commit, see :hg:`add`.
2870 To undo a forget before the next commit, see :hg:`add`.
2870
2871
2871 .. container:: verbose
2872 .. container:: verbose
2872
2873
2873 Examples:
2874 Examples:
2874
2875
2875 - forget newly-added binary files::
2876 - forget newly-added binary files::
2876
2877
2877 hg forget "set:added() and binary()"
2878 hg forget "set:added() and binary()"
2878
2879
2879 - forget files that would be excluded by .hgignore::
2880 - forget files that would be excluded by .hgignore::
2880
2881
2881 hg forget "set:hgignore()"
2882 hg forget "set:hgignore()"
2882
2883
2883 Returns 0 on success.
2884 Returns 0 on success.
2884 """
2885 """
2885
2886
2886 if not pats:
2887 if not pats:
2887 raise util.Abort(_('no files specified'))
2888 raise util.Abort(_('no files specified'))
2888
2889
2889 m = scmutil.match(repo[None], pats, opts)
2890 m = scmutil.match(repo[None], pats, opts)
2890 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2891 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2891 return rejected and 1 or 0
2892 return rejected and 1 or 0
2892
2893
2893 @command(
2894 @command(
2894 'graft',
2895 'graft',
2895 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2896 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2896 ('c', 'continue', False, _('resume interrupted graft')),
2897 ('c', 'continue', False, _('resume interrupted graft')),
2897 ('e', 'edit', False, _('invoke editor on commit messages')),
2898 ('e', 'edit', False, _('invoke editor on commit messages')),
2898 ('', 'log', None, _('append graft info to log message')),
2899 ('', 'log', None, _('append graft info to log message')),
2899 ('D', 'currentdate', False,
2900 ('D', 'currentdate', False,
2900 _('record the current date as commit date')),
2901 _('record the current date as commit date')),
2901 ('U', 'currentuser', False,
2902 ('U', 'currentuser', False,
2902 _('record the current user as committer'), _('DATE'))]
2903 _('record the current user as committer'), _('DATE'))]
2903 + commitopts2 + mergetoolopts + dryrunopts,
2904 + commitopts2 + mergetoolopts + dryrunopts,
2904 _('[OPTION]... [-r] REV...'))
2905 _('[OPTION]... [-r] REV...'))
2905 def graft(ui, repo, *revs, **opts):
2906 def graft(ui, repo, *revs, **opts):
2906 '''copy changes from other branches onto the current branch
2907 '''copy changes from other branches onto the current branch
2907
2908
2908 This command uses Mercurial's merge logic to copy individual
2909 This command uses Mercurial's merge logic to copy individual
2909 changes from other branches without merging branches in the
2910 changes from other branches without merging branches in the
2910 history graph. This is sometimes known as 'backporting' or
2911 history graph. This is sometimes known as 'backporting' or
2911 'cherry-picking'. By default, graft will copy user, date, and
2912 'cherry-picking'. By default, graft will copy user, date, and
2912 description from the source changesets.
2913 description from the source changesets.
2913
2914
2914 Changesets that are ancestors of the current revision, that have
2915 Changesets that are ancestors of the current revision, that have
2915 already been grafted, or that are merges will be skipped.
2916 already been grafted, or that are merges will be skipped.
2916
2917
2917 If --log is specified, log messages will have a comment appended
2918 If --log is specified, log messages will have a comment appended
2918 of the form::
2919 of the form::
2919
2920
2920 (grafted from CHANGESETHASH)
2921 (grafted from CHANGESETHASH)
2921
2922
2922 If a graft merge results in conflicts, the graft process is
2923 If a graft merge results in conflicts, the graft process is
2923 interrupted so that the current merge can be manually resolved.
2924 interrupted so that the current merge can be manually resolved.
2924 Once all conflicts are addressed, the graft process can be
2925 Once all conflicts are addressed, the graft process can be
2925 continued with the -c/--continue option.
2926 continued with the -c/--continue option.
2926
2927
2927 .. note::
2928 .. note::
2928
2929
2929 The -c/--continue option does not reapply earlier options.
2930 The -c/--continue option does not reapply earlier options.
2930
2931
2931 .. container:: verbose
2932 .. container:: verbose
2932
2933
2933 Examples:
2934 Examples:
2934
2935
2935 - copy a single change to the stable branch and edit its description::
2936 - copy a single change to the stable branch and edit its description::
2936
2937
2937 hg update stable
2938 hg update stable
2938 hg graft --edit 9393
2939 hg graft --edit 9393
2939
2940
2940 - graft a range of changesets with one exception, updating dates::
2941 - graft a range of changesets with one exception, updating dates::
2941
2942
2942 hg graft -D "2085::2093 and not 2091"
2943 hg graft -D "2085::2093 and not 2091"
2943
2944
2944 - continue a graft after resolving conflicts::
2945 - continue a graft after resolving conflicts::
2945
2946
2946 hg graft -c
2947 hg graft -c
2947
2948
2948 - show the source of a grafted changeset::
2949 - show the source of a grafted changeset::
2949
2950
2950 hg log --debug -r .
2951 hg log --debug -r .
2951
2952
2952 Returns 0 on successful completion.
2953 Returns 0 on successful completion.
2953 '''
2954 '''
2954
2955
2955 revs = list(revs)
2956 revs = list(revs)
2956 revs.extend(opts['rev'])
2957 revs.extend(opts['rev'])
2957
2958
2958 if not opts.get('user') and opts.get('currentuser'):
2959 if not opts.get('user') and opts.get('currentuser'):
2959 opts['user'] = ui.username()
2960 opts['user'] = ui.username()
2960 if not opts.get('date') and opts.get('currentdate'):
2961 if not opts.get('date') and opts.get('currentdate'):
2961 opts['date'] = "%d %d" % util.makedate()
2962 opts['date'] = "%d %d" % util.makedate()
2962
2963
2963 editor = None
2964 editor = None
2964 if opts.get('edit'):
2965 if opts.get('edit'):
2965 editor = cmdutil.commitforceeditor
2966 editor = cmdutil.commitforceeditor
2966
2967
2967 cont = False
2968 cont = False
2968 if opts['continue']:
2969 if opts['continue']:
2969 cont = True
2970 cont = True
2970 if revs:
2971 if revs:
2971 raise util.Abort(_("can't specify --continue and revisions"))
2972 raise util.Abort(_("can't specify --continue and revisions"))
2972 # read in unfinished revisions
2973 # read in unfinished revisions
2973 try:
2974 try:
2974 nodes = repo.opener.read('graftstate').splitlines()
2975 nodes = repo.opener.read('graftstate').splitlines()
2975 revs = [repo[node].rev() for node in nodes]
2976 revs = [repo[node].rev() for node in nodes]
2976 except IOError, inst:
2977 except IOError, inst:
2977 if inst.errno != errno.ENOENT:
2978 if inst.errno != errno.ENOENT:
2978 raise
2979 raise
2979 raise util.Abort(_("no graft state found, can't continue"))
2980 raise util.Abort(_("no graft state found, can't continue"))
2980 else:
2981 else:
2981 cmdutil.checkunfinished(repo)
2982 cmdutil.checkunfinished(repo)
2982 cmdutil.bailifchanged(repo)
2983 cmdutil.bailifchanged(repo)
2983 if not revs:
2984 if not revs:
2984 raise util.Abort(_('no revisions specified'))
2985 raise util.Abort(_('no revisions specified'))
2985 revs = scmutil.revrange(repo, revs)
2986 revs = scmutil.revrange(repo, revs)
2986
2987
2987 # check for merges
2988 # check for merges
2988 for rev in repo.revs('%ld and merge()', revs):
2989 for rev in repo.revs('%ld and merge()', revs):
2989 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2990 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2990 revs.remove(rev)
2991 revs.remove(rev)
2991 if not revs:
2992 if not revs:
2992 return -1
2993 return -1
2993
2994
2994 # check for ancestors of dest branch
2995 # check for ancestors of dest branch
2995 crev = repo['.'].rev()
2996 crev = repo['.'].rev()
2996 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2997 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2997 # don't mutate while iterating, create a copy
2998 # don't mutate while iterating, create a copy
2998 for rev in list(revs):
2999 for rev in list(revs):
2999 if rev in ancestors:
3000 if rev in ancestors:
3000 ui.warn(_('skipping ancestor revision %s\n') % rev)
3001 ui.warn(_('skipping ancestor revision %s\n') % rev)
3001 revs.remove(rev)
3002 revs.remove(rev)
3002 if not revs:
3003 if not revs:
3003 return -1
3004 return -1
3004
3005
3005 # analyze revs for earlier grafts
3006 # analyze revs for earlier grafts
3006 ids = {}
3007 ids = {}
3007 for ctx in repo.set("%ld", revs):
3008 for ctx in repo.set("%ld", revs):
3008 ids[ctx.hex()] = ctx.rev()
3009 ids[ctx.hex()] = ctx.rev()
3009 n = ctx.extra().get('source')
3010 n = ctx.extra().get('source')
3010 if n:
3011 if n:
3011 ids[n] = ctx.rev()
3012 ids[n] = ctx.rev()
3012
3013
3013 # check ancestors for earlier grafts
3014 # check ancestors for earlier grafts
3014 ui.debug('scanning for duplicate grafts\n')
3015 ui.debug('scanning for duplicate grafts\n')
3015
3016
3016 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3017 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3017 ctx = repo[rev]
3018 ctx = repo[rev]
3018 n = ctx.extra().get('source')
3019 n = ctx.extra().get('source')
3019 if n in ids:
3020 if n in ids:
3020 r = repo[n].rev()
3021 r = repo[n].rev()
3021 if r in revs:
3022 if r in revs:
3022 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3023 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3023 % (r, rev))
3024 % (r, rev))
3024 revs.remove(r)
3025 revs.remove(r)
3025 elif ids[n] in revs:
3026 elif ids[n] in revs:
3026 ui.warn(_('skipping already grafted revision %s '
3027 ui.warn(_('skipping already grafted revision %s '
3027 '(%s also has origin %d)\n') % (ids[n], rev, r))
3028 '(%s also has origin %d)\n') % (ids[n], rev, r))
3028 revs.remove(ids[n])
3029 revs.remove(ids[n])
3029 elif ctx.hex() in ids:
3030 elif ctx.hex() in ids:
3030 r = ids[ctx.hex()]
3031 r = ids[ctx.hex()]
3031 ui.warn(_('skipping already grafted revision %s '
3032 ui.warn(_('skipping already grafted revision %s '
3032 '(was grafted from %d)\n') % (r, rev))
3033 '(was grafted from %d)\n') % (r, rev))
3033 revs.remove(r)
3034 revs.remove(r)
3034 if not revs:
3035 if not revs:
3035 return -1
3036 return -1
3036
3037
3037 wlock = repo.wlock()
3038 wlock = repo.wlock()
3038 try:
3039 try:
3039 current = repo['.']
3040 current = repo['.']
3040 for pos, ctx in enumerate(repo.set("%ld", revs)):
3041 for pos, ctx in enumerate(repo.set("%ld", revs)):
3041
3042
3042 ui.status(_('grafting revision %s\n') % ctx.rev())
3043 ui.status(_('grafting revision %s\n') % ctx.rev())
3043 if opts.get('dry_run'):
3044 if opts.get('dry_run'):
3044 continue
3045 continue
3045
3046
3046 source = ctx.extra().get('source')
3047 source = ctx.extra().get('source')
3047 if not source:
3048 if not source:
3048 source = ctx.hex()
3049 source = ctx.hex()
3049 extra = {'source': source}
3050 extra = {'source': source}
3050 user = ctx.user()
3051 user = ctx.user()
3051 if opts.get('user'):
3052 if opts.get('user'):
3052 user = opts['user']
3053 user = opts['user']
3053 date = ctx.date()
3054 date = ctx.date()
3054 if opts.get('date'):
3055 if opts.get('date'):
3055 date = opts['date']
3056 date = opts['date']
3056 message = ctx.description()
3057 message = ctx.description()
3057 if opts.get('log'):
3058 if opts.get('log'):
3058 message += '\n(grafted from %s)' % ctx.hex()
3059 message += '\n(grafted from %s)' % ctx.hex()
3059
3060
3060 # we don't merge the first commit when continuing
3061 # we don't merge the first commit when continuing
3061 if not cont:
3062 if not cont:
3062 # perform the graft merge with p1(rev) as 'ancestor'
3063 # perform the graft merge with p1(rev) as 'ancestor'
3063 try:
3064 try:
3064 # ui.forcemerge is an internal variable, do not document
3065 # ui.forcemerge is an internal variable, do not document
3065 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3066 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3066 stats = mergemod.update(repo, ctx.node(), True, True, False,
3067 stats = mergemod.update(repo, ctx.node(), True, True, False,
3067 ctx.p1().node())
3068 ctx.p1().node())
3068 finally:
3069 finally:
3069 repo.ui.setconfig('ui', 'forcemerge', '')
3070 repo.ui.setconfig('ui', 'forcemerge', '')
3070 # report any conflicts
3071 # report any conflicts
3071 if stats and stats[3] > 0:
3072 if stats and stats[3] > 0:
3072 # write out state for --continue
3073 # write out state for --continue
3073 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3074 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3074 repo.opener.write('graftstate', ''.join(nodelines))
3075 repo.opener.write('graftstate', ''.join(nodelines))
3075 raise util.Abort(
3076 raise util.Abort(
3076 _("unresolved conflicts, can't continue"),
3077 _("unresolved conflicts, can't continue"),
3077 hint=_('use hg resolve and hg graft --continue'))
3078 hint=_('use hg resolve and hg graft --continue'))
3078 else:
3079 else:
3079 cont = False
3080 cont = False
3080
3081
3081 # drop the second merge parent
3082 # drop the second merge parent
3082 repo.setparents(current.node(), nullid)
3083 repo.setparents(current.node(), nullid)
3083 repo.dirstate.write()
3084 repo.dirstate.write()
3084 # fix up dirstate for copies and renames
3085 # fix up dirstate for copies and renames
3085 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3086 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3086
3087
3087 # commit
3088 # commit
3088 node = repo.commit(text=message, user=user,
3089 node = repo.commit(text=message, user=user,
3089 date=date, extra=extra, editor=editor)
3090 date=date, extra=extra, editor=editor)
3090 if node is None:
3091 if node is None:
3091 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3092 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3092 else:
3093 else:
3093 current = repo[node]
3094 current = repo[node]
3094 finally:
3095 finally:
3095 wlock.release()
3096 wlock.release()
3096
3097
3097 # remove state when we complete successfully
3098 # remove state when we complete successfully
3098 if not opts.get('dry_run'):
3099 if not opts.get('dry_run'):
3099 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3100 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3100
3101
3101 return 0
3102 return 0
3102
3103
3103 @command('grep',
3104 @command('grep',
3104 [('0', 'print0', None, _('end fields with NUL')),
3105 [('0', 'print0', None, _('end fields with NUL')),
3105 ('', 'all', None, _('print all revisions that match')),
3106 ('', 'all', None, _('print all revisions that match')),
3106 ('a', 'text', None, _('treat all files as text')),
3107 ('a', 'text', None, _('treat all files as text')),
3107 ('f', 'follow', None,
3108 ('f', 'follow', None,
3108 _('follow changeset history,'
3109 _('follow changeset history,'
3109 ' or file history across copies and renames')),
3110 ' or file history across copies and renames')),
3110 ('i', 'ignore-case', None, _('ignore case when matching')),
3111 ('i', 'ignore-case', None, _('ignore case when matching')),
3111 ('l', 'files-with-matches', None,
3112 ('l', 'files-with-matches', None,
3112 _('print only filenames and revisions that match')),
3113 _('print only filenames and revisions that match')),
3113 ('n', 'line-number', None, _('print matching line numbers')),
3114 ('n', 'line-number', None, _('print matching line numbers')),
3114 ('r', 'rev', [],
3115 ('r', 'rev', [],
3115 _('only search files changed within revision range'), _('REV')),
3116 _('only search files changed within revision range'), _('REV')),
3116 ('u', 'user', None, _('list the author (long with -v)')),
3117 ('u', 'user', None, _('list the author (long with -v)')),
3117 ('d', 'date', None, _('list the date (short with -q)')),
3118 ('d', 'date', None, _('list the date (short with -q)')),
3118 ] + walkopts,
3119 ] + walkopts,
3119 _('[OPTION]... PATTERN [FILE]...'))
3120 _('[OPTION]... PATTERN [FILE]...'))
3120 def grep(ui, repo, pattern, *pats, **opts):
3121 def grep(ui, repo, pattern, *pats, **opts):
3121 """search for a pattern in specified files and revisions
3122 """search for a pattern in specified files and revisions
3122
3123
3123 Search revisions of files for a regular expression.
3124 Search revisions of files for a regular expression.
3124
3125
3125 This command behaves differently than Unix grep. It only accepts
3126 This command behaves differently than Unix grep. It only accepts
3126 Python/Perl regexps. It searches repository history, not the
3127 Python/Perl regexps. It searches repository history, not the
3127 working directory. It always prints the revision number in which a
3128 working directory. It always prints the revision number in which a
3128 match appears.
3129 match appears.
3129
3130
3130 By default, grep only prints output for the first revision of a
3131 By default, grep only prints output for the first revision of a
3131 file in which it finds a match. To get it to print every revision
3132 file in which it finds a match. To get it to print every revision
3132 that contains a change in match status ("-" for a match that
3133 that contains a change in match status ("-" for a match that
3133 becomes a non-match, or "+" for a non-match that becomes a match),
3134 becomes a non-match, or "+" for a non-match that becomes a match),
3134 use the --all flag.
3135 use the --all flag.
3135
3136
3136 Returns 0 if a match is found, 1 otherwise.
3137 Returns 0 if a match is found, 1 otherwise.
3137 """
3138 """
3138 reflags = re.M
3139 reflags = re.M
3139 if opts.get('ignore_case'):
3140 if opts.get('ignore_case'):
3140 reflags |= re.I
3141 reflags |= re.I
3141 try:
3142 try:
3142 regexp = util.compilere(pattern, reflags)
3143 regexp = util.compilere(pattern, reflags)
3143 except re.error, inst:
3144 except re.error, inst:
3144 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3145 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3145 return 1
3146 return 1
3146 sep, eol = ':', '\n'
3147 sep, eol = ':', '\n'
3147 if opts.get('print0'):
3148 if opts.get('print0'):
3148 sep = eol = '\0'
3149 sep = eol = '\0'
3149
3150
3150 getfile = util.lrucachefunc(repo.file)
3151 getfile = util.lrucachefunc(repo.file)
3151
3152
3152 def matchlines(body):
3153 def matchlines(body):
3153 begin = 0
3154 begin = 0
3154 linenum = 0
3155 linenum = 0
3155 while begin < len(body):
3156 while begin < len(body):
3156 match = regexp.search(body, begin)
3157 match = regexp.search(body, begin)
3157 if not match:
3158 if not match:
3158 break
3159 break
3159 mstart, mend = match.span()
3160 mstart, mend = match.span()
3160 linenum += body.count('\n', begin, mstart) + 1
3161 linenum += body.count('\n', begin, mstart) + 1
3161 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3162 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3162 begin = body.find('\n', mend) + 1 or len(body) + 1
3163 begin = body.find('\n', mend) + 1 or len(body) + 1
3163 lend = begin - 1
3164 lend = begin - 1
3164 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3165 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3165
3166
3166 class linestate(object):
3167 class linestate(object):
3167 def __init__(self, line, linenum, colstart, colend):
3168 def __init__(self, line, linenum, colstart, colend):
3168 self.line = line
3169 self.line = line
3169 self.linenum = linenum
3170 self.linenum = linenum
3170 self.colstart = colstart
3171 self.colstart = colstart
3171 self.colend = colend
3172 self.colend = colend
3172
3173
3173 def __hash__(self):
3174 def __hash__(self):
3174 return hash((self.linenum, self.line))
3175 return hash((self.linenum, self.line))
3175
3176
3176 def __eq__(self, other):
3177 def __eq__(self, other):
3177 return self.line == other.line
3178 return self.line == other.line
3178
3179
3179 matches = {}
3180 matches = {}
3180 copies = {}
3181 copies = {}
3181 def grepbody(fn, rev, body):
3182 def grepbody(fn, rev, body):
3182 matches[rev].setdefault(fn, [])
3183 matches[rev].setdefault(fn, [])
3183 m = matches[rev][fn]
3184 m = matches[rev][fn]
3184 for lnum, cstart, cend, line in matchlines(body):
3185 for lnum, cstart, cend, line in matchlines(body):
3185 s = linestate(line, lnum, cstart, cend)
3186 s = linestate(line, lnum, cstart, cend)
3186 m.append(s)
3187 m.append(s)
3187
3188
3188 def difflinestates(a, b):
3189 def difflinestates(a, b):
3189 sm = difflib.SequenceMatcher(None, a, b)
3190 sm = difflib.SequenceMatcher(None, a, b)
3190 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3191 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3191 if tag == 'insert':
3192 if tag == 'insert':
3192 for i in xrange(blo, bhi):
3193 for i in xrange(blo, bhi):
3193 yield ('+', b[i])
3194 yield ('+', b[i])
3194 elif tag == 'delete':
3195 elif tag == 'delete':
3195 for i in xrange(alo, ahi):
3196 for i in xrange(alo, ahi):
3196 yield ('-', a[i])
3197 yield ('-', a[i])
3197 elif tag == 'replace':
3198 elif tag == 'replace':
3198 for i in xrange(alo, ahi):
3199 for i in xrange(alo, ahi):
3199 yield ('-', a[i])
3200 yield ('-', a[i])
3200 for i in xrange(blo, bhi):
3201 for i in xrange(blo, bhi):
3201 yield ('+', b[i])
3202 yield ('+', b[i])
3202
3203
3203 def display(fn, ctx, pstates, states):
3204 def display(fn, ctx, pstates, states):
3204 rev = ctx.rev()
3205 rev = ctx.rev()
3205 datefunc = ui.quiet and util.shortdate or util.datestr
3206 datefunc = ui.quiet and util.shortdate or util.datestr
3206 found = False
3207 found = False
3207 filerevmatches = {}
3208 filerevmatches = {}
3208 def binary():
3209 def binary():
3209 flog = getfile(fn)
3210 flog = getfile(fn)
3210 return util.binary(flog.read(ctx.filenode(fn)))
3211 return util.binary(flog.read(ctx.filenode(fn)))
3211
3212
3212 if opts.get('all'):
3213 if opts.get('all'):
3213 iter = difflinestates(pstates, states)
3214 iter = difflinestates(pstates, states)
3214 else:
3215 else:
3215 iter = [('', l) for l in states]
3216 iter = [('', l) for l in states]
3216 for change, l in iter:
3217 for change, l in iter:
3217 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3218 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3218 before, match, after = None, None, None
3219 before, match, after = None, None, None
3219
3220
3220 if opts.get('line_number'):
3221 if opts.get('line_number'):
3221 cols.append((str(l.linenum), 'grep.linenumber'))
3222 cols.append((str(l.linenum), 'grep.linenumber'))
3222 if opts.get('all'):
3223 if opts.get('all'):
3223 cols.append((change, 'grep.change'))
3224 cols.append((change, 'grep.change'))
3224 if opts.get('user'):
3225 if opts.get('user'):
3225 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3226 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3226 if opts.get('date'):
3227 if opts.get('date'):
3227 cols.append((datefunc(ctx.date()), 'grep.date'))
3228 cols.append((datefunc(ctx.date()), 'grep.date'))
3228 if opts.get('files_with_matches'):
3229 if opts.get('files_with_matches'):
3229 c = (fn, rev)
3230 c = (fn, rev)
3230 if c in filerevmatches:
3231 if c in filerevmatches:
3231 continue
3232 continue
3232 filerevmatches[c] = 1
3233 filerevmatches[c] = 1
3233 else:
3234 else:
3234 before = l.line[:l.colstart]
3235 before = l.line[:l.colstart]
3235 match = l.line[l.colstart:l.colend]
3236 match = l.line[l.colstart:l.colend]
3236 after = l.line[l.colend:]
3237 after = l.line[l.colend:]
3237 for col, label in cols[:-1]:
3238 for col, label in cols[:-1]:
3238 ui.write(col, label=label)
3239 ui.write(col, label=label)
3239 ui.write(sep, label='grep.sep')
3240 ui.write(sep, label='grep.sep')
3240 ui.write(cols[-1][0], label=cols[-1][1])
3241 ui.write(cols[-1][0], label=cols[-1][1])
3241 if before is not None:
3242 if before is not None:
3242 ui.write(sep, label='grep.sep')
3243 ui.write(sep, label='grep.sep')
3243 if not opts.get('text') and binary():
3244 if not opts.get('text') and binary():
3244 ui.write(" Binary file matches")
3245 ui.write(" Binary file matches")
3245 else:
3246 else:
3246 ui.write(before)
3247 ui.write(before)
3247 ui.write(match, label='grep.match')
3248 ui.write(match, label='grep.match')
3248 ui.write(after)
3249 ui.write(after)
3249 ui.write(eol)
3250 ui.write(eol)
3250 found = True
3251 found = True
3251 return found
3252 return found
3252
3253
3253 skip = {}
3254 skip = {}
3254 revfiles = {}
3255 revfiles = {}
3255 matchfn = scmutil.match(repo[None], pats, opts)
3256 matchfn = scmutil.match(repo[None], pats, opts)
3256 found = False
3257 found = False
3257 follow = opts.get('follow')
3258 follow = opts.get('follow')
3258
3259
3259 def prep(ctx, fns):
3260 def prep(ctx, fns):
3260 rev = ctx.rev()
3261 rev = ctx.rev()
3261 pctx = ctx.p1()
3262 pctx = ctx.p1()
3262 parent = pctx.rev()
3263 parent = pctx.rev()
3263 matches.setdefault(rev, {})
3264 matches.setdefault(rev, {})
3264 matches.setdefault(parent, {})
3265 matches.setdefault(parent, {})
3265 files = revfiles.setdefault(rev, [])
3266 files = revfiles.setdefault(rev, [])
3266 for fn in fns:
3267 for fn in fns:
3267 flog = getfile(fn)
3268 flog = getfile(fn)
3268 try:
3269 try:
3269 fnode = ctx.filenode(fn)
3270 fnode = ctx.filenode(fn)
3270 except error.LookupError:
3271 except error.LookupError:
3271 continue
3272 continue
3272
3273
3273 copied = flog.renamed(fnode)
3274 copied = flog.renamed(fnode)
3274 copy = follow and copied and copied[0]
3275 copy = follow and copied and copied[0]
3275 if copy:
3276 if copy:
3276 copies.setdefault(rev, {})[fn] = copy
3277 copies.setdefault(rev, {})[fn] = copy
3277 if fn in skip:
3278 if fn in skip:
3278 if copy:
3279 if copy:
3279 skip[copy] = True
3280 skip[copy] = True
3280 continue
3281 continue
3281 files.append(fn)
3282 files.append(fn)
3282
3283
3283 if fn not in matches[rev]:
3284 if fn not in matches[rev]:
3284 grepbody(fn, rev, flog.read(fnode))
3285 grepbody(fn, rev, flog.read(fnode))
3285
3286
3286 pfn = copy or fn
3287 pfn = copy or fn
3287 if pfn not in matches[parent]:
3288 if pfn not in matches[parent]:
3288 try:
3289 try:
3289 fnode = pctx.filenode(pfn)
3290 fnode = pctx.filenode(pfn)
3290 grepbody(pfn, parent, flog.read(fnode))
3291 grepbody(pfn, parent, flog.read(fnode))
3291 except error.LookupError:
3292 except error.LookupError:
3292 pass
3293 pass
3293
3294
3294 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3295 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3295 rev = ctx.rev()
3296 rev = ctx.rev()
3296 parent = ctx.p1().rev()
3297 parent = ctx.p1().rev()
3297 for fn in sorted(revfiles.get(rev, [])):
3298 for fn in sorted(revfiles.get(rev, [])):
3298 states = matches[rev][fn]
3299 states = matches[rev][fn]
3299 copy = copies.get(rev, {}).get(fn)
3300 copy = copies.get(rev, {}).get(fn)
3300 if fn in skip:
3301 if fn in skip:
3301 if copy:
3302 if copy:
3302 skip[copy] = True
3303 skip[copy] = True
3303 continue
3304 continue
3304 pstates = matches.get(parent, {}).get(copy or fn, [])
3305 pstates = matches.get(parent, {}).get(copy or fn, [])
3305 if pstates or states:
3306 if pstates or states:
3306 r = display(fn, ctx, pstates, states)
3307 r = display(fn, ctx, pstates, states)
3307 found = found or r
3308 found = found or r
3308 if r and not opts.get('all'):
3309 if r and not opts.get('all'):
3309 skip[fn] = True
3310 skip[fn] = True
3310 if copy:
3311 if copy:
3311 skip[copy] = True
3312 skip[copy] = True
3312 del matches[rev]
3313 del matches[rev]
3313 del revfiles[rev]
3314 del revfiles[rev]
3314
3315
3315 return not found
3316 return not found
3316
3317
3317 @command('heads',
3318 @command('heads',
3318 [('r', 'rev', '',
3319 [('r', 'rev', '',
3319 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3320 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3320 ('t', 'topo', False, _('show topological heads only')),
3321 ('t', 'topo', False, _('show topological heads only')),
3321 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3322 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3322 ('c', 'closed', False, _('show normal and closed branch heads')),
3323 ('c', 'closed', False, _('show normal and closed branch heads')),
3323 ] + templateopts,
3324 ] + templateopts,
3324 _('[-ct] [-r STARTREV] [REV]...'))
3325 _('[-ct] [-r STARTREV] [REV]...'))
3325 def heads(ui, repo, *branchrevs, **opts):
3326 def heads(ui, repo, *branchrevs, **opts):
3326 """show branch heads
3327 """show branch heads
3327
3328
3328 With no arguments, show all open branch heads in the repository.
3329 With no arguments, show all open branch heads in the repository.
3329 Branch heads are changesets that have no descendants on the
3330 Branch heads are changesets that have no descendants on the
3330 same branch. They are where development generally takes place and
3331 same branch. They are where development generally takes place and
3331 are the usual targets for update and merge operations.
3332 are the usual targets for update and merge operations.
3332
3333
3333 If one or more REVs are given, only open branch heads on the
3334 If one or more REVs are given, only open branch heads on the
3334 branches associated with the specified changesets are shown. This
3335 branches associated with the specified changesets are shown. This
3335 means that you can use :hg:`heads .` to see the heads on the
3336 means that you can use :hg:`heads .` to see the heads on the
3336 currently checked-out branch.
3337 currently checked-out branch.
3337
3338
3338 If -c/--closed is specified, also show branch heads marked closed
3339 If -c/--closed is specified, also show branch heads marked closed
3339 (see :hg:`commit --close-branch`).
3340 (see :hg:`commit --close-branch`).
3340
3341
3341 If STARTREV is specified, only those heads that are descendants of
3342 If STARTREV is specified, only those heads that are descendants of
3342 STARTREV will be displayed.
3343 STARTREV will be displayed.
3343
3344
3344 If -t/--topo is specified, named branch mechanics will be ignored and only
3345 If -t/--topo is specified, named branch mechanics will be ignored and only
3345 topological heads (changesets with no children) will be shown.
3346 topological heads (changesets with no children) will be shown.
3346
3347
3347 Returns 0 if matching heads are found, 1 if not.
3348 Returns 0 if matching heads are found, 1 if not.
3348 """
3349 """
3349
3350
3350 start = None
3351 start = None
3351 if 'rev' in opts:
3352 if 'rev' in opts:
3352 start = scmutil.revsingle(repo, opts['rev'], None).node()
3353 start = scmutil.revsingle(repo, opts['rev'], None).node()
3353
3354
3354 if opts.get('topo'):
3355 if opts.get('topo'):
3355 heads = [repo[h] for h in repo.heads(start)]
3356 heads = [repo[h] for h in repo.heads(start)]
3356 else:
3357 else:
3357 heads = []
3358 heads = []
3358 for branch in repo.branchmap():
3359 for branch in repo.branchmap():
3359 heads += repo.branchheads(branch, start, opts.get('closed'))
3360 heads += repo.branchheads(branch, start, opts.get('closed'))
3360 heads = [repo[h] for h in heads]
3361 heads = [repo[h] for h in heads]
3361
3362
3362 if branchrevs:
3363 if branchrevs:
3363 branches = set(repo[br].branch() for br in branchrevs)
3364 branches = set(repo[br].branch() for br in branchrevs)
3364 heads = [h for h in heads if h.branch() in branches]
3365 heads = [h for h in heads if h.branch() in branches]
3365
3366
3366 if opts.get('active') and branchrevs:
3367 if opts.get('active') and branchrevs:
3367 dagheads = repo.heads(start)
3368 dagheads = repo.heads(start)
3368 heads = [h for h in heads if h.node() in dagheads]
3369 heads = [h for h in heads if h.node() in dagheads]
3369
3370
3370 if branchrevs:
3371 if branchrevs:
3371 haveheads = set(h.branch() for h in heads)
3372 haveheads = set(h.branch() for h in heads)
3372 if branches - haveheads:
3373 if branches - haveheads:
3373 headless = ', '.join(b for b in branches - haveheads)
3374 headless = ', '.join(b for b in branches - haveheads)
3374 msg = _('no open branch heads found on branches %s')
3375 msg = _('no open branch heads found on branches %s')
3375 if opts.get('rev'):
3376 if opts.get('rev'):
3376 msg += _(' (started at %s)') % opts['rev']
3377 msg += _(' (started at %s)') % opts['rev']
3377 ui.warn((msg + '\n') % headless)
3378 ui.warn((msg + '\n') % headless)
3378
3379
3379 if not heads:
3380 if not heads:
3380 return 1
3381 return 1
3381
3382
3382 heads = sorted(heads, key=lambda x: -x.rev())
3383 heads = sorted(heads, key=lambda x: -x.rev())
3383 displayer = cmdutil.show_changeset(ui, repo, opts)
3384 displayer = cmdutil.show_changeset(ui, repo, opts)
3384 for ctx in heads:
3385 for ctx in heads:
3385 displayer.show(ctx)
3386 displayer.show(ctx)
3386 displayer.close()
3387 displayer.close()
3387
3388
3388 @command('help',
3389 @command('help',
3389 [('e', 'extension', None, _('show only help for extensions')),
3390 [('e', 'extension', None, _('show only help for extensions')),
3390 ('c', 'command', None, _('show only help for commands')),
3391 ('c', 'command', None, _('show only help for commands')),
3391 ('k', 'keyword', '', _('show topics matching keyword')),
3392 ('k', 'keyword', '', _('show topics matching keyword')),
3392 ],
3393 ],
3393 _('[-ec] [TOPIC]'))
3394 _('[-ec] [TOPIC]'))
3394 def help_(ui, name=None, **opts):
3395 def help_(ui, name=None, **opts):
3395 """show help for a given topic or a help overview
3396 """show help for a given topic or a help overview
3396
3397
3397 With no arguments, print a list of commands with short help messages.
3398 With no arguments, print a list of commands with short help messages.
3398
3399
3399 Given a topic, extension, or command name, print help for that
3400 Given a topic, extension, or command name, print help for that
3400 topic.
3401 topic.
3401
3402
3402 Returns 0 if successful.
3403 Returns 0 if successful.
3403 """
3404 """
3404
3405
3405 textwidth = min(ui.termwidth(), 80) - 2
3406 textwidth = min(ui.termwidth(), 80) - 2
3406
3407
3407 keep = ui.verbose and ['verbose'] or []
3408 keep = ui.verbose and ['verbose'] or []
3408 text = help.help_(ui, name, **opts)
3409 text = help.help_(ui, name, **opts)
3409
3410
3410 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3411 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3411 if 'verbose' in pruned:
3412 if 'verbose' in pruned:
3412 keep.append('omitted')
3413 keep.append('omitted')
3413 else:
3414 else:
3414 keep.append('notomitted')
3415 keep.append('notomitted')
3415 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3416 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3416 ui.write(formatted)
3417 ui.write(formatted)
3417
3418
3418
3419
3419 @command('identify|id',
3420 @command('identify|id',
3420 [('r', 'rev', '',
3421 [('r', 'rev', '',
3421 _('identify the specified revision'), _('REV')),
3422 _('identify the specified revision'), _('REV')),
3422 ('n', 'num', None, _('show local revision number')),
3423 ('n', 'num', None, _('show local revision number')),
3423 ('i', 'id', None, _('show global revision id')),
3424 ('i', 'id', None, _('show global revision id')),
3424 ('b', 'branch', None, _('show branch')),
3425 ('b', 'branch', None, _('show branch')),
3425 ('t', 'tags', None, _('show tags')),
3426 ('t', 'tags', None, _('show tags')),
3426 ('B', 'bookmarks', None, _('show bookmarks')),
3427 ('B', 'bookmarks', None, _('show bookmarks')),
3427 ] + remoteopts,
3428 ] + remoteopts,
3428 _('[-nibtB] [-r REV] [SOURCE]'))
3429 _('[-nibtB] [-r REV] [SOURCE]'))
3429 def identify(ui, repo, source=None, rev=None,
3430 def identify(ui, repo, source=None, rev=None,
3430 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3431 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3431 """identify the working copy or specified revision
3432 """identify the working copy or specified revision
3432
3433
3433 Print a summary identifying the repository state at REV using one or
3434 Print a summary identifying the repository state at REV using one or
3434 two parent hash identifiers, followed by a "+" if the working
3435 two parent hash identifiers, followed by a "+" if the working
3435 directory has uncommitted changes, the branch name (if not default),
3436 directory has uncommitted changes, the branch name (if not default),
3436 a list of tags, and a list of bookmarks.
3437 a list of tags, and a list of bookmarks.
3437
3438
3438 When REV is not given, print a summary of the current state of the
3439 When REV is not given, print a summary of the current state of the
3439 repository.
3440 repository.
3440
3441
3441 Specifying a path to a repository root or Mercurial bundle will
3442 Specifying a path to a repository root or Mercurial bundle will
3442 cause lookup to operate on that repository/bundle.
3443 cause lookup to operate on that repository/bundle.
3443
3444
3444 .. container:: verbose
3445 .. container:: verbose
3445
3446
3446 Examples:
3447 Examples:
3447
3448
3448 - generate a build identifier for the working directory::
3449 - generate a build identifier for the working directory::
3449
3450
3450 hg id --id > build-id.dat
3451 hg id --id > build-id.dat
3451
3452
3452 - find the revision corresponding to a tag::
3453 - find the revision corresponding to a tag::
3453
3454
3454 hg id -n -r 1.3
3455 hg id -n -r 1.3
3455
3456
3456 - check the most recent revision of a remote repository::
3457 - check the most recent revision of a remote repository::
3457
3458
3458 hg id -r tip http://selenic.com/hg/
3459 hg id -r tip http://selenic.com/hg/
3459
3460
3460 Returns 0 if successful.
3461 Returns 0 if successful.
3461 """
3462 """
3462
3463
3463 if not repo and not source:
3464 if not repo and not source:
3464 raise util.Abort(_("there is no Mercurial repository here "
3465 raise util.Abort(_("there is no Mercurial repository here "
3465 "(.hg not found)"))
3466 "(.hg not found)"))
3466
3467
3467 hexfunc = ui.debugflag and hex or short
3468 hexfunc = ui.debugflag and hex or short
3468 default = not (num or id or branch or tags or bookmarks)
3469 default = not (num or id or branch or tags or bookmarks)
3469 output = []
3470 output = []
3470 revs = []
3471 revs = []
3471
3472
3472 if source:
3473 if source:
3473 source, branches = hg.parseurl(ui.expandpath(source))
3474 source, branches = hg.parseurl(ui.expandpath(source))
3474 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3475 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3475 repo = peer.local()
3476 repo = peer.local()
3476 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3477 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3477
3478
3478 if not repo:
3479 if not repo:
3479 if num or branch or tags:
3480 if num or branch or tags:
3480 raise util.Abort(
3481 raise util.Abort(
3481 _("can't query remote revision number, branch, or tags"))
3482 _("can't query remote revision number, branch, or tags"))
3482 if not rev and revs:
3483 if not rev and revs:
3483 rev = revs[0]
3484 rev = revs[0]
3484 if not rev:
3485 if not rev:
3485 rev = "tip"
3486 rev = "tip"
3486
3487
3487 remoterev = peer.lookup(rev)
3488 remoterev = peer.lookup(rev)
3488 if default or id:
3489 if default or id:
3489 output = [hexfunc(remoterev)]
3490 output = [hexfunc(remoterev)]
3490
3491
3491 def getbms():
3492 def getbms():
3492 bms = []
3493 bms = []
3493
3494
3494 if 'bookmarks' in peer.listkeys('namespaces'):
3495 if 'bookmarks' in peer.listkeys('namespaces'):
3495 hexremoterev = hex(remoterev)
3496 hexremoterev = hex(remoterev)
3496 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3497 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3497 if bmr == hexremoterev]
3498 if bmr == hexremoterev]
3498
3499
3499 return sorted(bms)
3500 return sorted(bms)
3500
3501
3501 if bookmarks:
3502 if bookmarks:
3502 output.extend(getbms())
3503 output.extend(getbms())
3503 elif default and not ui.quiet:
3504 elif default and not ui.quiet:
3504 # multiple bookmarks for a single parent separated by '/'
3505 # multiple bookmarks for a single parent separated by '/'
3505 bm = '/'.join(getbms())
3506 bm = '/'.join(getbms())
3506 if bm:
3507 if bm:
3507 output.append(bm)
3508 output.append(bm)
3508 else:
3509 else:
3509 if not rev:
3510 if not rev:
3510 ctx = repo[None]
3511 ctx = repo[None]
3511 parents = ctx.parents()
3512 parents = ctx.parents()
3512 changed = ""
3513 changed = ""
3513 if default or id or num:
3514 if default or id or num:
3514 if (util.any(repo.status())
3515 if (util.any(repo.status())
3515 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3516 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3516 changed = '+'
3517 changed = '+'
3517 if default or id:
3518 if default or id:
3518 output = ["%s%s" %
3519 output = ["%s%s" %
3519 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3520 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3520 if num:
3521 if num:
3521 output.append("%s%s" %
3522 output.append("%s%s" %
3522 ('+'.join([str(p.rev()) for p in parents]), changed))
3523 ('+'.join([str(p.rev()) for p in parents]), changed))
3523 else:
3524 else:
3524 ctx = scmutil.revsingle(repo, rev)
3525 ctx = scmutil.revsingle(repo, rev)
3525 if default or id:
3526 if default or id:
3526 output = [hexfunc(ctx.node())]
3527 output = [hexfunc(ctx.node())]
3527 if num:
3528 if num:
3528 output.append(str(ctx.rev()))
3529 output.append(str(ctx.rev()))
3529
3530
3530 if default and not ui.quiet:
3531 if default and not ui.quiet:
3531 b = ctx.branch()
3532 b = ctx.branch()
3532 if b != 'default':
3533 if b != 'default':
3533 output.append("(%s)" % b)
3534 output.append("(%s)" % b)
3534
3535
3535 # multiple tags for a single parent separated by '/'
3536 # multiple tags for a single parent separated by '/'
3536 t = '/'.join(ctx.tags())
3537 t = '/'.join(ctx.tags())
3537 if t:
3538 if t:
3538 output.append(t)
3539 output.append(t)
3539
3540
3540 # multiple bookmarks for a single parent separated by '/'
3541 # multiple bookmarks for a single parent separated by '/'
3541 bm = '/'.join(ctx.bookmarks())
3542 bm = '/'.join(ctx.bookmarks())
3542 if bm:
3543 if bm:
3543 output.append(bm)
3544 output.append(bm)
3544 else:
3545 else:
3545 if branch:
3546 if branch:
3546 output.append(ctx.branch())
3547 output.append(ctx.branch())
3547
3548
3548 if tags:
3549 if tags:
3549 output.extend(ctx.tags())
3550 output.extend(ctx.tags())
3550
3551
3551 if bookmarks:
3552 if bookmarks:
3552 output.extend(ctx.bookmarks())
3553 output.extend(ctx.bookmarks())
3553
3554
3554 ui.write("%s\n" % ' '.join(output))
3555 ui.write("%s\n" % ' '.join(output))
3555
3556
3556 @command('import|patch',
3557 @command('import|patch',
3557 [('p', 'strip', 1,
3558 [('p', 'strip', 1,
3558 _('directory strip option for patch. This has the same '
3559 _('directory strip option for patch. This has the same '
3559 'meaning as the corresponding patch option'), _('NUM')),
3560 'meaning as the corresponding patch option'), _('NUM')),
3560 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3561 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3561 ('e', 'edit', False, _('invoke editor on commit messages')),
3562 ('e', 'edit', False, _('invoke editor on commit messages')),
3562 ('f', 'force', None,
3563 ('f', 'force', None,
3563 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3564 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3564 ('', 'no-commit', None,
3565 ('', 'no-commit', None,
3565 _("don't commit, just update the working directory")),
3566 _("don't commit, just update the working directory")),
3566 ('', 'bypass', None,
3567 ('', 'bypass', None,
3567 _("apply patch without touching the working directory")),
3568 _("apply patch without touching the working directory")),
3568 ('', 'exact', None,
3569 ('', 'exact', None,
3569 _('apply patch to the nodes from which it was generated')),
3570 _('apply patch to the nodes from which it was generated')),
3570 ('', 'import-branch', None,
3571 ('', 'import-branch', None,
3571 _('use any branch information in patch (implied by --exact)'))] +
3572 _('use any branch information in patch (implied by --exact)'))] +
3572 commitopts + commitopts2 + similarityopts,
3573 commitopts + commitopts2 + similarityopts,
3573 _('[OPTION]... PATCH...'))
3574 _('[OPTION]... PATCH...'))
3574 def import_(ui, repo, patch1=None, *patches, **opts):
3575 def import_(ui, repo, patch1=None, *patches, **opts):
3575 """import an ordered set of patches
3576 """import an ordered set of patches
3576
3577
3577 Import a list of patches and commit them individually (unless
3578 Import a list of patches and commit them individually (unless
3578 --no-commit is specified).
3579 --no-commit is specified).
3579
3580
3580 Because import first applies changes to the working directory,
3581 Because import first applies changes to the working directory,
3581 import will abort if there are outstanding changes.
3582 import will abort if there are outstanding changes.
3582
3583
3583 You can import a patch straight from a mail message. Even patches
3584 You can import a patch straight from a mail message. Even patches
3584 as attachments work (to use the body part, it must have type
3585 as attachments work (to use the body part, it must have type
3585 text/plain or text/x-patch). From and Subject headers of email
3586 text/plain or text/x-patch). From and Subject headers of email
3586 message are used as default committer and commit message. All
3587 message are used as default committer and commit message. All
3587 text/plain body parts before first diff are added to commit
3588 text/plain body parts before first diff are added to commit
3588 message.
3589 message.
3589
3590
3590 If the imported patch was generated by :hg:`export`, user and
3591 If the imported patch was generated by :hg:`export`, user and
3591 description from patch override values from message headers and
3592 description from patch override values from message headers and
3592 body. Values given on command line with -m/--message and -u/--user
3593 body. Values given on command line with -m/--message and -u/--user
3593 override these.
3594 override these.
3594
3595
3595 If --exact is specified, import will set the working directory to
3596 If --exact is specified, import will set the working directory to
3596 the parent of each patch before applying it, and will abort if the
3597 the parent of each patch before applying it, and will abort if the
3597 resulting changeset has a different ID than the one recorded in
3598 resulting changeset has a different ID than the one recorded in
3598 the patch. This may happen due to character set problems or other
3599 the patch. This may happen due to character set problems or other
3599 deficiencies in the text patch format.
3600 deficiencies in the text patch format.
3600
3601
3601 Use --bypass to apply and commit patches directly to the
3602 Use --bypass to apply and commit patches directly to the
3602 repository, not touching the working directory. Without --exact,
3603 repository, not touching the working directory. Without --exact,
3603 patches will be applied on top of the working directory parent
3604 patches will be applied on top of the working directory parent
3604 revision.
3605 revision.
3605
3606
3606 With -s/--similarity, hg will attempt to discover renames and
3607 With -s/--similarity, hg will attempt to discover renames and
3607 copies in the patch in the same way as :hg:`addremove`.
3608 copies in the patch in the same way as :hg:`addremove`.
3608
3609
3609 To read a patch from standard input, use "-" as the patch name. If
3610 To read a patch from standard input, use "-" as the patch name. If
3610 a URL is specified, the patch will be downloaded from it.
3611 a URL is specified, the patch will be downloaded from it.
3611 See :hg:`help dates` for a list of formats valid for -d/--date.
3612 See :hg:`help dates` for a list of formats valid for -d/--date.
3612
3613
3613 .. container:: verbose
3614 .. container:: verbose
3614
3615
3615 Examples:
3616 Examples:
3616
3617
3617 - import a traditional patch from a website and detect renames::
3618 - import a traditional patch from a website and detect renames::
3618
3619
3619 hg import -s 80 http://example.com/bugfix.patch
3620 hg import -s 80 http://example.com/bugfix.patch
3620
3621
3621 - import a changeset from an hgweb server::
3622 - import a changeset from an hgweb server::
3622
3623
3623 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3624 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3624
3625
3625 - import all the patches in an Unix-style mbox::
3626 - import all the patches in an Unix-style mbox::
3626
3627
3627 hg import incoming-patches.mbox
3628 hg import incoming-patches.mbox
3628
3629
3629 - attempt to exactly restore an exported changeset (not always
3630 - attempt to exactly restore an exported changeset (not always
3630 possible)::
3631 possible)::
3631
3632
3632 hg import --exact proposed-fix.patch
3633 hg import --exact proposed-fix.patch
3633
3634
3634 Returns 0 on success.
3635 Returns 0 on success.
3635 """
3636 """
3636
3637
3637 if not patch1:
3638 if not patch1:
3638 raise util.Abort(_('need at least one patch to import'))
3639 raise util.Abort(_('need at least one patch to import'))
3639
3640
3640 patches = (patch1,) + patches
3641 patches = (patch1,) + patches
3641
3642
3642 date = opts.get('date')
3643 date = opts.get('date')
3643 if date:
3644 if date:
3644 opts['date'] = util.parsedate(date)
3645 opts['date'] = util.parsedate(date)
3645
3646
3646 editor = cmdutil.commiteditor
3647 editor = cmdutil.commiteditor
3647 if opts.get('edit'):
3648 if opts.get('edit'):
3648 editor = cmdutil.commitforceeditor
3649 editor = cmdutil.commitforceeditor
3649
3650
3650 update = not opts.get('bypass')
3651 update = not opts.get('bypass')
3651 if not update and opts.get('no_commit'):
3652 if not update and opts.get('no_commit'):
3652 raise util.Abort(_('cannot use --no-commit with --bypass'))
3653 raise util.Abort(_('cannot use --no-commit with --bypass'))
3653 try:
3654 try:
3654 sim = float(opts.get('similarity') or 0)
3655 sim = float(opts.get('similarity') or 0)
3655 except ValueError:
3656 except ValueError:
3656 raise util.Abort(_('similarity must be a number'))
3657 raise util.Abort(_('similarity must be a number'))
3657 if sim < 0 or sim > 100:
3658 if sim < 0 or sim > 100:
3658 raise util.Abort(_('similarity must be between 0 and 100'))
3659 raise util.Abort(_('similarity must be between 0 and 100'))
3659 if sim and not update:
3660 if sim and not update:
3660 raise util.Abort(_('cannot use --similarity with --bypass'))
3661 raise util.Abort(_('cannot use --similarity with --bypass'))
3661
3662
3662 if update:
3663 if update:
3663 cmdutil.checkunfinished(repo)
3664 cmdutil.checkunfinished(repo)
3664 if (opts.get('exact') or not opts.get('force')) and update:
3665 if (opts.get('exact') or not opts.get('force')) and update:
3665 cmdutil.bailifchanged(repo)
3666 cmdutil.bailifchanged(repo)
3666
3667
3667 base = opts["base"]
3668 base = opts["base"]
3668 strip = opts["strip"]
3669 strip = opts["strip"]
3669 wlock = lock = tr = None
3670 wlock = lock = tr = None
3670 msgs = []
3671 msgs = []
3671
3672
3672 def tryone(ui, hunk, parents):
3673 def tryone(ui, hunk, parents):
3673 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3674 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3674 patch.extract(ui, hunk)
3675 patch.extract(ui, hunk)
3675
3676
3676 if not tmpname:
3677 if not tmpname:
3677 return (None, None)
3678 return (None, None)
3678 msg = _('applied to working directory')
3679 msg = _('applied to working directory')
3679
3680
3680 try:
3681 try:
3681 cmdline_message = cmdutil.logmessage(ui, opts)
3682 cmdline_message = cmdutil.logmessage(ui, opts)
3682 if cmdline_message:
3683 if cmdline_message:
3683 # pickup the cmdline msg
3684 # pickup the cmdline msg
3684 message = cmdline_message
3685 message = cmdline_message
3685 elif message:
3686 elif message:
3686 # pickup the patch msg
3687 # pickup the patch msg
3687 message = message.strip()
3688 message = message.strip()
3688 else:
3689 else:
3689 # launch the editor
3690 # launch the editor
3690 message = None
3691 message = None
3691 ui.debug('message:\n%s\n' % message)
3692 ui.debug('message:\n%s\n' % message)
3692
3693
3693 if len(parents) == 1:
3694 if len(parents) == 1:
3694 parents.append(repo[nullid])
3695 parents.append(repo[nullid])
3695 if opts.get('exact'):
3696 if opts.get('exact'):
3696 if not nodeid or not p1:
3697 if not nodeid or not p1:
3697 raise util.Abort(_('not a Mercurial patch'))
3698 raise util.Abort(_('not a Mercurial patch'))
3698 p1 = repo[p1]
3699 p1 = repo[p1]
3699 p2 = repo[p2 or nullid]
3700 p2 = repo[p2 or nullid]
3700 elif p2:
3701 elif p2:
3701 try:
3702 try:
3702 p1 = repo[p1]
3703 p1 = repo[p1]
3703 p2 = repo[p2]
3704 p2 = repo[p2]
3704 # Without any options, consider p2 only if the
3705 # Without any options, consider p2 only if the
3705 # patch is being applied on top of the recorded
3706 # patch is being applied on top of the recorded
3706 # first parent.
3707 # first parent.
3707 if p1 != parents[0]:
3708 if p1 != parents[0]:
3708 p1 = parents[0]
3709 p1 = parents[0]
3709 p2 = repo[nullid]
3710 p2 = repo[nullid]
3710 except error.RepoError:
3711 except error.RepoError:
3711 p1, p2 = parents
3712 p1, p2 = parents
3712 else:
3713 else:
3713 p1, p2 = parents
3714 p1, p2 = parents
3714
3715
3715 n = None
3716 n = None
3716 if update:
3717 if update:
3717 if p1 != parents[0]:
3718 if p1 != parents[0]:
3718 hg.clean(repo, p1.node())
3719 hg.clean(repo, p1.node())
3719 if p2 != parents[1]:
3720 if p2 != parents[1]:
3720 repo.setparents(p1.node(), p2.node())
3721 repo.setparents(p1.node(), p2.node())
3721
3722
3722 if opts.get('exact') or opts.get('import_branch'):
3723 if opts.get('exact') or opts.get('import_branch'):
3723 repo.dirstate.setbranch(branch or 'default')
3724 repo.dirstate.setbranch(branch or 'default')
3724
3725
3725 files = set()
3726 files = set()
3726 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3727 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3727 eolmode=None, similarity=sim / 100.0)
3728 eolmode=None, similarity=sim / 100.0)
3728 files = list(files)
3729 files = list(files)
3729 if opts.get('no_commit'):
3730 if opts.get('no_commit'):
3730 if message:
3731 if message:
3731 msgs.append(message)
3732 msgs.append(message)
3732 else:
3733 else:
3733 if opts.get('exact') or p2:
3734 if opts.get('exact') or p2:
3734 # If you got here, you either use --force and know what
3735 # If you got here, you either use --force and know what
3735 # you are doing or used --exact or a merge patch while
3736 # you are doing or used --exact or a merge patch while
3736 # being updated to its first parent.
3737 # being updated to its first parent.
3737 m = None
3738 m = None
3738 else:
3739 else:
3739 m = scmutil.matchfiles(repo, files or [])
3740 m = scmutil.matchfiles(repo, files or [])
3740 n = repo.commit(message, opts.get('user') or user,
3741 n = repo.commit(message, opts.get('user') or user,
3741 opts.get('date') or date, match=m,
3742 opts.get('date') or date, match=m,
3742 editor=editor)
3743 editor=editor)
3743 else:
3744 else:
3744 if opts.get('exact') or opts.get('import_branch'):
3745 if opts.get('exact') or opts.get('import_branch'):
3745 branch = branch or 'default'
3746 branch = branch or 'default'
3746 else:
3747 else:
3747 branch = p1.branch()
3748 branch = p1.branch()
3748 store = patch.filestore()
3749 store = patch.filestore()
3749 try:
3750 try:
3750 files = set()
3751 files = set()
3751 try:
3752 try:
3752 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3753 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3753 files, eolmode=None)
3754 files, eolmode=None)
3754 except patch.PatchError, e:
3755 except patch.PatchError, e:
3755 raise util.Abort(str(e))
3756 raise util.Abort(str(e))
3756 memctx = context.makememctx(repo, (p1.node(), p2.node()),
3757 memctx = context.makememctx(repo, (p1.node(), p2.node()),
3757 message,
3758 message,
3758 opts.get('user') or user,
3759 opts.get('user') or user,
3759 opts.get('date') or date,
3760 opts.get('date') or date,
3760 branch, files, store,
3761 branch, files, store,
3761 editor=cmdutil.commiteditor)
3762 editor=cmdutil.commiteditor)
3762 repo.savecommitmessage(memctx.description())
3763 repo.savecommitmessage(memctx.description())
3763 n = memctx.commit()
3764 n = memctx.commit()
3764 finally:
3765 finally:
3765 store.close()
3766 store.close()
3766 if opts.get('exact') and hex(n) != nodeid:
3767 if opts.get('exact') and hex(n) != nodeid:
3767 raise util.Abort(_('patch is damaged or loses information'))
3768 raise util.Abort(_('patch is damaged or loses information'))
3768 if n:
3769 if n:
3769 # i18n: refers to a short changeset id
3770 # i18n: refers to a short changeset id
3770 msg = _('created %s') % short(n)
3771 msg = _('created %s') % short(n)
3771 return (msg, n)
3772 return (msg, n)
3772 finally:
3773 finally:
3773 os.unlink(tmpname)
3774 os.unlink(tmpname)
3774
3775
3775 try:
3776 try:
3776 try:
3777 try:
3777 wlock = repo.wlock()
3778 wlock = repo.wlock()
3778 if not opts.get('no_commit'):
3779 if not opts.get('no_commit'):
3779 lock = repo.lock()
3780 lock = repo.lock()
3780 tr = repo.transaction('import')
3781 tr = repo.transaction('import')
3781 parents = repo.parents()
3782 parents = repo.parents()
3782 for patchurl in patches:
3783 for patchurl in patches:
3783 if patchurl == '-':
3784 if patchurl == '-':
3784 ui.status(_('applying patch from stdin\n'))
3785 ui.status(_('applying patch from stdin\n'))
3785 patchfile = ui.fin
3786 patchfile = ui.fin
3786 patchurl = 'stdin' # for error message
3787 patchurl = 'stdin' # for error message
3787 else:
3788 else:
3788 patchurl = os.path.join(base, patchurl)
3789 patchurl = os.path.join(base, patchurl)
3789 ui.status(_('applying %s\n') % patchurl)
3790 ui.status(_('applying %s\n') % patchurl)
3790 patchfile = hg.openpath(ui, patchurl)
3791 patchfile = hg.openpath(ui, patchurl)
3791
3792
3792 haspatch = False
3793 haspatch = False
3793 for hunk in patch.split(patchfile):
3794 for hunk in patch.split(patchfile):
3794 (msg, node) = tryone(ui, hunk, parents)
3795 (msg, node) = tryone(ui, hunk, parents)
3795 if msg:
3796 if msg:
3796 haspatch = True
3797 haspatch = True
3797 ui.note(msg + '\n')
3798 ui.note(msg + '\n')
3798 if update or opts.get('exact'):
3799 if update or opts.get('exact'):
3799 parents = repo.parents()
3800 parents = repo.parents()
3800 else:
3801 else:
3801 parents = [repo[node]]
3802 parents = [repo[node]]
3802
3803
3803 if not haspatch:
3804 if not haspatch:
3804 raise util.Abort(_('%s: no diffs found') % patchurl)
3805 raise util.Abort(_('%s: no diffs found') % patchurl)
3805
3806
3806 if tr:
3807 if tr:
3807 tr.close()
3808 tr.close()
3808 if msgs:
3809 if msgs:
3809 repo.savecommitmessage('\n* * *\n'.join(msgs))
3810 repo.savecommitmessage('\n* * *\n'.join(msgs))
3810 except: # re-raises
3811 except: # re-raises
3811 # wlock.release() indirectly calls dirstate.write(): since
3812 # wlock.release() indirectly calls dirstate.write(): since
3812 # we're crashing, we do not want to change the working dir
3813 # we're crashing, we do not want to change the working dir
3813 # parent after all, so make sure it writes nothing
3814 # parent after all, so make sure it writes nothing
3814 repo.dirstate.invalidate()
3815 repo.dirstate.invalidate()
3815 raise
3816 raise
3816 finally:
3817 finally:
3817 if tr:
3818 if tr:
3818 tr.release()
3819 tr.release()
3819 release(lock, wlock)
3820 release(lock, wlock)
3820
3821
3821 @command('incoming|in',
3822 @command('incoming|in',
3822 [('f', 'force', None,
3823 [('f', 'force', None,
3823 _('run even if remote repository is unrelated')),
3824 _('run even if remote repository is unrelated')),
3824 ('n', 'newest-first', None, _('show newest record first')),
3825 ('n', 'newest-first', None, _('show newest record first')),
3825 ('', 'bundle', '',
3826 ('', 'bundle', '',
3826 _('file to store the bundles into'), _('FILE')),
3827 _('file to store the bundles into'), _('FILE')),
3827 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3828 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3828 ('B', 'bookmarks', False, _("compare bookmarks")),
3829 ('B', 'bookmarks', False, _("compare bookmarks")),
3829 ('b', 'branch', [],
3830 ('b', 'branch', [],
3830 _('a specific branch you would like to pull'), _('BRANCH')),
3831 _('a specific branch you would like to pull'), _('BRANCH')),
3831 ] + logopts + remoteopts + subrepoopts,
3832 ] + logopts + remoteopts + subrepoopts,
3832 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3833 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3833 def incoming(ui, repo, source="default", **opts):
3834 def incoming(ui, repo, source="default", **opts):
3834 """show new changesets found in source
3835 """show new changesets found in source
3835
3836
3836 Show new changesets found in the specified path/URL or the default
3837 Show new changesets found in the specified path/URL or the default
3837 pull location. These are the changesets that would have been pulled
3838 pull location. These are the changesets that would have been pulled
3838 if a pull at the time you issued this command.
3839 if a pull at the time you issued this command.
3839
3840
3840 For remote repository, using --bundle avoids downloading the
3841 For remote repository, using --bundle avoids downloading the
3841 changesets twice if the incoming is followed by a pull.
3842 changesets twice if the incoming is followed by a pull.
3842
3843
3843 See pull for valid source format details.
3844 See pull for valid source format details.
3844
3845
3845 Returns 0 if there are incoming changes, 1 otherwise.
3846 Returns 0 if there are incoming changes, 1 otherwise.
3846 """
3847 """
3847 if opts.get('graph'):
3848 if opts.get('graph'):
3848 cmdutil.checkunsupportedgraphflags([], opts)
3849 cmdutil.checkunsupportedgraphflags([], opts)
3849 def display(other, chlist, displayer):
3850 def display(other, chlist, displayer):
3850 revdag = cmdutil.graphrevs(other, chlist, opts)
3851 revdag = cmdutil.graphrevs(other, chlist, opts)
3851 showparents = [ctx.node() for ctx in repo[None].parents()]
3852 showparents = [ctx.node() for ctx in repo[None].parents()]
3852 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3853 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3853 graphmod.asciiedges)
3854 graphmod.asciiedges)
3854
3855
3855 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3856 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3856 return 0
3857 return 0
3857
3858
3858 if opts.get('bundle') and opts.get('subrepos'):
3859 if opts.get('bundle') and opts.get('subrepos'):
3859 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3860 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3860
3861
3861 if opts.get('bookmarks'):
3862 if opts.get('bookmarks'):
3862 source, branches = hg.parseurl(ui.expandpath(source),
3863 source, branches = hg.parseurl(ui.expandpath(source),
3863 opts.get('branch'))
3864 opts.get('branch'))
3864 other = hg.peer(repo, opts, source)
3865 other = hg.peer(repo, opts, source)
3865 if 'bookmarks' not in other.listkeys('namespaces'):
3866 if 'bookmarks' not in other.listkeys('namespaces'):
3866 ui.warn(_("remote doesn't support bookmarks\n"))
3867 ui.warn(_("remote doesn't support bookmarks\n"))
3867 return 0
3868 return 0
3868 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3869 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3869 return bookmarks.diff(ui, repo, other)
3870 return bookmarks.diff(ui, repo, other)
3870
3871
3871 repo._subtoppath = ui.expandpath(source)
3872 repo._subtoppath = ui.expandpath(source)
3872 try:
3873 try:
3873 return hg.incoming(ui, repo, source, opts)
3874 return hg.incoming(ui, repo, source, opts)
3874 finally:
3875 finally:
3875 del repo._subtoppath
3876 del repo._subtoppath
3876
3877
3877
3878
3878 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3879 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3879 def init(ui, dest=".", **opts):
3880 def init(ui, dest=".", **opts):
3880 """create a new repository in the given directory
3881 """create a new repository in the given directory
3881
3882
3882 Initialize a new repository in the given directory. If the given
3883 Initialize a new repository in the given directory. If the given
3883 directory does not exist, it will be created.
3884 directory does not exist, it will be created.
3884
3885
3885 If no directory is given, the current directory is used.
3886 If no directory is given, the current directory is used.
3886
3887
3887 It is possible to specify an ``ssh://`` URL as the destination.
3888 It is possible to specify an ``ssh://`` URL as the destination.
3888 See :hg:`help urls` for more information.
3889 See :hg:`help urls` for more information.
3889
3890
3890 Returns 0 on success.
3891 Returns 0 on success.
3891 """
3892 """
3892 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3893 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3893
3894
3894 @command('locate',
3895 @command('locate',
3895 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3896 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3896 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3897 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3897 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3898 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3898 ] + walkopts,
3899 ] + walkopts,
3899 _('[OPTION]... [PATTERN]...'))
3900 _('[OPTION]... [PATTERN]...'))
3900 def locate(ui, repo, *pats, **opts):
3901 def locate(ui, repo, *pats, **opts):
3901 """locate files matching specific patterns
3902 """locate files matching specific patterns
3902
3903
3903 Print files under Mercurial control in the working directory whose
3904 Print files under Mercurial control in the working directory whose
3904 names match the given patterns.
3905 names match the given patterns.
3905
3906
3906 By default, this command searches all directories in the working
3907 By default, this command searches all directories in the working
3907 directory. To search just the current directory and its
3908 directory. To search just the current directory and its
3908 subdirectories, use "--include .".
3909 subdirectories, use "--include .".
3909
3910
3910 If no patterns are given to match, this command prints the names
3911 If no patterns are given to match, this command prints the names
3911 of all files under Mercurial control in the working directory.
3912 of all files under Mercurial control in the working directory.
3912
3913
3913 If you want to feed the output of this command into the "xargs"
3914 If you want to feed the output of this command into the "xargs"
3914 command, use the -0 option to both this command and "xargs". This
3915 command, use the -0 option to both this command and "xargs". This
3915 will avoid the problem of "xargs" treating single filenames that
3916 will avoid the problem of "xargs" treating single filenames that
3916 contain whitespace as multiple filenames.
3917 contain whitespace as multiple filenames.
3917
3918
3918 Returns 0 if a match is found, 1 otherwise.
3919 Returns 0 if a match is found, 1 otherwise.
3919 """
3920 """
3920 end = opts.get('print0') and '\0' or '\n'
3921 end = opts.get('print0') and '\0' or '\n'
3921 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3922 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3922
3923
3923 ret = 1
3924 ret = 1
3924 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3925 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3925 m.bad = lambda x, y: False
3926 m.bad = lambda x, y: False
3926 for abs in repo[rev].walk(m):
3927 for abs in repo[rev].walk(m):
3927 if not rev and abs not in repo.dirstate:
3928 if not rev and abs not in repo.dirstate:
3928 continue
3929 continue
3929 if opts.get('fullpath'):
3930 if opts.get('fullpath'):
3930 ui.write(repo.wjoin(abs), end)
3931 ui.write(repo.wjoin(abs), end)
3931 else:
3932 else:
3932 ui.write(((pats and m.rel(abs)) or abs), end)
3933 ui.write(((pats and m.rel(abs)) or abs), end)
3933 ret = 0
3934 ret = 0
3934
3935
3935 return ret
3936 return ret
3936
3937
3937 @command('^log|history',
3938 @command('^log|history',
3938 [('f', 'follow', None,
3939 [('f', 'follow', None,
3939 _('follow changeset history, or file history across copies and renames')),
3940 _('follow changeset history, or file history across copies and renames')),
3940 ('', 'follow-first', None,
3941 ('', 'follow-first', None,
3941 _('only follow the first parent of merge changesets (DEPRECATED)')),
3942 _('only follow the first parent of merge changesets (DEPRECATED)')),
3942 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3943 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3943 ('C', 'copies', None, _('show copied files')),
3944 ('C', 'copies', None, _('show copied files')),
3944 ('k', 'keyword', [],
3945 ('k', 'keyword', [],
3945 _('do case-insensitive search for a given text'), _('TEXT')),
3946 _('do case-insensitive search for a given text'), _('TEXT')),
3946 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3947 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3947 ('', 'removed', None, _('include revisions where files were removed')),
3948 ('', 'removed', None, _('include revisions where files were removed')),
3948 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3949 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3949 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3950 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3950 ('', 'only-branch', [],
3951 ('', 'only-branch', [],
3951 _('show only changesets within the given named branch (DEPRECATED)'),
3952 _('show only changesets within the given named branch (DEPRECATED)'),
3952 _('BRANCH')),
3953 _('BRANCH')),
3953 ('b', 'branch', [],
3954 ('b', 'branch', [],
3954 _('show changesets within the given named branch'), _('BRANCH')),
3955 _('show changesets within the given named branch'), _('BRANCH')),
3955 ('P', 'prune', [],
3956 ('P', 'prune', [],
3956 _('do not display revision or any of its ancestors'), _('REV')),
3957 _('do not display revision or any of its ancestors'), _('REV')),
3957 ] + logopts + walkopts,
3958 ] + logopts + walkopts,
3958 _('[OPTION]... [FILE]'))
3959 _('[OPTION]... [FILE]'))
3959 def log(ui, repo, *pats, **opts):
3960 def log(ui, repo, *pats, **opts):
3960 """show revision history of entire repository or files
3961 """show revision history of entire repository or files
3961
3962
3962 Print the revision history of the specified files or the entire
3963 Print the revision history of the specified files or the entire
3963 project.
3964 project.
3964
3965
3965 If no revision range is specified, the default is ``tip:0`` unless
3966 If no revision range is specified, the default is ``tip:0`` unless
3966 --follow is set, in which case the working directory parent is
3967 --follow is set, in which case the working directory parent is
3967 used as the starting revision.
3968 used as the starting revision.
3968
3969
3969 File history is shown without following rename or copy history of
3970 File history is shown without following rename or copy history of
3970 files. Use -f/--follow with a filename to follow history across
3971 files. Use -f/--follow with a filename to follow history across
3971 renames and copies. --follow without a filename will only show
3972 renames and copies. --follow without a filename will only show
3972 ancestors or descendants of the starting revision.
3973 ancestors or descendants of the starting revision.
3973
3974
3974 By default this command prints revision number and changeset id,
3975 By default this command prints revision number and changeset id,
3975 tags, non-trivial parents, user, date and time, and a summary for
3976 tags, non-trivial parents, user, date and time, and a summary for
3976 each commit. When the -v/--verbose switch is used, the list of
3977 each commit. When the -v/--verbose switch is used, the list of
3977 changed files and full commit message are shown.
3978 changed files and full commit message are shown.
3978
3979
3979 .. note::
3980 .. note::
3980
3981
3981 log -p/--patch may generate unexpected diff output for merge
3982 log -p/--patch may generate unexpected diff output for merge
3982 changesets, as it will only compare the merge changeset against
3983 changesets, as it will only compare the merge changeset against
3983 its first parent. Also, only files different from BOTH parents
3984 its first parent. Also, only files different from BOTH parents
3984 will appear in files:.
3985 will appear in files:.
3985
3986
3986 .. note::
3987 .. note::
3987
3988
3988 for performance reasons, log FILE may omit duplicate changes
3989 for performance reasons, log FILE may omit duplicate changes
3989 made on branches and will not show deletions. To see all
3990 made on branches and will not show deletions. To see all
3990 changes including duplicates and deletions, use the --removed
3991 changes including duplicates and deletions, use the --removed
3991 switch.
3992 switch.
3992
3993
3993 .. container:: verbose
3994 .. container:: verbose
3994
3995
3995 Some examples:
3996 Some examples:
3996
3997
3997 - changesets with full descriptions and file lists::
3998 - changesets with full descriptions and file lists::
3998
3999
3999 hg log -v
4000 hg log -v
4000
4001
4001 - changesets ancestral to the working directory::
4002 - changesets ancestral to the working directory::
4002
4003
4003 hg log -f
4004 hg log -f
4004
4005
4005 - last 10 commits on the current branch::
4006 - last 10 commits on the current branch::
4006
4007
4007 hg log -l 10 -b .
4008 hg log -l 10 -b .
4008
4009
4009 - changesets showing all modifications of a file, including removals::
4010 - changesets showing all modifications of a file, including removals::
4010
4011
4011 hg log --removed file.c
4012 hg log --removed file.c
4012
4013
4013 - all changesets that touch a directory, with diffs, excluding merges::
4014 - all changesets that touch a directory, with diffs, excluding merges::
4014
4015
4015 hg log -Mp lib/
4016 hg log -Mp lib/
4016
4017
4017 - all revision numbers that match a keyword::
4018 - all revision numbers that match a keyword::
4018
4019
4019 hg log -k bug --template "{rev}\\n"
4020 hg log -k bug --template "{rev}\\n"
4020
4021
4021 - check if a given changeset is included is a tagged release::
4022 - check if a given changeset is included is a tagged release::
4022
4023
4023 hg log -r "a21ccf and ancestor(1.9)"
4024 hg log -r "a21ccf and ancestor(1.9)"
4024
4025
4025 - find all changesets by some user in a date range::
4026 - find all changesets by some user in a date range::
4026
4027
4027 hg log -k alice -d "may 2008 to jul 2008"
4028 hg log -k alice -d "may 2008 to jul 2008"
4028
4029
4029 - summary of all changesets after the last tag::
4030 - summary of all changesets after the last tag::
4030
4031
4031 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4032 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4032
4033
4033 See :hg:`help dates` for a list of formats valid for -d/--date.
4034 See :hg:`help dates` for a list of formats valid for -d/--date.
4034
4035
4035 See :hg:`help revisions` and :hg:`help revsets` for more about
4036 See :hg:`help revisions` and :hg:`help revsets` for more about
4036 specifying revisions.
4037 specifying revisions.
4037
4038
4038 See :hg:`help templates` for more about pre-packaged styles and
4039 See :hg:`help templates` for more about pre-packaged styles and
4039 specifying custom templates.
4040 specifying custom templates.
4040
4041
4041 Returns 0 on success.
4042 Returns 0 on success.
4042 """
4043 """
4043 if opts.get('graph'):
4044 if opts.get('graph'):
4044 return cmdutil.graphlog(ui, repo, *pats, **opts)
4045 return cmdutil.graphlog(ui, repo, *pats, **opts)
4045
4046
4046 matchfn = scmutil.match(repo[None], pats, opts)
4047 matchfn = scmutil.match(repo[None], pats, opts)
4047 limit = cmdutil.loglimit(opts)
4048 limit = cmdutil.loglimit(opts)
4048 count = 0
4049 count = 0
4049
4050
4050 getrenamed, endrev = None, None
4051 getrenamed, endrev = None, None
4051 if opts.get('copies'):
4052 if opts.get('copies'):
4052 if opts.get('rev'):
4053 if opts.get('rev'):
4053 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4054 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4054 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4055 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4055
4056
4056 df = False
4057 df = False
4057 if opts.get("date"):
4058 if opts.get("date"):
4058 df = util.matchdate(opts["date"])
4059 df = util.matchdate(opts["date"])
4059
4060
4060 branches = opts.get('branch', []) + opts.get('only_branch', [])
4061 branches = opts.get('branch', []) + opts.get('only_branch', [])
4061 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4062 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4062
4063
4063 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4064 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4064 def prep(ctx, fns):
4065 def prep(ctx, fns):
4065 rev = ctx.rev()
4066 rev = ctx.rev()
4066 parents = [p for p in repo.changelog.parentrevs(rev)
4067 parents = [p for p in repo.changelog.parentrevs(rev)
4067 if p != nullrev]
4068 if p != nullrev]
4068 if opts.get('no_merges') and len(parents) == 2:
4069 if opts.get('no_merges') and len(parents) == 2:
4069 return
4070 return
4070 if opts.get('only_merges') and len(parents) != 2:
4071 if opts.get('only_merges') and len(parents) != 2:
4071 return
4072 return
4072 if opts.get('branch') and ctx.branch() not in opts['branch']:
4073 if opts.get('branch') and ctx.branch() not in opts['branch']:
4073 return
4074 return
4074 if df and not df(ctx.date()[0]):
4075 if df and not df(ctx.date()[0]):
4075 return
4076 return
4076
4077
4077 lower = encoding.lower
4078 lower = encoding.lower
4078 if opts.get('user'):
4079 if opts.get('user'):
4079 luser = lower(ctx.user())
4080 luser = lower(ctx.user())
4080 for k in [lower(x) for x in opts['user']]:
4081 for k in [lower(x) for x in opts['user']]:
4081 if (k in luser):
4082 if (k in luser):
4082 break
4083 break
4083 else:
4084 else:
4084 return
4085 return
4085 if opts.get('keyword'):
4086 if opts.get('keyword'):
4086 luser = lower(ctx.user())
4087 luser = lower(ctx.user())
4087 ldesc = lower(ctx.description())
4088 ldesc = lower(ctx.description())
4088 lfiles = lower(" ".join(ctx.files()))
4089 lfiles = lower(" ".join(ctx.files()))
4089 for k in [lower(x) for x in opts['keyword']]:
4090 for k in [lower(x) for x in opts['keyword']]:
4090 if (k in luser or k in ldesc or k in lfiles):
4091 if (k in luser or k in ldesc or k in lfiles):
4091 break
4092 break
4092 else:
4093 else:
4093 return
4094 return
4094
4095
4095 copies = None
4096 copies = None
4096 if getrenamed is not None and rev:
4097 if getrenamed is not None and rev:
4097 copies = []
4098 copies = []
4098 for fn in ctx.files():
4099 for fn in ctx.files():
4099 rename = getrenamed(fn, rev)
4100 rename = getrenamed(fn, rev)
4100 if rename:
4101 if rename:
4101 copies.append((fn, rename[0]))
4102 copies.append((fn, rename[0]))
4102
4103
4103 revmatchfn = None
4104 revmatchfn = None
4104 if opts.get('patch') or opts.get('stat'):
4105 if opts.get('patch') or opts.get('stat'):
4105 if opts.get('follow') or opts.get('follow_first'):
4106 if opts.get('follow') or opts.get('follow_first'):
4106 # note: this might be wrong when following through merges
4107 # note: this might be wrong when following through merges
4107 revmatchfn = scmutil.match(repo[None], fns, default='path')
4108 revmatchfn = scmutil.match(repo[None], fns, default='path')
4108 else:
4109 else:
4109 revmatchfn = matchfn
4110 revmatchfn = matchfn
4110
4111
4111 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4112 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4112
4113
4113 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4114 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4114 if displayer.flush(ctx.rev()):
4115 if displayer.flush(ctx.rev()):
4115 count += 1
4116 count += 1
4116 if count == limit:
4117 if count == limit:
4117 break
4118 break
4118 displayer.close()
4119 displayer.close()
4119
4120
4120 @command('manifest',
4121 @command('manifest',
4121 [('r', 'rev', '', _('revision to display'), _('REV')),
4122 [('r', 'rev', '', _('revision to display'), _('REV')),
4122 ('', 'all', False, _("list files from all revisions"))],
4123 ('', 'all', False, _("list files from all revisions"))],
4123 _('[-r REV]'))
4124 _('[-r REV]'))
4124 def manifest(ui, repo, node=None, rev=None, **opts):
4125 def manifest(ui, repo, node=None, rev=None, **opts):
4125 """output the current or given revision of the project manifest
4126 """output the current or given revision of the project manifest
4126
4127
4127 Print a list of version controlled files for the given revision.
4128 Print a list of version controlled files for the given revision.
4128 If no revision is given, the first parent of the working directory
4129 If no revision is given, the first parent of the working directory
4129 is used, or the null revision if no revision is checked out.
4130 is used, or the null revision if no revision is checked out.
4130
4131
4131 With -v, print file permissions, symlink and executable bits.
4132 With -v, print file permissions, symlink and executable bits.
4132 With --debug, print file revision hashes.
4133 With --debug, print file revision hashes.
4133
4134
4134 If option --all is specified, the list of all files from all revisions
4135 If option --all is specified, the list of all files from all revisions
4135 is printed. This includes deleted and renamed files.
4136 is printed. This includes deleted and renamed files.
4136
4137
4137 Returns 0 on success.
4138 Returns 0 on success.
4138 """
4139 """
4139
4140
4140 fm = ui.formatter('manifest', opts)
4141 fm = ui.formatter('manifest', opts)
4141
4142
4142 if opts.get('all'):
4143 if opts.get('all'):
4143 if rev or node:
4144 if rev or node:
4144 raise util.Abort(_("can't specify a revision with --all"))
4145 raise util.Abort(_("can't specify a revision with --all"))
4145
4146
4146 res = []
4147 res = []
4147 prefix = "data/"
4148 prefix = "data/"
4148 suffix = ".i"
4149 suffix = ".i"
4149 plen = len(prefix)
4150 plen = len(prefix)
4150 slen = len(suffix)
4151 slen = len(suffix)
4151 lock = repo.lock()
4152 lock = repo.lock()
4152 try:
4153 try:
4153 for fn, b, size in repo.store.datafiles():
4154 for fn, b, size in repo.store.datafiles():
4154 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4155 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4155 res.append(fn[plen:-slen])
4156 res.append(fn[plen:-slen])
4156 finally:
4157 finally:
4157 lock.release()
4158 lock.release()
4158 for f in res:
4159 for f in res:
4159 fm.startitem()
4160 fm.startitem()
4160 fm.write("path", '%s\n', f)
4161 fm.write("path", '%s\n', f)
4161 fm.end()
4162 fm.end()
4162 return
4163 return
4163
4164
4164 if rev and node:
4165 if rev and node:
4165 raise util.Abort(_("please specify just one revision"))
4166 raise util.Abort(_("please specify just one revision"))
4166
4167
4167 if not node:
4168 if not node:
4168 node = rev
4169 node = rev
4169
4170
4170 char = {'l': '@', 'x': '*', '': ''}
4171 char = {'l': '@', 'x': '*', '': ''}
4171 mode = {'l': '644', 'x': '755', '': '644'}
4172 mode = {'l': '644', 'x': '755', '': '644'}
4172 ctx = scmutil.revsingle(repo, node)
4173 ctx = scmutil.revsingle(repo, node)
4173 mf = ctx.manifest()
4174 mf = ctx.manifest()
4174 for f in ctx:
4175 for f in ctx:
4175 fm.startitem()
4176 fm.startitem()
4176 fl = ctx[f].flags()
4177 fl = ctx[f].flags()
4177 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4178 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4178 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4179 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4179 fm.write('path', '%s\n', f)
4180 fm.write('path', '%s\n', f)
4180 fm.end()
4181 fm.end()
4181
4182
4182 @command('^merge',
4183 @command('^merge',
4183 [('f', 'force', None,
4184 [('f', 'force', None,
4184 _('force a merge including outstanding changes (DEPRECATED)')),
4185 _('force a merge including outstanding changes (DEPRECATED)')),
4185 ('r', 'rev', '', _('revision to merge'), _('REV')),
4186 ('r', 'rev', '', _('revision to merge'), _('REV')),
4186 ('P', 'preview', None,
4187 ('P', 'preview', None,
4187 _('review revisions to merge (no merge is performed)'))
4188 _('review revisions to merge (no merge is performed)'))
4188 ] + mergetoolopts,
4189 ] + mergetoolopts,
4189 _('[-P] [-f] [[-r] REV]'))
4190 _('[-P] [-f] [[-r] REV]'))
4190 def merge(ui, repo, node=None, **opts):
4191 def merge(ui, repo, node=None, **opts):
4191 """merge working directory with another revision
4192 """merge working directory with another revision
4192
4193
4193 The current working directory is updated with all changes made in
4194 The current working directory is updated with all changes made in
4194 the requested revision since the last common predecessor revision.
4195 the requested revision since the last common predecessor revision.
4195
4196
4196 Files that changed between either parent are marked as changed for
4197 Files that changed between either parent are marked as changed for
4197 the next commit and a commit must be performed before any further
4198 the next commit and a commit must be performed before any further
4198 updates to the repository are allowed. The next commit will have
4199 updates to the repository are allowed. The next commit will have
4199 two parents.
4200 two parents.
4200
4201
4201 ``--tool`` can be used to specify the merge tool used for file
4202 ``--tool`` can be used to specify the merge tool used for file
4202 merges. It overrides the HGMERGE environment variable and your
4203 merges. It overrides the HGMERGE environment variable and your
4203 configuration files. See :hg:`help merge-tools` for options.
4204 configuration files. See :hg:`help merge-tools` for options.
4204
4205
4205 If no revision is specified, the working directory's parent is a
4206 If no revision is specified, the working directory's parent is a
4206 head revision, and the current branch contains exactly one other
4207 head revision, and the current branch contains exactly one other
4207 head, the other head is merged with by default. Otherwise, an
4208 head, the other head is merged with by default. Otherwise, an
4208 explicit revision with which to merge with must be provided.
4209 explicit revision with which to merge with must be provided.
4209
4210
4210 :hg:`resolve` must be used to resolve unresolved files.
4211 :hg:`resolve` must be used to resolve unresolved files.
4211
4212
4212 To undo an uncommitted merge, use :hg:`update --clean .` which
4213 To undo an uncommitted merge, use :hg:`update --clean .` which
4213 will check out a clean copy of the original merge parent, losing
4214 will check out a clean copy of the original merge parent, losing
4214 all changes.
4215 all changes.
4215
4216
4216 Returns 0 on success, 1 if there are unresolved files.
4217 Returns 0 on success, 1 if there are unresolved files.
4217 """
4218 """
4218
4219
4219 if opts.get('rev') and node:
4220 if opts.get('rev') and node:
4220 raise util.Abort(_("please specify just one revision"))
4221 raise util.Abort(_("please specify just one revision"))
4221 if not node:
4222 if not node:
4222 node = opts.get('rev')
4223 node = opts.get('rev')
4223
4224
4224 if node:
4225 if node:
4225 node = scmutil.revsingle(repo, node).node()
4226 node = scmutil.revsingle(repo, node).node()
4226
4227
4227 if not node and repo._bookmarkcurrent:
4228 if not node and repo._bookmarkcurrent:
4228 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4229 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4229 curhead = repo[repo._bookmarkcurrent].node()
4230 curhead = repo[repo._bookmarkcurrent].node()
4230 if len(bmheads) == 2:
4231 if len(bmheads) == 2:
4231 if curhead == bmheads[0]:
4232 if curhead == bmheads[0]:
4232 node = bmheads[1]
4233 node = bmheads[1]
4233 else:
4234 else:
4234 node = bmheads[0]
4235 node = bmheads[0]
4235 elif len(bmheads) > 2:
4236 elif len(bmheads) > 2:
4236 raise util.Abort(_("multiple matching bookmarks to merge - "
4237 raise util.Abort(_("multiple matching bookmarks to merge - "
4237 "please merge with an explicit rev or bookmark"),
4238 "please merge with an explicit rev or bookmark"),
4238 hint=_("run 'hg heads' to see all heads"))
4239 hint=_("run 'hg heads' to see all heads"))
4239 elif len(bmheads) <= 1:
4240 elif len(bmheads) <= 1:
4240 raise util.Abort(_("no matching bookmark to merge - "
4241 raise util.Abort(_("no matching bookmark to merge - "
4241 "please merge with an explicit rev or bookmark"),
4242 "please merge with an explicit rev or bookmark"),
4242 hint=_("run 'hg heads' to see all heads"))
4243 hint=_("run 'hg heads' to see all heads"))
4243
4244
4244 if not node and not repo._bookmarkcurrent:
4245 if not node and not repo._bookmarkcurrent:
4245 branch = repo[None].branch()
4246 branch = repo[None].branch()
4246 bheads = repo.branchheads(branch)
4247 bheads = repo.branchheads(branch)
4247 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4248 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4248
4249
4249 if len(nbhs) > 2:
4250 if len(nbhs) > 2:
4250 raise util.Abort(_("branch '%s' has %d heads - "
4251 raise util.Abort(_("branch '%s' has %d heads - "
4251 "please merge with an explicit rev")
4252 "please merge with an explicit rev")
4252 % (branch, len(bheads)),
4253 % (branch, len(bheads)),
4253 hint=_("run 'hg heads .' to see heads"))
4254 hint=_("run 'hg heads .' to see heads"))
4254
4255
4255 parent = repo.dirstate.p1()
4256 parent = repo.dirstate.p1()
4256 if len(nbhs) <= 1:
4257 if len(nbhs) <= 1:
4257 if len(bheads) > 1:
4258 if len(bheads) > 1:
4258 raise util.Abort(_("heads are bookmarked - "
4259 raise util.Abort(_("heads are bookmarked - "
4259 "please merge with an explicit rev"),
4260 "please merge with an explicit rev"),
4260 hint=_("run 'hg heads' to see all heads"))
4261 hint=_("run 'hg heads' to see all heads"))
4261 if len(repo.heads()) > 1:
4262 if len(repo.heads()) > 1:
4262 raise util.Abort(_("branch '%s' has one head - "
4263 raise util.Abort(_("branch '%s' has one head - "
4263 "please merge with an explicit rev")
4264 "please merge with an explicit rev")
4264 % branch,
4265 % branch,
4265 hint=_("run 'hg heads' to see all heads"))
4266 hint=_("run 'hg heads' to see all heads"))
4266 msg, hint = _('nothing to merge'), None
4267 msg, hint = _('nothing to merge'), None
4267 if parent != repo.lookup(branch):
4268 if parent != repo.lookup(branch):
4268 hint = _("use 'hg update' instead")
4269 hint = _("use 'hg update' instead")
4269 raise util.Abort(msg, hint=hint)
4270 raise util.Abort(msg, hint=hint)
4270
4271
4271 if parent not in bheads:
4272 if parent not in bheads:
4272 raise util.Abort(_('working directory not at a head revision'),
4273 raise util.Abort(_('working directory not at a head revision'),
4273 hint=_("use 'hg update' or merge with an "
4274 hint=_("use 'hg update' or merge with an "
4274 "explicit revision"))
4275 "explicit revision"))
4275 if parent == nbhs[0]:
4276 if parent == nbhs[0]:
4276 node = nbhs[-1]
4277 node = nbhs[-1]
4277 else:
4278 else:
4278 node = nbhs[0]
4279 node = nbhs[0]
4279
4280
4280 if opts.get('preview'):
4281 if opts.get('preview'):
4281 # find nodes that are ancestors of p2 but not of p1
4282 # find nodes that are ancestors of p2 but not of p1
4282 p1 = repo.lookup('.')
4283 p1 = repo.lookup('.')
4283 p2 = repo.lookup(node)
4284 p2 = repo.lookup(node)
4284 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4285 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4285
4286
4286 displayer = cmdutil.show_changeset(ui, repo, opts)
4287 displayer = cmdutil.show_changeset(ui, repo, opts)
4287 for node in nodes:
4288 for node in nodes:
4288 displayer.show(repo[node])
4289 displayer.show(repo[node])
4289 displayer.close()
4290 displayer.close()
4290 return 0
4291 return 0
4291
4292
4292 try:
4293 try:
4293 # ui.forcemerge is an internal variable, do not document
4294 # ui.forcemerge is an internal variable, do not document
4294 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4295 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4295 return hg.merge(repo, node, force=opts.get('force'))
4296 return hg.merge(repo, node, force=opts.get('force'))
4296 finally:
4297 finally:
4297 ui.setconfig('ui', 'forcemerge', '')
4298 ui.setconfig('ui', 'forcemerge', '')
4298
4299
4299 @command('outgoing|out',
4300 @command('outgoing|out',
4300 [('f', 'force', None, _('run even when the destination is unrelated')),
4301 [('f', 'force', None, _('run even when the destination is unrelated')),
4301 ('r', 'rev', [],
4302 ('r', 'rev', [],
4302 _('a changeset intended to be included in the destination'), _('REV')),
4303 _('a changeset intended to be included in the destination'), _('REV')),
4303 ('n', 'newest-first', None, _('show newest record first')),
4304 ('n', 'newest-first', None, _('show newest record first')),
4304 ('B', 'bookmarks', False, _('compare bookmarks')),
4305 ('B', 'bookmarks', False, _('compare bookmarks')),
4305 ('b', 'branch', [], _('a specific branch you would like to push'),
4306 ('b', 'branch', [], _('a specific branch you would like to push'),
4306 _('BRANCH')),
4307 _('BRANCH')),
4307 ] + logopts + remoteopts + subrepoopts,
4308 ] + logopts + remoteopts + subrepoopts,
4308 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4309 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4309 def outgoing(ui, repo, dest=None, **opts):
4310 def outgoing(ui, repo, dest=None, **opts):
4310 """show changesets not found in the destination
4311 """show changesets not found in the destination
4311
4312
4312 Show changesets not found in the specified destination repository
4313 Show changesets not found in the specified destination repository
4313 or the default push location. These are the changesets that would
4314 or the default push location. These are the changesets that would
4314 be pushed if a push was requested.
4315 be pushed if a push was requested.
4315
4316
4316 See pull for details of valid destination formats.
4317 See pull for details of valid destination formats.
4317
4318
4318 Returns 0 if there are outgoing changes, 1 otherwise.
4319 Returns 0 if there are outgoing changes, 1 otherwise.
4319 """
4320 """
4320 if opts.get('graph'):
4321 if opts.get('graph'):
4321 cmdutil.checkunsupportedgraphflags([], opts)
4322 cmdutil.checkunsupportedgraphflags([], opts)
4322 o = hg._outgoing(ui, repo, dest, opts)
4323 o = hg._outgoing(ui, repo, dest, opts)
4323 if o is None:
4324 if o is None:
4324 return
4325 return
4325
4326
4326 revdag = cmdutil.graphrevs(repo, o, opts)
4327 revdag = cmdutil.graphrevs(repo, o, opts)
4327 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4328 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4328 showparents = [ctx.node() for ctx in repo[None].parents()]
4329 showparents = [ctx.node() for ctx in repo[None].parents()]
4329 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4330 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4330 graphmod.asciiedges)
4331 graphmod.asciiedges)
4331 return 0
4332 return 0
4332
4333
4333 if opts.get('bookmarks'):
4334 if opts.get('bookmarks'):
4334 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4335 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4335 dest, branches = hg.parseurl(dest, opts.get('branch'))
4336 dest, branches = hg.parseurl(dest, opts.get('branch'))
4336 other = hg.peer(repo, opts, dest)
4337 other = hg.peer(repo, opts, dest)
4337 if 'bookmarks' not in other.listkeys('namespaces'):
4338 if 'bookmarks' not in other.listkeys('namespaces'):
4338 ui.warn(_("remote doesn't support bookmarks\n"))
4339 ui.warn(_("remote doesn't support bookmarks\n"))
4339 return 0
4340 return 0
4340 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4341 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4341 return bookmarks.diff(ui, other, repo)
4342 return bookmarks.diff(ui, other, repo)
4342
4343
4343 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4344 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4344 try:
4345 try:
4345 return hg.outgoing(ui, repo, dest, opts)
4346 return hg.outgoing(ui, repo, dest, opts)
4346 finally:
4347 finally:
4347 del repo._subtoppath
4348 del repo._subtoppath
4348
4349
4349 @command('parents',
4350 @command('parents',
4350 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4351 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4351 ] + templateopts,
4352 ] + templateopts,
4352 _('[-r REV] [FILE]'))
4353 _('[-r REV] [FILE]'))
4353 def parents(ui, repo, file_=None, **opts):
4354 def parents(ui, repo, file_=None, **opts):
4354 """show the parents of the working directory or revision
4355 """show the parents of the working directory or revision
4355
4356
4356 Print the working directory's parent revisions. If a revision is
4357 Print the working directory's parent revisions. If a revision is
4357 given via -r/--rev, the parent of that revision will be printed.
4358 given via -r/--rev, the parent of that revision will be printed.
4358 If a file argument is given, the revision in which the file was
4359 If a file argument is given, the revision in which the file was
4359 last changed (before the working directory revision or the
4360 last changed (before the working directory revision or the
4360 argument to --rev if given) is printed.
4361 argument to --rev if given) is printed.
4361
4362
4362 Returns 0 on success.
4363 Returns 0 on success.
4363 """
4364 """
4364
4365
4365 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4366 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4366
4367
4367 if file_:
4368 if file_:
4368 m = scmutil.match(ctx, (file_,), opts)
4369 m = scmutil.match(ctx, (file_,), opts)
4369 if m.anypats() or len(m.files()) != 1:
4370 if m.anypats() or len(m.files()) != 1:
4370 raise util.Abort(_('can only specify an explicit filename'))
4371 raise util.Abort(_('can only specify an explicit filename'))
4371 file_ = m.files()[0]
4372 file_ = m.files()[0]
4372 filenodes = []
4373 filenodes = []
4373 for cp in ctx.parents():
4374 for cp in ctx.parents():
4374 if not cp:
4375 if not cp:
4375 continue
4376 continue
4376 try:
4377 try:
4377 filenodes.append(cp.filenode(file_))
4378 filenodes.append(cp.filenode(file_))
4378 except error.LookupError:
4379 except error.LookupError:
4379 pass
4380 pass
4380 if not filenodes:
4381 if not filenodes:
4381 raise util.Abort(_("'%s' not found in manifest!") % file_)
4382 raise util.Abort(_("'%s' not found in manifest!") % file_)
4382 p = []
4383 p = []
4383 for fn in filenodes:
4384 for fn in filenodes:
4384 fctx = repo.filectx(file_, fileid=fn)
4385 fctx = repo.filectx(file_, fileid=fn)
4385 p.append(fctx.node())
4386 p.append(fctx.node())
4386 else:
4387 else:
4387 p = [cp.node() for cp in ctx.parents()]
4388 p = [cp.node() for cp in ctx.parents()]
4388
4389
4389 displayer = cmdutil.show_changeset(ui, repo, opts)
4390 displayer = cmdutil.show_changeset(ui, repo, opts)
4390 for n in p:
4391 for n in p:
4391 if n != nullid:
4392 if n != nullid:
4392 displayer.show(repo[n])
4393 displayer.show(repo[n])
4393 displayer.close()
4394 displayer.close()
4394
4395
4395 @command('paths', [], _('[NAME]'))
4396 @command('paths', [], _('[NAME]'))
4396 def paths(ui, repo, search=None):
4397 def paths(ui, repo, search=None):
4397 """show aliases for remote repositories
4398 """show aliases for remote repositories
4398
4399
4399 Show definition of symbolic path name NAME. If no name is given,
4400 Show definition of symbolic path name NAME. If no name is given,
4400 show definition of all available names.
4401 show definition of all available names.
4401
4402
4402 Option -q/--quiet suppresses all output when searching for NAME
4403 Option -q/--quiet suppresses all output when searching for NAME
4403 and shows only the path names when listing all definitions.
4404 and shows only the path names when listing all definitions.
4404
4405
4405 Path names are defined in the [paths] section of your
4406 Path names are defined in the [paths] section of your
4406 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4407 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4407 repository, ``.hg/hgrc`` is used, too.
4408 repository, ``.hg/hgrc`` is used, too.
4408
4409
4409 The path names ``default`` and ``default-push`` have a special
4410 The path names ``default`` and ``default-push`` have a special
4410 meaning. When performing a push or pull operation, they are used
4411 meaning. When performing a push or pull operation, they are used
4411 as fallbacks if no location is specified on the command-line.
4412 as fallbacks if no location is specified on the command-line.
4412 When ``default-push`` is set, it will be used for push and
4413 When ``default-push`` is set, it will be used for push and
4413 ``default`` will be used for pull; otherwise ``default`` is used
4414 ``default`` will be used for pull; otherwise ``default`` is used
4414 as the fallback for both. When cloning a repository, the clone
4415 as the fallback for both. When cloning a repository, the clone
4415 source is written as ``default`` in ``.hg/hgrc``. Note that
4416 source is written as ``default`` in ``.hg/hgrc``. Note that
4416 ``default`` and ``default-push`` apply to all inbound (e.g.
4417 ``default`` and ``default-push`` apply to all inbound (e.g.
4417 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4418 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4418 :hg:`bundle`) operations.
4419 :hg:`bundle`) operations.
4419
4420
4420 See :hg:`help urls` for more information.
4421 See :hg:`help urls` for more information.
4421
4422
4422 Returns 0 on success.
4423 Returns 0 on success.
4423 """
4424 """
4424 if search:
4425 if search:
4425 for name, path in ui.configitems("paths"):
4426 for name, path in ui.configitems("paths"):
4426 if name == search:
4427 if name == search:
4427 ui.status("%s\n" % util.hidepassword(path))
4428 ui.status("%s\n" % util.hidepassword(path))
4428 return
4429 return
4429 if not ui.quiet:
4430 if not ui.quiet:
4430 ui.warn(_("not found!\n"))
4431 ui.warn(_("not found!\n"))
4431 return 1
4432 return 1
4432 else:
4433 else:
4433 for name, path in ui.configitems("paths"):
4434 for name, path in ui.configitems("paths"):
4434 if ui.quiet:
4435 if ui.quiet:
4435 ui.write("%s\n" % name)
4436 ui.write("%s\n" % name)
4436 else:
4437 else:
4437 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4438 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4438
4439
4439 @command('phase',
4440 @command('phase',
4440 [('p', 'public', False, _('set changeset phase to public')),
4441 [('p', 'public', False, _('set changeset phase to public')),
4441 ('d', 'draft', False, _('set changeset phase to draft')),
4442 ('d', 'draft', False, _('set changeset phase to draft')),
4442 ('s', 'secret', False, _('set changeset phase to secret')),
4443 ('s', 'secret', False, _('set changeset phase to secret')),
4443 ('f', 'force', False, _('allow to move boundary backward')),
4444 ('f', 'force', False, _('allow to move boundary backward')),
4444 ('r', 'rev', [], _('target revision'), _('REV')),
4445 ('r', 'rev', [], _('target revision'), _('REV')),
4445 ],
4446 ],
4446 _('[-p|-d|-s] [-f] [-r] REV...'))
4447 _('[-p|-d|-s] [-f] [-r] REV...'))
4447 def phase(ui, repo, *revs, **opts):
4448 def phase(ui, repo, *revs, **opts):
4448 """set or show the current phase name
4449 """set or show the current phase name
4449
4450
4450 With no argument, show the phase name of specified revisions.
4451 With no argument, show the phase name of specified revisions.
4451
4452
4452 With one of -p/--public, -d/--draft or -s/--secret, change the
4453 With one of -p/--public, -d/--draft or -s/--secret, change the
4453 phase value of the specified revisions.
4454 phase value of the specified revisions.
4454
4455
4455 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4456 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4456 lower phase to an higher phase. Phases are ordered as follows::
4457 lower phase to an higher phase. Phases are ordered as follows::
4457
4458
4458 public < draft < secret
4459 public < draft < secret
4459
4460
4460 Return 0 on success, 1 if no phases were changed or some could not
4461 Return 0 on success, 1 if no phases were changed or some could not
4461 be changed.
4462 be changed.
4462 """
4463 """
4463 # search for a unique phase argument
4464 # search for a unique phase argument
4464 targetphase = None
4465 targetphase = None
4465 for idx, name in enumerate(phases.phasenames):
4466 for idx, name in enumerate(phases.phasenames):
4466 if opts[name]:
4467 if opts[name]:
4467 if targetphase is not None:
4468 if targetphase is not None:
4468 raise util.Abort(_('only one phase can be specified'))
4469 raise util.Abort(_('only one phase can be specified'))
4469 targetphase = idx
4470 targetphase = idx
4470
4471
4471 # look for specified revision
4472 # look for specified revision
4472 revs = list(revs)
4473 revs = list(revs)
4473 revs.extend(opts['rev'])
4474 revs.extend(opts['rev'])
4474 if not revs:
4475 if not revs:
4475 raise util.Abort(_('no revisions specified'))
4476 raise util.Abort(_('no revisions specified'))
4476
4477
4477 revs = scmutil.revrange(repo, revs)
4478 revs = scmutil.revrange(repo, revs)
4478
4479
4479 lock = None
4480 lock = None
4480 ret = 0
4481 ret = 0
4481 if targetphase is None:
4482 if targetphase is None:
4482 # display
4483 # display
4483 for r in revs:
4484 for r in revs:
4484 ctx = repo[r]
4485 ctx = repo[r]
4485 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4486 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4486 else:
4487 else:
4487 lock = repo.lock()
4488 lock = repo.lock()
4488 try:
4489 try:
4489 # set phase
4490 # set phase
4490 if not revs:
4491 if not revs:
4491 raise util.Abort(_('empty revision set'))
4492 raise util.Abort(_('empty revision set'))
4492 nodes = [repo[r].node() for r in revs]
4493 nodes = [repo[r].node() for r in revs]
4493 olddata = repo._phasecache.getphaserevs(repo)[:]
4494 olddata = repo._phasecache.getphaserevs(repo)[:]
4494 phases.advanceboundary(repo, targetphase, nodes)
4495 phases.advanceboundary(repo, targetphase, nodes)
4495 if opts['force']:
4496 if opts['force']:
4496 phases.retractboundary(repo, targetphase, nodes)
4497 phases.retractboundary(repo, targetphase, nodes)
4497 finally:
4498 finally:
4498 lock.release()
4499 lock.release()
4499 # moving revision from public to draft may hide them
4500 # moving revision from public to draft may hide them
4500 # We have to check result on an unfiltered repository
4501 # We have to check result on an unfiltered repository
4501 unfi = repo.unfiltered()
4502 unfi = repo.unfiltered()
4502 newdata = repo._phasecache.getphaserevs(unfi)
4503 newdata = repo._phasecache.getphaserevs(unfi)
4503 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4504 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4504 cl = unfi.changelog
4505 cl = unfi.changelog
4505 rejected = [n for n in nodes
4506 rejected = [n for n in nodes
4506 if newdata[cl.rev(n)] < targetphase]
4507 if newdata[cl.rev(n)] < targetphase]
4507 if rejected:
4508 if rejected:
4508 ui.warn(_('cannot move %i changesets to a higher '
4509 ui.warn(_('cannot move %i changesets to a higher '
4509 'phase, use --force\n') % len(rejected))
4510 'phase, use --force\n') % len(rejected))
4510 ret = 1
4511 ret = 1
4511 if changes:
4512 if changes:
4512 msg = _('phase changed for %i changesets\n') % changes
4513 msg = _('phase changed for %i changesets\n') % changes
4513 if ret:
4514 if ret:
4514 ui.status(msg)
4515 ui.status(msg)
4515 else:
4516 else:
4516 ui.note(msg)
4517 ui.note(msg)
4517 else:
4518 else:
4518 ui.warn(_('no phases changed\n'))
4519 ui.warn(_('no phases changed\n'))
4519 ret = 1
4520 ret = 1
4520 return ret
4521 return ret
4521
4522
4522 def postincoming(ui, repo, modheads, optupdate, checkout):
4523 def postincoming(ui, repo, modheads, optupdate, checkout):
4523 if modheads == 0:
4524 if modheads == 0:
4524 return
4525 return
4525 if optupdate:
4526 if optupdate:
4526 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4527 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4527 try:
4528 try:
4528 ret = hg.update(repo, checkout)
4529 ret = hg.update(repo, checkout)
4529 except util.Abort, inst:
4530 except util.Abort, inst:
4530 ui.warn(_("not updating: %s\n") % str(inst))
4531 ui.warn(_("not updating: %s\n") % str(inst))
4531 if inst.hint:
4532 if inst.hint:
4532 ui.warn(_("(%s)\n") % inst.hint)
4533 ui.warn(_("(%s)\n") % inst.hint)
4533 return 0
4534 return 0
4534 if not ret and not checkout:
4535 if not ret and not checkout:
4535 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4536 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4536 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4537 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4537 return ret
4538 return ret
4538 if modheads > 1:
4539 if modheads > 1:
4539 currentbranchheads = len(repo.branchheads())
4540 currentbranchheads = len(repo.branchheads())
4540 if currentbranchheads == modheads:
4541 if currentbranchheads == modheads:
4541 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4542 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4542 elif currentbranchheads > 1:
4543 elif currentbranchheads > 1:
4543 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4544 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4544 "merge)\n"))
4545 "merge)\n"))
4545 else:
4546 else:
4546 ui.status(_("(run 'hg heads' to see heads)\n"))
4547 ui.status(_("(run 'hg heads' to see heads)\n"))
4547 else:
4548 else:
4548 ui.status(_("(run 'hg update' to get a working copy)\n"))
4549 ui.status(_("(run 'hg update' to get a working copy)\n"))
4549
4550
4550 @command('^pull',
4551 @command('^pull',
4551 [('u', 'update', None,
4552 [('u', 'update', None,
4552 _('update to new branch head if changesets were pulled')),
4553 _('update to new branch head if changesets were pulled')),
4553 ('f', 'force', None, _('run even when remote repository is unrelated')),
4554 ('f', 'force', None, _('run even when remote repository is unrelated')),
4554 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4555 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4555 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4556 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4556 ('b', 'branch', [], _('a specific branch you would like to pull'),
4557 ('b', 'branch', [], _('a specific branch you would like to pull'),
4557 _('BRANCH')),
4558 _('BRANCH')),
4558 ] + remoteopts,
4559 ] + remoteopts,
4559 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4560 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4560 def pull(ui, repo, source="default", **opts):
4561 def pull(ui, repo, source="default", **opts):
4561 """pull changes from the specified source
4562 """pull changes from the specified source
4562
4563
4563 Pull changes from a remote repository to a local one.
4564 Pull changes from a remote repository to a local one.
4564
4565
4565 This finds all changes from the repository at the specified path
4566 This finds all changes from the repository at the specified path
4566 or URL and adds them to a local repository (the current one unless
4567 or URL and adds them to a local repository (the current one unless
4567 -R is specified). By default, this does not update the copy of the
4568 -R is specified). By default, this does not update the copy of the
4568 project in the working directory.
4569 project in the working directory.
4569
4570
4570 Use :hg:`incoming` if you want to see what would have been added
4571 Use :hg:`incoming` if you want to see what would have been added
4571 by a pull at the time you issued this command. If you then decide
4572 by a pull at the time you issued this command. If you then decide
4572 to add those changes to the repository, you should use :hg:`pull
4573 to add those changes to the repository, you should use :hg:`pull
4573 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4574 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4574
4575
4575 If SOURCE is omitted, the 'default' path will be used.
4576 If SOURCE is omitted, the 'default' path will be used.
4576 See :hg:`help urls` for more information.
4577 See :hg:`help urls` for more information.
4577
4578
4578 Returns 0 on success, 1 if an update had unresolved files.
4579 Returns 0 on success, 1 if an update had unresolved files.
4579 """
4580 """
4580 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4581 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4581 other = hg.peer(repo, opts, source)
4582 other = hg.peer(repo, opts, source)
4582 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4583 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4583 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4584 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4584
4585
4585 remotebookmarks = other.listkeys('bookmarks')
4586 remotebookmarks = other.listkeys('bookmarks')
4586
4587
4587 if opts.get('bookmark'):
4588 if opts.get('bookmark'):
4588 if not revs:
4589 if not revs:
4589 revs = []
4590 revs = []
4590 for b in opts['bookmark']:
4591 for b in opts['bookmark']:
4591 if b not in remotebookmarks:
4592 if b not in remotebookmarks:
4592 raise util.Abort(_('remote bookmark %s not found!') % b)
4593 raise util.Abort(_('remote bookmark %s not found!') % b)
4593 revs.append(remotebookmarks[b])
4594 revs.append(remotebookmarks[b])
4594
4595
4595 if revs:
4596 if revs:
4596 try:
4597 try:
4597 revs = [other.lookup(rev) for rev in revs]
4598 revs = [other.lookup(rev) for rev in revs]
4598 except error.CapabilityError:
4599 except error.CapabilityError:
4599 err = _("other repository doesn't support revision lookup, "
4600 err = _("other repository doesn't support revision lookup, "
4600 "so a rev cannot be specified.")
4601 "so a rev cannot be specified.")
4601 raise util.Abort(err)
4602 raise util.Abort(err)
4602
4603
4603 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4604 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4604 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4605 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4605 if checkout:
4606 if checkout:
4606 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4607 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4607 repo._subtoppath = source
4608 repo._subtoppath = source
4608 try:
4609 try:
4609 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4610 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4610
4611
4611 finally:
4612 finally:
4612 del repo._subtoppath
4613 del repo._subtoppath
4613
4614
4614 # update specified bookmarks
4615 # update specified bookmarks
4615 if opts.get('bookmark'):
4616 if opts.get('bookmark'):
4616 marks = repo._bookmarks
4617 marks = repo._bookmarks
4617 for b in opts['bookmark']:
4618 for b in opts['bookmark']:
4618 # explicit pull overrides local bookmark if any
4619 # explicit pull overrides local bookmark if any
4619 ui.status(_("importing bookmark %s\n") % b)
4620 ui.status(_("importing bookmark %s\n") % b)
4620 marks[b] = repo[remotebookmarks[b]].node()
4621 marks[b] = repo[remotebookmarks[b]].node()
4621 marks.write()
4622 marks.write()
4622
4623
4623 return ret
4624 return ret
4624
4625
4625 @command('^push',
4626 @command('^push',
4626 [('f', 'force', None, _('force push')),
4627 [('f', 'force', None, _('force push')),
4627 ('r', 'rev', [],
4628 ('r', 'rev', [],
4628 _('a changeset intended to be included in the destination'),
4629 _('a changeset intended to be included in the destination'),
4629 _('REV')),
4630 _('REV')),
4630 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4631 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4631 ('b', 'branch', [],
4632 ('b', 'branch', [],
4632 _('a specific branch you would like to push'), _('BRANCH')),
4633 _('a specific branch you would like to push'), _('BRANCH')),
4633 ('', 'new-branch', False, _('allow pushing a new branch')),
4634 ('', 'new-branch', False, _('allow pushing a new branch')),
4634 ] + remoteopts,
4635 ] + remoteopts,
4635 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4636 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4636 def push(ui, repo, dest=None, **opts):
4637 def push(ui, repo, dest=None, **opts):
4637 """push changes to the specified destination
4638 """push changes to the specified destination
4638
4639
4639 Push changesets from the local repository to the specified
4640 Push changesets from the local repository to the specified
4640 destination.
4641 destination.
4641
4642
4642 This operation is symmetrical to pull: it is identical to a pull
4643 This operation is symmetrical to pull: it is identical to a pull
4643 in the destination repository from the current one.
4644 in the destination repository from the current one.
4644
4645
4645 By default, push will not allow creation of new heads at the
4646 By default, push will not allow creation of new heads at the
4646 destination, since multiple heads would make it unclear which head
4647 destination, since multiple heads would make it unclear which head
4647 to use. In this situation, it is recommended to pull and merge
4648 to use. In this situation, it is recommended to pull and merge
4648 before pushing.
4649 before pushing.
4649
4650
4650 Use --new-branch if you want to allow push to create a new named
4651 Use --new-branch if you want to allow push to create a new named
4651 branch that is not present at the destination. This allows you to
4652 branch that is not present at the destination. This allows you to
4652 only create a new branch without forcing other changes.
4653 only create a new branch without forcing other changes.
4653
4654
4654 .. note::
4655 .. note::
4655
4656
4656 Extra care should be taken with the -f/--force option,
4657 Extra care should be taken with the -f/--force option,
4657 which will push all new heads on all branches, an action which will
4658 which will push all new heads on all branches, an action which will
4658 almost always cause confusion for collaborators.
4659 almost always cause confusion for collaborators.
4659
4660
4660 If -r/--rev is used, the specified revision and all its ancestors
4661 If -r/--rev is used, the specified revision and all its ancestors
4661 will be pushed to the remote repository.
4662 will be pushed to the remote repository.
4662
4663
4663 If -B/--bookmark is used, the specified bookmarked revision, its
4664 If -B/--bookmark is used, the specified bookmarked revision, its
4664 ancestors, and the bookmark will be pushed to the remote
4665 ancestors, and the bookmark will be pushed to the remote
4665 repository.
4666 repository.
4666
4667
4667 Please see :hg:`help urls` for important details about ``ssh://``
4668 Please see :hg:`help urls` for important details about ``ssh://``
4668 URLs. If DESTINATION is omitted, a default path will be used.
4669 URLs. If DESTINATION is omitted, a default path will be used.
4669
4670
4670 Returns 0 if push was successful, 1 if nothing to push.
4671 Returns 0 if push was successful, 1 if nothing to push.
4671 """
4672 """
4672
4673
4673 if opts.get('bookmark'):
4674 if opts.get('bookmark'):
4674 ui.setconfig('bookmarks', 'pushing', opts['bookmark'])
4675 ui.setconfig('bookmarks', 'pushing', opts['bookmark'])
4675 for b in opts['bookmark']:
4676 for b in opts['bookmark']:
4676 # translate -B options to -r so changesets get pushed
4677 # translate -B options to -r so changesets get pushed
4677 if b in repo._bookmarks:
4678 if b in repo._bookmarks:
4678 opts.setdefault('rev', []).append(b)
4679 opts.setdefault('rev', []).append(b)
4679 else:
4680 else:
4680 # if we try to push a deleted bookmark, translate it to null
4681 # if we try to push a deleted bookmark, translate it to null
4681 # this lets simultaneous -r, -b options continue working
4682 # this lets simultaneous -r, -b options continue working
4682 opts.setdefault('rev', []).append("null")
4683 opts.setdefault('rev', []).append("null")
4683
4684
4684 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4685 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4685 dest, branches = hg.parseurl(dest, opts.get('branch'))
4686 dest, branches = hg.parseurl(dest, opts.get('branch'))
4686 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4687 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4687 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4688 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4688 other = hg.peer(repo, opts, dest)
4689 other = hg.peer(repo, opts, dest)
4689 if revs:
4690 if revs:
4690 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4691 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4691
4692
4692 repo._subtoppath = dest
4693 repo._subtoppath = dest
4693 try:
4694 try:
4694 # push subrepos depth-first for coherent ordering
4695 # push subrepos depth-first for coherent ordering
4695 c = repo['']
4696 c = repo['']
4696 subs = c.substate # only repos that are committed
4697 subs = c.substate # only repos that are committed
4697 for s in sorted(subs):
4698 for s in sorted(subs):
4698 if c.sub(s).push(opts) == 0:
4699 if c.sub(s).push(opts) == 0:
4699 return False
4700 return False
4700 finally:
4701 finally:
4701 del repo._subtoppath
4702 del repo._subtoppath
4702 result = repo.push(other, opts.get('force'), revs=revs,
4703 result = repo.push(other, opts.get('force'), revs=revs,
4703 newbranch=opts.get('new_branch'))
4704 newbranch=opts.get('new_branch'))
4704
4705
4705 result = not result
4706 result = not result
4706
4707
4707 if opts.get('bookmark'):
4708 if opts.get('bookmark'):
4708 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4709 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4709 if bresult == 2:
4710 if bresult == 2:
4710 return 2
4711 return 2
4711 if not result and bresult:
4712 if not result and bresult:
4712 result = 2
4713 result = 2
4713
4714
4714 return result
4715 return result
4715
4716
4716 @command('recover', [])
4717 @command('recover', [])
4717 def recover(ui, repo):
4718 def recover(ui, repo):
4718 """roll back an interrupted transaction
4719 """roll back an interrupted transaction
4719
4720
4720 Recover from an interrupted commit or pull.
4721 Recover from an interrupted commit or pull.
4721
4722
4722 This command tries to fix the repository status after an
4723 This command tries to fix the repository status after an
4723 interrupted operation. It should only be necessary when Mercurial
4724 interrupted operation. It should only be necessary when Mercurial
4724 suggests it.
4725 suggests it.
4725
4726
4726 Returns 0 if successful, 1 if nothing to recover or verify fails.
4727 Returns 0 if successful, 1 if nothing to recover or verify fails.
4727 """
4728 """
4728 if repo.recover():
4729 if repo.recover():
4729 return hg.verify(repo)
4730 return hg.verify(repo)
4730 return 1
4731 return 1
4731
4732
4732 @command('^remove|rm',
4733 @command('^remove|rm',
4733 [('A', 'after', None, _('record delete for missing files')),
4734 [('A', 'after', None, _('record delete for missing files')),
4734 ('f', 'force', None,
4735 ('f', 'force', None,
4735 _('remove (and delete) file even if added or modified')),
4736 _('remove (and delete) file even if added or modified')),
4736 ] + walkopts,
4737 ] + walkopts,
4737 _('[OPTION]... FILE...'))
4738 _('[OPTION]... FILE...'))
4738 def remove(ui, repo, *pats, **opts):
4739 def remove(ui, repo, *pats, **opts):
4739 """remove the specified files on the next commit
4740 """remove the specified files on the next commit
4740
4741
4741 Schedule the indicated files for removal from the current branch.
4742 Schedule the indicated files for removal from the current branch.
4742
4743
4743 This command schedules the files to be removed at the next commit.
4744 This command schedules the files to be removed at the next commit.
4744 To undo a remove before that, see :hg:`revert`. To undo added
4745 To undo a remove before that, see :hg:`revert`. To undo added
4745 files, see :hg:`forget`.
4746 files, see :hg:`forget`.
4746
4747
4747 .. container:: verbose
4748 .. container:: verbose
4748
4749
4749 -A/--after can be used to remove only files that have already
4750 -A/--after can be used to remove only files that have already
4750 been deleted, -f/--force can be used to force deletion, and -Af
4751 been deleted, -f/--force can be used to force deletion, and -Af
4751 can be used to remove files from the next revision without
4752 can be used to remove files from the next revision without
4752 deleting them from the working directory.
4753 deleting them from the working directory.
4753
4754
4754 The following table details the behavior of remove for different
4755 The following table details the behavior of remove for different
4755 file states (columns) and option combinations (rows). The file
4756 file states (columns) and option combinations (rows). The file
4756 states are Added [A], Clean [C], Modified [M] and Missing [!]
4757 states are Added [A], Clean [C], Modified [M] and Missing [!]
4757 (as reported by :hg:`status`). The actions are Warn, Remove
4758 (as reported by :hg:`status`). The actions are Warn, Remove
4758 (from branch) and Delete (from disk):
4759 (from branch) and Delete (from disk):
4759
4760
4760 ========= == == == ==
4761 ========= == == == ==
4761 opt/state A C M !
4762 opt/state A C M !
4762 ========= == == == ==
4763 ========= == == == ==
4763 none W RD W R
4764 none W RD W R
4764 -f R RD RD R
4765 -f R RD RD R
4765 -A W W W R
4766 -A W W W R
4766 -Af R R R R
4767 -Af R R R R
4767 ========= == == == ==
4768 ========= == == == ==
4768
4769
4769 Note that remove never deletes files in Added [A] state from the
4770 Note that remove never deletes files in Added [A] state from the
4770 working directory, not even if option --force is specified.
4771 working directory, not even if option --force is specified.
4771
4772
4772 Returns 0 on success, 1 if any warnings encountered.
4773 Returns 0 on success, 1 if any warnings encountered.
4773 """
4774 """
4774
4775
4775 ret = 0
4776 ret = 0
4776 after, force = opts.get('after'), opts.get('force')
4777 after, force = opts.get('after'), opts.get('force')
4777 if not pats and not after:
4778 if not pats and not after:
4778 raise util.Abort(_('no files specified'))
4779 raise util.Abort(_('no files specified'))
4779
4780
4780 m = scmutil.match(repo[None], pats, opts)
4781 m = scmutil.match(repo[None], pats, opts)
4781 s = repo.status(match=m, clean=True)
4782 s = repo.status(match=m, clean=True)
4782 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4783 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4783
4784
4784 # warn about failure to delete explicit files/dirs
4785 # warn about failure to delete explicit files/dirs
4785 wctx = repo[None]
4786 wctx = repo[None]
4786 for f in m.files():
4787 for f in m.files():
4787 if f in repo.dirstate or f in wctx.dirs():
4788 if f in repo.dirstate or f in wctx.dirs():
4788 continue
4789 continue
4789 if os.path.exists(m.rel(f)):
4790 if os.path.exists(m.rel(f)):
4790 if os.path.isdir(m.rel(f)):
4791 if os.path.isdir(m.rel(f)):
4791 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4792 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4792 else:
4793 else:
4793 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4794 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4794 # missing files will generate a warning elsewhere
4795 # missing files will generate a warning elsewhere
4795 ret = 1
4796 ret = 1
4796
4797
4797 if force:
4798 if force:
4798 list = modified + deleted + clean + added
4799 list = modified + deleted + clean + added
4799 elif after:
4800 elif after:
4800 list = deleted
4801 list = deleted
4801 for f in modified + added + clean:
4802 for f in modified + added + clean:
4802 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4803 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4803 ret = 1
4804 ret = 1
4804 else:
4805 else:
4805 list = deleted + clean
4806 list = deleted + clean
4806 for f in modified:
4807 for f in modified:
4807 ui.warn(_('not removing %s: file is modified (use -f'
4808 ui.warn(_('not removing %s: file is modified (use -f'
4808 ' to force removal)\n') % m.rel(f))
4809 ' to force removal)\n') % m.rel(f))
4809 ret = 1
4810 ret = 1
4810 for f in added:
4811 for f in added:
4811 ui.warn(_('not removing %s: file has been marked for add'
4812 ui.warn(_('not removing %s: file has been marked for add'
4812 ' (use forget to undo)\n') % m.rel(f))
4813 ' (use forget to undo)\n') % m.rel(f))
4813 ret = 1
4814 ret = 1
4814
4815
4815 for f in sorted(list):
4816 for f in sorted(list):
4816 if ui.verbose or not m.exact(f):
4817 if ui.verbose or not m.exact(f):
4817 ui.status(_('removing %s\n') % m.rel(f))
4818 ui.status(_('removing %s\n') % m.rel(f))
4818
4819
4819 wlock = repo.wlock()
4820 wlock = repo.wlock()
4820 try:
4821 try:
4821 if not after:
4822 if not after:
4822 for f in list:
4823 for f in list:
4823 if f in added:
4824 if f in added:
4824 continue # we never unlink added files on remove
4825 continue # we never unlink added files on remove
4825 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4826 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4826 repo[None].forget(list)
4827 repo[None].forget(list)
4827 finally:
4828 finally:
4828 wlock.release()
4829 wlock.release()
4829
4830
4830 return ret
4831 return ret
4831
4832
4832 @command('rename|move|mv',
4833 @command('rename|move|mv',
4833 [('A', 'after', None, _('record a rename that has already occurred')),
4834 [('A', 'after', None, _('record a rename that has already occurred')),
4834 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4835 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4835 ] + walkopts + dryrunopts,
4836 ] + walkopts + dryrunopts,
4836 _('[OPTION]... SOURCE... DEST'))
4837 _('[OPTION]... SOURCE... DEST'))
4837 def rename(ui, repo, *pats, **opts):
4838 def rename(ui, repo, *pats, **opts):
4838 """rename files; equivalent of copy + remove
4839 """rename files; equivalent of copy + remove
4839
4840
4840 Mark dest as copies of sources; mark sources for deletion. If dest
4841 Mark dest as copies of sources; mark sources for deletion. If dest
4841 is a directory, copies are put in that directory. If dest is a
4842 is a directory, copies are put in that directory. If dest is a
4842 file, there can only be one source.
4843 file, there can only be one source.
4843
4844
4844 By default, this command copies the contents of files as they
4845 By default, this command copies the contents of files as they
4845 exist in the working directory. If invoked with -A/--after, the
4846 exist in the working directory. If invoked with -A/--after, the
4846 operation is recorded, but no copying is performed.
4847 operation is recorded, but no copying is performed.
4847
4848
4848 This command takes effect at the next commit. To undo a rename
4849 This command takes effect at the next commit. To undo a rename
4849 before that, see :hg:`revert`.
4850 before that, see :hg:`revert`.
4850
4851
4851 Returns 0 on success, 1 if errors are encountered.
4852 Returns 0 on success, 1 if errors are encountered.
4852 """
4853 """
4853 wlock = repo.wlock(False)
4854 wlock = repo.wlock(False)
4854 try:
4855 try:
4855 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4856 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4856 finally:
4857 finally:
4857 wlock.release()
4858 wlock.release()
4858
4859
4859 @command('resolve',
4860 @command('resolve',
4860 [('a', 'all', None, _('select all unresolved files')),
4861 [('a', 'all', None, _('select all unresolved files')),
4861 ('l', 'list', None, _('list state of files needing merge')),
4862 ('l', 'list', None, _('list state of files needing merge')),
4862 ('m', 'mark', None, _('mark files as resolved')),
4863 ('m', 'mark', None, _('mark files as resolved')),
4863 ('u', 'unmark', None, _('mark files as unresolved')),
4864 ('u', 'unmark', None, _('mark files as unresolved')),
4864 ('n', 'no-status', None, _('hide status prefix'))]
4865 ('n', 'no-status', None, _('hide status prefix'))]
4865 + mergetoolopts + walkopts,
4866 + mergetoolopts + walkopts,
4866 _('[OPTION]... [FILE]...'))
4867 _('[OPTION]... [FILE]...'))
4867 def resolve(ui, repo, *pats, **opts):
4868 def resolve(ui, repo, *pats, **opts):
4868 """redo merges or set/view the merge status of files
4869 """redo merges or set/view the merge status of files
4869
4870
4870 Merges with unresolved conflicts are often the result of
4871 Merges with unresolved conflicts are often the result of
4871 non-interactive merging using the ``internal:merge`` configuration
4872 non-interactive merging using the ``internal:merge`` configuration
4872 setting, or a command-line merge tool like ``diff3``. The resolve
4873 setting, or a command-line merge tool like ``diff3``. The resolve
4873 command is used to manage the files involved in a merge, after
4874 command is used to manage the files involved in a merge, after
4874 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4875 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4875 working directory must have two parents). See :hg:`help
4876 working directory must have two parents). See :hg:`help
4876 merge-tools` for information on configuring merge tools.
4877 merge-tools` for information on configuring merge tools.
4877
4878
4878 The resolve command can be used in the following ways:
4879 The resolve command can be used in the following ways:
4879
4880
4880 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4881 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4881 files, discarding any previous merge attempts. Re-merging is not
4882 files, discarding any previous merge attempts. Re-merging is not
4882 performed for files already marked as resolved. Use ``--all/-a``
4883 performed for files already marked as resolved. Use ``--all/-a``
4883 to select all unresolved files. ``--tool`` can be used to specify
4884 to select all unresolved files. ``--tool`` can be used to specify
4884 the merge tool used for the given files. It overrides the HGMERGE
4885 the merge tool used for the given files. It overrides the HGMERGE
4885 environment variable and your configuration files. Previous file
4886 environment variable and your configuration files. Previous file
4886 contents are saved with a ``.orig`` suffix.
4887 contents are saved with a ``.orig`` suffix.
4887
4888
4888 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4889 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4889 (e.g. after having manually fixed-up the files). The default is
4890 (e.g. after having manually fixed-up the files). The default is
4890 to mark all unresolved files.
4891 to mark all unresolved files.
4891
4892
4892 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4893 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4893 default is to mark all resolved files.
4894 default is to mark all resolved files.
4894
4895
4895 - :hg:`resolve -l`: list files which had or still have conflicts.
4896 - :hg:`resolve -l`: list files which had or still have conflicts.
4896 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4897 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4897
4898
4898 Note that Mercurial will not let you commit files with unresolved
4899 Note that Mercurial will not let you commit files with unresolved
4899 merge conflicts. You must use :hg:`resolve -m ...` before you can
4900 merge conflicts. You must use :hg:`resolve -m ...` before you can
4900 commit after a conflicting merge.
4901 commit after a conflicting merge.
4901
4902
4902 Returns 0 on success, 1 if any files fail a resolve attempt.
4903 Returns 0 on success, 1 if any files fail a resolve attempt.
4903 """
4904 """
4904
4905
4905 all, mark, unmark, show, nostatus = \
4906 all, mark, unmark, show, nostatus = \
4906 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4907 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4907
4908
4908 if (show and (mark or unmark)) or (mark and unmark):
4909 if (show and (mark or unmark)) or (mark and unmark):
4909 raise util.Abort(_("too many options specified"))
4910 raise util.Abort(_("too many options specified"))
4910 if pats and all:
4911 if pats and all:
4911 raise util.Abort(_("can't specify --all and patterns"))
4912 raise util.Abort(_("can't specify --all and patterns"))
4912 if not (all or pats or show or mark or unmark):
4913 if not (all or pats or show or mark or unmark):
4913 raise util.Abort(_('no files or directories specified; '
4914 raise util.Abort(_('no files or directories specified; '
4914 'use --all to remerge all files'))
4915 'use --all to remerge all files'))
4915
4916
4916 ms = mergemod.mergestate(repo)
4917 ms = mergemod.mergestate(repo)
4917 m = scmutil.match(repo[None], pats, opts)
4918 m = scmutil.match(repo[None], pats, opts)
4918 ret = 0
4919 ret = 0
4919
4920
4920 for f in ms:
4921 for f in ms:
4921 if m(f):
4922 if m(f):
4922 if show:
4923 if show:
4923 if nostatus:
4924 if nostatus:
4924 ui.write("%s\n" % f)
4925 ui.write("%s\n" % f)
4925 else:
4926 else:
4926 ui.write("%s %s\n" % (ms[f].upper(), f),
4927 ui.write("%s %s\n" % (ms[f].upper(), f),
4927 label='resolve.' +
4928 label='resolve.' +
4928 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4929 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4929 elif mark:
4930 elif mark:
4930 ms.mark(f, "r")
4931 ms.mark(f, "r")
4931 elif unmark:
4932 elif unmark:
4932 ms.mark(f, "u")
4933 ms.mark(f, "u")
4933 else:
4934 else:
4934 wctx = repo[None]
4935 wctx = repo[None]
4935 mctx = wctx.parents()[-1]
4936 mctx = wctx.parents()[-1]
4936
4937
4937 # backup pre-resolve (merge uses .orig for its own purposes)
4938 # backup pre-resolve (merge uses .orig for its own purposes)
4938 a = repo.wjoin(f)
4939 a = repo.wjoin(f)
4939 util.copyfile(a, a + ".resolve")
4940 util.copyfile(a, a + ".resolve")
4940
4941
4941 try:
4942 try:
4942 # resolve file
4943 # resolve file
4943 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4944 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4944 if ms.resolve(f, wctx, mctx):
4945 if ms.resolve(f, wctx, mctx):
4945 ret = 1
4946 ret = 1
4946 finally:
4947 finally:
4947 ui.setconfig('ui', 'forcemerge', '')
4948 ui.setconfig('ui', 'forcemerge', '')
4948 ms.commit()
4949 ms.commit()
4949
4950
4950 # replace filemerge's .orig file with our resolve file
4951 # replace filemerge's .orig file with our resolve file
4951 util.rename(a + ".resolve", a + ".orig")
4952 util.rename(a + ".resolve", a + ".orig")
4952
4953
4953 ms.commit()
4954 ms.commit()
4954 return ret
4955 return ret
4955
4956
4956 @command('revert',
4957 @command('revert',
4957 [('a', 'all', None, _('revert all changes when no arguments given')),
4958 [('a', 'all', None, _('revert all changes when no arguments given')),
4958 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4959 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4959 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4960 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4960 ('C', 'no-backup', None, _('do not save backup copies of files')),
4961 ('C', 'no-backup', None, _('do not save backup copies of files')),
4961 ] + walkopts + dryrunopts,
4962 ] + walkopts + dryrunopts,
4962 _('[OPTION]... [-r REV] [NAME]...'))
4963 _('[OPTION]... [-r REV] [NAME]...'))
4963 def revert(ui, repo, *pats, **opts):
4964 def revert(ui, repo, *pats, **opts):
4964 """restore files to their checkout state
4965 """restore files to their checkout state
4965
4966
4966 .. note::
4967 .. note::
4967
4968
4968 To check out earlier revisions, you should use :hg:`update REV`.
4969 To check out earlier revisions, you should use :hg:`update REV`.
4969 To cancel an uncommitted merge (and lose your changes),
4970 To cancel an uncommitted merge (and lose your changes),
4970 use :hg:`update --clean .`.
4971 use :hg:`update --clean .`.
4971
4972
4972 With no revision specified, revert the specified files or directories
4973 With no revision specified, revert the specified files or directories
4973 to the contents they had in the parent of the working directory.
4974 to the contents they had in the parent of the working directory.
4974 This restores the contents of files to an unmodified
4975 This restores the contents of files to an unmodified
4975 state and unschedules adds, removes, copies, and renames. If the
4976 state and unschedules adds, removes, copies, and renames. If the
4976 working directory has two parents, you must explicitly specify a
4977 working directory has two parents, you must explicitly specify a
4977 revision.
4978 revision.
4978
4979
4979 Using the -r/--rev or -d/--date options, revert the given files or
4980 Using the -r/--rev or -d/--date options, revert the given files or
4980 directories to their states as of a specific revision. Because
4981 directories to their states as of a specific revision. Because
4981 revert does not change the working directory parents, this will
4982 revert does not change the working directory parents, this will
4982 cause these files to appear modified. This can be helpful to "back
4983 cause these files to appear modified. This can be helpful to "back
4983 out" some or all of an earlier change. See :hg:`backout` for a
4984 out" some or all of an earlier change. See :hg:`backout` for a
4984 related method.
4985 related method.
4985
4986
4986 Modified files are saved with a .orig suffix before reverting.
4987 Modified files are saved with a .orig suffix before reverting.
4987 To disable these backups, use --no-backup.
4988 To disable these backups, use --no-backup.
4988
4989
4989 See :hg:`help dates` for a list of formats valid for -d/--date.
4990 See :hg:`help dates` for a list of formats valid for -d/--date.
4990
4991
4991 Returns 0 on success.
4992 Returns 0 on success.
4992 """
4993 """
4993
4994
4994 if opts.get("date"):
4995 if opts.get("date"):
4995 if opts.get("rev"):
4996 if opts.get("rev"):
4996 raise util.Abort(_("you can't specify a revision and a date"))
4997 raise util.Abort(_("you can't specify a revision and a date"))
4997 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4998 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4998
4999
4999 parent, p2 = repo.dirstate.parents()
5000 parent, p2 = repo.dirstate.parents()
5000 if not opts.get('rev') and p2 != nullid:
5001 if not opts.get('rev') and p2 != nullid:
5001 # revert after merge is a trap for new users (issue2915)
5002 # revert after merge is a trap for new users (issue2915)
5002 raise util.Abort(_('uncommitted merge with no revision specified'),
5003 raise util.Abort(_('uncommitted merge with no revision specified'),
5003 hint=_('use "hg update" or see "hg help revert"'))
5004 hint=_('use "hg update" or see "hg help revert"'))
5004
5005
5005 ctx = scmutil.revsingle(repo, opts.get('rev'))
5006 ctx = scmutil.revsingle(repo, opts.get('rev'))
5006
5007
5007 if not pats and not opts.get('all'):
5008 if not pats and not opts.get('all'):
5008 msg = _("no files or directories specified")
5009 msg = _("no files or directories specified")
5009 if p2 != nullid:
5010 if p2 != nullid:
5010 hint = _("uncommitted merge, use --all to discard all changes,"
5011 hint = _("uncommitted merge, use --all to discard all changes,"
5011 " or 'hg update -C .' to abort the merge")
5012 " or 'hg update -C .' to abort the merge")
5012 raise util.Abort(msg, hint=hint)
5013 raise util.Abort(msg, hint=hint)
5013 dirty = util.any(repo.status())
5014 dirty = util.any(repo.status())
5014 node = ctx.node()
5015 node = ctx.node()
5015 if node != parent:
5016 if node != parent:
5016 if dirty:
5017 if dirty:
5017 hint = _("uncommitted changes, use --all to discard all"
5018 hint = _("uncommitted changes, use --all to discard all"
5018 " changes, or 'hg update %s' to update") % ctx.rev()
5019 " changes, or 'hg update %s' to update") % ctx.rev()
5019 else:
5020 else:
5020 hint = _("use --all to revert all files,"
5021 hint = _("use --all to revert all files,"
5021 " or 'hg update %s' to update") % ctx.rev()
5022 " or 'hg update %s' to update") % ctx.rev()
5022 elif dirty:
5023 elif dirty:
5023 hint = _("uncommitted changes, use --all to discard all changes")
5024 hint = _("uncommitted changes, use --all to discard all changes")
5024 else:
5025 else:
5025 hint = _("use --all to revert all files")
5026 hint = _("use --all to revert all files")
5026 raise util.Abort(msg, hint=hint)
5027 raise util.Abort(msg, hint=hint)
5027
5028
5028 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5029 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5029
5030
5030 @command('rollback', dryrunopts +
5031 @command('rollback', dryrunopts +
5031 [('f', 'force', False, _('ignore safety measures'))])
5032 [('f', 'force', False, _('ignore safety measures'))])
5032 def rollback(ui, repo, **opts):
5033 def rollback(ui, repo, **opts):
5033 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5034 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5034
5035
5035 Please use :hg:`commit --amend` instead of rollback to correct
5036 Please use :hg:`commit --amend` instead of rollback to correct
5036 mistakes in the last commit.
5037 mistakes in the last commit.
5037
5038
5038 This command should be used with care. There is only one level of
5039 This command should be used with care. There is only one level of
5039 rollback, and there is no way to undo a rollback. It will also
5040 rollback, and there is no way to undo a rollback. It will also
5040 restore the dirstate at the time of the last transaction, losing
5041 restore the dirstate at the time of the last transaction, losing
5041 any dirstate changes since that time. This command does not alter
5042 any dirstate changes since that time. This command does not alter
5042 the working directory.
5043 the working directory.
5043
5044
5044 Transactions are used to encapsulate the effects of all commands
5045 Transactions are used to encapsulate the effects of all commands
5045 that create new changesets or propagate existing changesets into a
5046 that create new changesets or propagate existing changesets into a
5046 repository.
5047 repository.
5047
5048
5048 .. container:: verbose
5049 .. container:: verbose
5049
5050
5050 For example, the following commands are transactional, and their
5051 For example, the following commands are transactional, and their
5051 effects can be rolled back:
5052 effects can be rolled back:
5052
5053
5053 - commit
5054 - commit
5054 - import
5055 - import
5055 - pull
5056 - pull
5056 - push (with this repository as the destination)
5057 - push (with this repository as the destination)
5057 - unbundle
5058 - unbundle
5058
5059
5059 To avoid permanent data loss, rollback will refuse to rollback a
5060 To avoid permanent data loss, rollback will refuse to rollback a
5060 commit transaction if it isn't checked out. Use --force to
5061 commit transaction if it isn't checked out. Use --force to
5061 override this protection.
5062 override this protection.
5062
5063
5063 This command is not intended for use on public repositories. Once
5064 This command is not intended for use on public repositories. Once
5064 changes are visible for pull by other users, rolling a transaction
5065 changes are visible for pull by other users, rolling a transaction
5065 back locally is ineffective (someone else may already have pulled
5066 back locally is ineffective (someone else may already have pulled
5066 the changes). Furthermore, a race is possible with readers of the
5067 the changes). Furthermore, a race is possible with readers of the
5067 repository; for example an in-progress pull from the repository
5068 repository; for example an in-progress pull from the repository
5068 may fail if a rollback is performed.
5069 may fail if a rollback is performed.
5069
5070
5070 Returns 0 on success, 1 if no rollback data is available.
5071 Returns 0 on success, 1 if no rollback data is available.
5071 """
5072 """
5072 return repo.rollback(dryrun=opts.get('dry_run'),
5073 return repo.rollback(dryrun=opts.get('dry_run'),
5073 force=opts.get('force'))
5074 force=opts.get('force'))
5074
5075
5075 @command('root', [])
5076 @command('root', [])
5076 def root(ui, repo):
5077 def root(ui, repo):
5077 """print the root (top) of the current working directory
5078 """print the root (top) of the current working directory
5078
5079
5079 Print the root directory of the current repository.
5080 Print the root directory of the current repository.
5080
5081
5081 Returns 0 on success.
5082 Returns 0 on success.
5082 """
5083 """
5083 ui.write(repo.root + "\n")
5084 ui.write(repo.root + "\n")
5084
5085
5085 @command('^serve',
5086 @command('^serve',
5086 [('A', 'accesslog', '', _('name of access log file to write to'),
5087 [('A', 'accesslog', '', _('name of access log file to write to'),
5087 _('FILE')),
5088 _('FILE')),
5088 ('d', 'daemon', None, _('run server in background')),
5089 ('d', 'daemon', None, _('run server in background')),
5089 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5090 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5090 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5091 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5091 # use string type, then we can check if something was passed
5092 # use string type, then we can check if something was passed
5092 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5093 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5093 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5094 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5094 _('ADDR')),
5095 _('ADDR')),
5095 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5096 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5096 _('PREFIX')),
5097 _('PREFIX')),
5097 ('n', 'name', '',
5098 ('n', 'name', '',
5098 _('name to show in web pages (default: working directory)'), _('NAME')),
5099 _('name to show in web pages (default: working directory)'), _('NAME')),
5099 ('', 'web-conf', '',
5100 ('', 'web-conf', '',
5100 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5101 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5101 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5102 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5102 _('FILE')),
5103 _('FILE')),
5103 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5104 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5104 ('', 'stdio', None, _('for remote clients')),
5105 ('', 'stdio', None, _('for remote clients')),
5105 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5106 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5106 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5107 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5107 ('', 'style', '', _('template style to use'), _('STYLE')),
5108 ('', 'style', '', _('template style to use'), _('STYLE')),
5108 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5109 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5109 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5110 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5110 _('[OPTION]...'))
5111 _('[OPTION]...'))
5111 def serve(ui, repo, **opts):
5112 def serve(ui, repo, **opts):
5112 """start stand-alone webserver
5113 """start stand-alone webserver
5113
5114
5114 Start a local HTTP repository browser and pull server. You can use
5115 Start a local HTTP repository browser and pull server. You can use
5115 this for ad-hoc sharing and browsing of repositories. It is
5116 this for ad-hoc sharing and browsing of repositories. It is
5116 recommended to use a real web server to serve a repository for
5117 recommended to use a real web server to serve a repository for
5117 longer periods of time.
5118 longer periods of time.
5118
5119
5119 Please note that the server does not implement access control.
5120 Please note that the server does not implement access control.
5120 This means that, by default, anybody can read from the server and
5121 This means that, by default, anybody can read from the server and
5121 nobody can write to it by default. Set the ``web.allow_push``
5122 nobody can write to it by default. Set the ``web.allow_push``
5122 option to ``*`` to allow everybody to push to the server. You
5123 option to ``*`` to allow everybody to push to the server. You
5123 should use a real web server if you need to authenticate users.
5124 should use a real web server if you need to authenticate users.
5124
5125
5125 By default, the server logs accesses to stdout and errors to
5126 By default, the server logs accesses to stdout and errors to
5126 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5127 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5127 files.
5128 files.
5128
5129
5129 To have the server choose a free port number to listen on, specify
5130 To have the server choose a free port number to listen on, specify
5130 a port number of 0; in this case, the server will print the port
5131 a port number of 0; in this case, the server will print the port
5131 number it uses.
5132 number it uses.
5132
5133
5133 Returns 0 on success.
5134 Returns 0 on success.
5134 """
5135 """
5135
5136
5136 if opts["stdio"] and opts["cmdserver"]:
5137 if opts["stdio"] and opts["cmdserver"]:
5137 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5138 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5138
5139
5139 def checkrepo():
5140 def checkrepo():
5140 if repo is None:
5141 if repo is None:
5141 raise error.RepoError(_("there is no Mercurial repository here"
5142 raise error.RepoError(_("there is no Mercurial repository here"
5142 " (.hg not found)"))
5143 " (.hg not found)"))
5143
5144
5144 if opts["stdio"]:
5145 if opts["stdio"]:
5145 checkrepo()
5146 checkrepo()
5146 s = sshserver.sshserver(ui, repo)
5147 s = sshserver.sshserver(ui, repo)
5147 s.serve_forever()
5148 s.serve_forever()
5148
5149
5149 if opts["cmdserver"]:
5150 if opts["cmdserver"]:
5150 checkrepo()
5151 checkrepo()
5151 s = commandserver.server(ui, repo, opts["cmdserver"])
5152 s = commandserver.server(ui, repo, opts["cmdserver"])
5152 return s.serve()
5153 return s.serve()
5153
5154
5154 # this way we can check if something was given in the command-line
5155 # this way we can check if something was given in the command-line
5155 if opts.get('port'):
5156 if opts.get('port'):
5156 opts['port'] = util.getport(opts.get('port'))
5157 opts['port'] = util.getport(opts.get('port'))
5157
5158
5158 baseui = repo and repo.baseui or ui
5159 baseui = repo and repo.baseui or ui
5159 optlist = ("name templates style address port prefix ipv6"
5160 optlist = ("name templates style address port prefix ipv6"
5160 " accesslog errorlog certificate encoding")
5161 " accesslog errorlog certificate encoding")
5161 for o in optlist.split():
5162 for o in optlist.split():
5162 val = opts.get(o, '')
5163 val = opts.get(o, '')
5163 if val in (None, ''): # should check against default options instead
5164 if val in (None, ''): # should check against default options instead
5164 continue
5165 continue
5165 baseui.setconfig("web", o, val)
5166 baseui.setconfig("web", o, val)
5166 if repo and repo.ui != baseui:
5167 if repo and repo.ui != baseui:
5167 repo.ui.setconfig("web", o, val)
5168 repo.ui.setconfig("web", o, val)
5168
5169
5169 o = opts.get('web_conf') or opts.get('webdir_conf')
5170 o = opts.get('web_conf') or opts.get('webdir_conf')
5170 if not o:
5171 if not o:
5171 if not repo:
5172 if not repo:
5172 raise error.RepoError(_("there is no Mercurial repository"
5173 raise error.RepoError(_("there is no Mercurial repository"
5173 " here (.hg not found)"))
5174 " here (.hg not found)"))
5174 o = repo
5175 o = repo
5175
5176
5176 app = hgweb.hgweb(o, baseui=baseui)
5177 app = hgweb.hgweb(o, baseui=baseui)
5177 service = httpservice(ui, app, opts)
5178 service = httpservice(ui, app, opts)
5178 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5179 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5179
5180
5180 class httpservice(object):
5181 class httpservice(object):
5181 def __init__(self, ui, app, opts):
5182 def __init__(self, ui, app, opts):
5182 self.ui = ui
5183 self.ui = ui
5183 self.app = app
5184 self.app = app
5184 self.opts = opts
5185 self.opts = opts
5185
5186
5186 def init(self):
5187 def init(self):
5187 util.setsignalhandler()
5188 util.setsignalhandler()
5188 self.httpd = hgweb_server.create_server(self.ui, self.app)
5189 self.httpd = hgweb_server.create_server(self.ui, self.app)
5189
5190
5190 if self.opts['port'] and not self.ui.verbose:
5191 if self.opts['port'] and not self.ui.verbose:
5191 return
5192 return
5192
5193
5193 if self.httpd.prefix:
5194 if self.httpd.prefix:
5194 prefix = self.httpd.prefix.strip('/') + '/'
5195 prefix = self.httpd.prefix.strip('/') + '/'
5195 else:
5196 else:
5196 prefix = ''
5197 prefix = ''
5197
5198
5198 port = ':%d' % self.httpd.port
5199 port = ':%d' % self.httpd.port
5199 if port == ':80':
5200 if port == ':80':
5200 port = ''
5201 port = ''
5201
5202
5202 bindaddr = self.httpd.addr
5203 bindaddr = self.httpd.addr
5203 if bindaddr == '0.0.0.0':
5204 if bindaddr == '0.0.0.0':
5204 bindaddr = '*'
5205 bindaddr = '*'
5205 elif ':' in bindaddr: # IPv6
5206 elif ':' in bindaddr: # IPv6
5206 bindaddr = '[%s]' % bindaddr
5207 bindaddr = '[%s]' % bindaddr
5207
5208
5208 fqaddr = self.httpd.fqaddr
5209 fqaddr = self.httpd.fqaddr
5209 if ':' in fqaddr:
5210 if ':' in fqaddr:
5210 fqaddr = '[%s]' % fqaddr
5211 fqaddr = '[%s]' % fqaddr
5211 if self.opts['port']:
5212 if self.opts['port']:
5212 write = self.ui.status
5213 write = self.ui.status
5213 else:
5214 else:
5214 write = self.ui.write
5215 write = self.ui.write
5215 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5216 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5216 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5217 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5217
5218
5218 def run(self):
5219 def run(self):
5219 self.httpd.serve_forever()
5220 self.httpd.serve_forever()
5220
5221
5221
5222
5222 @command('showconfig|debugconfig',
5223 @command('showconfig|debugconfig',
5223 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5224 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5224 _('[-u] [NAME]...'))
5225 _('[-u] [NAME]...'))
5225 def showconfig(ui, repo, *values, **opts):
5226 def showconfig(ui, repo, *values, **opts):
5226 """show combined config settings from all hgrc files
5227 """show combined config settings from all hgrc files
5227
5228
5228 With no arguments, print names and values of all config items.
5229 With no arguments, print names and values of all config items.
5229
5230
5230 With one argument of the form section.name, print just the value
5231 With one argument of the form section.name, print just the value
5231 of that config item.
5232 of that config item.
5232
5233
5233 With multiple arguments, print names and values of all config
5234 With multiple arguments, print names and values of all config
5234 items with matching section names.
5235 items with matching section names.
5235
5236
5236 With --debug, the source (filename and line number) is printed
5237 With --debug, the source (filename and line number) is printed
5237 for each config item.
5238 for each config item.
5238
5239
5239 Returns 0 on success.
5240 Returns 0 on success.
5240 """
5241 """
5241
5242
5242 for f in scmutil.rcpath():
5243 for f in scmutil.rcpath():
5243 ui.debug('read config from: %s\n' % f)
5244 ui.debug('read config from: %s\n' % f)
5244 untrusted = bool(opts.get('untrusted'))
5245 untrusted = bool(opts.get('untrusted'))
5245 if values:
5246 if values:
5246 sections = [v for v in values if '.' not in v]
5247 sections = [v for v in values if '.' not in v]
5247 items = [v for v in values if '.' in v]
5248 items = [v for v in values if '.' in v]
5248 if len(items) > 1 or items and sections:
5249 if len(items) > 1 or items and sections:
5249 raise util.Abort(_('only one config item permitted'))
5250 raise util.Abort(_('only one config item permitted'))
5250 for section, name, value in ui.walkconfig(untrusted=untrusted):
5251 for section, name, value in ui.walkconfig(untrusted=untrusted):
5251 value = str(value).replace('\n', '\\n')
5252 value = str(value).replace('\n', '\\n')
5252 sectname = section + '.' + name
5253 sectname = section + '.' + name
5253 if values:
5254 if values:
5254 for v in values:
5255 for v in values:
5255 if v == section:
5256 if v == section:
5256 ui.debug('%s: ' %
5257 ui.debug('%s: ' %
5257 ui.configsource(section, name, untrusted))
5258 ui.configsource(section, name, untrusted))
5258 ui.write('%s=%s\n' % (sectname, value))
5259 ui.write('%s=%s\n' % (sectname, value))
5259 elif v == sectname:
5260 elif v == sectname:
5260 ui.debug('%s: ' %
5261 ui.debug('%s: ' %
5261 ui.configsource(section, name, untrusted))
5262 ui.configsource(section, name, untrusted))
5262 ui.write(value, '\n')
5263 ui.write(value, '\n')
5263 else:
5264 else:
5264 ui.debug('%s: ' %
5265 ui.debug('%s: ' %
5265 ui.configsource(section, name, untrusted))
5266 ui.configsource(section, name, untrusted))
5266 ui.write('%s=%s\n' % (sectname, value))
5267 ui.write('%s=%s\n' % (sectname, value))
5267
5268
5268 @command('^status|st',
5269 @command('^status|st',
5269 [('A', 'all', None, _('show status of all files')),
5270 [('A', 'all', None, _('show status of all files')),
5270 ('m', 'modified', None, _('show only modified files')),
5271 ('m', 'modified', None, _('show only modified files')),
5271 ('a', 'added', None, _('show only added files')),
5272 ('a', 'added', None, _('show only added files')),
5272 ('r', 'removed', None, _('show only removed files')),
5273 ('r', 'removed', None, _('show only removed files')),
5273 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5274 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5274 ('c', 'clean', None, _('show only files without changes')),
5275 ('c', 'clean', None, _('show only files without changes')),
5275 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5276 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5276 ('i', 'ignored', None, _('show only ignored files')),
5277 ('i', 'ignored', None, _('show only ignored files')),
5277 ('n', 'no-status', None, _('hide status prefix')),
5278 ('n', 'no-status', None, _('hide status prefix')),
5278 ('C', 'copies', None, _('show source of copied files')),
5279 ('C', 'copies', None, _('show source of copied files')),
5279 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5280 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5280 ('', 'rev', [], _('show difference from revision'), _('REV')),
5281 ('', 'rev', [], _('show difference from revision'), _('REV')),
5281 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5282 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5282 ] + walkopts + subrepoopts,
5283 ] + walkopts + subrepoopts,
5283 _('[OPTION]... [FILE]...'))
5284 _('[OPTION]... [FILE]...'))
5284 def status(ui, repo, *pats, **opts):
5285 def status(ui, repo, *pats, **opts):
5285 """show changed files in the working directory
5286 """show changed files in the working directory
5286
5287
5287 Show status of files in the repository. If names are given, only
5288 Show status of files in the repository. If names are given, only
5288 files that match are shown. Files that are clean or ignored or
5289 files that match are shown. Files that are clean or ignored or
5289 the source of a copy/move operation, are not listed unless
5290 the source of a copy/move operation, are not listed unless
5290 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5291 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5291 Unless options described with "show only ..." are given, the
5292 Unless options described with "show only ..." are given, the
5292 options -mardu are used.
5293 options -mardu are used.
5293
5294
5294 Option -q/--quiet hides untracked (unknown and ignored) files
5295 Option -q/--quiet hides untracked (unknown and ignored) files
5295 unless explicitly requested with -u/--unknown or -i/--ignored.
5296 unless explicitly requested with -u/--unknown or -i/--ignored.
5296
5297
5297 .. note::
5298 .. note::
5298
5299
5299 status may appear to disagree with diff if permissions have
5300 status may appear to disagree with diff if permissions have
5300 changed or a merge has occurred. The standard diff format does
5301 changed or a merge has occurred. The standard diff format does
5301 not report permission changes and diff only reports changes
5302 not report permission changes and diff only reports changes
5302 relative to one merge parent.
5303 relative to one merge parent.
5303
5304
5304 If one revision is given, it is used as the base revision.
5305 If one revision is given, it is used as the base revision.
5305 If two revisions are given, the differences between them are
5306 If two revisions are given, the differences between them are
5306 shown. The --change option can also be used as a shortcut to list
5307 shown. The --change option can also be used as a shortcut to list
5307 the changed files of a revision from its first parent.
5308 the changed files of a revision from its first parent.
5308
5309
5309 The codes used to show the status of files are::
5310 The codes used to show the status of files are::
5310
5311
5311 M = modified
5312 M = modified
5312 A = added
5313 A = added
5313 R = removed
5314 R = removed
5314 C = clean
5315 C = clean
5315 ! = missing (deleted by non-hg command, but still tracked)
5316 ! = missing (deleted by non-hg command, but still tracked)
5316 ? = not tracked
5317 ? = not tracked
5317 I = ignored
5318 I = ignored
5318 = origin of the previous file listed as A (added)
5319 = origin of the previous file listed as A (added)
5319
5320
5320 .. container:: verbose
5321 .. container:: verbose
5321
5322
5322 Examples:
5323 Examples:
5323
5324
5324 - show changes in the working directory relative to a
5325 - show changes in the working directory relative to a
5325 changeset::
5326 changeset::
5326
5327
5327 hg status --rev 9353
5328 hg status --rev 9353
5328
5329
5329 - show all changes including copies in an existing changeset::
5330 - show all changes including copies in an existing changeset::
5330
5331
5331 hg status --copies --change 9353
5332 hg status --copies --change 9353
5332
5333
5333 - get a NUL separated list of added files, suitable for xargs::
5334 - get a NUL separated list of added files, suitable for xargs::
5334
5335
5335 hg status -an0
5336 hg status -an0
5336
5337
5337 Returns 0 on success.
5338 Returns 0 on success.
5338 """
5339 """
5339
5340
5340 revs = opts.get('rev')
5341 revs = opts.get('rev')
5341 change = opts.get('change')
5342 change = opts.get('change')
5342
5343
5343 if revs and change:
5344 if revs and change:
5344 msg = _('cannot specify --rev and --change at the same time')
5345 msg = _('cannot specify --rev and --change at the same time')
5345 raise util.Abort(msg)
5346 raise util.Abort(msg)
5346 elif change:
5347 elif change:
5347 node2 = scmutil.revsingle(repo, change, None).node()
5348 node2 = scmutil.revsingle(repo, change, None).node()
5348 node1 = repo[node2].p1().node()
5349 node1 = repo[node2].p1().node()
5349 else:
5350 else:
5350 node1, node2 = scmutil.revpair(repo, revs)
5351 node1, node2 = scmutil.revpair(repo, revs)
5351
5352
5352 cwd = (pats and repo.getcwd()) or ''
5353 cwd = (pats and repo.getcwd()) or ''
5353 end = opts.get('print0') and '\0' or '\n'
5354 end = opts.get('print0') and '\0' or '\n'
5354 copy = {}
5355 copy = {}
5355 states = 'modified added removed deleted unknown ignored clean'.split()
5356 states = 'modified added removed deleted unknown ignored clean'.split()
5356 show = [k for k in states if opts.get(k)]
5357 show = [k for k in states if opts.get(k)]
5357 if opts.get('all'):
5358 if opts.get('all'):
5358 show += ui.quiet and (states[:4] + ['clean']) or states
5359 show += ui.quiet and (states[:4] + ['clean']) or states
5359 if not show:
5360 if not show:
5360 show = ui.quiet and states[:4] or states[:5]
5361 show = ui.quiet and states[:4] or states[:5]
5361
5362
5362 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5363 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5363 'ignored' in show, 'clean' in show, 'unknown' in show,
5364 'ignored' in show, 'clean' in show, 'unknown' in show,
5364 opts.get('subrepos'))
5365 opts.get('subrepos'))
5365 changestates = zip(states, 'MAR!?IC', stat)
5366 changestates = zip(states, 'MAR!?IC', stat)
5366
5367
5367 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5368 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5368 copy = copies.pathcopies(repo[node1], repo[node2])
5369 copy = copies.pathcopies(repo[node1], repo[node2])
5369
5370
5370 fm = ui.formatter('status', opts)
5371 fm = ui.formatter('status', opts)
5371 fmt = '%s' + end
5372 fmt = '%s' + end
5372 showchar = not opts.get('no_status')
5373 showchar = not opts.get('no_status')
5373
5374
5374 for state, char, files in changestates:
5375 for state, char, files in changestates:
5375 if state in show:
5376 if state in show:
5376 label = 'status.' + state
5377 label = 'status.' + state
5377 for f in files:
5378 for f in files:
5378 fm.startitem()
5379 fm.startitem()
5379 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5380 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5380 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5381 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5381 if f in copy:
5382 if f in copy:
5382 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5383 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5383 label='status.copied')
5384 label='status.copied')
5384 fm.end()
5385 fm.end()
5385
5386
5386 @command('^summary|sum',
5387 @command('^summary|sum',
5387 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5388 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5388 def summary(ui, repo, **opts):
5389 def summary(ui, repo, **opts):
5389 """summarize working directory state
5390 """summarize working directory state
5390
5391
5391 This generates a brief summary of the working directory state,
5392 This generates a brief summary of the working directory state,
5392 including parents, branch, commit status, and available updates.
5393 including parents, branch, commit status, and available updates.
5393
5394
5394 With the --remote option, this will check the default paths for
5395 With the --remote option, this will check the default paths for
5395 incoming and outgoing changes. This can be time-consuming.
5396 incoming and outgoing changes. This can be time-consuming.
5396
5397
5397 Returns 0 on success.
5398 Returns 0 on success.
5398 """
5399 """
5399
5400
5400 ctx = repo[None]
5401 ctx = repo[None]
5401 parents = ctx.parents()
5402 parents = ctx.parents()
5402 pnode = parents[0].node()
5403 pnode = parents[0].node()
5403 marks = []
5404 marks = []
5404
5405
5405 for p in parents:
5406 for p in parents:
5406 # label with log.changeset (instead of log.parent) since this
5407 # label with log.changeset (instead of log.parent) since this
5407 # shows a working directory parent *changeset*:
5408 # shows a working directory parent *changeset*:
5408 # i18n: column positioning for "hg summary"
5409 # i18n: column positioning for "hg summary"
5409 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5410 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5410 label='log.changeset changeset.%s' % p.phasestr())
5411 label='log.changeset changeset.%s' % p.phasestr())
5411 ui.write(' '.join(p.tags()), label='log.tag')
5412 ui.write(' '.join(p.tags()), label='log.tag')
5412 if p.bookmarks():
5413 if p.bookmarks():
5413 marks.extend(p.bookmarks())
5414 marks.extend(p.bookmarks())
5414 if p.rev() == -1:
5415 if p.rev() == -1:
5415 if not len(repo):
5416 if not len(repo):
5416 ui.write(_(' (empty repository)'))
5417 ui.write(_(' (empty repository)'))
5417 else:
5418 else:
5418 ui.write(_(' (no revision checked out)'))
5419 ui.write(_(' (no revision checked out)'))
5419 ui.write('\n')
5420 ui.write('\n')
5420 if p.description():
5421 if p.description():
5421 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5422 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5422 label='log.summary')
5423 label='log.summary')
5423
5424
5424 branch = ctx.branch()
5425 branch = ctx.branch()
5425 bheads = repo.branchheads(branch)
5426 bheads = repo.branchheads(branch)
5426 # i18n: column positioning for "hg summary"
5427 # i18n: column positioning for "hg summary"
5427 m = _('branch: %s\n') % branch
5428 m = _('branch: %s\n') % branch
5428 if branch != 'default':
5429 if branch != 'default':
5429 ui.write(m, label='log.branch')
5430 ui.write(m, label='log.branch')
5430 else:
5431 else:
5431 ui.status(m, label='log.branch')
5432 ui.status(m, label='log.branch')
5432
5433
5433 if marks:
5434 if marks:
5434 current = repo._bookmarkcurrent
5435 current = repo._bookmarkcurrent
5435 # i18n: column positioning for "hg summary"
5436 # i18n: column positioning for "hg summary"
5436 ui.write(_('bookmarks:'), label='log.bookmark')
5437 ui.write(_('bookmarks:'), label='log.bookmark')
5437 if current is not None:
5438 if current is not None:
5438 if current in marks:
5439 if current in marks:
5439 ui.write(' *' + current, label='bookmarks.current')
5440 ui.write(' *' + current, label='bookmarks.current')
5440 marks.remove(current)
5441 marks.remove(current)
5441 else:
5442 else:
5442 ui.write(' [%s]' % current, label='bookmarks.current')
5443 ui.write(' [%s]' % current, label='bookmarks.current')
5443 for m in marks:
5444 for m in marks:
5444 ui.write(' ' + m, label='log.bookmark')
5445 ui.write(' ' + m, label='log.bookmark')
5445 ui.write('\n', label='log.bookmark')
5446 ui.write('\n', label='log.bookmark')
5446
5447
5447 st = list(repo.status(unknown=True))[:6]
5448 st = list(repo.status(unknown=True))[:6]
5448
5449
5449 c = repo.dirstate.copies()
5450 c = repo.dirstate.copies()
5450 copied, renamed = [], []
5451 copied, renamed = [], []
5451 for d, s in c.iteritems():
5452 for d, s in c.iteritems():
5452 if s in st[2]:
5453 if s in st[2]:
5453 st[2].remove(s)
5454 st[2].remove(s)
5454 renamed.append(d)
5455 renamed.append(d)
5455 else:
5456 else:
5456 copied.append(d)
5457 copied.append(d)
5457 if d in st[1]:
5458 if d in st[1]:
5458 st[1].remove(d)
5459 st[1].remove(d)
5459 st.insert(3, renamed)
5460 st.insert(3, renamed)
5460 st.insert(4, copied)
5461 st.insert(4, copied)
5461
5462
5462 ms = mergemod.mergestate(repo)
5463 ms = mergemod.mergestate(repo)
5463 st.append([f for f in ms if ms[f] == 'u'])
5464 st.append([f for f in ms if ms[f] == 'u'])
5464
5465
5465 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5466 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5466 st.append(subs)
5467 st.append(subs)
5467
5468
5468 labels = [ui.label(_('%d modified'), 'status.modified'),
5469 labels = [ui.label(_('%d modified'), 'status.modified'),
5469 ui.label(_('%d added'), 'status.added'),
5470 ui.label(_('%d added'), 'status.added'),
5470 ui.label(_('%d removed'), 'status.removed'),
5471 ui.label(_('%d removed'), 'status.removed'),
5471 ui.label(_('%d renamed'), 'status.copied'),
5472 ui.label(_('%d renamed'), 'status.copied'),
5472 ui.label(_('%d copied'), 'status.copied'),
5473 ui.label(_('%d copied'), 'status.copied'),
5473 ui.label(_('%d deleted'), 'status.deleted'),
5474 ui.label(_('%d deleted'), 'status.deleted'),
5474 ui.label(_('%d unknown'), 'status.unknown'),
5475 ui.label(_('%d unknown'), 'status.unknown'),
5475 ui.label(_('%d ignored'), 'status.ignored'),
5476 ui.label(_('%d ignored'), 'status.ignored'),
5476 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5477 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5477 ui.label(_('%d subrepos'), 'status.modified')]
5478 ui.label(_('%d subrepos'), 'status.modified')]
5478 t = []
5479 t = []
5479 for s, l in zip(st, labels):
5480 for s, l in zip(st, labels):
5480 if s:
5481 if s:
5481 t.append(l % len(s))
5482 t.append(l % len(s))
5482
5483
5483 t = ', '.join(t)
5484 t = ', '.join(t)
5484 cleanworkdir = False
5485 cleanworkdir = False
5485
5486
5486 if repo.vfs.exists('updatestate'):
5487 if repo.vfs.exists('updatestate'):
5487 t += _(' (interrupted update)')
5488 t += _(' (interrupted update)')
5488 elif len(parents) > 1:
5489 elif len(parents) > 1:
5489 t += _(' (merge)')
5490 t += _(' (merge)')
5490 elif branch != parents[0].branch():
5491 elif branch != parents[0].branch():
5491 t += _(' (new branch)')
5492 t += _(' (new branch)')
5492 elif (parents[0].closesbranch() and
5493 elif (parents[0].closesbranch() and
5493 pnode in repo.branchheads(branch, closed=True)):
5494 pnode in repo.branchheads(branch, closed=True)):
5494 t += _(' (head closed)')
5495 t += _(' (head closed)')
5495 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5496 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5496 t += _(' (clean)')
5497 t += _(' (clean)')
5497 cleanworkdir = True
5498 cleanworkdir = True
5498 elif pnode not in bheads:
5499 elif pnode not in bheads:
5499 t += _(' (new branch head)')
5500 t += _(' (new branch head)')
5500
5501
5501 if cleanworkdir:
5502 if cleanworkdir:
5502 # i18n: column positioning for "hg summary"
5503 # i18n: column positioning for "hg summary"
5503 ui.status(_('commit: %s\n') % t.strip())
5504 ui.status(_('commit: %s\n') % t.strip())
5504 else:
5505 else:
5505 # i18n: column positioning for "hg summary"
5506 # i18n: column positioning for "hg summary"
5506 ui.write(_('commit: %s\n') % t.strip())
5507 ui.write(_('commit: %s\n') % t.strip())
5507
5508
5508 # all ancestors of branch heads - all ancestors of parent = new csets
5509 # all ancestors of branch heads - all ancestors of parent = new csets
5509 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5510 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5510 bheads))
5511 bheads))
5511
5512
5512 if new == 0:
5513 if new == 0:
5513 # i18n: column positioning for "hg summary"
5514 # i18n: column positioning for "hg summary"
5514 ui.status(_('update: (current)\n'))
5515 ui.status(_('update: (current)\n'))
5515 elif pnode not in bheads:
5516 elif pnode not in bheads:
5516 # i18n: column positioning for "hg summary"
5517 # i18n: column positioning for "hg summary"
5517 ui.write(_('update: %d new changesets (update)\n') % new)
5518 ui.write(_('update: %d new changesets (update)\n') % new)
5518 else:
5519 else:
5519 # i18n: column positioning for "hg summary"
5520 # i18n: column positioning for "hg summary"
5520 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5521 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5521 (new, len(bheads)))
5522 (new, len(bheads)))
5522
5523
5523 cmdutil.summaryhooks(ui, repo)
5524 cmdutil.summaryhooks(ui, repo)
5524
5525
5525 if opts.get('remote'):
5526 if opts.get('remote'):
5526 t = []
5527 t = []
5527 source, branches = hg.parseurl(ui.expandpath('default'))
5528 source, branches = hg.parseurl(ui.expandpath('default'))
5528 sbranch = branches[0]
5529 sbranch = branches[0]
5529 other = hg.peer(repo, {}, source)
5530 other = hg.peer(repo, {}, source)
5530 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5531 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5531 if revs:
5532 if revs:
5532 revs = [other.lookup(rev) for rev in revs]
5533 revs = [other.lookup(rev) for rev in revs]
5533 ui.debug('comparing with %s\n' % util.hidepassword(source))
5534 ui.debug('comparing with %s\n' % util.hidepassword(source))
5534 repo.ui.pushbuffer()
5535 repo.ui.pushbuffer()
5535 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5536 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5536 _common, incoming, _rheads = commoninc
5537 _common, incoming, _rheads = commoninc
5537 repo.ui.popbuffer()
5538 repo.ui.popbuffer()
5538 if incoming:
5539 if incoming:
5539 t.append(_('1 or more incoming'))
5540 t.append(_('1 or more incoming'))
5540
5541
5541 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5542 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5542 dbranch = branches[0]
5543 dbranch = branches[0]
5543 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5544 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5544 if source != dest:
5545 if source != dest:
5545 other = hg.peer(repo, {}, dest)
5546 other = hg.peer(repo, {}, dest)
5546 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5547 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5547 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5548 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5548 commoninc = None
5549 commoninc = None
5549 if revs:
5550 if revs:
5550 revs = [repo.lookup(rev) for rev in revs]
5551 revs = [repo.lookup(rev) for rev in revs]
5551 repo.ui.pushbuffer()
5552 repo.ui.pushbuffer()
5552 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5553 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5553 commoninc=commoninc)
5554 commoninc=commoninc)
5554 repo.ui.popbuffer()
5555 repo.ui.popbuffer()
5555 o = outgoing.missing
5556 o = outgoing.missing
5556 if o:
5557 if o:
5557 t.append(_('%d outgoing') % len(o))
5558 t.append(_('%d outgoing') % len(o))
5558 if 'bookmarks' in other.listkeys('namespaces'):
5559 if 'bookmarks' in other.listkeys('namespaces'):
5559 lmarks = repo.listkeys('bookmarks')
5560 lmarks = repo.listkeys('bookmarks')
5560 rmarks = other.listkeys('bookmarks')
5561 rmarks = other.listkeys('bookmarks')
5561 diff = set(rmarks) - set(lmarks)
5562 diff = set(rmarks) - set(lmarks)
5562 if len(diff) > 0:
5563 if len(diff) > 0:
5563 t.append(_('%d incoming bookmarks') % len(diff))
5564 t.append(_('%d incoming bookmarks') % len(diff))
5564 diff = set(lmarks) - set(rmarks)
5565 diff = set(lmarks) - set(rmarks)
5565 if len(diff) > 0:
5566 if len(diff) > 0:
5566 t.append(_('%d outgoing bookmarks') % len(diff))
5567 t.append(_('%d outgoing bookmarks') % len(diff))
5567
5568
5568 if t:
5569 if t:
5569 # i18n: column positioning for "hg summary"
5570 # i18n: column positioning for "hg summary"
5570 ui.write(_('remote: %s\n') % (', '.join(t)))
5571 ui.write(_('remote: %s\n') % (', '.join(t)))
5571 else:
5572 else:
5572 # i18n: column positioning for "hg summary"
5573 # i18n: column positioning for "hg summary"
5573 ui.status(_('remote: (synced)\n'))
5574 ui.status(_('remote: (synced)\n'))
5574
5575
5575 @command('tag',
5576 @command('tag',
5576 [('f', 'force', None, _('force tag')),
5577 [('f', 'force', None, _('force tag')),
5577 ('l', 'local', None, _('make the tag local')),
5578 ('l', 'local', None, _('make the tag local')),
5578 ('r', 'rev', '', _('revision to tag'), _('REV')),
5579 ('r', 'rev', '', _('revision to tag'), _('REV')),
5579 ('', 'remove', None, _('remove a tag')),
5580 ('', 'remove', None, _('remove a tag')),
5580 # -l/--local is already there, commitopts cannot be used
5581 # -l/--local is already there, commitopts cannot be used
5581 ('e', 'edit', None, _('edit commit message')),
5582 ('e', 'edit', None, _('edit commit message')),
5582 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5583 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5583 ] + commitopts2,
5584 ] + commitopts2,
5584 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5585 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5585 def tag(ui, repo, name1, *names, **opts):
5586 def tag(ui, repo, name1, *names, **opts):
5586 """add one or more tags for the current or given revision
5587 """add one or more tags for the current or given revision
5587
5588
5588 Name a particular revision using <name>.
5589 Name a particular revision using <name>.
5589
5590
5590 Tags are used to name particular revisions of the repository and are
5591 Tags are used to name particular revisions of the repository and are
5591 very useful to compare different revisions, to go back to significant
5592 very useful to compare different revisions, to go back to significant
5592 earlier versions or to mark branch points as releases, etc. Changing
5593 earlier versions or to mark branch points as releases, etc. Changing
5593 an existing tag is normally disallowed; use -f/--force to override.
5594 an existing tag is normally disallowed; use -f/--force to override.
5594
5595
5595 If no revision is given, the parent of the working directory is
5596 If no revision is given, the parent of the working directory is
5596 used.
5597 used.
5597
5598
5598 To facilitate version control, distribution, and merging of tags,
5599 To facilitate version control, distribution, and merging of tags,
5599 they are stored as a file named ".hgtags" which is managed similarly
5600 they are stored as a file named ".hgtags" which is managed similarly
5600 to other project files and can be hand-edited if necessary. This
5601 to other project files and can be hand-edited if necessary. This
5601 also means that tagging creates a new commit. The file
5602 also means that tagging creates a new commit. The file
5602 ".hg/localtags" is used for local tags (not shared among
5603 ".hg/localtags" is used for local tags (not shared among
5603 repositories).
5604 repositories).
5604
5605
5605 Tag commits are usually made at the head of a branch. If the parent
5606 Tag commits are usually made at the head of a branch. If the parent
5606 of the working directory is not a branch head, :hg:`tag` aborts; use
5607 of the working directory is not a branch head, :hg:`tag` aborts; use
5607 -f/--force to force the tag commit to be based on a non-head
5608 -f/--force to force the tag commit to be based on a non-head
5608 changeset.
5609 changeset.
5609
5610
5610 See :hg:`help dates` for a list of formats valid for -d/--date.
5611 See :hg:`help dates` for a list of formats valid for -d/--date.
5611
5612
5612 Since tag names have priority over branch names during revision
5613 Since tag names have priority over branch names during revision
5613 lookup, using an existing branch name as a tag name is discouraged.
5614 lookup, using an existing branch name as a tag name is discouraged.
5614
5615
5615 Returns 0 on success.
5616 Returns 0 on success.
5616 """
5617 """
5617 wlock = lock = None
5618 wlock = lock = None
5618 try:
5619 try:
5619 wlock = repo.wlock()
5620 wlock = repo.wlock()
5620 lock = repo.lock()
5621 lock = repo.lock()
5621 rev_ = "."
5622 rev_ = "."
5622 names = [t.strip() for t in (name1,) + names]
5623 names = [t.strip() for t in (name1,) + names]
5623 if len(names) != len(set(names)):
5624 if len(names) != len(set(names)):
5624 raise util.Abort(_('tag names must be unique'))
5625 raise util.Abort(_('tag names must be unique'))
5625 for n in names:
5626 for n in names:
5626 scmutil.checknewlabel(repo, n, 'tag')
5627 scmutil.checknewlabel(repo, n, 'tag')
5627 if not n:
5628 if not n:
5628 raise util.Abort(_('tag names cannot consist entirely of '
5629 raise util.Abort(_('tag names cannot consist entirely of '
5629 'whitespace'))
5630 'whitespace'))
5630 if opts.get('rev') and opts.get('remove'):
5631 if opts.get('rev') and opts.get('remove'):
5631 raise util.Abort(_("--rev and --remove are incompatible"))
5632 raise util.Abort(_("--rev and --remove are incompatible"))
5632 if opts.get('rev'):
5633 if opts.get('rev'):
5633 rev_ = opts['rev']
5634 rev_ = opts['rev']
5634 message = opts.get('message')
5635 message = opts.get('message')
5635 if opts.get('remove'):
5636 if opts.get('remove'):
5636 expectedtype = opts.get('local') and 'local' or 'global'
5637 expectedtype = opts.get('local') and 'local' or 'global'
5637 for n in names:
5638 for n in names:
5638 if not repo.tagtype(n):
5639 if not repo.tagtype(n):
5639 raise util.Abort(_("tag '%s' does not exist") % n)
5640 raise util.Abort(_("tag '%s' does not exist") % n)
5640 if repo.tagtype(n) != expectedtype:
5641 if repo.tagtype(n) != expectedtype:
5641 if expectedtype == 'global':
5642 if expectedtype == 'global':
5642 raise util.Abort(_("tag '%s' is not a global tag") % n)
5643 raise util.Abort(_("tag '%s' is not a global tag") % n)
5643 else:
5644 else:
5644 raise util.Abort(_("tag '%s' is not a local tag") % n)
5645 raise util.Abort(_("tag '%s' is not a local tag") % n)
5645 rev_ = nullid
5646 rev_ = nullid
5646 if not message:
5647 if not message:
5647 # we don't translate commit messages
5648 # we don't translate commit messages
5648 message = 'Removed tag %s' % ', '.join(names)
5649 message = 'Removed tag %s' % ', '.join(names)
5649 elif not opts.get('force'):
5650 elif not opts.get('force'):
5650 for n in names:
5651 for n in names:
5651 if n in repo.tags():
5652 if n in repo.tags():
5652 raise util.Abort(_("tag '%s' already exists "
5653 raise util.Abort(_("tag '%s' already exists "
5653 "(use -f to force)") % n)
5654 "(use -f to force)") % n)
5654 if not opts.get('local'):
5655 if not opts.get('local'):
5655 p1, p2 = repo.dirstate.parents()
5656 p1, p2 = repo.dirstate.parents()
5656 if p2 != nullid:
5657 if p2 != nullid:
5657 raise util.Abort(_('uncommitted merge'))
5658 raise util.Abort(_('uncommitted merge'))
5658 bheads = repo.branchheads()
5659 bheads = repo.branchheads()
5659 if not opts.get('force') and bheads and p1 not in bheads:
5660 if not opts.get('force') and bheads and p1 not in bheads:
5660 raise util.Abort(_('not at a branch head (use -f to force)'))
5661 raise util.Abort(_('not at a branch head (use -f to force)'))
5661 r = scmutil.revsingle(repo, rev_).node()
5662 r = scmutil.revsingle(repo, rev_).node()
5662
5663
5663 if not message:
5664 if not message:
5664 # we don't translate commit messages
5665 # we don't translate commit messages
5665 message = ('Added tag %s for changeset %s' %
5666 message = ('Added tag %s for changeset %s' %
5666 (', '.join(names), short(r)))
5667 (', '.join(names), short(r)))
5667
5668
5668 date = opts.get('date')
5669 date = opts.get('date')
5669 if date:
5670 if date:
5670 date = util.parsedate(date)
5671 date = util.parsedate(date)
5671
5672
5672 if opts.get('edit'):
5673 if opts.get('edit'):
5673 message = ui.edit(message, ui.username())
5674 message = ui.edit(message, ui.username())
5674
5675
5675 # don't allow tagging the null rev
5676 # don't allow tagging the null rev
5676 if (not opts.get('remove') and
5677 if (not opts.get('remove') and
5677 scmutil.revsingle(repo, rev_).rev() == nullrev):
5678 scmutil.revsingle(repo, rev_).rev() == nullrev):
5678 raise util.Abort(_("cannot tag null revision"))
5679 raise util.Abort(_("cannot tag null revision"))
5679
5680
5680 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5681 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5681 finally:
5682 finally:
5682 release(lock, wlock)
5683 release(lock, wlock)
5683
5684
5684 @command('tags', [], '')
5685 @command('tags', [], '')
5685 def tags(ui, repo, **opts):
5686 def tags(ui, repo, **opts):
5686 """list repository tags
5687 """list repository tags
5687
5688
5688 This lists both regular and local tags. When the -v/--verbose
5689 This lists both regular and local tags. When the -v/--verbose
5689 switch is used, a third column "local" is printed for local tags.
5690 switch is used, a third column "local" is printed for local tags.
5690
5691
5691 Returns 0 on success.
5692 Returns 0 on success.
5692 """
5693 """
5693
5694
5694 fm = ui.formatter('tags', opts)
5695 fm = ui.formatter('tags', opts)
5695 hexfunc = ui.debugflag and hex or short
5696 hexfunc = ui.debugflag and hex or short
5696 tagtype = ""
5697 tagtype = ""
5697
5698
5698 for t, n in reversed(repo.tagslist()):
5699 for t, n in reversed(repo.tagslist()):
5699 hn = hexfunc(n)
5700 hn = hexfunc(n)
5700 label = 'tags.normal'
5701 label = 'tags.normal'
5701 tagtype = ''
5702 tagtype = ''
5702 if repo.tagtype(t) == 'local':
5703 if repo.tagtype(t) == 'local':
5703 label = 'tags.local'
5704 label = 'tags.local'
5704 tagtype = 'local'
5705 tagtype = 'local'
5705
5706
5706 fm.startitem()
5707 fm.startitem()
5707 fm.write('tag', '%s', t, label=label)
5708 fm.write('tag', '%s', t, label=label)
5708 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5709 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5709 fm.condwrite(not ui.quiet, 'rev id', fmt,
5710 fm.condwrite(not ui.quiet, 'rev id', fmt,
5710 repo.changelog.rev(n), hn, label=label)
5711 repo.changelog.rev(n), hn, label=label)
5711 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5712 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5712 tagtype, label=label)
5713 tagtype, label=label)
5713 fm.plain('\n')
5714 fm.plain('\n')
5714 fm.end()
5715 fm.end()
5715
5716
5716 @command('tip',
5717 @command('tip',
5717 [('p', 'patch', None, _('show patch')),
5718 [('p', 'patch', None, _('show patch')),
5718 ('g', 'git', None, _('use git extended diff format')),
5719 ('g', 'git', None, _('use git extended diff format')),
5719 ] + templateopts,
5720 ] + templateopts,
5720 _('[-p] [-g]'))
5721 _('[-p] [-g]'))
5721 def tip(ui, repo, **opts):
5722 def tip(ui, repo, **opts):
5722 """show the tip revision (DEPRECATED)
5723 """show the tip revision (DEPRECATED)
5723
5724
5724 The tip revision (usually just called the tip) is the changeset
5725 The tip revision (usually just called the tip) is the changeset
5725 most recently added to the repository (and therefore the most
5726 most recently added to the repository (and therefore the most
5726 recently changed head).
5727 recently changed head).
5727
5728
5728 If you have just made a commit, that commit will be the tip. If
5729 If you have just made a commit, that commit will be the tip. If
5729 you have just pulled changes from another repository, the tip of
5730 you have just pulled changes from another repository, the tip of
5730 that repository becomes the current tip. The "tip" tag is special
5731 that repository becomes the current tip. The "tip" tag is special
5731 and cannot be renamed or assigned to a different changeset.
5732 and cannot be renamed or assigned to a different changeset.
5732
5733
5733 This command is deprecated, please use :hg:`heads` instead.
5734 This command is deprecated, please use :hg:`heads` instead.
5734
5735
5735 Returns 0 on success.
5736 Returns 0 on success.
5736 """
5737 """
5737 displayer = cmdutil.show_changeset(ui, repo, opts)
5738 displayer = cmdutil.show_changeset(ui, repo, opts)
5738 displayer.show(repo['tip'])
5739 displayer.show(repo['tip'])
5739 displayer.close()
5740 displayer.close()
5740
5741
5741 @command('unbundle',
5742 @command('unbundle',
5742 [('u', 'update', None,
5743 [('u', 'update', None,
5743 _('update to new branch head if changesets were unbundled'))],
5744 _('update to new branch head if changesets were unbundled'))],
5744 _('[-u] FILE...'))
5745 _('[-u] FILE...'))
5745 def unbundle(ui, repo, fname1, *fnames, **opts):
5746 def unbundle(ui, repo, fname1, *fnames, **opts):
5746 """apply one or more changegroup files
5747 """apply one or more changegroup files
5747
5748
5748 Apply one or more compressed changegroup files generated by the
5749 Apply one or more compressed changegroup files generated by the
5749 bundle command.
5750 bundle command.
5750
5751
5751 Returns 0 on success, 1 if an update has unresolved files.
5752 Returns 0 on success, 1 if an update has unresolved files.
5752 """
5753 """
5753 fnames = (fname1,) + fnames
5754 fnames = (fname1,) + fnames
5754
5755
5755 lock = repo.lock()
5756 lock = repo.lock()
5756 wc = repo['.']
5757 wc = repo['.']
5757 try:
5758 try:
5758 for fname in fnames:
5759 for fname in fnames:
5759 f = hg.openpath(ui, fname)
5760 f = hg.openpath(ui, fname)
5760 gen = changegroup.readbundle(f, fname)
5761 gen = changegroup.readbundle(f, fname)
5761 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5762 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5762 finally:
5763 finally:
5763 lock.release()
5764 lock.release()
5764 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5765 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5765 return postincoming(ui, repo, modheads, opts.get('update'), None)
5766 return postincoming(ui, repo, modheads, opts.get('update'), None)
5766
5767
5767 @command('^update|up|checkout|co',
5768 @command('^update|up|checkout|co',
5768 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5769 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5769 ('c', 'check', None,
5770 ('c', 'check', None,
5770 _('update across branches if no uncommitted changes')),
5771 _('update across branches if no uncommitted changes')),
5771 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5772 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5772 ('r', 'rev', '', _('revision'), _('REV'))],
5773 ('r', 'rev', '', _('revision'), _('REV'))],
5773 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5774 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5774 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5775 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5775 """update working directory (or switch revisions)
5776 """update working directory (or switch revisions)
5776
5777
5777 Update the repository's working directory to the specified
5778 Update the repository's working directory to the specified
5778 changeset. If no changeset is specified, update to the tip of the
5779 changeset. If no changeset is specified, update to the tip of the
5779 current named branch and move the current bookmark (see :hg:`help
5780 current named branch and move the current bookmark (see :hg:`help
5780 bookmarks`).
5781 bookmarks`).
5781
5782
5782 Update sets the working directory's parent revision to the specified
5783 Update sets the working directory's parent revision to the specified
5783 changeset (see :hg:`help parents`).
5784 changeset (see :hg:`help parents`).
5784
5785
5785 If the changeset is not a descendant or ancestor of the working
5786 If the changeset is not a descendant or ancestor of the working
5786 directory's parent, the update is aborted. With the -c/--check
5787 directory's parent, the update is aborted. With the -c/--check
5787 option, the working directory is checked for uncommitted changes; if
5788 option, the working directory is checked for uncommitted changes; if
5788 none are found, the working directory is updated to the specified
5789 none are found, the working directory is updated to the specified
5789 changeset.
5790 changeset.
5790
5791
5791 .. container:: verbose
5792 .. container:: verbose
5792
5793
5793 The following rules apply when the working directory contains
5794 The following rules apply when the working directory contains
5794 uncommitted changes:
5795 uncommitted changes:
5795
5796
5796 1. If neither -c/--check nor -C/--clean is specified, and if
5797 1. If neither -c/--check nor -C/--clean is specified, and if
5797 the requested changeset is an ancestor or descendant of
5798 the requested changeset is an ancestor or descendant of
5798 the working directory's parent, the uncommitted changes
5799 the working directory's parent, the uncommitted changes
5799 are merged into the requested changeset and the merged
5800 are merged into the requested changeset and the merged
5800 result is left uncommitted. If the requested changeset is
5801 result is left uncommitted. If the requested changeset is
5801 not an ancestor or descendant (that is, it is on another
5802 not an ancestor or descendant (that is, it is on another
5802 branch), the update is aborted and the uncommitted changes
5803 branch), the update is aborted and the uncommitted changes
5803 are preserved.
5804 are preserved.
5804
5805
5805 2. With the -c/--check option, the update is aborted and the
5806 2. With the -c/--check option, the update is aborted and the
5806 uncommitted changes are preserved.
5807 uncommitted changes are preserved.
5807
5808
5808 3. With the -C/--clean option, uncommitted changes are discarded and
5809 3. With the -C/--clean option, uncommitted changes are discarded and
5809 the working directory is updated to the requested changeset.
5810 the working directory is updated to the requested changeset.
5810
5811
5811 To cancel an uncommitted merge (and lose your changes), use
5812 To cancel an uncommitted merge (and lose your changes), use
5812 :hg:`update --clean .`.
5813 :hg:`update --clean .`.
5813
5814
5814 Use null as the changeset to remove the working directory (like
5815 Use null as the changeset to remove the working directory (like
5815 :hg:`clone -U`).
5816 :hg:`clone -U`).
5816
5817
5817 If you want to revert just one file to an older revision, use
5818 If you want to revert just one file to an older revision, use
5818 :hg:`revert [-r REV] NAME`.
5819 :hg:`revert [-r REV] NAME`.
5819
5820
5820 See :hg:`help dates` for a list of formats valid for -d/--date.
5821 See :hg:`help dates` for a list of formats valid for -d/--date.
5821
5822
5822 Returns 0 on success, 1 if there are unresolved files.
5823 Returns 0 on success, 1 if there are unresolved files.
5823 """
5824 """
5824 if rev and node:
5825 if rev and node:
5825 raise util.Abort(_("please specify just one revision"))
5826 raise util.Abort(_("please specify just one revision"))
5826
5827
5827 if rev is None or rev == '':
5828 if rev is None or rev == '':
5828 rev = node
5829 rev = node
5829
5830
5830 cmdutil.clearunfinished(repo)
5831 cmdutil.clearunfinished(repo)
5831
5832
5832 # with no argument, we also move the current bookmark, if any
5833 # with no argument, we also move the current bookmark, if any
5833 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5834 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5834
5835
5835 # if we defined a bookmark, we have to remember the original bookmark name
5836 # if we defined a bookmark, we have to remember the original bookmark name
5836 brev = rev
5837 brev = rev
5837 rev = scmutil.revsingle(repo, rev, rev).rev()
5838 rev = scmutil.revsingle(repo, rev, rev).rev()
5838
5839
5839 if check and clean:
5840 if check and clean:
5840 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5841 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5841
5842
5842 if date:
5843 if date:
5843 if rev is not None:
5844 if rev is not None:
5844 raise util.Abort(_("you can't specify a revision and a date"))
5845 raise util.Abort(_("you can't specify a revision and a date"))
5845 rev = cmdutil.finddate(ui, repo, date)
5846 rev = cmdutil.finddate(ui, repo, date)
5846
5847
5847 if check:
5848 if check:
5848 c = repo[None]
5849 c = repo[None]
5849 if c.dirty(merge=False, branch=False, missing=True):
5850 if c.dirty(merge=False, branch=False, missing=True):
5850 raise util.Abort(_("uncommitted changes"))
5851 raise util.Abort(_("uncommitted changes"))
5851 if rev is None:
5852 if rev is None:
5852 rev = repo[repo[None].branch()].rev()
5853 rev = repo[repo[None].branch()].rev()
5853 mergemod._checkunknown(repo, repo[None], repo[rev])
5854 mergemod._checkunknown(repo, repo[None], repo[rev])
5854
5855
5855 if clean:
5856 if clean:
5856 ret = hg.clean(repo, rev)
5857 ret = hg.clean(repo, rev)
5857 else:
5858 else:
5858 ret = hg.update(repo, rev)
5859 ret = hg.update(repo, rev)
5859
5860
5860 if not ret and movemarkfrom:
5861 if not ret and movemarkfrom:
5861 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5862 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5862 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5863 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5863 elif brev in repo._bookmarks:
5864 elif brev in repo._bookmarks:
5864 bookmarks.setcurrent(repo, brev)
5865 bookmarks.setcurrent(repo, brev)
5865 elif brev:
5866 elif brev:
5866 bookmarks.unsetcurrent(repo)
5867 bookmarks.unsetcurrent(repo)
5867
5868
5868 return ret
5869 return ret
5869
5870
5870 @command('verify', [])
5871 @command('verify', [])
5871 def verify(ui, repo):
5872 def verify(ui, repo):
5872 """verify the integrity of the repository
5873 """verify the integrity of the repository
5873
5874
5874 Verify the integrity of the current repository.
5875 Verify the integrity of the current repository.
5875
5876
5876 This will perform an extensive check of the repository's
5877 This will perform an extensive check of the repository's
5877 integrity, validating the hashes and checksums of each entry in
5878 integrity, validating the hashes and checksums of each entry in
5878 the changelog, manifest, and tracked files, as well as the
5879 the changelog, manifest, and tracked files, as well as the
5879 integrity of their crosslinks and indices.
5880 integrity of their crosslinks and indices.
5880
5881
5881 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5882 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5882 for more information about recovery from corruption of the
5883 for more information about recovery from corruption of the
5883 repository.
5884 repository.
5884
5885
5885 Returns 0 on success, 1 if errors are encountered.
5886 Returns 0 on success, 1 if errors are encountered.
5886 """
5887 """
5887 return hg.verify(repo)
5888 return hg.verify(repo)
5888
5889
5889 @command('version', [])
5890 @command('version', [])
5890 def version_(ui):
5891 def version_(ui):
5891 """output version and copyright information"""
5892 """output version and copyright information"""
5892 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5893 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5893 % util.version())
5894 % util.version())
5894 ui.status(_(
5895 ui.status(_(
5895 "(see http://mercurial.selenic.com for more information)\n"
5896 "(see http://mercurial.selenic.com for more information)\n"
5896 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
5897 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
5897 "This is free software; see the source for copying conditions. "
5898 "This is free software; see the source for copying conditions. "
5898 "There is NO\nwarranty; "
5899 "There is NO\nwarranty; "
5899 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5900 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5900 ))
5901 ))
5901
5902
5902 norepo = ("clone init version help debugcommands debugcomplete"
5903 norepo = ("clone init version help debugcommands debugcomplete"
5903 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5904 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5904 " debugknown debuggetbundle debugbundle")
5905 " debugknown debuggetbundle debugbundle")
5905 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5906 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5906 " debugdata debugindex debugindexdot debugrevlog")
5907 " debugdata debugindex debugindexdot debugrevlog")
5907 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5908 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5908 " remove resolve status debugwalk")
5909 " remove resolve status debugwalk")
@@ -1,571 +1,607 b''
1 $ hg init
1 $ hg init
2
2
3
3
4 committing changes
4 committing changes
5
5
6 $ count=0
6 $ count=0
7 $ echo > a
7 $ echo > a
8 $ while test $count -lt 32 ; do
8 $ while test $count -lt 32 ; do
9 > echo 'a' >> a
9 > echo 'a' >> a
10 > test $count -eq 0 && hg add
10 > test $count -eq 0 && hg add
11 > hg ci -m "msg $count" -d "$count 0"
11 > hg ci -m "msg $count" -d "$count 0"
12 > count=`expr $count + 1`
12 > count=`expr $count + 1`
13 > done
13 > done
14 adding a
14 adding a
15
15
16
16
17 $ hg log
17 $ hg log
18 changeset: 31:58c80a7c8a40
18 changeset: 31:58c80a7c8a40
19 tag: tip
19 tag: tip
20 user: test
20 user: test
21 date: Thu Jan 01 00:00:31 1970 +0000
21 date: Thu Jan 01 00:00:31 1970 +0000
22 summary: msg 31
22 summary: msg 31
23
23
24 changeset: 30:ed2d2f24b11c
24 changeset: 30:ed2d2f24b11c
25 user: test
25 user: test
26 date: Thu Jan 01 00:00:30 1970 +0000
26 date: Thu Jan 01 00:00:30 1970 +0000
27 summary: msg 30
27 summary: msg 30
28
28
29 changeset: 29:b5bd63375ab9
29 changeset: 29:b5bd63375ab9
30 user: test
30 user: test
31 date: Thu Jan 01 00:00:29 1970 +0000
31 date: Thu Jan 01 00:00:29 1970 +0000
32 summary: msg 29
32 summary: msg 29
33
33
34 changeset: 28:8e0c2264c8af
34 changeset: 28:8e0c2264c8af
35 user: test
35 user: test
36 date: Thu Jan 01 00:00:28 1970 +0000
36 date: Thu Jan 01 00:00:28 1970 +0000
37 summary: msg 28
37 summary: msg 28
38
38
39 changeset: 27:288867a866e9
39 changeset: 27:288867a866e9
40 user: test
40 user: test
41 date: Thu Jan 01 00:00:27 1970 +0000
41 date: Thu Jan 01 00:00:27 1970 +0000
42 summary: msg 27
42 summary: msg 27
43
43
44 changeset: 26:3efc6fd51aeb
44 changeset: 26:3efc6fd51aeb
45 user: test
45 user: test
46 date: Thu Jan 01 00:00:26 1970 +0000
46 date: Thu Jan 01 00:00:26 1970 +0000
47 summary: msg 26
47 summary: msg 26
48
48
49 changeset: 25:02a84173a97a
49 changeset: 25:02a84173a97a
50 user: test
50 user: test
51 date: Thu Jan 01 00:00:25 1970 +0000
51 date: Thu Jan 01 00:00:25 1970 +0000
52 summary: msg 25
52 summary: msg 25
53
53
54 changeset: 24:10e0acd3809e
54 changeset: 24:10e0acd3809e
55 user: test
55 user: test
56 date: Thu Jan 01 00:00:24 1970 +0000
56 date: Thu Jan 01 00:00:24 1970 +0000
57 summary: msg 24
57 summary: msg 24
58
58
59 changeset: 23:5ec79163bff4
59 changeset: 23:5ec79163bff4
60 user: test
60 user: test
61 date: Thu Jan 01 00:00:23 1970 +0000
61 date: Thu Jan 01 00:00:23 1970 +0000
62 summary: msg 23
62 summary: msg 23
63
63
64 changeset: 22:06c7993750ce
64 changeset: 22:06c7993750ce
65 user: test
65 user: test
66 date: Thu Jan 01 00:00:22 1970 +0000
66 date: Thu Jan 01 00:00:22 1970 +0000
67 summary: msg 22
67 summary: msg 22
68
68
69 changeset: 21:e5db6aa3fe2a
69 changeset: 21:e5db6aa3fe2a
70 user: test
70 user: test
71 date: Thu Jan 01 00:00:21 1970 +0000
71 date: Thu Jan 01 00:00:21 1970 +0000
72 summary: msg 21
72 summary: msg 21
73
73
74 changeset: 20:7128fb4fdbc9
74 changeset: 20:7128fb4fdbc9
75 user: test
75 user: test
76 date: Thu Jan 01 00:00:20 1970 +0000
76 date: Thu Jan 01 00:00:20 1970 +0000
77 summary: msg 20
77 summary: msg 20
78
78
79 changeset: 19:52798545b482
79 changeset: 19:52798545b482
80 user: test
80 user: test
81 date: Thu Jan 01 00:00:19 1970 +0000
81 date: Thu Jan 01 00:00:19 1970 +0000
82 summary: msg 19
82 summary: msg 19
83
83
84 changeset: 18:86977a90077e
84 changeset: 18:86977a90077e
85 user: test
85 user: test
86 date: Thu Jan 01 00:00:18 1970 +0000
86 date: Thu Jan 01 00:00:18 1970 +0000
87 summary: msg 18
87 summary: msg 18
88
88
89 changeset: 17:03515f4a9080
89 changeset: 17:03515f4a9080
90 user: test
90 user: test
91 date: Thu Jan 01 00:00:17 1970 +0000
91 date: Thu Jan 01 00:00:17 1970 +0000
92 summary: msg 17
92 summary: msg 17
93
93
94 changeset: 16:a2e6ea4973e9
94 changeset: 16:a2e6ea4973e9
95 user: test
95 user: test
96 date: Thu Jan 01 00:00:16 1970 +0000
96 date: Thu Jan 01 00:00:16 1970 +0000
97 summary: msg 16
97 summary: msg 16
98
98
99 changeset: 15:e7fa0811edb0
99 changeset: 15:e7fa0811edb0
100 user: test
100 user: test
101 date: Thu Jan 01 00:00:15 1970 +0000
101 date: Thu Jan 01 00:00:15 1970 +0000
102 summary: msg 15
102 summary: msg 15
103
103
104 changeset: 14:ce8f0998e922
104 changeset: 14:ce8f0998e922
105 user: test
105 user: test
106 date: Thu Jan 01 00:00:14 1970 +0000
106 date: Thu Jan 01 00:00:14 1970 +0000
107 summary: msg 14
107 summary: msg 14
108
108
109 changeset: 13:9d7d07bc967c
109 changeset: 13:9d7d07bc967c
110 user: test
110 user: test
111 date: Thu Jan 01 00:00:13 1970 +0000
111 date: Thu Jan 01 00:00:13 1970 +0000
112 summary: msg 13
112 summary: msg 13
113
113
114 changeset: 12:1941b52820a5
114 changeset: 12:1941b52820a5
115 user: test
115 user: test
116 date: Thu Jan 01 00:00:12 1970 +0000
116 date: Thu Jan 01 00:00:12 1970 +0000
117 summary: msg 12
117 summary: msg 12
118
118
119 changeset: 11:7b4cd9578619
119 changeset: 11:7b4cd9578619
120 user: test
120 user: test
121 date: Thu Jan 01 00:00:11 1970 +0000
121 date: Thu Jan 01 00:00:11 1970 +0000
122 summary: msg 11
122 summary: msg 11
123
123
124 changeset: 10:7c5eff49a6b6
124 changeset: 10:7c5eff49a6b6
125 user: test
125 user: test
126 date: Thu Jan 01 00:00:10 1970 +0000
126 date: Thu Jan 01 00:00:10 1970 +0000
127 summary: msg 10
127 summary: msg 10
128
128
129 changeset: 9:eb44510ef29a
129 changeset: 9:eb44510ef29a
130 user: test
130 user: test
131 date: Thu Jan 01 00:00:09 1970 +0000
131 date: Thu Jan 01 00:00:09 1970 +0000
132 summary: msg 9
132 summary: msg 9
133
133
134 changeset: 8:453eb4dba229
134 changeset: 8:453eb4dba229
135 user: test
135 user: test
136 date: Thu Jan 01 00:00:08 1970 +0000
136 date: Thu Jan 01 00:00:08 1970 +0000
137 summary: msg 8
137 summary: msg 8
138
138
139 changeset: 7:03750880c6b5
139 changeset: 7:03750880c6b5
140 user: test
140 user: test
141 date: Thu Jan 01 00:00:07 1970 +0000
141 date: Thu Jan 01 00:00:07 1970 +0000
142 summary: msg 7
142 summary: msg 7
143
143
144 changeset: 6:a3d5c6fdf0d3
144 changeset: 6:a3d5c6fdf0d3
145 user: test
145 user: test
146 date: Thu Jan 01 00:00:06 1970 +0000
146 date: Thu Jan 01 00:00:06 1970 +0000
147 summary: msg 6
147 summary: msg 6
148
148
149 changeset: 5:7874a09ea728
149 changeset: 5:7874a09ea728
150 user: test
150 user: test
151 date: Thu Jan 01 00:00:05 1970 +0000
151 date: Thu Jan 01 00:00:05 1970 +0000
152 summary: msg 5
152 summary: msg 5
153
153
154 changeset: 4:9b2ba8336a65
154 changeset: 4:9b2ba8336a65
155 user: test
155 user: test
156 date: Thu Jan 01 00:00:04 1970 +0000
156 date: Thu Jan 01 00:00:04 1970 +0000
157 summary: msg 4
157 summary: msg 4
158
158
159 changeset: 3:b53bea5e2fcb
159 changeset: 3:b53bea5e2fcb
160 user: test
160 user: test
161 date: Thu Jan 01 00:00:03 1970 +0000
161 date: Thu Jan 01 00:00:03 1970 +0000
162 summary: msg 3
162 summary: msg 3
163
163
164 changeset: 2:db07c04beaca
164 changeset: 2:db07c04beaca
165 user: test
165 user: test
166 date: Thu Jan 01 00:00:02 1970 +0000
166 date: Thu Jan 01 00:00:02 1970 +0000
167 summary: msg 2
167 summary: msg 2
168
168
169 changeset: 1:5cd978ea5149
169 changeset: 1:5cd978ea5149
170 user: test
170 user: test
171 date: Thu Jan 01 00:00:01 1970 +0000
171 date: Thu Jan 01 00:00:01 1970 +0000
172 summary: msg 1
172 summary: msg 1
173
173
174 changeset: 0:b99c7b9c8e11
174 changeset: 0:b99c7b9c8e11
175 user: test
175 user: test
176 date: Thu Jan 01 00:00:00 1970 +0000
176 date: Thu Jan 01 00:00:00 1970 +0000
177 summary: msg 0
177 summary: msg 0
178
178
179
179
180 $ hg up -C
180 $ hg up -C
181 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
181 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
182
182
183 bisect test
183 bisect test
184
184
185 $ hg bisect -r
185 $ hg bisect -r
186 $ hg bisect -b
186 $ hg bisect -b
187 $ hg summary
187 $ hg summary
188 parent: 31:58c80a7c8a40 tip
188 parent: 31:58c80a7c8a40 tip
189 msg 31
189 msg 31
190 branch: default
190 branch: default
191 commit: (clean)
191 commit: (clean)
192 update: (current)
192 update: (current)
193 $ hg bisect -g 1
193 $ hg bisect -g 1
194 Testing changeset 16:a2e6ea4973e9 (30 changesets remaining, ~4 tests)
194 Testing changeset 16:a2e6ea4973e9 (30 changesets remaining, ~4 tests)
195 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
195 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
196 $ hg bisect -g
196 $ hg bisect -g
197 Testing changeset 23:5ec79163bff4 (15 changesets remaining, ~3 tests)
197 Testing changeset 23:5ec79163bff4 (15 changesets remaining, ~3 tests)
198 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
198 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
199
199
200 skip
200 skip
201
201
202 $ hg bisect -s
202 $ hg bisect -s
203 Testing changeset 24:10e0acd3809e (15 changesets remaining, ~3 tests)
203 Testing changeset 24:10e0acd3809e (15 changesets remaining, ~3 tests)
204 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
204 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
205 $ hg bisect -g
205 $ hg bisect -g
206 Testing changeset 27:288867a866e9 (7 changesets remaining, ~2 tests)
206 Testing changeset 27:288867a866e9 (7 changesets remaining, ~2 tests)
207 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
207 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
208 $ hg bisect -g
208 $ hg bisect -g
209 Testing changeset 29:b5bd63375ab9 (4 changesets remaining, ~2 tests)
209 Testing changeset 29:b5bd63375ab9 (4 changesets remaining, ~2 tests)
210 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
210 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
211 $ hg bisect -b
211 $ hg bisect -b
212 Testing changeset 28:8e0c2264c8af (2 changesets remaining, ~1 tests)
212 Testing changeset 28:8e0c2264c8af (2 changesets remaining, ~1 tests)
213 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
213 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
214 $ hg bisect -g
214 $ hg bisect -g
215 The first bad revision is:
215 The first bad revision is:
216 changeset: 29:b5bd63375ab9
216 changeset: 29:b5bd63375ab9
217 user: test
217 user: test
218 date: Thu Jan 01 00:00:29 1970 +0000
218 date: Thu Jan 01 00:00:29 1970 +0000
219 summary: msg 29
219 summary: msg 29
220
220
221
221
222 mark revsets instead of single revs
222 mark revsets instead of single revs
223
223
224 $ hg bisect -r
224 $ hg bisect -r
225 $ hg bisect -b "0::3"
225 $ hg bisect -b "0::3"
226 $ hg bisect -s "13::16"
226 $ hg bisect -s "13::16"
227 $ hg bisect -g "26::tip"
227 $ hg bisect -g "26::tip"
228 Testing changeset 12:1941b52820a5 (23 changesets remaining, ~4 tests)
228 Testing changeset 12:1941b52820a5 (23 changesets remaining, ~4 tests)
229 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
229 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
230 $ cat .hg/bisect.state
230 $ cat .hg/bisect.state
231 bad b99c7b9c8e11558adef3fad9af211c58d46f325b
231 bad b99c7b9c8e11558adef3fad9af211c58d46f325b
232 bad 5cd978ea51499179507ee7b6f340d2dbaa401185
232 bad 5cd978ea51499179507ee7b6f340d2dbaa401185
233 bad db07c04beaca44cf24832541e7f4a2346a95275b
233 bad db07c04beaca44cf24832541e7f4a2346a95275b
234 bad b53bea5e2fcb30d3e00bd3409507a5659ce0fd8b
234 bad b53bea5e2fcb30d3e00bd3409507a5659ce0fd8b
235 current 1941b52820a544549596820a8ae006842b0e2c64
235 current 1941b52820a544549596820a8ae006842b0e2c64
236 good 3efc6fd51aeb8594398044c6c846ca59ae021203
236 good 3efc6fd51aeb8594398044c6c846ca59ae021203
237 good 288867a866e9adb7a29880b66936c874b80f4651
237 good 288867a866e9adb7a29880b66936c874b80f4651
238 good 8e0c2264c8af790daf3585ada0669d93dee09c83
238 good 8e0c2264c8af790daf3585ada0669d93dee09c83
239 good b5bd63375ab9a290419f2024b7f4ee9ea7ce90a8
239 good b5bd63375ab9a290419f2024b7f4ee9ea7ce90a8
240 good ed2d2f24b11c368fa8aa0da9f4e1db580abade59
240 good ed2d2f24b11c368fa8aa0da9f4e1db580abade59
241 good 58c80a7c8a4025a94cedaf7b4a4e3124e8909a96
241 good 58c80a7c8a4025a94cedaf7b4a4e3124e8909a96
242 skip 9d7d07bc967ca98ad0600c24953fd289ad5fa991
242 skip 9d7d07bc967ca98ad0600c24953fd289ad5fa991
243 skip ce8f0998e922c179e80819d5066fbe46e2998784
243 skip ce8f0998e922c179e80819d5066fbe46e2998784
244 skip e7fa0811edb063f6319531f0d0a865882138e180
244 skip e7fa0811edb063f6319531f0d0a865882138e180
245 skip a2e6ea4973e9196ddd3386493b0c214b41fd97d3
245 skip a2e6ea4973e9196ddd3386493b0c214b41fd97d3
246
246
247 bisect reverse test
247 bisect reverse test
248
248
249 $ hg bisect -r
249 $ hg bisect -r
250 $ hg bisect -b null
250 $ hg bisect -b null
251 $ hg bisect -g tip
251 $ hg bisect -g tip
252 Testing changeset 15:e7fa0811edb0 (32 changesets remaining, ~5 tests)
252 Testing changeset 15:e7fa0811edb0 (32 changesets remaining, ~5 tests)
253 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
253 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
254 $ hg bisect -g
254 $ hg bisect -g
255 Testing changeset 7:03750880c6b5 (16 changesets remaining, ~4 tests)
255 Testing changeset 7:03750880c6b5 (16 changesets remaining, ~4 tests)
256 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
256 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
257
257
258 skip
258 skip
259
259
260 $ hg bisect -s
260 $ hg bisect -s
261 Testing changeset 6:a3d5c6fdf0d3 (16 changesets remaining, ~4 tests)
261 Testing changeset 6:a3d5c6fdf0d3 (16 changesets remaining, ~4 tests)
262 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
262 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
263 $ hg bisect -g
263 $ hg bisect -g
264 Testing changeset 2:db07c04beaca (7 changesets remaining, ~2 tests)
264 Testing changeset 2:db07c04beaca (7 changesets remaining, ~2 tests)
265 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
265 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
266 $ hg bisect -g
266 $ hg bisect -g
267 Testing changeset 0:b99c7b9c8e11 (3 changesets remaining, ~1 tests)
267 Testing changeset 0:b99c7b9c8e11 (3 changesets remaining, ~1 tests)
268 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
268 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
269 $ hg bisect -b
269 $ hg bisect -b
270 Testing changeset 1:5cd978ea5149 (2 changesets remaining, ~1 tests)
270 Testing changeset 1:5cd978ea5149 (2 changesets remaining, ~1 tests)
271 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
271 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
272 $ hg bisect -g
272 $ hg bisect -g
273 The first good revision is:
273 The first good revision is:
274 changeset: 1:5cd978ea5149
274 changeset: 1:5cd978ea5149
275 user: test
275 user: test
276 date: Thu Jan 01 00:00:01 1970 +0000
276 date: Thu Jan 01 00:00:01 1970 +0000
277 summary: msg 1
277 summary: msg 1
278
278
279
279
280 $ hg bisect -r
280 $ hg bisect -r
281 $ hg bisect -g tip
281 $ hg bisect -g tip
282 $ hg bisect -b tip
282 $ hg bisect -b tip
283 abort: inconsistent state, 31:58c80a7c8a40 is good and bad
283 abort: inconsistent state, 31:58c80a7c8a40 is good and bad
284 [255]
284 [255]
285
285
286 $ hg bisect -r
286 $ hg bisect -r
287 $ hg bisect -g null
287 $ hg bisect -g null
288 $ hg bisect -bU tip
288 $ hg bisect -bU tip
289 Testing changeset 15:e7fa0811edb0 (32 changesets remaining, ~5 tests)
289 Testing changeset 15:e7fa0811edb0 (32 changesets remaining, ~5 tests)
290 $ hg id
290 $ hg id
291 5cd978ea5149
291 5cd978ea5149
292
292
293
293
294 Issue1228: hg bisect crashes when you skip the last rev in bisection
294 Issue1228: hg bisect crashes when you skip the last rev in bisection
295 Issue1182: hg bisect exception
295 Issue1182: hg bisect exception
296
296
297 $ hg bisect -r
297 $ hg bisect -r
298 $ hg bisect -b 4
298 $ hg bisect -b 4
299 $ hg bisect -g 0
299 $ hg bisect -g 0
300 Testing changeset 2:db07c04beaca (4 changesets remaining, ~2 tests)
300 Testing changeset 2:db07c04beaca (4 changesets remaining, ~2 tests)
301 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
301 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
302 $ hg bisect -s
302 $ hg bisect -s
303 Testing changeset 1:5cd978ea5149 (4 changesets remaining, ~2 tests)
303 Testing changeset 1:5cd978ea5149 (4 changesets remaining, ~2 tests)
304 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
304 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
305 $ hg bisect -s
305 $ hg bisect -s
306 Testing changeset 3:b53bea5e2fcb (4 changesets remaining, ~2 tests)
306 Testing changeset 3:b53bea5e2fcb (4 changesets remaining, ~2 tests)
307 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
307 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
308 $ hg bisect -s
308 $ hg bisect -s
309 Due to skipped revisions, the first bad revision could be any of:
309 Due to skipped revisions, the first bad revision could be any of:
310 changeset: 1:5cd978ea5149
310 changeset: 1:5cd978ea5149
311 user: test
311 user: test
312 date: Thu Jan 01 00:00:01 1970 +0000
312 date: Thu Jan 01 00:00:01 1970 +0000
313 summary: msg 1
313 summary: msg 1
314
314
315 changeset: 2:db07c04beaca
315 changeset: 2:db07c04beaca
316 user: test
316 user: test
317 date: Thu Jan 01 00:00:02 1970 +0000
317 date: Thu Jan 01 00:00:02 1970 +0000
318 summary: msg 2
318 summary: msg 2
319
319
320 changeset: 3:b53bea5e2fcb
320 changeset: 3:b53bea5e2fcb
321 user: test
321 user: test
322 date: Thu Jan 01 00:00:03 1970 +0000
322 date: Thu Jan 01 00:00:03 1970 +0000
323 summary: msg 3
323 summary: msg 3
324
324
325 changeset: 4:9b2ba8336a65
325 changeset: 4:9b2ba8336a65
326 user: test
326 user: test
327 date: Thu Jan 01 00:00:04 1970 +0000
327 date: Thu Jan 01 00:00:04 1970 +0000
328 summary: msg 4
328 summary: msg 4
329
329
330
330
331
331
332 reproduce non converging bisect, issue1182
332 reproduce non converging bisect, issue1182
333
333
334 $ hg bisect -r
334 $ hg bisect -r
335 $ hg bisect -g 0
335 $ hg bisect -g 0
336 $ hg bisect -b 2
336 $ hg bisect -b 2
337 Testing changeset 1:5cd978ea5149 (2 changesets remaining, ~1 tests)
337 Testing changeset 1:5cd978ea5149 (2 changesets remaining, ~1 tests)
338 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
338 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
339 $ hg bisect -s
339 $ hg bisect -s
340 Due to skipped revisions, the first bad revision could be any of:
340 Due to skipped revisions, the first bad revision could be any of:
341 changeset: 1:5cd978ea5149
341 changeset: 1:5cd978ea5149
342 user: test
342 user: test
343 date: Thu Jan 01 00:00:01 1970 +0000
343 date: Thu Jan 01 00:00:01 1970 +0000
344 summary: msg 1
344 summary: msg 1
345
345
346 changeset: 2:db07c04beaca
346 changeset: 2:db07c04beaca
347 user: test
347 user: test
348 date: Thu Jan 01 00:00:02 1970 +0000
348 date: Thu Jan 01 00:00:02 1970 +0000
349 summary: msg 2
349 summary: msg 2
350
350
351
351
352
352
353 test no action
353 test no action
354
354
355 $ hg bisect -r
355 $ hg bisect -r
356 $ hg bisect
356 $ hg bisect
357 abort: cannot bisect (no known good revisions)
357 abort: cannot bisect (no known good revisions)
358 [255]
358 [255]
359
359
360
360
361 reproduce AssertionError, issue1445
361 reproduce AssertionError, issue1445
362
362
363 $ hg bisect -r
363 $ hg bisect -r
364 $ hg bisect -b 6
364 $ hg bisect -b 6
365 $ hg bisect -g 0
365 $ hg bisect -g 0
366 Testing changeset 3:b53bea5e2fcb (6 changesets remaining, ~2 tests)
366 Testing changeset 3:b53bea5e2fcb (6 changesets remaining, ~2 tests)
367 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
367 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
368 $ hg bisect -s
368 $ hg bisect -s
369 Testing changeset 2:db07c04beaca (6 changesets remaining, ~2 tests)
369 Testing changeset 2:db07c04beaca (6 changesets remaining, ~2 tests)
370 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
370 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
371 $ hg bisect -s
371 $ hg bisect -s
372 Testing changeset 4:9b2ba8336a65 (6 changesets remaining, ~2 tests)
372 Testing changeset 4:9b2ba8336a65 (6 changesets remaining, ~2 tests)
373 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
373 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
374 $ hg bisect -s
374 $ hg bisect -s
375 Testing changeset 1:5cd978ea5149 (6 changesets remaining, ~2 tests)
375 Testing changeset 1:5cd978ea5149 (6 changesets remaining, ~2 tests)
376 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
376 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
377 $ hg bisect -s
377 $ hg bisect -s
378 Testing changeset 5:7874a09ea728 (6 changesets remaining, ~2 tests)
378 Testing changeset 5:7874a09ea728 (6 changesets remaining, ~2 tests)
379 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
379 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
380 $ hg bisect -g
380 $ hg bisect -g
381 The first bad revision is:
381 The first bad revision is:
382 changeset: 6:a3d5c6fdf0d3
382 changeset: 6:a3d5c6fdf0d3
383 user: test
383 user: test
384 date: Thu Jan 01 00:00:06 1970 +0000
384 date: Thu Jan 01 00:00:06 1970 +0000
385 summary: msg 6
385 summary: msg 6
386
386
387 $ hg log -r "bisect(good)"
387 $ hg log -r "bisect(good)"
388 changeset: 0:b99c7b9c8e11
388 changeset: 0:b99c7b9c8e11
389 user: test
389 user: test
390 date: Thu Jan 01 00:00:00 1970 +0000
390 date: Thu Jan 01 00:00:00 1970 +0000
391 summary: msg 0
391 summary: msg 0
392
392
393 changeset: 5:7874a09ea728
393 changeset: 5:7874a09ea728
394 user: test
394 user: test
395 date: Thu Jan 01 00:00:05 1970 +0000
395 date: Thu Jan 01 00:00:05 1970 +0000
396 summary: msg 5
396 summary: msg 5
397
397
398 $ hg log -r "bisect(bad)"
398 $ hg log -r "bisect(bad)"
399 changeset: 6:a3d5c6fdf0d3
399 changeset: 6:a3d5c6fdf0d3
400 user: test
400 user: test
401 date: Thu Jan 01 00:00:06 1970 +0000
401 date: Thu Jan 01 00:00:06 1970 +0000
402 summary: msg 6
402 summary: msg 6
403
403
404 $ hg log -r "bisect(current)"
404 $ hg log -r "bisect(current)"
405 changeset: 5:7874a09ea728
405 changeset: 5:7874a09ea728
406 user: test
406 user: test
407 date: Thu Jan 01 00:00:05 1970 +0000
407 date: Thu Jan 01 00:00:05 1970 +0000
408 summary: msg 5
408 summary: msg 5
409
409
410 $ hg log -r "bisect(skip)"
410 $ hg log -r "bisect(skip)"
411 changeset: 1:5cd978ea5149
411 changeset: 1:5cd978ea5149
412 user: test
412 user: test
413 date: Thu Jan 01 00:00:01 1970 +0000
413 date: Thu Jan 01 00:00:01 1970 +0000
414 summary: msg 1
414 summary: msg 1
415
415
416 changeset: 2:db07c04beaca
416 changeset: 2:db07c04beaca
417 user: test
417 user: test
418 date: Thu Jan 01 00:00:02 1970 +0000
418 date: Thu Jan 01 00:00:02 1970 +0000
419 summary: msg 2
419 summary: msg 2
420
420
421 changeset: 3:b53bea5e2fcb
421 changeset: 3:b53bea5e2fcb
422 user: test
422 user: test
423 date: Thu Jan 01 00:00:03 1970 +0000
423 date: Thu Jan 01 00:00:03 1970 +0000
424 summary: msg 3
424 summary: msg 3
425
425
426 changeset: 4:9b2ba8336a65
426 changeset: 4:9b2ba8336a65
427 user: test
427 user: test
428 date: Thu Jan 01 00:00:04 1970 +0000
428 date: Thu Jan 01 00:00:04 1970 +0000
429 summary: msg 4
429 summary: msg 4
430
430
431
431
432 test legacy bisected() keyword
432 test legacy bisected() keyword
433
433
434 $ hg log -r "bisected(bad)"
434 $ hg log -r "bisected(bad)"
435 changeset: 6:a3d5c6fdf0d3
435 changeset: 6:a3d5c6fdf0d3
436 user: test
436 user: test
437 date: Thu Jan 01 00:00:06 1970 +0000
437 date: Thu Jan 01 00:00:06 1970 +0000
438 summary: msg 6
438 summary: msg 6
439
439
440
440
441 $ set +e
441 $ set +e
442
442
443 test invalid command
443 test invalid command
444 assuming that the shell returns 127 if command not found ...
444 assuming that the shell returns 127 if command not found ...
445
445
446 $ hg bisect -r
446 $ hg bisect -r
447 $ hg bisect --command 'exit 127'
447 $ hg bisect --command 'exit 127'
448 abort: failed to execute exit 127
448 abort: failed to execute exit 127
449 [255]
449 [255]
450
450
451
451
452 test bisecting command
452 test bisecting command
453
453
454 $ cat > script.py <<EOF
454 $ cat > script.py <<EOF
455 > #!/usr/bin/env python
455 > #!/usr/bin/env python
456 > import sys
456 > import sys
457 > from mercurial import ui, hg
457 > from mercurial import ui, hg
458 > repo = hg.repository(ui.ui(), '.')
458 > repo = hg.repository(ui.ui(), '.')
459 > if repo['.'].rev() < 6:
459 > if repo['.'].rev() < 6:
460 > sys.exit(1)
460 > sys.exit(1)
461 > EOF
461 > EOF
462 $ chmod +x script.py
462 $ chmod +x script.py
463 $ hg bisect -r
463 $ hg bisect -r
464 $ hg bisect --good tip
464 $ hg up -qr tip
465 $ hg bisect --bad 0
466 Testing changeset 15:e7fa0811edb0 (31 changesets remaining, ~4 tests)
467 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
468 $ hg bisect --command "python \"$TESTTMP/script.py\" and some parameters"
465 $ hg bisect --command "python \"$TESTTMP/script.py\" and some parameters"
466 changeset 31:58c80a7c8a40: good
467 abort: cannot bisect (no known bad revisions)
468 [255]
469 $ hg up -qr 0
470 $ hg bisect --command "python \"$TESTTMP/script.py\" and some parameters"
471 changeset 0:b99c7b9c8e11: bad
469 changeset 15:e7fa0811edb0: good
472 changeset 15:e7fa0811edb0: good
470 changeset 7:03750880c6b5: good
473 changeset 7:03750880c6b5: good
471 changeset 3:b53bea5e2fcb: bad
474 changeset 3:b53bea5e2fcb: bad
472 changeset 5:7874a09ea728: bad
475 changeset 5:7874a09ea728: bad
473 changeset 6:a3d5c6fdf0d3: good
476 changeset 6:a3d5c6fdf0d3: good
474 The first good revision is:
477 The first good revision is:
475 changeset: 6:a3d5c6fdf0d3
478 changeset: 6:a3d5c6fdf0d3
476 user: test
479 user: test
477 date: Thu Jan 01 00:00:06 1970 +0000
480 date: Thu Jan 01 00:00:06 1970 +0000
478 summary: msg 6
481 summary: msg 6
479
482
480
483
481
484
482 test bisecting via a command without updating the working dir, and
485 test bisecting via a command without updating the working dir, and
483 ensure that the bisect state file is updated before running a test
486 ensure that the bisect state file is updated before running a test
484 command
487 command
485
488
486 $ hg update null
489 $ hg update null
487 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
490 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
488 $ cat > script.sh <<'EOF'
491 $ cat > script.sh <<'EOF'
489 > #!/bin/sh
492 > #!/bin/sh
490 > test -n "$HG_NODE" || (echo HG_NODE missing; exit 127)
493 > test -n "$HG_NODE" || (echo HG_NODE missing; exit 127)
491 > current="`hg log -r \"bisect(current)\" --template {node}`"
494 > current="`hg log -r \"bisect(current)\" --template {node}`"
492 > test "$current" = "$HG_NODE" || (echo current is bad: $current; exit 127)
495 > test "$current" = "$HG_NODE" || (echo current is bad: $current; exit 127)
493 > rev="`hg log -r $HG_NODE --template {rev}`"
496 > rev="`hg log -r $HG_NODE --template {rev}`"
494 > test "$rev" -ge 6
497 > test "$rev" -ge 6
495 > EOF
498 > EOF
496 $ chmod +x script.sh
499 $ chmod +x script.sh
497 $ hg bisect -r
500 $ hg bisect -r
498 $ hg bisect --good tip --noupdate
501 $ hg bisect --good tip --noupdate
499 $ hg bisect --bad 0 --noupdate
502 $ hg bisect --bad 0 --noupdate
500 Testing changeset 15:e7fa0811edb0 (31 changesets remaining, ~4 tests)
503 Testing changeset 15:e7fa0811edb0 (31 changesets remaining, ~4 tests)
501 $ hg bisect --command "sh \"$TESTTMP/script.sh\" and some params" --noupdate
504 $ hg bisect --command "sh \"$TESTTMP/script.sh\" and some params" --noupdate
502 changeset 15:e7fa0811edb0: good
505 changeset 15:e7fa0811edb0: good
503 changeset 7:03750880c6b5: good
506 changeset 7:03750880c6b5: good
504 changeset 3:b53bea5e2fcb: bad
507 changeset 3:b53bea5e2fcb: bad
505 changeset 5:7874a09ea728: bad
508 changeset 5:7874a09ea728: bad
506 changeset 6:a3d5c6fdf0d3: good
509 changeset 6:a3d5c6fdf0d3: good
507 The first good revision is:
510 The first good revision is:
508 changeset: 6:a3d5c6fdf0d3
511 changeset: 6:a3d5c6fdf0d3
509 user: test
512 user: test
510 date: Thu Jan 01 00:00:06 1970 +0000
513 date: Thu Jan 01 00:00:06 1970 +0000
511 summary: msg 6
514 summary: msg 6
512
515
513
516
514 ensure that we still don't have a working dir
517 ensure that we still don't have a working dir
515
518
516 $ hg parents
519 $ hg parents
517
520
518
521
522 test the same case, this time with updating
523
524 $ cat > script.sh <<'EOF'
525 > #!/bin/sh
526 > test -n "$HG_NODE" || (echo HG_NODE missing; exit 127)
527 > current="`hg log -r \"bisect(current)\" --template {node}`"
528 > test "$current" = "$HG_NODE" || (echo current is bad: $current; exit 127)
529 > rev="`hg log -r . --template {rev}`"
530 > test "$rev" -ge 6
531 > EOF
532 $ chmod +x script.sh
533 $ hg bisect -r
534 $ hg up -qr tip
535 $ hg bisect --command "sh \"$TESTTMP/script.sh\" and some params"
536 changeset 31:58c80a7c8a40: good
537 abort: cannot bisect (no known bad revisions)
538 [255]
539 $ hg up -qr 0
540 $ hg bisect --command "sh \"$TESTTMP/script.sh\" and some params"
541 changeset 0:b99c7b9c8e11: bad
542 changeset 15:e7fa0811edb0: good
543 changeset 7:03750880c6b5: good
544 changeset 3:b53bea5e2fcb: bad
545 changeset 5:7874a09ea728: bad
546 changeset 6:a3d5c6fdf0d3: good
547 The first good revision is:
548 changeset: 6:a3d5c6fdf0d3
549 user: test
550 date: Thu Jan 01 00:00:06 1970 +0000
551 summary: msg 6
552
553
554
519 Check that bisect does not break on obsolete changesets
555 Check that bisect does not break on obsolete changesets
520 =========================================================
556 =========================================================
521
557
522 $ cat > ${TESTTMP}/obs.py << EOF
558 $ cat > ${TESTTMP}/obs.py << EOF
523 > import mercurial.obsolete
559 > import mercurial.obsolete
524 > mercurial.obsolete._enabled = True
560 > mercurial.obsolete._enabled = True
525 > EOF
561 > EOF
526 $ echo '[extensions]' >> $HGRCPATH
562 $ echo '[extensions]' >> $HGRCPATH
527 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
563 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
528
564
529 tip is obsolete
565 tip is obsolete
530 ---------------------
566 ---------------------
531
567
532 $ hg debugobsolete `hg id --debug -i -r tip`
568 $ hg debugobsolete `hg id --debug -i -r tip`
533 $ hg bisect --reset
569 $ hg bisect --reset
534 $ hg bisect --good 15
570 $ hg bisect --good 15
535 $ hg bisect --bad 30
571 $ hg bisect --bad 30
536 Testing changeset 22:06c7993750ce (15 changesets remaining, ~3 tests)
572 Testing changeset 22:06c7993750ce (15 changesets remaining, ~3 tests)
537 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
573 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
538 $ hg bisect --command true
574 $ hg bisect --command true
539 changeset 22:06c7993750ce: good
575 changeset 22:06c7993750ce: good
540 changeset 26:3efc6fd51aeb: good
576 changeset 26:3efc6fd51aeb: good
541 changeset 28:8e0c2264c8af: good
577 changeset 28:8e0c2264c8af: good
542 changeset 29:b5bd63375ab9: good
578 changeset 29:b5bd63375ab9: good
543 The first bad revision is:
579 The first bad revision is:
544 changeset: 30:ed2d2f24b11c
580 changeset: 30:ed2d2f24b11c
545 tag: tip
581 tag: tip
546 user: test
582 user: test
547 date: Thu Jan 01 00:00:30 1970 +0000
583 date: Thu Jan 01 00:00:30 1970 +0000
548 summary: msg 30
584 summary: msg 30
549
585
550
586
551 Changeset in the bad:good range is obsolete
587 Changeset in the bad:good range is obsolete
552 ---------------------------------------------
588 ---------------------------------------------
553
589
554 $ hg up 30
590 $ hg up 30
555 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
591 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
556 $ echo 'a' >> a
592 $ echo 'a' >> a
557 $ hg ci -m "msg 32" -d "32 0"
593 $ hg ci -m "msg 32" -d "32 0"
558 $ hg bisect --reset
594 $ hg bisect --reset
559 $ hg bisect --good .
595 $ hg bisect --good .
560 $ hg bisect --bad 25
596 $ hg bisect --bad 25
561 Testing changeset 28:8e0c2264c8af (6 changesets remaining, ~2 tests)
597 Testing changeset 28:8e0c2264c8af (6 changesets remaining, ~2 tests)
562 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
598 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
563 $ hg bisect --command true
599 $ hg bisect --command true
564 changeset 28:8e0c2264c8af: good
600 changeset 28:8e0c2264c8af: good
565 changeset 26:3efc6fd51aeb: good
601 changeset 26:3efc6fd51aeb: good
566 The first good revision is:
602 The first good revision is:
567 changeset: 26:3efc6fd51aeb
603 changeset: 26:3efc6fd51aeb
568 user: test
604 user: test
569 date: Thu Jan 01 00:00:26 1970 +0000
605 date: Thu Jan 01 00:00:26 1970 +0000
570 summary: msg 26
606 summary: msg 26
571
607
General Comments 0
You need to be logged in to leave comments. Login now