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