##// END OF EJS Templates
Updated help text for 'hg log'.
Thomas Arendsen Hein -
r1557:f7d9823e default
parent child Browse files
Show More
@@ -1,2658 +1,2658 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 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 demandload import demandload
8 from demandload import demandload
9 from node import *
9 from node import *
10 from i18n import gettext as _
10 from i18n import gettext as _
11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
12 demandload(globals(), "fancyopts ui hg util lock revlog")
12 demandload(globals(), "fancyopts ui hg util lock revlog")
13 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
13 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
14 demandload(globals(), "errno socket version struct atexit sets bz2")
14 demandload(globals(), "errno socket version struct atexit sets bz2")
15
15
16 class UnknownCommand(Exception):
16 class UnknownCommand(Exception):
17 """Exception raised if command is not in the command table."""
17 """Exception raised if command is not in the command table."""
18 class AmbiguousCommand(Exception):
18 class AmbiguousCommand(Exception):
19 """Exception raised if command shortcut matches more than one command."""
19 """Exception raised if command shortcut matches more than one command."""
20
20
21 def filterfiles(filters, files):
21 def filterfiles(filters, files):
22 l = [x for x in files if x in filters]
22 l = [x for x in files if x in filters]
23
23
24 for t in filters:
24 for t in filters:
25 if t and t[-1] != "/":
25 if t and t[-1] != "/":
26 t += "/"
26 t += "/"
27 l += [x for x in files if x.startswith(t)]
27 l += [x for x in files if x.startswith(t)]
28 return l
28 return l
29
29
30 def relpath(repo, args):
30 def relpath(repo, args):
31 cwd = repo.getcwd()
31 cwd = repo.getcwd()
32 if cwd:
32 if cwd:
33 return [util.normpath(os.path.join(cwd, x)) for x in args]
33 return [util.normpath(os.path.join(cwd, x)) for x in args]
34 return args
34 return args
35
35
36 def matchpats(repo, cwd, pats=[], opts={}, head=''):
36 def matchpats(repo, cwd, pats=[], opts={}, head=''):
37 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
37 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
38 opts.get('exclude'), head)
38 opts.get('exclude'), head)
39
39
40 def makewalk(repo, pats, opts, head=''):
40 def makewalk(repo, pats, opts, head=''):
41 cwd = repo.getcwd()
41 cwd = repo.getcwd()
42 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
42 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
43 exact = dict(zip(files, files))
43 exact = dict(zip(files, files))
44 def walk():
44 def walk():
45 for src, fn in repo.walk(files=files, match=matchfn):
45 for src, fn in repo.walk(files=files, match=matchfn):
46 yield src, fn, util.pathto(cwd, fn), fn in exact
46 yield src, fn, util.pathto(cwd, fn), fn in exact
47 return files, matchfn, walk()
47 return files, matchfn, walk()
48
48
49 def walk(repo, pats, opts, head=''):
49 def walk(repo, pats, opts, head=''):
50 files, matchfn, results = makewalk(repo, pats, opts, head)
50 files, matchfn, results = makewalk(repo, pats, opts, head)
51 for r in results:
51 for r in results:
52 yield r
52 yield r
53
53
54 def walkchangerevs(ui, repo, cwd, pats, opts):
54 def walkchangerevs(ui, repo, cwd, pats, opts):
55 '''Iterate over files and the revs they changed in.
55 '''Iterate over files and the revs they changed in.
56
56
57 Callers most commonly need to iterate backwards over the history
57 Callers most commonly need to iterate backwards over the history
58 it is interested in. Doing so has awful (quadratic-looking)
58 it is interested in. Doing so has awful (quadratic-looking)
59 performance, so we use iterators in a "windowed" way.
59 performance, so we use iterators in a "windowed" way.
60
60
61 We walk a window of revisions in the desired order. Within the
61 We walk a window of revisions in the desired order. Within the
62 window, we first walk forwards to gather data, then in the desired
62 window, we first walk forwards to gather data, then in the desired
63 order (usually backwards) to display it.
63 order (usually backwards) to display it.
64
64
65 This function returns an (iterator, getchange) pair. The
65 This function returns an (iterator, getchange) pair. The
66 getchange function returns the changelog entry for a numeric
66 getchange function returns the changelog entry for a numeric
67 revision. The iterator yields 3-tuples. They will be of one of
67 revision. The iterator yields 3-tuples. They will be of one of
68 the following forms:
68 the following forms:
69
69
70 "window", incrementing, lastrev: stepping through a window,
70 "window", incrementing, lastrev: stepping through a window,
71 positive if walking forwards through revs, last rev in the
71 positive if walking forwards through revs, last rev in the
72 sequence iterated over - use to reset state for the current window
72 sequence iterated over - use to reset state for the current window
73
73
74 "add", rev, fns: out-of-order traversal of the given file names
74 "add", rev, fns: out-of-order traversal of the given file names
75 fns, which changed during revision rev - use to gather data for
75 fns, which changed during revision rev - use to gather data for
76 possible display
76 possible display
77
77
78 "iter", rev, None: in-order traversal of the revs earlier iterated
78 "iter", rev, None: in-order traversal of the revs earlier iterated
79 over with "add" - use to display data'''
79 over with "add" - use to display data'''
80
80
81 if repo.changelog.count() == 0:
81 if repo.changelog.count() == 0:
82 return [], False
82 return [], False
83
83
84 cwd = repo.getcwd()
84 cwd = repo.getcwd()
85 if not pats and cwd:
85 if not pats and cwd:
86 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
86 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
87 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
87 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
88 files, matchfn, anypats = matchpats(repo, (pats and cwd) or '',
88 files, matchfn, anypats = matchpats(repo, (pats and cwd) or '',
89 pats, opts)
89 pats, opts)
90 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
90 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
91 wanted = {}
91 wanted = {}
92 slowpath = anypats
92 slowpath = anypats
93 window = 300
93 window = 300
94 fncache = {}
94 fncache = {}
95
95
96 chcache = {}
96 chcache = {}
97 def getchange(rev):
97 def getchange(rev):
98 ch = chcache.get(rev)
98 ch = chcache.get(rev)
99 if ch is None:
99 if ch is None:
100 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
100 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
101 return ch
101 return ch
102
102
103 if not slowpath and not files:
103 if not slowpath and not files:
104 # No files, no patterns. Display all revs.
104 # No files, no patterns. Display all revs.
105 wanted = dict(zip(revs, revs))
105 wanted = dict(zip(revs, revs))
106 if not slowpath:
106 if not slowpath:
107 # Only files, no patterns. Check the history of each file.
107 # Only files, no patterns. Check the history of each file.
108 def filerevgen(filelog):
108 def filerevgen(filelog):
109 for i in xrange(filelog.count() - 1, -1, -window):
109 for i in xrange(filelog.count() - 1, -1, -window):
110 revs = []
110 revs = []
111 for j in xrange(max(0, i - window), i + 1):
111 for j in xrange(max(0, i - window), i + 1):
112 revs.append(filelog.linkrev(filelog.node(j)))
112 revs.append(filelog.linkrev(filelog.node(j)))
113 revs.reverse()
113 revs.reverse()
114 for rev in revs:
114 for rev in revs:
115 yield rev
115 yield rev
116
116
117 minrev, maxrev = min(revs), max(revs)
117 minrev, maxrev = min(revs), max(revs)
118 for file in files:
118 for file in files:
119 filelog = repo.file(file)
119 filelog = repo.file(file)
120 # A zero count may be a directory or deleted file, so
120 # A zero count may be a directory or deleted file, so
121 # try to find matching entries on the slow path.
121 # try to find matching entries on the slow path.
122 if filelog.count() == 0:
122 if filelog.count() == 0:
123 slowpath = True
123 slowpath = True
124 break
124 break
125 for rev in filerevgen(filelog):
125 for rev in filerevgen(filelog):
126 if rev <= maxrev:
126 if rev <= maxrev:
127 if rev < minrev:
127 if rev < minrev:
128 break
128 break
129 fncache.setdefault(rev, [])
129 fncache.setdefault(rev, [])
130 fncache[rev].append(file)
130 fncache[rev].append(file)
131 wanted[rev] = 1
131 wanted[rev] = 1
132 if slowpath:
132 if slowpath:
133 # The slow path checks files modified in every changeset.
133 # The slow path checks files modified in every changeset.
134 def changerevgen():
134 def changerevgen():
135 for i in xrange(repo.changelog.count() - 1, -1, -window):
135 for i in xrange(repo.changelog.count() - 1, -1, -window):
136 for j in xrange(max(0, i - window), i + 1):
136 for j in xrange(max(0, i - window), i + 1):
137 yield j, getchange(j)[3]
137 yield j, getchange(j)[3]
138
138
139 for rev, changefiles in changerevgen():
139 for rev, changefiles in changerevgen():
140 matches = filter(matchfn, changefiles)
140 matches = filter(matchfn, changefiles)
141 if matches:
141 if matches:
142 fncache[rev] = matches
142 fncache[rev] = matches
143 wanted[rev] = 1
143 wanted[rev] = 1
144
144
145 def iterate():
145 def iterate():
146 for i in xrange(0, len(revs), window):
146 for i in xrange(0, len(revs), window):
147 yield 'window', revs[0] < revs[-1], revs[-1]
147 yield 'window', revs[0] < revs[-1], revs[-1]
148 nrevs = [rev for rev in revs[i:min(i+window, len(revs))]
148 nrevs = [rev for rev in revs[i:min(i+window, len(revs))]
149 if rev in wanted]
149 if rev in wanted]
150 srevs = list(nrevs)
150 srevs = list(nrevs)
151 srevs.sort()
151 srevs.sort()
152 for rev in srevs:
152 for rev in srevs:
153 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
153 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
154 yield 'add', rev, fns
154 yield 'add', rev, fns
155 for rev in nrevs:
155 for rev in nrevs:
156 yield 'iter', rev, None
156 yield 'iter', rev, None
157 return iterate(), getchange
157 return iterate(), getchange
158
158
159 revrangesep = ':'
159 revrangesep = ':'
160
160
161 def revrange(ui, repo, revs, revlog=None):
161 def revrange(ui, repo, revs, revlog=None):
162 """Yield revision as strings from a list of revision specifications."""
162 """Yield revision as strings from a list of revision specifications."""
163 if revlog is None:
163 if revlog is None:
164 revlog = repo.changelog
164 revlog = repo.changelog
165 revcount = revlog.count()
165 revcount = revlog.count()
166 def fix(val, defval):
166 def fix(val, defval):
167 if not val:
167 if not val:
168 return defval
168 return defval
169 try:
169 try:
170 num = int(val)
170 num = int(val)
171 if str(num) != val:
171 if str(num) != val:
172 raise ValueError
172 raise ValueError
173 if num < 0: num += revcount
173 if num < 0: num += revcount
174 if num < 0: num = 0
174 if num < 0: num = 0
175 elif num >= revcount:
175 elif num >= revcount:
176 raise ValueError
176 raise ValueError
177 except ValueError:
177 except ValueError:
178 try:
178 try:
179 num = repo.changelog.rev(repo.lookup(val))
179 num = repo.changelog.rev(repo.lookup(val))
180 except KeyError:
180 except KeyError:
181 try:
181 try:
182 num = revlog.rev(revlog.lookup(val))
182 num = revlog.rev(revlog.lookup(val))
183 except KeyError:
183 except KeyError:
184 raise util.Abort(_('invalid revision identifier %s'), val)
184 raise util.Abort(_('invalid revision identifier %s'), val)
185 return num
185 return num
186 seen = {}
186 seen = {}
187 for spec in revs:
187 for spec in revs:
188 if spec.find(revrangesep) >= 0:
188 if spec.find(revrangesep) >= 0:
189 start, end = spec.split(revrangesep, 1)
189 start, end = spec.split(revrangesep, 1)
190 start = fix(start, 0)
190 start = fix(start, 0)
191 end = fix(end, revcount - 1)
191 end = fix(end, revcount - 1)
192 step = start > end and -1 or 1
192 step = start > end and -1 or 1
193 for rev in xrange(start, end+step, step):
193 for rev in xrange(start, end+step, step):
194 if rev in seen: continue
194 if rev in seen: continue
195 seen[rev] = 1
195 seen[rev] = 1
196 yield str(rev)
196 yield str(rev)
197 else:
197 else:
198 rev = fix(spec, None)
198 rev = fix(spec, None)
199 if rev in seen: continue
199 if rev in seen: continue
200 seen[rev] = 1
200 seen[rev] = 1
201 yield str(rev)
201 yield str(rev)
202
202
203 def make_filename(repo, r, pat, node=None,
203 def make_filename(repo, r, pat, node=None,
204 total=None, seqno=None, revwidth=None, pathname=None):
204 total=None, seqno=None, revwidth=None, pathname=None):
205 node_expander = {
205 node_expander = {
206 'H': lambda: hex(node),
206 'H': lambda: hex(node),
207 'R': lambda: str(r.rev(node)),
207 'R': lambda: str(r.rev(node)),
208 'h': lambda: short(node),
208 'h': lambda: short(node),
209 }
209 }
210 expander = {
210 expander = {
211 '%': lambda: '%',
211 '%': lambda: '%',
212 'b': lambda: os.path.basename(repo.root),
212 'b': lambda: os.path.basename(repo.root),
213 }
213 }
214
214
215 try:
215 try:
216 if node:
216 if node:
217 expander.update(node_expander)
217 expander.update(node_expander)
218 if node and revwidth is not None:
218 if node and revwidth is not None:
219 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
219 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
220 if total is not None:
220 if total is not None:
221 expander['N'] = lambda: str(total)
221 expander['N'] = lambda: str(total)
222 if seqno is not None:
222 if seqno is not None:
223 expander['n'] = lambda: str(seqno)
223 expander['n'] = lambda: str(seqno)
224 if total is not None and seqno is not None:
224 if total is not None and seqno is not None:
225 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
225 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
226 if pathname is not None:
226 if pathname is not None:
227 expander['s'] = lambda: os.path.basename(pathname)
227 expander['s'] = lambda: os.path.basename(pathname)
228 expander['d'] = lambda: os.path.dirname(pathname) or '.'
228 expander['d'] = lambda: os.path.dirname(pathname) or '.'
229 expander['p'] = lambda: pathname
229 expander['p'] = lambda: pathname
230
230
231 newname = []
231 newname = []
232 patlen = len(pat)
232 patlen = len(pat)
233 i = 0
233 i = 0
234 while i < patlen:
234 while i < patlen:
235 c = pat[i]
235 c = pat[i]
236 if c == '%':
236 if c == '%':
237 i += 1
237 i += 1
238 c = pat[i]
238 c = pat[i]
239 c = expander[c]()
239 c = expander[c]()
240 newname.append(c)
240 newname.append(c)
241 i += 1
241 i += 1
242 return ''.join(newname)
242 return ''.join(newname)
243 except KeyError, inst:
243 except KeyError, inst:
244 raise util.Abort(_("invalid format spec '%%%s' in output file name"),
244 raise util.Abort(_("invalid format spec '%%%s' in output file name"),
245 inst.args[0])
245 inst.args[0])
246
246
247 def make_file(repo, r, pat, node=None,
247 def make_file(repo, r, pat, node=None,
248 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
248 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
249 if not pat or pat == '-':
249 if not pat or pat == '-':
250 return 'w' in mode and sys.stdout or sys.stdin
250 return 'w' in mode and sys.stdout or sys.stdin
251 if hasattr(pat, 'write') and 'w' in mode:
251 if hasattr(pat, 'write') and 'w' in mode:
252 return pat
252 return pat
253 if hasattr(pat, 'read') and 'r' in mode:
253 if hasattr(pat, 'read') and 'r' in mode:
254 return pat
254 return pat
255 return open(make_filename(repo, r, pat, node, total, seqno, revwidth,
255 return open(make_filename(repo, r, pat, node, total, seqno, revwidth,
256 pathname),
256 pathname),
257 mode)
257 mode)
258
258
259 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
259 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
260 changes=None, text=False):
260 changes=None, text=False):
261 if not changes:
261 if not changes:
262 (c, a, d, u) = repo.changes(node1, node2, files, match=match)
262 (c, a, d, u) = repo.changes(node1, node2, files, match=match)
263 else:
263 else:
264 (c, a, d, u) = changes
264 (c, a, d, u) = changes
265 if files:
265 if files:
266 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
266 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
267
267
268 if not c and not a and not d:
268 if not c and not a and not d:
269 return
269 return
270
270
271 if node2:
271 if node2:
272 change = repo.changelog.read(node2)
272 change = repo.changelog.read(node2)
273 mmap2 = repo.manifest.read(change[0])
273 mmap2 = repo.manifest.read(change[0])
274 date2 = util.datestr(change[2])
274 date2 = util.datestr(change[2])
275 def read(f):
275 def read(f):
276 return repo.file(f).read(mmap2[f])
276 return repo.file(f).read(mmap2[f])
277 else:
277 else:
278 date2 = util.datestr()
278 date2 = util.datestr()
279 if not node1:
279 if not node1:
280 node1 = repo.dirstate.parents()[0]
280 node1 = repo.dirstate.parents()[0]
281 def read(f):
281 def read(f):
282 return repo.wfile(f).read()
282 return repo.wfile(f).read()
283
283
284 if ui.quiet:
284 if ui.quiet:
285 r = None
285 r = None
286 else:
286 else:
287 hexfunc = ui.verbose and hex or short
287 hexfunc = ui.verbose and hex or short
288 r = [hexfunc(node) for node in [node1, node2] if node]
288 r = [hexfunc(node) for node in [node1, node2] if node]
289
289
290 change = repo.changelog.read(node1)
290 change = repo.changelog.read(node1)
291 mmap = repo.manifest.read(change[0])
291 mmap = repo.manifest.read(change[0])
292 date1 = util.datestr(change[2])
292 date1 = util.datestr(change[2])
293
293
294 for f in c:
294 for f in c:
295 to = None
295 to = None
296 if f in mmap:
296 if f in mmap:
297 to = repo.file(f).read(mmap[f])
297 to = repo.file(f).read(mmap[f])
298 tn = read(f)
298 tn = read(f)
299 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
299 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
300 for f in a:
300 for f in a:
301 to = None
301 to = None
302 tn = read(f)
302 tn = read(f)
303 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
303 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
304 for f in d:
304 for f in d:
305 to = repo.file(f).read(mmap[f])
305 to = repo.file(f).read(mmap[f])
306 tn = None
306 tn = None
307 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
307 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
308
308
309 def trimuser(ui, name, rev, revcache):
309 def trimuser(ui, name, rev, revcache):
310 """trim the name of the user who committed a change"""
310 """trim the name of the user who committed a change"""
311 user = revcache.get(rev)
311 user = revcache.get(rev)
312 if user is None:
312 if user is None:
313 user = revcache[rev] = ui.shortuser(name)
313 user = revcache[rev] = ui.shortuser(name)
314 return user
314 return user
315
315
316 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
316 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
317 """show a single changeset or file revision"""
317 """show a single changeset or file revision"""
318 log = repo.changelog
318 log = repo.changelog
319 if changenode is None:
319 if changenode is None:
320 changenode = log.node(rev)
320 changenode = log.node(rev)
321 elif not rev:
321 elif not rev:
322 rev = log.rev(changenode)
322 rev = log.rev(changenode)
323
323
324 if ui.quiet:
324 if ui.quiet:
325 ui.write("%d:%s\n" % (rev, short(changenode)))
325 ui.write("%d:%s\n" % (rev, short(changenode)))
326 return
326 return
327
327
328 changes = log.read(changenode)
328 changes = log.read(changenode)
329 date = util.datestr(changes[2])
329 date = util.datestr(changes[2])
330
330
331 parents = [(log.rev(p), ui.verbose and hex(p) or short(p))
331 parents = [(log.rev(p), ui.verbose and hex(p) or short(p))
332 for p in log.parents(changenode)
332 for p in log.parents(changenode)
333 if ui.debugflag or p != nullid]
333 if ui.debugflag or p != nullid]
334 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
334 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
335 parents = []
335 parents = []
336
336
337 if ui.verbose:
337 if ui.verbose:
338 ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode)))
338 ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode)))
339 else:
339 else:
340 ui.write(_("changeset: %d:%s\n") % (rev, short(changenode)))
340 ui.write(_("changeset: %d:%s\n") % (rev, short(changenode)))
341
341
342 for tag in repo.nodetags(changenode):
342 for tag in repo.nodetags(changenode):
343 ui.status(_("tag: %s\n") % tag)
343 ui.status(_("tag: %s\n") % tag)
344 for parent in parents:
344 for parent in parents:
345 ui.write(_("parent: %d:%s\n") % parent)
345 ui.write(_("parent: %d:%s\n") % parent)
346
346
347 if brinfo and changenode in brinfo:
347 if brinfo and changenode in brinfo:
348 br = brinfo[changenode]
348 br = brinfo[changenode]
349 ui.write(_("branch: %s\n") % " ".join(br))
349 ui.write(_("branch: %s\n") % " ".join(br))
350
350
351 ui.debug(_("manifest: %d:%s\n") % (repo.manifest.rev(changes[0]),
351 ui.debug(_("manifest: %d:%s\n") % (repo.manifest.rev(changes[0]),
352 hex(changes[0])))
352 hex(changes[0])))
353 ui.status(_("user: %s\n") % changes[1])
353 ui.status(_("user: %s\n") % changes[1])
354 ui.status(_("date: %s\n") % date)
354 ui.status(_("date: %s\n") % date)
355
355
356 if ui.debugflag:
356 if ui.debugflag:
357 files = repo.changes(log.parents(changenode)[0], changenode)
357 files = repo.changes(log.parents(changenode)[0], changenode)
358 for key, value in zip([_("files:"), _("files+:"), _("files-:")], files):
358 for key, value in zip([_("files:"), _("files+:"), _("files-:")], files):
359 if value:
359 if value:
360 ui.note("%-12s %s\n" % (key, " ".join(value)))
360 ui.note("%-12s %s\n" % (key, " ".join(value)))
361 else:
361 else:
362 ui.note(_("files: %s\n") % " ".join(changes[3]))
362 ui.note(_("files: %s\n") % " ".join(changes[3]))
363
363
364 description = changes[4].strip()
364 description = changes[4].strip()
365 if description:
365 if description:
366 if ui.verbose:
366 if ui.verbose:
367 ui.status(_("description:\n"))
367 ui.status(_("description:\n"))
368 ui.status(description)
368 ui.status(description)
369 ui.status("\n\n")
369 ui.status("\n\n")
370 else:
370 else:
371 ui.status(_("summary: %s\n") % description.splitlines()[0])
371 ui.status(_("summary: %s\n") % description.splitlines()[0])
372 ui.status("\n")
372 ui.status("\n")
373
373
374 def show_version(ui):
374 def show_version(ui):
375 """output version and copyright information"""
375 """output version and copyright information"""
376 ui.write(_("Mercurial Distributed SCM (version %s)\n")
376 ui.write(_("Mercurial Distributed SCM (version %s)\n")
377 % version.get_version())
377 % version.get_version())
378 ui.status(_(
378 ui.status(_(
379 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
379 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
380 "This is free software; see the source for copying conditions. "
380 "This is free software; see the source for copying conditions. "
381 "There is NO\nwarranty; "
381 "There is NO\nwarranty; "
382 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
382 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
383 ))
383 ))
384
384
385 def help_(ui, cmd=None, with_version=False):
385 def help_(ui, cmd=None, with_version=False):
386 """show help for a given command or all commands"""
386 """show help for a given command or all commands"""
387 option_lists = []
387 option_lists = []
388 if cmd and cmd != 'shortlist':
388 if cmd and cmd != 'shortlist':
389 if with_version:
389 if with_version:
390 show_version(ui)
390 show_version(ui)
391 ui.write('\n')
391 ui.write('\n')
392 aliases, i = find(cmd)
392 aliases, i = find(cmd)
393 # synopsis
393 # synopsis
394 ui.write("%s\n\n" % i[2])
394 ui.write("%s\n\n" % i[2])
395
395
396 # description
396 # description
397 doc = i[0].__doc__
397 doc = i[0].__doc__
398 if ui.quiet:
398 if ui.quiet:
399 doc = doc.splitlines(0)[0]
399 doc = doc.splitlines(0)[0]
400 ui.write("%s\n" % doc.rstrip())
400 ui.write("%s\n" % doc.rstrip())
401
401
402 if not ui.quiet:
402 if not ui.quiet:
403 # aliases
403 # aliases
404 if len(aliases) > 1:
404 if len(aliases) > 1:
405 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
405 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
406
406
407 # options
407 # options
408 if i[1]:
408 if i[1]:
409 option_lists.append(("options", i[1]))
409 option_lists.append(("options", i[1]))
410
410
411 else:
411 else:
412 # program name
412 # program name
413 if ui.verbose or with_version:
413 if ui.verbose or with_version:
414 show_version(ui)
414 show_version(ui)
415 else:
415 else:
416 ui.status(_("Mercurial Distributed SCM\n"))
416 ui.status(_("Mercurial Distributed SCM\n"))
417 ui.status('\n')
417 ui.status('\n')
418
418
419 # list of commands
419 # list of commands
420 if cmd == "shortlist":
420 if cmd == "shortlist":
421 ui.status(_('basic commands (use "hg help" '
421 ui.status(_('basic commands (use "hg help" '
422 'for the full list or option "-v" for details):\n\n'))
422 'for the full list or option "-v" for details):\n\n'))
423 elif ui.verbose:
423 elif ui.verbose:
424 ui.status(_('list of commands:\n\n'))
424 ui.status(_('list of commands:\n\n'))
425 else:
425 else:
426 ui.status(_('list of commands (use "hg help -v" '
426 ui.status(_('list of commands (use "hg help -v" '
427 'to show aliases and global options):\n\n'))
427 'to show aliases and global options):\n\n'))
428
428
429 h = {}
429 h = {}
430 cmds = {}
430 cmds = {}
431 for c, e in table.items():
431 for c, e in table.items():
432 f = c.split("|")[0]
432 f = c.split("|")[0]
433 if cmd == "shortlist" and not f.startswith("^"):
433 if cmd == "shortlist" and not f.startswith("^"):
434 continue
434 continue
435 f = f.lstrip("^")
435 f = f.lstrip("^")
436 if not ui.debugflag and f.startswith("debug"):
436 if not ui.debugflag and f.startswith("debug"):
437 continue
437 continue
438 d = ""
438 d = ""
439 if e[0].__doc__:
439 if e[0].__doc__:
440 d = e[0].__doc__.splitlines(0)[0].rstrip()
440 d = e[0].__doc__.splitlines(0)[0].rstrip()
441 h[f] = d
441 h[f] = d
442 cmds[f]=c.lstrip("^")
442 cmds[f]=c.lstrip("^")
443
443
444 fns = h.keys()
444 fns = h.keys()
445 fns.sort()
445 fns.sort()
446 m = max(map(len, fns))
446 m = max(map(len, fns))
447 for f in fns:
447 for f in fns:
448 if ui.verbose:
448 if ui.verbose:
449 commands = cmds[f].replace("|",", ")
449 commands = cmds[f].replace("|",", ")
450 ui.write(" %s:\n %s\n"%(commands,h[f]))
450 ui.write(" %s:\n %s\n"%(commands,h[f]))
451 else:
451 else:
452 ui.write(' %-*s %s\n' % (m, f, h[f]))
452 ui.write(' %-*s %s\n' % (m, f, h[f]))
453
453
454 # global options
454 # global options
455 if ui.verbose:
455 if ui.verbose:
456 option_lists.append(("global options", globalopts))
456 option_lists.append(("global options", globalopts))
457
457
458 # list all option lists
458 # list all option lists
459 opt_output = []
459 opt_output = []
460 for title, options in option_lists:
460 for title, options in option_lists:
461 opt_output.append(("\n%s:\n" % title, None))
461 opt_output.append(("\n%s:\n" % title, None))
462 for shortopt, longopt, default, desc in options:
462 for shortopt, longopt, default, desc in options:
463 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
463 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
464 longopt and " --%s" % longopt),
464 longopt and " --%s" % longopt),
465 "%s%s" % (desc,
465 "%s%s" % (desc,
466 default and _(" (default: %s)") % default
466 default and _(" (default: %s)") % default
467 or "")))
467 or "")))
468
468
469 if opt_output:
469 if opt_output:
470 opts_len = max([len(line[0]) for line in opt_output if line[1]])
470 opts_len = max([len(line[0]) for line in opt_output if line[1]])
471 for first, second in opt_output:
471 for first, second in opt_output:
472 if second:
472 if second:
473 ui.write(" %-*s %s\n" % (opts_len, first, second))
473 ui.write(" %-*s %s\n" % (opts_len, first, second))
474 else:
474 else:
475 ui.write("%s\n" % first)
475 ui.write("%s\n" % first)
476
476
477 # Commands start here, listed alphabetically
477 # Commands start here, listed alphabetically
478
478
479 def add(ui, repo, *pats, **opts):
479 def add(ui, repo, *pats, **opts):
480 """add the specified files on the next commit
480 """add the specified files on the next commit
481
481
482 Schedule files to be version controlled and added to the repository.
482 Schedule files to be version controlled and added to the repository.
483
483
484 The files will be added to the repository at the next commit.
484 The files will be added to the repository at the next commit.
485
485
486 If no names are given, add all files in the current directory and
486 If no names are given, add all files in the current directory and
487 its subdirectories.
487 its subdirectories.
488 """
488 """
489
489
490 names = []
490 names = []
491 for src, abs, rel, exact in walk(repo, pats, opts):
491 for src, abs, rel, exact in walk(repo, pats, opts):
492 if exact:
492 if exact:
493 if ui.verbose: ui.status(_('adding %s\n') % rel)
493 if ui.verbose: ui.status(_('adding %s\n') % rel)
494 names.append(abs)
494 names.append(abs)
495 elif repo.dirstate.state(abs) == '?':
495 elif repo.dirstate.state(abs) == '?':
496 ui.status(_('adding %s\n') % rel)
496 ui.status(_('adding %s\n') % rel)
497 names.append(abs)
497 names.append(abs)
498 repo.add(names)
498 repo.add(names)
499
499
500 def addremove(ui, repo, *pats, **opts):
500 def addremove(ui, repo, *pats, **opts):
501 """add all new files, delete all missing files
501 """add all new files, delete all missing files
502
502
503 Add all new files and remove all missing files from the repository.
503 Add all new files and remove all missing files from the repository.
504
504
505 New files are ignored if they match any of the patterns in .hgignore. As
505 New files are ignored if they match any of the patterns in .hgignore. As
506 with add, these changes take effect at the next commit.
506 with add, these changes take effect at the next commit.
507 """
507 """
508 add, remove = [], []
508 add, remove = [], []
509 for src, abs, rel, exact in walk(repo, pats, opts):
509 for src, abs, rel, exact in walk(repo, pats, opts):
510 if src == 'f' and repo.dirstate.state(abs) == '?':
510 if src == 'f' and repo.dirstate.state(abs) == '?':
511 add.append(abs)
511 add.append(abs)
512 if ui.verbose or not exact:
512 if ui.verbose or not exact:
513 ui.status(_('adding %s\n') % rel)
513 ui.status(_('adding %s\n') % rel)
514 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
514 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
515 remove.append(abs)
515 remove.append(abs)
516 if ui.verbose or not exact:
516 if ui.verbose or not exact:
517 ui.status(_('removing %s\n') % rel)
517 ui.status(_('removing %s\n') % rel)
518 repo.add(add)
518 repo.add(add)
519 repo.remove(remove)
519 repo.remove(remove)
520
520
521 def annotate(ui, repo, *pats, **opts):
521 def annotate(ui, repo, *pats, **opts):
522 """show changeset information per file line
522 """show changeset information per file line
523
523
524 List changes in files, showing the revision id responsible for each line
524 List changes in files, showing the revision id responsible for each line
525
525
526 This command is useful to discover who did a change or when a change took
526 This command is useful to discover who did a change or when a change took
527 place.
527 place.
528
528
529 Without the -a option, annotate will avoid processing files it
529 Without the -a option, annotate will avoid processing files it
530 detects as binary. With -a, annotate will generate an annotation
530 detects as binary. With -a, annotate will generate an annotation
531 anyway, probably with undesirable results.
531 anyway, probably with undesirable results.
532 """
532 """
533 def getnode(rev):
533 def getnode(rev):
534 return short(repo.changelog.node(rev))
534 return short(repo.changelog.node(rev))
535
535
536 ucache = {}
536 ucache = {}
537 def getname(rev):
537 def getname(rev):
538 cl = repo.changelog.read(repo.changelog.node(rev))
538 cl = repo.changelog.read(repo.changelog.node(rev))
539 return trimuser(ui, cl[1], rev, ucache)
539 return trimuser(ui, cl[1], rev, ucache)
540
540
541 dcache = {}
541 dcache = {}
542 def getdate(rev):
542 def getdate(rev):
543 datestr = dcache.get(rev)
543 datestr = dcache.get(rev)
544 if datestr is None:
544 if datestr is None:
545 cl = repo.changelog.read(repo.changelog.node(rev))
545 cl = repo.changelog.read(repo.changelog.node(rev))
546 datestr = dcache[rev] = util.datestr(cl[2])
546 datestr = dcache[rev] = util.datestr(cl[2])
547 return datestr
547 return datestr
548
548
549 if not pats:
549 if not pats:
550 raise util.Abort(_('at least one file name or pattern required'))
550 raise util.Abort(_('at least one file name or pattern required'))
551
551
552 opmap = [['user', getname], ['number', str], ['changeset', getnode],
552 opmap = [['user', getname], ['number', str], ['changeset', getnode],
553 ['date', getdate]]
553 ['date', getdate]]
554 if not opts['user'] and not opts['changeset'] and not opts['date']:
554 if not opts['user'] and not opts['changeset'] and not opts['date']:
555 opts['number'] = 1
555 opts['number'] = 1
556
556
557 if opts['rev']:
557 if opts['rev']:
558 node = repo.changelog.lookup(opts['rev'])
558 node = repo.changelog.lookup(opts['rev'])
559 else:
559 else:
560 node = repo.dirstate.parents()[0]
560 node = repo.dirstate.parents()[0]
561 change = repo.changelog.read(node)
561 change = repo.changelog.read(node)
562 mmap = repo.manifest.read(change[0])
562 mmap = repo.manifest.read(change[0])
563
563
564 for src, abs, rel, exact in walk(repo, pats, opts):
564 for src, abs, rel, exact in walk(repo, pats, opts):
565 if abs not in mmap:
565 if abs not in mmap:
566 ui.warn(_("warning: %s is not in the repository!\n") % rel)
566 ui.warn(_("warning: %s is not in the repository!\n") % rel)
567 continue
567 continue
568
568
569 f = repo.file(abs)
569 f = repo.file(abs)
570 if not opts['text'] and util.binary(f.read(mmap[abs])):
570 if not opts['text'] and util.binary(f.read(mmap[abs])):
571 ui.write(_("%s: binary file\n") % rel)
571 ui.write(_("%s: binary file\n") % rel)
572 continue
572 continue
573
573
574 lines = f.annotate(mmap[abs])
574 lines = f.annotate(mmap[abs])
575 pieces = []
575 pieces = []
576
576
577 for o, f in opmap:
577 for o, f in opmap:
578 if opts[o]:
578 if opts[o]:
579 l = [f(n) for n, dummy in lines]
579 l = [f(n) for n, dummy in lines]
580 if l:
580 if l:
581 m = max(map(len, l))
581 m = max(map(len, l))
582 pieces.append(["%*s" % (m, x) for x in l])
582 pieces.append(["%*s" % (m, x) for x in l])
583
583
584 if pieces:
584 if pieces:
585 for p, l in zip(zip(*pieces), lines):
585 for p, l in zip(zip(*pieces), lines):
586 ui.write("%s: %s" % (" ".join(p), l[1]))
586 ui.write("%s: %s" % (" ".join(p), l[1]))
587
587
588 def bundle(ui, repo, fname, dest="default-push", **opts):
588 def bundle(ui, repo, fname, dest="default-push", **opts):
589 """create a changegroup file
589 """create a changegroup file
590
590
591 Generate a compressed changegroup file collecting all changesets
591 Generate a compressed changegroup file collecting all changesets
592 not found in the other repository.
592 not found in the other repository.
593
593
594 This file can then be transferred using conventional means and
594 This file can then be transferred using conventional means and
595 applied to another repository with the unbundle command. This is
595 applied to another repository with the unbundle command. This is
596 useful when native push and pull are not available or when
596 useful when native push and pull are not available or when
597 exporting an entire repository is undesirable. The standard file
597 exporting an entire repository is undesirable. The standard file
598 extension is ".hg".
598 extension is ".hg".
599
599
600 Unlike import/export, this exactly preserves all changeset
600 Unlike import/export, this exactly preserves all changeset
601 contents including permissions, rename data, and revision history.
601 contents including permissions, rename data, and revision history.
602 """
602 """
603 f = open(fname, "wb")
603 f = open(fname, "wb")
604 dest = ui.expandpath(dest, repo.root)
604 dest = ui.expandpath(dest, repo.root)
605 other = hg.repository(ui, dest)
605 other = hg.repository(ui, dest)
606 o = repo.findoutgoing(other)
606 o = repo.findoutgoing(other)
607 cg = repo.changegroup(o)
607 cg = repo.changegroup(o)
608
608
609 try:
609 try:
610 f.write("HG10")
610 f.write("HG10")
611 z = bz2.BZ2Compressor(9)
611 z = bz2.BZ2Compressor(9)
612 while 1:
612 while 1:
613 chunk = cg.read(4096)
613 chunk = cg.read(4096)
614 if not chunk:
614 if not chunk:
615 break
615 break
616 f.write(z.compress(chunk))
616 f.write(z.compress(chunk))
617 f.write(z.flush())
617 f.write(z.flush())
618 except:
618 except:
619 os.unlink(fname)
619 os.unlink(fname)
620 raise
620 raise
621
621
622 def cat(ui, repo, file1, *pats, **opts):
622 def cat(ui, repo, file1, *pats, **opts):
623 """output the latest or given revisions of files
623 """output the latest or given revisions of files
624
624
625 Print the specified files as they were at the given revision.
625 Print the specified files as they were at the given revision.
626 If no revision is given then the tip is used.
626 If no revision is given then the tip is used.
627
627
628 Output may be to a file, in which case the name of the file is
628 Output may be to a file, in which case the name of the file is
629 given using a format string. The formatting rules are the same as
629 given using a format string. The formatting rules are the same as
630 for the export command, with the following additions:
630 for the export command, with the following additions:
631
631
632 %s basename of file being printed
632 %s basename of file being printed
633 %d dirname of file being printed, or '.' if in repo root
633 %d dirname of file being printed, or '.' if in repo root
634 %p root-relative path name of file being printed
634 %p root-relative path name of file being printed
635 """
635 """
636 mf = {}
636 mf = {}
637 rev = opts['rev']
637 rev = opts['rev']
638 if rev:
638 if rev:
639 change = repo.changelog.read(repo.lookup(rev))
639 change = repo.changelog.read(repo.lookup(rev))
640 mf = repo.manifest.read(change[0])
640 mf = repo.manifest.read(change[0])
641 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts):
641 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts):
642 r = repo.file(abs)
642 r = repo.file(abs)
643 if rev:
643 if rev:
644 try:
644 try:
645 n = mf[abs]
645 n = mf[abs]
646 except (hg.RepoError, KeyError):
646 except (hg.RepoError, KeyError):
647 try:
647 try:
648 n = r.lookup(rev)
648 n = r.lookup(rev)
649 except KeyError, inst:
649 except KeyError, inst:
650 raise util.Abort(_('cannot find file %s in rev %s'), rel, rev)
650 raise util.Abort(_('cannot find file %s in rev %s'), rel, rev)
651 else:
651 else:
652 n = r.tip()
652 n = r.tip()
653 fp = make_file(repo, r, opts['output'], node=n, pathname=abs)
653 fp = make_file(repo, r, opts['output'], node=n, pathname=abs)
654 fp.write(r.read(n))
654 fp.write(r.read(n))
655
655
656 def clone(ui, source, dest=None, **opts):
656 def clone(ui, source, dest=None, **opts):
657 """make a copy of an existing repository
657 """make a copy of an existing repository
658
658
659 Create a copy of an existing repository in a new directory.
659 Create a copy of an existing repository in a new directory.
660
660
661 If no destination directory name is specified, it defaults to the
661 If no destination directory name is specified, it defaults to the
662 basename of the source.
662 basename of the source.
663
663
664 The location of the source is added to the new repository's
664 The location of the source is added to the new repository's
665 .hg/hgrc file, as the default to be used for future pulls.
665 .hg/hgrc file, as the default to be used for future pulls.
666
666
667 For efficiency, hardlinks are used for cloning whenever the source
667 For efficiency, hardlinks are used for cloning whenever the source
668 and destination are on the same filesystem. Some filesystems,
668 and destination are on the same filesystem. Some filesystems,
669 such as AFS, implement hardlinking incorrectly, but do not report
669 such as AFS, implement hardlinking incorrectly, but do not report
670 errors. In these cases, use the --pull option to avoid
670 errors. In these cases, use the --pull option to avoid
671 hardlinking.
671 hardlinking.
672 """
672 """
673 if dest is None:
673 if dest is None:
674 dest = os.path.basename(os.path.normpath(source))
674 dest = os.path.basename(os.path.normpath(source))
675
675
676 if os.path.exists(dest):
676 if os.path.exists(dest):
677 raise util.Abort(_("destination '%s' already exists"), dest)
677 raise util.Abort(_("destination '%s' already exists"), dest)
678
678
679 dest = os.path.realpath(dest)
679 dest = os.path.realpath(dest)
680
680
681 class Dircleanup:
681 class Dircleanup:
682 def __init__(self, dir_):
682 def __init__(self, dir_):
683 self.rmtree = shutil.rmtree
683 self.rmtree = shutil.rmtree
684 self.dir_ = dir_
684 self.dir_ = dir_
685 os.mkdir(dir_)
685 os.mkdir(dir_)
686 def close(self):
686 def close(self):
687 self.dir_ = None
687 self.dir_ = None
688 def __del__(self):
688 def __del__(self):
689 if self.dir_:
689 if self.dir_:
690 self.rmtree(self.dir_, True)
690 self.rmtree(self.dir_, True)
691
691
692 if opts['ssh']:
692 if opts['ssh']:
693 ui.setconfig("ui", "ssh", opts['ssh'])
693 ui.setconfig("ui", "ssh", opts['ssh'])
694 if opts['remotecmd']:
694 if opts['remotecmd']:
695 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
695 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
696
696
697 if not os.path.exists(source):
697 if not os.path.exists(source):
698 source = ui.expandpath(source)
698 source = ui.expandpath(source)
699
699
700 d = Dircleanup(dest)
700 d = Dircleanup(dest)
701 abspath = source
701 abspath = source
702 other = hg.repository(ui, source)
702 other = hg.repository(ui, source)
703
703
704 copy = False
704 copy = False
705 if other.dev() != -1:
705 if other.dev() != -1:
706 abspath = os.path.abspath(source)
706 abspath = os.path.abspath(source)
707 if not opts['pull'] and not opts['rev']:
707 if not opts['pull'] and not opts['rev']:
708 copy = True
708 copy = True
709
709
710 if copy:
710 if copy:
711 try:
711 try:
712 # we use a lock here because if we race with commit, we
712 # we use a lock here because if we race with commit, we
713 # can end up with extra data in the cloned revlogs that's
713 # can end up with extra data in the cloned revlogs that's
714 # not pointed to by changesets, thus causing verify to
714 # not pointed to by changesets, thus causing verify to
715 # fail
715 # fail
716 l1 = lock.lock(os.path.join(source, ".hg", "lock"))
716 l1 = lock.lock(os.path.join(source, ".hg", "lock"))
717 except OSError:
717 except OSError:
718 copy = False
718 copy = False
719
719
720 if copy:
720 if copy:
721 # we lock here to avoid premature writing to the target
721 # we lock here to avoid premature writing to the target
722 os.mkdir(os.path.join(dest, ".hg"))
722 os.mkdir(os.path.join(dest, ".hg"))
723 l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
723 l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
724
724
725 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
725 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
726 for f in files.split():
726 for f in files.split():
727 src = os.path.join(source, ".hg", f)
727 src = os.path.join(source, ".hg", f)
728 dst = os.path.join(dest, ".hg", f)
728 dst = os.path.join(dest, ".hg", f)
729 try:
729 try:
730 util.copyfiles(src, dst)
730 util.copyfiles(src, dst)
731 except OSError, inst:
731 except OSError, inst:
732 if inst.errno != errno.ENOENT: raise
732 if inst.errno != errno.ENOENT: raise
733
733
734 repo = hg.repository(ui, dest)
734 repo = hg.repository(ui, dest)
735
735
736 else:
736 else:
737 revs = None
737 revs = None
738 if opts['rev']:
738 if opts['rev']:
739 if not other.local():
739 if not other.local():
740 raise util.Abort("clone -r not supported yet for remote repositories.")
740 raise util.Abort("clone -r not supported yet for remote repositories.")
741 else:
741 else:
742 revs = [other.lookup(rev) for rev in opts['rev']]
742 revs = [other.lookup(rev) for rev in opts['rev']]
743 repo = hg.repository(ui, dest, create=1)
743 repo = hg.repository(ui, dest, create=1)
744 repo.pull(other, heads = revs)
744 repo.pull(other, heads = revs)
745
745
746 f = repo.opener("hgrc", "w", text=True)
746 f = repo.opener("hgrc", "w", text=True)
747 f.write("[paths]\n")
747 f.write("[paths]\n")
748 f.write("default = %s\n" % abspath)
748 f.write("default = %s\n" % abspath)
749 f.close()
749 f.close()
750
750
751 if not opts['noupdate']:
751 if not opts['noupdate']:
752 update(ui, repo)
752 update(ui, repo)
753
753
754 d.close()
754 d.close()
755
755
756 def commit(ui, repo, *pats, **opts):
756 def commit(ui, repo, *pats, **opts):
757 """commit the specified files or all outstanding changes
757 """commit the specified files or all outstanding changes
758
758
759 Commit changes to the given files into the repository.
759 Commit changes to the given files into the repository.
760
760
761 If a list of files is omitted, all changes reported by "hg status"
761 If a list of files is omitted, all changes reported by "hg status"
762 from the root of the repository will be commited.
762 from the root of the repository will be commited.
763
763
764 The HGEDITOR or EDITOR environment variables are used to start an
764 The HGEDITOR or EDITOR environment variables are used to start an
765 editor to add a commit comment.
765 editor to add a commit comment.
766 """
766 """
767 message = opts['message']
767 message = opts['message']
768 logfile = opts['logfile']
768 logfile = opts['logfile']
769
769
770 if message and logfile:
770 if message and logfile:
771 raise util.Abort(_('options --message and --logfile are mutually '
771 raise util.Abort(_('options --message and --logfile are mutually '
772 'exclusive'))
772 'exclusive'))
773 if not message and logfile:
773 if not message and logfile:
774 try:
774 try:
775 if logfile == '-':
775 if logfile == '-':
776 message = sys.stdin.read()
776 message = sys.stdin.read()
777 else:
777 else:
778 message = open(logfile).read()
778 message = open(logfile).read()
779 except IOError, inst:
779 except IOError, inst:
780 raise util.Abort(_("can't read commit message '%s': %s") %
780 raise util.Abort(_("can't read commit message '%s': %s") %
781 (logfile, inst.strerror))
781 (logfile, inst.strerror))
782
782
783 if opts['addremove']:
783 if opts['addremove']:
784 addremove(ui, repo, *pats, **opts)
784 addremove(ui, repo, *pats, **opts)
785 cwd = repo.getcwd()
785 cwd = repo.getcwd()
786 if not pats and cwd:
786 if not pats and cwd:
787 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
787 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
788 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
788 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
789 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
789 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
790 pats, opts)
790 pats, opts)
791 if pats:
791 if pats:
792 c, a, d, u = repo.changes(files=fns, match=match)
792 c, a, d, u = repo.changes(files=fns, match=match)
793 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
793 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
794 else:
794 else:
795 files = []
795 files = []
796 try:
796 try:
797 repo.commit(files, message, opts['user'], opts['date'], match)
797 repo.commit(files, message, opts['user'], opts['date'], match)
798 except ValueError, inst:
798 except ValueError, inst:
799 raise util.Abort(str(inst))
799 raise util.Abort(str(inst))
800
800
801 def docopy(ui, repo, pats, opts):
801 def docopy(ui, repo, pats, opts):
802 cwd = repo.getcwd()
802 cwd = repo.getcwd()
803 errors = 0
803 errors = 0
804 copied = []
804 copied = []
805 targets = {}
805 targets = {}
806
806
807 def okaytocopy(abs, rel, exact):
807 def okaytocopy(abs, rel, exact):
808 reasons = {'?': _('is not managed'),
808 reasons = {'?': _('is not managed'),
809 'a': _('has been marked for add')}
809 'a': _('has been marked for add')}
810 reason = reasons.get(repo.dirstate.state(abs))
810 reason = reasons.get(repo.dirstate.state(abs))
811 if reason:
811 if reason:
812 if exact: ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
812 if exact: ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
813 else:
813 else:
814 return True
814 return True
815
815
816 def copy(abssrc, relsrc, target, exact):
816 def copy(abssrc, relsrc, target, exact):
817 abstarget = util.canonpath(repo.root, cwd, target)
817 abstarget = util.canonpath(repo.root, cwd, target)
818 reltarget = util.pathto(cwd, abstarget)
818 reltarget = util.pathto(cwd, abstarget)
819 prevsrc = targets.get(abstarget)
819 prevsrc = targets.get(abstarget)
820 if prevsrc is not None:
820 if prevsrc is not None:
821 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
821 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
822 (reltarget, abssrc, prevsrc))
822 (reltarget, abssrc, prevsrc))
823 return
823 return
824 elif os.path.exists(reltarget):
824 elif os.path.exists(reltarget):
825 if opts['force']:
825 if opts['force']:
826 os.unlink(reltarget)
826 os.unlink(reltarget)
827 else:
827 else:
828 ui.warn(_('%s: not overwriting - file exists\n') %
828 ui.warn(_('%s: not overwriting - file exists\n') %
829 reltarget)
829 reltarget)
830 return
830 return
831 if ui.verbose or not exact:
831 if ui.verbose or not exact:
832 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
832 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
833 if not opts['after']:
833 if not opts['after']:
834 targetdir = os.path.dirname(reltarget) or '.'
834 targetdir = os.path.dirname(reltarget) or '.'
835 if not os.path.isdir(targetdir):
835 if not os.path.isdir(targetdir):
836 os.makedirs(targetdir)
836 os.makedirs(targetdir)
837 try:
837 try:
838 shutil.copyfile(relsrc, reltarget)
838 shutil.copyfile(relsrc, reltarget)
839 shutil.copymode(relsrc, reltarget)
839 shutil.copymode(relsrc, reltarget)
840 except shutil.Error, inst:
840 except shutil.Error, inst:
841 raise util.Abort(str(inst))
841 raise util.Abort(str(inst))
842 except IOError, inst:
842 except IOError, inst:
843 if inst.errno == errno.ENOENT:
843 if inst.errno == errno.ENOENT:
844 ui.warn(_('%s: deleted in working copy\n') % relsrc)
844 ui.warn(_('%s: deleted in working copy\n') % relsrc)
845 else:
845 else:
846 ui.warn(_('%s: cannot copy - %s\n') %
846 ui.warn(_('%s: cannot copy - %s\n') %
847 (relsrc, inst.strerror))
847 (relsrc, inst.strerror))
848 errors += 1
848 errors += 1
849 return
849 return
850 targets[abstarget] = abssrc
850 targets[abstarget] = abssrc
851 repo.copy(abssrc, abstarget)
851 repo.copy(abssrc, abstarget)
852 copied.append((abssrc, relsrc, exact))
852 copied.append((abssrc, relsrc, exact))
853
853
854 pats = list(pats)
854 pats = list(pats)
855 if not pats:
855 if not pats:
856 raise util.Abort(_('no source or destination specified'))
856 raise util.Abort(_('no source or destination specified'))
857 if len(pats) == 1:
857 if len(pats) == 1:
858 raise util.Abort(_('no destination specified'))
858 raise util.Abort(_('no destination specified'))
859 dest = pats.pop()
859 dest = pats.pop()
860 destdirexists = os.path.isdir(dest)
860 destdirexists = os.path.isdir(dest)
861 if (len(pats) > 1 or not os.path.exists(pats[0])) and not destdirexists:
861 if (len(pats) > 1 or not os.path.exists(pats[0])) and not destdirexists:
862 raise util.Abort(_('with multiple sources, destination must be an '
862 raise util.Abort(_('with multiple sources, destination must be an '
863 'existing directory'))
863 'existing directory'))
864
864
865 for pat in pats:
865 for pat in pats:
866 if os.path.isdir(pat):
866 if os.path.isdir(pat):
867 if destdirexists:
867 if destdirexists:
868 striplen = len(os.path.split(pat)[0])
868 striplen = len(os.path.split(pat)[0])
869 else:
869 else:
870 striplen = len(pat)
870 striplen = len(pat)
871 if striplen:
871 if striplen:
872 striplen += len(os.sep)
872 striplen += len(os.sep)
873 targetpath = lambda p: os.path.join(dest, p[striplen:])
873 targetpath = lambda p: os.path.join(dest, p[striplen:])
874 elif destdirexists:
874 elif destdirexists:
875 targetpath = lambda p: os.path.join(dest, os.path.basename(p))
875 targetpath = lambda p: os.path.join(dest, os.path.basename(p))
876 else:
876 else:
877 targetpath = lambda p: dest
877 targetpath = lambda p: dest
878 for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
878 for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
879 if okaytocopy(abssrc, relsrc, exact):
879 if okaytocopy(abssrc, relsrc, exact):
880 copy(abssrc, relsrc, targetpath(abssrc), exact)
880 copy(abssrc, relsrc, targetpath(abssrc), exact)
881
881
882 if errors:
882 if errors:
883 ui.warn(_('(consider using --after)\n'))
883 ui.warn(_('(consider using --after)\n'))
884 if len(copied) == 0:
884 if len(copied) == 0:
885 raise util.Abort(_('no files to copy'))
885 raise util.Abort(_('no files to copy'))
886 return errors, copied
886 return errors, copied
887
887
888 def copy(ui, repo, *pats, **opts):
888 def copy(ui, repo, *pats, **opts):
889 """mark files as copied for the next commit
889 """mark files as copied for the next commit
890
890
891 Mark dest as having copies of source files. If dest is a
891 Mark dest as having copies of source files. If dest is a
892 directory, copies are put in that directory. If dest is a file,
892 directory, copies are put in that directory. If dest is a file,
893 there can only be one source.
893 there can only be one source.
894
894
895 By default, this command copies the contents of files as they
895 By default, this command copies the contents of files as they
896 stand in the working directory. If invoked with --after, the
896 stand in the working directory. If invoked with --after, the
897 operation is recorded, but no copying is performed.
897 operation is recorded, but no copying is performed.
898
898
899 This command takes effect in the next commit.
899 This command takes effect in the next commit.
900
900
901 NOTE: This command should be treated as experimental. While it
901 NOTE: This command should be treated as experimental. While it
902 should properly record copied files, this information is not yet
902 should properly record copied files, this information is not yet
903 fully used by merge, nor fully reported by log.
903 fully used by merge, nor fully reported by log.
904 """
904 """
905 errs, copied = docopy(ui, repo, pats, opts)
905 errs, copied = docopy(ui, repo, pats, opts)
906 return errs
906 return errs
907
907
908 def debugancestor(ui, index, rev1, rev2):
908 def debugancestor(ui, index, rev1, rev2):
909 """find the ancestor revision of two revisions in a given index"""
909 """find the ancestor revision of two revisions in a given index"""
910 r = revlog.revlog(util.opener(os.getcwd()), index, "")
910 r = revlog.revlog(util.opener(os.getcwd()), index, "")
911 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
911 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
912 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
912 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
913
913
914 def debugcheckstate(ui, repo):
914 def debugcheckstate(ui, repo):
915 """validate the correctness of the current dirstate"""
915 """validate the correctness of the current dirstate"""
916 parent1, parent2 = repo.dirstate.parents()
916 parent1, parent2 = repo.dirstate.parents()
917 repo.dirstate.read()
917 repo.dirstate.read()
918 dc = repo.dirstate.map
918 dc = repo.dirstate.map
919 keys = dc.keys()
919 keys = dc.keys()
920 keys.sort()
920 keys.sort()
921 m1n = repo.changelog.read(parent1)[0]
921 m1n = repo.changelog.read(parent1)[0]
922 m2n = repo.changelog.read(parent2)[0]
922 m2n = repo.changelog.read(parent2)[0]
923 m1 = repo.manifest.read(m1n)
923 m1 = repo.manifest.read(m1n)
924 m2 = repo.manifest.read(m2n)
924 m2 = repo.manifest.read(m2n)
925 errors = 0
925 errors = 0
926 for f in dc:
926 for f in dc:
927 state = repo.dirstate.state(f)
927 state = repo.dirstate.state(f)
928 if state in "nr" and f not in m1:
928 if state in "nr" and f not in m1:
929 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
929 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
930 errors += 1
930 errors += 1
931 if state in "a" and f in m1:
931 if state in "a" and f in m1:
932 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
932 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
933 errors += 1
933 errors += 1
934 if state in "m" and f not in m1 and f not in m2:
934 if state in "m" and f not in m1 and f not in m2:
935 ui.warn(_("%s in state %s, but not in either manifest\n") %
935 ui.warn(_("%s in state %s, but not in either manifest\n") %
936 (f, state))
936 (f, state))
937 errors += 1
937 errors += 1
938 for f in m1:
938 for f in m1:
939 state = repo.dirstate.state(f)
939 state = repo.dirstate.state(f)
940 if state not in "nrm":
940 if state not in "nrm":
941 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
941 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
942 errors += 1
942 errors += 1
943 if errors:
943 if errors:
944 raise util.Abort(_(".hg/dirstate inconsistent with current parent's manifest"))
944 raise util.Abort(_(".hg/dirstate inconsistent with current parent's manifest"))
945
945
946 def debugconfig(ui):
946 def debugconfig(ui):
947 """show combined config settings from all hgrc files"""
947 """show combined config settings from all hgrc files"""
948 try:
948 try:
949 repo = hg.repository(ui)
949 repo = hg.repository(ui)
950 except hg.RepoError:
950 except hg.RepoError:
951 pass
951 pass
952 for section, name, value in ui.walkconfig():
952 for section, name, value in ui.walkconfig():
953 ui.write('%s.%s=%s\n' % (section, name, value))
953 ui.write('%s.%s=%s\n' % (section, name, value))
954
954
955 def debugsetparents(ui, repo, rev1, rev2=None):
955 def debugsetparents(ui, repo, rev1, rev2=None):
956 """manually set the parents of the current working directory
956 """manually set the parents of the current working directory
957
957
958 This is useful for writing repository conversion tools, but should
958 This is useful for writing repository conversion tools, but should
959 be used with care.
959 be used with care.
960 """
960 """
961
961
962 if not rev2:
962 if not rev2:
963 rev2 = hex(nullid)
963 rev2 = hex(nullid)
964
964
965 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
965 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
966
966
967 def debugstate(ui, repo):
967 def debugstate(ui, repo):
968 """show the contents of the current dirstate"""
968 """show the contents of the current dirstate"""
969 repo.dirstate.read()
969 repo.dirstate.read()
970 dc = repo.dirstate.map
970 dc = repo.dirstate.map
971 keys = dc.keys()
971 keys = dc.keys()
972 keys.sort()
972 keys.sort()
973 for file_ in keys:
973 for file_ in keys:
974 ui.write("%c %3o %10d %s %s\n"
974 ui.write("%c %3o %10d %s %s\n"
975 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
975 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
976 time.strftime("%x %X",
976 time.strftime("%x %X",
977 time.localtime(dc[file_][3])), file_))
977 time.localtime(dc[file_][3])), file_))
978 for f in repo.dirstate.copies:
978 for f in repo.dirstate.copies:
979 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
979 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
980
980
981 def debugdata(ui, file_, rev):
981 def debugdata(ui, file_, rev):
982 """dump the contents of an data file revision"""
982 """dump the contents of an data file revision"""
983 r = revlog.revlog(util.opener(os.getcwd()), file_[:-2] + ".i", file_)
983 r = revlog.revlog(util.opener(os.getcwd()), file_[:-2] + ".i", file_)
984 try:
984 try:
985 ui.write(r.revision(r.lookup(rev)))
985 ui.write(r.revision(r.lookup(rev)))
986 except KeyError:
986 except KeyError:
987 raise util.Abort(_('invalid revision identifier %s'), rev)
987 raise util.Abort(_('invalid revision identifier %s'), rev)
988
988
989 def debugindex(ui, file_):
989 def debugindex(ui, file_):
990 """dump the contents of an index file"""
990 """dump the contents of an index file"""
991 r = revlog.revlog(util.opener(os.getcwd()), file_, "")
991 r = revlog.revlog(util.opener(os.getcwd()), file_, "")
992 ui.write(" rev offset length base linkrev" +
992 ui.write(" rev offset length base linkrev" +
993 " nodeid p1 p2\n")
993 " nodeid p1 p2\n")
994 for i in range(r.count()):
994 for i in range(r.count()):
995 e = r.index[i]
995 e = r.index[i]
996 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
996 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
997 i, e[0], e[1], e[2], e[3],
997 i, e[0], e[1], e[2], e[3],
998 short(e[6]), short(e[4]), short(e[5])))
998 short(e[6]), short(e[4]), short(e[5])))
999
999
1000 def debugindexdot(ui, file_):
1000 def debugindexdot(ui, file_):
1001 """dump an index DAG as a .dot file"""
1001 """dump an index DAG as a .dot file"""
1002 r = revlog.revlog(util.opener(os.getcwd()), file_, "")
1002 r = revlog.revlog(util.opener(os.getcwd()), file_, "")
1003 ui.write("digraph G {\n")
1003 ui.write("digraph G {\n")
1004 for i in range(r.count()):
1004 for i in range(r.count()):
1005 e = r.index[i]
1005 e = r.index[i]
1006 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
1006 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
1007 if e[5] != nullid:
1007 if e[5] != nullid:
1008 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
1008 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
1009 ui.write("}\n")
1009 ui.write("}\n")
1010
1010
1011 def debugrename(ui, repo, file, rev=None):
1011 def debugrename(ui, repo, file, rev=None):
1012 """dump rename information"""
1012 """dump rename information"""
1013 r = repo.file(relpath(repo, [file])[0])
1013 r = repo.file(relpath(repo, [file])[0])
1014 if rev:
1014 if rev:
1015 try:
1015 try:
1016 # assume all revision numbers are for changesets
1016 # assume all revision numbers are for changesets
1017 n = repo.lookup(rev)
1017 n = repo.lookup(rev)
1018 change = repo.changelog.read(n)
1018 change = repo.changelog.read(n)
1019 m = repo.manifest.read(change[0])
1019 m = repo.manifest.read(change[0])
1020 n = m[relpath(repo, [file])[0]]
1020 n = m[relpath(repo, [file])[0]]
1021 except (hg.RepoError, KeyError):
1021 except (hg.RepoError, KeyError):
1022 n = r.lookup(rev)
1022 n = r.lookup(rev)
1023 else:
1023 else:
1024 n = r.tip()
1024 n = r.tip()
1025 m = r.renamed(n)
1025 m = r.renamed(n)
1026 if m:
1026 if m:
1027 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1027 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1028 else:
1028 else:
1029 ui.write(_("not renamed\n"))
1029 ui.write(_("not renamed\n"))
1030
1030
1031 def debugwalk(ui, repo, *pats, **opts):
1031 def debugwalk(ui, repo, *pats, **opts):
1032 """show how files match on given patterns"""
1032 """show how files match on given patterns"""
1033 items = list(walk(repo, pats, opts))
1033 items = list(walk(repo, pats, opts))
1034 if not items:
1034 if not items:
1035 return
1035 return
1036 fmt = '%%s %%-%ds %%-%ds %%s' % (
1036 fmt = '%%s %%-%ds %%-%ds %%s' % (
1037 max([len(abs) for (src, abs, rel, exact) in items]),
1037 max([len(abs) for (src, abs, rel, exact) in items]),
1038 max([len(rel) for (src, abs, rel, exact) in items]))
1038 max([len(rel) for (src, abs, rel, exact) in items]))
1039 for src, abs, rel, exact in items:
1039 for src, abs, rel, exact in items:
1040 line = fmt % (src, abs, rel, exact and 'exact' or '')
1040 line = fmt % (src, abs, rel, exact and 'exact' or '')
1041 ui.write("%s\n" % line.rstrip())
1041 ui.write("%s\n" % line.rstrip())
1042
1042
1043 def diff(ui, repo, *pats, **opts):
1043 def diff(ui, repo, *pats, **opts):
1044 """diff working directory (or selected files)
1044 """diff working directory (or selected files)
1045
1045
1046 Show differences between revisions for the specified files.
1046 Show differences between revisions for the specified files.
1047
1047
1048 Differences between files are shown using the unified diff format.
1048 Differences between files are shown using the unified diff format.
1049
1049
1050 When two revision arguments are given, then changes are shown
1050 When two revision arguments are given, then changes are shown
1051 between those revisions. If only one revision is specified then
1051 between those revisions. If only one revision is specified then
1052 that revision is compared to the working directory, and, when no
1052 that revision is compared to the working directory, and, when no
1053 revisions are specified, the working directory files are compared
1053 revisions are specified, the working directory files are compared
1054 to its parent.
1054 to its parent.
1055
1055
1056 Without the -a option, diff will avoid generating diffs of files
1056 Without the -a option, diff will avoid generating diffs of files
1057 it detects as binary. With -a, diff will generate a diff anyway,
1057 it detects as binary. With -a, diff will generate a diff anyway,
1058 probably with undesirable results.
1058 probably with undesirable results.
1059 """
1059 """
1060 node1, node2 = None, None
1060 node1, node2 = None, None
1061 revs = [repo.lookup(x) for x in opts['rev']]
1061 revs = [repo.lookup(x) for x in opts['rev']]
1062
1062
1063 if len(revs) > 0:
1063 if len(revs) > 0:
1064 node1 = revs[0]
1064 node1 = revs[0]
1065 if len(revs) > 1:
1065 if len(revs) > 1:
1066 node2 = revs[1]
1066 node2 = revs[1]
1067 if len(revs) > 2:
1067 if len(revs) > 2:
1068 raise util.Abort(_("too many revisions to diff"))
1068 raise util.Abort(_("too many revisions to diff"))
1069
1069
1070 fns, matchfn, anypats = matchpats(repo, repo.getcwd(), pats, opts)
1070 fns, matchfn, anypats = matchpats(repo, repo.getcwd(), pats, opts)
1071
1071
1072 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
1072 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
1073 text=opts['text'])
1073 text=opts['text'])
1074
1074
1075 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
1075 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
1076 node = repo.lookup(changeset)
1076 node = repo.lookup(changeset)
1077 prev, other = repo.changelog.parents(node)
1077 prev, other = repo.changelog.parents(node)
1078 change = repo.changelog.read(node)
1078 change = repo.changelog.read(node)
1079
1079
1080 fp = make_file(repo, repo.changelog, opts['output'],
1080 fp = make_file(repo, repo.changelog, opts['output'],
1081 node=node, total=total, seqno=seqno,
1081 node=node, total=total, seqno=seqno,
1082 revwidth=revwidth)
1082 revwidth=revwidth)
1083 if fp != sys.stdout:
1083 if fp != sys.stdout:
1084 ui.note("%s\n" % fp.name)
1084 ui.note("%s\n" % fp.name)
1085
1085
1086 fp.write("# HG changeset patch\n")
1086 fp.write("# HG changeset patch\n")
1087 fp.write("# User %s\n" % change[1])
1087 fp.write("# User %s\n" % change[1])
1088 fp.write("# Node ID %s\n" % hex(node))
1088 fp.write("# Node ID %s\n" % hex(node))
1089 fp.write("# Parent %s\n" % hex(prev))
1089 fp.write("# Parent %s\n" % hex(prev))
1090 if other != nullid:
1090 if other != nullid:
1091 fp.write("# Parent %s\n" % hex(other))
1091 fp.write("# Parent %s\n" % hex(other))
1092 fp.write(change[4].rstrip())
1092 fp.write(change[4].rstrip())
1093 fp.write("\n\n")
1093 fp.write("\n\n")
1094
1094
1095 dodiff(fp, ui, repo, prev, node, text=opts['text'])
1095 dodiff(fp, ui, repo, prev, node, text=opts['text'])
1096 if fp != sys.stdout:
1096 if fp != sys.stdout:
1097 fp.close()
1097 fp.close()
1098
1098
1099 def export(ui, repo, *changesets, **opts):
1099 def export(ui, repo, *changesets, **opts):
1100 """dump the header and diffs for one or more changesets
1100 """dump the header and diffs for one or more changesets
1101
1101
1102 Print the changeset header and diffs for one or more revisions.
1102 Print the changeset header and diffs for one or more revisions.
1103
1103
1104 The information shown in the changeset header is: author,
1104 The information shown in the changeset header is: author,
1105 changeset hash, parent and commit comment.
1105 changeset hash, parent and commit comment.
1106
1106
1107 Output may be to a file, in which case the name of the file is
1107 Output may be to a file, in which case the name of the file is
1108 given using a format string. The formatting rules are as follows:
1108 given using a format string. The formatting rules are as follows:
1109
1109
1110 %% literal "%" character
1110 %% literal "%" character
1111 %H changeset hash (40 bytes of hexadecimal)
1111 %H changeset hash (40 bytes of hexadecimal)
1112 %N number of patches being generated
1112 %N number of patches being generated
1113 %R changeset revision number
1113 %R changeset revision number
1114 %b basename of the exporting repository
1114 %b basename of the exporting repository
1115 %h short-form changeset hash (12 bytes of hexadecimal)
1115 %h short-form changeset hash (12 bytes of hexadecimal)
1116 %n zero-padded sequence number, starting at 1
1116 %n zero-padded sequence number, starting at 1
1117 %r zero-padded changeset revision number
1117 %r zero-padded changeset revision number
1118
1118
1119 Without the -a option, export will avoid generating diffs of files
1119 Without the -a option, export will avoid generating diffs of files
1120 it detects as binary. With -a, export will generate a diff anyway,
1120 it detects as binary. With -a, export will generate a diff anyway,
1121 probably with undesirable results.
1121 probably with undesirable results.
1122 """
1122 """
1123 if not changesets:
1123 if not changesets:
1124 raise util.Abort(_("export requires at least one changeset"))
1124 raise util.Abort(_("export requires at least one changeset"))
1125 seqno = 0
1125 seqno = 0
1126 revs = list(revrange(ui, repo, changesets))
1126 revs = list(revrange(ui, repo, changesets))
1127 total = len(revs)
1127 total = len(revs)
1128 revwidth = max(map(len, revs))
1128 revwidth = max(map(len, revs))
1129 ui.note(len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n"))
1129 ui.note(len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n"))
1130 for cset in revs:
1130 for cset in revs:
1131 seqno += 1
1131 seqno += 1
1132 doexport(ui, repo, cset, seqno, total, revwidth, opts)
1132 doexport(ui, repo, cset, seqno, total, revwidth, opts)
1133
1133
1134 def forget(ui, repo, *pats, **opts):
1134 def forget(ui, repo, *pats, **opts):
1135 """don't add the specified files on the next commit
1135 """don't add the specified files on the next commit
1136
1136
1137 Undo an 'hg add' scheduled for the next commit.
1137 Undo an 'hg add' scheduled for the next commit.
1138 """
1138 """
1139 forget = []
1139 forget = []
1140 for src, abs, rel, exact in walk(repo, pats, opts):
1140 for src, abs, rel, exact in walk(repo, pats, opts):
1141 if repo.dirstate.state(abs) == 'a':
1141 if repo.dirstate.state(abs) == 'a':
1142 forget.append(abs)
1142 forget.append(abs)
1143 if ui.verbose or not exact:
1143 if ui.verbose or not exact:
1144 ui.status(_('forgetting %s\n') % rel)
1144 ui.status(_('forgetting %s\n') % rel)
1145 repo.forget(forget)
1145 repo.forget(forget)
1146
1146
1147 def grep(ui, repo, pattern, *pats, **opts):
1147 def grep(ui, repo, pattern, *pats, **opts):
1148 """search for a pattern in specified files and revisions
1148 """search for a pattern in specified files and revisions
1149
1149
1150 Search revisions of files for a regular expression.
1150 Search revisions of files for a regular expression.
1151
1151
1152 This command behaves differently than Unix grep. It only accepts
1152 This command behaves differently than Unix grep. It only accepts
1153 Python/Perl regexps. It searches repository history, not the
1153 Python/Perl regexps. It searches repository history, not the
1154 working directory. It always prints the revision number in which
1154 working directory. It always prints the revision number in which
1155 a match appears.
1155 a match appears.
1156
1156
1157 By default, grep only prints output for the first revision of a
1157 By default, grep only prints output for the first revision of a
1158 file in which it finds a match. To get it to print every revision
1158 file in which it finds a match. To get it to print every revision
1159 that contains a change in match status ("-" for a match that
1159 that contains a change in match status ("-" for a match that
1160 becomes a non-match, or "+" for a non-match that becomes a match),
1160 becomes a non-match, or "+" for a non-match that becomes a match),
1161 use the --all flag.
1161 use the --all flag.
1162 """
1162 """
1163 reflags = 0
1163 reflags = 0
1164 if opts['ignore_case']:
1164 if opts['ignore_case']:
1165 reflags |= re.I
1165 reflags |= re.I
1166 regexp = re.compile(pattern, reflags)
1166 regexp = re.compile(pattern, reflags)
1167 sep, eol = ':', '\n'
1167 sep, eol = ':', '\n'
1168 if opts['print0']:
1168 if opts['print0']:
1169 sep = eol = '\0'
1169 sep = eol = '\0'
1170
1170
1171 fcache = {}
1171 fcache = {}
1172 def getfile(fn):
1172 def getfile(fn):
1173 if fn not in fcache:
1173 if fn not in fcache:
1174 fcache[fn] = repo.file(fn)
1174 fcache[fn] = repo.file(fn)
1175 return fcache[fn]
1175 return fcache[fn]
1176
1176
1177 def matchlines(body):
1177 def matchlines(body):
1178 begin = 0
1178 begin = 0
1179 linenum = 0
1179 linenum = 0
1180 while True:
1180 while True:
1181 match = regexp.search(body, begin)
1181 match = regexp.search(body, begin)
1182 if not match:
1182 if not match:
1183 break
1183 break
1184 mstart, mend = match.span()
1184 mstart, mend = match.span()
1185 linenum += body.count('\n', begin, mstart) + 1
1185 linenum += body.count('\n', begin, mstart) + 1
1186 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1186 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1187 lend = body.find('\n', mend)
1187 lend = body.find('\n', mend)
1188 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1188 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1189 begin = lend + 1
1189 begin = lend + 1
1190
1190
1191 class linestate:
1191 class linestate:
1192 def __init__(self, line, linenum, colstart, colend):
1192 def __init__(self, line, linenum, colstart, colend):
1193 self.line = line
1193 self.line = line
1194 self.linenum = linenum
1194 self.linenum = linenum
1195 self.colstart = colstart
1195 self.colstart = colstart
1196 self.colend = colend
1196 self.colend = colend
1197 def __eq__(self, other):
1197 def __eq__(self, other):
1198 return self.line == other.line
1198 return self.line == other.line
1199 def __hash__(self):
1199 def __hash__(self):
1200 return hash(self.line)
1200 return hash(self.line)
1201
1201
1202 matches = {}
1202 matches = {}
1203 def grepbody(fn, rev, body):
1203 def grepbody(fn, rev, body):
1204 matches[rev].setdefault(fn, {})
1204 matches[rev].setdefault(fn, {})
1205 m = matches[rev][fn]
1205 m = matches[rev][fn]
1206 for lnum, cstart, cend, line in matchlines(body):
1206 for lnum, cstart, cend, line in matchlines(body):
1207 s = linestate(line, lnum, cstart, cend)
1207 s = linestate(line, lnum, cstart, cend)
1208 m[s] = s
1208 m[s] = s
1209
1209
1210 prev = {}
1210 prev = {}
1211 ucache = {}
1211 ucache = {}
1212 def display(fn, rev, states, prevstates):
1212 def display(fn, rev, states, prevstates):
1213 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1213 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1214 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1214 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1215 counts = {'-': 0, '+': 0}
1215 counts = {'-': 0, '+': 0}
1216 filerevmatches = {}
1216 filerevmatches = {}
1217 for l in diff:
1217 for l in diff:
1218 if incrementing or not opts['all']:
1218 if incrementing or not opts['all']:
1219 change = ((l in prevstates) and '-') or '+'
1219 change = ((l in prevstates) and '-') or '+'
1220 r = rev
1220 r = rev
1221 else:
1221 else:
1222 change = ((l in states) and '-') or '+'
1222 change = ((l in states) and '-') or '+'
1223 r = prev[fn]
1223 r = prev[fn]
1224 cols = [fn, str(rev)]
1224 cols = [fn, str(rev)]
1225 if opts['line_number']: cols.append(str(l.linenum))
1225 if opts['line_number']: cols.append(str(l.linenum))
1226 if opts['all']: cols.append(change)
1226 if opts['all']: cols.append(change)
1227 if opts['user']: cols.append(trimuser(ui, getchange(rev)[1], rev,
1227 if opts['user']: cols.append(trimuser(ui, getchange(rev)[1], rev,
1228 ucache))
1228 ucache))
1229 if opts['files_with_matches']:
1229 if opts['files_with_matches']:
1230 c = (fn, rev)
1230 c = (fn, rev)
1231 if c in filerevmatches: continue
1231 if c in filerevmatches: continue
1232 filerevmatches[c] = 1
1232 filerevmatches[c] = 1
1233 else:
1233 else:
1234 cols.append(l.line)
1234 cols.append(l.line)
1235 ui.write(sep.join(cols), eol)
1235 ui.write(sep.join(cols), eol)
1236 counts[change] += 1
1236 counts[change] += 1
1237 return counts['+'], counts['-']
1237 return counts['+'], counts['-']
1238
1238
1239 fstate = {}
1239 fstate = {}
1240 skip = {}
1240 skip = {}
1241 changeiter, getchange = walkchangerevs(ui, repo, repo.getcwd(), pats, opts)
1241 changeiter, getchange = walkchangerevs(ui, repo, repo.getcwd(), pats, opts)
1242 count = 0
1242 count = 0
1243 incrementing = False
1243 incrementing = False
1244 for st, rev, fns in changeiter:
1244 for st, rev, fns in changeiter:
1245 if st == 'window':
1245 if st == 'window':
1246 incrementing = rev
1246 incrementing = rev
1247 matches.clear()
1247 matches.clear()
1248 elif st == 'add':
1248 elif st == 'add':
1249 change = repo.changelog.read(repo.lookup(str(rev)))
1249 change = repo.changelog.read(repo.lookup(str(rev)))
1250 mf = repo.manifest.read(change[0])
1250 mf = repo.manifest.read(change[0])
1251 matches[rev] = {}
1251 matches[rev] = {}
1252 for fn in fns:
1252 for fn in fns:
1253 if fn in skip: continue
1253 if fn in skip: continue
1254 fstate.setdefault(fn, {})
1254 fstate.setdefault(fn, {})
1255 try:
1255 try:
1256 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1256 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1257 except KeyError:
1257 except KeyError:
1258 pass
1258 pass
1259 elif st == 'iter':
1259 elif st == 'iter':
1260 states = matches[rev].items()
1260 states = matches[rev].items()
1261 states.sort()
1261 states.sort()
1262 for fn, m in states:
1262 for fn, m in states:
1263 if fn in skip: continue
1263 if fn in skip: continue
1264 if incrementing or not opts['all'] or fstate[fn]:
1264 if incrementing or not opts['all'] or fstate[fn]:
1265 pos, neg = display(fn, rev, m, fstate[fn])
1265 pos, neg = display(fn, rev, m, fstate[fn])
1266 count += pos + neg
1266 count += pos + neg
1267 if pos and not opts['all']:
1267 if pos and not opts['all']:
1268 skip[fn] = True
1268 skip[fn] = True
1269 fstate[fn] = m
1269 fstate[fn] = m
1270 prev[fn] = rev
1270 prev[fn] = rev
1271
1271
1272 if not incrementing:
1272 if not incrementing:
1273 fstate = fstate.items()
1273 fstate = fstate.items()
1274 fstate.sort()
1274 fstate.sort()
1275 for fn, state in fstate:
1275 for fn, state in fstate:
1276 if fn in skip: continue
1276 if fn in skip: continue
1277 display(fn, rev, {}, state)
1277 display(fn, rev, {}, state)
1278 return (count == 0 and 1) or 0
1278 return (count == 0 and 1) or 0
1279
1279
1280 def heads(ui, repo, **opts):
1280 def heads(ui, repo, **opts):
1281 """show current repository heads
1281 """show current repository heads
1282
1282
1283 Show all repository head changesets.
1283 Show all repository head changesets.
1284
1284
1285 Repository "heads" are changesets that don't have children
1285 Repository "heads" are changesets that don't have children
1286 changesets. They are where development generally takes place and
1286 changesets. They are where development generally takes place and
1287 are the usual targets for update and merge operations.
1287 are the usual targets for update and merge operations.
1288 """
1288 """
1289 if opts['rev']:
1289 if opts['rev']:
1290 heads = repo.heads(repo.lookup(opts['rev']))
1290 heads = repo.heads(repo.lookup(opts['rev']))
1291 else:
1291 else:
1292 heads = repo.heads()
1292 heads = repo.heads()
1293 br = None
1293 br = None
1294 if opts['branches']:
1294 if opts['branches']:
1295 br = repo.branchlookup(heads)
1295 br = repo.branchlookup(heads)
1296 for n in heads:
1296 for n in heads:
1297 show_changeset(ui, repo, changenode=n, brinfo=br)
1297 show_changeset(ui, repo, changenode=n, brinfo=br)
1298
1298
1299 def identify(ui, repo):
1299 def identify(ui, repo):
1300 """print information about the working copy
1300 """print information about the working copy
1301
1301
1302 Print a short summary of the current state of the repo.
1302 Print a short summary of the current state of the repo.
1303
1303
1304 This summary identifies the repository state using one or two parent
1304 This summary identifies the repository state using one or two parent
1305 hash identifiers, followed by a "+" if there are uncommitted changes
1305 hash identifiers, followed by a "+" if there are uncommitted changes
1306 in the working directory, followed by a list of tags for this revision.
1306 in the working directory, followed by a list of tags for this revision.
1307 """
1307 """
1308 parents = [p for p in repo.dirstate.parents() if p != nullid]
1308 parents = [p for p in repo.dirstate.parents() if p != nullid]
1309 if not parents:
1309 if not parents:
1310 ui.write(_("unknown\n"))
1310 ui.write(_("unknown\n"))
1311 return
1311 return
1312
1312
1313 hexfunc = ui.verbose and hex or short
1313 hexfunc = ui.verbose and hex or short
1314 (c, a, d, u) = repo.changes()
1314 (c, a, d, u) = repo.changes()
1315 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
1315 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
1316 (c or a or d) and "+" or "")]
1316 (c or a or d) and "+" or "")]
1317
1317
1318 if not ui.quiet:
1318 if not ui.quiet:
1319 # multiple tags for a single parent separated by '/'
1319 # multiple tags for a single parent separated by '/'
1320 parenttags = ['/'.join(tags)
1320 parenttags = ['/'.join(tags)
1321 for tags in map(repo.nodetags, parents) if tags]
1321 for tags in map(repo.nodetags, parents) if tags]
1322 # tags for multiple parents separated by ' + '
1322 # tags for multiple parents separated by ' + '
1323 if parenttags:
1323 if parenttags:
1324 output.append(' + '.join(parenttags))
1324 output.append(' + '.join(parenttags))
1325
1325
1326 ui.write("%s\n" % ' '.join(output))
1326 ui.write("%s\n" % ' '.join(output))
1327
1327
1328 def import_(ui, repo, patch1, *patches, **opts):
1328 def import_(ui, repo, patch1, *patches, **opts):
1329 """import an ordered set of patches
1329 """import an ordered set of patches
1330
1330
1331 Import a list of patches and commit them individually.
1331 Import a list of patches and commit them individually.
1332
1332
1333 If there are outstanding changes in the working directory, import
1333 If there are outstanding changes in the working directory, import
1334 will abort unless given the -f flag.
1334 will abort unless given the -f flag.
1335
1335
1336 If a patch looks like a mail message (its first line starts with
1336 If a patch looks like a mail message (its first line starts with
1337 "From " or looks like an RFC822 header), it will not be applied
1337 "From " or looks like an RFC822 header), it will not be applied
1338 unless the -f option is used. The importer neither parses nor
1338 unless the -f option is used. The importer neither parses nor
1339 discards mail headers, so use -f only to override the "mailness"
1339 discards mail headers, so use -f only to override the "mailness"
1340 safety check, not to import a real mail message.
1340 safety check, not to import a real mail message.
1341 """
1341 """
1342 patches = (patch1,) + patches
1342 patches = (patch1,) + patches
1343
1343
1344 if not opts['force']:
1344 if not opts['force']:
1345 (c, a, d, u) = repo.changes()
1345 (c, a, d, u) = repo.changes()
1346 if c or a or d:
1346 if c or a or d:
1347 raise util.Abort(_("outstanding uncommitted changes"))
1347 raise util.Abort(_("outstanding uncommitted changes"))
1348
1348
1349 d = opts["base"]
1349 d = opts["base"]
1350 strip = opts["strip"]
1350 strip = opts["strip"]
1351
1351
1352 mailre = re.compile(r'(?:From |[\w-]+:)')
1352 mailre = re.compile(r'(?:From |[\w-]+:)')
1353
1353
1354 # attempt to detect the start of a patch
1354 # attempt to detect the start of a patch
1355 # (this heuristic is borrowed from quilt)
1355 # (this heuristic is borrowed from quilt)
1356 diffre = re.compile(r'(?:Index:[ \t]|diff[ \t]|RCS file: |' +
1356 diffre = re.compile(r'(?:Index:[ \t]|diff[ \t]|RCS file: |' +
1357 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
1357 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
1358 '(---|\*\*\*)[ \t])')
1358 '(---|\*\*\*)[ \t])')
1359
1359
1360 for patch in patches:
1360 for patch in patches:
1361 ui.status(_("applying %s\n") % patch)
1361 ui.status(_("applying %s\n") % patch)
1362 pf = os.path.join(d, patch)
1362 pf = os.path.join(d, patch)
1363
1363
1364 message = []
1364 message = []
1365 user = None
1365 user = None
1366 hgpatch = False
1366 hgpatch = False
1367 for line in file(pf):
1367 for line in file(pf):
1368 line = line.rstrip()
1368 line = line.rstrip()
1369 if (not message and not hgpatch and
1369 if (not message and not hgpatch and
1370 mailre.match(line) and not opts['force']):
1370 mailre.match(line) and not opts['force']):
1371 if len(line) > 35: line = line[:32] + '...'
1371 if len(line) > 35: line = line[:32] + '...'
1372 raise util.Abort(_('first line looks like a '
1372 raise util.Abort(_('first line looks like a '
1373 'mail header: ') + line)
1373 'mail header: ') + line)
1374 if diffre.match(line):
1374 if diffre.match(line):
1375 break
1375 break
1376 elif hgpatch:
1376 elif hgpatch:
1377 # parse values when importing the result of an hg export
1377 # parse values when importing the result of an hg export
1378 if line.startswith("# User "):
1378 if line.startswith("# User "):
1379 user = line[7:]
1379 user = line[7:]
1380 ui.debug(_('User: %s\n') % user)
1380 ui.debug(_('User: %s\n') % user)
1381 elif not line.startswith("# ") and line:
1381 elif not line.startswith("# ") and line:
1382 message.append(line)
1382 message.append(line)
1383 hgpatch = False
1383 hgpatch = False
1384 elif line == '# HG changeset patch':
1384 elif line == '# HG changeset patch':
1385 hgpatch = True
1385 hgpatch = True
1386 message = [] # We may have collected garbage
1386 message = [] # We may have collected garbage
1387 else:
1387 else:
1388 message.append(line)
1388 message.append(line)
1389
1389
1390 # make sure message isn't empty
1390 # make sure message isn't empty
1391 if not message:
1391 if not message:
1392 message = _("imported patch %s\n") % patch
1392 message = _("imported patch %s\n") % patch
1393 else:
1393 else:
1394 message = "%s\n" % '\n'.join(message)
1394 message = "%s\n" % '\n'.join(message)
1395 ui.debug(_('message:\n%s\n') % message)
1395 ui.debug(_('message:\n%s\n') % message)
1396
1396
1397 files = util.patch(strip, pf, ui)
1397 files = util.patch(strip, pf, ui)
1398
1398
1399 if len(files) > 0:
1399 if len(files) > 0:
1400 addremove(ui, repo, *files)
1400 addremove(ui, repo, *files)
1401 repo.commit(files, message, user)
1401 repo.commit(files, message, user)
1402
1402
1403 def incoming(ui, repo, source="default", **opts):
1403 def incoming(ui, repo, source="default", **opts):
1404 """show new changesets found in source
1404 """show new changesets found in source
1405
1405
1406 Show new changesets found in the specified repo or the default
1406 Show new changesets found in the specified repo or the default
1407 pull repo. These are the changesets that would be pulled if a pull
1407 pull repo. These are the changesets that would be pulled if a pull
1408 was requested.
1408 was requested.
1409
1409
1410 Currently only local repositories are supported.
1410 Currently only local repositories are supported.
1411 """
1411 """
1412 source = ui.expandpath(source, repo.root)
1412 source = ui.expandpath(source, repo.root)
1413 other = hg.repository(ui, source)
1413 other = hg.repository(ui, source)
1414 if not other.local():
1414 if not other.local():
1415 raise util.Abort(_("incoming doesn't work for remote repositories yet"))
1415 raise util.Abort(_("incoming doesn't work for remote repositories yet"))
1416 o = repo.findincoming(other)
1416 o = repo.findincoming(other)
1417 if not o:
1417 if not o:
1418 return
1418 return
1419 o = other.changelog.nodesbetween(o)[0]
1419 o = other.changelog.nodesbetween(o)[0]
1420 if opts['newest_first']:
1420 if opts['newest_first']:
1421 o.reverse()
1421 o.reverse()
1422 for n in o:
1422 for n in o:
1423 parents = [p for p in other.changelog.parents(n) if p != nullid]
1423 parents = [p for p in other.changelog.parents(n) if p != nullid]
1424 if opts['no_merges'] and len(parents) == 2:
1424 if opts['no_merges'] and len(parents) == 2:
1425 continue
1425 continue
1426 show_changeset(ui, other, changenode=n)
1426 show_changeset(ui, other, changenode=n)
1427 if opts['patch']:
1427 if opts['patch']:
1428 prev = (parents and parents[0]) or nullid
1428 prev = (parents and parents[0]) or nullid
1429 dodiff(ui, ui, other, prev, n)
1429 dodiff(ui, ui, other, prev, n)
1430 ui.write("\n")
1430 ui.write("\n")
1431
1431
1432 def init(ui, dest="."):
1432 def init(ui, dest="."):
1433 """create a new repository in the given directory
1433 """create a new repository in the given directory
1434
1434
1435 Initialize a new repository in the given directory. If the given
1435 Initialize a new repository in the given directory. If the given
1436 directory does not exist, it is created.
1436 directory does not exist, it is created.
1437
1437
1438 If no directory is given, the current directory is used.
1438 If no directory is given, the current directory is used.
1439 """
1439 """
1440 if not os.path.exists(dest):
1440 if not os.path.exists(dest):
1441 os.mkdir(dest)
1441 os.mkdir(dest)
1442 hg.repository(ui, dest, create=1)
1442 hg.repository(ui, dest, create=1)
1443
1443
1444 def locate(ui, repo, *pats, **opts):
1444 def locate(ui, repo, *pats, **opts):
1445 """locate files matching specific patterns
1445 """locate files matching specific patterns
1446
1446
1447 Print all files under Mercurial control whose names match the
1447 Print all files under Mercurial control whose names match the
1448 given patterns.
1448 given patterns.
1449
1449
1450 This command searches the current directory and its
1450 This command searches the current directory and its
1451 subdirectories. To search an entire repository, move to the root
1451 subdirectories. To search an entire repository, move to the root
1452 of the repository.
1452 of the repository.
1453
1453
1454 If no patterns are given to match, this command prints all file
1454 If no patterns are given to match, this command prints all file
1455 names.
1455 names.
1456
1456
1457 If you want to feed the output of this command into the "xargs"
1457 If you want to feed the output of this command into the "xargs"
1458 command, use the "-0" option to both this command and "xargs".
1458 command, use the "-0" option to both this command and "xargs".
1459 This will avoid the problem of "xargs" treating single filenames
1459 This will avoid the problem of "xargs" treating single filenames
1460 that contain white space as multiple filenames.
1460 that contain white space as multiple filenames.
1461 """
1461 """
1462 end = opts['print0'] and '\0' or '\n'
1462 end = opts['print0'] and '\0' or '\n'
1463
1463
1464 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1464 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1465 if repo.dirstate.state(abs) == '?':
1465 if repo.dirstate.state(abs) == '?':
1466 continue
1466 continue
1467 if opts['fullpath']:
1467 if opts['fullpath']:
1468 ui.write(os.path.join(repo.root, abs), end)
1468 ui.write(os.path.join(repo.root, abs), end)
1469 else:
1469 else:
1470 ui.write(rel, end)
1470 ui.write(rel, end)
1471
1471
1472 def log(ui, repo, *pats, **opts):
1472 def log(ui, repo, *pats, **opts):
1473 """show revision history of entire repository or files
1473 """show revision history of entire repository or files
1474
1474
1475 Print the revision history of the specified files or the entire project.
1475 Print the revision history of the specified files or the entire project.
1476
1476
1477 By default this command outputs: changeset id and hash, tags,
1477 By default this command outputs: changeset id and hash, tags,
1478 parents, user, date and time, and a summary for each commit. The
1478 non-trivial parents, user, date and time, and a summary for each
1479 -v switch adds some more detail, such as changed files, manifest
1479 commit. When the -v/--verbose switch is used, the list of changed
1480 hashes or message signatures.
1480 files and full commit message is shown.
1481 """
1481 """
1482 class dui:
1482 class dui:
1483 # Implement and delegate some ui protocol. Save hunks of
1483 # Implement and delegate some ui protocol. Save hunks of
1484 # output for later display in the desired order.
1484 # output for later display in the desired order.
1485 def __init__(self, ui):
1485 def __init__(self, ui):
1486 self.ui = ui
1486 self.ui = ui
1487 self.hunk = {}
1487 self.hunk = {}
1488 def bump(self, rev):
1488 def bump(self, rev):
1489 self.rev = rev
1489 self.rev = rev
1490 self.hunk[rev] = []
1490 self.hunk[rev] = []
1491 def note(self, *args):
1491 def note(self, *args):
1492 if self.verbose:
1492 if self.verbose:
1493 self.write(*args)
1493 self.write(*args)
1494 def status(self, *args):
1494 def status(self, *args):
1495 if not self.quiet:
1495 if not self.quiet:
1496 self.write(*args)
1496 self.write(*args)
1497 def write(self, *args):
1497 def write(self, *args):
1498 self.hunk[self.rev].append(args)
1498 self.hunk[self.rev].append(args)
1499 def debug(self, *args):
1499 def debug(self, *args):
1500 if self.debugflag:
1500 if self.debugflag:
1501 self.write(*args)
1501 self.write(*args)
1502 def __getattr__(self, key):
1502 def __getattr__(self, key):
1503 return getattr(self.ui, key)
1503 return getattr(self.ui, key)
1504 cwd = repo.getcwd()
1504 cwd = repo.getcwd()
1505 if not pats and cwd:
1505 if not pats and cwd:
1506 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1506 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1507 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1507 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1508 changeiter, getchange = walkchangerevs(ui, repo, (pats and cwd) or '',
1508 changeiter, getchange = walkchangerevs(ui, repo, (pats and cwd) or '',
1509 pats, opts)
1509 pats, opts)
1510 for st, rev, fns in changeiter:
1510 for st, rev, fns in changeiter:
1511 if st == 'window':
1511 if st == 'window':
1512 du = dui(ui)
1512 du = dui(ui)
1513 elif st == 'add':
1513 elif st == 'add':
1514 du.bump(rev)
1514 du.bump(rev)
1515 changenode = repo.changelog.node(rev)
1515 changenode = repo.changelog.node(rev)
1516 parents = [p for p in repo.changelog.parents(changenode)
1516 parents = [p for p in repo.changelog.parents(changenode)
1517 if p != nullid]
1517 if p != nullid]
1518 if opts['no_merges'] and len(parents) == 2:
1518 if opts['no_merges'] and len(parents) == 2:
1519 continue
1519 continue
1520 if opts['only_merges'] and len(parents) != 2:
1520 if opts['only_merges'] and len(parents) != 2:
1521 continue
1521 continue
1522
1522
1523 br = None
1523 br = None
1524 if opts['keyword']:
1524 if opts['keyword']:
1525 changes = repo.changelog.read(repo.changelog.node(rev))
1525 changes = repo.changelog.read(repo.changelog.node(rev))
1526 miss = 0
1526 miss = 0
1527 for k in [kw.lower() for kw in opts['keyword']]:
1527 for k in [kw.lower() for kw in opts['keyword']]:
1528 if not (k in changes[1].lower() or
1528 if not (k in changes[1].lower() or
1529 k in changes[4].lower() or
1529 k in changes[4].lower() or
1530 k in " ".join(changes[3][:20]).lower()):
1530 k in " ".join(changes[3][:20]).lower()):
1531 miss = 1
1531 miss = 1
1532 break
1532 break
1533 if miss:
1533 if miss:
1534 continue
1534 continue
1535
1535
1536 if opts['branch']:
1536 if opts['branch']:
1537 br = repo.branchlookup([repo.changelog.node(rev)])
1537 br = repo.branchlookup([repo.changelog.node(rev)])
1538
1538
1539 show_changeset(du, repo, rev, brinfo=br)
1539 show_changeset(du, repo, rev, brinfo=br)
1540 if opts['patch']:
1540 if opts['patch']:
1541 prev = (parents and parents[0]) or nullid
1541 prev = (parents and parents[0]) or nullid
1542 dodiff(du, du, repo, prev, changenode, fns)
1542 dodiff(du, du, repo, prev, changenode, fns)
1543 du.write("\n\n")
1543 du.write("\n\n")
1544 elif st == 'iter':
1544 elif st == 'iter':
1545 for args in du.hunk[rev]:
1545 for args in du.hunk[rev]:
1546 ui.write(*args)
1546 ui.write(*args)
1547
1547
1548 def manifest(ui, repo, rev=None):
1548 def manifest(ui, repo, rev=None):
1549 """output the latest or given revision of the project manifest
1549 """output the latest or given revision of the project manifest
1550
1550
1551 Print a list of version controlled files for the given revision.
1551 Print a list of version controlled files for the given revision.
1552
1552
1553 The manifest is the list of files being version controlled. If no revision
1553 The manifest is the list of files being version controlled. If no revision
1554 is given then the tip is used.
1554 is given then the tip is used.
1555 """
1555 """
1556 if rev:
1556 if rev:
1557 try:
1557 try:
1558 # assume all revision numbers are for changesets
1558 # assume all revision numbers are for changesets
1559 n = repo.lookup(rev)
1559 n = repo.lookup(rev)
1560 change = repo.changelog.read(n)
1560 change = repo.changelog.read(n)
1561 n = change[0]
1561 n = change[0]
1562 except hg.RepoError:
1562 except hg.RepoError:
1563 n = repo.manifest.lookup(rev)
1563 n = repo.manifest.lookup(rev)
1564 else:
1564 else:
1565 n = repo.manifest.tip()
1565 n = repo.manifest.tip()
1566 m = repo.manifest.read(n)
1566 m = repo.manifest.read(n)
1567 mf = repo.manifest.readflags(n)
1567 mf = repo.manifest.readflags(n)
1568 files = m.keys()
1568 files = m.keys()
1569 files.sort()
1569 files.sort()
1570
1570
1571 for f in files:
1571 for f in files:
1572 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1572 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1573
1573
1574 def outgoing(ui, repo, dest="default-push", **opts):
1574 def outgoing(ui, repo, dest="default-push", **opts):
1575 """show changesets not found in destination
1575 """show changesets not found in destination
1576
1576
1577 Show changesets not found in the specified destination repo or the
1577 Show changesets not found in the specified destination repo or the
1578 default push repo. These are the changesets that would be pushed
1578 default push repo. These are the changesets that would be pushed
1579 if a push was requested.
1579 if a push was requested.
1580 """
1580 """
1581 dest = ui.expandpath(dest, repo.root)
1581 dest = ui.expandpath(dest, repo.root)
1582 other = hg.repository(ui, dest)
1582 other = hg.repository(ui, dest)
1583 o = repo.findoutgoing(other)
1583 o = repo.findoutgoing(other)
1584 o = repo.changelog.nodesbetween(o)[0]
1584 o = repo.changelog.nodesbetween(o)[0]
1585 if opts['newest_first']:
1585 if opts['newest_first']:
1586 o.reverse()
1586 o.reverse()
1587 for n in o:
1587 for n in o:
1588 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1588 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1589 if opts['no_merges'] and len(parents) == 2:
1589 if opts['no_merges'] and len(parents) == 2:
1590 continue
1590 continue
1591 show_changeset(ui, repo, changenode=n)
1591 show_changeset(ui, repo, changenode=n)
1592 if opts['patch']:
1592 if opts['patch']:
1593 prev = (parents and parents[0]) or nullid
1593 prev = (parents and parents[0]) or nullid
1594 dodiff(ui, ui, repo, prev, n)
1594 dodiff(ui, ui, repo, prev, n)
1595 ui.write("\n")
1595 ui.write("\n")
1596
1596
1597 def parents(ui, repo, rev=None):
1597 def parents(ui, repo, rev=None):
1598 """show the parents of the working dir or revision
1598 """show the parents of the working dir or revision
1599
1599
1600 Print the working directory's parent revisions.
1600 Print the working directory's parent revisions.
1601 """
1601 """
1602 if rev:
1602 if rev:
1603 p = repo.changelog.parents(repo.lookup(rev))
1603 p = repo.changelog.parents(repo.lookup(rev))
1604 else:
1604 else:
1605 p = repo.dirstate.parents()
1605 p = repo.dirstate.parents()
1606
1606
1607 for n in p:
1607 for n in p:
1608 if n != nullid:
1608 if n != nullid:
1609 show_changeset(ui, repo, changenode=n)
1609 show_changeset(ui, repo, changenode=n)
1610
1610
1611 def paths(ui, search=None):
1611 def paths(ui, search=None):
1612 """show definition of symbolic path names
1612 """show definition of symbolic path names
1613
1613
1614 Show definition of symbolic path name NAME. If no name is given, show
1614 Show definition of symbolic path name NAME. If no name is given, show
1615 definition of available names.
1615 definition of available names.
1616
1616
1617 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1617 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1618 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1618 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1619 """
1619 """
1620 try:
1620 try:
1621 repo = hg.repository(ui=ui)
1621 repo = hg.repository(ui=ui)
1622 except hg.RepoError:
1622 except hg.RepoError:
1623 pass
1623 pass
1624
1624
1625 if search:
1625 if search:
1626 for name, path in ui.configitems("paths"):
1626 for name, path in ui.configitems("paths"):
1627 if name == search:
1627 if name == search:
1628 ui.write("%s\n" % path)
1628 ui.write("%s\n" % path)
1629 return
1629 return
1630 ui.warn(_("not found!\n"))
1630 ui.warn(_("not found!\n"))
1631 return 1
1631 return 1
1632 else:
1632 else:
1633 for name, path in ui.configitems("paths"):
1633 for name, path in ui.configitems("paths"):
1634 ui.write("%s = %s\n" % (name, path))
1634 ui.write("%s = %s\n" % (name, path))
1635
1635
1636 def pull(ui, repo, source="default", **opts):
1636 def pull(ui, repo, source="default", **opts):
1637 """pull changes from the specified source
1637 """pull changes from the specified source
1638
1638
1639 Pull changes from a remote repository to a local one.
1639 Pull changes from a remote repository to a local one.
1640
1640
1641 This finds all changes from the repository at the specified path
1641 This finds all changes from the repository at the specified path
1642 or URL and adds them to the local repository. By default, this
1642 or URL and adds them to the local repository. By default, this
1643 does not update the copy of the project in the working directory.
1643 does not update the copy of the project in the working directory.
1644
1644
1645 Valid URLs are of the form:
1645 Valid URLs are of the form:
1646
1646
1647 local/filesystem/path
1647 local/filesystem/path
1648 http://[user@]host[:port][/path]
1648 http://[user@]host[:port][/path]
1649 https://[user@]host[:port][/path]
1649 https://[user@]host[:port][/path]
1650 ssh://[user@]host[:port][/path]
1650 ssh://[user@]host[:port][/path]
1651
1651
1652 SSH requires an accessible shell account on the destination machine
1652 SSH requires an accessible shell account on the destination machine
1653 and a copy of hg in the remote path. With SSH, paths are relative
1653 and a copy of hg in the remote path. With SSH, paths are relative
1654 to the remote user's home directory by default; use two slashes at
1654 to the remote user's home directory by default; use two slashes at
1655 the start of a path to specify it as relative to the filesystem root.
1655 the start of a path to specify it as relative to the filesystem root.
1656 """
1656 """
1657 source = ui.expandpath(source, repo.root)
1657 source = ui.expandpath(source, repo.root)
1658 ui.status(_('pulling from %s\n') % (source))
1658 ui.status(_('pulling from %s\n') % (source))
1659
1659
1660 if opts['ssh']:
1660 if opts['ssh']:
1661 ui.setconfig("ui", "ssh", opts['ssh'])
1661 ui.setconfig("ui", "ssh", opts['ssh'])
1662 if opts['remotecmd']:
1662 if opts['remotecmd']:
1663 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1663 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1664
1664
1665 other = hg.repository(ui, source)
1665 other = hg.repository(ui, source)
1666 revs = None
1666 revs = None
1667 if opts['rev'] and not other.local():
1667 if opts['rev'] and not other.local():
1668 raise util.Abort("pull -r doesn't work for remote repositories yet")
1668 raise util.Abort("pull -r doesn't work for remote repositories yet")
1669 elif opts['rev']:
1669 elif opts['rev']:
1670 revs = [other.lookup(rev) for rev in opts['rev']]
1670 revs = [other.lookup(rev) for rev in opts['rev']]
1671 r = repo.pull(other, heads=revs)
1671 r = repo.pull(other, heads=revs)
1672 if not r:
1672 if not r:
1673 if opts['update']:
1673 if opts['update']:
1674 return update(ui, repo)
1674 return update(ui, repo)
1675 else:
1675 else:
1676 ui.status(_("(run 'hg update' to get a working copy)\n"))
1676 ui.status(_("(run 'hg update' to get a working copy)\n"))
1677
1677
1678 return r
1678 return r
1679
1679
1680 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1680 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1681 """push changes to the specified destination
1681 """push changes to the specified destination
1682
1682
1683 Push changes from the local repository to the given destination.
1683 Push changes from the local repository to the given destination.
1684
1684
1685 This is the symmetrical operation for pull. It helps to move
1685 This is the symmetrical operation for pull. It helps to move
1686 changes from the current repository to a different one. If the
1686 changes from the current repository to a different one. If the
1687 destination is local this is identical to a pull in that directory
1687 destination is local this is identical to a pull in that directory
1688 from the current one.
1688 from the current one.
1689
1689
1690 By default, push will refuse to run if it detects the result would
1690 By default, push will refuse to run if it detects the result would
1691 increase the number of remote heads. This generally indicates the
1691 increase the number of remote heads. This generally indicates the
1692 the client has forgotten to sync and merge before pushing.
1692 the client has forgotten to sync and merge before pushing.
1693
1693
1694 Valid URLs are of the form:
1694 Valid URLs are of the form:
1695
1695
1696 local/filesystem/path
1696 local/filesystem/path
1697 ssh://[user@]host[:port][/path]
1697 ssh://[user@]host[:port][/path]
1698
1698
1699 SSH requires an accessible shell account on the destination
1699 SSH requires an accessible shell account on the destination
1700 machine and a copy of hg in the remote path.
1700 machine and a copy of hg in the remote path.
1701 """
1701 """
1702 dest = ui.expandpath(dest, repo.root)
1702 dest = ui.expandpath(dest, repo.root)
1703 ui.status('pushing to %s\n' % (dest))
1703 ui.status('pushing to %s\n' % (dest))
1704
1704
1705 if ssh:
1705 if ssh:
1706 ui.setconfig("ui", "ssh", ssh)
1706 ui.setconfig("ui", "ssh", ssh)
1707 if remotecmd:
1707 if remotecmd:
1708 ui.setconfig("ui", "remotecmd", remotecmd)
1708 ui.setconfig("ui", "remotecmd", remotecmd)
1709
1709
1710 other = hg.repository(ui, dest)
1710 other = hg.repository(ui, dest)
1711 r = repo.push(other, force)
1711 r = repo.push(other, force)
1712 return r
1712 return r
1713
1713
1714 def rawcommit(ui, repo, *flist, **rc):
1714 def rawcommit(ui, repo, *flist, **rc):
1715 """raw commit interface
1715 """raw commit interface
1716
1716
1717 Lowlevel commit, for use in helper scripts.
1717 Lowlevel commit, for use in helper scripts.
1718
1718
1719 This command is not intended to be used by normal users, as it is
1719 This command is not intended to be used by normal users, as it is
1720 primarily useful for importing from other SCMs.
1720 primarily useful for importing from other SCMs.
1721 """
1721 """
1722 message = rc['message']
1722 message = rc['message']
1723 if not message and rc['logfile']:
1723 if not message and rc['logfile']:
1724 try:
1724 try:
1725 message = open(rc['logfile']).read()
1725 message = open(rc['logfile']).read()
1726 except IOError:
1726 except IOError:
1727 pass
1727 pass
1728 if not message and not rc['logfile']:
1728 if not message and not rc['logfile']:
1729 raise util.Abort(_("missing commit message"))
1729 raise util.Abort(_("missing commit message"))
1730
1730
1731 files = relpath(repo, list(flist))
1731 files = relpath(repo, list(flist))
1732 if rc['files']:
1732 if rc['files']:
1733 files += open(rc['files']).read().splitlines()
1733 files += open(rc['files']).read().splitlines()
1734
1734
1735 rc['parent'] = map(repo.lookup, rc['parent'])
1735 rc['parent'] = map(repo.lookup, rc['parent'])
1736
1736
1737 try:
1737 try:
1738 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1738 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1739 except ValueError, inst:
1739 except ValueError, inst:
1740 raise util.Abort(str(inst))
1740 raise util.Abort(str(inst))
1741
1741
1742 def recover(ui, repo):
1742 def recover(ui, repo):
1743 """roll back an interrupted transaction
1743 """roll back an interrupted transaction
1744
1744
1745 Recover from an interrupted commit or pull.
1745 Recover from an interrupted commit or pull.
1746
1746
1747 This command tries to fix the repository status after an interrupted
1747 This command tries to fix the repository status after an interrupted
1748 operation. It should only be necessary when Mercurial suggests it.
1748 operation. It should only be necessary when Mercurial suggests it.
1749 """
1749 """
1750 if repo.recover():
1750 if repo.recover():
1751 return repo.verify()
1751 return repo.verify()
1752 return False
1752 return False
1753
1753
1754 def remove(ui, repo, pat, *pats, **opts):
1754 def remove(ui, repo, pat, *pats, **opts):
1755 """remove the specified files on the next commit
1755 """remove the specified files on the next commit
1756
1756
1757 Schedule the indicated files for removal from the repository.
1757 Schedule the indicated files for removal from the repository.
1758
1758
1759 This command schedules the files to be removed at the next commit.
1759 This command schedules the files to be removed at the next commit.
1760 This only removes files from the current branch, not from the
1760 This only removes files from the current branch, not from the
1761 entire project history. If the files still exist in the working
1761 entire project history. If the files still exist in the working
1762 directory, they will be deleted from it.
1762 directory, they will be deleted from it.
1763 """
1763 """
1764 names = []
1764 names = []
1765 def okaytoremove(abs, rel, exact):
1765 def okaytoremove(abs, rel, exact):
1766 c, a, d, u = repo.changes(files = [abs])
1766 c, a, d, u = repo.changes(files = [abs])
1767 reason = None
1767 reason = None
1768 if c: reason = _('is modified')
1768 if c: reason = _('is modified')
1769 elif a: reason = _('has been marked for add')
1769 elif a: reason = _('has been marked for add')
1770 elif u: reason = _('is not managed')
1770 elif u: reason = _('is not managed')
1771 if reason:
1771 if reason:
1772 if exact: ui.warn(_('not removing %s: file %s\n') % (rel, reason))
1772 if exact: ui.warn(_('not removing %s: file %s\n') % (rel, reason))
1773 else:
1773 else:
1774 return True
1774 return True
1775 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
1775 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
1776 if okaytoremove(abs, rel, exact):
1776 if okaytoremove(abs, rel, exact):
1777 if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
1777 if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
1778 names.append(abs)
1778 names.append(abs)
1779 repo.remove(names, unlink=True)
1779 repo.remove(names, unlink=True)
1780
1780
1781 def rename(ui, repo, *pats, **opts):
1781 def rename(ui, repo, *pats, **opts):
1782 """rename files; equivalent of copy + remove
1782 """rename files; equivalent of copy + remove
1783
1783
1784 Mark dest as copies of sources; mark sources for deletion. If
1784 Mark dest as copies of sources; mark sources for deletion. If
1785 dest is a directory, copies are put in that directory. If dest is
1785 dest is a directory, copies are put in that directory. If dest is
1786 a file, there can only be one source.
1786 a file, there can only be one source.
1787
1787
1788 By default, this command copies the contents of files as they
1788 By default, this command copies the contents of files as they
1789 stand in the working directory. If invoked with --after, the
1789 stand in the working directory. If invoked with --after, the
1790 operation is recorded, but no copying is performed.
1790 operation is recorded, but no copying is performed.
1791
1791
1792 This command takes effect in the next commit.
1792 This command takes effect in the next commit.
1793
1793
1794 NOTE: This command should be treated as experimental. While it
1794 NOTE: This command should be treated as experimental. While it
1795 should properly record rename files, this information is not yet
1795 should properly record rename files, this information is not yet
1796 fully used by merge, nor fully reported by log.
1796 fully used by merge, nor fully reported by log.
1797 """
1797 """
1798 errs, copied = docopy(ui, repo, pats, opts)
1798 errs, copied = docopy(ui, repo, pats, opts)
1799 names = []
1799 names = []
1800 for abs, rel, exact in copied:
1800 for abs, rel, exact in copied:
1801 if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
1801 if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
1802 names.append(abs)
1802 names.append(abs)
1803 repo.remove(names, unlink=True)
1803 repo.remove(names, unlink=True)
1804 return errs
1804 return errs
1805
1805
1806 def revert(ui, repo, *pats, **opts):
1806 def revert(ui, repo, *pats, **opts):
1807 """revert modified files or dirs back to their unmodified states
1807 """revert modified files or dirs back to their unmodified states
1808
1808
1809 Revert any uncommitted modifications made to the named files or
1809 Revert any uncommitted modifications made to the named files or
1810 directories. This restores the contents of the affected files to
1810 directories. This restores the contents of the affected files to
1811 an unmodified state.
1811 an unmodified state.
1812
1812
1813 If a file has been deleted, it is recreated. If the executable
1813 If a file has been deleted, it is recreated. If the executable
1814 mode of a file was changed, it is reset.
1814 mode of a file was changed, it is reset.
1815
1815
1816 If names are given, all files matching the names are reverted.
1816 If names are given, all files matching the names are reverted.
1817
1817
1818 If no names are given, all files in the current directory and
1818 If no names are given, all files in the current directory and
1819 its subdirectories are reverted.
1819 its subdirectories are reverted.
1820 """
1820 """
1821 node = opts['rev'] and repo.lookup(opts['rev']) or \
1821 node = opts['rev'] and repo.lookup(opts['rev']) or \
1822 repo.dirstate.parents()[0]
1822 repo.dirstate.parents()[0]
1823
1823
1824 files, choose, anypats = matchpats(repo, repo.getcwd(), pats, opts)
1824 files, choose, anypats = matchpats(repo, repo.getcwd(), pats, opts)
1825 (c, a, d, u) = repo.changes(match=choose)
1825 (c, a, d, u) = repo.changes(match=choose)
1826 repo.forget(a)
1826 repo.forget(a)
1827 repo.undelete(d)
1827 repo.undelete(d)
1828
1828
1829 return repo.update(node, False, True, choose, False)
1829 return repo.update(node, False, True, choose, False)
1830
1830
1831 def root(ui, repo):
1831 def root(ui, repo):
1832 """print the root (top) of the current working dir
1832 """print the root (top) of the current working dir
1833
1833
1834 Print the root directory of the current repository.
1834 Print the root directory of the current repository.
1835 """
1835 """
1836 ui.write(repo.root + "\n")
1836 ui.write(repo.root + "\n")
1837
1837
1838 def serve(ui, repo, **opts):
1838 def serve(ui, repo, **opts):
1839 """export the repository via HTTP
1839 """export the repository via HTTP
1840
1840
1841 Start a local HTTP repository browser and pull server.
1841 Start a local HTTP repository browser and pull server.
1842
1842
1843 By default, the server logs accesses to stdout and errors to
1843 By default, the server logs accesses to stdout and errors to
1844 stderr. Use the "-A" and "-E" options to log to files.
1844 stderr. Use the "-A" and "-E" options to log to files.
1845 """
1845 """
1846
1846
1847 if opts["stdio"]:
1847 if opts["stdio"]:
1848 fin, fout = sys.stdin, sys.stdout
1848 fin, fout = sys.stdin, sys.stdout
1849 sys.stdout = sys.stderr
1849 sys.stdout = sys.stderr
1850
1850
1851 # Prevent insertion/deletion of CRs
1851 # Prevent insertion/deletion of CRs
1852 util.set_binary(fin)
1852 util.set_binary(fin)
1853 util.set_binary(fout)
1853 util.set_binary(fout)
1854
1854
1855 def getarg():
1855 def getarg():
1856 argline = fin.readline()[:-1]
1856 argline = fin.readline()[:-1]
1857 arg, l = argline.split()
1857 arg, l = argline.split()
1858 val = fin.read(int(l))
1858 val = fin.read(int(l))
1859 return arg, val
1859 return arg, val
1860 def respond(v):
1860 def respond(v):
1861 fout.write("%d\n" % len(v))
1861 fout.write("%d\n" % len(v))
1862 fout.write(v)
1862 fout.write(v)
1863 fout.flush()
1863 fout.flush()
1864
1864
1865 lock = None
1865 lock = None
1866
1866
1867 while 1:
1867 while 1:
1868 cmd = fin.readline()[:-1]
1868 cmd = fin.readline()[:-1]
1869 if cmd == '':
1869 if cmd == '':
1870 return
1870 return
1871 if cmd == "heads":
1871 if cmd == "heads":
1872 h = repo.heads()
1872 h = repo.heads()
1873 respond(" ".join(map(hex, h)) + "\n")
1873 respond(" ".join(map(hex, h)) + "\n")
1874 if cmd == "lock":
1874 if cmd == "lock":
1875 lock = repo.lock()
1875 lock = repo.lock()
1876 respond("")
1876 respond("")
1877 if cmd == "unlock":
1877 if cmd == "unlock":
1878 if lock:
1878 if lock:
1879 lock.release()
1879 lock.release()
1880 lock = None
1880 lock = None
1881 respond("")
1881 respond("")
1882 elif cmd == "branches":
1882 elif cmd == "branches":
1883 arg, nodes = getarg()
1883 arg, nodes = getarg()
1884 nodes = map(bin, nodes.split(" "))
1884 nodes = map(bin, nodes.split(" "))
1885 r = []
1885 r = []
1886 for b in repo.branches(nodes):
1886 for b in repo.branches(nodes):
1887 r.append(" ".join(map(hex, b)) + "\n")
1887 r.append(" ".join(map(hex, b)) + "\n")
1888 respond("".join(r))
1888 respond("".join(r))
1889 elif cmd == "between":
1889 elif cmd == "between":
1890 arg, pairs = getarg()
1890 arg, pairs = getarg()
1891 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
1891 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
1892 r = []
1892 r = []
1893 for b in repo.between(pairs):
1893 for b in repo.between(pairs):
1894 r.append(" ".join(map(hex, b)) + "\n")
1894 r.append(" ".join(map(hex, b)) + "\n")
1895 respond("".join(r))
1895 respond("".join(r))
1896 elif cmd == "changegroup":
1896 elif cmd == "changegroup":
1897 nodes = []
1897 nodes = []
1898 arg, roots = getarg()
1898 arg, roots = getarg()
1899 nodes = map(bin, roots.split(" "))
1899 nodes = map(bin, roots.split(" "))
1900
1900
1901 cg = repo.changegroup(nodes)
1901 cg = repo.changegroup(nodes)
1902 while 1:
1902 while 1:
1903 d = cg.read(4096)
1903 d = cg.read(4096)
1904 if not d:
1904 if not d:
1905 break
1905 break
1906 fout.write(d)
1906 fout.write(d)
1907
1907
1908 fout.flush()
1908 fout.flush()
1909
1909
1910 elif cmd == "addchangegroup":
1910 elif cmd == "addchangegroup":
1911 if not lock:
1911 if not lock:
1912 respond("not locked")
1912 respond("not locked")
1913 continue
1913 continue
1914 respond("")
1914 respond("")
1915
1915
1916 r = repo.addchangegroup(fin)
1916 r = repo.addchangegroup(fin)
1917 respond("")
1917 respond("")
1918
1918
1919 optlist = "name templates style address port ipv6 accesslog errorlog"
1919 optlist = "name templates style address port ipv6 accesslog errorlog"
1920 for o in optlist.split():
1920 for o in optlist.split():
1921 if opts[o]:
1921 if opts[o]:
1922 ui.setconfig("web", o, opts[o])
1922 ui.setconfig("web", o, opts[o])
1923
1923
1924 try:
1924 try:
1925 httpd = hgweb.create_server(repo)
1925 httpd = hgweb.create_server(repo)
1926 except socket.error, inst:
1926 except socket.error, inst:
1927 raise util.Abort('cannot start server: ' + inst.args[1])
1927 raise util.Abort('cannot start server: ' + inst.args[1])
1928
1928
1929 if ui.verbose:
1929 if ui.verbose:
1930 addr, port = httpd.socket.getsockname()
1930 addr, port = httpd.socket.getsockname()
1931 if addr == '0.0.0.0':
1931 if addr == '0.0.0.0':
1932 addr = socket.gethostname()
1932 addr = socket.gethostname()
1933 else:
1933 else:
1934 try:
1934 try:
1935 addr = socket.gethostbyaddr(addr)[0]
1935 addr = socket.gethostbyaddr(addr)[0]
1936 except socket.error:
1936 except socket.error:
1937 pass
1937 pass
1938 if port != 80:
1938 if port != 80:
1939 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
1939 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
1940 else:
1940 else:
1941 ui.status(_('listening at http://%s/\n') % addr)
1941 ui.status(_('listening at http://%s/\n') % addr)
1942 httpd.serve_forever()
1942 httpd.serve_forever()
1943
1943
1944 def status(ui, repo, *pats, **opts):
1944 def status(ui, repo, *pats, **opts):
1945 """show changed files in the working directory
1945 """show changed files in the working directory
1946
1946
1947 Show changed files in the working directory. If no names are
1947 Show changed files in the working directory. If no names are
1948 given, all files are shown. Otherwise, only files matching the
1948 given, all files are shown. Otherwise, only files matching the
1949 given names are shown.
1949 given names are shown.
1950
1950
1951 The codes used to show the status of files are:
1951 The codes used to show the status of files are:
1952 M = modified
1952 M = modified
1953 A = added
1953 A = added
1954 R = removed
1954 R = removed
1955 ? = not tracked
1955 ? = not tracked
1956 """
1956 """
1957
1957
1958 cwd = repo.getcwd()
1958 cwd = repo.getcwd()
1959 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1959 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1960 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1960 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1961 for n in repo.changes(files=files, match=matchfn)]
1961 for n in repo.changes(files=files, match=matchfn)]
1962
1962
1963 changetypes = [(_('modified'), 'M', c),
1963 changetypes = [(_('modified'), 'M', c),
1964 (_('added'), 'A', a),
1964 (_('added'), 'A', a),
1965 (_('removed'), 'R', d),
1965 (_('removed'), 'R', d),
1966 (_('unknown'), '?', u)]
1966 (_('unknown'), '?', u)]
1967
1967
1968 end = opts['print0'] and '\0' or '\n'
1968 end = opts['print0'] and '\0' or '\n'
1969
1969
1970 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1970 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1971 or changetypes):
1971 or changetypes):
1972 if opts['no_status']:
1972 if opts['no_status']:
1973 format = "%%s%s" % end
1973 format = "%%s%s" % end
1974 else:
1974 else:
1975 format = "%s %%s%s" % (char, end);
1975 format = "%s %%s%s" % (char, end);
1976
1976
1977 for f in changes:
1977 for f in changes:
1978 ui.write(format % f)
1978 ui.write(format % f)
1979
1979
1980 def tag(ui, repo, name, rev=None, **opts):
1980 def tag(ui, repo, name, rev=None, **opts):
1981 """add a tag for the current tip or a given revision
1981 """add a tag for the current tip or a given revision
1982
1982
1983 Name a particular revision using <name>.
1983 Name a particular revision using <name>.
1984
1984
1985 Tags are used to name particular revisions of the repository and are
1985 Tags are used to name particular revisions of the repository and are
1986 very useful to compare different revision, to go back to significant
1986 very useful to compare different revision, to go back to significant
1987 earlier versions or to mark branch points as releases, etc.
1987 earlier versions or to mark branch points as releases, etc.
1988
1988
1989 If no revision is given, the tip is used.
1989 If no revision is given, the tip is used.
1990
1990
1991 To facilitate version control, distribution, and merging of tags,
1991 To facilitate version control, distribution, and merging of tags,
1992 they are stored as a file named ".hgtags" which is managed
1992 they are stored as a file named ".hgtags" which is managed
1993 similarly to other project files and can be hand-edited if
1993 similarly to other project files and can be hand-edited if
1994 necessary.
1994 necessary.
1995 """
1995 """
1996 if name == "tip":
1996 if name == "tip":
1997 raise util.Abort(_("the name 'tip' is reserved"))
1997 raise util.Abort(_("the name 'tip' is reserved"))
1998 if 'rev' in opts:
1998 if 'rev' in opts:
1999 rev = opts['rev']
1999 rev = opts['rev']
2000 if rev:
2000 if rev:
2001 r = hex(repo.lookup(rev))
2001 r = hex(repo.lookup(rev))
2002 else:
2002 else:
2003 r = hex(repo.changelog.tip())
2003 r = hex(repo.changelog.tip())
2004
2004
2005 if name.find(revrangesep) >= 0:
2005 if name.find(revrangesep) >= 0:
2006 raise util.Abort(_("'%s' cannot be used in a tag name") % revrangesep)
2006 raise util.Abort(_("'%s' cannot be used in a tag name") % revrangesep)
2007
2007
2008 if opts['local']:
2008 if opts['local']:
2009 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
2009 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
2010 return
2010 return
2011
2011
2012 (c, a, d, u) = repo.changes()
2012 (c, a, d, u) = repo.changes()
2013 for x in (c, a, d, u):
2013 for x in (c, a, d, u):
2014 if ".hgtags" in x:
2014 if ".hgtags" in x:
2015 raise util.Abort(_("working copy of .hgtags is changed "
2015 raise util.Abort(_("working copy of .hgtags is changed "
2016 "(please commit .hgtags manually)"))
2016 "(please commit .hgtags manually)"))
2017
2017
2018 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
2018 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
2019 if repo.dirstate.state(".hgtags") == '?':
2019 if repo.dirstate.state(".hgtags") == '?':
2020 repo.add([".hgtags"])
2020 repo.add([".hgtags"])
2021
2021
2022 message = (opts['message'] or
2022 message = (opts['message'] or
2023 _("Added tag %s for changeset %s") % (name, r))
2023 _("Added tag %s for changeset %s") % (name, r))
2024 try:
2024 try:
2025 repo.commit([".hgtags"], message, opts['user'], opts['date'])
2025 repo.commit([".hgtags"], message, opts['user'], opts['date'])
2026 except ValueError, inst:
2026 except ValueError, inst:
2027 raise util.Abort(str(inst))
2027 raise util.Abort(str(inst))
2028
2028
2029 def tags(ui, repo):
2029 def tags(ui, repo):
2030 """list repository tags
2030 """list repository tags
2031
2031
2032 List the repository tags.
2032 List the repository tags.
2033
2033
2034 This lists both regular and local tags.
2034 This lists both regular and local tags.
2035 """
2035 """
2036
2036
2037 l = repo.tagslist()
2037 l = repo.tagslist()
2038 l.reverse()
2038 l.reverse()
2039 for t, n in l:
2039 for t, n in l:
2040 try:
2040 try:
2041 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2041 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2042 except KeyError:
2042 except KeyError:
2043 r = " ?:?"
2043 r = " ?:?"
2044 ui.write("%-30s %s\n" % (t, r))
2044 ui.write("%-30s %s\n" % (t, r))
2045
2045
2046 def tip(ui, repo):
2046 def tip(ui, repo):
2047 """show the tip revision
2047 """show the tip revision
2048
2048
2049 Show the tip revision.
2049 Show the tip revision.
2050 """
2050 """
2051 n = repo.changelog.tip()
2051 n = repo.changelog.tip()
2052 show_changeset(ui, repo, changenode=n)
2052 show_changeset(ui, repo, changenode=n)
2053
2053
2054 def unbundle(ui, repo, fname):
2054 def unbundle(ui, repo, fname):
2055 """apply a changegroup file
2055 """apply a changegroup file
2056
2056
2057 Apply a compressed changegroup file generated by the bundle
2057 Apply a compressed changegroup file generated by the bundle
2058 command.
2058 command.
2059 """
2059 """
2060 f = urllib.urlopen(fname)
2060 f = urllib.urlopen(fname)
2061
2061
2062 if f.read(4) != "HG10":
2062 if f.read(4) != "HG10":
2063 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2063 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2064
2064
2065 def bzgenerator(f):
2065 def bzgenerator(f):
2066 zd = bz2.BZ2Decompressor()
2066 zd = bz2.BZ2Decompressor()
2067 for chunk in f:
2067 for chunk in f:
2068 yield zd.decompress(chunk)
2068 yield zd.decompress(chunk)
2069
2069
2070 bzgen = bzgenerator(util.filechunkiter(f, 4096))
2070 bzgen = bzgenerator(util.filechunkiter(f, 4096))
2071 repo.addchangegroup(util.chunkbuffer(bzgen))
2071 repo.addchangegroup(util.chunkbuffer(bzgen))
2072
2072
2073 def undo(ui, repo):
2073 def undo(ui, repo):
2074 """undo the last commit or pull
2074 """undo the last commit or pull
2075
2075
2076 Roll back the last pull or commit transaction on the
2076 Roll back the last pull or commit transaction on the
2077 repository, restoring the project to its earlier state.
2077 repository, restoring the project to its earlier state.
2078
2078
2079 This command should be used with care. There is only one level of
2079 This command should be used with care. There is only one level of
2080 undo and there is no redo.
2080 undo and there is no redo.
2081
2081
2082 This command is not intended for use on public repositories. Once
2082 This command is not intended for use on public repositories. Once
2083 a change is visible for pull by other users, undoing it locally is
2083 a change is visible for pull by other users, undoing it locally is
2084 ineffective.
2084 ineffective.
2085 """
2085 """
2086 repo.undo()
2086 repo.undo()
2087
2087
2088 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
2088 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
2089 """update or merge working directory
2089 """update or merge working directory
2090
2090
2091 Update the working directory to the specified revision.
2091 Update the working directory to the specified revision.
2092
2092
2093 If there are no outstanding changes in the working directory and
2093 If there are no outstanding changes in the working directory and
2094 there is a linear relationship between the current version and the
2094 there is a linear relationship between the current version and the
2095 requested version, the result is the requested version.
2095 requested version, the result is the requested version.
2096
2096
2097 Otherwise the result is a merge between the contents of the
2097 Otherwise the result is a merge between the contents of the
2098 current working directory and the requested version. Files that
2098 current working directory and the requested version. Files that
2099 changed between either parent are marked as changed for the next
2099 changed between either parent are marked as changed for the next
2100 commit and a commit must be performed before any further updates
2100 commit and a commit must be performed before any further updates
2101 are allowed.
2101 are allowed.
2102
2102
2103 By default, update will refuse to run if doing so would require
2103 By default, update will refuse to run if doing so would require
2104 merging or discarding local changes.
2104 merging or discarding local changes.
2105 """
2105 """
2106 if branch:
2106 if branch:
2107 br = repo.branchlookup(branch=branch)
2107 br = repo.branchlookup(branch=branch)
2108 found = []
2108 found = []
2109 for x in br:
2109 for x in br:
2110 if branch in br[x]:
2110 if branch in br[x]:
2111 found.append(x)
2111 found.append(x)
2112 if len(found) > 1:
2112 if len(found) > 1:
2113 ui.warn(_("Found multiple heads for %s\n") % branch)
2113 ui.warn(_("Found multiple heads for %s\n") % branch)
2114 for x in found:
2114 for x in found:
2115 show_changeset(ui, repo, changenode=x, brinfo=br)
2115 show_changeset(ui, repo, changenode=x, brinfo=br)
2116 return 1
2116 return 1
2117 if len(found) == 1:
2117 if len(found) == 1:
2118 node = found[0]
2118 node = found[0]
2119 ui.warn(_("Using head %s for branch %s\n") % (short(node), branch))
2119 ui.warn(_("Using head %s for branch %s\n") % (short(node), branch))
2120 else:
2120 else:
2121 ui.warn(_("branch %s not found\n") % (branch))
2121 ui.warn(_("branch %s not found\n") % (branch))
2122 return 1
2122 return 1
2123 else:
2123 else:
2124 node = node and repo.lookup(node) or repo.changelog.tip()
2124 node = node and repo.lookup(node) or repo.changelog.tip()
2125 return repo.update(node, allow=merge, force=clean)
2125 return repo.update(node, allow=merge, force=clean)
2126
2126
2127 def verify(ui, repo):
2127 def verify(ui, repo):
2128 """verify the integrity of the repository
2128 """verify the integrity of the repository
2129
2129
2130 Verify the integrity of the current repository.
2130 Verify the integrity of the current repository.
2131
2131
2132 This will perform an extensive check of the repository's
2132 This will perform an extensive check of the repository's
2133 integrity, validating the hashes and checksums of each entry in
2133 integrity, validating the hashes and checksums of each entry in
2134 the changelog, manifest, and tracked files, as well as the
2134 the changelog, manifest, and tracked files, as well as the
2135 integrity of their crosslinks and indices.
2135 integrity of their crosslinks and indices.
2136 """
2136 """
2137 return repo.verify()
2137 return repo.verify()
2138
2138
2139 # Command options and aliases are listed here, alphabetically
2139 # Command options and aliases are listed here, alphabetically
2140
2140
2141 table = {
2141 table = {
2142 "^add":
2142 "^add":
2143 (add,
2143 (add,
2144 [('I', 'include', [], _('include names matching the given patterns')),
2144 [('I', 'include', [], _('include names matching the given patterns')),
2145 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2145 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2146 "hg add [OPTION]... [FILE]..."),
2146 "hg add [OPTION]... [FILE]..."),
2147 "addremove":
2147 "addremove":
2148 (addremove,
2148 (addremove,
2149 [('I', 'include', [], _('include names matching the given patterns')),
2149 [('I', 'include', [], _('include names matching the given patterns')),
2150 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2150 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2151 "hg addremove [OPTION]... [FILE]..."),
2151 "hg addremove [OPTION]... [FILE]..."),
2152 "^annotate":
2152 "^annotate":
2153 (annotate,
2153 (annotate,
2154 [('r', 'rev', '', _('annotate the specified revision')),
2154 [('r', 'rev', '', _('annotate the specified revision')),
2155 ('a', 'text', None, _('treat all files as text')),
2155 ('a', 'text', None, _('treat all files as text')),
2156 ('u', 'user', None, _('list the author')),
2156 ('u', 'user', None, _('list the author')),
2157 ('d', 'date', None, _('list the date')),
2157 ('d', 'date', None, _('list the date')),
2158 ('n', 'number', None, _('list the revision number (default)')),
2158 ('n', 'number', None, _('list the revision number (default)')),
2159 ('c', 'changeset', None, _('list the changeset')),
2159 ('c', 'changeset', None, _('list the changeset')),
2160 ('I', 'include', [], _('include names matching the given patterns')),
2160 ('I', 'include', [], _('include names matching the given patterns')),
2161 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2161 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2162 _('hg annotate [OPTION]... FILE...')),
2162 _('hg annotate [OPTION]... FILE...')),
2163 "bundle":
2163 "bundle":
2164 (bundle,
2164 (bundle,
2165 [],
2165 [],
2166 _('hg bundle FILE DEST')),
2166 _('hg bundle FILE DEST')),
2167 "cat":
2167 "cat":
2168 (cat,
2168 (cat,
2169 [('I', 'include', [], _('include names matching the given patterns')),
2169 [('I', 'include', [], _('include names matching the given patterns')),
2170 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2170 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2171 ('o', 'output', "", _('print output to file with formatted name')),
2171 ('o', 'output', "", _('print output to file with formatted name')),
2172 ('r', 'rev', '', _('print the given revision'))],
2172 ('r', 'rev', '', _('print the given revision'))],
2173 _('hg cat [OPTION]... FILE...')),
2173 _('hg cat [OPTION]... FILE...')),
2174 "^clone":
2174 "^clone":
2175 (clone,
2175 (clone,
2176 [('U', 'noupdate', None, _('do not update the new working directory')),
2176 [('U', 'noupdate', None, _('do not update the new working directory')),
2177 ('e', 'ssh', "", _('specify ssh command to use')),
2177 ('e', 'ssh', "", _('specify ssh command to use')),
2178 ('', 'pull', None, _('use pull protocol to copy metadata')),
2178 ('', 'pull', None, _('use pull protocol to copy metadata')),
2179 ('r', 'rev', [], _('a changeset you would like to have after cloning')),
2179 ('r', 'rev', [], _('a changeset you would like to have after cloning')),
2180 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2180 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2181 _('hg clone [OPTION]... SOURCE [DEST]')),
2181 _('hg clone [OPTION]... SOURCE [DEST]')),
2182 "^commit|ci":
2182 "^commit|ci":
2183 (commit,
2183 (commit,
2184 [('A', 'addremove', None, _('run addremove during commit')),
2184 [('A', 'addremove', None, _('run addremove during commit')),
2185 ('I', 'include', [], _('include names matching the given patterns')),
2185 ('I', 'include', [], _('include names matching the given patterns')),
2186 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2186 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2187 ('m', 'message', "", _('use <text> as commit message')),
2187 ('m', 'message', "", _('use <text> as commit message')),
2188 ('l', 'logfile', "", _('read the commit message from <file>')),
2188 ('l', 'logfile', "", _('read the commit message from <file>')),
2189 ('d', 'date', "", _('record datecode as commit date')),
2189 ('d', 'date', "", _('record datecode as commit date')),
2190 ('u', 'user', "", _('record user as commiter'))],
2190 ('u', 'user', "", _('record user as commiter'))],
2191 _('hg commit [OPTION]... [FILE]...')),
2191 _('hg commit [OPTION]... [FILE]...')),
2192 "copy|cp": (copy,
2192 "copy|cp": (copy,
2193 [('I', 'include', [], _('include names matching the given patterns')),
2193 [('I', 'include', [], _('include names matching the given patterns')),
2194 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2194 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2195 ('A', 'after', None, _('record a copy that has already occurred')),
2195 ('A', 'after', None, _('record a copy that has already occurred')),
2196 ('f', 'force', None, _('forcibly copy over an existing managed file'))],
2196 ('f', 'force', None, _('forcibly copy over an existing managed file'))],
2197 _('hg copy [OPTION]... [SOURCE]... DEST')),
2197 _('hg copy [OPTION]... [SOURCE]... DEST')),
2198 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2198 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2199 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2199 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2200 "debugconfig": (debugconfig, [], _('debugconfig')),
2200 "debugconfig": (debugconfig, [], _('debugconfig')),
2201 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2201 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2202 "debugstate": (debugstate, [], _('debugstate')),
2202 "debugstate": (debugstate, [], _('debugstate')),
2203 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2203 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2204 "debugindex": (debugindex, [], _('debugindex FILE')),
2204 "debugindex": (debugindex, [], _('debugindex FILE')),
2205 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2205 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2206 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2206 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2207 "debugwalk":
2207 "debugwalk":
2208 (debugwalk,
2208 (debugwalk,
2209 [('I', 'include', [], _('include names matching the given patterns')),
2209 [('I', 'include', [], _('include names matching the given patterns')),
2210 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2210 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2211 _('debugwalk [OPTION]... [FILE]...')),
2211 _('debugwalk [OPTION]... [FILE]...')),
2212 "^diff":
2212 "^diff":
2213 (diff,
2213 (diff,
2214 [('r', 'rev', [], _('revision')),
2214 [('r', 'rev', [], _('revision')),
2215 ('a', 'text', None, _('treat all files as text')),
2215 ('a', 'text', None, _('treat all files as text')),
2216 ('I', 'include', [], _('include names matching the given patterns')),
2216 ('I', 'include', [], _('include names matching the given patterns')),
2217 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2217 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2218 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2218 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2219 "^export":
2219 "^export":
2220 (export,
2220 (export,
2221 [('o', 'output', "", _('print output to file with formatted name')),
2221 [('o', 'output', "", _('print output to file with formatted name')),
2222 ('a', 'text', None, _('treat all files as text'))],
2222 ('a', 'text', None, _('treat all files as text'))],
2223 "hg export [-a] [-o OUTFILE] REV..."),
2223 "hg export [-a] [-o OUTFILE] REV..."),
2224 "forget":
2224 "forget":
2225 (forget,
2225 (forget,
2226 [('I', 'include', [], _('include names matching the given patterns')),
2226 [('I', 'include', [], _('include names matching the given patterns')),
2227 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2227 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2228 "hg forget [OPTION]... FILE..."),
2228 "hg forget [OPTION]... FILE..."),
2229 "grep":
2229 "grep":
2230 (grep,
2230 (grep,
2231 [('0', 'print0', None, _('end fields with NUL')),
2231 [('0', 'print0', None, _('end fields with NUL')),
2232 ('I', 'include', [], _('include names matching the given patterns')),
2232 ('I', 'include', [], _('include names matching the given patterns')),
2233 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2233 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2234 ('', 'all', None, _('print all revisions that match')),
2234 ('', 'all', None, _('print all revisions that match')),
2235 ('i', 'ignore-case', None, _('ignore case when matching')),
2235 ('i', 'ignore-case', None, _('ignore case when matching')),
2236 ('l', 'files-with-matches', None, _('print only filenames and revs that match')),
2236 ('l', 'files-with-matches', None, _('print only filenames and revs that match')),
2237 ('n', 'line-number', None, _('print matching line numbers')),
2237 ('n', 'line-number', None, _('print matching line numbers')),
2238 ('r', 'rev', [], _('search in given revision range')),
2238 ('r', 'rev', [], _('search in given revision range')),
2239 ('u', 'user', None, _('print user who committed change'))],
2239 ('u', 'user', None, _('print user who committed change'))],
2240 "hg grep [OPTION]... PATTERN [FILE]..."),
2240 "hg grep [OPTION]... PATTERN [FILE]..."),
2241 "heads":
2241 "heads":
2242 (heads,
2242 (heads,
2243 [('b', 'branches', None, _('find branch info')),
2243 [('b', 'branches', None, _('find branch info')),
2244 ('r', 'rev', "", _('show only heads which are descendants of rev'))],
2244 ('r', 'rev', "", _('show only heads which are descendants of rev'))],
2245 _('hg heads [-b] [-r <rev>]')),
2245 _('hg heads [-b] [-r <rev>]')),
2246 "help": (help_, [], _('hg help [COMMAND]')),
2246 "help": (help_, [], _('hg help [COMMAND]')),
2247 "identify|id": (identify, [], _('hg identify')),
2247 "identify|id": (identify, [], _('hg identify')),
2248 "import|patch":
2248 "import|patch":
2249 (import_,
2249 (import_,
2250 [('p', 'strip', 1, _('directory strip option for patch. This has the same\n') +
2250 [('p', 'strip', 1, _('directory strip option for patch. This has the same\n') +
2251 _('meaning as the corresponding patch option')),
2251 _('meaning as the corresponding patch option')),
2252 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
2252 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
2253 ('b', 'base', "", _('base path'))],
2253 ('b', 'base', "", _('base path'))],
2254 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
2254 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
2255 "incoming|in": (incoming,
2255 "incoming|in": (incoming,
2256 [('M', 'no-merges', None, _("do not show merges")),
2256 [('M', 'no-merges', None, _("do not show merges")),
2257 ('p', 'patch', None, _('show patch')),
2257 ('p', 'patch', None, _('show patch')),
2258 ('n', 'newest-first', None, _('show newest record first'))],
2258 ('n', 'newest-first', None, _('show newest record first'))],
2259 _('hg incoming [-p] [-n] [-M] [SOURCE]')),
2259 _('hg incoming [-p] [-n] [-M] [SOURCE]')),
2260 "^init": (init, [], _('hg init [DEST]')),
2260 "^init": (init, [], _('hg init [DEST]')),
2261 "locate":
2261 "locate":
2262 (locate,
2262 (locate,
2263 [('r', 'rev', '', _('search the repository as it stood at rev')),
2263 [('r', 'rev', '', _('search the repository as it stood at rev')),
2264 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2264 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2265 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
2265 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
2266 ('I', 'include', [], _('include names matching the given patterns')),
2266 ('I', 'include', [], _('include names matching the given patterns')),
2267 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2267 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2268 _('hg locate [OPTION]... [PATTERN]...')),
2268 _('hg locate [OPTION]... [PATTERN]...')),
2269 "^log|history":
2269 "^log|history":
2270 (log,
2270 (log,
2271 [('I', 'include', [], _('include names matching the given patterns')),
2271 [('I', 'include', [], _('include names matching the given patterns')),
2272 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2272 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2273 ('b', 'branch', None, _('show branches')),
2273 ('b', 'branch', None, _('show branches')),
2274 ('k', 'keyword', [], _('search for a keyword')),
2274 ('k', 'keyword', [], _('search for a keyword')),
2275 ('r', 'rev', [], _('show the specified revision or range')),
2275 ('r', 'rev', [], _('show the specified revision or range')),
2276 ('M', 'no-merges', None, _("do not show merges")),
2276 ('M', 'no-merges', None, _("do not show merges")),
2277 ('m', 'only-merges', None, _("show only merges")),
2277 ('m', 'only-merges', None, _("show only merges")),
2278 ('p', 'patch', None, _('show patch'))],
2278 ('p', 'patch', None, _('show patch'))],
2279 _('hg log [-I] [-X] [-r REV]... [-p] [FILE]')),
2279 _('hg log [-I] [-X] [-r REV]... [-p] [FILE]')),
2280 "manifest": (manifest, [], _('hg manifest [REV]')),
2280 "manifest": (manifest, [], _('hg manifest [REV]')),
2281 "outgoing|out": (outgoing,
2281 "outgoing|out": (outgoing,
2282 [('M', 'no-merges', None, _("do not show merges")),
2282 [('M', 'no-merges', None, _("do not show merges")),
2283 ('p', 'patch', None, _('show patch')),
2283 ('p', 'patch', None, _('show patch')),
2284 ('n', 'newest-first', None, _('show newest record first'))],
2284 ('n', 'newest-first', None, _('show newest record first'))],
2285 _('hg outgoing [-p] [-n] [-M] [DEST]')),
2285 _('hg outgoing [-p] [-n] [-M] [DEST]')),
2286 "^parents": (parents, [], _('hg parents [REV]')),
2286 "^parents": (parents, [], _('hg parents [REV]')),
2287 "paths": (paths, [], _('hg paths [NAME]')),
2287 "paths": (paths, [], _('hg paths [NAME]')),
2288 "^pull":
2288 "^pull":
2289 (pull,
2289 (pull,
2290 [('u', 'update', None, _('update the working directory to tip after pull')),
2290 [('u', 'update', None, _('update the working directory to tip after pull')),
2291 ('e', 'ssh', "", _('specify ssh command to use')),
2291 ('e', 'ssh', "", _('specify ssh command to use')),
2292 ('r', 'rev', [], _('a specific revision you would like to pull')),
2292 ('r', 'rev', [], _('a specific revision you would like to pull')),
2293 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2293 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2294 _('hg pull [-u] [-e FILE] [-r rev] [--remotecmd FILE] [SOURCE]')),
2294 _('hg pull [-u] [-e FILE] [-r rev] [--remotecmd FILE] [SOURCE]')),
2295 "^push":
2295 "^push":
2296 (push,
2296 (push,
2297 [('f', 'force', None, _('force push')),
2297 [('f', 'force', None, _('force push')),
2298 ('e', 'ssh', "", _('specify ssh command to use')),
2298 ('e', 'ssh', "", _('specify ssh command to use')),
2299 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2299 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2300 _('hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]')),
2300 _('hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]')),
2301 "rawcommit":
2301 "rawcommit":
2302 (rawcommit,
2302 (rawcommit,
2303 [('p', 'parent', [], _('parent')),
2303 [('p', 'parent', [], _('parent')),
2304 ('d', 'date', "", _('date code')),
2304 ('d', 'date', "", _('date code')),
2305 ('u', 'user', "", _('user')),
2305 ('u', 'user', "", _('user')),
2306 ('F', 'files', "", _('file list')),
2306 ('F', 'files', "", _('file list')),
2307 ('m', 'message', "", _('commit message')),
2307 ('m', 'message', "", _('commit message')),
2308 ('l', 'logfile', "", _('commit message file'))],
2308 ('l', 'logfile', "", _('commit message file'))],
2309 _('hg rawcommit [OPTION]... [FILE]...')),
2309 _('hg rawcommit [OPTION]... [FILE]...')),
2310 "recover": (recover, [], _("hg recover")),
2310 "recover": (recover, [], _("hg recover")),
2311 "^remove|rm": (remove,
2311 "^remove|rm": (remove,
2312 [('I', 'include', [], _('include names matching the given patterns')),
2312 [('I', 'include', [], _('include names matching the given patterns')),
2313 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2313 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2314 _("hg remove [OPTION]... FILE...")),
2314 _("hg remove [OPTION]... FILE...")),
2315 "rename|mv": (rename,
2315 "rename|mv": (rename,
2316 [('I', 'include', [], _('include names matching the given patterns')),
2316 [('I', 'include', [], _('include names matching the given patterns')),
2317 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2317 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2318 ('A', 'after', None, _('record a rename that has already occurred')),
2318 ('A', 'after', None, _('record a rename that has already occurred')),
2319 ('f', 'force', None, _('forcibly copy over an existing managed file'))],
2319 ('f', 'force', None, _('forcibly copy over an existing managed file'))],
2320 _('hg rename [OPTION]... [SOURCE]... DEST')),
2320 _('hg rename [OPTION]... [SOURCE]... DEST')),
2321 "^revert":
2321 "^revert":
2322 (revert,
2322 (revert,
2323 [('I', 'include', [], _('include names matching the given patterns')),
2323 [('I', 'include', [], _('include names matching the given patterns')),
2324 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2324 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2325 ("r", "rev", "", _("revision to revert to"))],
2325 ("r", "rev", "", _("revision to revert to"))],
2326 _("hg revert [-n] [-r REV] [NAME]...")),
2326 _("hg revert [-n] [-r REV] [NAME]...")),
2327 "root": (root, [], _("hg root")),
2327 "root": (root, [], _("hg root")),
2328 "^serve":
2328 "^serve":
2329 (serve,
2329 (serve,
2330 [('A', 'accesslog', '', _('name of access log file to write to')),
2330 [('A', 'accesslog', '', _('name of access log file to write to')),
2331 ('E', 'errorlog', '', _('name of error log file to write to')),
2331 ('E', 'errorlog', '', _('name of error log file to write to')),
2332 ('p', 'port', 0, _('port to use (default: 8000)')),
2332 ('p', 'port', 0, _('port to use (default: 8000)')),
2333 ('a', 'address', '', _('address to use')),
2333 ('a', 'address', '', _('address to use')),
2334 ('n', 'name', "", _('name to show in web pages (default: working dir)')),
2334 ('n', 'name', "", _('name to show in web pages (default: working dir)')),
2335 ('', 'stdio', None, _('for remote clients')),
2335 ('', 'stdio', None, _('for remote clients')),
2336 ('t', 'templates', "", _('web templates to use')),
2336 ('t', 'templates', "", _('web templates to use')),
2337 ('', 'style', "", _('template style to use')),
2337 ('', 'style', "", _('template style to use')),
2338 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2338 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2339 _("hg serve [OPTION]...")),
2339 _("hg serve [OPTION]...")),
2340 "^status|st":
2340 "^status|st":
2341 (status,
2341 (status,
2342 [('m', 'modified', None, _('show only modified files')),
2342 [('m', 'modified', None, _('show only modified files')),
2343 ('a', 'added', None, _('show only added files')),
2343 ('a', 'added', None, _('show only added files')),
2344 ('r', 'removed', None, _('show only removed files')),
2344 ('r', 'removed', None, _('show only removed files')),
2345 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2345 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2346 ('n', 'no-status', None, _('hide status prefix')),
2346 ('n', 'no-status', None, _('hide status prefix')),
2347 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2347 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2348 ('I', 'include', [], _('include names matching the given patterns')),
2348 ('I', 'include', [], _('include names matching the given patterns')),
2349 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2349 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2350 _("hg status [OPTION]... [FILE]...")),
2350 _("hg status [OPTION]... [FILE]...")),
2351 "tag":
2351 "tag":
2352 (tag,
2352 (tag,
2353 [('l', 'local', None, _('make the tag local')),
2353 [('l', 'local', None, _('make the tag local')),
2354 ('m', 'message', "", _('message for tag commit log entry')),
2354 ('m', 'message', "", _('message for tag commit log entry')),
2355 ('d', 'date', "", _('record datecode as commit date')),
2355 ('d', 'date', "", _('record datecode as commit date')),
2356 ('u', 'user', "", _('record user as commiter')),
2356 ('u', 'user', "", _('record user as commiter')),
2357 ('r', 'rev', "", _('revision to tag'))],
2357 ('r', 'rev', "", _('revision to tag'))],
2358 _('hg tag [OPTION]... NAME [REV]')),
2358 _('hg tag [OPTION]... NAME [REV]')),
2359 "tags": (tags, [], _('hg tags')),
2359 "tags": (tags, [], _('hg tags')),
2360 "tip": (tip, [], _('hg tip')),
2360 "tip": (tip, [], _('hg tip')),
2361 "unbundle":
2361 "unbundle":
2362 (unbundle,
2362 (unbundle,
2363 [],
2363 [],
2364 _('hg unbundle FILE')),
2364 _('hg unbundle FILE')),
2365 "undo": (undo, [], _('hg undo')),
2365 "undo": (undo, [], _('hg undo')),
2366 "^update|up|checkout|co":
2366 "^update|up|checkout|co":
2367 (update,
2367 (update,
2368 [('b', 'branch', "", _('checkout the head of a specific branch')),
2368 [('b', 'branch', "", _('checkout the head of a specific branch')),
2369 ('m', 'merge', None, _('allow merging of branches')),
2369 ('m', 'merge', None, _('allow merging of branches')),
2370 ('C', 'clean', None, _('overwrite locally modified files'))],
2370 ('C', 'clean', None, _('overwrite locally modified files'))],
2371 _('hg update [-b TAG] [-m] [-C] [REV]')),
2371 _('hg update [-b TAG] [-m] [-C] [REV]')),
2372 "verify": (verify, [], _('hg verify')),
2372 "verify": (verify, [], _('hg verify')),
2373 "version": (show_version, [], _('hg version')),
2373 "version": (show_version, [], _('hg version')),
2374 }
2374 }
2375
2375
2376 globalopts = [
2376 globalopts = [
2377 ('R', 'repository', "", _("repository root directory")),
2377 ('R', 'repository', "", _("repository root directory")),
2378 ('', 'cwd', '', _("change working directory")),
2378 ('', 'cwd', '', _("change working directory")),
2379 ('y', 'noninteractive', None, _("do not prompt, assume 'yes' for any required answers")),
2379 ('y', 'noninteractive', None, _("do not prompt, assume 'yes' for any required answers")),
2380 ('q', 'quiet', None, _("suppress output")),
2380 ('q', 'quiet', None, _("suppress output")),
2381 ('v', 'verbose', None, _("enable additional output")),
2381 ('v', 'verbose', None, _("enable additional output")),
2382 ('', 'debug', None, _("enable debugging output")),
2382 ('', 'debug', None, _("enable debugging output")),
2383 ('', 'debugger', None, _("start debugger")),
2383 ('', 'debugger', None, _("start debugger")),
2384 ('', 'traceback', None, _("print traceback on exception")),
2384 ('', 'traceback', None, _("print traceback on exception")),
2385 ('', 'time', None, _("time how long the command takes")),
2385 ('', 'time', None, _("time how long the command takes")),
2386 ('', 'profile', None, _("print command execution profile")),
2386 ('', 'profile', None, _("print command execution profile")),
2387 ('', 'version', None, _("output version information and exit")),
2387 ('', 'version', None, _("output version information and exit")),
2388 ('h', 'help', None, _("display help and exit")),
2388 ('h', 'help', None, _("display help and exit")),
2389 ]
2389 ]
2390
2390
2391 norepo = ("clone init version help debugancestor debugconfig debugdata"
2391 norepo = ("clone init version help debugancestor debugconfig debugdata"
2392 " debugindex debugindexdot paths")
2392 " debugindex debugindexdot paths")
2393
2393
2394 def find(cmd):
2394 def find(cmd):
2395 """Return (aliases, command table entry) for command string."""
2395 """Return (aliases, command table entry) for command string."""
2396 choice = None
2396 choice = None
2397 for e in table.keys():
2397 for e in table.keys():
2398 aliases = e.lstrip("^").split("|")
2398 aliases = e.lstrip("^").split("|")
2399 if cmd in aliases:
2399 if cmd in aliases:
2400 return aliases, table[e]
2400 return aliases, table[e]
2401 for a in aliases:
2401 for a in aliases:
2402 if a.startswith(cmd):
2402 if a.startswith(cmd):
2403 if choice:
2403 if choice:
2404 raise AmbiguousCommand(cmd)
2404 raise AmbiguousCommand(cmd)
2405 else:
2405 else:
2406 choice = aliases, table[e]
2406 choice = aliases, table[e]
2407 break
2407 break
2408 if choice:
2408 if choice:
2409 return choice
2409 return choice
2410
2410
2411 raise UnknownCommand(cmd)
2411 raise UnknownCommand(cmd)
2412
2412
2413 class SignalInterrupt(Exception):
2413 class SignalInterrupt(Exception):
2414 """Exception raised on SIGTERM and SIGHUP."""
2414 """Exception raised on SIGTERM and SIGHUP."""
2415
2415
2416 def catchterm(*args):
2416 def catchterm(*args):
2417 raise SignalInterrupt
2417 raise SignalInterrupt
2418
2418
2419 def run():
2419 def run():
2420 sys.exit(dispatch(sys.argv[1:]))
2420 sys.exit(dispatch(sys.argv[1:]))
2421
2421
2422 class ParseError(Exception):
2422 class ParseError(Exception):
2423 """Exception raised on errors in parsing the command line."""
2423 """Exception raised on errors in parsing the command line."""
2424
2424
2425 def parse(ui, args):
2425 def parse(ui, args):
2426 options = {}
2426 options = {}
2427 cmdoptions = {}
2427 cmdoptions = {}
2428
2428
2429 try:
2429 try:
2430 args = fancyopts.fancyopts(args, globalopts, options)
2430 args = fancyopts.fancyopts(args, globalopts, options)
2431 except fancyopts.getopt.GetoptError, inst:
2431 except fancyopts.getopt.GetoptError, inst:
2432 raise ParseError(None, inst)
2432 raise ParseError(None, inst)
2433
2433
2434 if args:
2434 if args:
2435 cmd, args = args[0], args[1:]
2435 cmd, args = args[0], args[1:]
2436 defaults = ui.config("defaults", cmd)
2436 defaults = ui.config("defaults", cmd)
2437 if defaults:
2437 if defaults:
2438 args = defaults.split() + args
2438 args = defaults.split() + args
2439
2439
2440 aliases, i = find(cmd)
2440 aliases, i = find(cmd)
2441 cmd = aliases[0]
2441 cmd = aliases[0]
2442 c = list(i[1])
2442 c = list(i[1])
2443 else:
2443 else:
2444 cmd = None
2444 cmd = None
2445 c = []
2445 c = []
2446
2446
2447 # combine global options into local
2447 # combine global options into local
2448 for o in globalopts:
2448 for o in globalopts:
2449 c.append((o[0], o[1], options[o[1]], o[3]))
2449 c.append((o[0], o[1], options[o[1]], o[3]))
2450
2450
2451 try:
2451 try:
2452 args = fancyopts.fancyopts(args, c, cmdoptions)
2452 args = fancyopts.fancyopts(args, c, cmdoptions)
2453 except fancyopts.getopt.GetoptError, inst:
2453 except fancyopts.getopt.GetoptError, inst:
2454 raise ParseError(cmd, inst)
2454 raise ParseError(cmd, inst)
2455
2455
2456 # separate global options back out
2456 # separate global options back out
2457 for o in globalopts:
2457 for o in globalopts:
2458 n = o[1]
2458 n = o[1]
2459 options[n] = cmdoptions[n]
2459 options[n] = cmdoptions[n]
2460 del cmdoptions[n]
2460 del cmdoptions[n]
2461
2461
2462 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
2462 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
2463
2463
2464 def dispatch(args):
2464 def dispatch(args):
2465 signal.signal(signal.SIGTERM, catchterm)
2465 signal.signal(signal.SIGTERM, catchterm)
2466 try:
2466 try:
2467 signal.signal(signal.SIGHUP, catchterm)
2467 signal.signal(signal.SIGHUP, catchterm)
2468 except AttributeError:
2468 except AttributeError:
2469 pass
2469 pass
2470
2470
2471 try:
2471 try:
2472 u = ui.ui()
2472 u = ui.ui()
2473 except util.Abort, inst:
2473 except util.Abort, inst:
2474 sys.stderr.write(_("abort: %s\n") % inst)
2474 sys.stderr.write(_("abort: %s\n") % inst)
2475 sys.exit(1)
2475 sys.exit(1)
2476
2476
2477 external = []
2477 external = []
2478 for x in u.extensions():
2478 for x in u.extensions():
2479 def on_exception(exc, inst):
2479 def on_exception(exc, inst):
2480 u.warn(_("*** failed to import extension %s\n") % x[1])
2480 u.warn(_("*** failed to import extension %s\n") % x[1])
2481 u.warn("%s\n" % inst)
2481 u.warn("%s\n" % inst)
2482 if "--traceback" in sys.argv[1:]:
2482 if "--traceback" in sys.argv[1:]:
2483 traceback.print_exc()
2483 traceback.print_exc()
2484 if x[1]:
2484 if x[1]:
2485 try:
2485 try:
2486 mod = imp.load_source(x[0], x[1])
2486 mod = imp.load_source(x[0], x[1])
2487 except Exception, inst:
2487 except Exception, inst:
2488 on_exception(Exception, inst)
2488 on_exception(Exception, inst)
2489 continue
2489 continue
2490 else:
2490 else:
2491 def importh(name):
2491 def importh(name):
2492 mod = __import__(name)
2492 mod = __import__(name)
2493 components = name.split('.')
2493 components = name.split('.')
2494 for comp in components[1:]:
2494 for comp in components[1:]:
2495 mod = getattr(mod, comp)
2495 mod = getattr(mod, comp)
2496 return mod
2496 return mod
2497 try:
2497 try:
2498 mod = importh(x[0])
2498 mod = importh(x[0])
2499 except Exception, inst:
2499 except Exception, inst:
2500 on_exception(Exception, inst)
2500 on_exception(Exception, inst)
2501 continue
2501 continue
2502
2502
2503 external.append(mod)
2503 external.append(mod)
2504 for x in external:
2504 for x in external:
2505 cmdtable = getattr(x, 'cmdtable', {})
2505 cmdtable = getattr(x, 'cmdtable', {})
2506 for t in cmdtable:
2506 for t in cmdtable:
2507 if t in table:
2507 if t in table:
2508 u.warn(_("module %s overrides %s\n") % (x.__name__, t))
2508 u.warn(_("module %s overrides %s\n") % (x.__name__, t))
2509 table.update(cmdtable)
2509 table.update(cmdtable)
2510
2510
2511 try:
2511 try:
2512 cmd, func, args, options, cmdoptions = parse(u, args)
2512 cmd, func, args, options, cmdoptions = parse(u, args)
2513 except ParseError, inst:
2513 except ParseError, inst:
2514 if inst.args[0]:
2514 if inst.args[0]:
2515 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
2515 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
2516 help_(u, inst.args[0])
2516 help_(u, inst.args[0])
2517 else:
2517 else:
2518 u.warn(_("hg: %s\n") % inst.args[1])
2518 u.warn(_("hg: %s\n") % inst.args[1])
2519 help_(u, 'shortlist')
2519 help_(u, 'shortlist')
2520 sys.exit(-1)
2520 sys.exit(-1)
2521 except AmbiguousCommand, inst:
2521 except AmbiguousCommand, inst:
2522 u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
2522 u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
2523 sys.exit(1)
2523 sys.exit(1)
2524 except UnknownCommand, inst:
2524 except UnknownCommand, inst:
2525 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2525 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2526 help_(u, 'shortlist')
2526 help_(u, 'shortlist')
2527 sys.exit(1)
2527 sys.exit(1)
2528
2528
2529 if options["time"]:
2529 if options["time"]:
2530 def get_times():
2530 def get_times():
2531 t = os.times()
2531 t = os.times()
2532 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
2532 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
2533 t = (t[0], t[1], t[2], t[3], time.clock())
2533 t = (t[0], t[1], t[2], t[3], time.clock())
2534 return t
2534 return t
2535 s = get_times()
2535 s = get_times()
2536 def print_time():
2536 def print_time():
2537 t = get_times()
2537 t = get_times()
2538 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
2538 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
2539 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
2539 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
2540 atexit.register(print_time)
2540 atexit.register(print_time)
2541
2541
2542 u.updateopts(options["verbose"], options["debug"], options["quiet"],
2542 u.updateopts(options["verbose"], options["debug"], options["quiet"],
2543 not options["noninteractive"])
2543 not options["noninteractive"])
2544
2544
2545 # enter the debugger before command execution
2545 # enter the debugger before command execution
2546 if options['debugger']:
2546 if options['debugger']:
2547 pdb.set_trace()
2547 pdb.set_trace()
2548
2548
2549 try:
2549 try:
2550 try:
2550 try:
2551 if options['help']:
2551 if options['help']:
2552 help_(u, cmd, options['version'])
2552 help_(u, cmd, options['version'])
2553 sys.exit(0)
2553 sys.exit(0)
2554 elif options['version']:
2554 elif options['version']:
2555 show_version(u)
2555 show_version(u)
2556 sys.exit(0)
2556 sys.exit(0)
2557 elif not cmd:
2557 elif not cmd:
2558 help_(u, 'shortlist')
2558 help_(u, 'shortlist')
2559 sys.exit(0)
2559 sys.exit(0)
2560
2560
2561 if options['cwd']:
2561 if options['cwd']:
2562 try:
2562 try:
2563 os.chdir(options['cwd'])
2563 os.chdir(options['cwd'])
2564 except OSError, inst:
2564 except OSError, inst:
2565 raise util.Abort('%s: %s' %
2565 raise util.Abort('%s: %s' %
2566 (options['cwd'], inst.strerror))
2566 (options['cwd'], inst.strerror))
2567
2567
2568 if cmd not in norepo.split():
2568 if cmd not in norepo.split():
2569 path = options["repository"] or ""
2569 path = options["repository"] or ""
2570 repo = hg.repository(ui=u, path=path)
2570 repo = hg.repository(ui=u, path=path)
2571 for x in external:
2571 for x in external:
2572 if hasattr(x, 'reposetup'): x.reposetup(u, repo)
2572 if hasattr(x, 'reposetup'): x.reposetup(u, repo)
2573 d = lambda: func(u, repo, *args, **cmdoptions)
2573 d = lambda: func(u, repo, *args, **cmdoptions)
2574 else:
2574 else:
2575 d = lambda: func(u, *args, **cmdoptions)
2575 d = lambda: func(u, *args, **cmdoptions)
2576
2576
2577 if options['profile']:
2577 if options['profile']:
2578 import hotshot, hotshot.stats
2578 import hotshot, hotshot.stats
2579 prof = hotshot.Profile("hg.prof")
2579 prof = hotshot.Profile("hg.prof")
2580 r = prof.runcall(d)
2580 r = prof.runcall(d)
2581 prof.close()
2581 prof.close()
2582 stats = hotshot.stats.load("hg.prof")
2582 stats = hotshot.stats.load("hg.prof")
2583 stats.strip_dirs()
2583 stats.strip_dirs()
2584 stats.sort_stats('time', 'calls')
2584 stats.sort_stats('time', 'calls')
2585 stats.print_stats(40)
2585 stats.print_stats(40)
2586 return r
2586 return r
2587 else:
2587 else:
2588 return d()
2588 return d()
2589 except:
2589 except:
2590 # enter the debugger when we hit an exception
2590 # enter the debugger when we hit an exception
2591 if options['debugger']:
2591 if options['debugger']:
2592 pdb.post_mortem(sys.exc_info()[2])
2592 pdb.post_mortem(sys.exc_info()[2])
2593 if options['traceback']:
2593 if options['traceback']:
2594 traceback.print_exc()
2594 traceback.print_exc()
2595 raise
2595 raise
2596 except hg.RepoError, inst:
2596 except hg.RepoError, inst:
2597 u.warn(_("abort: "), inst, "!\n")
2597 u.warn(_("abort: "), inst, "!\n")
2598 except revlog.RevlogError, inst:
2598 except revlog.RevlogError, inst:
2599 u.warn(_("abort: "), inst, "!\n")
2599 u.warn(_("abort: "), inst, "!\n")
2600 except SignalInterrupt:
2600 except SignalInterrupt:
2601 u.warn(_("killed!\n"))
2601 u.warn(_("killed!\n"))
2602 except KeyboardInterrupt:
2602 except KeyboardInterrupt:
2603 try:
2603 try:
2604 u.warn(_("interrupted!\n"))
2604 u.warn(_("interrupted!\n"))
2605 except IOError, inst:
2605 except IOError, inst:
2606 if inst.errno == errno.EPIPE:
2606 if inst.errno == errno.EPIPE:
2607 if u.debugflag:
2607 if u.debugflag:
2608 u.warn(_("\nbroken pipe\n"))
2608 u.warn(_("\nbroken pipe\n"))
2609 else:
2609 else:
2610 raise
2610 raise
2611 except IOError, inst:
2611 except IOError, inst:
2612 if hasattr(inst, "code"):
2612 if hasattr(inst, "code"):
2613 u.warn(_("abort: %s\n") % inst)
2613 u.warn(_("abort: %s\n") % inst)
2614 elif hasattr(inst, "reason"):
2614 elif hasattr(inst, "reason"):
2615 u.warn(_("abort: error: %s\n") % inst.reason[1])
2615 u.warn(_("abort: error: %s\n") % inst.reason[1])
2616 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
2616 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
2617 if u.debugflag:
2617 if u.debugflag:
2618 u.warn(_("broken pipe\n"))
2618 u.warn(_("broken pipe\n"))
2619 elif getattr(inst, "strerror", None):
2619 elif getattr(inst, "strerror", None):
2620 if getattr(inst, "filename", None):
2620 if getattr(inst, "filename", None):
2621 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
2621 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
2622 else:
2622 else:
2623 u.warn(_("abort: %s\n") % inst.strerror)
2623 u.warn(_("abort: %s\n") % inst.strerror)
2624 else:
2624 else:
2625 raise
2625 raise
2626 except OSError, inst:
2626 except OSError, inst:
2627 if hasattr(inst, "filename"):
2627 if hasattr(inst, "filename"):
2628 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
2628 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
2629 else:
2629 else:
2630 u.warn(_("abort: %s\n") % inst.strerror)
2630 u.warn(_("abort: %s\n") % inst.strerror)
2631 except util.Abort, inst:
2631 except util.Abort, inst:
2632 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
2632 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
2633 sys.exit(1)
2633 sys.exit(1)
2634 except TypeError, inst:
2634 except TypeError, inst:
2635 # was this an argument error?
2635 # was this an argument error?
2636 tb = traceback.extract_tb(sys.exc_info()[2])
2636 tb = traceback.extract_tb(sys.exc_info()[2])
2637 if len(tb) > 2: # no
2637 if len(tb) > 2: # no
2638 raise
2638 raise
2639 u.debug(inst, "\n")
2639 u.debug(inst, "\n")
2640 u.warn(_("%s: invalid arguments\n") % cmd)
2640 u.warn(_("%s: invalid arguments\n") % cmd)
2641 help_(u, cmd)
2641 help_(u, cmd)
2642 except AmbiguousCommand, inst:
2642 except AmbiguousCommand, inst:
2643 u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
2643 u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
2644 help_(u, 'shortlist')
2644 help_(u, 'shortlist')
2645 except UnknownCommand, inst:
2645 except UnknownCommand, inst:
2646 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2646 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2647 help_(u, 'shortlist')
2647 help_(u, 'shortlist')
2648 except SystemExit:
2648 except SystemExit:
2649 # don't catch this in the catch-all below
2649 # don't catch this in the catch-all below
2650 raise
2650 raise
2651 except:
2651 except:
2652 u.warn(_("** unknown exception encountered, details follow\n"))
2652 u.warn(_("** unknown exception encountered, details follow\n"))
2653 u.warn(_("** report bug details to mercurial@selenic.com\n"))
2653 u.warn(_("** report bug details to mercurial@selenic.com\n"))
2654 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
2654 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
2655 % version.get_version())
2655 % version.get_version())
2656 raise
2656 raise
2657
2657
2658 sys.exit(-1)
2658 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now