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