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