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