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