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