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