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