##// END OF EJS Templates
bisect: handle search for bad to good transitions...
Matt Mackall -
r5776:35ec669c default
parent child Browse files
Show More
@@ -1,3090 +1,3085 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
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from node import *
8 from node import *
9 from i18n import _
9 from i18n import _
10 import os, re, sys, urllib
10 import os, re, sys, urllib
11 import hg, util, revlog, bundlerepo, extensions
11 import hg, util, revlog, bundlerepo, extensions
12 import difflib, patch, time, help, mdiff, tempfile
12 import difflib, patch, time, help, mdiff, tempfile
13 import errno, version, socket
13 import errno, version, socket
14 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
14 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
15
15
16 # Commands start here, listed alphabetically
16 # Commands start here, listed alphabetically
17
17
18 def add(ui, repo, *pats, **opts):
18 def add(ui, repo, *pats, **opts):
19 """add the specified files on the next commit
19 """add the specified files on the next commit
20
20
21 Schedule files to be version controlled and added to the repository.
21 Schedule files to be version controlled and added to the repository.
22
22
23 The files will be added to the repository at the next commit. To
23 The files will be added to the repository at the next commit. To
24 undo an add before that, see hg revert.
24 undo an add before that, see hg revert.
25
25
26 If no names are given, add all files in the repository.
26 If no names are given, add all files in the repository.
27 """
27 """
28
28
29 rejected = None
29 rejected = None
30 exacts = {}
30 exacts = {}
31 names = []
31 names = []
32 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
32 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
33 badmatch=util.always):
33 badmatch=util.always):
34 if exact:
34 if exact:
35 if ui.verbose:
35 if ui.verbose:
36 ui.status(_('adding %s\n') % rel)
36 ui.status(_('adding %s\n') % rel)
37 names.append(abs)
37 names.append(abs)
38 exacts[abs] = 1
38 exacts[abs] = 1
39 elif abs not in repo.dirstate:
39 elif abs not in repo.dirstate:
40 ui.status(_('adding %s\n') % rel)
40 ui.status(_('adding %s\n') % rel)
41 names.append(abs)
41 names.append(abs)
42 if not opts.get('dry_run'):
42 if not opts.get('dry_run'):
43 rejected = repo.add(names)
43 rejected = repo.add(names)
44 rejected = [p for p in rejected if p in exacts]
44 rejected = [p for p in rejected if p in exacts]
45 return rejected and 1 or 0
45 return rejected and 1 or 0
46
46
47 def addremove(ui, repo, *pats, **opts):
47 def addremove(ui, repo, *pats, **opts):
48 """add all new files, delete all missing files
48 """add all new files, delete all missing files
49
49
50 Add all new files and remove all missing files from the repository.
50 Add all new files and remove all missing files from the repository.
51
51
52 New files are ignored if they match any of the patterns in .hgignore. As
52 New files are ignored if they match any of the patterns in .hgignore. As
53 with add, these changes take effect at the next commit.
53 with add, these changes take effect at the next commit.
54
54
55 Use the -s option to detect renamed files. With a parameter > 0,
55 Use the -s option to detect renamed files. With a parameter > 0,
56 this compares every removed file with every added file and records
56 this compares every removed file with every added file and records
57 those similar enough as renames. This option takes a percentage
57 those similar enough as renames. This option takes a percentage
58 between 0 (disabled) and 100 (files must be identical) as its
58 between 0 (disabled) and 100 (files must be identical) as its
59 parameter. Detecting renamed files this way can be expensive.
59 parameter. Detecting renamed files this way can be expensive.
60 """
60 """
61 try:
61 try:
62 sim = float(opts.get('similarity') or 0)
62 sim = float(opts.get('similarity') or 0)
63 except ValueError:
63 except ValueError:
64 raise util.Abort(_('similarity must be a number'))
64 raise util.Abort(_('similarity must be a number'))
65 if sim < 0 or sim > 100:
65 if sim < 0 or sim > 100:
66 raise util.Abort(_('similarity must be between 0 and 100'))
66 raise util.Abort(_('similarity must be between 0 and 100'))
67 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
67 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
68
68
69 def annotate(ui, repo, *pats, **opts):
69 def annotate(ui, repo, *pats, **opts):
70 """show changeset information per file line
70 """show changeset information per file line
71
71
72 List changes in files, showing the revision id responsible for each line
72 List changes in files, showing the revision id responsible for each line
73
73
74 This command is useful to discover who did a change or when a change took
74 This command is useful to discover who did a change or when a change took
75 place.
75 place.
76
76
77 Without the -a option, annotate will avoid processing files it
77 Without the -a option, annotate will avoid processing files it
78 detects as binary. With -a, annotate will generate an annotation
78 detects as binary. With -a, annotate will generate an annotation
79 anyway, probably with undesirable results.
79 anyway, probably with undesirable results.
80 """
80 """
81 getdate = util.cachefunc(lambda x: util.datestr(x[0].date()))
81 getdate = util.cachefunc(lambda x: util.datestr(x[0].date()))
82
82
83 if not pats:
83 if not pats:
84 raise util.Abort(_('at least one file name or pattern required'))
84 raise util.Abort(_('at least one file name or pattern required'))
85
85
86 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
86 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
87 ('number', lambda x: str(x[0].rev())),
87 ('number', lambda x: str(x[0].rev())),
88 ('changeset', lambda x: short(x[0].node())),
88 ('changeset', lambda x: short(x[0].node())),
89 ('date', getdate),
89 ('date', getdate),
90 ('follow', lambda x: x[0].path()),
90 ('follow', lambda x: x[0].path()),
91 ]
91 ]
92
92
93 if (not opts['user'] and not opts['changeset'] and not opts['date']
93 if (not opts['user'] and not opts['changeset'] and not opts['date']
94 and not opts['follow']):
94 and not opts['follow']):
95 opts['number'] = 1
95 opts['number'] = 1
96
96
97 linenumber = opts.get('line_number') is not None
97 linenumber = opts.get('line_number') is not None
98 if (linenumber and (not opts['changeset']) and (not opts['number'])):
98 if (linenumber and (not opts['changeset']) and (not opts['number'])):
99 raise util.Abort(_('at least one of -n/-c is required for -l'))
99 raise util.Abort(_('at least one of -n/-c is required for -l'))
100
100
101 funcmap = [func for op, func in opmap if opts.get(op)]
101 funcmap = [func for op, func in opmap if opts.get(op)]
102 if linenumber:
102 if linenumber:
103 lastfunc = funcmap[-1]
103 lastfunc = funcmap[-1]
104 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
104 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
105
105
106 ctx = repo.changectx(opts['rev'])
106 ctx = repo.changectx(opts['rev'])
107
107
108 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
108 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
109 node=ctx.node()):
109 node=ctx.node()):
110 fctx = ctx.filectx(abs)
110 fctx = ctx.filectx(abs)
111 if not opts['text'] and util.binary(fctx.data()):
111 if not opts['text'] and util.binary(fctx.data()):
112 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
112 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
113 continue
113 continue
114
114
115 lines = fctx.annotate(follow=opts.get('follow'),
115 lines = fctx.annotate(follow=opts.get('follow'),
116 linenumber=linenumber)
116 linenumber=linenumber)
117 pieces = []
117 pieces = []
118
118
119 for f in funcmap:
119 for f in funcmap:
120 l = [f(n) for n, dummy in lines]
120 l = [f(n) for n, dummy in lines]
121 if l:
121 if l:
122 m = max(map(len, l))
122 m = max(map(len, l))
123 pieces.append(["%*s" % (m, x) for x in l])
123 pieces.append(["%*s" % (m, x) for x in l])
124
124
125 if pieces:
125 if pieces:
126 for p, l in zip(zip(*pieces), lines):
126 for p, l in zip(zip(*pieces), lines):
127 ui.write("%s: %s" % (" ".join(p), l[1]))
127 ui.write("%s: %s" % (" ".join(p), l[1]))
128
128
129 def archive(ui, repo, dest, **opts):
129 def archive(ui, repo, dest, **opts):
130 '''create unversioned archive of a repository revision
130 '''create unversioned archive of a repository revision
131
131
132 By default, the revision used is the parent of the working
132 By default, the revision used is the parent of the working
133 directory; use "-r" to specify a different revision.
133 directory; use "-r" to specify a different revision.
134
134
135 To specify the type of archive to create, use "-t". Valid
135 To specify the type of archive to create, use "-t". Valid
136 types are:
136 types are:
137
137
138 "files" (default): a directory full of files
138 "files" (default): a directory full of files
139 "tar": tar archive, uncompressed
139 "tar": tar archive, uncompressed
140 "tbz2": tar archive, compressed using bzip2
140 "tbz2": tar archive, compressed using bzip2
141 "tgz": tar archive, compressed using gzip
141 "tgz": tar archive, compressed using gzip
142 "uzip": zip archive, uncompressed
142 "uzip": zip archive, uncompressed
143 "zip": zip archive, compressed using deflate
143 "zip": zip archive, compressed using deflate
144
144
145 The exact name of the destination archive or directory is given
145 The exact name of the destination archive or directory is given
146 using a format string; see "hg help export" for details.
146 using a format string; see "hg help export" for details.
147
147
148 Each member added to an archive file has a directory prefix
148 Each member added to an archive file has a directory prefix
149 prepended. Use "-p" to specify a format string for the prefix.
149 prepended. Use "-p" to specify a format string for the prefix.
150 The default is the basename of the archive, with suffixes removed.
150 The default is the basename of the archive, with suffixes removed.
151 '''
151 '''
152
152
153 ctx = repo.changectx(opts['rev'])
153 ctx = repo.changectx(opts['rev'])
154 if not ctx:
154 if not ctx:
155 raise util.Abort(_('repository has no revisions'))
155 raise util.Abort(_('repository has no revisions'))
156 node = ctx.node()
156 node = ctx.node()
157 dest = cmdutil.make_filename(repo, dest, node)
157 dest = cmdutil.make_filename(repo, dest, node)
158 if os.path.realpath(dest) == repo.root:
158 if os.path.realpath(dest) == repo.root:
159 raise util.Abort(_('repository root cannot be destination'))
159 raise util.Abort(_('repository root cannot be destination'))
160 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
160 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
161 kind = opts.get('type') or 'files'
161 kind = opts.get('type') or 'files'
162 prefix = opts['prefix']
162 prefix = opts['prefix']
163 if dest == '-':
163 if dest == '-':
164 if kind == 'files':
164 if kind == 'files':
165 raise util.Abort(_('cannot archive plain files to stdout'))
165 raise util.Abort(_('cannot archive plain files to stdout'))
166 dest = sys.stdout
166 dest = sys.stdout
167 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
167 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
168 prefix = cmdutil.make_filename(repo, prefix, node)
168 prefix = cmdutil.make_filename(repo, prefix, node)
169 archival.archive(repo, dest, node, kind, not opts['no_decode'],
169 archival.archive(repo, dest, node, kind, not opts['no_decode'],
170 matchfn, prefix)
170 matchfn, prefix)
171
171
172 def backout(ui, repo, node=None, rev=None, **opts):
172 def backout(ui, repo, node=None, rev=None, **opts):
173 '''reverse effect of earlier changeset
173 '''reverse effect of earlier changeset
174
174
175 Commit the backed out changes as a new changeset. The new
175 Commit the backed out changes as a new changeset. The new
176 changeset is a child of the backed out changeset.
176 changeset is a child of the backed out changeset.
177
177
178 If you back out a changeset other than the tip, a new head is
178 If you back out a changeset other than the tip, a new head is
179 created. This head is the parent of the working directory. If
179 created. This head is the parent of the working directory. If
180 you back out an old changeset, your working directory will appear
180 you back out an old changeset, your working directory will appear
181 old after the backout. You should merge the backout changeset
181 old after the backout. You should merge the backout changeset
182 with another head.
182 with another head.
183
183
184 The --merge option remembers the parent of the working directory
184 The --merge option remembers the parent of the working directory
185 before starting the backout, then merges the new head with that
185 before starting the backout, then merges the new head with that
186 changeset afterwards. This saves you from doing the merge by
186 changeset afterwards. This saves you from doing the merge by
187 hand. The result of this merge is not committed, as for a normal
187 hand. The result of this merge is not committed, as for a normal
188 merge.'''
188 merge.'''
189 if rev and node:
189 if rev and node:
190 raise util.Abort(_("please specify just one revision"))
190 raise util.Abort(_("please specify just one revision"))
191
191
192 if not rev:
192 if not rev:
193 rev = node
193 rev = node
194
194
195 if not rev:
195 if not rev:
196 raise util.Abort(_("please specify a revision to backout"))
196 raise util.Abort(_("please specify a revision to backout"))
197
197
198 cmdutil.bail_if_changed(repo)
198 cmdutil.bail_if_changed(repo)
199 node = repo.lookup(rev)
199 node = repo.lookup(rev)
200
200
201 op1, op2 = repo.dirstate.parents()
201 op1, op2 = repo.dirstate.parents()
202 a = repo.changelog.ancestor(op1, node)
202 a = repo.changelog.ancestor(op1, node)
203 if a != node:
203 if a != node:
204 raise util.Abort(_('cannot back out change on a different branch'))
204 raise util.Abort(_('cannot back out change on a different branch'))
205
205
206 p1, p2 = repo.changelog.parents(node)
206 p1, p2 = repo.changelog.parents(node)
207 if p1 == nullid:
207 if p1 == nullid:
208 raise util.Abort(_('cannot back out a change with no parents'))
208 raise util.Abort(_('cannot back out a change with no parents'))
209 if p2 != nullid:
209 if p2 != nullid:
210 if not opts['parent']:
210 if not opts['parent']:
211 raise util.Abort(_('cannot back out a merge changeset without '
211 raise util.Abort(_('cannot back out a merge changeset without '
212 '--parent'))
212 '--parent'))
213 p = repo.lookup(opts['parent'])
213 p = repo.lookup(opts['parent'])
214 if p not in (p1, p2):
214 if p not in (p1, p2):
215 raise util.Abort(_('%s is not a parent of %s') %
215 raise util.Abort(_('%s is not a parent of %s') %
216 (short(p), short(node)))
216 (short(p), short(node)))
217 parent = p
217 parent = p
218 else:
218 else:
219 if opts['parent']:
219 if opts['parent']:
220 raise util.Abort(_('cannot use --parent on non-merge changeset'))
220 raise util.Abort(_('cannot use --parent on non-merge changeset'))
221 parent = p1
221 parent = p1
222
222
223 hg.clean(repo, node, show_stats=False)
223 hg.clean(repo, node, show_stats=False)
224 revert_opts = opts.copy()
224 revert_opts = opts.copy()
225 revert_opts['date'] = None
225 revert_opts['date'] = None
226 revert_opts['all'] = True
226 revert_opts['all'] = True
227 revert_opts['rev'] = hex(parent)
227 revert_opts['rev'] = hex(parent)
228 revert(ui, repo, **revert_opts)
228 revert(ui, repo, **revert_opts)
229 commit_opts = opts.copy()
229 commit_opts = opts.copy()
230 commit_opts['addremove'] = False
230 commit_opts['addremove'] = False
231 if not commit_opts['message'] and not commit_opts['logfile']:
231 if not commit_opts['message'] and not commit_opts['logfile']:
232 commit_opts['message'] = _("Backed out changeset %s") % (short(node))
232 commit_opts['message'] = _("Backed out changeset %s") % (short(node))
233 commit_opts['force_editor'] = True
233 commit_opts['force_editor'] = True
234 commit(ui, repo, **commit_opts)
234 commit(ui, repo, **commit_opts)
235 def nice(node):
235 def nice(node):
236 return '%d:%s' % (repo.changelog.rev(node), short(node))
236 return '%d:%s' % (repo.changelog.rev(node), short(node))
237 ui.status(_('changeset %s backs out changeset %s\n') %
237 ui.status(_('changeset %s backs out changeset %s\n') %
238 (nice(repo.changelog.tip()), nice(node)))
238 (nice(repo.changelog.tip()), nice(node)))
239 if op1 != node:
239 if op1 != node:
240 if opts['merge']:
240 if opts['merge']:
241 ui.status(_('merging with changeset %s\n') % nice(op1))
241 ui.status(_('merging with changeset %s\n') % nice(op1))
242 hg.merge(repo, hex(op1))
242 hg.merge(repo, hex(op1))
243 else:
243 else:
244 ui.status(_('the backout changeset is a new head - '
244 ui.status(_('the backout changeset is a new head - '
245 'do not forget to merge\n'))
245 'do not forget to merge\n'))
246 ui.status(_('(use "backout --merge" '
246 ui.status(_('(use "backout --merge" '
247 'if you want to auto-merge)\n'))
247 'if you want to auto-merge)\n'))
248
248
249 def bisect(ui, repo, rev=None, extra=None,
249 def bisect(ui, repo, rev=None, extra=None,
250 reset=None, good=None, bad=None, skip=None, noupdate=None):
250 reset=None, good=None, bad=None, skip=None, noupdate=None):
251 """subdivision search of changesets
251 """subdivision search of changesets
252
252
253 This command helps to find changesets which introduce problems.
253 This command helps to find changesets which introduce problems.
254 To use, mark the earliest changeset you know exhibits the problem
254 To use, mark the earliest changeset you know exhibits the problem
255 as bad, then mark the latest changeset which is free from the
255 as bad, then mark the latest changeset which is free from the
256 problem as good. Bisect will update your working directory to a
256 problem as good. Bisect will update your working directory to a
257 revision for testing. Once you have performed tests, mark the
257 revision for testing. Once you have performed tests, mark the
258 working directory as bad or good and bisect will either update to
258 working directory as bad or good and bisect will either update to
259 another candidate changeset or announce that it has found the bad
259 another candidate changeset or announce that it has found the bad
260 revision.
260 revision.
261
262 Note: bisect expects bad revisions to be descendants of good
263 revisions. If you are looking for the point at which a problem was
264 fixed, then make the problem-free state \"bad\" and the
265 problematic state \"good.\"
266 """
261 """
267 # backward compatibility
262 # backward compatibility
268 if rev in "good bad reset init".split():
263 if rev in "good bad reset init".split():
269 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
264 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
270 cmd, rev, extra = rev, extra, None
265 cmd, rev, extra = rev, extra, None
271 if cmd == "good":
266 if cmd == "good":
272 good = True
267 good = True
273 elif cmd == "bad":
268 elif cmd == "bad":
274 bad = True
269 bad = True
275 else:
270 else:
276 reset = True
271 reset = True
277 elif extra or good + bad + skip + reset > 1:
272 elif extra or good + bad + skip + reset > 1:
278 raise util.Abort("Incompatible arguments")
273 raise util.Abort("Incompatible arguments")
279
274
280 if reset:
275 if reset:
281 p = repo.join("bisect.state")
276 p = repo.join("bisect.state")
282 if os.path.exists(p):
277 if os.path.exists(p):
283 os.unlink(p)
278 os.unlink(p)
284 return
279 return
285
280
286 # load state
281 # load state
287 state = {'good': [], 'bad': [], 'skip': []}
282 state = {'good': [], 'bad': [], 'skip': []}
288 if os.path.exists(repo.join("bisect.state")):
283 if os.path.exists(repo.join("bisect.state")):
289 for l in repo.opener("bisect.state"):
284 for l in repo.opener("bisect.state"):
290 kind, node = l[:-1].split()
285 kind, node = l[:-1].split()
291 node = repo.lookup(node)
286 node = repo.lookup(node)
292 if kind not in state:
287 if kind not in state:
293 raise util.Abort(_("unknown bisect kind %s") % kind)
288 raise util.Abort(_("unknown bisect kind %s") % kind)
294 state[kind].append(node)
289 state[kind].append(node)
295
290
296 # update state
291 # update state
297 node = repo.lookup(rev or '.')
292 node = repo.lookup(rev or '.')
298 if good:
293 if good:
299 state['good'].append(node)
294 state['good'].append(node)
300 elif bad:
295 elif bad:
301 state['bad'].append(node)
296 state['bad'].append(node)
302 elif skip:
297 elif skip:
303 state['skip'].append(node)
298 state['skip'].append(node)
304
299
305 # save state
300 # save state
306 f = repo.opener("bisect.state", "w", atomictemp=True)
301 f = repo.opener("bisect.state", "w", atomictemp=True)
307 wlock = repo.wlock()
302 wlock = repo.wlock()
308 try:
303 try:
309 for kind in state:
304 for kind in state:
310 for node in state[kind]:
305 for node in state[kind]:
311 f.write("%s %s\n" % (kind, hg.hex(node)))
306 f.write("%s %s\n" % (kind, hg.hex(node)))
312 f.rename()
307 f.rename()
313 finally:
308 finally:
314 del wlock
309 del wlock
315
310
316 if not state['good'] or not state['bad']:
311 if not state['good'] or not state['bad']:
317 return
312 return
318
313
319 # actually bisect
314 # actually bisect
320 node, changesets = hbisect.bisect(repo.changelog, state)
315 node, changesets, good = hbisect.bisect(repo.changelog, state)
321 if changesets == 0:
316 if changesets == 0:
322 ui.write(_("The first bad revision is:\n"))
317 ui.write(_("The first %s revision is:\n") % (good and "good" or "bad"))
323 displayer = cmdutil.show_changeset(ui, repo, {})
318 displayer = cmdutil.show_changeset(ui, repo, {})
324 displayer.show(changenode=node)
319 displayer.show(changenode=node)
325 elif node is not None:
320 elif node is not None:
326 # compute the approximate number of remaining tests
321 # compute the approximate number of remaining tests
327 tests, size = 0, 2
322 tests, size = 0, 2
328 while size <= changesets:
323 while size <= changesets:
329 tests, size = tests + 1, size * 2
324 tests, size = tests + 1, size * 2
330 rev = repo.changelog.rev(node)
325 rev = repo.changelog.rev(node)
331 ui.write(_("Testing changeset %s:%s "
326 ui.write(_("Testing changeset %s:%s "
332 "(%s changesets remaining, ~%s tests)\n")
327 "(%s changesets remaining, ~%s tests)\n")
333 % (rev, hg.short(node), changesets, tests))
328 % (rev, hg.short(node), changesets, tests))
334 if not noupdate:
329 if not noupdate:
335 cmdutil.bail_if_changed(repo)
330 cmdutil.bail_if_changed(repo)
336 return hg.clean(repo, node)
331 return hg.clean(repo, node)
337
332
338 def branch(ui, repo, label=None, **opts):
333 def branch(ui, repo, label=None, **opts):
339 """set or show the current branch name
334 """set or show the current branch name
340
335
341 With no argument, show the current branch name. With one argument,
336 With no argument, show the current branch name. With one argument,
342 set the working directory branch name (the branch does not exist in
337 set the working directory branch name (the branch does not exist in
343 the repository until the next commit).
338 the repository until the next commit).
344
339
345 Unless --force is specified, branch will not let you set a
340 Unless --force is specified, branch will not let you set a
346 branch name that shadows an existing branch.
341 branch name that shadows an existing branch.
347 """
342 """
348
343
349 if label:
344 if label:
350 if not opts.get('force') and label in repo.branchtags():
345 if not opts.get('force') and label in repo.branchtags():
351 if label not in [p.branch() for p in repo.workingctx().parents()]:
346 if label not in [p.branch() for p in repo.workingctx().parents()]:
352 raise util.Abort(_('a branch of the same name already exists'
347 raise util.Abort(_('a branch of the same name already exists'
353 ' (use --force to override)'))
348 ' (use --force to override)'))
354 repo.dirstate.setbranch(util.fromlocal(label))
349 repo.dirstate.setbranch(util.fromlocal(label))
355 ui.status(_('marked working directory as branch %s\n') % label)
350 ui.status(_('marked working directory as branch %s\n') % label)
356 else:
351 else:
357 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
352 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
358
353
359 def branches(ui, repo, active=False):
354 def branches(ui, repo, active=False):
360 """list repository named branches
355 """list repository named branches
361
356
362 List the repository's named branches, indicating which ones are
357 List the repository's named branches, indicating which ones are
363 inactive. If active is specified, only show active branches.
358 inactive. If active is specified, only show active branches.
364
359
365 A branch is considered active if it contains unmerged heads.
360 A branch is considered active if it contains unmerged heads.
366 """
361 """
367 b = repo.branchtags()
362 b = repo.branchtags()
368 heads = dict.fromkeys(repo.heads(), 1)
363 heads = dict.fromkeys(repo.heads(), 1)
369 l = [((n in heads), repo.changelog.rev(n), n, t) for t, n in b.items()]
364 l = [((n in heads), repo.changelog.rev(n), n, t) for t, n in b.items()]
370 l.sort()
365 l.sort()
371 l.reverse()
366 l.reverse()
372 for ishead, r, n, t in l:
367 for ishead, r, n, t in l:
373 if active and not ishead:
368 if active and not ishead:
374 # If we're only displaying active branches, abort the loop on
369 # If we're only displaying active branches, abort the loop on
375 # encountering the first inactive head
370 # encountering the first inactive head
376 break
371 break
377 else:
372 else:
378 hexfunc = ui.debugflag and hex or short
373 hexfunc = ui.debugflag and hex or short
379 if ui.quiet:
374 if ui.quiet:
380 ui.write("%s\n" % t)
375 ui.write("%s\n" % t)
381 else:
376 else:
382 spaces = " " * (30 - util.locallen(t))
377 spaces = " " * (30 - util.locallen(t))
383 # The code only gets here if inactive branches are being
378 # The code only gets here if inactive branches are being
384 # displayed or the branch is active.
379 # displayed or the branch is active.
385 isinactive = ((not ishead) and " (inactive)") or ''
380 isinactive = ((not ishead) and " (inactive)") or ''
386 ui.write("%s%s %s:%s%s\n" % (t, spaces, r, hexfunc(n), isinactive))
381 ui.write("%s%s %s:%s%s\n" % (t, spaces, r, hexfunc(n), isinactive))
387
382
388 def bundle(ui, repo, fname, dest=None, **opts):
383 def bundle(ui, repo, fname, dest=None, **opts):
389 """create a changegroup file
384 """create a changegroup file
390
385
391 Generate a compressed changegroup file collecting changesets not
386 Generate a compressed changegroup file collecting changesets not
392 found in the other repository.
387 found in the other repository.
393
388
394 If no destination repository is specified the destination is assumed
389 If no destination repository is specified the destination is assumed
395 to have all the nodes specified by one or more --base parameters.
390 to have all the nodes specified by one or more --base parameters.
396
391
397 The bundle file can then be transferred using conventional means and
392 The bundle file can then be transferred using conventional means and
398 applied to another repository with the unbundle or pull command.
393 applied to another repository with the unbundle or pull command.
399 This is useful when direct push and pull are not available or when
394 This is useful when direct push and pull are not available or when
400 exporting an entire repository is undesirable.
395 exporting an entire repository is undesirable.
401
396
402 Applying bundles preserves all changeset contents including
397 Applying bundles preserves all changeset contents including
403 permissions, copy/rename information, and revision history.
398 permissions, copy/rename information, and revision history.
404 """
399 """
405 revs = opts.get('rev') or None
400 revs = opts.get('rev') or None
406 if revs:
401 if revs:
407 revs = [repo.lookup(rev) for rev in revs]
402 revs = [repo.lookup(rev) for rev in revs]
408 base = opts.get('base')
403 base = opts.get('base')
409 if base:
404 if base:
410 if dest:
405 if dest:
411 raise util.Abort(_("--base is incompatible with specifiying "
406 raise util.Abort(_("--base is incompatible with specifiying "
412 "a destination"))
407 "a destination"))
413 base = [repo.lookup(rev) for rev in base]
408 base = [repo.lookup(rev) for rev in base]
414 # create the right base
409 # create the right base
415 # XXX: nodesbetween / changegroup* should be "fixed" instead
410 # XXX: nodesbetween / changegroup* should be "fixed" instead
416 o = []
411 o = []
417 has = {nullid: None}
412 has = {nullid: None}
418 for n in base:
413 for n in base:
419 has.update(repo.changelog.reachable(n))
414 has.update(repo.changelog.reachable(n))
420 if revs:
415 if revs:
421 visit = list(revs)
416 visit = list(revs)
422 else:
417 else:
423 visit = repo.changelog.heads()
418 visit = repo.changelog.heads()
424 seen = {}
419 seen = {}
425 while visit:
420 while visit:
426 n = visit.pop(0)
421 n = visit.pop(0)
427 parents = [p for p in repo.changelog.parents(n) if p not in has]
422 parents = [p for p in repo.changelog.parents(n) if p not in has]
428 if len(parents) == 0:
423 if len(parents) == 0:
429 o.insert(0, n)
424 o.insert(0, n)
430 else:
425 else:
431 for p in parents:
426 for p in parents:
432 if p not in seen:
427 if p not in seen:
433 seen[p] = 1
428 seen[p] = 1
434 visit.append(p)
429 visit.append(p)
435 else:
430 else:
436 cmdutil.setremoteconfig(ui, opts)
431 cmdutil.setremoteconfig(ui, opts)
437 dest, revs, checkout = hg.parseurl(
432 dest, revs, checkout = hg.parseurl(
438 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
433 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
439 other = hg.repository(ui, dest)
434 other = hg.repository(ui, dest)
440 o = repo.findoutgoing(other, force=opts['force'])
435 o = repo.findoutgoing(other, force=opts['force'])
441
436
442 if revs:
437 if revs:
443 cg = repo.changegroupsubset(o, revs, 'bundle')
438 cg = repo.changegroupsubset(o, revs, 'bundle')
444 else:
439 else:
445 cg = repo.changegroup(o, 'bundle')
440 cg = repo.changegroup(o, 'bundle')
446 changegroup.writebundle(cg, fname, "HG10BZ")
441 changegroup.writebundle(cg, fname, "HG10BZ")
447
442
448 def cat(ui, repo, file1, *pats, **opts):
443 def cat(ui, repo, file1, *pats, **opts):
449 """output the current or given revision of files
444 """output the current or given revision of files
450
445
451 Print the specified files as they were at the given revision.
446 Print the specified files as they were at the given revision.
452 If no revision is given, the parent of the working directory is used,
447 If no revision is given, the parent of the working directory is used,
453 or tip if no revision is checked out.
448 or tip if no revision is checked out.
454
449
455 Output may be to a file, in which case the name of the file is
450 Output may be to a file, in which case the name of the file is
456 given using a format string. The formatting rules are the same as
451 given using a format string. The formatting rules are the same as
457 for the export command, with the following additions:
452 for the export command, with the following additions:
458
453
459 %s basename of file being printed
454 %s basename of file being printed
460 %d dirname of file being printed, or '.' if in repo root
455 %d dirname of file being printed, or '.' if in repo root
461 %p root-relative path name of file being printed
456 %p root-relative path name of file being printed
462 """
457 """
463 ctx = repo.changectx(opts['rev'])
458 ctx = repo.changectx(opts['rev'])
464 err = 1
459 err = 1
465 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
460 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
466 ctx.node()):
461 ctx.node()):
467 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
462 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
468 fp.write(ctx.filectx(abs).data())
463 fp.write(ctx.filectx(abs).data())
469 err = 0
464 err = 0
470 return err
465 return err
471
466
472 def clone(ui, source, dest=None, **opts):
467 def clone(ui, source, dest=None, **opts):
473 """make a copy of an existing repository
468 """make a copy of an existing repository
474
469
475 Create a copy of an existing repository in a new directory.
470 Create a copy of an existing repository in a new directory.
476
471
477 If no destination directory name is specified, it defaults to the
472 If no destination directory name is specified, it defaults to the
478 basename of the source.
473 basename of the source.
479
474
480 The location of the source is added to the new repository's
475 The location of the source is added to the new repository's
481 .hg/hgrc file, as the default to be used for future pulls.
476 .hg/hgrc file, as the default to be used for future pulls.
482
477
483 For efficiency, hardlinks are used for cloning whenever the source
478 For efficiency, hardlinks are used for cloning whenever the source
484 and destination are on the same filesystem (note this applies only
479 and destination are on the same filesystem (note this applies only
485 to the repository data, not to the checked out files). Some
480 to the repository data, not to the checked out files). Some
486 filesystems, such as AFS, implement hardlinking incorrectly, but
481 filesystems, such as AFS, implement hardlinking incorrectly, but
487 do not report errors. In these cases, use the --pull option to
482 do not report errors. In these cases, use the --pull option to
488 avoid hardlinking.
483 avoid hardlinking.
489
484
490 You can safely clone repositories and checked out files using full
485 You can safely clone repositories and checked out files using full
491 hardlinks with
486 hardlinks with
492
487
493 $ cp -al REPO REPOCLONE
488 $ cp -al REPO REPOCLONE
494
489
495 which is the fastest way to clone. However, the operation is not
490 which is the fastest way to clone. However, the operation is not
496 atomic (making sure REPO is not modified during the operation is
491 atomic (making sure REPO is not modified during the operation is
497 up to you) and you have to make sure your editor breaks hardlinks
492 up to you) and you have to make sure your editor breaks hardlinks
498 (Emacs and most Linux Kernel tools do so).
493 (Emacs and most Linux Kernel tools do so).
499
494
500 If you use the -r option to clone up to a specific revision, no
495 If you use the -r option to clone up to a specific revision, no
501 subsequent revisions will be present in the cloned repository.
496 subsequent revisions will be present in the cloned repository.
502 This option implies --pull, even on local repositories.
497 This option implies --pull, even on local repositories.
503
498
504 See pull for valid source format details.
499 See pull for valid source format details.
505
500
506 It is possible to specify an ssh:// URL as the destination, but no
501 It is possible to specify an ssh:// URL as the destination, but no
507 .hg/hgrc and working directory will be created on the remote side.
502 .hg/hgrc and working directory will be created on the remote side.
508 Look at the help text for the pull command for important details
503 Look at the help text for the pull command for important details
509 about ssh:// URLs.
504 about ssh:// URLs.
510 """
505 """
511 cmdutil.setremoteconfig(ui, opts)
506 cmdutil.setremoteconfig(ui, opts)
512 hg.clone(ui, source, dest,
507 hg.clone(ui, source, dest,
513 pull=opts['pull'],
508 pull=opts['pull'],
514 stream=opts['uncompressed'],
509 stream=opts['uncompressed'],
515 rev=opts['rev'],
510 rev=opts['rev'],
516 update=not opts['noupdate'])
511 update=not opts['noupdate'])
517
512
518 def commit(ui, repo, *pats, **opts):
513 def commit(ui, repo, *pats, **opts):
519 """commit the specified files or all outstanding changes
514 """commit the specified files or all outstanding changes
520
515
521 Commit changes to the given files into the repository.
516 Commit changes to the given files into the repository.
522
517
523 If a list of files is omitted, all changes reported by "hg status"
518 If a list of files is omitted, all changes reported by "hg status"
524 will be committed.
519 will be committed.
525
520
526 If no commit message is specified, the configured editor is started to
521 If no commit message is specified, the configured editor is started to
527 enter a message.
522 enter a message.
528 """
523 """
529 def commitfunc(ui, repo, files, message, match, opts):
524 def commitfunc(ui, repo, files, message, match, opts):
530 return repo.commit(files, message, opts['user'], opts['date'], match,
525 return repo.commit(files, message, opts['user'], opts['date'], match,
531 force_editor=opts.get('force_editor'))
526 force_editor=opts.get('force_editor'))
532 cmdutil.commit(ui, repo, commitfunc, pats, opts)
527 cmdutil.commit(ui, repo, commitfunc, pats, opts)
533
528
534 def copy(ui, repo, *pats, **opts):
529 def copy(ui, repo, *pats, **opts):
535 """mark files as copied for the next commit
530 """mark files as copied for the next commit
536
531
537 Mark dest as having copies of source files. If dest is a
532 Mark dest as having copies of source files. If dest is a
538 directory, copies are put in that directory. If dest is a file,
533 directory, copies are put in that directory. If dest is a file,
539 there can only be one source.
534 there can only be one source.
540
535
541 By default, this command copies the contents of files as they
536 By default, this command copies the contents of files as they
542 stand in the working directory. If invoked with --after, the
537 stand in the working directory. If invoked with --after, the
543 operation is recorded, but no copying is performed.
538 operation is recorded, but no copying is performed.
544
539
545 This command takes effect in the next commit. To undo a copy
540 This command takes effect in the next commit. To undo a copy
546 before that, see hg revert.
541 before that, see hg revert.
547 """
542 """
548 wlock = repo.wlock(False)
543 wlock = repo.wlock(False)
549 try:
544 try:
550 return cmdutil.copy(ui, repo, pats, opts)
545 return cmdutil.copy(ui, repo, pats, opts)
551 finally:
546 finally:
552 del wlock
547 del wlock
553
548
554 def debugancestor(ui, index, rev1, rev2):
549 def debugancestor(ui, index, rev1, rev2):
555 """find the ancestor revision of two revisions in a given index"""
550 """find the ancestor revision of two revisions in a given index"""
556 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
551 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
557 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
552 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
558 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
553 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
559
554
560 def debugcomplete(ui, cmd='', **opts):
555 def debugcomplete(ui, cmd='', **opts):
561 """returns the completion list associated with the given command"""
556 """returns the completion list associated with the given command"""
562
557
563 if opts['options']:
558 if opts['options']:
564 options = []
559 options = []
565 otables = [globalopts]
560 otables = [globalopts]
566 if cmd:
561 if cmd:
567 aliases, entry = cmdutil.findcmd(ui, cmd, table)
562 aliases, entry = cmdutil.findcmd(ui, cmd, table)
568 otables.append(entry[1])
563 otables.append(entry[1])
569 for t in otables:
564 for t in otables:
570 for o in t:
565 for o in t:
571 if o[0]:
566 if o[0]:
572 options.append('-%s' % o[0])
567 options.append('-%s' % o[0])
573 options.append('--%s' % o[1])
568 options.append('--%s' % o[1])
574 ui.write("%s\n" % "\n".join(options))
569 ui.write("%s\n" % "\n".join(options))
575 return
570 return
576
571
577 clist = cmdutil.findpossible(ui, cmd, table).keys()
572 clist = cmdutil.findpossible(ui, cmd, table).keys()
578 clist.sort()
573 clist.sort()
579 ui.write("%s\n" % "\n".join(clist))
574 ui.write("%s\n" % "\n".join(clist))
580
575
581 def debugfsinfo(ui, path = "."):
576 def debugfsinfo(ui, path = "."):
582 file('.debugfsinfo', 'w').write('')
577 file('.debugfsinfo', 'w').write('')
583 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
578 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
584 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
579 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
585 ui.write('case-sensitive: %s\n' % (util.checkfolding('.debugfsinfo')
580 ui.write('case-sensitive: %s\n' % (util.checkfolding('.debugfsinfo')
586 and 'yes' or 'no'))
581 and 'yes' or 'no'))
587 os.unlink('.debugfsinfo')
582 os.unlink('.debugfsinfo')
588
583
589 def debugrebuildstate(ui, repo, rev=""):
584 def debugrebuildstate(ui, repo, rev=""):
590 """rebuild the dirstate as it would look like for the given revision"""
585 """rebuild the dirstate as it would look like for the given revision"""
591 if rev == "":
586 if rev == "":
592 rev = repo.changelog.tip()
587 rev = repo.changelog.tip()
593 ctx = repo.changectx(rev)
588 ctx = repo.changectx(rev)
594 files = ctx.manifest()
589 files = ctx.manifest()
595 wlock = repo.wlock()
590 wlock = repo.wlock()
596 try:
591 try:
597 repo.dirstate.rebuild(rev, files)
592 repo.dirstate.rebuild(rev, files)
598 finally:
593 finally:
599 del wlock
594 del wlock
600
595
601 def debugcheckstate(ui, repo):
596 def debugcheckstate(ui, repo):
602 """validate the correctness of the current dirstate"""
597 """validate the correctness of the current dirstate"""
603 parent1, parent2 = repo.dirstate.parents()
598 parent1, parent2 = repo.dirstate.parents()
604 m1 = repo.changectx(parent1).manifest()
599 m1 = repo.changectx(parent1).manifest()
605 m2 = repo.changectx(parent2).manifest()
600 m2 = repo.changectx(parent2).manifest()
606 errors = 0
601 errors = 0
607 for f in repo.dirstate:
602 for f in repo.dirstate:
608 state = repo.dirstate[f]
603 state = repo.dirstate[f]
609 if state in "nr" and f not in m1:
604 if state in "nr" and f not in m1:
610 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
605 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
611 errors += 1
606 errors += 1
612 if state in "a" and f in m1:
607 if state in "a" and f in m1:
613 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
608 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
614 errors += 1
609 errors += 1
615 if state in "m" and f not in m1 and f not in m2:
610 if state in "m" and f not in m1 and f not in m2:
616 ui.warn(_("%s in state %s, but not in either manifest\n") %
611 ui.warn(_("%s in state %s, but not in either manifest\n") %
617 (f, state))
612 (f, state))
618 errors += 1
613 errors += 1
619 for f in m1:
614 for f in m1:
620 state = repo.dirstate[f]
615 state = repo.dirstate[f]
621 if state not in "nrm":
616 if state not in "nrm":
622 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
617 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
623 errors += 1
618 errors += 1
624 if errors:
619 if errors:
625 error = _(".hg/dirstate inconsistent with current parent's manifest")
620 error = _(".hg/dirstate inconsistent with current parent's manifest")
626 raise util.Abort(error)
621 raise util.Abort(error)
627
622
628 def showconfig(ui, repo, *values, **opts):
623 def showconfig(ui, repo, *values, **opts):
629 """show combined config settings from all hgrc files
624 """show combined config settings from all hgrc files
630
625
631 With no args, print names and values of all config items.
626 With no args, print names and values of all config items.
632
627
633 With one arg of the form section.name, print just the value of
628 With one arg of the form section.name, print just the value of
634 that config item.
629 that config item.
635
630
636 With multiple args, print names and values of all config items
631 With multiple args, print names and values of all config items
637 with matching section names."""
632 with matching section names."""
638
633
639 untrusted = bool(opts.get('untrusted'))
634 untrusted = bool(opts.get('untrusted'))
640 if values:
635 if values:
641 if len([v for v in values if '.' in v]) > 1:
636 if len([v for v in values if '.' in v]) > 1:
642 raise util.Abort(_('only one config item permitted'))
637 raise util.Abort(_('only one config item permitted'))
643 for section, name, value in ui.walkconfig(untrusted=untrusted):
638 for section, name, value in ui.walkconfig(untrusted=untrusted):
644 sectname = section + '.' + name
639 sectname = section + '.' + name
645 if values:
640 if values:
646 for v in values:
641 for v in values:
647 if v == section:
642 if v == section:
648 ui.write('%s=%s\n' % (sectname, value))
643 ui.write('%s=%s\n' % (sectname, value))
649 elif v == sectname:
644 elif v == sectname:
650 ui.write(value, '\n')
645 ui.write(value, '\n')
651 else:
646 else:
652 ui.write('%s=%s\n' % (sectname, value))
647 ui.write('%s=%s\n' % (sectname, value))
653
648
654 def debugsetparents(ui, repo, rev1, rev2=None):
649 def debugsetparents(ui, repo, rev1, rev2=None):
655 """manually set the parents of the current working directory
650 """manually set the parents of the current working directory
656
651
657 This is useful for writing repository conversion tools, but should
652 This is useful for writing repository conversion tools, but should
658 be used with care.
653 be used with care.
659 """
654 """
660
655
661 if not rev2:
656 if not rev2:
662 rev2 = hex(nullid)
657 rev2 = hex(nullid)
663
658
664 wlock = repo.wlock()
659 wlock = repo.wlock()
665 try:
660 try:
666 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
661 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
667 finally:
662 finally:
668 del wlock
663 del wlock
669
664
670 def debugstate(ui, repo):
665 def debugstate(ui, repo):
671 """show the contents of the current dirstate"""
666 """show the contents of the current dirstate"""
672 k = repo.dirstate._map.items()
667 k = repo.dirstate._map.items()
673 k.sort()
668 k.sort()
674 for file_, ent in k:
669 for file_, ent in k:
675 if ent[3] == -1:
670 if ent[3] == -1:
676 # Pad or slice to locale representation
671 # Pad or slice to locale representation
677 locale_len = len(time.strftime("%x %X", time.localtime(0)))
672 locale_len = len(time.strftime("%x %X", time.localtime(0)))
678 timestr = 'unset'
673 timestr = 'unset'
679 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
674 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
680 else:
675 else:
681 timestr = time.strftime("%x %X", time.localtime(ent[3]))
676 timestr = time.strftime("%x %X", time.localtime(ent[3]))
682 if ent[1] & 020000:
677 if ent[1] & 020000:
683 mode = 'lnk'
678 mode = 'lnk'
684 else:
679 else:
685 mode = '%3o' % (ent[1] & 0777)
680 mode = '%3o' % (ent[1] & 0777)
686 ui.write("%c %s %10d %s %s\n" % (ent[0], mode, ent[2], timestr, file_))
681 ui.write("%c %s %10d %s %s\n" % (ent[0], mode, ent[2], timestr, file_))
687 for f in repo.dirstate.copies():
682 for f in repo.dirstate.copies():
688 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
683 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
689
684
690 def debugdata(ui, file_, rev):
685 def debugdata(ui, file_, rev):
691 """dump the contents of a data file revision"""
686 """dump the contents of a data file revision"""
692 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
687 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
693 try:
688 try:
694 ui.write(r.revision(r.lookup(rev)))
689 ui.write(r.revision(r.lookup(rev)))
695 except KeyError:
690 except KeyError:
696 raise util.Abort(_('invalid revision identifier %s') % rev)
691 raise util.Abort(_('invalid revision identifier %s') % rev)
697
692
698 def debugdate(ui, date, range=None, **opts):
693 def debugdate(ui, date, range=None, **opts):
699 """parse and display a date"""
694 """parse and display a date"""
700 if opts["extended"]:
695 if opts["extended"]:
701 d = util.parsedate(date, util.extendeddateformats)
696 d = util.parsedate(date, util.extendeddateformats)
702 else:
697 else:
703 d = util.parsedate(date)
698 d = util.parsedate(date)
704 ui.write("internal: %s %s\n" % d)
699 ui.write("internal: %s %s\n" % d)
705 ui.write("standard: %s\n" % util.datestr(d))
700 ui.write("standard: %s\n" % util.datestr(d))
706 if range:
701 if range:
707 m = util.matchdate(range)
702 m = util.matchdate(range)
708 ui.write("match: %s\n" % m(d[0]))
703 ui.write("match: %s\n" % m(d[0]))
709
704
710 def debugindex(ui, file_):
705 def debugindex(ui, file_):
711 """dump the contents of an index file"""
706 """dump the contents of an index file"""
712 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
707 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
713 ui.write(" rev offset length base linkrev" +
708 ui.write(" rev offset length base linkrev" +
714 " nodeid p1 p2\n")
709 " nodeid p1 p2\n")
715 for i in xrange(r.count()):
710 for i in xrange(r.count()):
716 node = r.node(i)
711 node = r.node(i)
717 try:
712 try:
718 pp = r.parents(node)
713 pp = r.parents(node)
719 except:
714 except:
720 pp = [nullid, nullid]
715 pp = [nullid, nullid]
721 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
716 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
722 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
717 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
723 short(node), short(pp[0]), short(pp[1])))
718 short(node), short(pp[0]), short(pp[1])))
724
719
725 def debugindexdot(ui, file_):
720 def debugindexdot(ui, file_):
726 """dump an index DAG as a .dot file"""
721 """dump an index DAG as a .dot file"""
727 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
722 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
728 ui.write("digraph G {\n")
723 ui.write("digraph G {\n")
729 for i in xrange(r.count()):
724 for i in xrange(r.count()):
730 node = r.node(i)
725 node = r.node(i)
731 pp = r.parents(node)
726 pp = r.parents(node)
732 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
727 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
733 if pp[1] != nullid:
728 if pp[1] != nullid:
734 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
729 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
735 ui.write("}\n")
730 ui.write("}\n")
736
731
737 def debuginstall(ui):
732 def debuginstall(ui):
738 '''test Mercurial installation'''
733 '''test Mercurial installation'''
739
734
740 def writetemp(contents):
735 def writetemp(contents):
741 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
736 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
742 f = os.fdopen(fd, "wb")
737 f = os.fdopen(fd, "wb")
743 f.write(contents)
738 f.write(contents)
744 f.close()
739 f.close()
745 return name
740 return name
746
741
747 problems = 0
742 problems = 0
748
743
749 # encoding
744 # encoding
750 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
745 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
751 try:
746 try:
752 util.fromlocal("test")
747 util.fromlocal("test")
753 except util.Abort, inst:
748 except util.Abort, inst:
754 ui.write(" %s\n" % inst)
749 ui.write(" %s\n" % inst)
755 ui.write(_(" (check that your locale is properly set)\n"))
750 ui.write(_(" (check that your locale is properly set)\n"))
756 problems += 1
751 problems += 1
757
752
758 # compiled modules
753 # compiled modules
759 ui.status(_("Checking extensions...\n"))
754 ui.status(_("Checking extensions...\n"))
760 try:
755 try:
761 import bdiff, mpatch, base85
756 import bdiff, mpatch, base85
762 except Exception, inst:
757 except Exception, inst:
763 ui.write(" %s\n" % inst)
758 ui.write(" %s\n" % inst)
764 ui.write(_(" One or more extensions could not be found"))
759 ui.write(_(" One or more extensions could not be found"))
765 ui.write(_(" (check that you compiled the extensions)\n"))
760 ui.write(_(" (check that you compiled the extensions)\n"))
766 problems += 1
761 problems += 1
767
762
768 # templates
763 # templates
769 ui.status(_("Checking templates...\n"))
764 ui.status(_("Checking templates...\n"))
770 try:
765 try:
771 import templater
766 import templater
772 t = templater.templater(templater.templatepath("map-cmdline.default"))
767 t = templater.templater(templater.templatepath("map-cmdline.default"))
773 except Exception, inst:
768 except Exception, inst:
774 ui.write(" %s\n" % inst)
769 ui.write(" %s\n" % inst)
775 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
770 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
776 problems += 1
771 problems += 1
777
772
778 # patch
773 # patch
779 ui.status(_("Checking patch...\n"))
774 ui.status(_("Checking patch...\n"))
780 patchproblems = 0
775 patchproblems = 0
781 a = "1\n2\n3\n4\n"
776 a = "1\n2\n3\n4\n"
782 b = "1\n2\n3\ninsert\n4\n"
777 b = "1\n2\n3\ninsert\n4\n"
783 fa = writetemp(a)
778 fa = writetemp(a)
784 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
779 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
785 os.path.basename(fa))
780 os.path.basename(fa))
786 fd = writetemp(d)
781 fd = writetemp(d)
787
782
788 files = {}
783 files = {}
789 try:
784 try:
790 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
785 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
791 except util.Abort, e:
786 except util.Abort, e:
792 ui.write(_(" patch call failed:\n"))
787 ui.write(_(" patch call failed:\n"))
793 ui.write(" " + str(e) + "\n")
788 ui.write(" " + str(e) + "\n")
794 patchproblems += 1
789 patchproblems += 1
795 else:
790 else:
796 if list(files) != [os.path.basename(fa)]:
791 if list(files) != [os.path.basename(fa)]:
797 ui.write(_(" unexpected patch output!\n"))
792 ui.write(_(" unexpected patch output!\n"))
798 patchproblems += 1
793 patchproblems += 1
799 a = file(fa).read()
794 a = file(fa).read()
800 if a != b:
795 if a != b:
801 ui.write(_(" patch test failed!\n"))
796 ui.write(_(" patch test failed!\n"))
802 patchproblems += 1
797 patchproblems += 1
803
798
804 if patchproblems:
799 if patchproblems:
805 if ui.config('ui', 'patch'):
800 if ui.config('ui', 'patch'):
806 ui.write(_(" (Current patch tool may be incompatible with patch,"
801 ui.write(_(" (Current patch tool may be incompatible with patch,"
807 " or misconfigured. Please check your .hgrc file)\n"))
802 " or misconfigured. Please check your .hgrc file)\n"))
808 else:
803 else:
809 ui.write(_(" Internal patcher failure, please report this error"
804 ui.write(_(" Internal patcher failure, please report this error"
810 " to http://www.selenic.com/mercurial/bts\n"))
805 " to http://www.selenic.com/mercurial/bts\n"))
811 problems += patchproblems
806 problems += patchproblems
812
807
813 os.unlink(fa)
808 os.unlink(fa)
814 os.unlink(fd)
809 os.unlink(fd)
815
810
816 # merge helper
811 # merge helper
817 ui.status(_("Checking merge helper...\n"))
812 ui.status(_("Checking merge helper...\n"))
818 cmd = (os.environ.get("HGMERGE") or ui.config("ui", "merge")
813 cmd = (os.environ.get("HGMERGE") or ui.config("ui", "merge")
819 or "hgmerge")
814 or "hgmerge")
820 cmdpath = util.find_exe(cmd) or util.find_exe(cmd.split()[0])
815 cmdpath = util.find_exe(cmd) or util.find_exe(cmd.split()[0])
821 if not cmdpath:
816 if not cmdpath:
822 if cmd == 'hgmerge':
817 if cmd == 'hgmerge':
823 ui.write(_(" No merge helper set and can't find default"
818 ui.write(_(" No merge helper set and can't find default"
824 " hgmerge script in PATH\n"))
819 " hgmerge script in PATH\n"))
825 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
820 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
826 else:
821 else:
827 ui.write(_(" Can't find merge helper '%s' in PATH\n") % cmd)
822 ui.write(_(" Can't find merge helper '%s' in PATH\n") % cmd)
828 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
823 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
829 problems += 1
824 problems += 1
830 else:
825 else:
831 # actually attempt a patch here
826 # actually attempt a patch here
832 fa = writetemp("1\n2\n3\n4\n")
827 fa = writetemp("1\n2\n3\n4\n")
833 fl = writetemp("1\n2\n3\ninsert\n4\n")
828 fl = writetemp("1\n2\n3\ninsert\n4\n")
834 fr = writetemp("begin\n1\n2\n3\n4\n")
829 fr = writetemp("begin\n1\n2\n3\n4\n")
835 r = util.system('%s "%s" "%s" "%s"' % (cmd, fl, fa, fr))
830 r = util.system('%s "%s" "%s" "%s"' % (cmd, fl, fa, fr))
836 if r:
831 if r:
837 ui.write(_(" Got unexpected merge error %d!\n") % r)
832 ui.write(_(" Got unexpected merge error %d!\n") % r)
838 problems += 1
833 problems += 1
839 m = file(fl).read()
834 m = file(fl).read()
840 if m != "begin\n1\n2\n3\ninsert\n4\n":
835 if m != "begin\n1\n2\n3\ninsert\n4\n":
841 ui.write(_(" Got unexpected merge results!\n"))
836 ui.write(_(" Got unexpected merge results!\n"))
842 ui.write(_(" (your merge helper may have the"
837 ui.write(_(" (your merge helper may have the"
843 " wrong argument order)\n"))
838 " wrong argument order)\n"))
844 ui.write(_(" Result: %r\n") % m)
839 ui.write(_(" Result: %r\n") % m)
845 problems += 1
840 problems += 1
846 os.unlink(fa)
841 os.unlink(fa)
847 os.unlink(fl)
842 os.unlink(fl)
848 os.unlink(fr)
843 os.unlink(fr)
849
844
850 # editor
845 # editor
851 ui.status(_("Checking commit editor...\n"))
846 ui.status(_("Checking commit editor...\n"))
852 editor = ui.geteditor()
847 editor = ui.geteditor()
853 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
848 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
854 if not cmdpath:
849 if not cmdpath:
855 if editor == 'vi':
850 if editor == 'vi':
856 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
851 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
857 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
852 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
858 else:
853 else:
859 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
854 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
860 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
855 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
861 problems += 1
856 problems += 1
862
857
863 # check username
858 # check username
864 ui.status(_("Checking username...\n"))
859 ui.status(_("Checking username...\n"))
865 user = os.environ.get("HGUSER")
860 user = os.environ.get("HGUSER")
866 if user is None:
861 if user is None:
867 user = ui.config("ui", "username")
862 user = ui.config("ui", "username")
868 if user is None:
863 if user is None:
869 user = os.environ.get("EMAIL")
864 user = os.environ.get("EMAIL")
870 if not user:
865 if not user:
871 ui.warn(" ")
866 ui.warn(" ")
872 ui.username()
867 ui.username()
873 ui.write(_(" (specify a username in your .hgrc file)\n"))
868 ui.write(_(" (specify a username in your .hgrc file)\n"))
874
869
875 if not problems:
870 if not problems:
876 ui.status(_("No problems detected\n"))
871 ui.status(_("No problems detected\n"))
877 else:
872 else:
878 ui.write(_("%s problems detected,"
873 ui.write(_("%s problems detected,"
879 " please check your install!\n") % problems)
874 " please check your install!\n") % problems)
880
875
881 return problems
876 return problems
882
877
883 def debugrename(ui, repo, file1, *pats, **opts):
878 def debugrename(ui, repo, file1, *pats, **opts):
884 """dump rename information"""
879 """dump rename information"""
885
880
886 ctx = repo.changectx(opts.get('rev', 'tip'))
881 ctx = repo.changectx(opts.get('rev', 'tip'))
887 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
882 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
888 ctx.node()):
883 ctx.node()):
889 m = ctx.filectx(abs).renamed()
884 m = ctx.filectx(abs).renamed()
890 if m:
885 if m:
891 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
886 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
892 else:
887 else:
893 ui.write(_("%s not renamed\n") % rel)
888 ui.write(_("%s not renamed\n") % rel)
894
889
895 def debugwalk(ui, repo, *pats, **opts):
890 def debugwalk(ui, repo, *pats, **opts):
896 """show how files match on given patterns"""
891 """show how files match on given patterns"""
897 items = list(cmdutil.walk(repo, pats, opts))
892 items = list(cmdutil.walk(repo, pats, opts))
898 if not items:
893 if not items:
899 return
894 return
900 fmt = '%%s %%-%ds %%-%ds %%s' % (
895 fmt = '%%s %%-%ds %%-%ds %%s' % (
901 max([len(abs) for (src, abs, rel, exact) in items]),
896 max([len(abs) for (src, abs, rel, exact) in items]),
902 max([len(rel) for (src, abs, rel, exact) in items]))
897 max([len(rel) for (src, abs, rel, exact) in items]))
903 for src, abs, rel, exact in items:
898 for src, abs, rel, exact in items:
904 line = fmt % (src, abs, rel, exact and 'exact' or '')
899 line = fmt % (src, abs, rel, exact and 'exact' or '')
905 ui.write("%s\n" % line.rstrip())
900 ui.write("%s\n" % line.rstrip())
906
901
907 def diff(ui, repo, *pats, **opts):
902 def diff(ui, repo, *pats, **opts):
908 """diff repository (or selected files)
903 """diff repository (or selected files)
909
904
910 Show differences between revisions for the specified files.
905 Show differences between revisions for the specified files.
911
906
912 Differences between files are shown using the unified diff format.
907 Differences between files are shown using the unified diff format.
913
908
914 NOTE: diff may generate unexpected results for merges, as it will
909 NOTE: diff may generate unexpected results for merges, as it will
915 default to comparing against the working directory's first parent
910 default to comparing against the working directory's first parent
916 changeset if no revisions are specified.
911 changeset if no revisions are specified.
917
912
918 When two revision arguments are given, then changes are shown
913 When two revision arguments are given, then changes are shown
919 between those revisions. If only one revision is specified then
914 between those revisions. If only one revision is specified then
920 that revision is compared to the working directory, and, when no
915 that revision is compared to the working directory, and, when no
921 revisions are specified, the working directory files are compared
916 revisions are specified, the working directory files are compared
922 to its parent.
917 to its parent.
923
918
924 Without the -a option, diff will avoid generating diffs of files
919 Without the -a option, diff will avoid generating diffs of files
925 it detects as binary. With -a, diff will generate a diff anyway,
920 it detects as binary. With -a, diff will generate a diff anyway,
926 probably with undesirable results.
921 probably with undesirable results.
927 """
922 """
928 node1, node2 = cmdutil.revpair(repo, opts['rev'])
923 node1, node2 = cmdutil.revpair(repo, opts['rev'])
929
924
930 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
925 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
931
926
932 patch.diff(repo, node1, node2, fns, match=matchfn,
927 patch.diff(repo, node1, node2, fns, match=matchfn,
933 opts=patch.diffopts(ui, opts))
928 opts=patch.diffopts(ui, opts))
934
929
935 def export(ui, repo, *changesets, **opts):
930 def export(ui, repo, *changesets, **opts):
936 """dump the header and diffs for one or more changesets
931 """dump the header and diffs for one or more changesets
937
932
938 Print the changeset header and diffs for one or more revisions.
933 Print the changeset header and diffs for one or more revisions.
939
934
940 The information shown in the changeset header is: author,
935 The information shown in the changeset header is: author,
941 changeset hash, parent(s) and commit comment.
936 changeset hash, parent(s) and commit comment.
942
937
943 NOTE: export may generate unexpected diff output for merge changesets,
938 NOTE: export may generate unexpected diff output for merge changesets,
944 as it will compare the merge changeset against its first parent only.
939 as it will compare the merge changeset against its first parent only.
945
940
946 Output may be to a file, in which case the name of the file is
941 Output may be to a file, in which case the name of the file is
947 given using a format string. The formatting rules are as follows:
942 given using a format string. The formatting rules are as follows:
948
943
949 %% literal "%" character
944 %% literal "%" character
950 %H changeset hash (40 bytes of hexadecimal)
945 %H changeset hash (40 bytes of hexadecimal)
951 %N number of patches being generated
946 %N number of patches being generated
952 %R changeset revision number
947 %R changeset revision number
953 %b basename of the exporting repository
948 %b basename of the exporting repository
954 %h short-form changeset hash (12 bytes of hexadecimal)
949 %h short-form changeset hash (12 bytes of hexadecimal)
955 %n zero-padded sequence number, starting at 1
950 %n zero-padded sequence number, starting at 1
956 %r zero-padded changeset revision number
951 %r zero-padded changeset revision number
957
952
958 Without the -a option, export will avoid generating diffs of files
953 Without the -a option, export will avoid generating diffs of files
959 it detects as binary. With -a, export will generate a diff anyway,
954 it detects as binary. With -a, export will generate a diff anyway,
960 probably with undesirable results.
955 probably with undesirable results.
961
956
962 With the --switch-parent option, the diff will be against the second
957 With the --switch-parent option, the diff will be against the second
963 parent. It can be useful to review a merge.
958 parent. It can be useful to review a merge.
964 """
959 """
965 if not changesets:
960 if not changesets:
966 raise util.Abort(_("export requires at least one changeset"))
961 raise util.Abort(_("export requires at least one changeset"))
967 revs = cmdutil.revrange(repo, changesets)
962 revs = cmdutil.revrange(repo, changesets)
968 if len(revs) > 1:
963 if len(revs) > 1:
969 ui.note(_('exporting patches:\n'))
964 ui.note(_('exporting patches:\n'))
970 else:
965 else:
971 ui.note(_('exporting patch:\n'))
966 ui.note(_('exporting patch:\n'))
972 patch.export(repo, revs, template=opts['output'],
967 patch.export(repo, revs, template=opts['output'],
973 switch_parent=opts['switch_parent'],
968 switch_parent=opts['switch_parent'],
974 opts=patch.diffopts(ui, opts))
969 opts=patch.diffopts(ui, opts))
975
970
976 def grep(ui, repo, pattern, *pats, **opts):
971 def grep(ui, repo, pattern, *pats, **opts):
977 """search for a pattern in specified files and revisions
972 """search for a pattern in specified files and revisions
978
973
979 Search revisions of files for a regular expression.
974 Search revisions of files for a regular expression.
980
975
981 This command behaves differently than Unix grep. It only accepts
976 This command behaves differently than Unix grep. It only accepts
982 Python/Perl regexps. It searches repository history, not the
977 Python/Perl regexps. It searches repository history, not the
983 working directory. It always prints the revision number in which
978 working directory. It always prints the revision number in which
984 a match appears.
979 a match appears.
985
980
986 By default, grep only prints output for the first revision of a
981 By default, grep only prints output for the first revision of a
987 file in which it finds a match. To get it to print every revision
982 file in which it finds a match. To get it to print every revision
988 that contains a change in match status ("-" for a match that
983 that contains a change in match status ("-" for a match that
989 becomes a non-match, or "+" for a non-match that becomes a match),
984 becomes a non-match, or "+" for a non-match that becomes a match),
990 use the --all flag.
985 use the --all flag.
991 """
986 """
992 reflags = 0
987 reflags = 0
993 if opts['ignore_case']:
988 if opts['ignore_case']:
994 reflags |= re.I
989 reflags |= re.I
995 try:
990 try:
996 regexp = re.compile(pattern, reflags)
991 regexp = re.compile(pattern, reflags)
997 except Exception, inst:
992 except Exception, inst:
998 ui.warn(_("grep: invalid match pattern: %s!\n") % inst)
993 ui.warn(_("grep: invalid match pattern: %s!\n") % inst)
999 return None
994 return None
1000 sep, eol = ':', '\n'
995 sep, eol = ':', '\n'
1001 if opts['print0']:
996 if opts['print0']:
1002 sep = eol = '\0'
997 sep = eol = '\0'
1003
998
1004 fcache = {}
999 fcache = {}
1005 def getfile(fn):
1000 def getfile(fn):
1006 if fn not in fcache:
1001 if fn not in fcache:
1007 fcache[fn] = repo.file(fn)
1002 fcache[fn] = repo.file(fn)
1008 return fcache[fn]
1003 return fcache[fn]
1009
1004
1010 def matchlines(body):
1005 def matchlines(body):
1011 begin = 0
1006 begin = 0
1012 linenum = 0
1007 linenum = 0
1013 while True:
1008 while True:
1014 match = regexp.search(body, begin)
1009 match = regexp.search(body, begin)
1015 if not match:
1010 if not match:
1016 break
1011 break
1017 mstart, mend = match.span()
1012 mstart, mend = match.span()
1018 linenum += body.count('\n', begin, mstart) + 1
1013 linenum += body.count('\n', begin, mstart) + 1
1019 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1014 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1020 lend = body.find('\n', mend)
1015 lend = body.find('\n', mend)
1021 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1016 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1022 begin = lend + 1
1017 begin = lend + 1
1023
1018
1024 class linestate(object):
1019 class linestate(object):
1025 def __init__(self, line, linenum, colstart, colend):
1020 def __init__(self, line, linenum, colstart, colend):
1026 self.line = line
1021 self.line = line
1027 self.linenum = linenum
1022 self.linenum = linenum
1028 self.colstart = colstart
1023 self.colstart = colstart
1029 self.colend = colend
1024 self.colend = colend
1030
1025
1031 def __eq__(self, other):
1026 def __eq__(self, other):
1032 return self.line == other.line
1027 return self.line == other.line
1033
1028
1034 matches = {}
1029 matches = {}
1035 copies = {}
1030 copies = {}
1036 def grepbody(fn, rev, body):
1031 def grepbody(fn, rev, body):
1037 matches[rev].setdefault(fn, [])
1032 matches[rev].setdefault(fn, [])
1038 m = matches[rev][fn]
1033 m = matches[rev][fn]
1039 for lnum, cstart, cend, line in matchlines(body):
1034 for lnum, cstart, cend, line in matchlines(body):
1040 s = linestate(line, lnum, cstart, cend)
1035 s = linestate(line, lnum, cstart, cend)
1041 m.append(s)
1036 m.append(s)
1042
1037
1043 def difflinestates(a, b):
1038 def difflinestates(a, b):
1044 sm = difflib.SequenceMatcher(None, a, b)
1039 sm = difflib.SequenceMatcher(None, a, b)
1045 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1040 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1046 if tag == 'insert':
1041 if tag == 'insert':
1047 for i in xrange(blo, bhi):
1042 for i in xrange(blo, bhi):
1048 yield ('+', b[i])
1043 yield ('+', b[i])
1049 elif tag == 'delete':
1044 elif tag == 'delete':
1050 for i in xrange(alo, ahi):
1045 for i in xrange(alo, ahi):
1051 yield ('-', a[i])
1046 yield ('-', a[i])
1052 elif tag == 'replace':
1047 elif tag == 'replace':
1053 for i in xrange(alo, ahi):
1048 for i in xrange(alo, ahi):
1054 yield ('-', a[i])
1049 yield ('-', a[i])
1055 for i in xrange(blo, bhi):
1050 for i in xrange(blo, bhi):
1056 yield ('+', b[i])
1051 yield ('+', b[i])
1057
1052
1058 prev = {}
1053 prev = {}
1059 def display(fn, rev, states, prevstates):
1054 def display(fn, rev, states, prevstates):
1060 found = False
1055 found = False
1061 filerevmatches = {}
1056 filerevmatches = {}
1062 r = prev.get(fn, -1)
1057 r = prev.get(fn, -1)
1063 if opts['all']:
1058 if opts['all']:
1064 iter = difflinestates(states, prevstates)
1059 iter = difflinestates(states, prevstates)
1065 else:
1060 else:
1066 iter = [('', l) for l in prevstates]
1061 iter = [('', l) for l in prevstates]
1067 for change, l in iter:
1062 for change, l in iter:
1068 cols = [fn, str(r)]
1063 cols = [fn, str(r)]
1069 if opts['line_number']:
1064 if opts['line_number']:
1070 cols.append(str(l.linenum))
1065 cols.append(str(l.linenum))
1071 if opts['all']:
1066 if opts['all']:
1072 cols.append(change)
1067 cols.append(change)
1073 if opts['user']:
1068 if opts['user']:
1074 cols.append(ui.shortuser(get(r)[1]))
1069 cols.append(ui.shortuser(get(r)[1]))
1075 if opts['files_with_matches']:
1070 if opts['files_with_matches']:
1076 c = (fn, r)
1071 c = (fn, r)
1077 if c in filerevmatches:
1072 if c in filerevmatches:
1078 continue
1073 continue
1079 filerevmatches[c] = 1
1074 filerevmatches[c] = 1
1080 else:
1075 else:
1081 cols.append(l.line)
1076 cols.append(l.line)
1082 ui.write(sep.join(cols), eol)
1077 ui.write(sep.join(cols), eol)
1083 found = True
1078 found = True
1084 return found
1079 return found
1085
1080
1086 fstate = {}
1081 fstate = {}
1087 skip = {}
1082 skip = {}
1088 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1083 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1089 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1084 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1090 found = False
1085 found = False
1091 follow = opts.get('follow')
1086 follow = opts.get('follow')
1092 for st, rev, fns in changeiter:
1087 for st, rev, fns in changeiter:
1093 if st == 'window':
1088 if st == 'window':
1094 matches.clear()
1089 matches.clear()
1095 elif st == 'add':
1090 elif st == 'add':
1096 mf = repo.changectx(rev).manifest()
1091 mf = repo.changectx(rev).manifest()
1097 matches[rev] = {}
1092 matches[rev] = {}
1098 for fn in fns:
1093 for fn in fns:
1099 if fn in skip:
1094 if fn in skip:
1100 continue
1095 continue
1101 try:
1096 try:
1102 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1097 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1103 fstate.setdefault(fn, [])
1098 fstate.setdefault(fn, [])
1104 if follow:
1099 if follow:
1105 copied = getfile(fn).renamed(mf[fn])
1100 copied = getfile(fn).renamed(mf[fn])
1106 if copied:
1101 if copied:
1107 copies.setdefault(rev, {})[fn] = copied[0]
1102 copies.setdefault(rev, {})[fn] = copied[0]
1108 except KeyError:
1103 except KeyError:
1109 pass
1104 pass
1110 elif st == 'iter':
1105 elif st == 'iter':
1111 states = matches[rev].items()
1106 states = matches[rev].items()
1112 states.sort()
1107 states.sort()
1113 for fn, m in states:
1108 for fn, m in states:
1114 copy = copies.get(rev, {}).get(fn)
1109 copy = copies.get(rev, {}).get(fn)
1115 if fn in skip:
1110 if fn in skip:
1116 if copy:
1111 if copy:
1117 skip[copy] = True
1112 skip[copy] = True
1118 continue
1113 continue
1119 if fn in prev or fstate[fn]:
1114 if fn in prev or fstate[fn]:
1120 r = display(fn, rev, m, fstate[fn])
1115 r = display(fn, rev, m, fstate[fn])
1121 found = found or r
1116 found = found or r
1122 if r and not opts['all']:
1117 if r and not opts['all']:
1123 skip[fn] = True
1118 skip[fn] = True
1124 if copy:
1119 if copy:
1125 skip[copy] = True
1120 skip[copy] = True
1126 fstate[fn] = m
1121 fstate[fn] = m
1127 if copy:
1122 if copy:
1128 fstate[copy] = m
1123 fstate[copy] = m
1129 prev[fn] = rev
1124 prev[fn] = rev
1130
1125
1131 fstate = fstate.items()
1126 fstate = fstate.items()
1132 fstate.sort()
1127 fstate.sort()
1133 for fn, state in fstate:
1128 for fn, state in fstate:
1134 if fn in skip:
1129 if fn in skip:
1135 continue
1130 continue
1136 if fn not in copies.get(prev[fn], {}):
1131 if fn not in copies.get(prev[fn], {}):
1137 found = display(fn, rev, {}, state) or found
1132 found = display(fn, rev, {}, state) or found
1138 return (not found and 1) or 0
1133 return (not found and 1) or 0
1139
1134
1140 def heads(ui, repo, *branchrevs, **opts):
1135 def heads(ui, repo, *branchrevs, **opts):
1141 """show current repository heads or show branch heads
1136 """show current repository heads or show branch heads
1142
1137
1143 With no arguments, show all repository head changesets.
1138 With no arguments, show all repository head changesets.
1144
1139
1145 If branch or revisions names are given this will show the heads of
1140 If branch or revisions names are given this will show the heads of
1146 the specified branches or the branches those revisions are tagged
1141 the specified branches or the branches those revisions are tagged
1147 with.
1142 with.
1148
1143
1149 Repository "heads" are changesets that don't have child
1144 Repository "heads" are changesets that don't have child
1150 changesets. They are where development generally takes place and
1145 changesets. They are where development generally takes place and
1151 are the usual targets for update and merge operations.
1146 are the usual targets for update and merge operations.
1152
1147
1153 Branch heads are changesets that have a given branch tag, but have
1148 Branch heads are changesets that have a given branch tag, but have
1154 no child changesets with that tag. They are usually where
1149 no child changesets with that tag. They are usually where
1155 development on the given branch takes place.
1150 development on the given branch takes place.
1156 """
1151 """
1157 if opts['rev']:
1152 if opts['rev']:
1158 start = repo.lookup(opts['rev'])
1153 start = repo.lookup(opts['rev'])
1159 else:
1154 else:
1160 start = None
1155 start = None
1161 if not branchrevs:
1156 if not branchrevs:
1162 # Assume we're looking repo-wide heads if no revs were specified.
1157 # Assume we're looking repo-wide heads if no revs were specified.
1163 heads = repo.heads(start)
1158 heads = repo.heads(start)
1164 else:
1159 else:
1165 heads = []
1160 heads = []
1166 visitedset = util.set()
1161 visitedset = util.set()
1167 for branchrev in branchrevs:
1162 for branchrev in branchrevs:
1168 branch = repo.changectx(branchrev).branch()
1163 branch = repo.changectx(branchrev).branch()
1169 if branch in visitedset:
1164 if branch in visitedset:
1170 continue
1165 continue
1171 visitedset.add(branch)
1166 visitedset.add(branch)
1172 bheads = repo.branchheads(branch, start)
1167 bheads = repo.branchheads(branch, start)
1173 if not bheads:
1168 if not bheads:
1174 if branch != branchrev:
1169 if branch != branchrev:
1175 ui.warn(_("no changes on branch %s containing %s are "
1170 ui.warn(_("no changes on branch %s containing %s are "
1176 "reachable from %s\n")
1171 "reachable from %s\n")
1177 % (branch, branchrev, opts['rev']))
1172 % (branch, branchrev, opts['rev']))
1178 else:
1173 else:
1179 ui.warn(_("no changes on branch %s are reachable from %s\n")
1174 ui.warn(_("no changes on branch %s are reachable from %s\n")
1180 % (branch, opts['rev']))
1175 % (branch, opts['rev']))
1181 heads.extend(bheads)
1176 heads.extend(bheads)
1182 if not heads:
1177 if not heads:
1183 return 1
1178 return 1
1184 displayer = cmdutil.show_changeset(ui, repo, opts)
1179 displayer = cmdutil.show_changeset(ui, repo, opts)
1185 for n in heads:
1180 for n in heads:
1186 displayer.show(changenode=n)
1181 displayer.show(changenode=n)
1187
1182
1188 def help_(ui, name=None, with_version=False):
1183 def help_(ui, name=None, with_version=False):
1189 """show help for a command, extension, or list of commands
1184 """show help for a command, extension, or list of commands
1190
1185
1191 With no arguments, print a list of commands and short help.
1186 With no arguments, print a list of commands and short help.
1192
1187
1193 Given a command name, print help for that command.
1188 Given a command name, print help for that command.
1194
1189
1195 Given an extension name, print help for that extension, and the
1190 Given an extension name, print help for that extension, and the
1196 commands it provides."""
1191 commands it provides."""
1197 option_lists = []
1192 option_lists = []
1198
1193
1199 def addglobalopts(aliases):
1194 def addglobalopts(aliases):
1200 if ui.verbose:
1195 if ui.verbose:
1201 option_lists.append((_("global options:"), globalopts))
1196 option_lists.append((_("global options:"), globalopts))
1202 if name == 'shortlist':
1197 if name == 'shortlist':
1203 option_lists.append((_('use "hg help" for the full list '
1198 option_lists.append((_('use "hg help" for the full list '
1204 'of commands'), ()))
1199 'of commands'), ()))
1205 else:
1200 else:
1206 if name == 'shortlist':
1201 if name == 'shortlist':
1207 msg = _('use "hg help" for the full list of commands '
1202 msg = _('use "hg help" for the full list of commands '
1208 'or "hg -v" for details')
1203 'or "hg -v" for details')
1209 elif aliases:
1204 elif aliases:
1210 msg = _('use "hg -v help%s" to show aliases and '
1205 msg = _('use "hg -v help%s" to show aliases and '
1211 'global options') % (name and " " + name or "")
1206 'global options') % (name and " " + name or "")
1212 else:
1207 else:
1213 msg = _('use "hg -v help %s" to show global options') % name
1208 msg = _('use "hg -v help %s" to show global options') % name
1214 option_lists.append((msg, ()))
1209 option_lists.append((msg, ()))
1215
1210
1216 def helpcmd(name):
1211 def helpcmd(name):
1217 if with_version:
1212 if with_version:
1218 version_(ui)
1213 version_(ui)
1219 ui.write('\n')
1214 ui.write('\n')
1220 aliases, i = cmdutil.findcmd(ui, name, table)
1215 aliases, i = cmdutil.findcmd(ui, name, table)
1221 # synopsis
1216 # synopsis
1222 ui.write("%s\n\n" % i[2])
1217 ui.write("%s\n\n" % i[2])
1223
1218
1224 # description
1219 # description
1225 doc = i[0].__doc__
1220 doc = i[0].__doc__
1226 if not doc:
1221 if not doc:
1227 doc = _("(No help text available)")
1222 doc = _("(No help text available)")
1228 if ui.quiet:
1223 if ui.quiet:
1229 doc = doc.splitlines(0)[0]
1224 doc = doc.splitlines(0)[0]
1230 ui.write("%s\n" % doc.rstrip())
1225 ui.write("%s\n" % doc.rstrip())
1231
1226
1232 if not ui.quiet:
1227 if not ui.quiet:
1233 # aliases
1228 # aliases
1234 if len(aliases) > 1:
1229 if len(aliases) > 1:
1235 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1230 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1236
1231
1237 # options
1232 # options
1238 if i[1]:
1233 if i[1]:
1239 option_lists.append((_("options:\n"), i[1]))
1234 option_lists.append((_("options:\n"), i[1]))
1240
1235
1241 addglobalopts(False)
1236 addglobalopts(False)
1242
1237
1243 def helplist(header, select=None):
1238 def helplist(header, select=None):
1244 h = {}
1239 h = {}
1245 cmds = {}
1240 cmds = {}
1246 for c, e in table.items():
1241 for c, e in table.items():
1247 f = c.split("|", 1)[0]
1242 f = c.split("|", 1)[0]
1248 if select and not select(f):
1243 if select and not select(f):
1249 continue
1244 continue
1250 if name == "shortlist" and not f.startswith("^"):
1245 if name == "shortlist" and not f.startswith("^"):
1251 continue
1246 continue
1252 f = f.lstrip("^")
1247 f = f.lstrip("^")
1253 if not ui.debugflag and f.startswith("debug"):
1248 if not ui.debugflag and f.startswith("debug"):
1254 continue
1249 continue
1255 doc = e[0].__doc__
1250 doc = e[0].__doc__
1256 if not doc:
1251 if not doc:
1257 doc = _("(No help text available)")
1252 doc = _("(No help text available)")
1258 h[f] = doc.splitlines(0)[0].rstrip()
1253 h[f] = doc.splitlines(0)[0].rstrip()
1259 cmds[f] = c.lstrip("^")
1254 cmds[f] = c.lstrip("^")
1260
1255
1261 if not h:
1256 if not h:
1262 ui.status(_('no commands defined\n'))
1257 ui.status(_('no commands defined\n'))
1263 return
1258 return
1264
1259
1265 ui.status(header)
1260 ui.status(header)
1266 fns = h.keys()
1261 fns = h.keys()
1267 fns.sort()
1262 fns.sort()
1268 m = max(map(len, fns))
1263 m = max(map(len, fns))
1269 for f in fns:
1264 for f in fns:
1270 if ui.verbose:
1265 if ui.verbose:
1271 commands = cmds[f].replace("|",", ")
1266 commands = cmds[f].replace("|",", ")
1272 ui.write(" %s:\n %s\n"%(commands, h[f]))
1267 ui.write(" %s:\n %s\n"%(commands, h[f]))
1273 else:
1268 else:
1274 ui.write(' %-*s %s\n' % (m, f, h[f]))
1269 ui.write(' %-*s %s\n' % (m, f, h[f]))
1275
1270
1276 if not ui.quiet:
1271 if not ui.quiet:
1277 addglobalopts(True)
1272 addglobalopts(True)
1278
1273
1279 def helptopic(name):
1274 def helptopic(name):
1280 v = None
1275 v = None
1281 for i in help.helptable:
1276 for i in help.helptable:
1282 l = i.split('|')
1277 l = i.split('|')
1283 if name in l:
1278 if name in l:
1284 v = i
1279 v = i
1285 header = l[-1]
1280 header = l[-1]
1286 if not v:
1281 if not v:
1287 raise cmdutil.UnknownCommand(name)
1282 raise cmdutil.UnknownCommand(name)
1288
1283
1289 # description
1284 # description
1290 doc = help.helptable[v]
1285 doc = help.helptable[v]
1291 if not doc:
1286 if not doc:
1292 doc = _("(No help text available)")
1287 doc = _("(No help text available)")
1293 if callable(doc):
1288 if callable(doc):
1294 doc = doc()
1289 doc = doc()
1295
1290
1296 ui.write("%s\n" % header)
1291 ui.write("%s\n" % header)
1297 ui.write("%s\n" % doc.rstrip())
1292 ui.write("%s\n" % doc.rstrip())
1298
1293
1299 def helpext(name):
1294 def helpext(name):
1300 try:
1295 try:
1301 mod = extensions.find(name)
1296 mod = extensions.find(name)
1302 except KeyError:
1297 except KeyError:
1303 raise cmdutil.UnknownCommand(name)
1298 raise cmdutil.UnknownCommand(name)
1304
1299
1305 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1300 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1306 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1301 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1307 for d in doc[1:]:
1302 for d in doc[1:]:
1308 ui.write(d, '\n')
1303 ui.write(d, '\n')
1309
1304
1310 ui.status('\n')
1305 ui.status('\n')
1311
1306
1312 try:
1307 try:
1313 ct = mod.cmdtable
1308 ct = mod.cmdtable
1314 except AttributeError:
1309 except AttributeError:
1315 ct = {}
1310 ct = {}
1316
1311
1317 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1312 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1318 helplist(_('list of commands:\n\n'), modcmds.has_key)
1313 helplist(_('list of commands:\n\n'), modcmds.has_key)
1319
1314
1320 if name and name != 'shortlist':
1315 if name and name != 'shortlist':
1321 i = None
1316 i = None
1322 for f in (helpcmd, helptopic, helpext):
1317 for f in (helpcmd, helptopic, helpext):
1323 try:
1318 try:
1324 f(name)
1319 f(name)
1325 i = None
1320 i = None
1326 break
1321 break
1327 except cmdutil.UnknownCommand, inst:
1322 except cmdutil.UnknownCommand, inst:
1328 i = inst
1323 i = inst
1329 if i:
1324 if i:
1330 raise i
1325 raise i
1331
1326
1332 else:
1327 else:
1333 # program name
1328 # program name
1334 if ui.verbose or with_version:
1329 if ui.verbose or with_version:
1335 version_(ui)
1330 version_(ui)
1336 else:
1331 else:
1337 ui.status(_("Mercurial Distributed SCM\n"))
1332 ui.status(_("Mercurial Distributed SCM\n"))
1338 ui.status('\n')
1333 ui.status('\n')
1339
1334
1340 # list of commands
1335 # list of commands
1341 if name == "shortlist":
1336 if name == "shortlist":
1342 header = _('basic commands:\n\n')
1337 header = _('basic commands:\n\n')
1343 else:
1338 else:
1344 header = _('list of commands:\n\n')
1339 header = _('list of commands:\n\n')
1345
1340
1346 helplist(header)
1341 helplist(header)
1347
1342
1348 # list all option lists
1343 # list all option lists
1349 opt_output = []
1344 opt_output = []
1350 for title, options in option_lists:
1345 for title, options in option_lists:
1351 opt_output.append(("\n%s" % title, None))
1346 opt_output.append(("\n%s" % title, None))
1352 for shortopt, longopt, default, desc in options:
1347 for shortopt, longopt, default, desc in options:
1353 if "DEPRECATED" in desc and not ui.verbose: continue
1348 if "DEPRECATED" in desc and not ui.verbose: continue
1354 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1349 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1355 longopt and " --%s" % longopt),
1350 longopt and " --%s" % longopt),
1356 "%s%s" % (desc,
1351 "%s%s" % (desc,
1357 default
1352 default
1358 and _(" (default: %s)") % default
1353 and _(" (default: %s)") % default
1359 or "")))
1354 or "")))
1360
1355
1361 if opt_output:
1356 if opt_output:
1362 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1357 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1363 for first, second in opt_output:
1358 for first, second in opt_output:
1364 if second:
1359 if second:
1365 ui.write(" %-*s %s\n" % (opts_len, first, second))
1360 ui.write(" %-*s %s\n" % (opts_len, first, second))
1366 else:
1361 else:
1367 ui.write("%s\n" % first)
1362 ui.write("%s\n" % first)
1368
1363
1369 def identify(ui, repo, source=None,
1364 def identify(ui, repo, source=None,
1370 rev=None, num=None, id=None, branch=None, tags=None):
1365 rev=None, num=None, id=None, branch=None, tags=None):
1371 """identify the working copy or specified revision
1366 """identify the working copy or specified revision
1372
1367
1373 With no revision, print a summary of the current state of the repo.
1368 With no revision, print a summary of the current state of the repo.
1374
1369
1375 With a path, do a lookup in another repository.
1370 With a path, do a lookup in another repository.
1376
1371
1377 This summary identifies the repository state using one or two parent
1372 This summary identifies the repository state using one or two parent
1378 hash identifiers, followed by a "+" if there are uncommitted changes
1373 hash identifiers, followed by a "+" if there are uncommitted changes
1379 in the working directory, a list of tags for this revision and a branch
1374 in the working directory, a list of tags for this revision and a branch
1380 name for non-default branches.
1375 name for non-default branches.
1381 """
1376 """
1382
1377
1383 if not repo and not source:
1378 if not repo and not source:
1384 raise util.Abort(_("There is no Mercurial repository here "
1379 raise util.Abort(_("There is no Mercurial repository here "
1385 "(.hg not found)"))
1380 "(.hg not found)"))
1386
1381
1387 hexfunc = ui.debugflag and hex or short
1382 hexfunc = ui.debugflag and hex or short
1388 default = not (num or id or branch or tags)
1383 default = not (num or id or branch or tags)
1389 output = []
1384 output = []
1390
1385
1391 if source:
1386 if source:
1392 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1387 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1393 srepo = hg.repository(ui, source)
1388 srepo = hg.repository(ui, source)
1394 if not rev and revs:
1389 if not rev and revs:
1395 rev = revs[0]
1390 rev = revs[0]
1396 if not rev:
1391 if not rev:
1397 rev = "tip"
1392 rev = "tip"
1398 if num or branch or tags:
1393 if num or branch or tags:
1399 raise util.Abort(
1394 raise util.Abort(
1400 "can't query remote revision number, branch, or tags")
1395 "can't query remote revision number, branch, or tags")
1401 output = [hexfunc(srepo.lookup(rev))]
1396 output = [hexfunc(srepo.lookup(rev))]
1402 elif not rev:
1397 elif not rev:
1403 ctx = repo.workingctx()
1398 ctx = repo.workingctx()
1404 parents = ctx.parents()
1399 parents = ctx.parents()
1405 changed = False
1400 changed = False
1406 if default or id or num:
1401 if default or id or num:
1407 changed = ctx.files() + ctx.deleted()
1402 changed = ctx.files() + ctx.deleted()
1408 if default or id:
1403 if default or id:
1409 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1404 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1410 (changed) and "+" or "")]
1405 (changed) and "+" or "")]
1411 if num:
1406 if num:
1412 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1407 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1413 (changed) and "+" or ""))
1408 (changed) and "+" or ""))
1414 else:
1409 else:
1415 ctx = repo.changectx(rev)
1410 ctx = repo.changectx(rev)
1416 if default or id:
1411 if default or id:
1417 output = [hexfunc(ctx.node())]
1412 output = [hexfunc(ctx.node())]
1418 if num:
1413 if num:
1419 output.append(str(ctx.rev()))
1414 output.append(str(ctx.rev()))
1420
1415
1421 if not source and default and not ui.quiet:
1416 if not source and default and not ui.quiet:
1422 b = util.tolocal(ctx.branch())
1417 b = util.tolocal(ctx.branch())
1423 if b != 'default':
1418 if b != 'default':
1424 output.append("(%s)" % b)
1419 output.append("(%s)" % b)
1425
1420
1426 # multiple tags for a single parent separated by '/'
1421 # multiple tags for a single parent separated by '/'
1427 t = "/".join(ctx.tags())
1422 t = "/".join(ctx.tags())
1428 if t:
1423 if t:
1429 output.append(t)
1424 output.append(t)
1430
1425
1431 if branch:
1426 if branch:
1432 output.append(util.tolocal(ctx.branch()))
1427 output.append(util.tolocal(ctx.branch()))
1433
1428
1434 if tags:
1429 if tags:
1435 output.extend(ctx.tags())
1430 output.extend(ctx.tags())
1436
1431
1437 ui.write("%s\n" % ' '.join(output))
1432 ui.write("%s\n" % ' '.join(output))
1438
1433
1439 def import_(ui, repo, patch1, *patches, **opts):
1434 def import_(ui, repo, patch1, *patches, **opts):
1440 """import an ordered set of patches
1435 """import an ordered set of patches
1441
1436
1442 Import a list of patches and commit them individually.
1437 Import a list of patches and commit them individually.
1443
1438
1444 If there are outstanding changes in the working directory, import
1439 If there are outstanding changes in the working directory, import
1445 will abort unless given the -f flag.
1440 will abort unless given the -f flag.
1446
1441
1447 You can import a patch straight from a mail message. Even patches
1442 You can import a patch straight from a mail message. Even patches
1448 as attachments work (body part must be type text/plain or
1443 as attachments work (body part must be type text/plain or
1449 text/x-patch to be used). From and Subject headers of email
1444 text/x-patch to be used). From and Subject headers of email
1450 message are used as default committer and commit message. All
1445 message are used as default committer and commit message. All
1451 text/plain body parts before first diff are added to commit
1446 text/plain body parts before first diff are added to commit
1452 message.
1447 message.
1453
1448
1454 If the imported patch was generated by hg export, user and description
1449 If the imported patch was generated by hg export, user and description
1455 from patch override values from message headers and body. Values
1450 from patch override values from message headers and body. Values
1456 given on command line with -m and -u override these.
1451 given on command line with -m and -u override these.
1457
1452
1458 If --exact is specified, import will set the working directory
1453 If --exact is specified, import will set the working directory
1459 to the parent of each patch before applying it, and will abort
1454 to the parent of each patch before applying it, and will abort
1460 if the resulting changeset has a different ID than the one
1455 if the resulting changeset has a different ID than the one
1461 recorded in the patch. This may happen due to character set
1456 recorded in the patch. This may happen due to character set
1462 problems or other deficiencies in the text patch format.
1457 problems or other deficiencies in the text patch format.
1463
1458
1464 To read a patch from standard input, use patch name "-".
1459 To read a patch from standard input, use patch name "-".
1465 """
1460 """
1466 patches = (patch1,) + patches
1461 patches = (patch1,) + patches
1467
1462
1468 if opts.get('exact') or not opts['force']:
1463 if opts.get('exact') or not opts['force']:
1469 cmdutil.bail_if_changed(repo)
1464 cmdutil.bail_if_changed(repo)
1470
1465
1471 d = opts["base"]
1466 d = opts["base"]
1472 strip = opts["strip"]
1467 strip = opts["strip"]
1473 wlock = lock = None
1468 wlock = lock = None
1474 try:
1469 try:
1475 wlock = repo.wlock()
1470 wlock = repo.wlock()
1476 lock = repo.lock()
1471 lock = repo.lock()
1477 for p in patches:
1472 for p in patches:
1478 pf = os.path.join(d, p)
1473 pf = os.path.join(d, p)
1479
1474
1480 if pf == '-':
1475 if pf == '-':
1481 ui.status(_("applying patch from stdin\n"))
1476 ui.status(_("applying patch from stdin\n"))
1482 data = patch.extract(ui, sys.stdin)
1477 data = patch.extract(ui, sys.stdin)
1483 else:
1478 else:
1484 ui.status(_("applying %s\n") % p)
1479 ui.status(_("applying %s\n") % p)
1485 if os.path.exists(pf):
1480 if os.path.exists(pf):
1486 data = patch.extract(ui, file(pf, 'rb'))
1481 data = patch.extract(ui, file(pf, 'rb'))
1487 else:
1482 else:
1488 data = patch.extract(ui, urllib.urlopen(pf))
1483 data = patch.extract(ui, urllib.urlopen(pf))
1489 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1484 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1490
1485
1491 if tmpname is None:
1486 if tmpname is None:
1492 raise util.Abort(_('no diffs found'))
1487 raise util.Abort(_('no diffs found'))
1493
1488
1494 try:
1489 try:
1495 cmdline_message = cmdutil.logmessage(opts)
1490 cmdline_message = cmdutil.logmessage(opts)
1496 if cmdline_message:
1491 if cmdline_message:
1497 # pickup the cmdline msg
1492 # pickup the cmdline msg
1498 message = cmdline_message
1493 message = cmdline_message
1499 elif message:
1494 elif message:
1500 # pickup the patch msg
1495 # pickup the patch msg
1501 message = message.strip()
1496 message = message.strip()
1502 else:
1497 else:
1503 # launch the editor
1498 # launch the editor
1504 message = None
1499 message = None
1505 ui.debug(_('message:\n%s\n') % message)
1500 ui.debug(_('message:\n%s\n') % message)
1506
1501
1507 wp = repo.workingctx().parents()
1502 wp = repo.workingctx().parents()
1508 if opts.get('exact'):
1503 if opts.get('exact'):
1509 if not nodeid or not p1:
1504 if not nodeid or not p1:
1510 raise util.Abort(_('not a mercurial patch'))
1505 raise util.Abort(_('not a mercurial patch'))
1511 p1 = repo.lookup(p1)
1506 p1 = repo.lookup(p1)
1512 p2 = repo.lookup(p2 or hex(nullid))
1507 p2 = repo.lookup(p2 or hex(nullid))
1513
1508
1514 if p1 != wp[0].node():
1509 if p1 != wp[0].node():
1515 hg.clean(repo, p1)
1510 hg.clean(repo, p1)
1516 repo.dirstate.setparents(p1, p2)
1511 repo.dirstate.setparents(p1, p2)
1517 elif p2:
1512 elif p2:
1518 try:
1513 try:
1519 p1 = repo.lookup(p1)
1514 p1 = repo.lookup(p1)
1520 p2 = repo.lookup(p2)
1515 p2 = repo.lookup(p2)
1521 if p1 == wp[0].node():
1516 if p1 == wp[0].node():
1522 repo.dirstate.setparents(p1, p2)
1517 repo.dirstate.setparents(p1, p2)
1523 except hg.RepoError:
1518 except hg.RepoError:
1524 pass
1519 pass
1525 if opts.get('exact') or opts.get('import_branch'):
1520 if opts.get('exact') or opts.get('import_branch'):
1526 repo.dirstate.setbranch(branch or 'default')
1521 repo.dirstate.setbranch(branch or 'default')
1527
1522
1528 files = {}
1523 files = {}
1529 try:
1524 try:
1530 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1525 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1531 files=files)
1526 files=files)
1532 finally:
1527 finally:
1533 files = patch.updatedir(ui, repo, files)
1528 files = patch.updatedir(ui, repo, files)
1534 n = repo.commit(files, message, user, date)
1529 n = repo.commit(files, message, user, date)
1535 if opts.get('exact'):
1530 if opts.get('exact'):
1536 if hex(n) != nodeid:
1531 if hex(n) != nodeid:
1537 repo.rollback()
1532 repo.rollback()
1538 raise util.Abort(_('patch is damaged'
1533 raise util.Abort(_('patch is damaged'
1539 ' or loses information'))
1534 ' or loses information'))
1540 finally:
1535 finally:
1541 os.unlink(tmpname)
1536 os.unlink(tmpname)
1542 finally:
1537 finally:
1543 del lock, wlock
1538 del lock, wlock
1544
1539
1545 def incoming(ui, repo, source="default", **opts):
1540 def incoming(ui, repo, source="default", **opts):
1546 """show new changesets found in source
1541 """show new changesets found in source
1547
1542
1548 Show new changesets found in the specified path/URL or the default
1543 Show new changesets found in the specified path/URL or the default
1549 pull location. These are the changesets that would be pulled if a pull
1544 pull location. These are the changesets that would be pulled if a pull
1550 was requested.
1545 was requested.
1551
1546
1552 For remote repository, using --bundle avoids downloading the changesets
1547 For remote repository, using --bundle avoids downloading the changesets
1553 twice if the incoming is followed by a pull.
1548 twice if the incoming is followed by a pull.
1554
1549
1555 See pull for valid source format details.
1550 See pull for valid source format details.
1556 """
1551 """
1557 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
1552 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
1558 cmdutil.setremoteconfig(ui, opts)
1553 cmdutil.setremoteconfig(ui, opts)
1559
1554
1560 other = hg.repository(ui, source)
1555 other = hg.repository(ui, source)
1561 ui.status(_('comparing with %s\n') % util.hidepassword(source))
1556 ui.status(_('comparing with %s\n') % util.hidepassword(source))
1562 if revs:
1557 if revs:
1563 revs = [other.lookup(rev) for rev in revs]
1558 revs = [other.lookup(rev) for rev in revs]
1564 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1559 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1565 if not incoming:
1560 if not incoming:
1566 try:
1561 try:
1567 os.unlink(opts["bundle"])
1562 os.unlink(opts["bundle"])
1568 except:
1563 except:
1569 pass
1564 pass
1570 ui.status(_("no changes found\n"))
1565 ui.status(_("no changes found\n"))
1571 return 1
1566 return 1
1572
1567
1573 cleanup = None
1568 cleanup = None
1574 try:
1569 try:
1575 fname = opts["bundle"]
1570 fname = opts["bundle"]
1576 if fname or not other.local():
1571 if fname or not other.local():
1577 # create a bundle (uncompressed if other repo is not local)
1572 # create a bundle (uncompressed if other repo is not local)
1578 if revs is None:
1573 if revs is None:
1579 cg = other.changegroup(incoming, "incoming")
1574 cg = other.changegroup(incoming, "incoming")
1580 else:
1575 else:
1581 cg = other.changegroupsubset(incoming, revs, 'incoming')
1576 cg = other.changegroupsubset(incoming, revs, 'incoming')
1582 bundletype = other.local() and "HG10BZ" or "HG10UN"
1577 bundletype = other.local() and "HG10BZ" or "HG10UN"
1583 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1578 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1584 # keep written bundle?
1579 # keep written bundle?
1585 if opts["bundle"]:
1580 if opts["bundle"]:
1586 cleanup = None
1581 cleanup = None
1587 if not other.local():
1582 if not other.local():
1588 # use the created uncompressed bundlerepo
1583 # use the created uncompressed bundlerepo
1589 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1584 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1590
1585
1591 o = other.changelog.nodesbetween(incoming, revs)[0]
1586 o = other.changelog.nodesbetween(incoming, revs)[0]
1592 if opts['newest_first']:
1587 if opts['newest_first']:
1593 o.reverse()
1588 o.reverse()
1594 displayer = cmdutil.show_changeset(ui, other, opts)
1589 displayer = cmdutil.show_changeset(ui, other, opts)
1595 for n in o:
1590 for n in o:
1596 parents = [p for p in other.changelog.parents(n) if p != nullid]
1591 parents = [p for p in other.changelog.parents(n) if p != nullid]
1597 if opts['no_merges'] and len(parents) == 2:
1592 if opts['no_merges'] and len(parents) == 2:
1598 continue
1593 continue
1599 displayer.show(changenode=n)
1594 displayer.show(changenode=n)
1600 finally:
1595 finally:
1601 if hasattr(other, 'close'):
1596 if hasattr(other, 'close'):
1602 other.close()
1597 other.close()
1603 if cleanup:
1598 if cleanup:
1604 os.unlink(cleanup)
1599 os.unlink(cleanup)
1605
1600
1606 def init(ui, dest=".", **opts):
1601 def init(ui, dest=".", **opts):
1607 """create a new repository in the given directory
1602 """create a new repository in the given directory
1608
1603
1609 Initialize a new repository in the given directory. If the given
1604 Initialize a new repository in the given directory. If the given
1610 directory does not exist, it is created.
1605 directory does not exist, it is created.
1611
1606
1612 If no directory is given, the current directory is used.
1607 If no directory is given, the current directory is used.
1613
1608
1614 It is possible to specify an ssh:// URL as the destination.
1609 It is possible to specify an ssh:// URL as the destination.
1615 Look at the help text for the pull command for important details
1610 Look at the help text for the pull command for important details
1616 about ssh:// URLs.
1611 about ssh:// URLs.
1617 """
1612 """
1618 cmdutil.setremoteconfig(ui, opts)
1613 cmdutil.setremoteconfig(ui, opts)
1619 hg.repository(ui, dest, create=1)
1614 hg.repository(ui, dest, create=1)
1620
1615
1621 def locate(ui, repo, *pats, **opts):
1616 def locate(ui, repo, *pats, **opts):
1622 """locate files matching specific patterns
1617 """locate files matching specific patterns
1623
1618
1624 Print all files under Mercurial control whose names match the
1619 Print all files under Mercurial control whose names match the
1625 given patterns.
1620 given patterns.
1626
1621
1627 This command searches the entire repository by default. To search
1622 This command searches the entire repository by default. To search
1628 just the current directory and its subdirectories, use
1623 just the current directory and its subdirectories, use
1629 "--include .".
1624 "--include .".
1630
1625
1631 If no patterns are given to match, this command prints all file
1626 If no patterns are given to match, this command prints all file
1632 names.
1627 names.
1633
1628
1634 If you want to feed the output of this command into the "xargs"
1629 If you want to feed the output of this command into the "xargs"
1635 command, use the "-0" option to both this command and "xargs".
1630 command, use the "-0" option to both this command and "xargs".
1636 This will avoid the problem of "xargs" treating single filenames
1631 This will avoid the problem of "xargs" treating single filenames
1637 that contain white space as multiple filenames.
1632 that contain white space as multiple filenames.
1638 """
1633 """
1639 end = opts['print0'] and '\0' or '\n'
1634 end = opts['print0'] and '\0' or '\n'
1640 rev = opts['rev']
1635 rev = opts['rev']
1641 if rev:
1636 if rev:
1642 node = repo.lookup(rev)
1637 node = repo.lookup(rev)
1643 else:
1638 else:
1644 node = None
1639 node = None
1645
1640
1646 ret = 1
1641 ret = 1
1647 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1642 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1648 badmatch=util.always,
1643 badmatch=util.always,
1649 default='relglob'):
1644 default='relglob'):
1650 if src == 'b':
1645 if src == 'b':
1651 continue
1646 continue
1652 if not node and abs not in repo.dirstate:
1647 if not node and abs not in repo.dirstate:
1653 continue
1648 continue
1654 if opts['fullpath']:
1649 if opts['fullpath']:
1655 ui.write(os.path.join(repo.root, abs), end)
1650 ui.write(os.path.join(repo.root, abs), end)
1656 else:
1651 else:
1657 ui.write(((pats and rel) or abs), end)
1652 ui.write(((pats and rel) or abs), end)
1658 ret = 0
1653 ret = 0
1659
1654
1660 return ret
1655 return ret
1661
1656
1662 def log(ui, repo, *pats, **opts):
1657 def log(ui, repo, *pats, **opts):
1663 """show revision history of entire repository or files
1658 """show revision history of entire repository or files
1664
1659
1665 Print the revision history of the specified files or the entire
1660 Print the revision history of the specified files or the entire
1666 project.
1661 project.
1667
1662
1668 File history is shown without following rename or copy history of
1663 File history is shown without following rename or copy history of
1669 files. Use -f/--follow with a file name to follow history across
1664 files. Use -f/--follow with a file name to follow history across
1670 renames and copies. --follow without a file name will only show
1665 renames and copies. --follow without a file name will only show
1671 ancestors or descendants of the starting revision. --follow-first
1666 ancestors or descendants of the starting revision. --follow-first
1672 only follows the first parent of merge revisions.
1667 only follows the first parent of merge revisions.
1673
1668
1674 If no revision range is specified, the default is tip:0 unless
1669 If no revision range is specified, the default is tip:0 unless
1675 --follow is set, in which case the working directory parent is
1670 --follow is set, in which case the working directory parent is
1676 used as the starting revision.
1671 used as the starting revision.
1677
1672
1678 By default this command outputs: changeset id and hash, tags,
1673 By default this command outputs: changeset id and hash, tags,
1679 non-trivial parents, user, date and time, and a summary for each
1674 non-trivial parents, user, date and time, and a summary for each
1680 commit. When the -v/--verbose switch is used, the list of changed
1675 commit. When the -v/--verbose switch is used, the list of changed
1681 files and full commit message is shown.
1676 files and full commit message is shown.
1682
1677
1683 NOTE: log -p may generate unexpected diff output for merge
1678 NOTE: log -p may generate unexpected diff output for merge
1684 changesets, as it will compare the merge changeset against its
1679 changesets, as it will compare the merge changeset against its
1685 first parent only. Also, the files: list will only reflect files
1680 first parent only. Also, the files: list will only reflect files
1686 that are different from BOTH parents.
1681 that are different from BOTH parents.
1687
1682
1688 """
1683 """
1689
1684
1690 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1685 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1691 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1686 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1692
1687
1693 if opts['limit']:
1688 if opts['limit']:
1694 try:
1689 try:
1695 limit = int(opts['limit'])
1690 limit = int(opts['limit'])
1696 except ValueError:
1691 except ValueError:
1697 raise util.Abort(_('limit must be a positive integer'))
1692 raise util.Abort(_('limit must be a positive integer'))
1698 if limit <= 0: raise util.Abort(_('limit must be positive'))
1693 if limit <= 0: raise util.Abort(_('limit must be positive'))
1699 else:
1694 else:
1700 limit = sys.maxint
1695 limit = sys.maxint
1701 count = 0
1696 count = 0
1702
1697
1703 if opts['copies'] and opts['rev']:
1698 if opts['copies'] and opts['rev']:
1704 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1699 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1705 else:
1700 else:
1706 endrev = repo.changelog.count()
1701 endrev = repo.changelog.count()
1707 rcache = {}
1702 rcache = {}
1708 ncache = {}
1703 ncache = {}
1709 dcache = []
1704 dcache = []
1710 def getrenamed(fn, rev, man):
1705 def getrenamed(fn, rev, man):
1711 '''looks up all renames for a file (up to endrev) the first
1706 '''looks up all renames for a file (up to endrev) the first
1712 time the file is given. It indexes on the changerev and only
1707 time the file is given. It indexes on the changerev and only
1713 parses the manifest if linkrev != changerev.
1708 parses the manifest if linkrev != changerev.
1714 Returns rename info for fn at changerev rev.'''
1709 Returns rename info for fn at changerev rev.'''
1715 if fn not in rcache:
1710 if fn not in rcache:
1716 rcache[fn] = {}
1711 rcache[fn] = {}
1717 ncache[fn] = {}
1712 ncache[fn] = {}
1718 fl = repo.file(fn)
1713 fl = repo.file(fn)
1719 for i in xrange(fl.count()):
1714 for i in xrange(fl.count()):
1720 node = fl.node(i)
1715 node = fl.node(i)
1721 lr = fl.linkrev(node)
1716 lr = fl.linkrev(node)
1722 renamed = fl.renamed(node)
1717 renamed = fl.renamed(node)
1723 rcache[fn][lr] = renamed
1718 rcache[fn][lr] = renamed
1724 if renamed:
1719 if renamed:
1725 ncache[fn][node] = renamed
1720 ncache[fn][node] = renamed
1726 if lr >= endrev:
1721 if lr >= endrev:
1727 break
1722 break
1728 if rev in rcache[fn]:
1723 if rev in rcache[fn]:
1729 return rcache[fn][rev]
1724 return rcache[fn][rev]
1730 mr = repo.manifest.rev(man)
1725 mr = repo.manifest.rev(man)
1731 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1726 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1732 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1727 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1733 if not dcache or dcache[0] != man:
1728 if not dcache or dcache[0] != man:
1734 dcache[:] = [man, repo.manifest.readdelta(man)]
1729 dcache[:] = [man, repo.manifest.readdelta(man)]
1735 if fn in dcache[1]:
1730 if fn in dcache[1]:
1736 return ncache[fn].get(dcache[1][fn])
1731 return ncache[fn].get(dcache[1][fn])
1737 return None
1732 return None
1738
1733
1739 df = False
1734 df = False
1740 if opts["date"]:
1735 if opts["date"]:
1741 df = util.matchdate(opts["date"])
1736 df = util.matchdate(opts["date"])
1742
1737
1743 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1738 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1744 for st, rev, fns in changeiter:
1739 for st, rev, fns in changeiter:
1745 if st == 'add':
1740 if st == 'add':
1746 changenode = repo.changelog.node(rev)
1741 changenode = repo.changelog.node(rev)
1747 parents = [p for p in repo.changelog.parentrevs(rev)
1742 parents = [p for p in repo.changelog.parentrevs(rev)
1748 if p != nullrev]
1743 if p != nullrev]
1749 if opts['no_merges'] and len(parents) == 2:
1744 if opts['no_merges'] and len(parents) == 2:
1750 continue
1745 continue
1751 if opts['only_merges'] and len(parents) != 2:
1746 if opts['only_merges'] and len(parents) != 2:
1752 continue
1747 continue
1753
1748
1754 if df:
1749 if df:
1755 changes = get(rev)
1750 changes = get(rev)
1756 if not df(changes[2][0]):
1751 if not df(changes[2][0]):
1757 continue
1752 continue
1758
1753
1759 if opts['keyword']:
1754 if opts['keyword']:
1760 changes = get(rev)
1755 changes = get(rev)
1761 miss = 0
1756 miss = 0
1762 for k in [kw.lower() for kw in opts['keyword']]:
1757 for k in [kw.lower() for kw in opts['keyword']]:
1763 if not (k in changes[1].lower() or
1758 if not (k in changes[1].lower() or
1764 k in changes[4].lower() or
1759 k in changes[4].lower() or
1765 k in " ".join(changes[3]).lower()):
1760 k in " ".join(changes[3]).lower()):
1766 miss = 1
1761 miss = 1
1767 break
1762 break
1768 if miss:
1763 if miss:
1769 continue
1764 continue
1770
1765
1771 copies = []
1766 copies = []
1772 if opts.get('copies') and rev:
1767 if opts.get('copies') and rev:
1773 mf = get(rev)[0]
1768 mf = get(rev)[0]
1774 for fn in get(rev)[3]:
1769 for fn in get(rev)[3]:
1775 rename = getrenamed(fn, rev, mf)
1770 rename = getrenamed(fn, rev, mf)
1776 if rename:
1771 if rename:
1777 copies.append((fn, rename[0]))
1772 copies.append((fn, rename[0]))
1778 displayer.show(rev, changenode, copies=copies)
1773 displayer.show(rev, changenode, copies=copies)
1779 elif st == 'iter':
1774 elif st == 'iter':
1780 if count == limit: break
1775 if count == limit: break
1781 if displayer.flush(rev):
1776 if displayer.flush(rev):
1782 count += 1
1777 count += 1
1783
1778
1784 def manifest(ui, repo, node=None, rev=None):
1779 def manifest(ui, repo, node=None, rev=None):
1785 """output the current or given revision of the project manifest
1780 """output the current or given revision of the project manifest
1786
1781
1787 Print a list of version controlled files for the given revision.
1782 Print a list of version controlled files for the given revision.
1788 If no revision is given, the parent of the working directory is used,
1783 If no revision is given, the parent of the working directory is used,
1789 or tip if no revision is checked out.
1784 or tip if no revision is checked out.
1790
1785
1791 The manifest is the list of files being version controlled. If no revision
1786 The manifest is the list of files being version controlled. If no revision
1792 is given then the first parent of the working directory is used.
1787 is given then the first parent of the working directory is used.
1793
1788
1794 With -v flag, print file permissions, symlink and executable bits. With
1789 With -v flag, print file permissions, symlink and executable bits. With
1795 --debug flag, print file revision hashes.
1790 --debug flag, print file revision hashes.
1796 """
1791 """
1797
1792
1798 if rev and node:
1793 if rev and node:
1799 raise util.Abort(_("please specify just one revision"))
1794 raise util.Abort(_("please specify just one revision"))
1800
1795
1801 if not node:
1796 if not node:
1802 node = rev
1797 node = rev
1803
1798
1804 m = repo.changectx(node).manifest()
1799 m = repo.changectx(node).manifest()
1805 files = m.keys()
1800 files = m.keys()
1806 files.sort()
1801 files.sort()
1807
1802
1808 for f in files:
1803 for f in files:
1809 if ui.debugflag:
1804 if ui.debugflag:
1810 ui.write("%40s " % hex(m[f]))
1805 ui.write("%40s " % hex(m[f]))
1811 if ui.verbose:
1806 if ui.verbose:
1812 type = m.execf(f) and "*" or m.linkf(f) and "@" or " "
1807 type = m.execf(f) and "*" or m.linkf(f) and "@" or " "
1813 perm = m.execf(f) and "755" or "644"
1808 perm = m.execf(f) and "755" or "644"
1814 ui.write("%3s %1s " % (perm, type))
1809 ui.write("%3s %1s " % (perm, type))
1815 ui.write("%s\n" % f)
1810 ui.write("%s\n" % f)
1816
1811
1817 def merge(ui, repo, node=None, force=None, rev=None):
1812 def merge(ui, repo, node=None, force=None, rev=None):
1818 """merge working directory with another revision
1813 """merge working directory with another revision
1819
1814
1820 Merge the contents of the current working directory and the
1815 Merge the contents of the current working directory and the
1821 requested revision. Files that changed between either parent are
1816 requested revision. Files that changed between either parent are
1822 marked as changed for the next commit and a commit must be
1817 marked as changed for the next commit and a commit must be
1823 performed before any further updates are allowed.
1818 performed before any further updates are allowed.
1824
1819
1825 If no revision is specified, the working directory's parent is a
1820 If no revision is specified, the working directory's parent is a
1826 head revision, and the repository contains exactly one other head,
1821 head revision, and the repository contains exactly one other head,
1827 the other head is merged with by default. Otherwise, an explicit
1822 the other head is merged with by default. Otherwise, an explicit
1828 revision to merge with must be provided.
1823 revision to merge with must be provided.
1829 """
1824 """
1830
1825
1831 if rev and node:
1826 if rev and node:
1832 raise util.Abort(_("please specify just one revision"))
1827 raise util.Abort(_("please specify just one revision"))
1833 if not node:
1828 if not node:
1834 node = rev
1829 node = rev
1835
1830
1836 if not node:
1831 if not node:
1837 heads = repo.heads()
1832 heads = repo.heads()
1838 if len(heads) > 2:
1833 if len(heads) > 2:
1839 raise util.Abort(_('repo has %d heads - '
1834 raise util.Abort(_('repo has %d heads - '
1840 'please merge with an explicit rev') %
1835 'please merge with an explicit rev') %
1841 len(heads))
1836 len(heads))
1842 parent = repo.dirstate.parents()[0]
1837 parent = repo.dirstate.parents()[0]
1843 if len(heads) == 1:
1838 if len(heads) == 1:
1844 msg = _('there is nothing to merge')
1839 msg = _('there is nothing to merge')
1845 if parent != repo.lookup(repo.workingctx().branch()):
1840 if parent != repo.lookup(repo.workingctx().branch()):
1846 msg = _('%s - use "hg update" instead') % msg
1841 msg = _('%s - use "hg update" instead') % msg
1847 raise util.Abort(msg)
1842 raise util.Abort(msg)
1848
1843
1849 if parent not in heads:
1844 if parent not in heads:
1850 raise util.Abort(_('working dir not at a head rev - '
1845 raise util.Abort(_('working dir not at a head rev - '
1851 'use "hg update" or merge with an explicit rev'))
1846 'use "hg update" or merge with an explicit rev'))
1852 node = parent == heads[0] and heads[-1] or heads[0]
1847 node = parent == heads[0] and heads[-1] or heads[0]
1853 return hg.merge(repo, node, force=force)
1848 return hg.merge(repo, node, force=force)
1854
1849
1855 def outgoing(ui, repo, dest=None, **opts):
1850 def outgoing(ui, repo, dest=None, **opts):
1856 """show changesets not found in destination
1851 """show changesets not found in destination
1857
1852
1858 Show changesets not found in the specified destination repository or
1853 Show changesets not found in the specified destination repository or
1859 the default push location. These are the changesets that would be pushed
1854 the default push location. These are the changesets that would be pushed
1860 if a push was requested.
1855 if a push was requested.
1861
1856
1862 See pull for valid destination format details.
1857 See pull for valid destination format details.
1863 """
1858 """
1864 dest, revs, checkout = hg.parseurl(
1859 dest, revs, checkout = hg.parseurl(
1865 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
1860 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
1866 cmdutil.setremoteconfig(ui, opts)
1861 cmdutil.setremoteconfig(ui, opts)
1867 if revs:
1862 if revs:
1868 revs = [repo.lookup(rev) for rev in revs]
1863 revs = [repo.lookup(rev) for rev in revs]
1869
1864
1870 other = hg.repository(ui, dest)
1865 other = hg.repository(ui, dest)
1871 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
1866 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
1872 o = repo.findoutgoing(other, force=opts['force'])
1867 o = repo.findoutgoing(other, force=opts['force'])
1873 if not o:
1868 if not o:
1874 ui.status(_("no changes found\n"))
1869 ui.status(_("no changes found\n"))
1875 return 1
1870 return 1
1876 o = repo.changelog.nodesbetween(o, revs)[0]
1871 o = repo.changelog.nodesbetween(o, revs)[0]
1877 if opts['newest_first']:
1872 if opts['newest_first']:
1878 o.reverse()
1873 o.reverse()
1879 displayer = cmdutil.show_changeset(ui, repo, opts)
1874 displayer = cmdutil.show_changeset(ui, repo, opts)
1880 for n in o:
1875 for n in o:
1881 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1876 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1882 if opts['no_merges'] and len(parents) == 2:
1877 if opts['no_merges'] and len(parents) == 2:
1883 continue
1878 continue
1884 displayer.show(changenode=n)
1879 displayer.show(changenode=n)
1885
1880
1886 def parents(ui, repo, file_=None, **opts):
1881 def parents(ui, repo, file_=None, **opts):
1887 """show the parents of the working dir or revision
1882 """show the parents of the working dir or revision
1888
1883
1889 Print the working directory's parent revisions. If a
1884 Print the working directory's parent revisions. If a
1890 revision is given via --rev, the parent of that revision
1885 revision is given via --rev, the parent of that revision
1891 will be printed. If a file argument is given, revision in
1886 will be printed. If a file argument is given, revision in
1892 which the file was last changed (before the working directory
1887 which the file was last changed (before the working directory
1893 revision or the argument to --rev if given) is printed.
1888 revision or the argument to --rev if given) is printed.
1894 """
1889 """
1895 rev = opts.get('rev')
1890 rev = opts.get('rev')
1896 if rev:
1891 if rev:
1897 ctx = repo.changectx(rev)
1892 ctx = repo.changectx(rev)
1898 else:
1893 else:
1899 ctx = repo.workingctx()
1894 ctx = repo.workingctx()
1900
1895
1901 if file_:
1896 if file_:
1902 files, match, anypats = cmdutil.matchpats(repo, (file_,), opts)
1897 files, match, anypats = cmdutil.matchpats(repo, (file_,), opts)
1903 if anypats or len(files) != 1:
1898 if anypats or len(files) != 1:
1904 raise util.Abort(_('can only specify an explicit file name'))
1899 raise util.Abort(_('can only specify an explicit file name'))
1905 file_ = files[0]
1900 file_ = files[0]
1906 filenodes = []
1901 filenodes = []
1907 for cp in ctx.parents():
1902 for cp in ctx.parents():
1908 if not cp:
1903 if not cp:
1909 continue
1904 continue
1910 try:
1905 try:
1911 filenodes.append(cp.filenode(file_))
1906 filenodes.append(cp.filenode(file_))
1912 except revlog.LookupError:
1907 except revlog.LookupError:
1913 pass
1908 pass
1914 if not filenodes:
1909 if not filenodes:
1915 raise util.Abort(_("'%s' not found in manifest!") % file_)
1910 raise util.Abort(_("'%s' not found in manifest!") % file_)
1916 fl = repo.file(file_)
1911 fl = repo.file(file_)
1917 p = [repo.lookup(fl.linkrev(fn)) for fn in filenodes]
1912 p = [repo.lookup(fl.linkrev(fn)) for fn in filenodes]
1918 else:
1913 else:
1919 p = [cp.node() for cp in ctx.parents()]
1914 p = [cp.node() for cp in ctx.parents()]
1920
1915
1921 displayer = cmdutil.show_changeset(ui, repo, opts)
1916 displayer = cmdutil.show_changeset(ui, repo, opts)
1922 for n in p:
1917 for n in p:
1923 if n != nullid:
1918 if n != nullid:
1924 displayer.show(changenode=n)
1919 displayer.show(changenode=n)
1925
1920
1926 def paths(ui, repo, search=None):
1921 def paths(ui, repo, search=None):
1927 """show definition of symbolic path names
1922 """show definition of symbolic path names
1928
1923
1929 Show definition of symbolic path name NAME. If no name is given, show
1924 Show definition of symbolic path name NAME. If no name is given, show
1930 definition of available names.
1925 definition of available names.
1931
1926
1932 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1927 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1933 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1928 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1934 """
1929 """
1935 if search:
1930 if search:
1936 for name, path in ui.configitems("paths"):
1931 for name, path in ui.configitems("paths"):
1937 if name == search:
1932 if name == search:
1938 ui.write("%s\n" % path)
1933 ui.write("%s\n" % path)
1939 return
1934 return
1940 ui.warn(_("not found!\n"))
1935 ui.warn(_("not found!\n"))
1941 return 1
1936 return 1
1942 else:
1937 else:
1943 for name, path in ui.configitems("paths"):
1938 for name, path in ui.configitems("paths"):
1944 ui.write("%s = %s\n" % (name, path))
1939 ui.write("%s = %s\n" % (name, path))
1945
1940
1946 def postincoming(ui, repo, modheads, optupdate, checkout):
1941 def postincoming(ui, repo, modheads, optupdate, checkout):
1947 if modheads == 0:
1942 if modheads == 0:
1948 return
1943 return
1949 if optupdate:
1944 if optupdate:
1950 if modheads <= 1 or checkout:
1945 if modheads <= 1 or checkout:
1951 return hg.update(repo, checkout)
1946 return hg.update(repo, checkout)
1952 else:
1947 else:
1953 ui.status(_("not updating, since new heads added\n"))
1948 ui.status(_("not updating, since new heads added\n"))
1954 if modheads > 1:
1949 if modheads > 1:
1955 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1950 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1956 else:
1951 else:
1957 ui.status(_("(run 'hg update' to get a working copy)\n"))
1952 ui.status(_("(run 'hg update' to get a working copy)\n"))
1958
1953
1959 def pull(ui, repo, source="default", **opts):
1954 def pull(ui, repo, source="default", **opts):
1960 """pull changes from the specified source
1955 """pull changes from the specified source
1961
1956
1962 Pull changes from a remote repository to a local one.
1957 Pull changes from a remote repository to a local one.
1963
1958
1964 This finds all changes from the repository at the specified path
1959 This finds all changes from the repository at the specified path
1965 or URL and adds them to the local repository. By default, this
1960 or URL and adds them to the local repository. By default, this
1966 does not update the copy of the project in the working directory.
1961 does not update the copy of the project in the working directory.
1967
1962
1968 Valid URLs are of the form:
1963 Valid URLs are of the form:
1969
1964
1970 local/filesystem/path (or file://local/filesystem/path)
1965 local/filesystem/path (or file://local/filesystem/path)
1971 http://[user@]host[:port]/[path]
1966 http://[user@]host[:port]/[path]
1972 https://[user@]host[:port]/[path]
1967 https://[user@]host[:port]/[path]
1973 ssh://[user@]host[:port]/[path]
1968 ssh://[user@]host[:port]/[path]
1974 static-http://host[:port]/[path]
1969 static-http://host[:port]/[path]
1975
1970
1976 Paths in the local filesystem can either point to Mercurial
1971 Paths in the local filesystem can either point to Mercurial
1977 repositories or to bundle files (as created by 'hg bundle' or
1972 repositories or to bundle files (as created by 'hg bundle' or
1978 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1973 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1979 allows access to a Mercurial repository where you simply use a web
1974 allows access to a Mercurial repository where you simply use a web
1980 server to publish the .hg directory as static content.
1975 server to publish the .hg directory as static content.
1981
1976
1982 An optional identifier after # indicates a particular branch, tag,
1977 An optional identifier after # indicates a particular branch, tag,
1983 or changeset to pull.
1978 or changeset to pull.
1984
1979
1985 Some notes about using SSH with Mercurial:
1980 Some notes about using SSH with Mercurial:
1986 - SSH requires an accessible shell account on the destination machine
1981 - SSH requires an accessible shell account on the destination machine
1987 and a copy of hg in the remote path or specified with as remotecmd.
1982 and a copy of hg in the remote path or specified with as remotecmd.
1988 - path is relative to the remote user's home directory by default.
1983 - path is relative to the remote user's home directory by default.
1989 Use an extra slash at the start of a path to specify an absolute path:
1984 Use an extra slash at the start of a path to specify an absolute path:
1990 ssh://example.com//tmp/repository
1985 ssh://example.com//tmp/repository
1991 - Mercurial doesn't use its own compression via SSH; the right thing
1986 - Mercurial doesn't use its own compression via SSH; the right thing
1992 to do is to configure it in your ~/.ssh/config, e.g.:
1987 to do is to configure it in your ~/.ssh/config, e.g.:
1993 Host *.mylocalnetwork.example.com
1988 Host *.mylocalnetwork.example.com
1994 Compression no
1989 Compression no
1995 Host *
1990 Host *
1996 Compression yes
1991 Compression yes
1997 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1992 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1998 with the --ssh command line option.
1993 with the --ssh command line option.
1999 """
1994 """
2000 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
1995 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
2001 cmdutil.setremoteconfig(ui, opts)
1996 cmdutil.setremoteconfig(ui, opts)
2002
1997
2003 other = hg.repository(ui, source)
1998 other = hg.repository(ui, source)
2004 ui.status(_('pulling from %s\n') % util.hidepassword(source))
1999 ui.status(_('pulling from %s\n') % util.hidepassword(source))
2005 if revs:
2000 if revs:
2006 try:
2001 try:
2007 revs = [other.lookup(rev) for rev in revs]
2002 revs = [other.lookup(rev) for rev in revs]
2008 except repo.NoCapability:
2003 except repo.NoCapability:
2009 error = _("Other repository doesn't support revision lookup, "
2004 error = _("Other repository doesn't support revision lookup, "
2010 "so a rev cannot be specified.")
2005 "so a rev cannot be specified.")
2011 raise util.Abort(error)
2006 raise util.Abort(error)
2012
2007
2013 modheads = repo.pull(other, heads=revs, force=opts['force'])
2008 modheads = repo.pull(other, heads=revs, force=opts['force'])
2014 return postincoming(ui, repo, modheads, opts['update'], checkout)
2009 return postincoming(ui, repo, modheads, opts['update'], checkout)
2015
2010
2016 def push(ui, repo, dest=None, **opts):
2011 def push(ui, repo, dest=None, **opts):
2017 """push changes to the specified destination
2012 """push changes to the specified destination
2018
2013
2019 Push changes from the local repository to the given destination.
2014 Push changes from the local repository to the given destination.
2020
2015
2021 This is the symmetrical operation for pull. It helps to move
2016 This is the symmetrical operation for pull. It helps to move
2022 changes from the current repository to a different one. If the
2017 changes from the current repository to a different one. If the
2023 destination is local this is identical to a pull in that directory
2018 destination is local this is identical to a pull in that directory
2024 from the current one.
2019 from the current one.
2025
2020
2026 By default, push will refuse to run if it detects the result would
2021 By default, push will refuse to run if it detects the result would
2027 increase the number of remote heads. This generally indicates the
2022 increase the number of remote heads. This generally indicates the
2028 the client has forgotten to sync and merge before pushing.
2023 the client has forgotten to sync and merge before pushing.
2029
2024
2030 Valid URLs are of the form:
2025 Valid URLs are of the form:
2031
2026
2032 local/filesystem/path (or file://local/filesystem/path)
2027 local/filesystem/path (or file://local/filesystem/path)
2033 ssh://[user@]host[:port]/[path]
2028 ssh://[user@]host[:port]/[path]
2034 http://[user@]host[:port]/[path]
2029 http://[user@]host[:port]/[path]
2035 https://[user@]host[:port]/[path]
2030 https://[user@]host[:port]/[path]
2036
2031
2037 An optional identifier after # indicates a particular branch, tag,
2032 An optional identifier after # indicates a particular branch, tag,
2038 or changeset to push.
2033 or changeset to push.
2039
2034
2040 Look at the help text for the pull command for important details
2035 Look at the help text for the pull command for important details
2041 about ssh:// URLs.
2036 about ssh:// URLs.
2042
2037
2043 Pushing to http:// and https:// URLs is only possible, if this
2038 Pushing to http:// and https:// URLs is only possible, if this
2044 feature is explicitly enabled on the remote Mercurial server.
2039 feature is explicitly enabled on the remote Mercurial server.
2045 """
2040 """
2046 dest, revs, checkout = hg.parseurl(
2041 dest, revs, checkout = hg.parseurl(
2047 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
2042 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
2048 cmdutil.setremoteconfig(ui, opts)
2043 cmdutil.setremoteconfig(ui, opts)
2049
2044
2050 other = hg.repository(ui, dest)
2045 other = hg.repository(ui, dest)
2051 ui.status('pushing to %s\n' % util.hidepassword(dest))
2046 ui.status('pushing to %s\n' % util.hidepassword(dest))
2052 if revs:
2047 if revs:
2053 revs = [repo.lookup(rev) for rev in revs]
2048 revs = [repo.lookup(rev) for rev in revs]
2054 r = repo.push(other, opts['force'], revs=revs)
2049 r = repo.push(other, opts['force'], revs=revs)
2055 return r == 0
2050 return r == 0
2056
2051
2057 def rawcommit(ui, repo, *pats, **opts):
2052 def rawcommit(ui, repo, *pats, **opts):
2058 """raw commit interface (DEPRECATED)
2053 """raw commit interface (DEPRECATED)
2059
2054
2060 (DEPRECATED)
2055 (DEPRECATED)
2061 Lowlevel commit, for use in helper scripts.
2056 Lowlevel commit, for use in helper scripts.
2062
2057
2063 This command is not intended to be used by normal users, as it is
2058 This command is not intended to be used by normal users, as it is
2064 primarily useful for importing from other SCMs.
2059 primarily useful for importing from other SCMs.
2065
2060
2066 This command is now deprecated and will be removed in a future
2061 This command is now deprecated and will be removed in a future
2067 release, please use debugsetparents and commit instead.
2062 release, please use debugsetparents and commit instead.
2068 """
2063 """
2069
2064
2070 ui.warn(_("(the rawcommit command is deprecated)\n"))
2065 ui.warn(_("(the rawcommit command is deprecated)\n"))
2071
2066
2072 message = cmdutil.logmessage(opts)
2067 message = cmdutil.logmessage(opts)
2073
2068
2074 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
2069 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
2075 if opts['files']:
2070 if opts['files']:
2076 files += open(opts['files']).read().splitlines()
2071 files += open(opts['files']).read().splitlines()
2077
2072
2078 parents = [repo.lookup(p) for p in opts['parent']]
2073 parents = [repo.lookup(p) for p in opts['parent']]
2079
2074
2080 try:
2075 try:
2081 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2076 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2082 except ValueError, inst:
2077 except ValueError, inst:
2083 raise util.Abort(str(inst))
2078 raise util.Abort(str(inst))
2084
2079
2085 def recover(ui, repo):
2080 def recover(ui, repo):
2086 """roll back an interrupted transaction
2081 """roll back an interrupted transaction
2087
2082
2088 Recover from an interrupted commit or pull.
2083 Recover from an interrupted commit or pull.
2089
2084
2090 This command tries to fix the repository status after an interrupted
2085 This command tries to fix the repository status after an interrupted
2091 operation. It should only be necessary when Mercurial suggests it.
2086 operation. It should only be necessary when Mercurial suggests it.
2092 """
2087 """
2093 if repo.recover():
2088 if repo.recover():
2094 return hg.verify(repo)
2089 return hg.verify(repo)
2095 return 1
2090 return 1
2096
2091
2097 def remove(ui, repo, *pats, **opts):
2092 def remove(ui, repo, *pats, **opts):
2098 """remove the specified files on the next commit
2093 """remove the specified files on the next commit
2099
2094
2100 Schedule the indicated files for removal from the repository.
2095 Schedule the indicated files for removal from the repository.
2101
2096
2102 This only removes files from the current branch, not from the
2097 This only removes files from the current branch, not from the
2103 entire project history. If the files still exist in the working
2098 entire project history. If the files still exist in the working
2104 directory, they will be deleted from it. If invoked with --after,
2099 directory, they will be deleted from it. If invoked with --after,
2105 files are marked as removed, but not actually unlinked unless --force
2100 files are marked as removed, but not actually unlinked unless --force
2106 is also given. Without exact file names, --after will only mark
2101 is also given. Without exact file names, --after will only mark
2107 files as removed if they are no longer in the working directory.
2102 files as removed if they are no longer in the working directory.
2108
2103
2109 This command schedules the files to be removed at the next commit.
2104 This command schedules the files to be removed at the next commit.
2110 To undo a remove before that, see hg revert.
2105 To undo a remove before that, see hg revert.
2111
2106
2112 Modified files and added files are not removed by default. To
2107 Modified files and added files are not removed by default. To
2113 remove them, use the -f/--force option.
2108 remove them, use the -f/--force option.
2114 """
2109 """
2115 if not opts['after'] and not pats:
2110 if not opts['after'] and not pats:
2116 raise util.Abort(_('no files specified'))
2111 raise util.Abort(_('no files specified'))
2117 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2112 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2118 exact = dict.fromkeys(files)
2113 exact = dict.fromkeys(files)
2119 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2114 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2120 modified, added, removed, deleted, unknown = mardu
2115 modified, added, removed, deleted, unknown = mardu
2121 remove, forget = [], []
2116 remove, forget = [], []
2122 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2117 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2123 reason = None
2118 reason = None
2124 if abs in modified and not opts['force']:
2119 if abs in modified and not opts['force']:
2125 reason = _('is modified (use -f to force removal)')
2120 reason = _('is modified (use -f to force removal)')
2126 elif abs in added:
2121 elif abs in added:
2127 if opts['force']:
2122 if opts['force']:
2128 forget.append(abs)
2123 forget.append(abs)
2129 continue
2124 continue
2130 reason = _('has been marked for add (use -f to force removal)')
2125 reason = _('has been marked for add (use -f to force removal)')
2131 exact = 1 # force the message
2126 exact = 1 # force the message
2132 elif abs not in repo.dirstate:
2127 elif abs not in repo.dirstate:
2133 reason = _('is not managed')
2128 reason = _('is not managed')
2134 elif opts['after'] and not exact and abs not in deleted:
2129 elif opts['after'] and not exact and abs not in deleted:
2135 continue
2130 continue
2136 elif abs in removed:
2131 elif abs in removed:
2137 continue
2132 continue
2138 if reason:
2133 if reason:
2139 if exact:
2134 if exact:
2140 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2135 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2141 else:
2136 else:
2142 if ui.verbose or not exact:
2137 if ui.verbose or not exact:
2143 ui.status(_('removing %s\n') % rel)
2138 ui.status(_('removing %s\n') % rel)
2144 remove.append(abs)
2139 remove.append(abs)
2145 repo.forget(forget)
2140 repo.forget(forget)
2146 repo.remove(remove, unlink=opts['force'] or not opts['after'])
2141 repo.remove(remove, unlink=opts['force'] or not opts['after'])
2147
2142
2148 def rename(ui, repo, *pats, **opts):
2143 def rename(ui, repo, *pats, **opts):
2149 """rename files; equivalent of copy + remove
2144 """rename files; equivalent of copy + remove
2150
2145
2151 Mark dest as copies of sources; mark sources for deletion. If
2146 Mark dest as copies of sources; mark sources for deletion. If
2152 dest is a directory, copies are put in that directory. If dest is
2147 dest is a directory, copies are put in that directory. If dest is
2153 a file, there can only be one source.
2148 a file, there can only be one source.
2154
2149
2155 By default, this command copies the contents of files as they
2150 By default, this command copies the contents of files as they
2156 stand in the working directory. If invoked with --after, the
2151 stand in the working directory. If invoked with --after, the
2157 operation is recorded, but no copying is performed.
2152 operation is recorded, but no copying is performed.
2158
2153
2159 This command takes effect in the next commit. To undo a rename
2154 This command takes effect in the next commit. To undo a rename
2160 before that, see hg revert.
2155 before that, see hg revert.
2161 """
2156 """
2162 wlock = repo.wlock(False)
2157 wlock = repo.wlock(False)
2163 try:
2158 try:
2164 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2159 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2165 finally:
2160 finally:
2166 del wlock
2161 del wlock
2167
2162
2168 def revert(ui, repo, *pats, **opts):
2163 def revert(ui, repo, *pats, **opts):
2169 """restore individual files or dirs to an earlier state
2164 """restore individual files or dirs to an earlier state
2170
2165
2171 (use update -r to check out earlier revisions, revert does not
2166 (use update -r to check out earlier revisions, revert does not
2172 change the working dir parents)
2167 change the working dir parents)
2173
2168
2174 With no revision specified, revert the named files or directories
2169 With no revision specified, revert the named files or directories
2175 to the contents they had in the parent of the working directory.
2170 to the contents they had in the parent of the working directory.
2176 This restores the contents of the affected files to an unmodified
2171 This restores the contents of the affected files to an unmodified
2177 state and unschedules adds, removes, copies, and renames. If the
2172 state and unschedules adds, removes, copies, and renames. If the
2178 working directory has two parents, you must explicitly specify the
2173 working directory has two parents, you must explicitly specify the
2179 revision to revert to.
2174 revision to revert to.
2180
2175
2181 Using the -r option, revert the given files or directories to their
2176 Using the -r option, revert the given files or directories to their
2182 contents as of a specific revision. This can be helpful to "roll
2177 contents as of a specific revision. This can be helpful to "roll
2183 back" some or all of an earlier change.
2178 back" some or all of an earlier change.
2184
2179
2185 Revert modifies the working directory. It does not commit any
2180 Revert modifies the working directory. It does not commit any
2186 changes, or change the parent of the working directory. If you
2181 changes, or change the parent of the working directory. If you
2187 revert to a revision other than the parent of the working
2182 revert to a revision other than the parent of the working
2188 directory, the reverted files will thus appear modified
2183 directory, the reverted files will thus appear modified
2189 afterwards.
2184 afterwards.
2190
2185
2191 If a file has been deleted, it is restored. If the executable
2186 If a file has been deleted, it is restored. If the executable
2192 mode of a file was changed, it is reset.
2187 mode of a file was changed, it is reset.
2193
2188
2194 If names are given, all files matching the names are reverted.
2189 If names are given, all files matching the names are reverted.
2195
2190
2196 If no arguments are given, no files are reverted.
2191 If no arguments are given, no files are reverted.
2197
2192
2198 Modified files are saved with a .orig suffix before reverting.
2193 Modified files are saved with a .orig suffix before reverting.
2199 To disable these backups, use --no-backup.
2194 To disable these backups, use --no-backup.
2200 """
2195 """
2201
2196
2202 if opts["date"]:
2197 if opts["date"]:
2203 if opts["rev"]:
2198 if opts["rev"]:
2204 raise util.Abort(_("you can't specify a revision and a date"))
2199 raise util.Abort(_("you can't specify a revision and a date"))
2205 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2200 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2206
2201
2207 if not pats and not opts['all']:
2202 if not pats and not opts['all']:
2208 raise util.Abort(_('no files or directories specified; '
2203 raise util.Abort(_('no files or directories specified; '
2209 'use --all to revert the whole repo'))
2204 'use --all to revert the whole repo'))
2210
2205
2211 parent, p2 = repo.dirstate.parents()
2206 parent, p2 = repo.dirstate.parents()
2212 if not opts['rev'] and p2 != nullid:
2207 if not opts['rev'] and p2 != nullid:
2213 raise util.Abort(_('uncommitted merge - please provide a '
2208 raise util.Abort(_('uncommitted merge - please provide a '
2214 'specific revision'))
2209 'specific revision'))
2215 ctx = repo.changectx(opts['rev'])
2210 ctx = repo.changectx(opts['rev'])
2216 node = ctx.node()
2211 node = ctx.node()
2217 mf = ctx.manifest()
2212 mf = ctx.manifest()
2218 if node == parent:
2213 if node == parent:
2219 pmf = mf
2214 pmf = mf
2220 else:
2215 else:
2221 pmf = None
2216 pmf = None
2222
2217
2223 # need all matching names in dirstate and manifest of target rev,
2218 # need all matching names in dirstate and manifest of target rev,
2224 # so have to walk both. do not print errors if files exist in one
2219 # so have to walk both. do not print errors if files exist in one
2225 # but not other.
2220 # but not other.
2226
2221
2227 names = {}
2222 names = {}
2228 target_only = {}
2223 target_only = {}
2229
2224
2230 wlock = repo.wlock()
2225 wlock = repo.wlock()
2231 try:
2226 try:
2232 # walk dirstate.
2227 # walk dirstate.
2233 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2228 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2234 badmatch=mf.has_key):
2229 badmatch=mf.has_key):
2235 names[abs] = (rel, exact)
2230 names[abs] = (rel, exact)
2236 if src == 'b':
2231 if src == 'b':
2237 target_only[abs] = True
2232 target_only[abs] = True
2238
2233
2239 # walk target manifest.
2234 # walk target manifest.
2240
2235
2241 def badmatch(path):
2236 def badmatch(path):
2242 if path in names:
2237 if path in names:
2243 return True
2238 return True
2244 path_ = path + '/'
2239 path_ = path + '/'
2245 for f in names:
2240 for f in names:
2246 if f.startswith(path_):
2241 if f.startswith(path_):
2247 return True
2242 return True
2248 return False
2243 return False
2249
2244
2250 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2245 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2251 badmatch=badmatch):
2246 badmatch=badmatch):
2252 if abs in names or src == 'b':
2247 if abs in names or src == 'b':
2253 continue
2248 continue
2254 names[abs] = (rel, exact)
2249 names[abs] = (rel, exact)
2255 target_only[abs] = True
2250 target_only[abs] = True
2256
2251
2257 changes = repo.status(match=names.has_key)[:5]
2252 changes = repo.status(match=names.has_key)[:5]
2258 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2253 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2259
2254
2260 # if f is a rename, also revert the source
2255 # if f is a rename, also revert the source
2261 cwd = repo.getcwd()
2256 cwd = repo.getcwd()
2262 for f in added:
2257 for f in added:
2263 src = repo.dirstate.copied(f)
2258 src = repo.dirstate.copied(f)
2264 if src and src not in names and repo.dirstate[src] == 'r':
2259 if src and src not in names and repo.dirstate[src] == 'r':
2265 removed[src] = None
2260 removed[src] = None
2266 names[src] = (repo.pathto(src, cwd), True)
2261 names[src] = (repo.pathto(src, cwd), True)
2267
2262
2268 revert = ([], _('reverting %s\n'))
2263 revert = ([], _('reverting %s\n'))
2269 add = ([], _('adding %s\n'))
2264 add = ([], _('adding %s\n'))
2270 remove = ([], _('removing %s\n'))
2265 remove = ([], _('removing %s\n'))
2271 forget = ([], _('forgetting %s\n'))
2266 forget = ([], _('forgetting %s\n'))
2272 undelete = ([], _('undeleting %s\n'))
2267 undelete = ([], _('undeleting %s\n'))
2273 update = {}
2268 update = {}
2274
2269
2275 disptable = (
2270 disptable = (
2276 # dispatch table:
2271 # dispatch table:
2277 # file state
2272 # file state
2278 # action if in target manifest
2273 # action if in target manifest
2279 # action if not in target manifest
2274 # action if not in target manifest
2280 # make backup if in target manifest
2275 # make backup if in target manifest
2281 # make backup if not in target manifest
2276 # make backup if not in target manifest
2282 (modified, revert, remove, True, True),
2277 (modified, revert, remove, True, True),
2283 (added, revert, forget, True, False),
2278 (added, revert, forget, True, False),
2284 (removed, undelete, None, False, False),
2279 (removed, undelete, None, False, False),
2285 (deleted, revert, remove, False, False),
2280 (deleted, revert, remove, False, False),
2286 (unknown, add, None, True, False),
2281 (unknown, add, None, True, False),
2287 (target_only, add, None, False, False),
2282 (target_only, add, None, False, False),
2288 )
2283 )
2289
2284
2290 entries = names.items()
2285 entries = names.items()
2291 entries.sort()
2286 entries.sort()
2292
2287
2293 for abs, (rel, exact) in entries:
2288 for abs, (rel, exact) in entries:
2294 mfentry = mf.get(abs)
2289 mfentry = mf.get(abs)
2295 target = repo.wjoin(abs)
2290 target = repo.wjoin(abs)
2296 def handle(xlist, dobackup):
2291 def handle(xlist, dobackup):
2297 xlist[0].append(abs)
2292 xlist[0].append(abs)
2298 update[abs] = 1
2293 update[abs] = 1
2299 if dobackup and not opts['no_backup'] and util.lexists(target):
2294 if dobackup and not opts['no_backup'] and util.lexists(target):
2300 bakname = "%s.orig" % rel
2295 bakname = "%s.orig" % rel
2301 ui.note(_('saving current version of %s as %s\n') %
2296 ui.note(_('saving current version of %s as %s\n') %
2302 (rel, bakname))
2297 (rel, bakname))
2303 if not opts.get('dry_run'):
2298 if not opts.get('dry_run'):
2304 util.copyfile(target, bakname)
2299 util.copyfile(target, bakname)
2305 if ui.verbose or not exact:
2300 if ui.verbose or not exact:
2306 ui.status(xlist[1] % rel)
2301 ui.status(xlist[1] % rel)
2307 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2302 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2308 if abs not in table: continue
2303 if abs not in table: continue
2309 # file has changed in dirstate
2304 # file has changed in dirstate
2310 if mfentry:
2305 if mfentry:
2311 handle(hitlist, backuphit)
2306 handle(hitlist, backuphit)
2312 elif misslist is not None:
2307 elif misslist is not None:
2313 handle(misslist, backupmiss)
2308 handle(misslist, backupmiss)
2314 else:
2309 else:
2315 if exact: ui.warn(_('file not managed: %s\n') % rel)
2310 if exact: ui.warn(_('file not managed: %s\n') % rel)
2316 break
2311 break
2317 else:
2312 else:
2318 # file has not changed in dirstate
2313 # file has not changed in dirstate
2319 if node == parent:
2314 if node == parent:
2320 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2315 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2321 continue
2316 continue
2322 if pmf is None:
2317 if pmf is None:
2323 # only need parent manifest in this unlikely case,
2318 # only need parent manifest in this unlikely case,
2324 # so do not read by default
2319 # so do not read by default
2325 pmf = repo.changectx(parent).manifest()
2320 pmf = repo.changectx(parent).manifest()
2326 if abs in pmf:
2321 if abs in pmf:
2327 if mfentry:
2322 if mfentry:
2328 # if version of file is same in parent and target
2323 # if version of file is same in parent and target
2329 # manifests, do nothing
2324 # manifests, do nothing
2330 if pmf[abs] != mfentry:
2325 if pmf[abs] != mfentry:
2331 handle(revert, False)
2326 handle(revert, False)
2332 else:
2327 else:
2333 handle(remove, False)
2328 handle(remove, False)
2334
2329
2335 if not opts.get('dry_run'):
2330 if not opts.get('dry_run'):
2336 for f in forget[0]:
2331 for f in forget[0]:
2337 repo.dirstate.forget(f)
2332 repo.dirstate.forget(f)
2338 r = hg.revert(repo, node, update.has_key)
2333 r = hg.revert(repo, node, update.has_key)
2339 for f in add[0]:
2334 for f in add[0]:
2340 repo.dirstate.add(f)
2335 repo.dirstate.add(f)
2341 for f in undelete[0]:
2336 for f in undelete[0]:
2342 repo.dirstate.normal(f)
2337 repo.dirstate.normal(f)
2343 for f in remove[0]:
2338 for f in remove[0]:
2344 repo.dirstate.remove(f)
2339 repo.dirstate.remove(f)
2345 return r
2340 return r
2346 finally:
2341 finally:
2347 del wlock
2342 del wlock
2348
2343
2349 def rollback(ui, repo):
2344 def rollback(ui, repo):
2350 """roll back the last transaction
2345 """roll back the last transaction
2351
2346
2352 This command should be used with care. There is only one level of
2347 This command should be used with care. There is only one level of
2353 rollback, and there is no way to undo a rollback. It will also
2348 rollback, and there is no way to undo a rollback. It will also
2354 restore the dirstate at the time of the last transaction, losing
2349 restore the dirstate at the time of the last transaction, losing
2355 any dirstate changes since that time.
2350 any dirstate changes since that time.
2356
2351
2357 Transactions are used to encapsulate the effects of all commands
2352 Transactions are used to encapsulate the effects of all commands
2358 that create new changesets or propagate existing changesets into a
2353 that create new changesets or propagate existing changesets into a
2359 repository. For example, the following commands are transactional,
2354 repository. For example, the following commands are transactional,
2360 and their effects can be rolled back:
2355 and their effects can be rolled back:
2361
2356
2362 commit
2357 commit
2363 import
2358 import
2364 pull
2359 pull
2365 push (with this repository as destination)
2360 push (with this repository as destination)
2366 unbundle
2361 unbundle
2367
2362
2368 This command is not intended for use on public repositories. Once
2363 This command is not intended for use on public repositories. Once
2369 changes are visible for pull by other users, rolling a transaction
2364 changes are visible for pull by other users, rolling a transaction
2370 back locally is ineffective (someone else may already have pulled
2365 back locally is ineffective (someone else may already have pulled
2371 the changes). Furthermore, a race is possible with readers of the
2366 the changes). Furthermore, a race is possible with readers of the
2372 repository; for example an in-progress pull from the repository
2367 repository; for example an in-progress pull from the repository
2373 may fail if a rollback is performed.
2368 may fail if a rollback is performed.
2374 """
2369 """
2375 repo.rollback()
2370 repo.rollback()
2376
2371
2377 def root(ui, repo):
2372 def root(ui, repo):
2378 """print the root (top) of the current working dir
2373 """print the root (top) of the current working dir
2379
2374
2380 Print the root directory of the current repository.
2375 Print the root directory of the current repository.
2381 """
2376 """
2382 ui.write(repo.root + "\n")
2377 ui.write(repo.root + "\n")
2383
2378
2384 def serve(ui, repo, **opts):
2379 def serve(ui, repo, **opts):
2385 """export the repository via HTTP
2380 """export the repository via HTTP
2386
2381
2387 Start a local HTTP repository browser and pull server.
2382 Start a local HTTP repository browser and pull server.
2388
2383
2389 By default, the server logs accesses to stdout and errors to
2384 By default, the server logs accesses to stdout and errors to
2390 stderr. Use the "-A" and "-E" options to log to files.
2385 stderr. Use the "-A" and "-E" options to log to files.
2391 """
2386 """
2392
2387
2393 if opts["stdio"]:
2388 if opts["stdio"]:
2394 if repo is None:
2389 if repo is None:
2395 raise hg.RepoError(_("There is no Mercurial repository here"
2390 raise hg.RepoError(_("There is no Mercurial repository here"
2396 " (.hg not found)"))
2391 " (.hg not found)"))
2397 s = sshserver.sshserver(ui, repo)
2392 s = sshserver.sshserver(ui, repo)
2398 s.serve_forever()
2393 s.serve_forever()
2399
2394
2400 parentui = ui.parentui or ui
2395 parentui = ui.parentui or ui
2401 optlist = ("name templates style address port ipv6"
2396 optlist = ("name templates style address port ipv6"
2402 " accesslog errorlog webdir_conf certificate")
2397 " accesslog errorlog webdir_conf certificate")
2403 for o in optlist.split():
2398 for o in optlist.split():
2404 if opts[o]:
2399 if opts[o]:
2405 parentui.setconfig("web", o, str(opts[o]))
2400 parentui.setconfig("web", o, str(opts[o]))
2406 if (repo is not None) and (repo.ui != parentui):
2401 if (repo is not None) and (repo.ui != parentui):
2407 repo.ui.setconfig("web", o, str(opts[o]))
2402 repo.ui.setconfig("web", o, str(opts[o]))
2408
2403
2409 if repo is None and not ui.config("web", "webdir_conf"):
2404 if repo is None and not ui.config("web", "webdir_conf"):
2410 raise hg.RepoError(_("There is no Mercurial repository here"
2405 raise hg.RepoError(_("There is no Mercurial repository here"
2411 " (.hg not found)"))
2406 " (.hg not found)"))
2412
2407
2413 class service:
2408 class service:
2414 def init(self):
2409 def init(self):
2415 util.set_signal_handler()
2410 util.set_signal_handler()
2416 try:
2411 try:
2417 self.httpd = hgweb.server.create_server(parentui, repo)
2412 self.httpd = hgweb.server.create_server(parentui, repo)
2418 except socket.error, inst:
2413 except socket.error, inst:
2419 raise util.Abort(_('cannot start server: ') + inst.args[1])
2414 raise util.Abort(_('cannot start server: ') + inst.args[1])
2420
2415
2421 if not ui.verbose: return
2416 if not ui.verbose: return
2422
2417
2423 if self.httpd.port != 80:
2418 if self.httpd.port != 80:
2424 ui.status(_('listening at http://%s:%d/\n') %
2419 ui.status(_('listening at http://%s:%d/\n') %
2425 (self.httpd.addr, self.httpd.port))
2420 (self.httpd.addr, self.httpd.port))
2426 else:
2421 else:
2427 ui.status(_('listening at http://%s/\n') % self.httpd.addr)
2422 ui.status(_('listening at http://%s/\n') % self.httpd.addr)
2428
2423
2429 def run(self):
2424 def run(self):
2430 self.httpd.serve_forever()
2425 self.httpd.serve_forever()
2431
2426
2432 service = service()
2427 service = service()
2433
2428
2434 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2429 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2435
2430
2436 def status(ui, repo, *pats, **opts):
2431 def status(ui, repo, *pats, **opts):
2437 """show changed files in the working directory
2432 """show changed files in the working directory
2438
2433
2439 Show status of files in the repository. If names are given, only
2434 Show status of files in the repository. If names are given, only
2440 files that match are shown. Files that are clean or ignored, are
2435 files that match are shown. Files that are clean or ignored, are
2441 not listed unless -c (clean), -i (ignored) or -A is given.
2436 not listed unless -c (clean), -i (ignored) or -A is given.
2442
2437
2443 NOTE: status may appear to disagree with diff if permissions have
2438 NOTE: status may appear to disagree with diff if permissions have
2444 changed or a merge has occurred. The standard diff format does not
2439 changed or a merge has occurred. The standard diff format does not
2445 report permission changes and diff only reports changes relative
2440 report permission changes and diff only reports changes relative
2446 to one merge parent.
2441 to one merge parent.
2447
2442
2448 If one revision is given, it is used as the base revision.
2443 If one revision is given, it is used as the base revision.
2449 If two revisions are given, the difference between them is shown.
2444 If two revisions are given, the difference between them is shown.
2450
2445
2451 The codes used to show the status of files are:
2446 The codes used to show the status of files are:
2452 M = modified
2447 M = modified
2453 A = added
2448 A = added
2454 R = removed
2449 R = removed
2455 C = clean
2450 C = clean
2456 ! = deleted, but still tracked
2451 ! = deleted, but still tracked
2457 ? = not tracked
2452 ? = not tracked
2458 I = ignored (not shown by default)
2453 I = ignored (not shown by default)
2459 = the previous added file was copied from here
2454 = the previous added file was copied from here
2460 """
2455 """
2461
2456
2462 all = opts['all']
2457 all = opts['all']
2463 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2458 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2464
2459
2465 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2460 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2466 cwd = (pats and repo.getcwd()) or ''
2461 cwd = (pats and repo.getcwd()) or ''
2467 modified, added, removed, deleted, unknown, ignored, clean = [
2462 modified, added, removed, deleted, unknown, ignored, clean = [
2468 n for n in repo.status(node1=node1, node2=node2, files=files,
2463 n for n in repo.status(node1=node1, node2=node2, files=files,
2469 match=matchfn,
2464 match=matchfn,
2470 list_ignored=all or opts['ignored'],
2465 list_ignored=all or opts['ignored'],
2471 list_clean=all or opts['clean'])]
2466 list_clean=all or opts['clean'])]
2472
2467
2473 changetypes = (('modified', 'M', modified),
2468 changetypes = (('modified', 'M', modified),
2474 ('added', 'A', added),
2469 ('added', 'A', added),
2475 ('removed', 'R', removed),
2470 ('removed', 'R', removed),
2476 ('deleted', '!', deleted),
2471 ('deleted', '!', deleted),
2477 ('unknown', '?', unknown),
2472 ('unknown', '?', unknown),
2478 ('ignored', 'I', ignored))
2473 ('ignored', 'I', ignored))
2479
2474
2480 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2475 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2481
2476
2482 end = opts['print0'] and '\0' or '\n'
2477 end = opts['print0'] and '\0' or '\n'
2483
2478
2484 for opt, char, changes in ([ct for ct in explicit_changetypes
2479 for opt, char, changes in ([ct for ct in explicit_changetypes
2485 if all or opts[ct[0]]]
2480 if all or opts[ct[0]]]
2486 or changetypes):
2481 or changetypes):
2487 if opts['no_status']:
2482 if opts['no_status']:
2488 format = "%%s%s" % end
2483 format = "%%s%s" % end
2489 else:
2484 else:
2490 format = "%s %%s%s" % (char, end)
2485 format = "%s %%s%s" % (char, end)
2491
2486
2492 for f in changes:
2487 for f in changes:
2493 ui.write(format % repo.pathto(f, cwd))
2488 ui.write(format % repo.pathto(f, cwd))
2494 if ((all or opts.get('copies')) and not opts.get('no_status')):
2489 if ((all or opts.get('copies')) and not opts.get('no_status')):
2495 copied = repo.dirstate.copied(f)
2490 copied = repo.dirstate.copied(f)
2496 if copied:
2491 if copied:
2497 ui.write(' %s%s' % (repo.pathto(copied, cwd), end))
2492 ui.write(' %s%s' % (repo.pathto(copied, cwd), end))
2498
2493
2499 def tag(ui, repo, name, rev_=None, **opts):
2494 def tag(ui, repo, name, rev_=None, **opts):
2500 """add a tag for the current or given revision
2495 """add a tag for the current or given revision
2501
2496
2502 Name a particular revision using <name>.
2497 Name a particular revision using <name>.
2503
2498
2504 Tags are used to name particular revisions of the repository and are
2499 Tags are used to name particular revisions of the repository and are
2505 very useful to compare different revision, to go back to significant
2500 very useful to compare different revision, to go back to significant
2506 earlier versions or to mark branch points as releases, etc.
2501 earlier versions or to mark branch points as releases, etc.
2507
2502
2508 If no revision is given, the parent of the working directory is used,
2503 If no revision is given, the parent of the working directory is used,
2509 or tip if no revision is checked out.
2504 or tip if no revision is checked out.
2510
2505
2511 To facilitate version control, distribution, and merging of tags,
2506 To facilitate version control, distribution, and merging of tags,
2512 they are stored as a file named ".hgtags" which is managed
2507 they are stored as a file named ".hgtags" which is managed
2513 similarly to other project files and can be hand-edited if
2508 similarly to other project files and can be hand-edited if
2514 necessary. The file '.hg/localtags' is used for local tags (not
2509 necessary. The file '.hg/localtags' is used for local tags (not
2515 shared among repositories).
2510 shared among repositories).
2516 """
2511 """
2517 if name in ['tip', '.', 'null']:
2512 if name in ['tip', '.', 'null']:
2518 raise util.Abort(_("the name '%s' is reserved") % name)
2513 raise util.Abort(_("the name '%s' is reserved") % name)
2519 if rev_ is not None:
2514 if rev_ is not None:
2520 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2515 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2521 "please use 'hg tag [-r REV] NAME' instead\n"))
2516 "please use 'hg tag [-r REV] NAME' instead\n"))
2522 if opts['rev']:
2517 if opts['rev']:
2523 raise util.Abort(_("use only one form to specify the revision"))
2518 raise util.Abort(_("use only one form to specify the revision"))
2524 if opts['rev'] and opts['remove']:
2519 if opts['rev'] and opts['remove']:
2525 raise util.Abort(_("--rev and --remove are incompatible"))
2520 raise util.Abort(_("--rev and --remove are incompatible"))
2526 if opts['rev']:
2521 if opts['rev']:
2527 rev_ = opts['rev']
2522 rev_ = opts['rev']
2528 message = opts['message']
2523 message = opts['message']
2529 if opts['remove']:
2524 if opts['remove']:
2530 tagtype = repo.tagtype(name)
2525 tagtype = repo.tagtype(name)
2531
2526
2532 if not tagtype:
2527 if not tagtype:
2533 raise util.Abort(_('tag %s does not exist') % name)
2528 raise util.Abort(_('tag %s does not exist') % name)
2534 if opts['local'] and tagtype == 'global':
2529 if opts['local'] and tagtype == 'global':
2535 raise util.Abort(_('%s tag is global') % name)
2530 raise util.Abort(_('%s tag is global') % name)
2536 if not opts['local'] and tagtype == 'local':
2531 if not opts['local'] and tagtype == 'local':
2537 raise util.Abort(_('%s tag is local') % name)
2532 raise util.Abort(_('%s tag is local') % name)
2538
2533
2539 rev_ = nullid
2534 rev_ = nullid
2540 if not message:
2535 if not message:
2541 message = _('Removed tag %s') % name
2536 message = _('Removed tag %s') % name
2542 elif name in repo.tags() and not opts['force']:
2537 elif name in repo.tags() and not opts['force']:
2543 raise util.Abort(_('a tag named %s already exists (use -f to force)')
2538 raise util.Abort(_('a tag named %s already exists (use -f to force)')
2544 % name)
2539 % name)
2545 if not rev_ and repo.dirstate.parents()[1] != nullid:
2540 if not rev_ and repo.dirstate.parents()[1] != nullid:
2546 raise util.Abort(_('uncommitted merge - please provide a '
2541 raise util.Abort(_('uncommitted merge - please provide a '
2547 'specific revision'))
2542 'specific revision'))
2548 r = repo.changectx(rev_).node()
2543 r = repo.changectx(rev_).node()
2549
2544
2550 if not message:
2545 if not message:
2551 message = _('Added tag %s for changeset %s') % (name, short(r))
2546 message = _('Added tag %s for changeset %s') % (name, short(r))
2552
2547
2553 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2548 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2554
2549
2555 def tags(ui, repo):
2550 def tags(ui, repo):
2556 """list repository tags
2551 """list repository tags
2557
2552
2558 List the repository tags.
2553 List the repository tags.
2559
2554
2560 This lists both regular and local tags. When the -v/--verbose switch
2555 This lists both regular and local tags. When the -v/--verbose switch
2561 is used, a third column "local" is printed for local tags.
2556 is used, a third column "local" is printed for local tags.
2562 """
2557 """
2563
2558
2564 l = repo.tagslist()
2559 l = repo.tagslist()
2565 l.reverse()
2560 l.reverse()
2566 hexfunc = ui.debugflag and hex or short
2561 hexfunc = ui.debugflag and hex or short
2567 tagtype = ""
2562 tagtype = ""
2568
2563
2569 for t, n in l:
2564 for t, n in l:
2570 if ui.quiet:
2565 if ui.quiet:
2571 ui.write("%s\n" % t)
2566 ui.write("%s\n" % t)
2572 continue
2567 continue
2573
2568
2574 try:
2569 try:
2575 hn = hexfunc(n)
2570 hn = hexfunc(n)
2576 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2571 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2577 except revlog.LookupError:
2572 except revlog.LookupError:
2578 r = " ?:%s" % hn
2573 r = " ?:%s" % hn
2579 else:
2574 else:
2580 spaces = " " * (30 - util.locallen(t))
2575 spaces = " " * (30 - util.locallen(t))
2581 if ui.verbose:
2576 if ui.verbose:
2582 if repo.tagtype(t) == 'local':
2577 if repo.tagtype(t) == 'local':
2583 tagtype = " local"
2578 tagtype = " local"
2584 else:
2579 else:
2585 tagtype = ""
2580 tagtype = ""
2586 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2581 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2587
2582
2588 def tip(ui, repo, **opts):
2583 def tip(ui, repo, **opts):
2589 """show the tip revision
2584 """show the tip revision
2590
2585
2591 Show the tip revision.
2586 Show the tip revision.
2592 """
2587 """
2593 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2588 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2594
2589
2595 def unbundle(ui, repo, fname1, *fnames, **opts):
2590 def unbundle(ui, repo, fname1, *fnames, **opts):
2596 """apply one or more changegroup files
2591 """apply one or more changegroup files
2597
2592
2598 Apply one or more compressed changegroup files generated by the
2593 Apply one or more compressed changegroup files generated by the
2599 bundle command.
2594 bundle command.
2600 """
2595 """
2601 fnames = (fname1,) + fnames
2596 fnames = (fname1,) + fnames
2602 for fname in fnames:
2597 for fname in fnames:
2603 if os.path.exists(fname):
2598 if os.path.exists(fname):
2604 f = open(fname, "rb")
2599 f = open(fname, "rb")
2605 else:
2600 else:
2606 f = urllib.urlopen(fname)
2601 f = urllib.urlopen(fname)
2607 gen = changegroup.readbundle(f, fname)
2602 gen = changegroup.readbundle(f, fname)
2608 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2603 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2609
2604
2610 return postincoming(ui, repo, modheads, opts['update'], None)
2605 return postincoming(ui, repo, modheads, opts['update'], None)
2611
2606
2612 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2607 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2613 """update working directory
2608 """update working directory
2614
2609
2615 Update the working directory to the specified revision, or the
2610 Update the working directory to the specified revision, or the
2616 tip of the current branch if none is specified.
2611 tip of the current branch if none is specified.
2617
2612
2618 If there are no outstanding changes in the working directory and
2613 If there are no outstanding changes in the working directory and
2619 there is a linear relationship between the current version and the
2614 there is a linear relationship between the current version and the
2620 requested version, the result is the requested version.
2615 requested version, the result is the requested version.
2621
2616
2622 To merge the working directory with another revision, use the
2617 To merge the working directory with another revision, use the
2623 merge command.
2618 merge command.
2624
2619
2625 By default, update will refuse to run if doing so would require
2620 By default, update will refuse to run if doing so would require
2626 discarding local changes.
2621 discarding local changes.
2627 """
2622 """
2628 if rev and node:
2623 if rev and node:
2629 raise util.Abort(_("please specify just one revision"))
2624 raise util.Abort(_("please specify just one revision"))
2630
2625
2631 if not rev:
2626 if not rev:
2632 rev = node
2627 rev = node
2633
2628
2634 if date:
2629 if date:
2635 if rev:
2630 if rev:
2636 raise util.Abort(_("you can't specify a revision and a date"))
2631 raise util.Abort(_("you can't specify a revision and a date"))
2637 rev = cmdutil.finddate(ui, repo, date)
2632 rev = cmdutil.finddate(ui, repo, date)
2638
2633
2639 if clean:
2634 if clean:
2640 return hg.clean(repo, rev)
2635 return hg.clean(repo, rev)
2641 else:
2636 else:
2642 return hg.update(repo, rev)
2637 return hg.update(repo, rev)
2643
2638
2644 def verify(ui, repo):
2639 def verify(ui, repo):
2645 """verify the integrity of the repository
2640 """verify the integrity of the repository
2646
2641
2647 Verify the integrity of the current repository.
2642 Verify the integrity of the current repository.
2648
2643
2649 This will perform an extensive check of the repository's
2644 This will perform an extensive check of the repository's
2650 integrity, validating the hashes and checksums of each entry in
2645 integrity, validating the hashes and checksums of each entry in
2651 the changelog, manifest, and tracked files, as well as the
2646 the changelog, manifest, and tracked files, as well as the
2652 integrity of their crosslinks and indices.
2647 integrity of their crosslinks and indices.
2653 """
2648 """
2654 return hg.verify(repo)
2649 return hg.verify(repo)
2655
2650
2656 def version_(ui):
2651 def version_(ui):
2657 """output version and copyright information"""
2652 """output version and copyright information"""
2658 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2653 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2659 % version.get_version())
2654 % version.get_version())
2660 ui.status(_(
2655 ui.status(_(
2661 "\nCopyright (C) 2005-2007 Matt Mackall <mpm@selenic.com> and others\n"
2656 "\nCopyright (C) 2005-2007 Matt Mackall <mpm@selenic.com> and others\n"
2662 "This is free software; see the source for copying conditions. "
2657 "This is free software; see the source for copying conditions. "
2663 "There is NO\nwarranty; "
2658 "There is NO\nwarranty; "
2664 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2659 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2665 ))
2660 ))
2666
2661
2667 # Command options and aliases are listed here, alphabetically
2662 # Command options and aliases are listed here, alphabetically
2668
2663
2669 globalopts = [
2664 globalopts = [
2670 ('R', 'repository', '',
2665 ('R', 'repository', '',
2671 _('repository root directory or symbolic path name')),
2666 _('repository root directory or symbolic path name')),
2672 ('', 'cwd', '', _('change working directory')),
2667 ('', 'cwd', '', _('change working directory')),
2673 ('y', 'noninteractive', None,
2668 ('y', 'noninteractive', None,
2674 _('do not prompt, assume \'yes\' for any required answers')),
2669 _('do not prompt, assume \'yes\' for any required answers')),
2675 ('q', 'quiet', None, _('suppress output')),
2670 ('q', 'quiet', None, _('suppress output')),
2676 ('v', 'verbose', None, _('enable additional output')),
2671 ('v', 'verbose', None, _('enable additional output')),
2677 ('', 'config', [], _('set/override config option')),
2672 ('', 'config', [], _('set/override config option')),
2678 ('', 'debug', None, _('enable debugging output')),
2673 ('', 'debug', None, _('enable debugging output')),
2679 ('', 'debugger', None, _('start debugger')),
2674 ('', 'debugger', None, _('start debugger')),
2680 ('', 'encoding', util._encoding, _('set the charset encoding')),
2675 ('', 'encoding', util._encoding, _('set the charset encoding')),
2681 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2676 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2682 ('', 'lsprof', None, _('print improved command execution profile')),
2677 ('', 'lsprof', None, _('print improved command execution profile')),
2683 ('', 'traceback', None, _('print traceback on exception')),
2678 ('', 'traceback', None, _('print traceback on exception')),
2684 ('', 'time', None, _('time how long the command takes')),
2679 ('', 'time', None, _('time how long the command takes')),
2685 ('', 'profile', None, _('print command execution profile')),
2680 ('', 'profile', None, _('print command execution profile')),
2686 ('', 'version', None, _('output version information and exit')),
2681 ('', 'version', None, _('output version information and exit')),
2687 ('h', 'help', None, _('display help and exit')),
2682 ('h', 'help', None, _('display help and exit')),
2688 ]
2683 ]
2689
2684
2690 dryrunopts = [('n', 'dry-run', None,
2685 dryrunopts = [('n', 'dry-run', None,
2691 _('do not perform actions, just print output'))]
2686 _('do not perform actions, just print output'))]
2692
2687
2693 remoteopts = [
2688 remoteopts = [
2694 ('e', 'ssh', '', _('specify ssh command to use')),
2689 ('e', 'ssh', '', _('specify ssh command to use')),
2695 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2690 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2696 ]
2691 ]
2697
2692
2698 walkopts = [
2693 walkopts = [
2699 ('I', 'include', [], _('include names matching the given patterns')),
2694 ('I', 'include', [], _('include names matching the given patterns')),
2700 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2695 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2701 ]
2696 ]
2702
2697
2703 commitopts = [
2698 commitopts = [
2704 ('m', 'message', '', _('use <text> as commit message')),
2699 ('m', 'message', '', _('use <text> as commit message')),
2705 ('l', 'logfile', '', _('read commit message from <file>')),
2700 ('l', 'logfile', '', _('read commit message from <file>')),
2706 ]
2701 ]
2707
2702
2708 commitopts2 = [
2703 commitopts2 = [
2709 ('d', 'date', '', _('record datecode as commit date')),
2704 ('d', 'date', '', _('record datecode as commit date')),
2710 ('u', 'user', '', _('record user as committer')),
2705 ('u', 'user', '', _('record user as committer')),
2711 ]
2706 ]
2712
2707
2713 table = {
2708 table = {
2714 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2709 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2715 "addremove":
2710 "addremove":
2716 (addremove,
2711 (addremove,
2717 [('s', 'similarity', '',
2712 [('s', 'similarity', '',
2718 _('guess renamed files by similarity (0<=s<=100)')),
2713 _('guess renamed files by similarity (0<=s<=100)')),
2719 ] + walkopts + dryrunopts,
2714 ] + walkopts + dryrunopts,
2720 _('hg addremove [OPTION]... [FILE]...')),
2715 _('hg addremove [OPTION]... [FILE]...')),
2721 "^annotate":
2716 "^annotate":
2722 (annotate,
2717 (annotate,
2723 [('r', 'rev', '', _('annotate the specified revision')),
2718 [('r', 'rev', '', _('annotate the specified revision')),
2724 ('f', 'follow', None, _('follow file copies and renames')),
2719 ('f', 'follow', None, _('follow file copies and renames')),
2725 ('a', 'text', None, _('treat all files as text')),
2720 ('a', 'text', None, _('treat all files as text')),
2726 ('u', 'user', None, _('list the author')),
2721 ('u', 'user', None, _('list the author')),
2727 ('d', 'date', None, _('list the date')),
2722 ('d', 'date', None, _('list the date')),
2728 ('n', 'number', None, _('list the revision number (default)')),
2723 ('n', 'number', None, _('list the revision number (default)')),
2729 ('c', 'changeset', None, _('list the changeset')),
2724 ('c', 'changeset', None, _('list the changeset')),
2730 ('l', 'line-number', None,
2725 ('l', 'line-number', None,
2731 _('show line number at the first appearance'))
2726 _('show line number at the first appearance'))
2732 ] + walkopts,
2727 ] + walkopts,
2733 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
2728 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
2734 "archive":
2729 "archive":
2735 (archive,
2730 (archive,
2736 [('', 'no-decode', None, _('do not pass files through decoders')),
2731 [('', 'no-decode', None, _('do not pass files through decoders')),
2737 ('p', 'prefix', '', _('directory prefix for files in archive')),
2732 ('p', 'prefix', '', _('directory prefix for files in archive')),
2738 ('r', 'rev', '', _('revision to distribute')),
2733 ('r', 'rev', '', _('revision to distribute')),
2739 ('t', 'type', '', _('type of distribution to create')),
2734 ('t', 'type', '', _('type of distribution to create')),
2740 ] + walkopts,
2735 ] + walkopts,
2741 _('hg archive [OPTION]... DEST')),
2736 _('hg archive [OPTION]... DEST')),
2742 "backout":
2737 "backout":
2743 (backout,
2738 (backout,
2744 [('', 'merge', None,
2739 [('', 'merge', None,
2745 _('merge with old dirstate parent after backout')),
2740 _('merge with old dirstate parent after backout')),
2746 ('', 'parent', '', _('parent to choose when backing out merge')),
2741 ('', 'parent', '', _('parent to choose when backing out merge')),
2747 ('r', 'rev', '', _('revision to backout')),
2742 ('r', 'rev', '', _('revision to backout')),
2748 ] + walkopts + commitopts + commitopts2,
2743 ] + walkopts + commitopts + commitopts2,
2749 _('hg backout [OPTION]... [-r] REV')),
2744 _('hg backout [OPTION]... [-r] REV')),
2750 "bisect": (bisect,
2745 "bisect": (bisect,
2751 [('r', 'reset', False, _('reset bisect state')),
2746 [('r', 'reset', False, _('reset bisect state')),
2752 ('g', 'good', False, _('mark changeset good')),
2747 ('g', 'good', False, _('mark changeset good')),
2753 ('b', 'bad', False, _('mark changeset bad')),
2748 ('b', 'bad', False, _('mark changeset bad')),
2754 ('s', 'skip', False, _('skip testing changeset')),
2749 ('s', 'skip', False, _('skip testing changeset')),
2755 ('U', 'noupdate', False, _('do not update to target'))],
2750 ('U', 'noupdate', False, _('do not update to target'))],
2756 _("hg bisect [-gbsr] [REV]")),
2751 _("hg bisect [-gbsr] [REV]")),
2757 "branch":
2752 "branch":
2758 (branch,
2753 (branch,
2759 [('f', 'force', None,
2754 [('f', 'force', None,
2760 _('set branch name even if it shadows an existing branch'))],
2755 _('set branch name even if it shadows an existing branch'))],
2761 _('hg branch [NAME]')),
2756 _('hg branch [NAME]')),
2762 "branches":
2757 "branches":
2763 (branches,
2758 (branches,
2764 [('a', 'active', False,
2759 [('a', 'active', False,
2765 _('show only branches that have unmerged heads'))],
2760 _('show only branches that have unmerged heads'))],
2766 _('hg branches [-a]')),
2761 _('hg branches [-a]')),
2767 "bundle":
2762 "bundle":
2768 (bundle,
2763 (bundle,
2769 [('f', 'force', None,
2764 [('f', 'force', None,
2770 _('run even when remote repository is unrelated')),
2765 _('run even when remote repository is unrelated')),
2771 ('r', 'rev', [],
2766 ('r', 'rev', [],
2772 _('a changeset you would like to bundle')),
2767 _('a changeset you would like to bundle')),
2773 ('', 'base', [],
2768 ('', 'base', [],
2774 _('a base changeset to specify instead of a destination')),
2769 _('a base changeset to specify instead of a destination')),
2775 ] + remoteopts,
2770 ] + remoteopts,
2776 _('hg bundle [-f] [-r REV]... [--base REV]... FILE [DEST]')),
2771 _('hg bundle [-f] [-r REV]... [--base REV]... FILE [DEST]')),
2777 "cat":
2772 "cat":
2778 (cat,
2773 (cat,
2779 [('o', 'output', '', _('print output to file with formatted name')),
2774 [('o', 'output', '', _('print output to file with formatted name')),
2780 ('r', 'rev', '', _('print the given revision')),
2775 ('r', 'rev', '', _('print the given revision')),
2781 ] + walkopts,
2776 ] + walkopts,
2782 _('hg cat [OPTION]... FILE...')),
2777 _('hg cat [OPTION]... FILE...')),
2783 "^clone":
2778 "^clone":
2784 (clone,
2779 (clone,
2785 [('U', 'noupdate', None, _('do not update the new working directory')),
2780 [('U', 'noupdate', None, _('do not update the new working directory')),
2786 ('r', 'rev', [],
2781 ('r', 'rev', [],
2787 _('a changeset you would like to have after cloning')),
2782 _('a changeset you would like to have after cloning')),
2788 ('', 'pull', None, _('use pull protocol to copy metadata')),
2783 ('', 'pull', None, _('use pull protocol to copy metadata')),
2789 ('', 'uncompressed', None,
2784 ('', 'uncompressed', None,
2790 _('use uncompressed transfer (fast over LAN)')),
2785 _('use uncompressed transfer (fast over LAN)')),
2791 ] + remoteopts,
2786 ] + remoteopts,
2792 _('hg clone [OPTION]... SOURCE [DEST]')),
2787 _('hg clone [OPTION]... SOURCE [DEST]')),
2793 "^commit|ci":
2788 "^commit|ci":
2794 (commit,
2789 (commit,
2795 [('A', 'addremove', None,
2790 [('A', 'addremove', None,
2796 _('mark new/missing files as added/removed before committing')),
2791 _('mark new/missing files as added/removed before committing')),
2797 ] + walkopts + commitopts + commitopts2,
2792 ] + walkopts + commitopts + commitopts2,
2798 _('hg commit [OPTION]... [FILE]...')),
2793 _('hg commit [OPTION]... [FILE]...')),
2799 "copy|cp":
2794 "copy|cp":
2800 (copy,
2795 (copy,
2801 [('A', 'after', None, _('record a copy that has already occurred')),
2796 [('A', 'after', None, _('record a copy that has already occurred')),
2802 ('f', 'force', None,
2797 ('f', 'force', None,
2803 _('forcibly copy over an existing managed file')),
2798 _('forcibly copy over an existing managed file')),
2804 ] + walkopts + dryrunopts,
2799 ] + walkopts + dryrunopts,
2805 _('hg copy [OPTION]... [SOURCE]... DEST')),
2800 _('hg copy [OPTION]... [SOURCE]... DEST')),
2806 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2801 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2807 "debugcomplete":
2802 "debugcomplete":
2808 (debugcomplete,
2803 (debugcomplete,
2809 [('o', 'options', None, _('show the command options'))],
2804 [('o', 'options', None, _('show the command options'))],
2810 _('debugcomplete [-o] CMD')),
2805 _('debugcomplete [-o] CMD')),
2811 "debuginstall": (debuginstall, [], _('debuginstall')),
2806 "debuginstall": (debuginstall, [], _('debuginstall')),
2812 "debugrebuildstate":
2807 "debugrebuildstate":
2813 (debugrebuildstate,
2808 (debugrebuildstate,
2814 [('r', 'rev', '', _('revision to rebuild to'))],
2809 [('r', 'rev', '', _('revision to rebuild to'))],
2815 _('debugrebuildstate [-r REV] [REV]')),
2810 _('debugrebuildstate [-r REV] [REV]')),
2816 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2811 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2817 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2812 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2818 "debugstate": (debugstate, [], _('debugstate')),
2813 "debugstate": (debugstate, [], _('debugstate')),
2819 "debugdate":
2814 "debugdate":
2820 (debugdate,
2815 (debugdate,
2821 [('e', 'extended', None, _('try extended date formats'))],
2816 [('e', 'extended', None, _('try extended date formats'))],
2822 _('debugdate [-e] DATE [RANGE]')),
2817 _('debugdate [-e] DATE [RANGE]')),
2823 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2818 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2824 "debugfsinfo": (debugfsinfo, [], _('debugfsinfo [PATH]')),
2819 "debugfsinfo": (debugfsinfo, [], _('debugfsinfo [PATH]')),
2825 "debugindex": (debugindex, [], _('debugindex FILE')),
2820 "debugindex": (debugindex, [], _('debugindex FILE')),
2826 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2821 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2827 "debugrename":
2822 "debugrename":
2828 (debugrename,
2823 (debugrename,
2829 [('r', 'rev', '', _('revision to debug'))],
2824 [('r', 'rev', '', _('revision to debug'))],
2830 _('debugrename [-r REV] FILE')),
2825 _('debugrename [-r REV] FILE')),
2831 "debugwalk": (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2826 "debugwalk": (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2832 "^diff":
2827 "^diff":
2833 (diff,
2828 (diff,
2834 [('r', 'rev', [], _('revision')),
2829 [('r', 'rev', [], _('revision')),
2835 ('a', 'text', None, _('treat all files as text')),
2830 ('a', 'text', None, _('treat all files as text')),
2836 ('p', 'show-function', None,
2831 ('p', 'show-function', None,
2837 _('show which function each change is in')),
2832 _('show which function each change is in')),
2838 ('g', 'git', None, _('use git extended diff format')),
2833 ('g', 'git', None, _('use git extended diff format')),
2839 ('', 'nodates', None, _("don't include dates in diff headers")),
2834 ('', 'nodates', None, _("don't include dates in diff headers")),
2840 ('w', 'ignore-all-space', None,
2835 ('w', 'ignore-all-space', None,
2841 _('ignore white space when comparing lines')),
2836 _('ignore white space when comparing lines')),
2842 ('b', 'ignore-space-change', None,
2837 ('b', 'ignore-space-change', None,
2843 _('ignore changes in the amount of white space')),
2838 _('ignore changes in the amount of white space')),
2844 ('B', 'ignore-blank-lines', None,
2839 ('B', 'ignore-blank-lines', None,
2845 _('ignore changes whose lines are all blank')),
2840 _('ignore changes whose lines are all blank')),
2846 ] + walkopts,
2841 ] + walkopts,
2847 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
2842 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
2848 "^export":
2843 "^export":
2849 (export,
2844 (export,
2850 [('o', 'output', '', _('print output to file with formatted name')),
2845 [('o', 'output', '', _('print output to file with formatted name')),
2851 ('a', 'text', None, _('treat all files as text')),
2846 ('a', 'text', None, _('treat all files as text')),
2852 ('g', 'git', None, _('use git extended diff format')),
2847 ('g', 'git', None, _('use git extended diff format')),
2853 ('', 'nodates', None, _("don't include dates in diff headers")),
2848 ('', 'nodates', None, _("don't include dates in diff headers")),
2854 ('', 'switch-parent', None, _('diff against the second parent'))],
2849 ('', 'switch-parent', None, _('diff against the second parent'))],
2855 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
2850 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
2856 "grep":
2851 "grep":
2857 (grep,
2852 (grep,
2858 [('0', 'print0', None, _('end fields with NUL')),
2853 [('0', 'print0', None, _('end fields with NUL')),
2859 ('', 'all', None, _('print all revisions that match')),
2854 ('', 'all', None, _('print all revisions that match')),
2860 ('f', 'follow', None,
2855 ('f', 'follow', None,
2861 _('follow changeset history, or file history across copies and renames')),
2856 _('follow changeset history, or file history across copies and renames')),
2862 ('i', 'ignore-case', None, _('ignore case when matching')),
2857 ('i', 'ignore-case', None, _('ignore case when matching')),
2863 ('l', 'files-with-matches', None,
2858 ('l', 'files-with-matches', None,
2864 _('print only filenames and revs that match')),
2859 _('print only filenames and revs that match')),
2865 ('n', 'line-number', None, _('print matching line numbers')),
2860 ('n', 'line-number', None, _('print matching line numbers')),
2866 ('r', 'rev', [], _('search in given revision range')),
2861 ('r', 'rev', [], _('search in given revision range')),
2867 ('u', 'user', None, _('print user who committed change')),
2862 ('u', 'user', None, _('print user who committed change')),
2868 ] + walkopts,
2863 ] + walkopts,
2869 _('hg grep [OPTION]... PATTERN [FILE]...')),
2864 _('hg grep [OPTION]... PATTERN [FILE]...')),
2870 "heads":
2865 "heads":
2871 (heads,
2866 (heads,
2872 [('', 'style', '', _('display using template map file')),
2867 [('', 'style', '', _('display using template map file')),
2873 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2868 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2874 ('', 'template', '', _('display with template'))],
2869 ('', 'template', '', _('display with template'))],
2875 _('hg heads [-r REV] [REV]...')),
2870 _('hg heads [-r REV] [REV]...')),
2876 "help": (help_, [], _('hg help [COMMAND]')),
2871 "help": (help_, [], _('hg help [COMMAND]')),
2877 "identify|id":
2872 "identify|id":
2878 (identify,
2873 (identify,
2879 [('r', 'rev', '', _('identify the specified rev')),
2874 [('r', 'rev', '', _('identify the specified rev')),
2880 ('n', 'num', None, _('show local revision number')),
2875 ('n', 'num', None, _('show local revision number')),
2881 ('i', 'id', None, _('show global revision id')),
2876 ('i', 'id', None, _('show global revision id')),
2882 ('b', 'branch', None, _('show branch')),
2877 ('b', 'branch', None, _('show branch')),
2883 ('t', 'tags', None, _('show tags'))],
2878 ('t', 'tags', None, _('show tags'))],
2884 _('hg identify [-nibt] [-r REV] [SOURCE]')),
2879 _('hg identify [-nibt] [-r REV] [SOURCE]')),
2885 "import|patch":
2880 "import|patch":
2886 (import_,
2881 (import_,
2887 [('p', 'strip', 1,
2882 [('p', 'strip', 1,
2888 _('directory strip option for patch. This has the same\n'
2883 _('directory strip option for patch. This has the same\n'
2889 'meaning as the corresponding patch option')),
2884 'meaning as the corresponding patch option')),
2890 ('b', 'base', '', _('base path')),
2885 ('b', 'base', '', _('base path')),
2891 ('f', 'force', None,
2886 ('f', 'force', None,
2892 _('skip check for outstanding uncommitted changes')),
2887 _('skip check for outstanding uncommitted changes')),
2893 ('', 'exact', None,
2888 ('', 'exact', None,
2894 _('apply patch to the nodes from which it was generated')),
2889 _('apply patch to the nodes from which it was generated')),
2895 ('', 'import-branch', None,
2890 ('', 'import-branch', None,
2896 _('Use any branch information in patch (implied by --exact)'))] + commitopts,
2891 _('Use any branch information in patch (implied by --exact)'))] + commitopts,
2897 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2892 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2898 "incoming|in": (incoming,
2893 "incoming|in": (incoming,
2899 [('M', 'no-merges', None, _('do not show merges')),
2894 [('M', 'no-merges', None, _('do not show merges')),
2900 ('f', 'force', None,
2895 ('f', 'force', None,
2901 _('run even when remote repository is unrelated')),
2896 _('run even when remote repository is unrelated')),
2902 ('', 'style', '', _('display using template map file')),
2897 ('', 'style', '', _('display using template map file')),
2903 ('n', 'newest-first', None, _('show newest record first')),
2898 ('n', 'newest-first', None, _('show newest record first')),
2904 ('', 'bundle', '', _('file to store the bundles into')),
2899 ('', 'bundle', '', _('file to store the bundles into')),
2905 ('p', 'patch', None, _('show patch')),
2900 ('p', 'patch', None, _('show patch')),
2906 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2901 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2907 ('', 'template', '', _('display with template')),
2902 ('', 'template', '', _('display with template')),
2908 ] + remoteopts,
2903 ] + remoteopts,
2909 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
2904 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
2910 ' [--bundle FILENAME] [SOURCE]')),
2905 ' [--bundle FILENAME] [SOURCE]')),
2911 "^init":
2906 "^init":
2912 (init,
2907 (init,
2913 remoteopts,
2908 remoteopts,
2914 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
2909 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
2915 "locate":
2910 "locate":
2916 (locate,
2911 (locate,
2917 [('r', 'rev', '', _('search the repository as it stood at rev')),
2912 [('r', 'rev', '', _('search the repository as it stood at rev')),
2918 ('0', 'print0', None,
2913 ('0', 'print0', None,
2919 _('end filenames with NUL, for use with xargs')),
2914 _('end filenames with NUL, for use with xargs')),
2920 ('f', 'fullpath', None,
2915 ('f', 'fullpath', None,
2921 _('print complete paths from the filesystem root')),
2916 _('print complete paths from the filesystem root')),
2922 ] + walkopts,
2917 ] + walkopts,
2923 _('hg locate [OPTION]... [PATTERN]...')),
2918 _('hg locate [OPTION]... [PATTERN]...')),
2924 "^log|history":
2919 "^log|history":
2925 (log,
2920 (log,
2926 [('f', 'follow', None,
2921 [('f', 'follow', None,
2927 _('follow changeset history, or file history across copies and renames')),
2922 _('follow changeset history, or file history across copies and renames')),
2928 ('', 'follow-first', None,
2923 ('', 'follow-first', None,
2929 _('only follow the first parent of merge changesets')),
2924 _('only follow the first parent of merge changesets')),
2930 ('d', 'date', '', _('show revs matching date spec')),
2925 ('d', 'date', '', _('show revs matching date spec')),
2931 ('C', 'copies', None, _('show copied files')),
2926 ('C', 'copies', None, _('show copied files')),
2932 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
2927 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
2933 ('l', 'limit', '', _('limit number of changes displayed')),
2928 ('l', 'limit', '', _('limit number of changes displayed')),
2934 ('r', 'rev', [], _('show the specified revision or range')),
2929 ('r', 'rev', [], _('show the specified revision or range')),
2935 ('', 'removed', None, _('include revs where files were removed')),
2930 ('', 'removed', None, _('include revs where files were removed')),
2936 ('M', 'no-merges', None, _('do not show merges')),
2931 ('M', 'no-merges', None, _('do not show merges')),
2937 ('', 'style', '', _('display using template map file')),
2932 ('', 'style', '', _('display using template map file')),
2938 ('m', 'only-merges', None, _('show only merges')),
2933 ('m', 'only-merges', None, _('show only merges')),
2939 ('p', 'patch', None, _('show patch')),
2934 ('p', 'patch', None, _('show patch')),
2940 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2935 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2941 ('', 'template', '', _('display with template')),
2936 ('', 'template', '', _('display with template')),
2942 ] + walkopts,
2937 ] + walkopts,
2943 _('hg log [OPTION]... [FILE]')),
2938 _('hg log [OPTION]... [FILE]')),
2944 "manifest": (manifest, [('r', 'rev', '', _('revision to display'))],
2939 "manifest": (manifest, [('r', 'rev', '', _('revision to display'))],
2945 _('hg manifest [-r REV]')),
2940 _('hg manifest [-r REV]')),
2946 "^merge":
2941 "^merge":
2947 (merge,
2942 (merge,
2948 [('f', 'force', None, _('force a merge with outstanding changes')),
2943 [('f', 'force', None, _('force a merge with outstanding changes')),
2949 ('r', 'rev', '', _('revision to merge')),
2944 ('r', 'rev', '', _('revision to merge')),
2950 ],
2945 ],
2951 _('hg merge [-f] [[-r] REV]')),
2946 _('hg merge [-f] [[-r] REV]')),
2952 "outgoing|out": (outgoing,
2947 "outgoing|out": (outgoing,
2953 [('M', 'no-merges', None, _('do not show merges')),
2948 [('M', 'no-merges', None, _('do not show merges')),
2954 ('f', 'force', None,
2949 ('f', 'force', None,
2955 _('run even when remote repository is unrelated')),
2950 _('run even when remote repository is unrelated')),
2956 ('p', 'patch', None, _('show patch')),
2951 ('p', 'patch', None, _('show patch')),
2957 ('', 'style', '', _('display using template map file')),
2952 ('', 'style', '', _('display using template map file')),
2958 ('r', 'rev', [], _('a specific revision you would like to push')),
2953 ('r', 'rev', [], _('a specific revision you would like to push')),
2959 ('n', 'newest-first', None, _('show newest record first')),
2954 ('n', 'newest-first', None, _('show newest record first')),
2960 ('', 'template', '', _('display with template')),
2955 ('', 'template', '', _('display with template')),
2961 ] + remoteopts,
2956 ] + remoteopts,
2962 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
2957 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
2963 "^parents":
2958 "^parents":
2964 (parents,
2959 (parents,
2965 [('r', 'rev', '', _('show parents from the specified rev')),
2960 [('r', 'rev', '', _('show parents from the specified rev')),
2966 ('', 'style', '', _('display using template map file')),
2961 ('', 'style', '', _('display using template map file')),
2967 ('', 'template', '', _('display with template'))],
2962 ('', 'template', '', _('display with template'))],
2968 _('hg parents [-r REV] [FILE]')),
2963 _('hg parents [-r REV] [FILE]')),
2969 "paths": (paths, [], _('hg paths [NAME]')),
2964 "paths": (paths, [], _('hg paths [NAME]')),
2970 "^pull":
2965 "^pull":
2971 (pull,
2966 (pull,
2972 [('u', 'update', None,
2967 [('u', 'update', None,
2973 _('update to new tip if changesets were pulled')),
2968 _('update to new tip if changesets were pulled')),
2974 ('f', 'force', None,
2969 ('f', 'force', None,
2975 _('run even when remote repository is unrelated')),
2970 _('run even when remote repository is unrelated')),
2976 ('r', 'rev', [],
2971 ('r', 'rev', [],
2977 _('a specific revision up to which you would like to pull')),
2972 _('a specific revision up to which you would like to pull')),
2978 ] + remoteopts,
2973 ] + remoteopts,
2979 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
2974 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
2980 "^push":
2975 "^push":
2981 (push,
2976 (push,
2982 [('f', 'force', None, _('force push')),
2977 [('f', 'force', None, _('force push')),
2983 ('r', 'rev', [], _('a specific revision you would like to push')),
2978 ('r', 'rev', [], _('a specific revision you would like to push')),
2984 ] + remoteopts,
2979 ] + remoteopts,
2985 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
2980 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
2986 "debugrawcommit|rawcommit":
2981 "debugrawcommit|rawcommit":
2987 (rawcommit,
2982 (rawcommit,
2988 [('p', 'parent', [], _('parent')),
2983 [('p', 'parent', [], _('parent')),
2989 ('F', 'files', '', _('file list'))
2984 ('F', 'files', '', _('file list'))
2990 ] + commitopts + commitopts2,
2985 ] + commitopts + commitopts2,
2991 _('hg debugrawcommit [OPTION]... [FILE]...')),
2986 _('hg debugrawcommit [OPTION]... [FILE]...')),
2992 "recover": (recover, [], _('hg recover')),
2987 "recover": (recover, [], _('hg recover')),
2993 "^remove|rm":
2988 "^remove|rm":
2994 (remove,
2989 (remove,
2995 [('A', 'after', None, _('record remove without deleting')),
2990 [('A', 'after', None, _('record remove without deleting')),
2996 ('f', 'force', None, _('remove file even if modified')),
2991 ('f', 'force', None, _('remove file even if modified')),
2997 ] + walkopts,
2992 ] + walkopts,
2998 _('hg remove [OPTION]... FILE...')),
2993 _('hg remove [OPTION]... FILE...')),
2999 "rename|mv":
2994 "rename|mv":
3000 (rename,
2995 (rename,
3001 [('A', 'after', None, _('record a rename that has already occurred')),
2996 [('A', 'after', None, _('record a rename that has already occurred')),
3002 ('f', 'force', None,
2997 ('f', 'force', None,
3003 _('forcibly copy over an existing managed file')),
2998 _('forcibly copy over an existing managed file')),
3004 ] + walkopts + dryrunopts,
2999 ] + walkopts + dryrunopts,
3005 _('hg rename [OPTION]... SOURCE... DEST')),
3000 _('hg rename [OPTION]... SOURCE... DEST')),
3006 "revert":
3001 "revert":
3007 (revert,
3002 (revert,
3008 [('a', 'all', None, _('revert all changes when no arguments given')),
3003 [('a', 'all', None, _('revert all changes when no arguments given')),
3009 ('d', 'date', '', _('tipmost revision matching date')),
3004 ('d', 'date', '', _('tipmost revision matching date')),
3010 ('r', 'rev', '', _('revision to revert to')),
3005 ('r', 'rev', '', _('revision to revert to')),
3011 ('', 'no-backup', None, _('do not save backup copies of files')),
3006 ('', 'no-backup', None, _('do not save backup copies of files')),
3012 ] + walkopts + dryrunopts,
3007 ] + walkopts + dryrunopts,
3013 _('hg revert [OPTION]... [-r REV] [NAME]...')),
3008 _('hg revert [OPTION]... [-r REV] [NAME]...')),
3014 "rollback": (rollback, [], _('hg rollback')),
3009 "rollback": (rollback, [], _('hg rollback')),
3015 "root": (root, [], _('hg root')),
3010 "root": (root, [], _('hg root')),
3016 "showconfig|debugconfig":
3011 "showconfig|debugconfig":
3017 (showconfig,
3012 (showconfig,
3018 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3013 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3019 _('showconfig [-u] [NAME]...')),
3014 _('showconfig [-u] [NAME]...')),
3020 "^serve":
3015 "^serve":
3021 (serve,
3016 (serve,
3022 [('A', 'accesslog', '', _('name of access log file to write to')),
3017 [('A', 'accesslog', '', _('name of access log file to write to')),
3023 ('d', 'daemon', None, _('run server in background')),
3018 ('d', 'daemon', None, _('run server in background')),
3024 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3019 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3025 ('E', 'errorlog', '', _('name of error log file to write to')),
3020 ('E', 'errorlog', '', _('name of error log file to write to')),
3026 ('p', 'port', 0, _('port to use (default: 8000)')),
3021 ('p', 'port', 0, _('port to use (default: 8000)')),
3027 ('a', 'address', '', _('address to use')),
3022 ('a', 'address', '', _('address to use')),
3028 ('n', 'name', '',
3023 ('n', 'name', '',
3029 _('name to show in web pages (default: working dir)')),
3024 _('name to show in web pages (default: working dir)')),
3030 ('', 'webdir-conf', '', _('name of the webdir config file'
3025 ('', 'webdir-conf', '', _('name of the webdir config file'
3031 ' (serve more than one repo)')),
3026 ' (serve more than one repo)')),
3032 ('', 'pid-file', '', _('name of file to write process ID to')),
3027 ('', 'pid-file', '', _('name of file to write process ID to')),
3033 ('', 'stdio', None, _('for remote clients')),
3028 ('', 'stdio', None, _('for remote clients')),
3034 ('t', 'templates', '', _('web templates to use')),
3029 ('t', 'templates', '', _('web templates to use')),
3035 ('', 'style', '', _('template style to use')),
3030 ('', 'style', '', _('template style to use')),
3036 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3031 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3037 ('', 'certificate', '', _('SSL certificate file'))],
3032 ('', 'certificate', '', _('SSL certificate file'))],
3038 _('hg serve [OPTION]...')),
3033 _('hg serve [OPTION]...')),
3039 "^status|st":
3034 "^status|st":
3040 (status,
3035 (status,
3041 [('A', 'all', None, _('show status of all files')),
3036 [('A', 'all', None, _('show status of all files')),
3042 ('m', 'modified', None, _('show only modified files')),
3037 ('m', 'modified', None, _('show only modified files')),
3043 ('a', 'added', None, _('show only added files')),
3038 ('a', 'added', None, _('show only added files')),
3044 ('r', 'removed', None, _('show only removed files')),
3039 ('r', 'removed', None, _('show only removed files')),
3045 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3040 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3046 ('c', 'clean', None, _('show only files without changes')),
3041 ('c', 'clean', None, _('show only files without changes')),
3047 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3042 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3048 ('i', 'ignored', None, _('show only ignored files')),
3043 ('i', 'ignored', None, _('show only ignored files')),
3049 ('n', 'no-status', None, _('hide status prefix')),
3044 ('n', 'no-status', None, _('hide status prefix')),
3050 ('C', 'copies', None, _('show source of copied files')),
3045 ('C', 'copies', None, _('show source of copied files')),
3051 ('0', 'print0', None,
3046 ('0', 'print0', None,
3052 _('end filenames with NUL, for use with xargs')),
3047 _('end filenames with NUL, for use with xargs')),
3053 ('', 'rev', [], _('show difference from revision')),
3048 ('', 'rev', [], _('show difference from revision')),
3054 ] + walkopts,
3049 ] + walkopts,
3055 _('hg status [OPTION]... [FILE]...')),
3050 _('hg status [OPTION]... [FILE]...')),
3056 "tag":
3051 "tag":
3057 (tag,
3052 (tag,
3058 [('f', 'force', None, _('replace existing tag')),
3053 [('f', 'force', None, _('replace existing tag')),
3059 ('l', 'local', None, _('make the tag local')),
3054 ('l', 'local', None, _('make the tag local')),
3060 ('r', 'rev', '', _('revision to tag')),
3055 ('r', 'rev', '', _('revision to tag')),
3061 ('', 'remove', None, _('remove a tag')),
3056 ('', 'remove', None, _('remove a tag')),
3062 # -l/--local is already there, commitopts cannot be used
3057 # -l/--local is already there, commitopts cannot be used
3063 ('m', 'message', '', _('use <text> as commit message')),
3058 ('m', 'message', '', _('use <text> as commit message')),
3064 ] + commitopts2,
3059 ] + commitopts2,
3065 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3060 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3066 "tags": (tags, [], _('hg tags')),
3061 "tags": (tags, [], _('hg tags')),
3067 "tip":
3062 "tip":
3068 (tip,
3063 (tip,
3069 [('', 'style', '', _('display using template map file')),
3064 [('', 'style', '', _('display using template map file')),
3070 ('p', 'patch', None, _('show patch')),
3065 ('p', 'patch', None, _('show patch')),
3071 ('', 'template', '', _('display with template'))],
3066 ('', 'template', '', _('display with template'))],
3072 _('hg tip [-p]')),
3067 _('hg tip [-p]')),
3073 "unbundle":
3068 "unbundle":
3074 (unbundle,
3069 (unbundle,
3075 [('u', 'update', None,
3070 [('u', 'update', None,
3076 _('update to new tip if changesets were unbundled'))],
3071 _('update to new tip if changesets were unbundled'))],
3077 _('hg unbundle [-u] FILE...')),
3072 _('hg unbundle [-u] FILE...')),
3078 "^update|up|checkout|co":
3073 "^update|up|checkout|co":
3079 (update,
3074 (update,
3080 [('C', 'clean', None, _('overwrite locally modified files')),
3075 [('C', 'clean', None, _('overwrite locally modified files')),
3081 ('d', 'date', '', _('tipmost revision matching date')),
3076 ('d', 'date', '', _('tipmost revision matching date')),
3082 ('r', 'rev', '', _('revision'))],
3077 ('r', 'rev', '', _('revision'))],
3083 _('hg update [-C] [-d DATE] [[-r] REV]')),
3078 _('hg update [-C] [-d DATE] [[-r] REV]')),
3084 "verify": (verify, [], _('hg verify')),
3079 "verify": (verify, [], _('hg verify')),
3085 "version": (version_, [], _('hg version')),
3080 "version": (version_, [], _('hg version')),
3086 }
3081 }
3087
3082
3088 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3083 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3089 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3084 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3090 optionalrepo = ("identify paths serve showconfig")
3085 optionalrepo = ("identify paths serve showconfig")
@@ -1,94 +1,105 b''
1 # changelog bisection for mercurial
1 # changelog bisection for mercurial
2 #
2 #
3 # Copyright 2007 Matt Mackall
3 # Copyright 2007 Matt Mackall
4 # Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org>
4 # Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org>
5 # Inspired by git bisect, extension skeleton taken from mq.py.
5 # Inspired by git bisect, extension skeleton taken from mq.py.
6 #
6 #
7 # This software may be used and distributed according to the terms
7 # This software may be used and distributed according to the terms
8 # of the GNU General Public License, incorporated herein by reference.
8 # of the GNU General Public License, incorporated herein by reference.
9
9
10 from i18n import _
10 from i18n import _
11 import hg, util
11 import hg, util
12
12
13 def bisect(changelog, state):
13 def bisect(changelog, state):
14 clparents = changelog.parentrevs
14 clparents = changelog.parentrevs
15 # only the earliest bad revision matters
16 badrev = min([changelog.rev(n) for n in state['bad']])
17 bad = changelog.node(badrev)
18 skip = dict.fromkeys([changelog.rev(n) for n in state['skip']])
15 skip = dict.fromkeys([changelog.rev(n) for n in state['skip']])
19
16
17 def buildancestors(bad, good):
18 # only the earliest bad revision matters
19 badrev = min([changelog.rev(n) for n in bad])
20 goodrevs = [changelog.rev(n) for n in good]
20 # build ancestors array
21 # build ancestors array
21 ancestors = [[]] * (changelog.count() + 1) # an extra for [-1]
22 ancestors = [[]] * (changelog.count() + 1) # an extra for [-1]
22
23
23 # clear good revs from array
24 # clear good revs from array
24 for node in state['good']:
25 for node in goodrevs:
25 ancestors[changelog.rev(node)] = None
26 ancestors[node] = None
26 for rev in xrange(changelog.count(), -1, -1):
27 for rev in xrange(changelog.count(), -1, -1):
27 if ancestors[rev] is None:
28 if ancestors[rev] is None:
28 for prev in clparents(rev):
29 for prev in clparents(rev):
29 ancestors[prev] = None
30 ancestors[prev] = None
30
31
31 if ancestors[badrev] is None:
32 if ancestors[badrev] is None:
33 return None, None
34 return badrev, ancestors
35
36 good = 0
37 badrev, ancestors = buildancestors(state['bad'], state['good'])
38 if not ancestors: # looking for bad to good transition?
39 good = 1
40 badrev, ancestors = buildancestors(state['good'], state['bad'])
41 if not ancestors: # now we're confused
32 raise util.Abort(_("Inconsistent state, %s:%s is good and bad")
42 raise util.Abort(_("Inconsistent state, %s:%s is good and bad")
33 % (badrev, hg.short(bad)))
43 % (badrev, hg.short(bad)))
44 bad = changelog.node(badrev)
34
45
35 # build children dict
46 # build children dict
36 children = {}
47 children = {}
37 visit = [badrev]
48 visit = [badrev]
38 candidates = []
49 candidates = []
39 while visit:
50 while visit:
40 rev = visit.pop(0)
51 rev = visit.pop(0)
41 if ancestors[rev] == []:
52 if ancestors[rev] == []:
42 candidates.append(rev)
53 candidates.append(rev)
43 for prev in clparents(rev):
54 for prev in clparents(rev):
44 if prev != -1:
55 if prev != -1:
45 if prev in children:
56 if prev in children:
46 children[prev].append(rev)
57 children[prev].append(rev)
47 else:
58 else:
48 children[prev] = [rev]
59 children[prev] = [rev]
49 visit.append(prev)
60 visit.append(prev)
50
61
51 candidates.sort()
62 candidates.sort()
52 # have we narrowed it down to one entry?
63 # have we narrowed it down to one entry?
53 tot = len(candidates)
64 tot = len(candidates)
54 if tot == 1:
65 if tot == 1:
55 return (bad, 0)
66 return (bad, 0, good)
56 perfect = tot / 2
67 perfect = tot / 2
57
68
58 # find the best node to test
69 # find the best node to test
59 best_rev = None
70 best_rev = None
60 best_len = -1
71 best_len = -1
61 poison = {}
72 poison = {}
62 for rev in candidates:
73 for rev in candidates:
63 if rev in poison:
74 if rev in poison:
64 for c in children.get(rev, []):
75 for c in children.get(rev, []):
65 poison[c] = True # poison children
76 poison[c] = True # poison children
66 continue
77 continue
67
78
68 a = ancestors[rev] or [rev]
79 a = ancestors[rev] or [rev]
69 ancestors[rev] = None
80 ancestors[rev] = None
70
81
71 x = len(a) # number of ancestors
82 x = len(a) # number of ancestors
72 y = tot - x # number of non-ancestors
83 y = tot - x # number of non-ancestors
73 value = min(x, y) # how good is this test?
84 value = min(x, y) # how good is this test?
74 if value > best_len and rev not in skip:
85 if value > best_len and rev not in skip:
75 best_len = value
86 best_len = value
76 best_rev = rev
87 best_rev = rev
77 if value == perfect: # found a perfect candidate? quit early
88 if value == perfect: # found a perfect candidate? quit early
78 break
89 break
79
90
80 if y < perfect: # all downhill from here?
91 if y < perfect: # all downhill from here?
81 for c in children.get(rev, []):
92 for c in children.get(rev, []):
82 poison[c] = True # poison children
93 poison[c] = True # poison children
83 continue
94 continue
84
95
85 for c in children.get(rev, []):
96 for c in children.get(rev, []):
86 if ancestors[c]:
97 if ancestors[c]:
87 ancestors[c] = dict.fromkeys(ancestors[c] + a).keys()
98 ancestors[c] = dict.fromkeys(ancestors[c] + a).keys()
88 else:
99 else:
89 ancestors[c] = a + [c]
100 ancestors[c] = a + [c]
90
101
91 assert best_rev is not None
102 assert best_rev is not None
92 best_node = changelog.node(best_rev)
103 best_node = changelog.node(best_rev)
93
104
94 return (best_node, tot)
105 return (best_node, tot, good)
@@ -1,33 +1,43 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 set -e
3 set -e
4
4
5 echo % init
5 echo % init
6 hg init
6 hg init
7
7
8 echo % committing changes
8 echo % committing changes
9 count=0
9 count=0
10 echo > a
10 echo > a
11 while test $count -lt 32 ; do
11 while test $count -lt 32 ; do
12 echo 'a' >> a
12 echo 'a' >> a
13 test $count -eq 0 && hg add
13 test $count -eq 0 && hg add
14 hg ci -m "msg $count" -d "$count 0"
14 hg ci -m "msg $count" -d "$count 0"
15 echo % committed changeset $count
15 echo % committed changeset $count
16 count=`expr $count + 1`
16 count=`expr $count + 1`
17 done
17 done
18
18
19 echo % log
19 echo % log
20 hg log
20 hg log
21
21
22 echo % hg up -C
22 echo % hg up -C
23 hg up -C
23 hg up -C
24
24
25 echo % bisect test
25 echo % bisect test
26 hg bisect -r
26 hg bisect -r
27 hg bisect -b
27 hg bisect -b
28 hg bisect -g 1
28 hg bisect -g 1
29 hg bisect -g
29 hg bisect -g
30 hg bisect -g
30 hg bisect -g
31 hg bisect -g
31 hg bisect -g
32 hg bisect -b
32 hg bisect -b
33 hg bisect -g
33 hg bisect -g
34
35 echo % bisect reverse test
36 hg bisect -r
37 hg bisect -b null
38 hg bisect -g tip
39 hg bisect -g
40 hg bisect -g
41 hg bisect -g
42 hg bisect -b
43 hg bisect -g
@@ -1,216 +1,233 b''
1 % init
1 % init
2 % committing changes
2 % committing changes
3 adding a
3 adding a
4 % committed changeset 0
4 % committed changeset 0
5 % committed changeset 1
5 % committed changeset 1
6 % committed changeset 2
6 % committed changeset 2
7 % committed changeset 3
7 % committed changeset 3
8 % committed changeset 4
8 % committed changeset 4
9 % committed changeset 5
9 % committed changeset 5
10 % committed changeset 6
10 % committed changeset 6
11 % committed changeset 7
11 % committed changeset 7
12 % committed changeset 8
12 % committed changeset 8
13 % committed changeset 9
13 % committed changeset 9
14 % committed changeset 10
14 % committed changeset 10
15 % committed changeset 11
15 % committed changeset 11
16 % committed changeset 12
16 % committed changeset 12
17 % committed changeset 13
17 % committed changeset 13
18 % committed changeset 14
18 % committed changeset 14
19 % committed changeset 15
19 % committed changeset 15
20 % committed changeset 16
20 % committed changeset 16
21 % committed changeset 17
21 % committed changeset 17
22 % committed changeset 18
22 % committed changeset 18
23 % committed changeset 19
23 % committed changeset 19
24 % committed changeset 20
24 % committed changeset 20
25 % committed changeset 21
25 % committed changeset 21
26 % committed changeset 22
26 % committed changeset 22
27 % committed changeset 23
27 % committed changeset 23
28 % committed changeset 24
28 % committed changeset 24
29 % committed changeset 25
29 % committed changeset 25
30 % committed changeset 26
30 % committed changeset 26
31 % committed changeset 27
31 % committed changeset 27
32 % committed changeset 28
32 % committed changeset 28
33 % committed changeset 29
33 % committed changeset 29
34 % committed changeset 30
34 % committed changeset 30
35 % committed changeset 31
35 % committed changeset 31
36 % log
36 % log
37 changeset: 31:58c80a7c8a40
37 changeset: 31:58c80a7c8a40
38 tag: tip
38 tag: tip
39 user: test
39 user: test
40 date: Thu Jan 01 00:00:31 1970 +0000
40 date: Thu Jan 01 00:00:31 1970 +0000
41 summary: msg 31
41 summary: msg 31
42
42
43 changeset: 30:ed2d2f24b11c
43 changeset: 30:ed2d2f24b11c
44 user: test
44 user: test
45 date: Thu Jan 01 00:00:30 1970 +0000
45 date: Thu Jan 01 00:00:30 1970 +0000
46 summary: msg 30
46 summary: msg 30
47
47
48 changeset: 29:b5bd63375ab9
48 changeset: 29:b5bd63375ab9
49 user: test
49 user: test
50 date: Thu Jan 01 00:00:29 1970 +0000
50 date: Thu Jan 01 00:00:29 1970 +0000
51 summary: msg 29
51 summary: msg 29
52
52
53 changeset: 28:8e0c2264c8af
53 changeset: 28:8e0c2264c8af
54 user: test
54 user: test
55 date: Thu Jan 01 00:00:28 1970 +0000
55 date: Thu Jan 01 00:00:28 1970 +0000
56 summary: msg 28
56 summary: msg 28
57
57
58 changeset: 27:288867a866e9
58 changeset: 27:288867a866e9
59 user: test
59 user: test
60 date: Thu Jan 01 00:00:27 1970 +0000
60 date: Thu Jan 01 00:00:27 1970 +0000
61 summary: msg 27
61 summary: msg 27
62
62
63 changeset: 26:3efc6fd51aeb
63 changeset: 26:3efc6fd51aeb
64 user: test
64 user: test
65 date: Thu Jan 01 00:00:26 1970 +0000
65 date: Thu Jan 01 00:00:26 1970 +0000
66 summary: msg 26
66 summary: msg 26
67
67
68 changeset: 25:02a84173a97a
68 changeset: 25:02a84173a97a
69 user: test
69 user: test
70 date: Thu Jan 01 00:00:25 1970 +0000
70 date: Thu Jan 01 00:00:25 1970 +0000
71 summary: msg 25
71 summary: msg 25
72
72
73 changeset: 24:10e0acd3809e
73 changeset: 24:10e0acd3809e
74 user: test
74 user: test
75 date: Thu Jan 01 00:00:24 1970 +0000
75 date: Thu Jan 01 00:00:24 1970 +0000
76 summary: msg 24
76 summary: msg 24
77
77
78 changeset: 23:5ec79163bff4
78 changeset: 23:5ec79163bff4
79 user: test
79 user: test
80 date: Thu Jan 01 00:00:23 1970 +0000
80 date: Thu Jan 01 00:00:23 1970 +0000
81 summary: msg 23
81 summary: msg 23
82
82
83 changeset: 22:06c7993750ce
83 changeset: 22:06c7993750ce
84 user: test
84 user: test
85 date: Thu Jan 01 00:00:22 1970 +0000
85 date: Thu Jan 01 00:00:22 1970 +0000
86 summary: msg 22
86 summary: msg 22
87
87
88 changeset: 21:e5db6aa3fe2a
88 changeset: 21:e5db6aa3fe2a
89 user: test
89 user: test
90 date: Thu Jan 01 00:00:21 1970 +0000
90 date: Thu Jan 01 00:00:21 1970 +0000
91 summary: msg 21
91 summary: msg 21
92
92
93 changeset: 20:7128fb4fdbc9
93 changeset: 20:7128fb4fdbc9
94 user: test
94 user: test
95 date: Thu Jan 01 00:00:20 1970 +0000
95 date: Thu Jan 01 00:00:20 1970 +0000
96 summary: msg 20
96 summary: msg 20
97
97
98 changeset: 19:52798545b482
98 changeset: 19:52798545b482
99 user: test
99 user: test
100 date: Thu Jan 01 00:00:19 1970 +0000
100 date: Thu Jan 01 00:00:19 1970 +0000
101 summary: msg 19
101 summary: msg 19
102
102
103 changeset: 18:86977a90077e
103 changeset: 18:86977a90077e
104 user: test
104 user: test
105 date: Thu Jan 01 00:00:18 1970 +0000
105 date: Thu Jan 01 00:00:18 1970 +0000
106 summary: msg 18
106 summary: msg 18
107
107
108 changeset: 17:03515f4a9080
108 changeset: 17:03515f4a9080
109 user: test
109 user: test
110 date: Thu Jan 01 00:00:17 1970 +0000
110 date: Thu Jan 01 00:00:17 1970 +0000
111 summary: msg 17
111 summary: msg 17
112
112
113 changeset: 16:a2e6ea4973e9
113 changeset: 16:a2e6ea4973e9
114 user: test
114 user: test
115 date: Thu Jan 01 00:00:16 1970 +0000
115 date: Thu Jan 01 00:00:16 1970 +0000
116 summary: msg 16
116 summary: msg 16
117
117
118 changeset: 15:e7fa0811edb0
118 changeset: 15:e7fa0811edb0
119 user: test
119 user: test
120 date: Thu Jan 01 00:00:15 1970 +0000
120 date: Thu Jan 01 00:00:15 1970 +0000
121 summary: msg 15
121 summary: msg 15
122
122
123 changeset: 14:ce8f0998e922
123 changeset: 14:ce8f0998e922
124 user: test
124 user: test
125 date: Thu Jan 01 00:00:14 1970 +0000
125 date: Thu Jan 01 00:00:14 1970 +0000
126 summary: msg 14
126 summary: msg 14
127
127
128 changeset: 13:9d7d07bc967c
128 changeset: 13:9d7d07bc967c
129 user: test
129 user: test
130 date: Thu Jan 01 00:00:13 1970 +0000
130 date: Thu Jan 01 00:00:13 1970 +0000
131 summary: msg 13
131 summary: msg 13
132
132
133 changeset: 12:1941b52820a5
133 changeset: 12:1941b52820a5
134 user: test
134 user: test
135 date: Thu Jan 01 00:00:12 1970 +0000
135 date: Thu Jan 01 00:00:12 1970 +0000
136 summary: msg 12
136 summary: msg 12
137
137
138 changeset: 11:7b4cd9578619
138 changeset: 11:7b4cd9578619
139 user: test
139 user: test
140 date: Thu Jan 01 00:00:11 1970 +0000
140 date: Thu Jan 01 00:00:11 1970 +0000
141 summary: msg 11
141 summary: msg 11
142
142
143 changeset: 10:7c5eff49a6b6
143 changeset: 10:7c5eff49a6b6
144 user: test
144 user: test
145 date: Thu Jan 01 00:00:10 1970 +0000
145 date: Thu Jan 01 00:00:10 1970 +0000
146 summary: msg 10
146 summary: msg 10
147
147
148 changeset: 9:eb44510ef29a
148 changeset: 9:eb44510ef29a
149 user: test
149 user: test
150 date: Thu Jan 01 00:00:09 1970 +0000
150 date: Thu Jan 01 00:00:09 1970 +0000
151 summary: msg 9
151 summary: msg 9
152
152
153 changeset: 8:453eb4dba229
153 changeset: 8:453eb4dba229
154 user: test
154 user: test
155 date: Thu Jan 01 00:00:08 1970 +0000
155 date: Thu Jan 01 00:00:08 1970 +0000
156 summary: msg 8
156 summary: msg 8
157
157
158 changeset: 7:03750880c6b5
158 changeset: 7:03750880c6b5
159 user: test
159 user: test
160 date: Thu Jan 01 00:00:07 1970 +0000
160 date: Thu Jan 01 00:00:07 1970 +0000
161 summary: msg 7
161 summary: msg 7
162
162
163 changeset: 6:a3d5c6fdf0d3
163 changeset: 6:a3d5c6fdf0d3
164 user: test
164 user: test
165 date: Thu Jan 01 00:00:06 1970 +0000
165 date: Thu Jan 01 00:00:06 1970 +0000
166 summary: msg 6
166 summary: msg 6
167
167
168 changeset: 5:7874a09ea728
168 changeset: 5:7874a09ea728
169 user: test
169 user: test
170 date: Thu Jan 01 00:00:05 1970 +0000
170 date: Thu Jan 01 00:00:05 1970 +0000
171 summary: msg 5
171 summary: msg 5
172
172
173 changeset: 4:9b2ba8336a65
173 changeset: 4:9b2ba8336a65
174 user: test
174 user: test
175 date: Thu Jan 01 00:00:04 1970 +0000
175 date: Thu Jan 01 00:00:04 1970 +0000
176 summary: msg 4
176 summary: msg 4
177
177
178 changeset: 3:b53bea5e2fcb
178 changeset: 3:b53bea5e2fcb
179 user: test
179 user: test
180 date: Thu Jan 01 00:00:03 1970 +0000
180 date: Thu Jan 01 00:00:03 1970 +0000
181 summary: msg 3
181 summary: msg 3
182
182
183 changeset: 2:db07c04beaca
183 changeset: 2:db07c04beaca
184 user: test
184 user: test
185 date: Thu Jan 01 00:00:02 1970 +0000
185 date: Thu Jan 01 00:00:02 1970 +0000
186 summary: msg 2
186 summary: msg 2
187
187
188 changeset: 1:5cd978ea5149
188 changeset: 1:5cd978ea5149
189 user: test
189 user: test
190 date: Thu Jan 01 00:00:01 1970 +0000
190 date: Thu Jan 01 00:00:01 1970 +0000
191 summary: msg 1
191 summary: msg 1
192
192
193 changeset: 0:b99c7b9c8e11
193 changeset: 0:b99c7b9c8e11
194 user: test
194 user: test
195 date: Thu Jan 01 00:00:00 1970 +0000
195 date: Thu Jan 01 00:00:00 1970 +0000
196 summary: msg 0
196 summary: msg 0
197
197
198 % hg up -C
198 % hg up -C
199 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
199 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
200 % bisect test
200 % bisect test
201 Testing changeset 16:a2e6ea4973e9 (30 changesets remaining, ~4 tests)
201 Testing changeset 16:a2e6ea4973e9 (30 changesets remaining, ~4 tests)
202 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
202 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
203 Testing changeset 23:5ec79163bff4 (15 changesets remaining, ~3 tests)
203 Testing changeset 23:5ec79163bff4 (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 Testing changeset 27:288867a866e9 (8 changesets remaining, ~3 tests)
205 Testing changeset 27:288867a866e9 (8 changesets remaining, ~3 tests)
206 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
206 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
207 Testing changeset 29:b5bd63375ab9 (4 changesets remaining, ~2 tests)
207 Testing changeset 29:b5bd63375ab9 (4 changesets remaining, ~2 tests)
208 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
208 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
209 Testing changeset 28:8e0c2264c8af (2 changesets remaining, ~1 tests)
209 Testing changeset 28:8e0c2264c8af (2 changesets remaining, ~1 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 The first bad revision is:
211 The first bad revision is:
212 changeset: 29:b5bd63375ab9
212 changeset: 29:b5bd63375ab9
213 user: test
213 user: test
214 date: Thu Jan 01 00:00:29 1970 +0000
214 date: Thu Jan 01 00:00:29 1970 +0000
215 summary: msg 29
215 summary: msg 29
216
216
217 % bisect reverse test
218 Testing changeset 15:e7fa0811edb0 (32 changesets remaining, ~5 tests)
219 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
220 Testing changeset 7:03750880c6b5 (16 changesets remaining, ~4 tests)
221 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
222 Testing changeset 3:b53bea5e2fcb (8 changesets remaining, ~3 tests)
223 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
224 Testing changeset 1:5cd978ea5149 (4 changesets remaining, ~2 tests)
225 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
226 Testing changeset 2:db07c04beaca (2 changesets remaining, ~1 tests)
227 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
228 The first good revision is:
229 changeset: 2:db07c04beaca
230 user: test
231 date: Thu Jan 01 00:00:02 1970 +0000
232 summary: msg 2
233
General Comments 0
You need to be logged in to leave comments. Login now