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