##// END OF EJS Templates
revert: fix corner case found by faheem mitha....
Vadim Gelfer -
r2272:e9a0ed9e default
parent child Browse files
Show More
@@ -1,3440 +1,3446 b''
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 update(ui, repo, hex(op1), **opts)
800 update(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 update(repo.ui, repo)
950 update(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 e = r.index[i]
1308 e = r.index[i]
1309 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
1309 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
1310 if e[5] != nullid:
1310 if e[5] != nullid:
1311 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
1311 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
1312 ui.write("}\n")
1312 ui.write("}\n")
1313
1313
1314 def debugrename(ui, repo, file, rev=None):
1314 def debugrename(ui, repo, file, rev=None):
1315 """dump rename information"""
1315 """dump rename information"""
1316 r = repo.file(relpath(repo, [file])[0])
1316 r = repo.file(relpath(repo, [file])[0])
1317 if rev:
1317 if rev:
1318 try:
1318 try:
1319 # assume all revision numbers are for changesets
1319 # assume all revision numbers are for changesets
1320 n = repo.lookup(rev)
1320 n = repo.lookup(rev)
1321 change = repo.changelog.read(n)
1321 change = repo.changelog.read(n)
1322 m = repo.manifest.read(change[0])
1322 m = repo.manifest.read(change[0])
1323 n = m[relpath(repo, [file])[0]]
1323 n = m[relpath(repo, [file])[0]]
1324 except (hg.RepoError, KeyError):
1324 except (hg.RepoError, KeyError):
1325 n = r.lookup(rev)
1325 n = r.lookup(rev)
1326 else:
1326 else:
1327 n = r.tip()
1327 n = r.tip()
1328 m = r.renamed(n)
1328 m = r.renamed(n)
1329 if m:
1329 if m:
1330 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1330 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1331 else:
1331 else:
1332 ui.write(_("not renamed\n"))
1332 ui.write(_("not renamed\n"))
1333
1333
1334 def debugwalk(ui, repo, *pats, **opts):
1334 def debugwalk(ui, repo, *pats, **opts):
1335 """show how files match on given patterns"""
1335 """show how files match on given patterns"""
1336 items = list(walk(repo, pats, opts))
1336 items = list(walk(repo, pats, opts))
1337 if not items:
1337 if not items:
1338 return
1338 return
1339 fmt = '%%s %%-%ds %%-%ds %%s' % (
1339 fmt = '%%s %%-%ds %%-%ds %%s' % (
1340 max([len(abs) for (src, abs, rel, exact) in items]),
1340 max([len(abs) for (src, abs, rel, exact) in items]),
1341 max([len(rel) for (src, abs, rel, exact) in items]))
1341 max([len(rel) for (src, abs, rel, exact) in items]))
1342 for src, abs, rel, exact in items:
1342 for src, abs, rel, exact in items:
1343 line = fmt % (src, abs, rel, exact and 'exact' or '')
1343 line = fmt % (src, abs, rel, exact and 'exact' or '')
1344 ui.write("%s\n" % line.rstrip())
1344 ui.write("%s\n" % line.rstrip())
1345
1345
1346 def diff(ui, repo, *pats, **opts):
1346 def diff(ui, repo, *pats, **opts):
1347 """diff repository (or selected files)
1347 """diff repository (or selected files)
1348
1348
1349 Show differences between revisions for the specified files.
1349 Show differences between revisions for the specified files.
1350
1350
1351 Differences between files are shown using the unified diff format.
1351 Differences between files are shown using the unified diff format.
1352
1352
1353 When two revision arguments are given, then changes are shown
1353 When two revision arguments are given, then changes are shown
1354 between those revisions. If only one revision is specified then
1354 between those revisions. If only one revision is specified then
1355 that revision is compared to the working directory, and, when no
1355 that revision is compared to the working directory, and, when no
1356 revisions are specified, the working directory files are compared
1356 revisions are specified, the working directory files are compared
1357 to its parent.
1357 to its parent.
1358
1358
1359 Without the -a option, diff will avoid generating diffs of files
1359 Without the -a option, diff will avoid generating diffs of files
1360 it detects as binary. With -a, diff will generate a diff anyway,
1360 it detects as binary. With -a, diff will generate a diff anyway,
1361 probably with undesirable results.
1361 probably with undesirable results.
1362 """
1362 """
1363 node1, node2 = None, None
1363 node1, node2 = None, None
1364 revs = [repo.lookup(x) for x in opts['rev']]
1364 revs = [repo.lookup(x) for x in opts['rev']]
1365
1365
1366 if len(revs) > 0:
1366 if len(revs) > 0:
1367 node1 = revs[0]
1367 node1 = revs[0]
1368 if len(revs) > 1:
1368 if len(revs) > 1:
1369 node2 = revs[1]
1369 node2 = revs[1]
1370 if len(revs) > 2:
1370 if len(revs) > 2:
1371 raise util.Abort(_("too many revisions to diff"))
1371 raise util.Abort(_("too many revisions to diff"))
1372
1372
1373 fns, matchfn, anypats = matchpats(repo, pats, opts)
1373 fns, matchfn, anypats = matchpats(repo, pats, opts)
1374
1374
1375 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
1375 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
1376 text=opts['text'], opts=opts)
1376 text=opts['text'], opts=opts)
1377
1377
1378 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
1378 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
1379 node = repo.lookup(changeset)
1379 node = repo.lookup(changeset)
1380 parents = [p for p in repo.changelog.parents(node) if p != nullid]
1380 parents = [p for p in repo.changelog.parents(node) if p != nullid]
1381 if opts['switch_parent']:
1381 if opts['switch_parent']:
1382 parents.reverse()
1382 parents.reverse()
1383 prev = (parents and parents[0]) or nullid
1383 prev = (parents and parents[0]) or nullid
1384 change = repo.changelog.read(node)
1384 change = repo.changelog.read(node)
1385
1385
1386 fp = make_file(repo, repo.changelog, opts['output'],
1386 fp = make_file(repo, repo.changelog, opts['output'],
1387 node=node, total=total, seqno=seqno,
1387 node=node, total=total, seqno=seqno,
1388 revwidth=revwidth)
1388 revwidth=revwidth)
1389 if fp != sys.stdout:
1389 if fp != sys.stdout:
1390 ui.note("%s\n" % fp.name)
1390 ui.note("%s\n" % fp.name)
1391
1391
1392 fp.write("# HG changeset patch\n")
1392 fp.write("# HG changeset patch\n")
1393 fp.write("# User %s\n" % change[1])
1393 fp.write("# User %s\n" % change[1])
1394 fp.write("# Node ID %s\n" % hex(node))
1394 fp.write("# Node ID %s\n" % hex(node))
1395 fp.write("# Parent %s\n" % hex(prev))
1395 fp.write("# Parent %s\n" % hex(prev))
1396 if len(parents) > 1:
1396 if len(parents) > 1:
1397 fp.write("# Parent %s\n" % hex(parents[1]))
1397 fp.write("# Parent %s\n" % hex(parents[1]))
1398 fp.write(change[4].rstrip())
1398 fp.write(change[4].rstrip())
1399 fp.write("\n\n")
1399 fp.write("\n\n")
1400
1400
1401 dodiff(fp, ui, repo, prev, node, text=opts['text'])
1401 dodiff(fp, ui, repo, prev, node, text=opts['text'])
1402 if fp != sys.stdout:
1402 if fp != sys.stdout:
1403 fp.close()
1403 fp.close()
1404
1404
1405 def export(ui, repo, *changesets, **opts):
1405 def export(ui, repo, *changesets, **opts):
1406 """dump the header and diffs for one or more changesets
1406 """dump the header and diffs for one or more changesets
1407
1407
1408 Print the changeset header and diffs for one or more revisions.
1408 Print the changeset header and diffs for one or more revisions.
1409
1409
1410 The information shown in the changeset header is: author,
1410 The information shown in the changeset header is: author,
1411 changeset hash, parent and commit comment.
1411 changeset hash, parent and commit comment.
1412
1412
1413 Output may be to a file, in which case the name of the file is
1413 Output may be to a file, in which case the name of the file is
1414 given using a format string. The formatting rules are as follows:
1414 given using a format string. The formatting rules are as follows:
1415
1415
1416 %% literal "%" character
1416 %% literal "%" character
1417 %H changeset hash (40 bytes of hexadecimal)
1417 %H changeset hash (40 bytes of hexadecimal)
1418 %N number of patches being generated
1418 %N number of patches being generated
1419 %R changeset revision number
1419 %R changeset revision number
1420 %b basename of the exporting repository
1420 %b basename of the exporting repository
1421 %h short-form changeset hash (12 bytes of hexadecimal)
1421 %h short-form changeset hash (12 bytes of hexadecimal)
1422 %n zero-padded sequence number, starting at 1
1422 %n zero-padded sequence number, starting at 1
1423 %r zero-padded changeset revision number
1423 %r zero-padded changeset revision number
1424
1424
1425 Without the -a option, export will avoid generating diffs of files
1425 Without the -a option, export will avoid generating diffs of files
1426 it detects as binary. With -a, export will generate a diff anyway,
1426 it detects as binary. With -a, export will generate a diff anyway,
1427 probably with undesirable results.
1427 probably with undesirable results.
1428
1428
1429 With the --switch-parent option, the diff will be against the second
1429 With the --switch-parent option, the diff will be against the second
1430 parent. It can be useful to review a merge.
1430 parent. It can be useful to review a merge.
1431 """
1431 """
1432 if not changesets:
1432 if not changesets:
1433 raise util.Abort(_("export requires at least one changeset"))
1433 raise util.Abort(_("export requires at least one changeset"))
1434 seqno = 0
1434 seqno = 0
1435 revs = list(revrange(ui, repo, changesets))
1435 revs = list(revrange(ui, repo, changesets))
1436 total = len(revs)
1436 total = len(revs)
1437 revwidth = max(map(len, revs))
1437 revwidth = max(map(len, revs))
1438 msg = len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n")
1438 msg = len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n")
1439 ui.note(msg)
1439 ui.note(msg)
1440 for cset in revs:
1440 for cset in revs:
1441 seqno += 1
1441 seqno += 1
1442 doexport(ui, repo, cset, seqno, total, revwidth, opts)
1442 doexport(ui, repo, cset, seqno, total, revwidth, opts)
1443
1443
1444 def forget(ui, repo, *pats, **opts):
1444 def forget(ui, repo, *pats, **opts):
1445 """don't add the specified files on the next commit (DEPRECATED)
1445 """don't add the specified files on the next commit (DEPRECATED)
1446
1446
1447 (DEPRECATED)
1447 (DEPRECATED)
1448 Undo an 'hg add' scheduled for the next commit.
1448 Undo an 'hg add' scheduled for the next commit.
1449
1449
1450 This command is now deprecated and will be removed in a future
1450 This command is now deprecated and will be removed in a future
1451 release. Please use revert instead.
1451 release. Please use revert instead.
1452 """
1452 """
1453 ui.warn(_("(the forget command is deprecated; use revert instead)\n"))
1453 ui.warn(_("(the forget command is deprecated; use revert instead)\n"))
1454 forget = []
1454 forget = []
1455 for src, abs, rel, exact in walk(repo, pats, opts):
1455 for src, abs, rel, exact in walk(repo, pats, opts):
1456 if repo.dirstate.state(abs) == 'a':
1456 if repo.dirstate.state(abs) == 'a':
1457 forget.append(abs)
1457 forget.append(abs)
1458 if ui.verbose or not exact:
1458 if ui.verbose or not exact:
1459 ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
1459 ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
1460 repo.forget(forget)
1460 repo.forget(forget)
1461
1461
1462 def grep(ui, repo, pattern, *pats, **opts):
1462 def grep(ui, repo, pattern, *pats, **opts):
1463 """search for a pattern in specified files and revisions
1463 """search for a pattern in specified files and revisions
1464
1464
1465 Search revisions of files for a regular expression.
1465 Search revisions of files for a regular expression.
1466
1466
1467 This command behaves differently than Unix grep. It only accepts
1467 This command behaves differently than Unix grep. It only accepts
1468 Python/Perl regexps. It searches repository history, not the
1468 Python/Perl regexps. It searches repository history, not the
1469 working directory. It always prints the revision number in which
1469 working directory. It always prints the revision number in which
1470 a match appears.
1470 a match appears.
1471
1471
1472 By default, grep only prints output for the first revision of a
1472 By default, grep only prints output for the first revision of a
1473 file in which it finds a match. To get it to print every revision
1473 file in which it finds a match. To get it to print every revision
1474 that contains a change in match status ("-" for a match that
1474 that contains a change in match status ("-" for a match that
1475 becomes a non-match, or "+" for a non-match that becomes a match),
1475 becomes a non-match, or "+" for a non-match that becomes a match),
1476 use the --all flag.
1476 use the --all flag.
1477 """
1477 """
1478 reflags = 0
1478 reflags = 0
1479 if opts['ignore_case']:
1479 if opts['ignore_case']:
1480 reflags |= re.I
1480 reflags |= re.I
1481 regexp = re.compile(pattern, reflags)
1481 regexp = re.compile(pattern, reflags)
1482 sep, eol = ':', '\n'
1482 sep, eol = ':', '\n'
1483 if opts['print0']:
1483 if opts['print0']:
1484 sep = eol = '\0'
1484 sep = eol = '\0'
1485
1485
1486 fcache = {}
1486 fcache = {}
1487 def getfile(fn):
1487 def getfile(fn):
1488 if fn not in fcache:
1488 if fn not in fcache:
1489 fcache[fn] = repo.file(fn)
1489 fcache[fn] = repo.file(fn)
1490 return fcache[fn]
1490 return fcache[fn]
1491
1491
1492 def matchlines(body):
1492 def matchlines(body):
1493 begin = 0
1493 begin = 0
1494 linenum = 0
1494 linenum = 0
1495 while True:
1495 while True:
1496 match = regexp.search(body, begin)
1496 match = regexp.search(body, begin)
1497 if not match:
1497 if not match:
1498 break
1498 break
1499 mstart, mend = match.span()
1499 mstart, mend = match.span()
1500 linenum += body.count('\n', begin, mstart) + 1
1500 linenum += body.count('\n', begin, mstart) + 1
1501 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1501 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1502 lend = body.find('\n', mend)
1502 lend = body.find('\n', mend)
1503 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1503 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1504 begin = lend + 1
1504 begin = lend + 1
1505
1505
1506 class linestate(object):
1506 class linestate(object):
1507 def __init__(self, line, linenum, colstart, colend):
1507 def __init__(self, line, linenum, colstart, colend):
1508 self.line = line
1508 self.line = line
1509 self.linenum = linenum
1509 self.linenum = linenum
1510 self.colstart = colstart
1510 self.colstart = colstart
1511 self.colend = colend
1511 self.colend = colend
1512 def __eq__(self, other):
1512 def __eq__(self, other):
1513 return self.line == other.line
1513 return self.line == other.line
1514 def __hash__(self):
1514 def __hash__(self):
1515 return hash(self.line)
1515 return hash(self.line)
1516
1516
1517 matches = {}
1517 matches = {}
1518 def grepbody(fn, rev, body):
1518 def grepbody(fn, rev, body):
1519 matches[rev].setdefault(fn, {})
1519 matches[rev].setdefault(fn, {})
1520 m = matches[rev][fn]
1520 m = matches[rev][fn]
1521 for lnum, cstart, cend, line in matchlines(body):
1521 for lnum, cstart, cend, line in matchlines(body):
1522 s = linestate(line, lnum, cstart, cend)
1522 s = linestate(line, lnum, cstart, cend)
1523 m[s] = s
1523 m[s] = s
1524
1524
1525 # FIXME: prev isn't used, why ?
1525 # FIXME: prev isn't used, why ?
1526 prev = {}
1526 prev = {}
1527 ucache = {}
1527 ucache = {}
1528 def display(fn, rev, states, prevstates):
1528 def display(fn, rev, states, prevstates):
1529 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1529 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1530 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1530 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1531 counts = {'-': 0, '+': 0}
1531 counts = {'-': 0, '+': 0}
1532 filerevmatches = {}
1532 filerevmatches = {}
1533 for l in diff:
1533 for l in diff:
1534 if incrementing or not opts['all']:
1534 if incrementing or not opts['all']:
1535 change = ((l in prevstates) and '-') or '+'
1535 change = ((l in prevstates) and '-') or '+'
1536 r = rev
1536 r = rev
1537 else:
1537 else:
1538 change = ((l in states) and '-') or '+'
1538 change = ((l in states) and '-') or '+'
1539 r = prev[fn]
1539 r = prev[fn]
1540 cols = [fn, str(rev)]
1540 cols = [fn, str(rev)]
1541 if opts['line_number']:
1541 if opts['line_number']:
1542 cols.append(str(l.linenum))
1542 cols.append(str(l.linenum))
1543 if opts['all']:
1543 if opts['all']:
1544 cols.append(change)
1544 cols.append(change)
1545 if opts['user']:
1545 if opts['user']:
1546 cols.append(trimuser(ui, getchange(rev)[1], rev,
1546 cols.append(trimuser(ui, getchange(rev)[1], rev,
1547 ucache))
1547 ucache))
1548 if opts['files_with_matches']:
1548 if opts['files_with_matches']:
1549 c = (fn, rev)
1549 c = (fn, rev)
1550 if c in filerevmatches:
1550 if c in filerevmatches:
1551 continue
1551 continue
1552 filerevmatches[c] = 1
1552 filerevmatches[c] = 1
1553 else:
1553 else:
1554 cols.append(l.line)
1554 cols.append(l.line)
1555 ui.write(sep.join(cols), eol)
1555 ui.write(sep.join(cols), eol)
1556 counts[change] += 1
1556 counts[change] += 1
1557 return counts['+'], counts['-']
1557 return counts['+'], counts['-']
1558
1558
1559 fstate = {}
1559 fstate = {}
1560 skip = {}
1560 skip = {}
1561 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1561 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1562 count = 0
1562 count = 0
1563 incrementing = False
1563 incrementing = False
1564 for st, rev, fns in changeiter:
1564 for st, rev, fns in changeiter:
1565 if st == 'window':
1565 if st == 'window':
1566 incrementing = rev
1566 incrementing = rev
1567 matches.clear()
1567 matches.clear()
1568 elif st == 'add':
1568 elif st == 'add':
1569 change = repo.changelog.read(repo.lookup(str(rev)))
1569 change = repo.changelog.read(repo.lookup(str(rev)))
1570 mf = repo.manifest.read(change[0])
1570 mf = repo.manifest.read(change[0])
1571 matches[rev] = {}
1571 matches[rev] = {}
1572 for fn in fns:
1572 for fn in fns:
1573 if fn in skip:
1573 if fn in skip:
1574 continue
1574 continue
1575 fstate.setdefault(fn, {})
1575 fstate.setdefault(fn, {})
1576 try:
1576 try:
1577 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1577 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1578 except KeyError:
1578 except KeyError:
1579 pass
1579 pass
1580 elif st == 'iter':
1580 elif st == 'iter':
1581 states = matches[rev].items()
1581 states = matches[rev].items()
1582 states.sort()
1582 states.sort()
1583 for fn, m in states:
1583 for fn, m in states:
1584 if fn in skip:
1584 if fn in skip:
1585 continue
1585 continue
1586 if incrementing or not opts['all'] or fstate[fn]:
1586 if incrementing or not opts['all'] or fstate[fn]:
1587 pos, neg = display(fn, rev, m, fstate[fn])
1587 pos, neg = display(fn, rev, m, fstate[fn])
1588 count += pos + neg
1588 count += pos + neg
1589 if pos and not opts['all']:
1589 if pos and not opts['all']:
1590 skip[fn] = True
1590 skip[fn] = True
1591 fstate[fn] = m
1591 fstate[fn] = m
1592 prev[fn] = rev
1592 prev[fn] = rev
1593
1593
1594 if not incrementing:
1594 if not incrementing:
1595 fstate = fstate.items()
1595 fstate = fstate.items()
1596 fstate.sort()
1596 fstate.sort()
1597 for fn, state in fstate:
1597 for fn, state in fstate:
1598 if fn in skip:
1598 if fn in skip:
1599 continue
1599 continue
1600 display(fn, rev, {}, state)
1600 display(fn, rev, {}, state)
1601 return (count == 0 and 1) or 0
1601 return (count == 0 and 1) or 0
1602
1602
1603 def heads(ui, repo, **opts):
1603 def heads(ui, repo, **opts):
1604 """show current repository heads
1604 """show current repository heads
1605
1605
1606 Show all repository head changesets.
1606 Show all repository head changesets.
1607
1607
1608 Repository "heads" are changesets that don't have children
1608 Repository "heads" are changesets that don't have children
1609 changesets. They are where development generally takes place and
1609 changesets. They are where development generally takes place and
1610 are the usual targets for update and merge operations.
1610 are the usual targets for update and merge operations.
1611 """
1611 """
1612 if opts['rev']:
1612 if opts['rev']:
1613 heads = repo.heads(repo.lookup(opts['rev']))
1613 heads = repo.heads(repo.lookup(opts['rev']))
1614 else:
1614 else:
1615 heads = repo.heads()
1615 heads = repo.heads()
1616 br = None
1616 br = None
1617 if opts['branches']:
1617 if opts['branches']:
1618 br = repo.branchlookup(heads)
1618 br = repo.branchlookup(heads)
1619 displayer = show_changeset(ui, repo, opts)
1619 displayer = show_changeset(ui, repo, opts)
1620 for n in heads:
1620 for n in heads:
1621 displayer.show(changenode=n, brinfo=br)
1621 displayer.show(changenode=n, brinfo=br)
1622
1622
1623 def identify(ui, repo):
1623 def identify(ui, repo):
1624 """print information about the working copy
1624 """print information about the working copy
1625
1625
1626 Print a short summary of the current state of the repo.
1626 Print a short summary of the current state of the repo.
1627
1627
1628 This summary identifies the repository state using one or two parent
1628 This summary identifies the repository state using one or two parent
1629 hash identifiers, followed by a "+" if there are uncommitted changes
1629 hash identifiers, followed by a "+" if there are uncommitted changes
1630 in the working directory, followed by a list of tags for this revision.
1630 in the working directory, followed by a list of tags for this revision.
1631 """
1631 """
1632 parents = [p for p in repo.dirstate.parents() if p != nullid]
1632 parents = [p for p in repo.dirstate.parents() if p != nullid]
1633 if not parents:
1633 if not parents:
1634 ui.write(_("unknown\n"))
1634 ui.write(_("unknown\n"))
1635 return
1635 return
1636
1636
1637 hexfunc = ui.verbose and hex or short
1637 hexfunc = ui.verbose and hex or short
1638 modified, added, removed, deleted, unknown = repo.changes()
1638 modified, added, removed, deleted, unknown = repo.changes()
1639 output = ["%s%s" %
1639 output = ["%s%s" %
1640 ('+'.join([hexfunc(parent) for parent in parents]),
1640 ('+'.join([hexfunc(parent) for parent in parents]),
1641 (modified or added or removed or deleted) and "+" or "")]
1641 (modified or added or removed or deleted) and "+" or "")]
1642
1642
1643 if not ui.quiet:
1643 if not ui.quiet:
1644 # multiple tags for a single parent separated by '/'
1644 # multiple tags for a single parent separated by '/'
1645 parenttags = ['/'.join(tags)
1645 parenttags = ['/'.join(tags)
1646 for tags in map(repo.nodetags, parents) if tags]
1646 for tags in map(repo.nodetags, parents) if tags]
1647 # tags for multiple parents separated by ' + '
1647 # tags for multiple parents separated by ' + '
1648 if parenttags:
1648 if parenttags:
1649 output.append(' + '.join(parenttags))
1649 output.append(' + '.join(parenttags))
1650
1650
1651 ui.write("%s\n" % ' '.join(output))
1651 ui.write("%s\n" % ' '.join(output))
1652
1652
1653 def import_(ui, repo, patch1, *patches, **opts):
1653 def import_(ui, repo, patch1, *patches, **opts):
1654 """import an ordered set of patches
1654 """import an ordered set of patches
1655
1655
1656 Import a list of patches and commit them individually.
1656 Import a list of patches and commit them individually.
1657
1657
1658 If there are outstanding changes in the working directory, import
1658 If there are outstanding changes in the working directory, import
1659 will abort unless given the -f flag.
1659 will abort unless given the -f flag.
1660
1660
1661 If a patch looks like a mail message (its first line starts with
1661 If a patch looks like a mail message (its first line starts with
1662 "From " or looks like an RFC822 header), it will not be applied
1662 "From " or looks like an RFC822 header), it will not be applied
1663 unless the -f option is used. The importer neither parses nor
1663 unless the -f option is used. The importer neither parses nor
1664 discards mail headers, so use -f only to override the "mailness"
1664 discards mail headers, so use -f only to override the "mailness"
1665 safety check, not to import a real mail message.
1665 safety check, not to import a real mail message.
1666 """
1666 """
1667 patches = (patch1,) + patches
1667 patches = (patch1,) + patches
1668
1668
1669 if not opts['force']:
1669 if not opts['force']:
1670 bail_if_changed(repo)
1670 bail_if_changed(repo)
1671
1671
1672 d = opts["base"]
1672 d = opts["base"]
1673 strip = opts["strip"]
1673 strip = opts["strip"]
1674
1674
1675 mailre = re.compile(r'(?:From |[\w-]+:)')
1675 mailre = re.compile(r'(?:From |[\w-]+:)')
1676
1676
1677 # attempt to detect the start of a patch
1677 # attempt to detect the start of a patch
1678 # (this heuristic is borrowed from quilt)
1678 # (this heuristic is borrowed from quilt)
1679 diffre = re.compile(r'(?:Index:[ \t]|diff[ \t]|RCS file: |' +
1679 diffre = re.compile(r'(?:Index:[ \t]|diff[ \t]|RCS file: |' +
1680 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
1680 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
1681 '(---|\*\*\*)[ \t])')
1681 '(---|\*\*\*)[ \t])')
1682
1682
1683 for patch in patches:
1683 for patch in patches:
1684 ui.status(_("applying %s\n") % patch)
1684 ui.status(_("applying %s\n") % patch)
1685 pf = os.path.join(d, patch)
1685 pf = os.path.join(d, patch)
1686
1686
1687 message = []
1687 message = []
1688 user = None
1688 user = None
1689 hgpatch = False
1689 hgpatch = False
1690 for line in file(pf):
1690 for line in file(pf):
1691 line = line.rstrip()
1691 line = line.rstrip()
1692 if (not message and not hgpatch and
1692 if (not message and not hgpatch and
1693 mailre.match(line) and not opts['force']):
1693 mailre.match(line) and not opts['force']):
1694 if len(line) > 35:
1694 if len(line) > 35:
1695 line = line[:32] + '...'
1695 line = line[:32] + '...'
1696 raise util.Abort(_('first line looks like a '
1696 raise util.Abort(_('first line looks like a '
1697 'mail header: ') + line)
1697 'mail header: ') + line)
1698 if diffre.match(line):
1698 if diffre.match(line):
1699 break
1699 break
1700 elif hgpatch:
1700 elif hgpatch:
1701 # parse values when importing the result of an hg export
1701 # parse values when importing the result of an hg export
1702 if line.startswith("# User "):
1702 if line.startswith("# User "):
1703 user = line[7:]
1703 user = line[7:]
1704 ui.debug(_('User: %s\n') % user)
1704 ui.debug(_('User: %s\n') % user)
1705 elif not line.startswith("# ") and line:
1705 elif not line.startswith("# ") and line:
1706 message.append(line)
1706 message.append(line)
1707 hgpatch = False
1707 hgpatch = False
1708 elif line == '# HG changeset patch':
1708 elif line == '# HG changeset patch':
1709 hgpatch = True
1709 hgpatch = True
1710 message = [] # We may have collected garbage
1710 message = [] # We may have collected garbage
1711 else:
1711 else:
1712 message.append(line)
1712 message.append(line)
1713
1713
1714 # make sure message isn't empty
1714 # make sure message isn't empty
1715 if not message:
1715 if not message:
1716 message = _("imported patch %s\n") % patch
1716 message = _("imported patch %s\n") % patch
1717 else:
1717 else:
1718 message = "%s\n" % '\n'.join(message)
1718 message = "%s\n" % '\n'.join(message)
1719 ui.debug(_('message:\n%s\n') % message)
1719 ui.debug(_('message:\n%s\n') % message)
1720
1720
1721 files = util.patch(strip, pf, ui)
1721 files = util.patch(strip, pf, ui)
1722
1722
1723 if len(files) > 0:
1723 if len(files) > 0:
1724 addremove_lock(ui, repo, files, {})
1724 addremove_lock(ui, repo, files, {})
1725 repo.commit(files, message, user)
1725 repo.commit(files, message, user)
1726
1726
1727 def incoming(ui, repo, source="default", **opts):
1727 def incoming(ui, repo, source="default", **opts):
1728 """show new changesets found in source
1728 """show new changesets found in source
1729
1729
1730 Show new changesets found in the specified path/URL or the default
1730 Show new changesets found in the specified path/URL or the default
1731 pull location. These are the changesets that would be pulled if a pull
1731 pull location. These are the changesets that would be pulled if a pull
1732 was requested.
1732 was requested.
1733
1733
1734 For remote repository, using --bundle avoids downloading the changesets
1734 For remote repository, using --bundle avoids downloading the changesets
1735 twice if the incoming is followed by a pull.
1735 twice if the incoming is followed by a pull.
1736
1736
1737 See pull for valid source format details.
1737 See pull for valid source format details.
1738 """
1738 """
1739 source = ui.expandpath(source)
1739 source = ui.expandpath(source)
1740 if opts['ssh']:
1740 if opts['ssh']:
1741 ui.setconfig("ui", "ssh", opts['ssh'])
1741 ui.setconfig("ui", "ssh", opts['ssh'])
1742 if opts['remotecmd']:
1742 if opts['remotecmd']:
1743 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1743 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1744
1744
1745 other = hg.repository(ui, source)
1745 other = hg.repository(ui, source)
1746 incoming = repo.findincoming(other, force=opts["force"])
1746 incoming = repo.findincoming(other, force=opts["force"])
1747 if not incoming:
1747 if not incoming:
1748 ui.status(_("no changes found\n"))
1748 ui.status(_("no changes found\n"))
1749 return
1749 return
1750
1750
1751 cleanup = None
1751 cleanup = None
1752 try:
1752 try:
1753 fname = opts["bundle"]
1753 fname = opts["bundle"]
1754 if fname or not other.local():
1754 if fname or not other.local():
1755 # create a bundle (uncompressed if other repo is not local)
1755 # create a bundle (uncompressed if other repo is not local)
1756 cg = other.changegroup(incoming, "incoming")
1756 cg = other.changegroup(incoming, "incoming")
1757 fname = cleanup = write_bundle(cg, fname, compress=other.local())
1757 fname = cleanup = write_bundle(cg, fname, compress=other.local())
1758 # keep written bundle?
1758 # keep written bundle?
1759 if opts["bundle"]:
1759 if opts["bundle"]:
1760 cleanup = None
1760 cleanup = None
1761 if not other.local():
1761 if not other.local():
1762 # use the created uncompressed bundlerepo
1762 # use the created uncompressed bundlerepo
1763 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1763 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1764
1764
1765 o = other.changelog.nodesbetween(incoming)[0]
1765 o = other.changelog.nodesbetween(incoming)[0]
1766 if opts['newest_first']:
1766 if opts['newest_first']:
1767 o.reverse()
1767 o.reverse()
1768 displayer = show_changeset(ui, other, opts)
1768 displayer = show_changeset(ui, other, opts)
1769 for n in o:
1769 for n in o:
1770 parents = [p for p in other.changelog.parents(n) if p != nullid]
1770 parents = [p for p in other.changelog.parents(n) if p != nullid]
1771 if opts['no_merges'] and len(parents) == 2:
1771 if opts['no_merges'] and len(parents) == 2:
1772 continue
1772 continue
1773 displayer.show(changenode=n)
1773 displayer.show(changenode=n)
1774 if opts['patch']:
1774 if opts['patch']:
1775 prev = (parents and parents[0]) or nullid
1775 prev = (parents and parents[0]) or nullid
1776 dodiff(ui, ui, other, prev, n)
1776 dodiff(ui, ui, other, prev, n)
1777 ui.write("\n")
1777 ui.write("\n")
1778 finally:
1778 finally:
1779 if hasattr(other, 'close'):
1779 if hasattr(other, 'close'):
1780 other.close()
1780 other.close()
1781 if cleanup:
1781 if cleanup:
1782 os.unlink(cleanup)
1782 os.unlink(cleanup)
1783
1783
1784 def init(ui, dest="."):
1784 def init(ui, dest="."):
1785 """create a new repository in the given directory
1785 """create a new repository in the given directory
1786
1786
1787 Initialize a new repository in the given directory. If the given
1787 Initialize a new repository in the given directory. If the given
1788 directory does not exist, it is created.
1788 directory does not exist, it is created.
1789
1789
1790 If no directory is given, the current directory is used.
1790 If no directory is given, the current directory is used.
1791 """
1791 """
1792 if not os.path.exists(dest):
1792 if not os.path.exists(dest):
1793 os.mkdir(dest)
1793 os.mkdir(dest)
1794 hg.repository(ui, dest, create=1)
1794 hg.repository(ui, dest, create=1)
1795
1795
1796 def locate(ui, repo, *pats, **opts):
1796 def locate(ui, repo, *pats, **opts):
1797 """locate files matching specific patterns
1797 """locate files matching specific patterns
1798
1798
1799 Print all files under Mercurial control whose names match the
1799 Print all files under Mercurial control whose names match the
1800 given patterns.
1800 given patterns.
1801
1801
1802 This command searches the current directory and its
1802 This command searches the current directory and its
1803 subdirectories. To search an entire repository, move to the root
1803 subdirectories. To search an entire repository, move to the root
1804 of the repository.
1804 of the repository.
1805
1805
1806 If no patterns are given to match, this command prints all file
1806 If no patterns are given to match, this command prints all file
1807 names.
1807 names.
1808
1808
1809 If you want to feed the output of this command into the "xargs"
1809 If you want to feed the output of this command into the "xargs"
1810 command, use the "-0" option to both this command and "xargs".
1810 command, use the "-0" option to both this command and "xargs".
1811 This will avoid the problem of "xargs" treating single filenames
1811 This will avoid the problem of "xargs" treating single filenames
1812 that contain white space as multiple filenames.
1812 that contain white space as multiple filenames.
1813 """
1813 """
1814 end = opts['print0'] and '\0' or '\n'
1814 end = opts['print0'] and '\0' or '\n'
1815 rev = opts['rev']
1815 rev = opts['rev']
1816 if rev:
1816 if rev:
1817 node = repo.lookup(rev)
1817 node = repo.lookup(rev)
1818 else:
1818 else:
1819 node = None
1819 node = None
1820
1820
1821 for src, abs, rel, exact in walk(repo, pats, opts, node=node,
1821 for src, abs, rel, exact in walk(repo, pats, opts, node=node,
1822 head='(?:.*/|)'):
1822 head='(?:.*/|)'):
1823 if not node and repo.dirstate.state(abs) == '?':
1823 if not node and repo.dirstate.state(abs) == '?':
1824 continue
1824 continue
1825 if opts['fullpath']:
1825 if opts['fullpath']:
1826 ui.write(os.path.join(repo.root, abs), end)
1826 ui.write(os.path.join(repo.root, abs), end)
1827 else:
1827 else:
1828 ui.write(((pats and rel) or abs), end)
1828 ui.write(((pats and rel) or abs), end)
1829
1829
1830 def log(ui, repo, *pats, **opts):
1830 def log(ui, repo, *pats, **opts):
1831 """show revision history of entire repository or files
1831 """show revision history of entire repository or files
1832
1832
1833 Print the revision history of the specified files or the entire project.
1833 Print the revision history of the specified files or the entire project.
1834
1834
1835 By default this command outputs: changeset id and hash, tags,
1835 By default this command outputs: changeset id and hash, tags,
1836 non-trivial parents, user, date and time, and a summary for each
1836 non-trivial parents, user, date and time, and a summary for each
1837 commit. When the -v/--verbose switch is used, the list of changed
1837 commit. When the -v/--verbose switch is used, the list of changed
1838 files and full commit message is shown.
1838 files and full commit message is shown.
1839 """
1839 """
1840 class dui(object):
1840 class dui(object):
1841 # Implement and delegate some ui protocol. Save hunks of
1841 # Implement and delegate some ui protocol. Save hunks of
1842 # output for later display in the desired order.
1842 # output for later display in the desired order.
1843 def __init__(self, ui):
1843 def __init__(self, ui):
1844 self.ui = ui
1844 self.ui = ui
1845 self.hunk = {}
1845 self.hunk = {}
1846 self.header = {}
1846 self.header = {}
1847 def bump(self, rev):
1847 def bump(self, rev):
1848 self.rev = rev
1848 self.rev = rev
1849 self.hunk[rev] = []
1849 self.hunk[rev] = []
1850 self.header[rev] = []
1850 self.header[rev] = []
1851 def note(self, *args):
1851 def note(self, *args):
1852 if self.verbose:
1852 if self.verbose:
1853 self.write(*args)
1853 self.write(*args)
1854 def status(self, *args):
1854 def status(self, *args):
1855 if not self.quiet:
1855 if not self.quiet:
1856 self.write(*args)
1856 self.write(*args)
1857 def write(self, *args):
1857 def write(self, *args):
1858 self.hunk[self.rev].append(args)
1858 self.hunk[self.rev].append(args)
1859 def write_header(self, *args):
1859 def write_header(self, *args):
1860 self.header[self.rev].append(args)
1860 self.header[self.rev].append(args)
1861 def debug(self, *args):
1861 def debug(self, *args):
1862 if self.debugflag:
1862 if self.debugflag:
1863 self.write(*args)
1863 self.write(*args)
1864 def __getattr__(self, key):
1864 def __getattr__(self, key):
1865 return getattr(self.ui, key)
1865 return getattr(self.ui, key)
1866
1866
1867 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1867 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1868
1868
1869 if opts['limit']:
1869 if opts['limit']:
1870 try:
1870 try:
1871 limit = int(opts['limit'])
1871 limit = int(opts['limit'])
1872 except ValueError:
1872 except ValueError:
1873 raise util.Abort(_('limit must be a positive integer'))
1873 raise util.Abort(_('limit must be a positive integer'))
1874 if limit <= 0: raise util.Abort(_('limit must be positive'))
1874 if limit <= 0: raise util.Abort(_('limit must be positive'))
1875 else:
1875 else:
1876 limit = sys.maxint
1876 limit = sys.maxint
1877 count = 0
1877 count = 0
1878
1878
1879 displayer = show_changeset(ui, repo, opts)
1879 displayer = show_changeset(ui, repo, opts)
1880 for st, rev, fns in changeiter:
1880 for st, rev, fns in changeiter:
1881 if st == 'window':
1881 if st == 'window':
1882 du = dui(ui)
1882 du = dui(ui)
1883 displayer.ui = du
1883 displayer.ui = du
1884 elif st == 'add':
1884 elif st == 'add':
1885 du.bump(rev)
1885 du.bump(rev)
1886 changenode = repo.changelog.node(rev)
1886 changenode = repo.changelog.node(rev)
1887 parents = [p for p in repo.changelog.parents(changenode)
1887 parents = [p for p in repo.changelog.parents(changenode)
1888 if p != nullid]
1888 if p != nullid]
1889 if opts['no_merges'] and len(parents) == 2:
1889 if opts['no_merges'] and len(parents) == 2:
1890 continue
1890 continue
1891 if opts['only_merges'] and len(parents) != 2:
1891 if opts['only_merges'] and len(parents) != 2:
1892 continue
1892 continue
1893
1893
1894 if opts['keyword']:
1894 if opts['keyword']:
1895 changes = getchange(rev)
1895 changes = getchange(rev)
1896 miss = 0
1896 miss = 0
1897 for k in [kw.lower() for kw in opts['keyword']]:
1897 for k in [kw.lower() for kw in opts['keyword']]:
1898 if not (k in changes[1].lower() or
1898 if not (k in changes[1].lower() or
1899 k in changes[4].lower() or
1899 k in changes[4].lower() or
1900 k in " ".join(changes[3][:20]).lower()):
1900 k in " ".join(changes[3][:20]).lower()):
1901 miss = 1
1901 miss = 1
1902 break
1902 break
1903 if miss:
1903 if miss:
1904 continue
1904 continue
1905
1905
1906 br = None
1906 br = None
1907 if opts['branches']:
1907 if opts['branches']:
1908 br = repo.branchlookup([repo.changelog.node(rev)])
1908 br = repo.branchlookup([repo.changelog.node(rev)])
1909
1909
1910 displayer.show(rev, brinfo=br)
1910 displayer.show(rev, brinfo=br)
1911 if opts['patch']:
1911 if opts['patch']:
1912 prev = (parents and parents[0]) or nullid
1912 prev = (parents and parents[0]) or nullid
1913 dodiff(du, du, repo, prev, changenode, match=matchfn)
1913 dodiff(du, du, repo, prev, changenode, match=matchfn)
1914 du.write("\n\n")
1914 du.write("\n\n")
1915 elif st == 'iter':
1915 elif st == 'iter':
1916 if count == limit: break
1916 if count == limit: break
1917 if du.header[rev]:
1917 if du.header[rev]:
1918 for args in du.header[rev]:
1918 for args in du.header[rev]:
1919 ui.write_header(*args)
1919 ui.write_header(*args)
1920 if du.hunk[rev]:
1920 if du.hunk[rev]:
1921 count += 1
1921 count += 1
1922 for args in du.hunk[rev]:
1922 for args in du.hunk[rev]:
1923 ui.write(*args)
1923 ui.write(*args)
1924
1924
1925 def manifest(ui, repo, rev=None):
1925 def manifest(ui, repo, rev=None):
1926 """output the latest or given revision of the project manifest
1926 """output the latest or given revision of the project manifest
1927
1927
1928 Print a list of version controlled files for the given revision.
1928 Print a list of version controlled files for the given revision.
1929
1929
1930 The manifest is the list of files being version controlled. If no revision
1930 The manifest is the list of files being version controlled. If no revision
1931 is given then the tip is used.
1931 is given then the tip is used.
1932 """
1932 """
1933 if rev:
1933 if rev:
1934 try:
1934 try:
1935 # assume all revision numbers are for changesets
1935 # assume all revision numbers are for changesets
1936 n = repo.lookup(rev)
1936 n = repo.lookup(rev)
1937 change = repo.changelog.read(n)
1937 change = repo.changelog.read(n)
1938 n = change[0]
1938 n = change[0]
1939 except hg.RepoError:
1939 except hg.RepoError:
1940 n = repo.manifest.lookup(rev)
1940 n = repo.manifest.lookup(rev)
1941 else:
1941 else:
1942 n = repo.manifest.tip()
1942 n = repo.manifest.tip()
1943 m = repo.manifest.read(n)
1943 m = repo.manifest.read(n)
1944 mf = repo.manifest.readflags(n)
1944 mf = repo.manifest.readflags(n)
1945 files = m.keys()
1945 files = m.keys()
1946 files.sort()
1946 files.sort()
1947
1947
1948 for f in files:
1948 for f in files:
1949 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1949 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1950
1950
1951 def merge(ui, repo, node=None, **opts):
1951 def merge(ui, repo, node=None, **opts):
1952 """Merge working directory with another revision
1952 """Merge working directory with another revision
1953
1953
1954 Merge the contents of the current working directory and the
1954 Merge the contents of the current working directory and the
1955 requested revision. Files that changed between either parent are
1955 requested revision. Files that changed between either parent are
1956 marked as changed for the next commit and a commit must be
1956 marked as changed for the next commit and a commit must be
1957 performed before any further updates are allowed.
1957 performed before any further updates are allowed.
1958 """
1958 """
1959 return update(ui, repo, node=node, merge=True, **opts)
1959 return update(ui, repo, node=node, merge=True, **opts)
1960
1960
1961 def outgoing(ui, repo, dest="default-push", **opts):
1961 def outgoing(ui, repo, dest="default-push", **opts):
1962 """show changesets not found in destination
1962 """show changesets not found in destination
1963
1963
1964 Show changesets not found in the specified destination repository or
1964 Show changesets not found in the specified destination repository or
1965 the default push location. These are the changesets that would be pushed
1965 the default push location. These are the changesets that would be pushed
1966 if a push was requested.
1966 if a push was requested.
1967
1967
1968 See pull for valid destination format details.
1968 See pull for valid destination format details.
1969 """
1969 """
1970 dest = ui.expandpath(dest)
1970 dest = ui.expandpath(dest)
1971 if opts['ssh']:
1971 if opts['ssh']:
1972 ui.setconfig("ui", "ssh", opts['ssh'])
1972 ui.setconfig("ui", "ssh", opts['ssh'])
1973 if opts['remotecmd']:
1973 if opts['remotecmd']:
1974 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1974 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1975
1975
1976 other = hg.repository(ui, dest)
1976 other = hg.repository(ui, dest)
1977 o = repo.findoutgoing(other, force=opts['force'])
1977 o = repo.findoutgoing(other, force=opts['force'])
1978 if not o:
1978 if not o:
1979 ui.status(_("no changes found\n"))
1979 ui.status(_("no changes found\n"))
1980 return
1980 return
1981 o = repo.changelog.nodesbetween(o)[0]
1981 o = repo.changelog.nodesbetween(o)[0]
1982 if opts['newest_first']:
1982 if opts['newest_first']:
1983 o.reverse()
1983 o.reverse()
1984 displayer = show_changeset(ui, repo, opts)
1984 displayer = show_changeset(ui, repo, opts)
1985 for n in o:
1985 for n in o:
1986 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1986 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1987 if opts['no_merges'] and len(parents) == 2:
1987 if opts['no_merges'] and len(parents) == 2:
1988 continue
1988 continue
1989 displayer.show(changenode=n)
1989 displayer.show(changenode=n)
1990 if opts['patch']:
1990 if opts['patch']:
1991 prev = (parents and parents[0]) or nullid
1991 prev = (parents and parents[0]) or nullid
1992 dodiff(ui, ui, repo, prev, n)
1992 dodiff(ui, ui, repo, prev, n)
1993 ui.write("\n")
1993 ui.write("\n")
1994
1994
1995 def parents(ui, repo, rev=None, branches=None, **opts):
1995 def parents(ui, repo, rev=None, branches=None, **opts):
1996 """show the parents of the working dir or revision
1996 """show the parents of the working dir or revision
1997
1997
1998 Print the working directory's parent revisions.
1998 Print the working directory's parent revisions.
1999 """
1999 """
2000 if rev:
2000 if rev:
2001 p = repo.changelog.parents(repo.lookup(rev))
2001 p = repo.changelog.parents(repo.lookup(rev))
2002 else:
2002 else:
2003 p = repo.dirstate.parents()
2003 p = repo.dirstate.parents()
2004
2004
2005 br = None
2005 br = None
2006 if branches is not None:
2006 if branches is not None:
2007 br = repo.branchlookup(p)
2007 br = repo.branchlookup(p)
2008 displayer = show_changeset(ui, repo, opts)
2008 displayer = show_changeset(ui, repo, opts)
2009 for n in p:
2009 for n in p:
2010 if n != nullid:
2010 if n != nullid:
2011 displayer.show(changenode=n, brinfo=br)
2011 displayer.show(changenode=n, brinfo=br)
2012
2012
2013 def paths(ui, repo, search=None):
2013 def paths(ui, repo, search=None):
2014 """show definition of symbolic path names
2014 """show definition of symbolic path names
2015
2015
2016 Show definition of symbolic path name NAME. If no name is given, show
2016 Show definition of symbolic path name NAME. If no name is given, show
2017 definition of available names.
2017 definition of available names.
2018
2018
2019 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2019 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2020 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2020 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2021 """
2021 """
2022 if search:
2022 if search:
2023 for name, path in ui.configitems("paths"):
2023 for name, path in ui.configitems("paths"):
2024 if name == search:
2024 if name == search:
2025 ui.write("%s\n" % path)
2025 ui.write("%s\n" % path)
2026 return
2026 return
2027 ui.warn(_("not found!\n"))
2027 ui.warn(_("not found!\n"))
2028 return 1
2028 return 1
2029 else:
2029 else:
2030 for name, path in ui.configitems("paths"):
2030 for name, path in ui.configitems("paths"):
2031 ui.write("%s = %s\n" % (name, path))
2031 ui.write("%s = %s\n" % (name, path))
2032
2032
2033 def postincoming(ui, repo, modheads, optupdate):
2033 def postincoming(ui, repo, modheads, optupdate):
2034 if modheads == 0:
2034 if modheads == 0:
2035 return
2035 return
2036 if optupdate:
2036 if optupdate:
2037 if modheads == 1:
2037 if modheads == 1:
2038 return update(ui, repo)
2038 return update(ui, repo)
2039 else:
2039 else:
2040 ui.status(_("not updating, since new heads added\n"))
2040 ui.status(_("not updating, since new heads added\n"))
2041 if modheads > 1:
2041 if modheads > 1:
2042 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2042 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2043 else:
2043 else:
2044 ui.status(_("(run 'hg update' to get a working copy)\n"))
2044 ui.status(_("(run 'hg update' to get a working copy)\n"))
2045
2045
2046 def pull(ui, repo, source="default", **opts):
2046 def pull(ui, repo, source="default", **opts):
2047 """pull changes from the specified source
2047 """pull changes from the specified source
2048
2048
2049 Pull changes from a remote repository to a local one.
2049 Pull changes from a remote repository to a local one.
2050
2050
2051 This finds all changes from the repository at the specified path
2051 This finds all changes from the repository at the specified path
2052 or URL and adds them to the local repository. By default, this
2052 or URL and adds them to the local repository. By default, this
2053 does not update the copy of the project in the working directory.
2053 does not update the copy of the project in the working directory.
2054
2054
2055 Valid URLs are of the form:
2055 Valid URLs are of the form:
2056
2056
2057 local/filesystem/path
2057 local/filesystem/path
2058 http://[user@]host[:port][/path]
2058 http://[user@]host[:port][/path]
2059 https://[user@]host[:port][/path]
2059 https://[user@]host[:port][/path]
2060 ssh://[user@]host[:port][/path]
2060 ssh://[user@]host[:port][/path]
2061
2061
2062 Some notes about using SSH with Mercurial:
2062 Some notes about using SSH with Mercurial:
2063 - SSH requires an accessible shell account on the destination machine
2063 - SSH requires an accessible shell account on the destination machine
2064 and a copy of hg in the remote path or specified with as remotecmd.
2064 and a copy of hg in the remote path or specified with as remotecmd.
2065 - /path is relative to the remote user's home directory by default.
2065 - /path is relative to the remote user's home directory by default.
2066 Use two slashes at the start of a path to specify an absolute path.
2066 Use two slashes at the start of a path to specify an absolute path.
2067 - Mercurial doesn't use its own compression via SSH; the right thing
2067 - Mercurial doesn't use its own compression via SSH; the right thing
2068 to do is to configure it in your ~/.ssh/ssh_config, e.g.:
2068 to do is to configure it in your ~/.ssh/ssh_config, e.g.:
2069 Host *.mylocalnetwork.example.com
2069 Host *.mylocalnetwork.example.com
2070 Compression off
2070 Compression off
2071 Host *
2071 Host *
2072 Compression on
2072 Compression on
2073 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2073 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2074 with the --ssh command line option.
2074 with the --ssh command line option.
2075 """
2075 """
2076 source = ui.expandpath(source)
2076 source = ui.expandpath(source)
2077 ui.status(_('pulling from %s\n') % (source))
2077 ui.status(_('pulling from %s\n') % (source))
2078
2078
2079 if opts['ssh']:
2079 if opts['ssh']:
2080 ui.setconfig("ui", "ssh", opts['ssh'])
2080 ui.setconfig("ui", "ssh", opts['ssh'])
2081 if opts['remotecmd']:
2081 if opts['remotecmd']:
2082 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
2082 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
2083
2083
2084 other = hg.repository(ui, source)
2084 other = hg.repository(ui, source)
2085 revs = None
2085 revs = None
2086 if opts['rev'] and not other.local():
2086 if opts['rev'] and not other.local():
2087 raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
2087 raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
2088 elif opts['rev']:
2088 elif opts['rev']:
2089 revs = [other.lookup(rev) for rev in opts['rev']]
2089 revs = [other.lookup(rev) for rev in opts['rev']]
2090 modheads = repo.pull(other, heads=revs, force=opts['force'])
2090 modheads = repo.pull(other, heads=revs, force=opts['force'])
2091 return postincoming(ui, repo, modheads, opts['update'])
2091 return postincoming(ui, repo, modheads, opts['update'])
2092
2092
2093 def push(ui, repo, dest="default-push", **opts):
2093 def push(ui, repo, dest="default-push", **opts):
2094 """push changes to the specified destination
2094 """push changes to the specified destination
2095
2095
2096 Push changes from the local repository to the given destination.
2096 Push changes from the local repository to the given destination.
2097
2097
2098 This is the symmetrical operation for pull. It helps to move
2098 This is the symmetrical operation for pull. It helps to move
2099 changes from the current repository to a different one. If the
2099 changes from the current repository to a different one. If the
2100 destination is local this is identical to a pull in that directory
2100 destination is local this is identical to a pull in that directory
2101 from the current one.
2101 from the current one.
2102
2102
2103 By default, push will refuse to run if it detects the result would
2103 By default, push will refuse to run if it detects the result would
2104 increase the number of remote heads. This generally indicates the
2104 increase the number of remote heads. This generally indicates the
2105 the client has forgotten to sync and merge before pushing.
2105 the client has forgotten to sync and merge before pushing.
2106
2106
2107 Valid URLs are of the form:
2107 Valid URLs are of the form:
2108
2108
2109 local/filesystem/path
2109 local/filesystem/path
2110 ssh://[user@]host[:port][/path]
2110 ssh://[user@]host[:port][/path]
2111
2111
2112 Look at the help text for the pull command for important details
2112 Look at the help text for the pull command for important details
2113 about ssh:// URLs.
2113 about ssh:// URLs.
2114 """
2114 """
2115 dest = ui.expandpath(dest)
2115 dest = ui.expandpath(dest)
2116 ui.status('pushing to %s\n' % (dest))
2116 ui.status('pushing to %s\n' % (dest))
2117
2117
2118 if opts['ssh']:
2118 if opts['ssh']:
2119 ui.setconfig("ui", "ssh", opts['ssh'])
2119 ui.setconfig("ui", "ssh", opts['ssh'])
2120 if opts['remotecmd']:
2120 if opts['remotecmd']:
2121 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
2121 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
2122
2122
2123 other = hg.repository(ui, dest)
2123 other = hg.repository(ui, dest)
2124 revs = None
2124 revs = None
2125 if opts['rev']:
2125 if opts['rev']:
2126 revs = [repo.lookup(rev) for rev in opts['rev']]
2126 revs = [repo.lookup(rev) for rev in opts['rev']]
2127 r = repo.push(other, opts['force'], revs=revs)
2127 r = repo.push(other, opts['force'], revs=revs)
2128 return r == 0
2128 return r == 0
2129
2129
2130 def rawcommit(ui, repo, *flist, **rc):
2130 def rawcommit(ui, repo, *flist, **rc):
2131 """raw commit interface (DEPRECATED)
2131 """raw commit interface (DEPRECATED)
2132
2132
2133 (DEPRECATED)
2133 (DEPRECATED)
2134 Lowlevel commit, for use in helper scripts.
2134 Lowlevel commit, for use in helper scripts.
2135
2135
2136 This command is not intended to be used by normal users, as it is
2136 This command is not intended to be used by normal users, as it is
2137 primarily useful for importing from other SCMs.
2137 primarily useful for importing from other SCMs.
2138
2138
2139 This command is now deprecated and will be removed in a future
2139 This command is now deprecated and will be removed in a future
2140 release, please use debugsetparents and commit instead.
2140 release, please use debugsetparents and commit instead.
2141 """
2141 """
2142
2142
2143 ui.warn(_("(the rawcommit command is deprecated)\n"))
2143 ui.warn(_("(the rawcommit command is deprecated)\n"))
2144
2144
2145 message = rc['message']
2145 message = rc['message']
2146 if not message and rc['logfile']:
2146 if not message and rc['logfile']:
2147 try:
2147 try:
2148 message = open(rc['logfile']).read()
2148 message = open(rc['logfile']).read()
2149 except IOError:
2149 except IOError:
2150 pass
2150 pass
2151 if not message and not rc['logfile']:
2151 if not message and not rc['logfile']:
2152 raise util.Abort(_("missing commit message"))
2152 raise util.Abort(_("missing commit message"))
2153
2153
2154 files = relpath(repo, list(flist))
2154 files = relpath(repo, list(flist))
2155 if rc['files']:
2155 if rc['files']:
2156 files += open(rc['files']).read().splitlines()
2156 files += open(rc['files']).read().splitlines()
2157
2157
2158 rc['parent'] = map(repo.lookup, rc['parent'])
2158 rc['parent'] = map(repo.lookup, rc['parent'])
2159
2159
2160 try:
2160 try:
2161 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
2161 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
2162 except ValueError, inst:
2162 except ValueError, inst:
2163 raise util.Abort(str(inst))
2163 raise util.Abort(str(inst))
2164
2164
2165 def recover(ui, repo):
2165 def recover(ui, repo):
2166 """roll back an interrupted transaction
2166 """roll back an interrupted transaction
2167
2167
2168 Recover from an interrupted commit or pull.
2168 Recover from an interrupted commit or pull.
2169
2169
2170 This command tries to fix the repository status after an interrupted
2170 This command tries to fix the repository status after an interrupted
2171 operation. It should only be necessary when Mercurial suggests it.
2171 operation. It should only be necessary when Mercurial suggests it.
2172 """
2172 """
2173 if repo.recover():
2173 if repo.recover():
2174 return repo.verify()
2174 return repo.verify()
2175 return 1
2175 return 1
2176
2176
2177 def remove(ui, repo, *pats, **opts):
2177 def remove(ui, repo, *pats, **opts):
2178 """remove the specified files on the next commit
2178 """remove the specified files on the next commit
2179
2179
2180 Schedule the indicated files for removal from the repository.
2180 Schedule the indicated files for removal from the repository.
2181
2181
2182 This command schedules the files to be removed at the next commit.
2182 This command schedules the files to be removed at the next commit.
2183 This only removes files from the current branch, not from the
2183 This only removes files from the current branch, not from the
2184 entire project history. If the files still exist in the working
2184 entire project history. If the files still exist in the working
2185 directory, they will be deleted from it. If invoked with --after,
2185 directory, they will be deleted from it. If invoked with --after,
2186 files that have been manually deleted are marked as removed.
2186 files that have been manually deleted are marked as removed.
2187 """
2187 """
2188 names = []
2188 names = []
2189 if not opts['after'] and not pats:
2189 if not opts['after'] and not pats:
2190 raise util.Abort(_('no files specified'))
2190 raise util.Abort(_('no files specified'))
2191 def okaytoremove(abs, rel, exact):
2191 def okaytoremove(abs, rel, exact):
2192 modified, added, removed, deleted, unknown = repo.changes(files=[abs])
2192 modified, added, removed, deleted, unknown = repo.changes(files=[abs])
2193 reason = None
2193 reason = None
2194 if not deleted and opts['after']:
2194 if not deleted and opts['after']:
2195 reason = _('is still present')
2195 reason = _('is still present')
2196 elif modified and not opts['force']:
2196 elif modified and not opts['force']:
2197 reason = _('is modified')
2197 reason = _('is modified')
2198 elif added:
2198 elif added:
2199 reason = _('has been marked for add')
2199 reason = _('has been marked for add')
2200 elif unknown:
2200 elif unknown:
2201 reason = _('is not managed')
2201 reason = _('is not managed')
2202 elif removed:
2202 elif removed:
2203 return False
2203 return False
2204 if reason:
2204 if reason:
2205 if exact:
2205 if exact:
2206 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2206 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2207 else:
2207 else:
2208 return True
2208 return True
2209 for src, abs, rel, exact in walk(repo, pats, opts):
2209 for src, abs, rel, exact in walk(repo, pats, opts):
2210 if okaytoremove(abs, rel, exact):
2210 if okaytoremove(abs, rel, exact):
2211 if ui.verbose or not exact:
2211 if ui.verbose or not exact:
2212 ui.status(_('removing %s\n') % rel)
2212 ui.status(_('removing %s\n') % rel)
2213 names.append(abs)
2213 names.append(abs)
2214 repo.remove(names, unlink=not opts['after'])
2214 repo.remove(names, unlink=not opts['after'])
2215
2215
2216 def rename(ui, repo, *pats, **opts):
2216 def rename(ui, repo, *pats, **opts):
2217 """rename files; equivalent of copy + remove
2217 """rename files; equivalent of copy + remove
2218
2218
2219 Mark dest as copies of sources; mark sources for deletion. If
2219 Mark dest as copies of sources; mark sources for deletion. If
2220 dest is a directory, copies are put in that directory. If dest is
2220 dest is a directory, copies are put in that directory. If dest is
2221 a file, there can only be one source.
2221 a file, there can only be one source.
2222
2222
2223 By default, this command copies the contents of files as they
2223 By default, this command copies the contents of files as they
2224 stand in the working directory. If invoked with --after, the
2224 stand in the working directory. If invoked with --after, the
2225 operation is recorded, but no copying is performed.
2225 operation is recorded, but no copying is performed.
2226
2226
2227 This command takes effect in the next commit.
2227 This command takes effect in the next commit.
2228
2228
2229 NOTE: This command should be treated as experimental. While it
2229 NOTE: This command should be treated as experimental. While it
2230 should properly record rename files, this information is not yet
2230 should properly record rename files, this information is not yet
2231 fully used by merge, nor fully reported by log.
2231 fully used by merge, nor fully reported by log.
2232 """
2232 """
2233 wlock = repo.wlock(0)
2233 wlock = repo.wlock(0)
2234 errs, copied = docopy(ui, repo, pats, opts, wlock)
2234 errs, copied = docopy(ui, repo, pats, opts, wlock)
2235 names = []
2235 names = []
2236 for abs, rel, exact in copied:
2236 for abs, rel, exact in copied:
2237 if ui.verbose or not exact:
2237 if ui.verbose or not exact:
2238 ui.status(_('removing %s\n') % rel)
2238 ui.status(_('removing %s\n') % rel)
2239 names.append(abs)
2239 names.append(abs)
2240 repo.remove(names, True, wlock)
2240 repo.remove(names, True, wlock)
2241 return errs
2241 return errs
2242
2242
2243 def revert(ui, repo, *pats, **opts):
2243 def revert(ui, repo, *pats, **opts):
2244 """revert files or dirs to their states as of some revision
2244 """revert files or dirs to their states as of some revision
2245
2245
2246 With no revision specified, revert the named files or directories
2246 With no revision specified, revert the named files or directories
2247 to the contents they had in the parent of the working directory.
2247 to the contents they had in the parent of the working directory.
2248 This restores the contents of the affected files to an unmodified
2248 This restores the contents of the affected files to an unmodified
2249 state. If the working directory has two parents, you must
2249 state. If the working directory has two parents, you must
2250 explicitly specify the revision to revert to.
2250 explicitly specify the revision to revert to.
2251
2251
2252 Modified files are saved with a .orig suffix before reverting.
2252 Modified files are saved with a .orig suffix before reverting.
2253 To disable these backups, use --no-backup.
2253 To disable these backups, use --no-backup.
2254
2254
2255 Using the -r option, revert the given files or directories to
2255 Using the -r option, revert the given files or directories to
2256 their contents as of a specific revision. This can be helpful to"roll
2256 their contents as of a specific revision. This can be helpful to"roll
2257 back" some or all of a change that should not have been committed.
2257 back" some or all of a change that should not have been committed.
2258
2258
2259 Revert modifies the working directory. It does not commit any
2259 Revert modifies the working directory. It does not commit any
2260 changes, or change the parent of the working directory. If you
2260 changes, or change the parent of the working directory. If you
2261 revert to a revision other than the parent of the working
2261 revert to a revision other than the parent of the working
2262 directory, the reverted files will thus appear modified
2262 directory, the reverted files will thus appear modified
2263 afterwards.
2263 afterwards.
2264
2264
2265 If a file has been deleted, it is recreated. If the executable
2265 If a file has been deleted, it is recreated. If the executable
2266 mode of a file was changed, it is reset.
2266 mode of a file was changed, it is reset.
2267
2267
2268 If names are given, all files matching the names are reverted.
2268 If names are given, all files matching the names are reverted.
2269
2269
2270 If no arguments are given, all files in the repository are reverted.
2270 If no arguments are given, all files in the repository are reverted.
2271 """
2271 """
2272 parent, p2 = repo.dirstate.parents()
2272 parent, p2 = repo.dirstate.parents()
2273 if opts['rev']:
2273 if opts['rev']:
2274 node = repo.lookup(opts['rev'])
2274 node = repo.lookup(opts['rev'])
2275 elif p2 != nullid:
2275 elif p2 != nullid:
2276 raise util.Abort(_('working dir has two parents; '
2276 raise util.Abort(_('working dir has two parents; '
2277 'you must specify the revision to revert to'))
2277 'you must specify the revision to revert to'))
2278 else:
2278 else:
2279 node = parent
2279 node = parent
2280 pmf = None
2280 mf = repo.manifest.read(repo.changelog.read(node)[0])
2281 mf = repo.manifest.read(repo.changelog.read(node)[0])
2281
2282
2282 wlock = repo.wlock()
2283 wlock = repo.wlock()
2283
2284
2284 # need all matching names in dirstate and manifest of target rev,
2285 # need all matching names in dirstate and manifest of target rev,
2285 # so have to walk both. do not print errors if files exist in one
2286 # so have to walk both. do not print errors if files exist in one
2286 # but not other.
2287 # but not other.
2287
2288
2288 names = {}
2289 names = {}
2289 target_only = {}
2290 target_only = {}
2290
2291
2291 # walk dirstate.
2292 # walk dirstate.
2292
2293
2293 for src, abs, rel, exact in walk(repo, pats, opts, badmatch=mf.has_key):
2294 for src, abs, rel, exact in walk(repo, pats, opts, badmatch=mf.has_key):
2294 names[abs] = (rel, exact)
2295 names[abs] = (rel, exact)
2295 if src == 'b':
2296 if src == 'b':
2296 target_only[abs] = True
2297 target_only[abs] = True
2297
2298
2298 # walk target manifest.
2299 # walk target manifest.
2299
2300
2300 for src, abs, rel, exact in walk(repo, pats, opts, node=node,
2301 for src, abs, rel, exact in walk(repo, pats, opts, node=node,
2301 badmatch=names.has_key):
2302 badmatch=names.has_key):
2302 if abs in names: continue
2303 if abs in names: continue
2303 names[abs] = (rel, exact)
2304 names[abs] = (rel, exact)
2304 target_only[abs] = True
2305 target_only[abs] = True
2305
2306
2306 changes = repo.changes(match=names.has_key, wlock=wlock)
2307 changes = repo.changes(match=names.has_key, wlock=wlock)
2307 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2308 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2308
2309
2309 revert = ([], _('reverting %s\n'))
2310 revert = ([], _('reverting %s\n'))
2310 add = ([], _('adding %s\n'))
2311 add = ([], _('adding %s\n'))
2311 remove = ([], _('removing %s\n'))
2312 remove = ([], _('removing %s\n'))
2312 forget = ([], _('forgetting %s\n'))
2313 forget = ([], _('forgetting %s\n'))
2313 undelete = ([], _('undeleting %s\n'))
2314 undelete = ([], _('undeleting %s\n'))
2314 update = {}
2315 update = {}
2315
2316
2316 disptable = (
2317 disptable = (
2317 # dispatch table:
2318 # dispatch table:
2318 # file state
2319 # file state
2319 # action if in target manifest
2320 # action if in target manifest
2320 # action if not in target manifest
2321 # action if not in target manifest
2321 # make backup if in target manifest
2322 # make backup if in target manifest
2322 # make backup if not in target manifest
2323 # make backup if not in target manifest
2323 (modified, revert, remove, True, True),
2324 (modified, revert, remove, True, True),
2324 (added, revert, forget, True, False),
2325 (added, revert, forget, True, False),
2325 (removed, undelete, None, False, False),
2326 (removed, undelete, None, False, False),
2326 (deleted, revert, remove, False, False),
2327 (deleted, revert, remove, False, False),
2327 (unknown, add, None, True, False),
2328 (unknown, add, None, True, False),
2328 (target_only, add, None, False, False),
2329 (target_only, add, None, False, False),
2329 )
2330 )
2330
2331
2331 entries = names.items()
2332 entries = names.items()
2332 entries.sort()
2333 entries.sort()
2333
2334
2334 for abs, (rel, exact) in entries:
2335 for abs, (rel, exact) in entries:
2335 in_mf = abs in mf
2336 in_mf = abs in mf
2336 def handle(xlist, dobackup):
2337 def handle(xlist, dobackup):
2337 xlist[0].append(abs)
2338 xlist[0].append(abs)
2338 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2339 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2339 bakname = "%s.orig" % rel
2340 bakname = "%s.orig" % rel
2340 ui.note(_('saving current version of %s as %s\n') %
2341 ui.note(_('saving current version of %s as %s\n') %
2341 (rel, bakname))
2342 (rel, bakname))
2342 shutil.copyfile(rel, bakname)
2343 shutil.copyfile(rel, bakname)
2343 shutil.copymode(rel, bakname)
2344 shutil.copymode(rel, bakname)
2344 if ui.verbose or not exact:
2345 if ui.verbose or not exact:
2345 ui.status(xlist[1] % rel)
2346 ui.status(xlist[1] % rel)
2346 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2347 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2347 if abs not in table: continue
2348 if abs not in table: continue
2348 # file has changed in dirstate
2349 # file has changed in dirstate
2349 if in_mf:
2350 if in_mf:
2350 handle(hitlist, backuphit)
2351 handle(hitlist, backuphit)
2351 elif misslist is not None:
2352 elif misslist is not None:
2352 handle(misslist, backupmiss)
2353 handle(misslist, backupmiss)
2353 else:
2354 else:
2354 if exact: ui.warn(_('file not managed: %s\n' % rel))
2355 if exact: ui.warn(_('file not managed: %s\n' % rel))
2355 break
2356 break
2356 else:
2357 else:
2357 # file has not changed in dirstate
2358 # file has not changed in dirstate
2358 if node == parent:
2359 if node == parent:
2359 if exact: ui.warn(_('no changes needed to %s\n' % rel))
2360 if exact: ui.warn(_('no changes needed to %s\n' % rel))
2360 continue
2361 continue
2361 if not in_mf:
2362 if not in_mf:
2362 handle(remove, False)
2363 if pmf is None:
2364 # only need parent manifest in this unlikely case,
2365 # so do not read by default
2366 pmf = repo.manifest.read(repo.changelog.read(parent)[0])
2367 if abs in pmf:
2368 handle(remove, False)
2363 update[abs] = True
2369 update[abs] = True
2364
2370
2365 repo.dirstate.forget(forget[0])
2371 repo.dirstate.forget(forget[0])
2366 r = repo.update(node, False, True, update.has_key, False, wlock=wlock,
2372 r = repo.update(node, False, True, update.has_key, False, wlock=wlock,
2367 show_stats=False)
2373 show_stats=False)
2368 repo.dirstate.update(add[0], 'a')
2374 repo.dirstate.update(add[0], 'a')
2369 repo.dirstate.update(undelete[0], 'n')
2375 repo.dirstate.update(undelete[0], 'n')
2370 repo.dirstate.update(remove[0], 'r')
2376 repo.dirstate.update(remove[0], 'r')
2371 return r
2377 return r
2372
2378
2373 def rollback(ui, repo):
2379 def rollback(ui, repo):
2374 """roll back the last transaction in this repository
2380 """roll back the last transaction in this repository
2375
2381
2376 Roll back the last transaction in this repository, restoring the
2382 Roll back the last transaction in this repository, restoring the
2377 project to its state prior to the transaction.
2383 project to its state prior to the transaction.
2378
2384
2379 Transactions are used to encapsulate the effects of all commands
2385 Transactions are used to encapsulate the effects of all commands
2380 that create new changesets or propagate existing changesets into a
2386 that create new changesets or propagate existing changesets into a
2381 repository. For example, the following commands are transactional,
2387 repository. For example, the following commands are transactional,
2382 and their effects can be rolled back:
2388 and their effects can be rolled back:
2383
2389
2384 commit
2390 commit
2385 import
2391 import
2386 pull
2392 pull
2387 push (with this repository as destination)
2393 push (with this repository as destination)
2388 unbundle
2394 unbundle
2389
2395
2390 This command should be used with care. There is only one level of
2396 This command should be used with care. There is only one level of
2391 rollback, and there is no way to undo a rollback.
2397 rollback, and there is no way to undo a rollback.
2392
2398
2393 This command is not intended for use on public repositories. Once
2399 This command is not intended for use on public repositories. Once
2394 changes are visible for pull by other users, rolling a transaction
2400 changes are visible for pull by other users, rolling a transaction
2395 back locally is ineffective (someone else may already have pulled
2401 back locally is ineffective (someone else may already have pulled
2396 the changes). Furthermore, a race is possible with readers of the
2402 the changes). Furthermore, a race is possible with readers of the
2397 repository; for example an in-progress pull from the repository
2403 repository; for example an in-progress pull from the repository
2398 may fail if a rollback is performed.
2404 may fail if a rollback is performed.
2399 """
2405 """
2400 repo.undo()
2406 repo.undo()
2401
2407
2402 def root(ui, repo):
2408 def root(ui, repo):
2403 """print the root (top) of the current working dir
2409 """print the root (top) of the current working dir
2404
2410
2405 Print the root directory of the current repository.
2411 Print the root directory of the current repository.
2406 """
2412 """
2407 ui.write(repo.root + "\n")
2413 ui.write(repo.root + "\n")
2408
2414
2409 def serve(ui, repo, **opts):
2415 def serve(ui, repo, **opts):
2410 """export the repository via HTTP
2416 """export the repository via HTTP
2411
2417
2412 Start a local HTTP repository browser and pull server.
2418 Start a local HTTP repository browser and pull server.
2413
2419
2414 By default, the server logs accesses to stdout and errors to
2420 By default, the server logs accesses to stdout and errors to
2415 stderr. Use the "-A" and "-E" options to log to files.
2421 stderr. Use the "-A" and "-E" options to log to files.
2416 """
2422 """
2417
2423
2418 if opts["stdio"]:
2424 if opts["stdio"]:
2419 if repo is None:
2425 if repo is None:
2420 raise hg.RepoError(_('no repo found'))
2426 raise hg.RepoError(_('no repo found'))
2421 fin, fout = sys.stdin, sys.stdout
2427 fin, fout = sys.stdin, sys.stdout
2422 sys.stdout = sys.stderr
2428 sys.stdout = sys.stderr
2423
2429
2424 # Prevent insertion/deletion of CRs
2430 # Prevent insertion/deletion of CRs
2425 util.set_binary(fin)
2431 util.set_binary(fin)
2426 util.set_binary(fout)
2432 util.set_binary(fout)
2427
2433
2428 def getarg():
2434 def getarg():
2429 argline = fin.readline()[:-1]
2435 argline = fin.readline()[:-1]
2430 arg, l = argline.split()
2436 arg, l = argline.split()
2431 val = fin.read(int(l))
2437 val = fin.read(int(l))
2432 return arg, val
2438 return arg, val
2433 def respond(v):
2439 def respond(v):
2434 fout.write("%d\n" % len(v))
2440 fout.write("%d\n" % len(v))
2435 fout.write(v)
2441 fout.write(v)
2436 fout.flush()
2442 fout.flush()
2437
2443
2438 lock = None
2444 lock = None
2439
2445
2440 while 1:
2446 while 1:
2441 cmd = fin.readline()[:-1]
2447 cmd = fin.readline()[:-1]
2442 if cmd == '':
2448 if cmd == '':
2443 return
2449 return
2444 if cmd == "heads":
2450 if cmd == "heads":
2445 h = repo.heads()
2451 h = repo.heads()
2446 respond(" ".join(map(hex, h)) + "\n")
2452 respond(" ".join(map(hex, h)) + "\n")
2447 if cmd == "lock":
2453 if cmd == "lock":
2448 lock = repo.lock()
2454 lock = repo.lock()
2449 respond("")
2455 respond("")
2450 if cmd == "unlock":
2456 if cmd == "unlock":
2451 if lock:
2457 if lock:
2452 lock.release()
2458 lock.release()
2453 lock = None
2459 lock = None
2454 respond("")
2460 respond("")
2455 elif cmd == "branches":
2461 elif cmd == "branches":
2456 arg, nodes = getarg()
2462 arg, nodes = getarg()
2457 nodes = map(bin, nodes.split(" "))
2463 nodes = map(bin, nodes.split(" "))
2458 r = []
2464 r = []
2459 for b in repo.branches(nodes):
2465 for b in repo.branches(nodes):
2460 r.append(" ".join(map(hex, b)) + "\n")
2466 r.append(" ".join(map(hex, b)) + "\n")
2461 respond("".join(r))
2467 respond("".join(r))
2462 elif cmd == "between":
2468 elif cmd == "between":
2463 arg, pairs = getarg()
2469 arg, pairs = getarg()
2464 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
2470 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
2465 r = []
2471 r = []
2466 for b in repo.between(pairs):
2472 for b in repo.between(pairs):
2467 r.append(" ".join(map(hex, b)) + "\n")
2473 r.append(" ".join(map(hex, b)) + "\n")
2468 respond("".join(r))
2474 respond("".join(r))
2469 elif cmd == "changegroup":
2475 elif cmd == "changegroup":
2470 nodes = []
2476 nodes = []
2471 arg, roots = getarg()
2477 arg, roots = getarg()
2472 nodes = map(bin, roots.split(" "))
2478 nodes = map(bin, roots.split(" "))
2473
2479
2474 cg = repo.changegroup(nodes, 'serve')
2480 cg = repo.changegroup(nodes, 'serve')
2475 while 1:
2481 while 1:
2476 d = cg.read(4096)
2482 d = cg.read(4096)
2477 if not d:
2483 if not d:
2478 break
2484 break
2479 fout.write(d)
2485 fout.write(d)
2480
2486
2481 fout.flush()
2487 fout.flush()
2482
2488
2483 elif cmd == "addchangegroup":
2489 elif cmd == "addchangegroup":
2484 if not lock:
2490 if not lock:
2485 respond("not locked")
2491 respond("not locked")
2486 continue
2492 continue
2487 respond("")
2493 respond("")
2488
2494
2489 r = repo.addchangegroup(fin, 'serve')
2495 r = repo.addchangegroup(fin, 'serve')
2490 respond(str(r))
2496 respond(str(r))
2491
2497
2492 optlist = ("name templates style address port ipv6"
2498 optlist = ("name templates style address port ipv6"
2493 " accesslog errorlog webdir_conf")
2499 " accesslog errorlog webdir_conf")
2494 for o in optlist.split():
2500 for o in optlist.split():
2495 if opts[o]:
2501 if opts[o]:
2496 ui.setconfig("web", o, opts[o])
2502 ui.setconfig("web", o, opts[o])
2497
2503
2498 if repo is None and not ui.config("web", "webdir_conf"):
2504 if repo is None and not ui.config("web", "webdir_conf"):
2499 raise hg.RepoError(_('no repo found'))
2505 raise hg.RepoError(_('no repo found'))
2500
2506
2501 if opts['daemon'] and not opts['daemon_pipefds']:
2507 if opts['daemon'] and not opts['daemon_pipefds']:
2502 rfd, wfd = os.pipe()
2508 rfd, wfd = os.pipe()
2503 args = sys.argv[:]
2509 args = sys.argv[:]
2504 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2510 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2505 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2511 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2506 args[0], args)
2512 args[0], args)
2507 os.close(wfd)
2513 os.close(wfd)
2508 os.read(rfd, 1)
2514 os.read(rfd, 1)
2509 os._exit(0)
2515 os._exit(0)
2510
2516
2511 try:
2517 try:
2512 httpd = hgweb.create_server(ui, repo)
2518 httpd = hgweb.create_server(ui, repo)
2513 except socket.error, inst:
2519 except socket.error, inst:
2514 raise util.Abort(_('cannot start server: ') + inst.args[1])
2520 raise util.Abort(_('cannot start server: ') + inst.args[1])
2515
2521
2516 if ui.verbose:
2522 if ui.verbose:
2517 addr, port = httpd.socket.getsockname()
2523 addr, port = httpd.socket.getsockname()
2518 if addr == '0.0.0.0':
2524 if addr == '0.0.0.0':
2519 addr = socket.gethostname()
2525 addr = socket.gethostname()
2520 else:
2526 else:
2521 try:
2527 try:
2522 addr = socket.gethostbyaddr(addr)[0]
2528 addr = socket.gethostbyaddr(addr)[0]
2523 except socket.error:
2529 except socket.error:
2524 pass
2530 pass
2525 if port != 80:
2531 if port != 80:
2526 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
2532 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
2527 else:
2533 else:
2528 ui.status(_('listening at http://%s/\n') % addr)
2534 ui.status(_('listening at http://%s/\n') % addr)
2529
2535
2530 if opts['pid_file']:
2536 if opts['pid_file']:
2531 fp = open(opts['pid_file'], 'w')
2537 fp = open(opts['pid_file'], 'w')
2532 fp.write(str(os.getpid()))
2538 fp.write(str(os.getpid()))
2533 fp.close()
2539 fp.close()
2534
2540
2535 if opts['daemon_pipefds']:
2541 if opts['daemon_pipefds']:
2536 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2542 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2537 os.close(rfd)
2543 os.close(rfd)
2538 os.write(wfd, 'y')
2544 os.write(wfd, 'y')
2539 os.close(wfd)
2545 os.close(wfd)
2540 sys.stdout.flush()
2546 sys.stdout.flush()
2541 sys.stderr.flush()
2547 sys.stderr.flush()
2542 fd = os.open(util.nulldev, os.O_RDWR)
2548 fd = os.open(util.nulldev, os.O_RDWR)
2543 if fd != 0: os.dup2(fd, 0)
2549 if fd != 0: os.dup2(fd, 0)
2544 if fd != 1: os.dup2(fd, 1)
2550 if fd != 1: os.dup2(fd, 1)
2545 if fd != 2: os.dup2(fd, 2)
2551 if fd != 2: os.dup2(fd, 2)
2546 if fd not in (0, 1, 2): os.close(fd)
2552 if fd not in (0, 1, 2): os.close(fd)
2547
2553
2548 httpd.serve_forever()
2554 httpd.serve_forever()
2549
2555
2550 def status(ui, repo, *pats, **opts):
2556 def status(ui, repo, *pats, **opts):
2551 """show changed files in the working directory
2557 """show changed files in the working directory
2552
2558
2553 Show changed files in the repository. If names are
2559 Show changed files in the repository. If names are
2554 given, only files that match are shown.
2560 given, only files that match are shown.
2555
2561
2556 The codes used to show the status of files are:
2562 The codes used to show the status of files are:
2557 M = modified
2563 M = modified
2558 A = added
2564 A = added
2559 R = removed
2565 R = removed
2560 ! = deleted, but still tracked
2566 ! = deleted, but still tracked
2561 ? = not tracked
2567 ? = not tracked
2562 I = ignored (not shown by default)
2568 I = ignored (not shown by default)
2563 """
2569 """
2564
2570
2565 show_ignored = opts['ignored'] and True or False
2571 show_ignored = opts['ignored'] and True or False
2566 files, matchfn, anypats = matchpats(repo, pats, opts)
2572 files, matchfn, anypats = matchpats(repo, pats, opts)
2567 cwd = (pats and repo.getcwd()) or ''
2573 cwd = (pats and repo.getcwd()) or ''
2568 modified, added, removed, deleted, unknown, ignored = [
2574 modified, added, removed, deleted, unknown, ignored = [
2569 [util.pathto(cwd, x) for x in n]
2575 [util.pathto(cwd, x) for x in n]
2570 for n in repo.changes(files=files, match=matchfn,
2576 for n in repo.changes(files=files, match=matchfn,
2571 show_ignored=show_ignored)]
2577 show_ignored=show_ignored)]
2572
2578
2573 changetypes = [('modified', 'M', modified),
2579 changetypes = [('modified', 'M', modified),
2574 ('added', 'A', added),
2580 ('added', 'A', added),
2575 ('removed', 'R', removed),
2581 ('removed', 'R', removed),
2576 ('deleted', '!', deleted),
2582 ('deleted', '!', deleted),
2577 ('unknown', '?', unknown),
2583 ('unknown', '?', unknown),
2578 ('ignored', 'I', ignored)]
2584 ('ignored', 'I', ignored)]
2579
2585
2580 end = opts['print0'] and '\0' or '\n'
2586 end = opts['print0'] and '\0' or '\n'
2581
2587
2582 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
2588 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
2583 or changetypes):
2589 or changetypes):
2584 if opts['no_status']:
2590 if opts['no_status']:
2585 format = "%%s%s" % end
2591 format = "%%s%s" % end
2586 else:
2592 else:
2587 format = "%s %%s%s" % (char, end)
2593 format = "%s %%s%s" % (char, end)
2588
2594
2589 for f in changes:
2595 for f in changes:
2590 ui.write(format % f)
2596 ui.write(format % f)
2591
2597
2592 def tag(ui, repo, name, rev_=None, **opts):
2598 def tag(ui, repo, name, rev_=None, **opts):
2593 """add a tag for the current tip or a given revision
2599 """add a tag for the current tip or a given revision
2594
2600
2595 Name a particular revision using <name>.
2601 Name a particular revision using <name>.
2596
2602
2597 Tags are used to name particular revisions of the repository and are
2603 Tags are used to name particular revisions of the repository and are
2598 very useful to compare different revision, to go back to significant
2604 very useful to compare different revision, to go back to significant
2599 earlier versions or to mark branch points as releases, etc.
2605 earlier versions or to mark branch points as releases, etc.
2600
2606
2601 If no revision is given, the tip is used.
2607 If no revision is given, the tip is used.
2602
2608
2603 To facilitate version control, distribution, and merging of tags,
2609 To facilitate version control, distribution, and merging of tags,
2604 they are stored as a file named ".hgtags" which is managed
2610 they are stored as a file named ".hgtags" which is managed
2605 similarly to other project files and can be hand-edited if
2611 similarly to other project files and can be hand-edited if
2606 necessary. The file '.hg/localtags' is used for local tags (not
2612 necessary. The file '.hg/localtags' is used for local tags (not
2607 shared among repositories).
2613 shared among repositories).
2608 """
2614 """
2609 if name == "tip":
2615 if name == "tip":
2610 raise util.Abort(_("the name 'tip' is reserved"))
2616 raise util.Abort(_("the name 'tip' is reserved"))
2611 if rev_ is not None:
2617 if rev_ is not None:
2612 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2618 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2613 "please use 'hg tag [-r REV] NAME' instead\n"))
2619 "please use 'hg tag [-r REV] NAME' instead\n"))
2614 if opts['rev']:
2620 if opts['rev']:
2615 raise util.Abort(_("use only one form to specify the revision"))
2621 raise util.Abort(_("use only one form to specify the revision"))
2616 if opts['rev']:
2622 if opts['rev']:
2617 rev_ = opts['rev']
2623 rev_ = opts['rev']
2618 if rev_:
2624 if rev_:
2619 r = hex(repo.lookup(rev_))
2625 r = hex(repo.lookup(rev_))
2620 else:
2626 else:
2621 r = hex(repo.changelog.tip())
2627 r = hex(repo.changelog.tip())
2622
2628
2623 disallowed = (revrangesep, '\r', '\n')
2629 disallowed = (revrangesep, '\r', '\n')
2624 for c in disallowed:
2630 for c in disallowed:
2625 if name.find(c) >= 0:
2631 if name.find(c) >= 0:
2626 raise util.Abort(_("%s cannot be used in a tag name") % repr(c))
2632 raise util.Abort(_("%s cannot be used in a tag name") % repr(c))
2627
2633
2628 repo.hook('pretag', throw=True, node=r, tag=name,
2634 repo.hook('pretag', throw=True, node=r, tag=name,
2629 local=int(not not opts['local']))
2635 local=int(not not opts['local']))
2630
2636
2631 if opts['local']:
2637 if opts['local']:
2632 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
2638 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
2633 repo.hook('tag', node=r, tag=name, local=1)
2639 repo.hook('tag', node=r, tag=name, local=1)
2634 return
2640 return
2635
2641
2636 for x in repo.changes():
2642 for x in repo.changes():
2637 if ".hgtags" in x:
2643 if ".hgtags" in x:
2638 raise util.Abort(_("working copy of .hgtags is changed "
2644 raise util.Abort(_("working copy of .hgtags is changed "
2639 "(please commit .hgtags manually)"))
2645 "(please commit .hgtags manually)"))
2640
2646
2641 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
2647 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
2642 if repo.dirstate.state(".hgtags") == '?':
2648 if repo.dirstate.state(".hgtags") == '?':
2643 repo.add([".hgtags"])
2649 repo.add([".hgtags"])
2644
2650
2645 message = (opts['message'] or
2651 message = (opts['message'] or
2646 _("Added tag %s for changeset %s") % (name, r))
2652 _("Added tag %s for changeset %s") % (name, r))
2647 try:
2653 try:
2648 repo.commit([".hgtags"], message, opts['user'], opts['date'])
2654 repo.commit([".hgtags"], message, opts['user'], opts['date'])
2649 repo.hook('tag', node=r, tag=name, local=0)
2655 repo.hook('tag', node=r, tag=name, local=0)
2650 except ValueError, inst:
2656 except ValueError, inst:
2651 raise util.Abort(str(inst))
2657 raise util.Abort(str(inst))
2652
2658
2653 def tags(ui, repo):
2659 def tags(ui, repo):
2654 """list repository tags
2660 """list repository tags
2655
2661
2656 List the repository tags.
2662 List the repository tags.
2657
2663
2658 This lists both regular and local tags.
2664 This lists both regular and local tags.
2659 """
2665 """
2660
2666
2661 l = repo.tagslist()
2667 l = repo.tagslist()
2662 l.reverse()
2668 l.reverse()
2663 for t, n in l:
2669 for t, n in l:
2664 try:
2670 try:
2665 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2671 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2666 except KeyError:
2672 except KeyError:
2667 r = " ?:?"
2673 r = " ?:?"
2668 if ui.quiet:
2674 if ui.quiet:
2669 ui.write("%s\n" % t)
2675 ui.write("%s\n" % t)
2670 else:
2676 else:
2671 ui.write("%-30s %s\n" % (t, r))
2677 ui.write("%-30s %s\n" % (t, r))
2672
2678
2673 def tip(ui, repo, **opts):
2679 def tip(ui, repo, **opts):
2674 """show the tip revision
2680 """show the tip revision
2675
2681
2676 Show the tip revision.
2682 Show the tip revision.
2677 """
2683 """
2678 n = repo.changelog.tip()
2684 n = repo.changelog.tip()
2679 br = None
2685 br = None
2680 if opts['branches']:
2686 if opts['branches']:
2681 br = repo.branchlookup([n])
2687 br = repo.branchlookup([n])
2682 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
2688 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
2683 if opts['patch']:
2689 if opts['patch']:
2684 dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n)
2690 dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n)
2685
2691
2686 def unbundle(ui, repo, fname, **opts):
2692 def unbundle(ui, repo, fname, **opts):
2687 """apply a changegroup file
2693 """apply a changegroup file
2688
2694
2689 Apply a compressed changegroup file generated by the bundle
2695 Apply a compressed changegroup file generated by the bundle
2690 command.
2696 command.
2691 """
2697 """
2692 f = urllib.urlopen(fname)
2698 f = urllib.urlopen(fname)
2693
2699
2694 header = f.read(6)
2700 header = f.read(6)
2695 if not header.startswith("HG"):
2701 if not header.startswith("HG"):
2696 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2702 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2697 elif not header.startswith("HG10"):
2703 elif not header.startswith("HG10"):
2698 raise util.Abort(_("%s: unknown bundle version") % fname)
2704 raise util.Abort(_("%s: unknown bundle version") % fname)
2699 elif header == "HG10BZ":
2705 elif header == "HG10BZ":
2700 def generator(f):
2706 def generator(f):
2701 zd = bz2.BZ2Decompressor()
2707 zd = bz2.BZ2Decompressor()
2702 zd.decompress("BZ")
2708 zd.decompress("BZ")
2703 for chunk in f:
2709 for chunk in f:
2704 yield zd.decompress(chunk)
2710 yield zd.decompress(chunk)
2705 elif header == "HG10UN":
2711 elif header == "HG10UN":
2706 def generator(f):
2712 def generator(f):
2707 for chunk in f:
2713 for chunk in f:
2708 yield chunk
2714 yield chunk
2709 else:
2715 else:
2710 raise util.Abort(_("%s: unknown bundle compression type")
2716 raise util.Abort(_("%s: unknown bundle compression type")
2711 % fname)
2717 % fname)
2712 gen = generator(util.filechunkiter(f, 4096))
2718 gen = generator(util.filechunkiter(f, 4096))
2713 modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle')
2719 modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle')
2714 return postincoming(ui, repo, modheads, opts['update'])
2720 return postincoming(ui, repo, modheads, opts['update'])
2715
2721
2716 def undo(ui, repo):
2722 def undo(ui, repo):
2717 """undo the last commit or pull (DEPRECATED)
2723 """undo the last commit or pull (DEPRECATED)
2718
2724
2719 (DEPRECATED)
2725 (DEPRECATED)
2720 This command is now deprecated and will be removed in a future
2726 This command is now deprecated and will be removed in a future
2721 release. Please use the rollback command instead. For usage
2727 release. Please use the rollback command instead. For usage
2722 instructions, see the rollback command.
2728 instructions, see the rollback command.
2723 """
2729 """
2724 ui.warn(_('(the undo command is deprecated; use rollback instead)\n'))
2730 ui.warn(_('(the undo command is deprecated; use rollback instead)\n'))
2725 repo.undo()
2731 repo.undo()
2726
2732
2727 def update(ui, repo, node=None, merge=False, clean=False, force=None,
2733 def update(ui, repo, node=None, merge=False, clean=False, force=None,
2728 branch=None, **opts):
2734 branch=None, **opts):
2729 """update or merge working directory
2735 """update or merge working directory
2730
2736
2731 Update the working directory to the specified revision.
2737 Update the working directory to the specified revision.
2732
2738
2733 If there are no outstanding changes in the working directory and
2739 If there are no outstanding changes in the working directory and
2734 there is a linear relationship between the current version and the
2740 there is a linear relationship between the current version and the
2735 requested version, the result is the requested version.
2741 requested version, the result is the requested version.
2736
2742
2737 Otherwise the result is a merge between the contents of the
2743 Otherwise the result is a merge between the contents of the
2738 current working directory and the requested version. Files that
2744 current working directory and the requested version. Files that
2739 changed between either parent are marked as changed for the next
2745 changed between either parent are marked as changed for the next
2740 commit and a commit must be performed before any further updates
2746 commit and a commit must be performed before any further updates
2741 are allowed.
2747 are allowed.
2742
2748
2743 By default, update will refuse to run if doing so would require
2749 By default, update will refuse to run if doing so would require
2744 merging or discarding local changes.
2750 merging or discarding local changes.
2745 """
2751 """
2746 if branch:
2752 if branch:
2747 br = repo.branchlookup(branch=branch)
2753 br = repo.branchlookup(branch=branch)
2748 found = []
2754 found = []
2749 for x in br:
2755 for x in br:
2750 if branch in br[x]:
2756 if branch in br[x]:
2751 found.append(x)
2757 found.append(x)
2752 if len(found) > 1:
2758 if len(found) > 1:
2753 ui.warn(_("Found multiple heads for %s\n") % branch)
2759 ui.warn(_("Found multiple heads for %s\n") % branch)
2754 for x in found:
2760 for x in found:
2755 show_changeset(ui, repo, opts).show(changenode=x, brinfo=br)
2761 show_changeset(ui, repo, opts).show(changenode=x, brinfo=br)
2756 return 1
2762 return 1
2757 if len(found) == 1:
2763 if len(found) == 1:
2758 node = found[0]
2764 node = found[0]
2759 ui.warn(_("Using head %s for branch %s\n") % (short(node), branch))
2765 ui.warn(_("Using head %s for branch %s\n") % (short(node), branch))
2760 else:
2766 else:
2761 ui.warn(_("branch %s not found\n") % (branch))
2767 ui.warn(_("branch %s not found\n") % (branch))
2762 return 1
2768 return 1
2763 else:
2769 else:
2764 node = node and repo.lookup(node) or repo.changelog.tip()
2770 node = node and repo.lookup(node) or repo.changelog.tip()
2765 return repo.update(node, allow=merge, force=clean, forcemerge=force)
2771 return repo.update(node, allow=merge, force=clean, forcemerge=force)
2766
2772
2767 def verify(ui, repo):
2773 def verify(ui, repo):
2768 """verify the integrity of the repository
2774 """verify the integrity of the repository
2769
2775
2770 Verify the integrity of the current repository.
2776 Verify the integrity of the current repository.
2771
2777
2772 This will perform an extensive check of the repository's
2778 This will perform an extensive check of the repository's
2773 integrity, validating the hashes and checksums of each entry in
2779 integrity, validating the hashes and checksums of each entry in
2774 the changelog, manifest, and tracked files, as well as the
2780 the changelog, manifest, and tracked files, as well as the
2775 integrity of their crosslinks and indices.
2781 integrity of their crosslinks and indices.
2776 """
2782 """
2777 return repo.verify()
2783 return repo.verify()
2778
2784
2779 # Command options and aliases are listed here, alphabetically
2785 # Command options and aliases are listed here, alphabetically
2780
2786
2781 table = {
2787 table = {
2782 "^add":
2788 "^add":
2783 (add,
2789 (add,
2784 [('I', 'include', [], _('include names matching the given patterns')),
2790 [('I', 'include', [], _('include names matching the given patterns')),
2785 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2791 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2786 _('hg add [OPTION]... [FILE]...')),
2792 _('hg add [OPTION]... [FILE]...')),
2787 "debugaddremove|addremove":
2793 "debugaddremove|addremove":
2788 (addremove,
2794 (addremove,
2789 [('I', 'include', [], _('include names matching the given patterns')),
2795 [('I', 'include', [], _('include names matching the given patterns')),
2790 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2796 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2791 _('hg addremove [OPTION]... [FILE]...')),
2797 _('hg addremove [OPTION]... [FILE]...')),
2792 "^annotate":
2798 "^annotate":
2793 (annotate,
2799 (annotate,
2794 [('r', 'rev', '', _('annotate the specified revision')),
2800 [('r', 'rev', '', _('annotate the specified revision')),
2795 ('a', 'text', None, _('treat all files as text')),
2801 ('a', 'text', None, _('treat all files as text')),
2796 ('u', 'user', None, _('list the author')),
2802 ('u', 'user', None, _('list the author')),
2797 ('d', 'date', None, _('list the date')),
2803 ('d', 'date', None, _('list the date')),
2798 ('n', 'number', None, _('list the revision number (default)')),
2804 ('n', 'number', None, _('list the revision number (default)')),
2799 ('c', 'changeset', None, _('list the changeset')),
2805 ('c', 'changeset', None, _('list the changeset')),
2800 ('I', 'include', [], _('include names matching the given patterns')),
2806 ('I', 'include', [], _('include names matching the given patterns')),
2801 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2807 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2802 _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
2808 _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
2803 "archive":
2809 "archive":
2804 (archive,
2810 (archive,
2805 [('', 'no-decode', None, _('do not pass files through decoders')),
2811 [('', 'no-decode', None, _('do not pass files through decoders')),
2806 ('p', 'prefix', '', _('directory prefix for files in archive')),
2812 ('p', 'prefix', '', _('directory prefix for files in archive')),
2807 ('r', 'rev', '', _('revision to distribute')),
2813 ('r', 'rev', '', _('revision to distribute')),
2808 ('t', 'type', '', _('type of distribution to create')),
2814 ('t', 'type', '', _('type of distribution to create')),
2809 ('I', 'include', [], _('include names matching the given patterns')),
2815 ('I', 'include', [], _('include names matching the given patterns')),
2810 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2816 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2811 _('hg archive [OPTION]... DEST')),
2817 _('hg archive [OPTION]... DEST')),
2812 "backout":
2818 "backout":
2813 (backout,
2819 (backout,
2814 [('', 'merge', None,
2820 [('', 'merge', None,
2815 _('merge with old dirstate parent after backout')),
2821 _('merge with old dirstate parent after backout')),
2816 ('m', 'message', '', _('use <text> as commit message')),
2822 ('m', 'message', '', _('use <text> as commit message')),
2817 ('l', 'logfile', '', _('read commit message from <file>')),
2823 ('l', 'logfile', '', _('read commit message from <file>')),
2818 ('d', 'date', '', _('record datecode as commit date')),
2824 ('d', 'date', '', _('record datecode as commit date')),
2819 ('u', 'user', '', _('record user as committer')),
2825 ('u', 'user', '', _('record user as committer')),
2820 ('I', 'include', [], _('include names matching the given patterns')),
2826 ('I', 'include', [], _('include names matching the given patterns')),
2821 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2827 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2822 _('hg backout [OPTION]... REV')),
2828 _('hg backout [OPTION]... REV')),
2823 "bundle":
2829 "bundle":
2824 (bundle,
2830 (bundle,
2825 [('f', 'force', None,
2831 [('f', 'force', None,
2826 _('run even when remote repository is unrelated'))],
2832 _('run even when remote repository is unrelated'))],
2827 _('hg bundle FILE DEST')),
2833 _('hg bundle FILE DEST')),
2828 "cat":
2834 "cat":
2829 (cat,
2835 (cat,
2830 [('o', 'output', '', _('print output to file with formatted name')),
2836 [('o', 'output', '', _('print output to file with formatted name')),
2831 ('r', 'rev', '', _('print the given revision')),
2837 ('r', 'rev', '', _('print the given revision')),
2832 ('I', 'include', [], _('include names matching the given patterns')),
2838 ('I', 'include', [], _('include names matching the given patterns')),
2833 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2839 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2834 _('hg cat [OPTION]... FILE...')),
2840 _('hg cat [OPTION]... FILE...')),
2835 "^clone":
2841 "^clone":
2836 (clone,
2842 (clone,
2837 [('U', 'noupdate', None, _('do not update the new working directory')),
2843 [('U', 'noupdate', None, _('do not update the new working directory')),
2838 ('r', 'rev', [],
2844 ('r', 'rev', [],
2839 _('a changeset you would like to have after cloning')),
2845 _('a changeset you would like to have after cloning')),
2840 ('', 'pull', None, _('use pull protocol to copy metadata')),
2846 ('', 'pull', None, _('use pull protocol to copy metadata')),
2841 ('e', 'ssh', '', _('specify ssh command to use')),
2847 ('e', 'ssh', '', _('specify ssh command to use')),
2842 ('', 'remotecmd', '',
2848 ('', 'remotecmd', '',
2843 _('specify hg command to run on the remote side'))],
2849 _('specify hg command to run on the remote side'))],
2844 _('hg clone [OPTION]... SOURCE [DEST]')),
2850 _('hg clone [OPTION]... SOURCE [DEST]')),
2845 "^commit|ci":
2851 "^commit|ci":
2846 (commit,
2852 (commit,
2847 [('A', 'addremove', None,
2853 [('A', 'addremove', None,
2848 _('mark new/missing files as added/removed before committing')),
2854 _('mark new/missing files as added/removed before committing')),
2849 ('m', 'message', '', _('use <text> as commit message')),
2855 ('m', 'message', '', _('use <text> as commit message')),
2850 ('l', 'logfile', '', _('read the commit message from <file>')),
2856 ('l', 'logfile', '', _('read the commit message from <file>')),
2851 ('d', 'date', '', _('record datecode as commit date')),
2857 ('d', 'date', '', _('record datecode as commit date')),
2852 ('u', 'user', '', _('record user as commiter')),
2858 ('u', 'user', '', _('record user as commiter')),
2853 ('I', 'include', [], _('include names matching the given patterns')),
2859 ('I', 'include', [], _('include names matching the given patterns')),
2854 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2860 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2855 _('hg commit [OPTION]... [FILE]...')),
2861 _('hg commit [OPTION]... [FILE]...')),
2856 "copy|cp":
2862 "copy|cp":
2857 (copy,
2863 (copy,
2858 [('A', 'after', None, _('record a copy that has already occurred')),
2864 [('A', 'after', None, _('record a copy that has already occurred')),
2859 ('f', 'force', None,
2865 ('f', 'force', None,
2860 _('forcibly copy over an existing managed file')),
2866 _('forcibly copy over an existing managed file')),
2861 ('I', 'include', [], _('include names matching the given patterns')),
2867 ('I', 'include', [], _('include names matching the given patterns')),
2862 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2868 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2863 _('hg copy [OPTION]... [SOURCE]... DEST')),
2869 _('hg copy [OPTION]... [SOURCE]... DEST')),
2864 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2870 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2865 "debugcomplete":
2871 "debugcomplete":
2866 (debugcomplete,
2872 (debugcomplete,
2867 [('o', 'options', None, _('show the command options'))],
2873 [('o', 'options', None, _('show the command options'))],
2868 _('debugcomplete [-o] CMD')),
2874 _('debugcomplete [-o] CMD')),
2869 "debugrebuildstate":
2875 "debugrebuildstate":
2870 (debugrebuildstate,
2876 (debugrebuildstate,
2871 [('r', 'rev', '', _('revision to rebuild to'))],
2877 [('r', 'rev', '', _('revision to rebuild to'))],
2872 _('debugrebuildstate [-r REV] [REV]')),
2878 _('debugrebuildstate [-r REV] [REV]')),
2873 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2879 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2874 "debugconfig": (debugconfig, [], _('debugconfig')),
2880 "debugconfig": (debugconfig, [], _('debugconfig')),
2875 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2881 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2876 "debugstate": (debugstate, [], _('debugstate')),
2882 "debugstate": (debugstate, [], _('debugstate')),
2877 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2883 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2878 "debugindex": (debugindex, [], _('debugindex FILE')),
2884 "debugindex": (debugindex, [], _('debugindex FILE')),
2879 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2885 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2880 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2886 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2881 "debugwalk":
2887 "debugwalk":
2882 (debugwalk,
2888 (debugwalk,
2883 [('I', 'include', [], _('include names matching the given patterns')),
2889 [('I', 'include', [], _('include names matching the given patterns')),
2884 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2890 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2885 _('debugwalk [OPTION]... [FILE]...')),
2891 _('debugwalk [OPTION]... [FILE]...')),
2886 "^diff":
2892 "^diff":
2887 (diff,
2893 (diff,
2888 [('r', 'rev', [], _('revision')),
2894 [('r', 'rev', [], _('revision')),
2889 ('a', 'text', None, _('treat all files as text')),
2895 ('a', 'text', None, _('treat all files as text')),
2890 ('p', 'show-function', None,
2896 ('p', 'show-function', None,
2891 _('show which function each change is in')),
2897 _('show which function each change is in')),
2892 ('w', 'ignore-all-space', None,
2898 ('w', 'ignore-all-space', None,
2893 _('ignore white space when comparing lines')),
2899 _('ignore white space when comparing lines')),
2894 ('I', 'include', [], _('include names matching the given patterns')),
2900 ('I', 'include', [], _('include names matching the given patterns')),
2895 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2901 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2896 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2902 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2897 "^export":
2903 "^export":
2898 (export,
2904 (export,
2899 [('o', 'output', '', _('print output to file with formatted name')),
2905 [('o', 'output', '', _('print output to file with formatted name')),
2900 ('a', 'text', None, _('treat all files as text')),
2906 ('a', 'text', None, _('treat all files as text')),
2901 ('', 'switch-parent', None, _('diff against the second parent'))],
2907 ('', 'switch-parent', None, _('diff against the second parent'))],
2902 _('hg export [-a] [-o OUTFILESPEC] REV...')),
2908 _('hg export [-a] [-o OUTFILESPEC] REV...')),
2903 "debugforget|forget":
2909 "debugforget|forget":
2904 (forget,
2910 (forget,
2905 [('I', 'include', [], _('include names matching the given patterns')),
2911 [('I', 'include', [], _('include names matching the given patterns')),
2906 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2912 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2907 _('hg forget [OPTION]... FILE...')),
2913 _('hg forget [OPTION]... FILE...')),
2908 "grep":
2914 "grep":
2909 (grep,
2915 (grep,
2910 [('0', 'print0', None, _('end fields with NUL')),
2916 [('0', 'print0', None, _('end fields with NUL')),
2911 ('', 'all', None, _('print all revisions that match')),
2917 ('', 'all', None, _('print all revisions that match')),
2912 ('i', 'ignore-case', None, _('ignore case when matching')),
2918 ('i', 'ignore-case', None, _('ignore case when matching')),
2913 ('l', 'files-with-matches', None,
2919 ('l', 'files-with-matches', None,
2914 _('print only filenames and revs that match')),
2920 _('print only filenames and revs that match')),
2915 ('n', 'line-number', None, _('print matching line numbers')),
2921 ('n', 'line-number', None, _('print matching line numbers')),
2916 ('r', 'rev', [], _('search in given revision range')),
2922 ('r', 'rev', [], _('search in given revision range')),
2917 ('u', 'user', None, _('print user who committed change')),
2923 ('u', 'user', None, _('print user who committed change')),
2918 ('I', 'include', [], _('include names matching the given patterns')),
2924 ('I', 'include', [], _('include names matching the given patterns')),
2919 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2925 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2920 _('hg grep [OPTION]... PATTERN [FILE]...')),
2926 _('hg grep [OPTION]... PATTERN [FILE]...')),
2921 "heads":
2927 "heads":
2922 (heads,
2928 (heads,
2923 [('b', 'branches', None, _('show branches')),
2929 [('b', 'branches', None, _('show branches')),
2924 ('', 'style', '', _('display using template map file')),
2930 ('', 'style', '', _('display using template map file')),
2925 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2931 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2926 ('', 'template', '', _('display with template'))],
2932 ('', 'template', '', _('display with template'))],
2927 _('hg heads [-b] [-r <rev>]')),
2933 _('hg heads [-b] [-r <rev>]')),
2928 "help": (help_, [], _('hg help [COMMAND]')),
2934 "help": (help_, [], _('hg help [COMMAND]')),
2929 "identify|id": (identify, [], _('hg identify')),
2935 "identify|id": (identify, [], _('hg identify')),
2930 "import|patch":
2936 "import|patch":
2931 (import_,
2937 (import_,
2932 [('p', 'strip', 1,
2938 [('p', 'strip', 1,
2933 _('directory strip option for patch. This has the same\n'
2939 _('directory strip option for patch. This has the same\n'
2934 'meaning as the corresponding patch option')),
2940 'meaning as the corresponding patch option')),
2935 ('b', 'base', '', _('base path')),
2941 ('b', 'base', '', _('base path')),
2936 ('f', 'force', None,
2942 ('f', 'force', None,
2937 _('skip check for outstanding uncommitted changes'))],
2943 _('skip check for outstanding uncommitted changes'))],
2938 _('hg import [-p NUM] [-b BASE] [-f] PATCH...')),
2944 _('hg import [-p NUM] [-b BASE] [-f] PATCH...')),
2939 "incoming|in": (incoming,
2945 "incoming|in": (incoming,
2940 [('M', 'no-merges', None, _('do not show merges')),
2946 [('M', 'no-merges', None, _('do not show merges')),
2941 ('f', 'force', None,
2947 ('f', 'force', None,
2942 _('run even when remote repository is unrelated')),
2948 _('run even when remote repository is unrelated')),
2943 ('', 'style', '', _('display using template map file')),
2949 ('', 'style', '', _('display using template map file')),
2944 ('n', 'newest-first', None, _('show newest record first')),
2950 ('n', 'newest-first', None, _('show newest record first')),
2945 ('', 'bundle', '', _('file to store the bundles into')),
2951 ('', 'bundle', '', _('file to store the bundles into')),
2946 ('p', 'patch', None, _('show patch')),
2952 ('p', 'patch', None, _('show patch')),
2947 ('', 'template', '', _('display with template')),
2953 ('', 'template', '', _('display with template')),
2948 ('e', 'ssh', '', _('specify ssh command to use')),
2954 ('e', 'ssh', '', _('specify ssh command to use')),
2949 ('', 'remotecmd', '',
2955 ('', 'remotecmd', '',
2950 _('specify hg command to run on the remote side'))],
2956 _('specify hg command to run on the remote side'))],
2951 _('hg incoming [-p] [-n] [-M] [--bundle FILENAME] [SOURCE]')),
2957 _('hg incoming [-p] [-n] [-M] [--bundle FILENAME] [SOURCE]')),
2952 "^init": (init, [], _('hg init [DEST]')),
2958 "^init": (init, [], _('hg init [DEST]')),
2953 "locate":
2959 "locate":
2954 (locate,
2960 (locate,
2955 [('r', 'rev', '', _('search the repository as it stood at rev')),
2961 [('r', 'rev', '', _('search the repository as it stood at rev')),
2956 ('0', 'print0', None,
2962 ('0', 'print0', None,
2957 _('end filenames with NUL, for use with xargs')),
2963 _('end filenames with NUL, for use with xargs')),
2958 ('f', 'fullpath', None,
2964 ('f', 'fullpath', None,
2959 _('print complete paths from the filesystem root')),
2965 _('print complete paths from the filesystem root')),
2960 ('I', 'include', [], _('include names matching the given patterns')),
2966 ('I', 'include', [], _('include names matching the given patterns')),
2961 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2967 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2962 _('hg locate [OPTION]... [PATTERN]...')),
2968 _('hg locate [OPTION]... [PATTERN]...')),
2963 "^log|history":
2969 "^log|history":
2964 (log,
2970 (log,
2965 [('b', 'branches', None, _('show branches')),
2971 [('b', 'branches', None, _('show branches')),
2966 ('k', 'keyword', [], _('search for a keyword')),
2972 ('k', 'keyword', [], _('search for a keyword')),
2967 ('l', 'limit', '', _('limit number of changes displayed')),
2973 ('l', 'limit', '', _('limit number of changes displayed')),
2968 ('r', 'rev', [], _('show the specified revision or range')),
2974 ('r', 'rev', [], _('show the specified revision or range')),
2969 ('M', 'no-merges', None, _('do not show merges')),
2975 ('M', 'no-merges', None, _('do not show merges')),
2970 ('', 'style', '', _('display using template map file')),
2976 ('', 'style', '', _('display using template map file')),
2971 ('m', 'only-merges', None, _('show only merges')),
2977 ('m', 'only-merges', None, _('show only merges')),
2972 ('p', 'patch', None, _('show patch')),
2978 ('p', 'patch', None, _('show patch')),
2973 ('', 'template', '', _('display with template')),
2979 ('', 'template', '', _('display with template')),
2974 ('I', 'include', [], _('include names matching the given patterns')),
2980 ('I', 'include', [], _('include names matching the given patterns')),
2975 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2981 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2976 _('hg log [OPTION]... [FILE]')),
2982 _('hg log [OPTION]... [FILE]')),
2977 "manifest": (manifest, [], _('hg manifest [REV]')),
2983 "manifest": (manifest, [], _('hg manifest [REV]')),
2978 "merge":
2984 "merge":
2979 (merge,
2985 (merge,
2980 [('b', 'branch', '', _('merge with head of a specific branch')),
2986 [('b', 'branch', '', _('merge with head of a specific branch')),
2981 ('f', 'force', None, _('force a merge with outstanding changes'))],
2987 ('f', 'force', None, _('force a merge with outstanding changes'))],
2982 _('hg merge [-b TAG] [-f] [REV]')),
2988 _('hg merge [-b TAG] [-f] [REV]')),
2983 "outgoing|out": (outgoing,
2989 "outgoing|out": (outgoing,
2984 [('M', 'no-merges', None, _('do not show merges')),
2990 [('M', 'no-merges', None, _('do not show merges')),
2985 ('f', 'force', None,
2991 ('f', 'force', None,
2986 _('run even when remote repository is unrelated')),
2992 _('run even when remote repository is unrelated')),
2987 ('p', 'patch', None, _('show patch')),
2993 ('p', 'patch', None, _('show patch')),
2988 ('', 'style', '', _('display using template map file')),
2994 ('', 'style', '', _('display using template map file')),
2989 ('n', 'newest-first', None, _('show newest record first')),
2995 ('n', 'newest-first', None, _('show newest record first')),
2990 ('', 'template', '', _('display with template')),
2996 ('', 'template', '', _('display with template')),
2991 ('e', 'ssh', '', _('specify ssh command to use')),
2997 ('e', 'ssh', '', _('specify ssh command to use')),
2992 ('', 'remotecmd', '',
2998 ('', 'remotecmd', '',
2993 _('specify hg command to run on the remote side'))],
2999 _('specify hg command to run on the remote side'))],
2994 _('hg outgoing [-M] [-p] [-n] [DEST]')),
3000 _('hg outgoing [-M] [-p] [-n] [DEST]')),
2995 "^parents":
3001 "^parents":
2996 (parents,
3002 (parents,
2997 [('b', 'branches', None, _('show branches')),
3003 [('b', 'branches', None, _('show branches')),
2998 ('', 'style', '', _('display using template map file')),
3004 ('', 'style', '', _('display using template map file')),
2999 ('', 'template', '', _('display with template'))],
3005 ('', 'template', '', _('display with template'))],
3000 _('hg parents [-b] [REV]')),
3006 _('hg parents [-b] [REV]')),
3001 "paths": (paths, [], _('hg paths [NAME]')),
3007 "paths": (paths, [], _('hg paths [NAME]')),
3002 "^pull":
3008 "^pull":
3003 (pull,
3009 (pull,
3004 [('u', 'update', None,
3010 [('u', 'update', None,
3005 _('update the working directory to tip after pull')),
3011 _('update the working directory to tip after pull')),
3006 ('e', 'ssh', '', _('specify ssh command to use')),
3012 ('e', 'ssh', '', _('specify ssh command to use')),
3007 ('f', 'force', None,
3013 ('f', 'force', None,
3008 _('run even when remote repository is unrelated')),
3014 _('run even when remote repository is unrelated')),
3009 ('r', 'rev', [], _('a specific revision you would like to pull')),
3015 ('r', 'rev', [], _('a specific revision you would like to pull')),
3010 ('', 'remotecmd', '',
3016 ('', 'remotecmd', '',
3011 _('specify hg command to run on the remote side'))],
3017 _('specify hg command to run on the remote side'))],
3012 _('hg pull [-u] [-e FILE] [-r REV]... [--remotecmd FILE] [SOURCE]')),
3018 _('hg pull [-u] [-e FILE] [-r REV]... [--remotecmd FILE] [SOURCE]')),
3013 "^push":
3019 "^push":
3014 (push,
3020 (push,
3015 [('f', 'force', None, _('force push')),
3021 [('f', 'force', None, _('force push')),
3016 ('e', 'ssh', '', _('specify ssh command to use')),
3022 ('e', 'ssh', '', _('specify ssh command to use')),
3017 ('r', 'rev', [], _('a specific revision you would like to push')),
3023 ('r', 'rev', [], _('a specific revision you would like to push')),
3018 ('', 'remotecmd', '',
3024 ('', 'remotecmd', '',
3019 _('specify hg command to run on the remote side'))],
3025 _('specify hg command to run on the remote side'))],
3020 _('hg push [-f] [-e FILE] [-r REV]... [--remotecmd FILE] [DEST]')),
3026 _('hg push [-f] [-e FILE] [-r REV]... [--remotecmd FILE] [DEST]')),
3021 "debugrawcommit|rawcommit":
3027 "debugrawcommit|rawcommit":
3022 (rawcommit,
3028 (rawcommit,
3023 [('p', 'parent', [], _('parent')),
3029 [('p', 'parent', [], _('parent')),
3024 ('d', 'date', '', _('date code')),
3030 ('d', 'date', '', _('date code')),
3025 ('u', 'user', '', _('user')),
3031 ('u', 'user', '', _('user')),
3026 ('F', 'files', '', _('file list')),
3032 ('F', 'files', '', _('file list')),
3027 ('m', 'message', '', _('commit message')),
3033 ('m', 'message', '', _('commit message')),
3028 ('l', 'logfile', '', _('commit message file'))],
3034 ('l', 'logfile', '', _('commit message file'))],
3029 _('hg debugrawcommit [OPTION]... [FILE]...')),
3035 _('hg debugrawcommit [OPTION]... [FILE]...')),
3030 "recover": (recover, [], _('hg recover')),
3036 "recover": (recover, [], _('hg recover')),
3031 "^remove|rm":
3037 "^remove|rm":
3032 (remove,
3038 (remove,
3033 [('A', 'after', None, _('record remove that has already occurred')),
3039 [('A', 'after', None, _('record remove that has already occurred')),
3034 ('f', 'force', None, _('remove file even if modified')),
3040 ('f', 'force', None, _('remove file even if modified')),
3035 ('I', 'include', [], _('include names matching the given patterns')),
3041 ('I', 'include', [], _('include names matching the given patterns')),
3036 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3042 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3037 _('hg remove [OPTION]... FILE...')),
3043 _('hg remove [OPTION]... FILE...')),
3038 "rename|mv":
3044 "rename|mv":
3039 (rename,
3045 (rename,
3040 [('A', 'after', None, _('record a rename that has already occurred')),
3046 [('A', 'after', None, _('record a rename that has already occurred')),
3041 ('f', 'force', None,
3047 ('f', 'force', None,
3042 _('forcibly copy over an existing managed file')),
3048 _('forcibly copy over an existing managed file')),
3043 ('I', 'include', [], _('include names matching the given patterns')),
3049 ('I', 'include', [], _('include names matching the given patterns')),
3044 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3050 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3045 _('hg rename [OPTION]... SOURCE... DEST')),
3051 _('hg rename [OPTION]... SOURCE... DEST')),
3046 "^revert":
3052 "^revert":
3047 (revert,
3053 (revert,
3048 [('r', 'rev', '', _('revision to revert to')),
3054 [('r', 'rev', '', _('revision to revert to')),
3049 ('', 'no-backup', None, _('do not save backup copies of files')),
3055 ('', 'no-backup', None, _('do not save backup copies of files')),
3050 ('I', 'include', [], _('include names matching given patterns')),
3056 ('I', 'include', [], _('include names matching given patterns')),
3051 ('X', 'exclude', [], _('exclude names matching given patterns'))],
3057 ('X', 'exclude', [], _('exclude names matching given patterns'))],
3052 _('hg revert [-r REV] [NAME]...')),
3058 _('hg revert [-r REV] [NAME]...')),
3053 "rollback": (rollback, [], _('hg rollback')),
3059 "rollback": (rollback, [], _('hg rollback')),
3054 "root": (root, [], _('hg root')),
3060 "root": (root, [], _('hg root')),
3055 "^serve":
3061 "^serve":
3056 (serve,
3062 (serve,
3057 [('A', 'accesslog', '', _('name of access log file to write to')),
3063 [('A', 'accesslog', '', _('name of access log file to write to')),
3058 ('d', 'daemon', None, _('run server in background')),
3064 ('d', 'daemon', None, _('run server in background')),
3059 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3065 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3060 ('E', 'errorlog', '', _('name of error log file to write to')),
3066 ('E', 'errorlog', '', _('name of error log file to write to')),
3061 ('p', 'port', 0, _('port to use (default: 8000)')),
3067 ('p', 'port', 0, _('port to use (default: 8000)')),
3062 ('a', 'address', '', _('address to use')),
3068 ('a', 'address', '', _('address to use')),
3063 ('n', 'name', '',
3069 ('n', 'name', '',
3064 _('name to show in web pages (default: working dir)')),
3070 _('name to show in web pages (default: working dir)')),
3065 ('', 'webdir-conf', '', _('name of the webdir config file'
3071 ('', 'webdir-conf', '', _('name of the webdir config file'
3066 ' (serve more than one repo)')),
3072 ' (serve more than one repo)')),
3067 ('', 'pid-file', '', _('name of file to write process ID to')),
3073 ('', 'pid-file', '', _('name of file to write process ID to')),
3068 ('', 'stdio', None, _('for remote clients')),
3074 ('', 'stdio', None, _('for remote clients')),
3069 ('t', 'templates', '', _('web templates to use')),
3075 ('t', 'templates', '', _('web templates to use')),
3070 ('', 'style', '', _('template style to use')),
3076 ('', 'style', '', _('template style to use')),
3071 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
3077 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
3072 _('hg serve [OPTION]...')),
3078 _('hg serve [OPTION]...')),
3073 "^status|st":
3079 "^status|st":
3074 (status,
3080 (status,
3075 [('m', 'modified', None, _('show only modified files')),
3081 [('m', 'modified', None, _('show only modified files')),
3076 ('a', 'added', None, _('show only added files')),
3082 ('a', 'added', None, _('show only added files')),
3077 ('r', 'removed', None, _('show only removed files')),
3083 ('r', 'removed', None, _('show only removed files')),
3078 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3084 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3079 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3085 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3080 ('i', 'ignored', None, _('show ignored files')),
3086 ('i', 'ignored', None, _('show ignored files')),
3081 ('n', 'no-status', None, _('hide status prefix')),
3087 ('n', 'no-status', None, _('hide status prefix')),
3082 ('0', 'print0', None,
3088 ('0', 'print0', None,
3083 _('end filenames with NUL, for use with xargs')),
3089 _('end filenames with NUL, for use with xargs')),
3084 ('I', 'include', [], _('include names matching the given patterns')),
3090 ('I', 'include', [], _('include names matching the given patterns')),
3085 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3091 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3086 _('hg status [OPTION]... [FILE]...')),
3092 _('hg status [OPTION]... [FILE]...')),
3087 "tag":
3093 "tag":
3088 (tag,
3094 (tag,
3089 [('l', 'local', None, _('make the tag local')),
3095 [('l', 'local', None, _('make the tag local')),
3090 ('m', 'message', '', _('message for tag commit log entry')),
3096 ('m', 'message', '', _('message for tag commit log entry')),
3091 ('d', 'date', '', _('record datecode as commit date')),
3097 ('d', 'date', '', _('record datecode as commit date')),
3092 ('u', 'user', '', _('record user as commiter')),
3098 ('u', 'user', '', _('record user as commiter')),
3093 ('r', 'rev', '', _('revision to tag'))],
3099 ('r', 'rev', '', _('revision to tag'))],
3094 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3100 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3095 "tags": (tags, [], _('hg tags')),
3101 "tags": (tags, [], _('hg tags')),
3096 "tip":
3102 "tip":
3097 (tip,
3103 (tip,
3098 [('b', 'branches', None, _('show branches')),
3104 [('b', 'branches', None, _('show branches')),
3099 ('', 'style', '', _('display using template map file')),
3105 ('', 'style', '', _('display using template map file')),
3100 ('p', 'patch', None, _('show patch')),
3106 ('p', 'patch', None, _('show patch')),
3101 ('', 'template', '', _('display with template'))],
3107 ('', 'template', '', _('display with template'))],
3102 _('hg tip [-b] [-p]')),
3108 _('hg tip [-b] [-p]')),
3103 "unbundle":
3109 "unbundle":
3104 (unbundle,
3110 (unbundle,
3105 [('u', 'update', None,
3111 [('u', 'update', None,
3106 _('update the working directory to tip after unbundle'))],
3112 _('update the working directory to tip after unbundle'))],
3107 _('hg unbundle [-u] FILE')),
3113 _('hg unbundle [-u] FILE')),
3108 "debugundo|undo": (undo, [], _('hg undo')),
3114 "debugundo|undo": (undo, [], _('hg undo')),
3109 "^update|up|checkout|co":
3115 "^update|up|checkout|co":
3110 (update,
3116 (update,
3111 [('b', 'branch', '', _('checkout the head of a specific branch')),
3117 [('b', 'branch', '', _('checkout the head of a specific branch')),
3112 ('m', 'merge', None, _('allow merging of branches')),
3118 ('m', 'merge', None, _('allow merging of branches')),
3113 ('C', 'clean', None, _('overwrite locally modified files')),
3119 ('C', 'clean', None, _('overwrite locally modified files')),
3114 ('f', 'force', None, _('force a merge with outstanding changes'))],
3120 ('f', 'force', None, _('force a merge with outstanding changes'))],
3115 _('hg update [-b TAG] [-m] [-C] [-f] [REV]')),
3121 _('hg update [-b TAG] [-m] [-C] [-f] [REV]')),
3116 "verify": (verify, [], _('hg verify')),
3122 "verify": (verify, [], _('hg verify')),
3117 "version": (show_version, [], _('hg version')),
3123 "version": (show_version, [], _('hg version')),
3118 }
3124 }
3119
3125
3120 globalopts = [
3126 globalopts = [
3121 ('R', 'repository', '',
3127 ('R', 'repository', '',
3122 _('repository root directory or symbolic path name')),
3128 _('repository root directory or symbolic path name')),
3123 ('', 'cwd', '', _('change working directory')),
3129 ('', 'cwd', '', _('change working directory')),
3124 ('y', 'noninteractive', None,
3130 ('y', 'noninteractive', None,
3125 _('do not prompt, assume \'yes\' for any required answers')),
3131 _('do not prompt, assume \'yes\' for any required answers')),
3126 ('q', 'quiet', None, _('suppress output')),
3132 ('q', 'quiet', None, _('suppress output')),
3127 ('v', 'verbose', None, _('enable additional output')),
3133 ('v', 'verbose', None, _('enable additional output')),
3128 ('', 'debug', None, _('enable debugging output')),
3134 ('', 'debug', None, _('enable debugging output')),
3129 ('', 'debugger', None, _('start debugger')),
3135 ('', 'debugger', None, _('start debugger')),
3130 ('', 'traceback', None, _('print traceback on exception')),
3136 ('', 'traceback', None, _('print traceback on exception')),
3131 ('', 'time', None, _('time how long the command takes')),
3137 ('', 'time', None, _('time how long the command takes')),
3132 ('', 'profile', None, _('print command execution profile')),
3138 ('', 'profile', None, _('print command execution profile')),
3133 ('', 'version', None, _('output version information and exit')),
3139 ('', 'version', None, _('output version information and exit')),
3134 ('h', 'help', None, _('display help and exit')),
3140 ('h', 'help', None, _('display help and exit')),
3135 ]
3141 ]
3136
3142
3137 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3143 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3138 " debugindex debugindexdot")
3144 " debugindex debugindexdot")
3139 optionalrepo = ("paths serve debugconfig")
3145 optionalrepo = ("paths serve debugconfig")
3140
3146
3141 def findpossible(cmd):
3147 def findpossible(cmd):
3142 """
3148 """
3143 Return cmd -> (aliases, command table entry)
3149 Return cmd -> (aliases, command table entry)
3144 for each matching command.
3150 for each matching command.
3145 Return debug commands (or their aliases) only if no normal command matches.
3151 Return debug commands (or their aliases) only if no normal command matches.
3146 """
3152 """
3147 choice = {}
3153 choice = {}
3148 debugchoice = {}
3154 debugchoice = {}
3149 for e in table.keys():
3155 for e in table.keys():
3150 aliases = e.lstrip("^").split("|")
3156 aliases = e.lstrip("^").split("|")
3151 found = None
3157 found = None
3152 if cmd in aliases:
3158 if cmd in aliases:
3153 found = cmd
3159 found = cmd
3154 else:
3160 else:
3155 for a in aliases:
3161 for a in aliases:
3156 if a.startswith(cmd):
3162 if a.startswith(cmd):
3157 found = a
3163 found = a
3158 break
3164 break
3159 if found is not None:
3165 if found is not None:
3160 if aliases[0].startswith("debug"):
3166 if aliases[0].startswith("debug"):
3161 debugchoice[found] = (aliases, table[e])
3167 debugchoice[found] = (aliases, table[e])
3162 else:
3168 else:
3163 choice[found] = (aliases, table[e])
3169 choice[found] = (aliases, table[e])
3164
3170
3165 if not choice and debugchoice:
3171 if not choice and debugchoice:
3166 choice = debugchoice
3172 choice = debugchoice
3167
3173
3168 return choice
3174 return choice
3169
3175
3170 def find(cmd):
3176 def find(cmd):
3171 """Return (aliases, command table entry) for command string."""
3177 """Return (aliases, command table entry) for command string."""
3172 choice = findpossible(cmd)
3178 choice = findpossible(cmd)
3173
3179
3174 if choice.has_key(cmd):
3180 if choice.has_key(cmd):
3175 return choice[cmd]
3181 return choice[cmd]
3176
3182
3177 if len(choice) > 1:
3183 if len(choice) > 1:
3178 clist = choice.keys()
3184 clist = choice.keys()
3179 clist.sort()
3185 clist.sort()
3180 raise AmbiguousCommand(cmd, clist)
3186 raise AmbiguousCommand(cmd, clist)
3181
3187
3182 if choice:
3188 if choice:
3183 return choice.values()[0]
3189 return choice.values()[0]
3184
3190
3185 raise UnknownCommand(cmd)
3191 raise UnknownCommand(cmd)
3186
3192
3187 def catchterm(*args):
3193 def catchterm(*args):
3188 raise util.SignalInterrupt
3194 raise util.SignalInterrupt
3189
3195
3190 def run():
3196 def run():
3191 sys.exit(dispatch(sys.argv[1:]))
3197 sys.exit(dispatch(sys.argv[1:]))
3192
3198
3193 class ParseError(Exception):
3199 class ParseError(Exception):
3194 """Exception raised on errors in parsing the command line."""
3200 """Exception raised on errors in parsing the command line."""
3195
3201
3196 def parse(ui, args):
3202 def parse(ui, args):
3197 options = {}
3203 options = {}
3198 cmdoptions = {}
3204 cmdoptions = {}
3199
3205
3200 try:
3206 try:
3201 args = fancyopts.fancyopts(args, globalopts, options)
3207 args = fancyopts.fancyopts(args, globalopts, options)
3202 except fancyopts.getopt.GetoptError, inst:
3208 except fancyopts.getopt.GetoptError, inst:
3203 raise ParseError(None, inst)
3209 raise ParseError(None, inst)
3204
3210
3205 if args:
3211 if args:
3206 cmd, args = args[0], args[1:]
3212 cmd, args = args[0], args[1:]
3207 aliases, i = find(cmd)
3213 aliases, i = find(cmd)
3208 cmd = aliases[0]
3214 cmd = aliases[0]
3209 defaults = ui.config("defaults", cmd)
3215 defaults = ui.config("defaults", cmd)
3210 if defaults:
3216 if defaults:
3211 args = defaults.split() + args
3217 args = defaults.split() + args
3212 c = list(i[1])
3218 c = list(i[1])
3213 else:
3219 else:
3214 cmd = None
3220 cmd = None
3215 c = []
3221 c = []
3216
3222
3217 # combine global options into local
3223 # combine global options into local
3218 for o in globalopts:
3224 for o in globalopts:
3219 c.append((o[0], o[1], options[o[1]], o[3]))
3225 c.append((o[0], o[1], options[o[1]], o[3]))
3220
3226
3221 try:
3227 try:
3222 args = fancyopts.fancyopts(args, c, cmdoptions)
3228 args = fancyopts.fancyopts(args, c, cmdoptions)
3223 except fancyopts.getopt.GetoptError, inst:
3229 except fancyopts.getopt.GetoptError, inst:
3224 raise ParseError(cmd, inst)
3230 raise ParseError(cmd, inst)
3225
3231
3226 # separate global options back out
3232 # separate global options back out
3227 for o in globalopts:
3233 for o in globalopts:
3228 n = o[1]
3234 n = o[1]
3229 options[n] = cmdoptions[n]
3235 options[n] = cmdoptions[n]
3230 del cmdoptions[n]
3236 del cmdoptions[n]
3231
3237
3232 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3238 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3233
3239
3234 def dispatch(args):
3240 def dispatch(args):
3235 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3241 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3236 num = getattr(signal, name, None)
3242 num = getattr(signal, name, None)
3237 if num: signal.signal(num, catchterm)
3243 if num: signal.signal(num, catchterm)
3238
3244
3239 try:
3245 try:
3240 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3246 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3241 except util.Abort, inst:
3247 except util.Abort, inst:
3242 sys.stderr.write(_("abort: %s\n") % inst)
3248 sys.stderr.write(_("abort: %s\n") % inst)
3243 return -1
3249 return -1
3244
3250
3245 external = []
3251 external = []
3246 for x in u.extensions():
3252 for x in u.extensions():
3247 try:
3253 try:
3248 if x[1]:
3254 if x[1]:
3249 mod = imp.load_source(x[0], x[1])
3255 mod = imp.load_source(x[0], x[1])
3250 else:
3256 else:
3251 def importh(name):
3257 def importh(name):
3252 mod = __import__(name)
3258 mod = __import__(name)
3253 components = name.split('.')
3259 components = name.split('.')
3254 for comp in components[1:]:
3260 for comp in components[1:]:
3255 mod = getattr(mod, comp)
3261 mod = getattr(mod, comp)
3256 return mod
3262 return mod
3257 try:
3263 try:
3258 mod = importh("hgext." + x[0])
3264 mod = importh("hgext." + x[0])
3259 except ImportError:
3265 except ImportError:
3260 mod = importh(x[0])
3266 mod = importh(x[0])
3261 external.append(mod)
3267 external.append(mod)
3262 except Exception, inst:
3268 except Exception, inst:
3263 u.warn(_("*** failed to import extension %s: %s\n") % (x[0], inst))
3269 u.warn(_("*** failed to import extension %s: %s\n") % (x[0], inst))
3264 if u.traceback:
3270 if u.traceback:
3265 traceback.print_exc()
3271 traceback.print_exc()
3266 return 1
3272 return 1
3267 continue
3273 continue
3268
3274
3269 for x in external:
3275 for x in external:
3270 cmdtable = getattr(x, 'cmdtable', {})
3276 cmdtable = getattr(x, 'cmdtable', {})
3271 for t in cmdtable:
3277 for t in cmdtable:
3272 if t in table:
3278 if t in table:
3273 u.warn(_("module %s overrides %s\n") % (x.__name__, t))
3279 u.warn(_("module %s overrides %s\n") % (x.__name__, t))
3274 table.update(cmdtable)
3280 table.update(cmdtable)
3275
3281
3276 try:
3282 try:
3277 cmd, func, args, options, cmdoptions = parse(u, args)
3283 cmd, func, args, options, cmdoptions = parse(u, args)
3278 if options["time"]:
3284 if options["time"]:
3279 def get_times():
3285 def get_times():
3280 t = os.times()
3286 t = os.times()
3281 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3287 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3282 t = (t[0], t[1], t[2], t[3], time.clock())
3288 t = (t[0], t[1], t[2], t[3], time.clock())
3283 return t
3289 return t
3284 s = get_times()
3290 s = get_times()
3285 def print_time():
3291 def print_time():
3286 t = get_times()
3292 t = get_times()
3287 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3293 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3288 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3294 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3289 atexit.register(print_time)
3295 atexit.register(print_time)
3290
3296
3291 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3297 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3292 not options["noninteractive"], options["traceback"])
3298 not options["noninteractive"], options["traceback"])
3293
3299
3294 # enter the debugger before command execution
3300 # enter the debugger before command execution
3295 if options['debugger']:
3301 if options['debugger']:
3296 pdb.set_trace()
3302 pdb.set_trace()
3297
3303
3298 try:
3304 try:
3299 if options['cwd']:
3305 if options['cwd']:
3300 try:
3306 try:
3301 os.chdir(options['cwd'])
3307 os.chdir(options['cwd'])
3302 except OSError, inst:
3308 except OSError, inst:
3303 raise util.Abort('%s: %s' %
3309 raise util.Abort('%s: %s' %
3304 (options['cwd'], inst.strerror))
3310 (options['cwd'], inst.strerror))
3305
3311
3306 path = u.expandpath(options["repository"]) or ""
3312 path = u.expandpath(options["repository"]) or ""
3307 repo = path and hg.repository(u, path=path) or None
3313 repo = path and hg.repository(u, path=path) or None
3308
3314
3309 if options['help']:
3315 if options['help']:
3310 return help_(u, cmd, options['version'])
3316 return help_(u, cmd, options['version'])
3311 elif options['version']:
3317 elif options['version']:
3312 return show_version(u)
3318 return show_version(u)
3313 elif not cmd:
3319 elif not cmd:
3314 return help_(u, 'shortlist')
3320 return help_(u, 'shortlist')
3315
3321
3316 if cmd not in norepo.split():
3322 if cmd not in norepo.split():
3317 try:
3323 try:
3318 if not repo:
3324 if not repo:
3319 repo = hg.repository(u, path=path)
3325 repo = hg.repository(u, path=path)
3320 u = repo.ui
3326 u = repo.ui
3321 for x in external:
3327 for x in external:
3322 if hasattr(x, 'reposetup'):
3328 if hasattr(x, 'reposetup'):
3323 x.reposetup(u, repo)
3329 x.reposetup(u, repo)
3324 except hg.RepoError:
3330 except hg.RepoError:
3325 if cmd not in optionalrepo.split():
3331 if cmd not in optionalrepo.split():
3326 raise
3332 raise
3327 d = lambda: func(u, repo, *args, **cmdoptions)
3333 d = lambda: func(u, repo, *args, **cmdoptions)
3328 else:
3334 else:
3329 d = lambda: func(u, *args, **cmdoptions)
3335 d = lambda: func(u, *args, **cmdoptions)
3330
3336
3331 try:
3337 try:
3332 if options['profile']:
3338 if options['profile']:
3333 import hotshot, hotshot.stats
3339 import hotshot, hotshot.stats
3334 prof = hotshot.Profile("hg.prof")
3340 prof = hotshot.Profile("hg.prof")
3335 try:
3341 try:
3336 try:
3342 try:
3337 return prof.runcall(d)
3343 return prof.runcall(d)
3338 except:
3344 except:
3339 try:
3345 try:
3340 u.warn(_('exception raised - generating '
3346 u.warn(_('exception raised - generating '
3341 'profile anyway\n'))
3347 'profile anyway\n'))
3342 except:
3348 except:
3343 pass
3349 pass
3344 raise
3350 raise
3345 finally:
3351 finally:
3346 prof.close()
3352 prof.close()
3347 stats = hotshot.stats.load("hg.prof")
3353 stats = hotshot.stats.load("hg.prof")
3348 stats.strip_dirs()
3354 stats.strip_dirs()
3349 stats.sort_stats('time', 'calls')
3355 stats.sort_stats('time', 'calls')
3350 stats.print_stats(40)
3356 stats.print_stats(40)
3351 else:
3357 else:
3352 return d()
3358 return d()
3353 finally:
3359 finally:
3354 u.flush()
3360 u.flush()
3355 except:
3361 except:
3356 # enter the debugger when we hit an exception
3362 # enter the debugger when we hit an exception
3357 if options['debugger']:
3363 if options['debugger']:
3358 pdb.post_mortem(sys.exc_info()[2])
3364 pdb.post_mortem(sys.exc_info()[2])
3359 if u.traceback:
3365 if u.traceback:
3360 traceback.print_exc()
3366 traceback.print_exc()
3361 raise
3367 raise
3362 except ParseError, inst:
3368 except ParseError, inst:
3363 if inst.args[0]:
3369 if inst.args[0]:
3364 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3370 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3365 help_(u, inst.args[0])
3371 help_(u, inst.args[0])
3366 else:
3372 else:
3367 u.warn(_("hg: %s\n") % inst.args[1])
3373 u.warn(_("hg: %s\n") % inst.args[1])
3368 help_(u, 'shortlist')
3374 help_(u, 'shortlist')
3369 except AmbiguousCommand, inst:
3375 except AmbiguousCommand, inst:
3370 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3376 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3371 (inst.args[0], " ".join(inst.args[1])))
3377 (inst.args[0], " ".join(inst.args[1])))
3372 except UnknownCommand, inst:
3378 except UnknownCommand, inst:
3373 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3379 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3374 help_(u, 'shortlist')
3380 help_(u, 'shortlist')
3375 except hg.RepoError, inst:
3381 except hg.RepoError, inst:
3376 u.warn(_("abort: %s!\n") % inst)
3382 u.warn(_("abort: %s!\n") % inst)
3377 except lock.LockHeld, inst:
3383 except lock.LockHeld, inst:
3378 if inst.errno == errno.ETIMEDOUT:
3384 if inst.errno == errno.ETIMEDOUT:
3379 reason = _('timed out waiting for lock held by %s') % inst.locker
3385 reason = _('timed out waiting for lock held by %s') % inst.locker
3380 else:
3386 else:
3381 reason = _('lock held by %s') % inst.locker
3387 reason = _('lock held by %s') % inst.locker
3382 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3388 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3383 except lock.LockUnavailable, inst:
3389 except lock.LockUnavailable, inst:
3384 u.warn(_("abort: could not lock %s: %s\n") %
3390 u.warn(_("abort: could not lock %s: %s\n") %
3385 (inst.desc or inst.filename, inst.strerror))
3391 (inst.desc or inst.filename, inst.strerror))
3386 except revlog.RevlogError, inst:
3392 except revlog.RevlogError, inst:
3387 u.warn(_("abort: "), inst, "!\n")
3393 u.warn(_("abort: "), inst, "!\n")
3388 except util.SignalInterrupt:
3394 except util.SignalInterrupt:
3389 u.warn(_("killed!\n"))
3395 u.warn(_("killed!\n"))
3390 except KeyboardInterrupt:
3396 except KeyboardInterrupt:
3391 try:
3397 try:
3392 u.warn(_("interrupted!\n"))
3398 u.warn(_("interrupted!\n"))
3393 except IOError, inst:
3399 except IOError, inst:
3394 if inst.errno == errno.EPIPE:
3400 if inst.errno == errno.EPIPE:
3395 if u.debugflag:
3401 if u.debugflag:
3396 u.warn(_("\nbroken pipe\n"))
3402 u.warn(_("\nbroken pipe\n"))
3397 else:
3403 else:
3398 raise
3404 raise
3399 except IOError, inst:
3405 except IOError, inst:
3400 if hasattr(inst, "code"):
3406 if hasattr(inst, "code"):
3401 u.warn(_("abort: %s\n") % inst)
3407 u.warn(_("abort: %s\n") % inst)
3402 elif hasattr(inst, "reason"):
3408 elif hasattr(inst, "reason"):
3403 u.warn(_("abort: error: %s\n") % inst.reason[1])
3409 u.warn(_("abort: error: %s\n") % inst.reason[1])
3404 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3410 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3405 if u.debugflag:
3411 if u.debugflag:
3406 u.warn(_("broken pipe\n"))
3412 u.warn(_("broken pipe\n"))
3407 elif getattr(inst, "strerror", None):
3413 elif getattr(inst, "strerror", None):
3408 if getattr(inst, "filename", None):
3414 if getattr(inst, "filename", None):
3409 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
3415 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
3410 else:
3416 else:
3411 u.warn(_("abort: %s\n") % inst.strerror)
3417 u.warn(_("abort: %s\n") % inst.strerror)
3412 else:
3418 else:
3413 raise
3419 raise
3414 except OSError, inst:
3420 except OSError, inst:
3415 if hasattr(inst, "filename"):
3421 if hasattr(inst, "filename"):
3416 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3422 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3417 else:
3423 else:
3418 u.warn(_("abort: %s\n") % inst.strerror)
3424 u.warn(_("abort: %s\n") % inst.strerror)
3419 except util.Abort, inst:
3425 except util.Abort, inst:
3420 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
3426 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
3421 except TypeError, inst:
3427 except TypeError, inst:
3422 # was this an argument error?
3428 # was this an argument error?
3423 tb = traceback.extract_tb(sys.exc_info()[2])
3429 tb = traceback.extract_tb(sys.exc_info()[2])
3424 if len(tb) > 2: # no
3430 if len(tb) > 2: # no
3425 raise
3431 raise
3426 u.debug(inst, "\n")
3432 u.debug(inst, "\n")
3427 u.warn(_("%s: invalid arguments\n") % cmd)
3433 u.warn(_("%s: invalid arguments\n") % cmd)
3428 help_(u, cmd)
3434 help_(u, cmd)
3429 except SystemExit, inst:
3435 except SystemExit, inst:
3430 # Commands shouldn't sys.exit directly, but give a return code.
3436 # Commands shouldn't sys.exit directly, but give a return code.
3431 # Just in case catch this and and pass exit code to caller.
3437 # Just in case catch this and and pass exit code to caller.
3432 return inst.code
3438 return inst.code
3433 except:
3439 except:
3434 u.warn(_("** unknown exception encountered, details follow\n"))
3440 u.warn(_("** unknown exception encountered, details follow\n"))
3435 u.warn(_("** report bug details to mercurial@selenic.com\n"))
3441 u.warn(_("** report bug details to mercurial@selenic.com\n"))
3436 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3442 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3437 % version.get_version())
3443 % version.get_version())
3438 raise
3444 raise
3439
3445
3440 return -1
3446 return -1
@@ -1,71 +1,83 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 hg init
3 hg init
4 echo 123 > a
4 echo 123 > a
5 echo 123 > c
5 echo 123 > c
6 echo 123 > e
6 echo 123 > e
7 hg add a c e
7 hg add a c e
8 hg commit -m "first" -d "1000000 0" a c e
8 hg commit -m "first" -d "1000000 0" a c e
9 echo 123 > b
9 echo 123 > b
10 echo %% should show b unknown
10 echo %% should show b unknown
11 hg status
11 hg status
12 echo 12 > c
12 echo 12 > c
13 echo %% should show b unknown and c modified
13 echo %% should show b unknown and c modified
14 hg status
14 hg status
15 hg add b
15 hg add b
16 echo %% should show b added and c modified
16 echo %% should show b added and c modified
17 hg status
17 hg status
18 hg rm a
18 hg rm a
19 echo %% should show a removed, b added and c modified
19 echo %% should show a removed, b added and c modified
20 hg status
20 hg status
21 hg revert a
21 hg revert a
22 echo %% should show b added, copy saved, and c modified
22 echo %% should show b added, copy saved, and c modified
23 hg status
23 hg status
24 hg revert b
24 hg revert b
25 echo %% should show b unknown, and c modified
25 echo %% should show b unknown, and c modified
26 hg status
26 hg status
27 hg revert --no-backup c
27 hg revert --no-backup c
28 echo %% should show unknown: b
28 echo %% should show unknown: b
29 hg status
29 hg status
30 echo %% should show a b c e
30 echo %% should show a b c e
31 ls
31 ls
32 echo %% should verbosely save backup to e.orig
32 echo %% should verbosely save backup to e.orig
33 echo z > e
33 echo z > e
34 hg revert -v
34 hg revert -v
35 echo %% should say no changes needed
35 echo %% should say no changes needed
36 hg revert a
36 hg revert a
37 echo %% should say file not managed
37 echo %% should say file not managed
38 echo q > q
38 echo q > q
39 hg revert q
39 hg revert q
40 rm q
40 rm q
41 echo %% should say file not found
41 echo %% should say file not found
42 hg revert notfound
42 hg revert notfound
43 hg rm a
43 hg rm a
44 hg commit -m "second" -d "1000000 0"
44 hg commit -m "second" -d "1000000 0"
45 echo z > z
45 echo z > z
46 hg add z
46 hg add z
47 hg st
47 hg st
48 echo %% should add a, forget z
48 echo %% should add a, forget z
49 hg revert -r0
49 hg revert -r0
50 echo %% should forget a
50 echo %% should forget a
51 hg revert -rtip
51 hg revert -rtip
52 rm -f a *.orig
52 rm -f a *.orig
53 echo %% should silently add a
53 echo %% should silently add a
54 hg revert -r0 a
54 hg revert -r0 a
55 hg st a
55 hg st a
56
56
57 hg update -C
57 hg update -C
58 chmod +x c
58 chmod +x c
59 hg revert
59 hg revert
60 echo %% should print non-executable
60 echo %% should print non-executable
61 test -x c || echo non-executable
61 test -x c || echo non-executable
62
62
63 chmod +x c
63 chmod +x c
64 hg commit -d '1000001 0' -m exe
64 hg commit -d '1000001 0' -m exe
65
65
66 chmod -x c
66 chmod -x c
67 hg revert
67 hg revert
68 echo %% should print executable
68 echo %% should print executable
69 test -x c && echo executable
69 test -x c && echo executable
70
70
71 echo %% issue 241
72 hg init a
73 cd a
74 echo a >> a
75 hg commit -A -d '1 0' -m a
76 echo a >> a
77 hg commit -d '2 0' -m a
78 hg update 0
79 mkdir b
80 echo b > b/b
81 hg revert -rtip
82
71 true
83 true
@@ -1,53 +1,56 b''
1 %% should show b unknown
1 %% should show b unknown
2 ? b
2 ? b
3 %% should show b unknown and c modified
3 %% should show b unknown and c modified
4 M c
4 M c
5 ? b
5 ? b
6 %% should show b added and c modified
6 %% should show b added and c modified
7 M c
7 M c
8 A b
8 A b
9 %% should show a removed, b added and c modified
9 %% should show a removed, b added and c modified
10 M c
10 M c
11 A b
11 A b
12 R a
12 R a
13 %% should show b added, copy saved, and c modified
13 %% should show b added, copy saved, and c modified
14 M c
14 M c
15 A b
15 A b
16 %% should show b unknown, and c modified
16 %% should show b unknown, and c modified
17 M c
17 M c
18 ? b
18 ? b
19 %% should show unknown: b
19 %% should show unknown: b
20 ? b
20 ? b
21 %% should show a b c e
21 %% should show a b c e
22 a
22 a
23 b
23 b
24 c
24 c
25 e
25 e
26 %% should verbosely save backup to e.orig
26 %% should verbosely save backup to e.orig
27 saving current version of e as e.orig
27 saving current version of e as e.orig
28 reverting e
28 reverting e
29 resolving manifests
29 resolving manifests
30 getting e
30 getting e
31 %% should say no changes needed
31 %% should say no changes needed
32 no changes needed to a
32 no changes needed to a
33 %% should say file not managed
33 %% should say file not managed
34 file not managed: q
34 file not managed: q
35 %% should say file not found
35 %% should say file not found
36 notfound: No such file in rev 095eacd0c0d7
36 notfound: No such file in rev 095eacd0c0d7
37 A z
37 A z
38 ? b
38 ? b
39 ? e.orig
39 ? e.orig
40 %% should add a, forget z
40 %% should add a, forget z
41 adding a
41 adding a
42 forgetting z
42 forgetting z
43 %% should forget a
43 %% should forget a
44 forgetting a
44 forgetting a
45 %% should silently add a
45 %% should silently add a
46 A a
46 A a
47 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
47 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
48 reverting c
48 reverting c
49 %% should print non-executable
49 %% should print non-executable
50 non-executable
50 non-executable
51 reverting c
51 reverting c
52 %% should print executable
52 %% should print executable
53 executable
53 executable
54 %% issue 241
55 adding a
56 1 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