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