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