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