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