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