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