##// END OF EJS Templates
revset aliases
Alexander Solovyov -
r14098:9f5a0acb default
parent child Browse files
Show More
@@ -1,1398 +1,1398
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, nullid, nullrev, short
8 from node import hex, nullid, nullrev, short
9 from i18n import _
9 from i18n import _
10 import os, sys, errno, re, glob, tempfile
10 import os, sys, errno, re, glob, tempfile
11 import util, scmutil, templater, patch, error, templatekw
11 import util, scmutil, templater, patch, error, templatekw
12 import match as matchmod
12 import match as matchmod
13 import similar, revset, subrepo
13 import similar, revset, subrepo
14
14
15 revrangesep = ':'
15 revrangesep = ':'
16
16
17 def parsealiases(cmd):
17 def parsealiases(cmd):
18 return cmd.lstrip("^").split("|")
18 return cmd.lstrip("^").split("|")
19
19
20 def findpossible(cmd, table, strict=False):
20 def findpossible(cmd, table, strict=False):
21 """
21 """
22 Return cmd -> (aliases, command table entry)
22 Return cmd -> (aliases, command table entry)
23 for each matching command.
23 for each matching command.
24 Return debug commands (or their aliases) only if no normal command matches.
24 Return debug commands (or their aliases) only if no normal command matches.
25 """
25 """
26 choice = {}
26 choice = {}
27 debugchoice = {}
27 debugchoice = {}
28 for e in table.keys():
28 for e in table.keys():
29 aliases = parsealiases(e)
29 aliases = parsealiases(e)
30 found = None
30 found = None
31 if cmd in aliases:
31 if cmd in aliases:
32 found = cmd
32 found = cmd
33 elif not strict:
33 elif not strict:
34 for a in aliases:
34 for a in aliases:
35 if a.startswith(cmd):
35 if a.startswith(cmd):
36 found = a
36 found = a
37 break
37 break
38 if found is not None:
38 if found is not None:
39 if aliases[0].startswith("debug") or found.startswith("debug"):
39 if aliases[0].startswith("debug") or found.startswith("debug"):
40 debugchoice[found] = (aliases, table[e])
40 debugchoice[found] = (aliases, table[e])
41 else:
41 else:
42 choice[found] = (aliases, table[e])
42 choice[found] = (aliases, table[e])
43
43
44 if not choice and debugchoice:
44 if not choice and debugchoice:
45 choice = debugchoice
45 choice = debugchoice
46
46
47 return choice
47 return choice
48
48
49 def findcmd(cmd, table, strict=True):
49 def findcmd(cmd, table, strict=True):
50 """Return (aliases, command table entry) for command string."""
50 """Return (aliases, command table entry) for command string."""
51 choice = findpossible(cmd, table, strict)
51 choice = findpossible(cmd, table, strict)
52
52
53 if cmd in choice:
53 if cmd in choice:
54 return choice[cmd]
54 return choice[cmd]
55
55
56 if len(choice) > 1:
56 if len(choice) > 1:
57 clist = choice.keys()
57 clist = choice.keys()
58 clist.sort()
58 clist.sort()
59 raise error.AmbiguousCommand(cmd, clist)
59 raise error.AmbiguousCommand(cmd, clist)
60
60
61 if choice:
61 if choice:
62 return choice.values()[0]
62 return choice.values()[0]
63
63
64 raise error.UnknownCommand(cmd)
64 raise error.UnknownCommand(cmd)
65
65
66 def findrepo(p):
66 def findrepo(p):
67 while not os.path.isdir(os.path.join(p, ".hg")):
67 while not os.path.isdir(os.path.join(p, ".hg")):
68 oldp, p = p, os.path.dirname(p)
68 oldp, p = p, os.path.dirname(p)
69 if p == oldp:
69 if p == oldp:
70 return None
70 return None
71
71
72 return p
72 return p
73
73
74 def bail_if_changed(repo):
74 def bail_if_changed(repo):
75 if repo.dirstate.p2() != nullid:
75 if repo.dirstate.p2() != nullid:
76 raise util.Abort(_('outstanding uncommitted merge'))
76 raise util.Abort(_('outstanding uncommitted merge'))
77 modified, added, removed, deleted = repo.status()[:4]
77 modified, added, removed, deleted = repo.status()[:4]
78 if modified or added or removed or deleted:
78 if modified or added or removed or deleted:
79 raise util.Abort(_("outstanding uncommitted changes"))
79 raise util.Abort(_("outstanding uncommitted changes"))
80
80
81 def logmessage(opts):
81 def logmessage(opts):
82 """ get the log message according to -m and -l option """
82 """ get the log message according to -m and -l option """
83 message = opts.get('message')
83 message = opts.get('message')
84 logfile = opts.get('logfile')
84 logfile = opts.get('logfile')
85
85
86 if message and logfile:
86 if message and logfile:
87 raise util.Abort(_('options --message and --logfile are mutually '
87 raise util.Abort(_('options --message and --logfile are mutually '
88 'exclusive'))
88 'exclusive'))
89 if not message and logfile:
89 if not message and logfile:
90 try:
90 try:
91 if logfile == '-':
91 if logfile == '-':
92 message = sys.stdin.read()
92 message = sys.stdin.read()
93 else:
93 else:
94 message = open(logfile).read()
94 message = open(logfile).read()
95 except IOError, inst:
95 except IOError, inst:
96 raise util.Abort(_("can't read commit message '%s': %s") %
96 raise util.Abort(_("can't read commit message '%s': %s") %
97 (logfile, inst.strerror))
97 (logfile, inst.strerror))
98 return message
98 return message
99
99
100 def loglimit(opts):
100 def loglimit(opts):
101 """get the log limit according to option -l/--limit"""
101 """get the log limit according to option -l/--limit"""
102 limit = opts.get('limit')
102 limit = opts.get('limit')
103 if limit:
103 if limit:
104 try:
104 try:
105 limit = int(limit)
105 limit = int(limit)
106 except ValueError:
106 except ValueError:
107 raise util.Abort(_('limit must be a positive integer'))
107 raise util.Abort(_('limit must be a positive integer'))
108 if limit <= 0:
108 if limit <= 0:
109 raise util.Abort(_('limit must be positive'))
109 raise util.Abort(_('limit must be positive'))
110 else:
110 else:
111 limit = None
111 limit = None
112 return limit
112 return limit
113
113
114 def revsingle(repo, revspec, default='.'):
114 def revsingle(repo, revspec, default='.'):
115 if not revspec:
115 if not revspec:
116 return repo[default]
116 return repo[default]
117
117
118 l = revrange(repo, [revspec])
118 l = revrange(repo, [revspec])
119 if len(l) < 1:
119 if len(l) < 1:
120 raise util.Abort(_('empty revision set'))
120 raise util.Abort(_('empty revision set'))
121 return repo[l[-1]]
121 return repo[l[-1]]
122
122
123 def revpair(repo, revs):
123 def revpair(repo, revs):
124 if not revs:
124 if not revs:
125 return repo.dirstate.p1(), None
125 return repo.dirstate.p1(), None
126
126
127 l = revrange(repo, revs)
127 l = revrange(repo, revs)
128
128
129 if len(l) == 0:
129 if len(l) == 0:
130 return repo.dirstate.p1(), None
130 return repo.dirstate.p1(), None
131
131
132 if len(l) == 1:
132 if len(l) == 1:
133 return repo.lookup(l[0]), None
133 return repo.lookup(l[0]), None
134
134
135 return repo.lookup(l[0]), repo.lookup(l[-1])
135 return repo.lookup(l[0]), repo.lookup(l[-1])
136
136
137 def revrange(repo, revs):
137 def revrange(repo, revs):
138 """Yield revision as strings from a list of revision specifications."""
138 """Yield revision as strings from a list of revision specifications."""
139
139
140 def revfix(repo, val, defval):
140 def revfix(repo, val, defval):
141 if not val and val != 0 and defval is not None:
141 if not val and val != 0 and defval is not None:
142 return defval
142 return defval
143 return repo.changelog.rev(repo.lookup(val))
143 return repo.changelog.rev(repo.lookup(val))
144
144
145 seen, l = set(), []
145 seen, l = set(), []
146 for spec in revs:
146 for spec in revs:
147 # attempt to parse old-style ranges first to deal with
147 # attempt to parse old-style ranges first to deal with
148 # things like old-tag which contain query metacharacters
148 # things like old-tag which contain query metacharacters
149 try:
149 try:
150 if isinstance(spec, int):
150 if isinstance(spec, int):
151 seen.add(spec)
151 seen.add(spec)
152 l.append(spec)
152 l.append(spec)
153 continue
153 continue
154
154
155 if revrangesep in spec:
155 if revrangesep in spec:
156 start, end = spec.split(revrangesep, 1)
156 start, end = spec.split(revrangesep, 1)
157 start = revfix(repo, start, 0)
157 start = revfix(repo, start, 0)
158 end = revfix(repo, end, len(repo) - 1)
158 end = revfix(repo, end, len(repo) - 1)
159 step = start > end and -1 or 1
159 step = start > end and -1 or 1
160 for rev in xrange(start, end + step, step):
160 for rev in xrange(start, end + step, step):
161 if rev in seen:
161 if rev in seen:
162 continue
162 continue
163 seen.add(rev)
163 seen.add(rev)
164 l.append(rev)
164 l.append(rev)
165 continue
165 continue
166 elif spec and spec in repo: # single unquoted rev
166 elif spec and spec in repo: # single unquoted rev
167 rev = revfix(repo, spec, None)
167 rev = revfix(repo, spec, None)
168 if rev in seen:
168 if rev in seen:
169 continue
169 continue
170 seen.add(rev)
170 seen.add(rev)
171 l.append(rev)
171 l.append(rev)
172 continue
172 continue
173 except error.RepoLookupError:
173 except error.RepoLookupError:
174 pass
174 pass
175
175
176 # fall through to new-style queries if old-style fails
176 # fall through to new-style queries if old-style fails
177 m = revset.match(spec)
177 m = revset.match(repo.ui, spec)
178 for r in m(repo, range(len(repo))):
178 for r in m(repo, range(len(repo))):
179 if r not in seen:
179 if r not in seen:
180 l.append(r)
180 l.append(r)
181 seen.update(l)
181 seen.update(l)
182
182
183 return l
183 return l
184
184
185 def make_filename(repo, pat, node,
185 def make_filename(repo, pat, node,
186 total=None, seqno=None, revwidth=None, pathname=None):
186 total=None, seqno=None, revwidth=None, pathname=None):
187 node_expander = {
187 node_expander = {
188 'H': lambda: hex(node),
188 'H': lambda: hex(node),
189 'R': lambda: str(repo.changelog.rev(node)),
189 'R': lambda: str(repo.changelog.rev(node)),
190 'h': lambda: short(node),
190 'h': lambda: short(node),
191 }
191 }
192 expander = {
192 expander = {
193 '%': lambda: '%',
193 '%': lambda: '%',
194 'b': lambda: os.path.basename(repo.root),
194 'b': lambda: os.path.basename(repo.root),
195 }
195 }
196
196
197 try:
197 try:
198 if node:
198 if node:
199 expander.update(node_expander)
199 expander.update(node_expander)
200 if node:
200 if node:
201 expander['r'] = (lambda:
201 expander['r'] = (lambda:
202 str(repo.changelog.rev(node)).zfill(revwidth or 0))
202 str(repo.changelog.rev(node)).zfill(revwidth or 0))
203 if total is not None:
203 if total is not None:
204 expander['N'] = lambda: str(total)
204 expander['N'] = lambda: str(total)
205 if seqno is not None:
205 if seqno is not None:
206 expander['n'] = lambda: str(seqno)
206 expander['n'] = lambda: str(seqno)
207 if total is not None and seqno is not None:
207 if total is not None and seqno is not None:
208 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
208 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
209 if pathname is not None:
209 if pathname is not None:
210 expander['s'] = lambda: os.path.basename(pathname)
210 expander['s'] = lambda: os.path.basename(pathname)
211 expander['d'] = lambda: os.path.dirname(pathname) or '.'
211 expander['d'] = lambda: os.path.dirname(pathname) or '.'
212 expander['p'] = lambda: pathname
212 expander['p'] = lambda: pathname
213
213
214 newname = []
214 newname = []
215 patlen = len(pat)
215 patlen = len(pat)
216 i = 0
216 i = 0
217 while i < patlen:
217 while i < patlen:
218 c = pat[i]
218 c = pat[i]
219 if c == '%':
219 if c == '%':
220 i += 1
220 i += 1
221 c = pat[i]
221 c = pat[i]
222 c = expander[c]()
222 c = expander[c]()
223 newname.append(c)
223 newname.append(c)
224 i += 1
224 i += 1
225 return ''.join(newname)
225 return ''.join(newname)
226 except KeyError, inst:
226 except KeyError, inst:
227 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
227 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
228 inst.args[0])
228 inst.args[0])
229
229
230 def make_file(repo, pat, node=None,
230 def make_file(repo, pat, node=None,
231 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
231 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
232
232
233 writable = mode not in ('r', 'rb')
233 writable = mode not in ('r', 'rb')
234
234
235 if not pat or pat == '-':
235 if not pat or pat == '-':
236 fp = writable and sys.stdout or sys.stdin
236 fp = writable and sys.stdout or sys.stdin
237 return os.fdopen(os.dup(fp.fileno()), mode)
237 return os.fdopen(os.dup(fp.fileno()), mode)
238 if hasattr(pat, 'write') and writable:
238 if hasattr(pat, 'write') and writable:
239 return pat
239 return pat
240 if hasattr(pat, 'read') and 'r' in mode:
240 if hasattr(pat, 'read') and 'r' in mode:
241 return pat
241 return pat
242 return open(make_filename(repo, pat, node, total, seqno, revwidth,
242 return open(make_filename(repo, pat, node, total, seqno, revwidth,
243 pathname),
243 pathname),
244 mode)
244 mode)
245
245
246 def expandpats(pats):
246 def expandpats(pats):
247 if not util.expandglobs:
247 if not util.expandglobs:
248 return list(pats)
248 return list(pats)
249 ret = []
249 ret = []
250 for p in pats:
250 for p in pats:
251 kind, name = matchmod._patsplit(p, None)
251 kind, name = matchmod._patsplit(p, None)
252 if kind is None:
252 if kind is None:
253 try:
253 try:
254 globbed = glob.glob(name)
254 globbed = glob.glob(name)
255 except re.error:
255 except re.error:
256 globbed = [name]
256 globbed = [name]
257 if globbed:
257 if globbed:
258 ret.extend(globbed)
258 ret.extend(globbed)
259 continue
259 continue
260 ret.append(p)
260 ret.append(p)
261 return ret
261 return ret
262
262
263 def match(repo, pats=[], opts={}, globbed=False, default='relpath'):
263 def match(repo, pats=[], opts={}, globbed=False, default='relpath'):
264 if pats == ("",):
264 if pats == ("",):
265 pats = []
265 pats = []
266 if not globbed and default == 'relpath':
266 if not globbed and default == 'relpath':
267 pats = expandpats(pats or [])
267 pats = expandpats(pats or [])
268 m = matchmod.match(repo.root, repo.getcwd(), pats,
268 m = matchmod.match(repo.root, repo.getcwd(), pats,
269 opts.get('include'), opts.get('exclude'), default,
269 opts.get('include'), opts.get('exclude'), default,
270 auditor=repo.auditor)
270 auditor=repo.auditor)
271 def badfn(f, msg):
271 def badfn(f, msg):
272 repo.ui.warn("%s: %s\n" % (m.rel(f), msg))
272 repo.ui.warn("%s: %s\n" % (m.rel(f), msg))
273 m.bad = badfn
273 m.bad = badfn
274 return m
274 return m
275
275
276 def matchall(repo):
276 def matchall(repo):
277 return matchmod.always(repo.root, repo.getcwd())
277 return matchmod.always(repo.root, repo.getcwd())
278
278
279 def matchfiles(repo, files):
279 def matchfiles(repo, files):
280 return matchmod.exact(repo.root, repo.getcwd(), files)
280 return matchmod.exact(repo.root, repo.getcwd(), files)
281
281
282 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
282 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
283 if dry_run is None:
283 if dry_run is None:
284 dry_run = opts.get('dry_run')
284 dry_run = opts.get('dry_run')
285 if similarity is None:
285 if similarity is None:
286 similarity = float(opts.get('similarity') or 0)
286 similarity = float(opts.get('similarity') or 0)
287 # we'd use status here, except handling of symlinks and ignore is tricky
287 # we'd use status here, except handling of symlinks and ignore is tricky
288 added, unknown, deleted, removed = [], [], [], []
288 added, unknown, deleted, removed = [], [], [], []
289 audit_path = scmutil.path_auditor(repo.root)
289 audit_path = scmutil.path_auditor(repo.root)
290 m = match(repo, pats, opts)
290 m = match(repo, pats, opts)
291 for abs in repo.walk(m):
291 for abs in repo.walk(m):
292 target = repo.wjoin(abs)
292 target = repo.wjoin(abs)
293 good = True
293 good = True
294 try:
294 try:
295 audit_path(abs)
295 audit_path(abs)
296 except (OSError, util.Abort):
296 except (OSError, util.Abort):
297 good = False
297 good = False
298 rel = m.rel(abs)
298 rel = m.rel(abs)
299 exact = m.exact(abs)
299 exact = m.exact(abs)
300 if good and abs not in repo.dirstate:
300 if good and abs not in repo.dirstate:
301 unknown.append(abs)
301 unknown.append(abs)
302 if repo.ui.verbose or not exact:
302 if repo.ui.verbose or not exact:
303 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
303 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
304 elif repo.dirstate[abs] != 'r' and (not good or not os.path.lexists(target)
304 elif repo.dirstate[abs] != 'r' and (not good or not os.path.lexists(target)
305 or (os.path.isdir(target) and not os.path.islink(target))):
305 or (os.path.isdir(target) and not os.path.islink(target))):
306 deleted.append(abs)
306 deleted.append(abs)
307 if repo.ui.verbose or not exact:
307 if repo.ui.verbose or not exact:
308 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
308 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
309 # for finding renames
309 # for finding renames
310 elif repo.dirstate[abs] == 'r':
310 elif repo.dirstate[abs] == 'r':
311 removed.append(abs)
311 removed.append(abs)
312 elif repo.dirstate[abs] == 'a':
312 elif repo.dirstate[abs] == 'a':
313 added.append(abs)
313 added.append(abs)
314 copies = {}
314 copies = {}
315 if similarity > 0:
315 if similarity > 0:
316 for old, new, score in similar.findrenames(repo,
316 for old, new, score in similar.findrenames(repo,
317 added + unknown, removed + deleted, similarity):
317 added + unknown, removed + deleted, similarity):
318 if repo.ui.verbose or not m.exact(old) or not m.exact(new):
318 if repo.ui.verbose or not m.exact(old) or not m.exact(new):
319 repo.ui.status(_('recording removal of %s as rename to %s '
319 repo.ui.status(_('recording removal of %s as rename to %s '
320 '(%d%% similar)\n') %
320 '(%d%% similar)\n') %
321 (m.rel(old), m.rel(new), score * 100))
321 (m.rel(old), m.rel(new), score * 100))
322 copies[new] = old
322 copies[new] = old
323
323
324 if not dry_run:
324 if not dry_run:
325 wctx = repo[None]
325 wctx = repo[None]
326 wlock = repo.wlock()
326 wlock = repo.wlock()
327 try:
327 try:
328 wctx.remove(deleted)
328 wctx.remove(deleted)
329 wctx.add(unknown)
329 wctx.add(unknown)
330 for new, old in copies.iteritems():
330 for new, old in copies.iteritems():
331 wctx.copy(old, new)
331 wctx.copy(old, new)
332 finally:
332 finally:
333 wlock.release()
333 wlock.release()
334
334
335 def updatedir(ui, repo, patches, similarity=0):
335 def updatedir(ui, repo, patches, similarity=0):
336 '''Update dirstate after patch application according to metadata'''
336 '''Update dirstate after patch application according to metadata'''
337 if not patches:
337 if not patches:
338 return
338 return
339 copies = []
339 copies = []
340 removes = set()
340 removes = set()
341 cfiles = patches.keys()
341 cfiles = patches.keys()
342 cwd = repo.getcwd()
342 cwd = repo.getcwd()
343 if cwd:
343 if cwd:
344 cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()]
344 cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()]
345 for f in patches:
345 for f in patches:
346 gp = patches[f]
346 gp = patches[f]
347 if not gp:
347 if not gp:
348 continue
348 continue
349 if gp.op == 'RENAME':
349 if gp.op == 'RENAME':
350 copies.append((gp.oldpath, gp.path))
350 copies.append((gp.oldpath, gp.path))
351 removes.add(gp.oldpath)
351 removes.add(gp.oldpath)
352 elif gp.op == 'COPY':
352 elif gp.op == 'COPY':
353 copies.append((gp.oldpath, gp.path))
353 copies.append((gp.oldpath, gp.path))
354 elif gp.op == 'DELETE':
354 elif gp.op == 'DELETE':
355 removes.add(gp.path)
355 removes.add(gp.path)
356
356
357 wctx = repo[None]
357 wctx = repo[None]
358 for src, dst in copies:
358 for src, dst in copies:
359 dirstatecopy(ui, repo, wctx, src, dst, cwd=cwd)
359 dirstatecopy(ui, repo, wctx, src, dst, cwd=cwd)
360 if (not similarity) and removes:
360 if (not similarity) and removes:
361 wctx.remove(sorted(removes), True)
361 wctx.remove(sorted(removes), True)
362
362
363 for f in patches:
363 for f in patches:
364 gp = patches[f]
364 gp = patches[f]
365 if gp and gp.mode:
365 if gp and gp.mode:
366 islink, isexec = gp.mode
366 islink, isexec = gp.mode
367 dst = repo.wjoin(gp.path)
367 dst = repo.wjoin(gp.path)
368 # patch won't create empty files
368 # patch won't create empty files
369 if gp.op == 'ADD' and not os.path.lexists(dst):
369 if gp.op == 'ADD' and not os.path.lexists(dst):
370 flags = (isexec and 'x' or '') + (islink and 'l' or '')
370 flags = (isexec and 'x' or '') + (islink and 'l' or '')
371 repo.wwrite(gp.path, '', flags)
371 repo.wwrite(gp.path, '', flags)
372 util.set_flags(dst, islink, isexec)
372 util.set_flags(dst, islink, isexec)
373 addremove(repo, cfiles, similarity=similarity)
373 addremove(repo, cfiles, similarity=similarity)
374 files = patches.keys()
374 files = patches.keys()
375 files.extend([r for r in removes if r not in files])
375 files.extend([r for r in removes if r not in files])
376 return sorted(files)
376 return sorted(files)
377
377
378 def dirstatecopy(ui, repo, wctx, src, dst, dryrun=False, cwd=None):
378 def dirstatecopy(ui, repo, wctx, src, dst, dryrun=False, cwd=None):
379 """Update the dirstate to reflect the intent of copying src to dst. For
379 """Update the dirstate to reflect the intent of copying src to dst. For
380 different reasons it might not end with dst being marked as copied from src.
380 different reasons it might not end with dst being marked as copied from src.
381 """
381 """
382 origsrc = repo.dirstate.copied(src) or src
382 origsrc = repo.dirstate.copied(src) or src
383 if dst == origsrc: # copying back a copy?
383 if dst == origsrc: # copying back a copy?
384 if repo.dirstate[dst] not in 'mn' and not dryrun:
384 if repo.dirstate[dst] not in 'mn' and not dryrun:
385 repo.dirstate.normallookup(dst)
385 repo.dirstate.normallookup(dst)
386 else:
386 else:
387 if repo.dirstate[origsrc] == 'a' and origsrc == src:
387 if repo.dirstate[origsrc] == 'a' and origsrc == src:
388 if not ui.quiet:
388 if not ui.quiet:
389 ui.warn(_("%s has not been committed yet, so no copy "
389 ui.warn(_("%s has not been committed yet, so no copy "
390 "data will be stored for %s.\n")
390 "data will be stored for %s.\n")
391 % (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd)))
391 % (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd)))
392 if repo.dirstate[dst] in '?r' and not dryrun:
392 if repo.dirstate[dst] in '?r' and not dryrun:
393 wctx.add([dst])
393 wctx.add([dst])
394 elif not dryrun:
394 elif not dryrun:
395 wctx.copy(origsrc, dst)
395 wctx.copy(origsrc, dst)
396
396
397 def copy(ui, repo, pats, opts, rename=False):
397 def copy(ui, repo, pats, opts, rename=False):
398 # called with the repo lock held
398 # called with the repo lock held
399 #
399 #
400 # hgsep => pathname that uses "/" to separate directories
400 # hgsep => pathname that uses "/" to separate directories
401 # ossep => pathname that uses os.sep to separate directories
401 # ossep => pathname that uses os.sep to separate directories
402 cwd = repo.getcwd()
402 cwd = repo.getcwd()
403 targets = {}
403 targets = {}
404 after = opts.get("after")
404 after = opts.get("after")
405 dryrun = opts.get("dry_run")
405 dryrun = opts.get("dry_run")
406 wctx = repo[None]
406 wctx = repo[None]
407
407
408 def walkpat(pat):
408 def walkpat(pat):
409 srcs = []
409 srcs = []
410 badstates = after and '?' or '?r'
410 badstates = after and '?' or '?r'
411 m = match(repo, [pat], opts, globbed=True)
411 m = match(repo, [pat], opts, globbed=True)
412 for abs in repo.walk(m):
412 for abs in repo.walk(m):
413 state = repo.dirstate[abs]
413 state = repo.dirstate[abs]
414 rel = m.rel(abs)
414 rel = m.rel(abs)
415 exact = m.exact(abs)
415 exact = m.exact(abs)
416 if state in badstates:
416 if state in badstates:
417 if exact and state == '?':
417 if exact and state == '?':
418 ui.warn(_('%s: not copying - file is not managed\n') % rel)
418 ui.warn(_('%s: not copying - file is not managed\n') % rel)
419 if exact and state == 'r':
419 if exact and state == 'r':
420 ui.warn(_('%s: not copying - file has been marked for'
420 ui.warn(_('%s: not copying - file has been marked for'
421 ' remove\n') % rel)
421 ' remove\n') % rel)
422 continue
422 continue
423 # abs: hgsep
423 # abs: hgsep
424 # rel: ossep
424 # rel: ossep
425 srcs.append((abs, rel, exact))
425 srcs.append((abs, rel, exact))
426 return srcs
426 return srcs
427
427
428 # abssrc: hgsep
428 # abssrc: hgsep
429 # relsrc: ossep
429 # relsrc: ossep
430 # otarget: ossep
430 # otarget: ossep
431 def copyfile(abssrc, relsrc, otarget, exact):
431 def copyfile(abssrc, relsrc, otarget, exact):
432 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
432 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
433 reltarget = repo.pathto(abstarget, cwd)
433 reltarget = repo.pathto(abstarget, cwd)
434 target = repo.wjoin(abstarget)
434 target = repo.wjoin(abstarget)
435 src = repo.wjoin(abssrc)
435 src = repo.wjoin(abssrc)
436 state = repo.dirstate[abstarget]
436 state = repo.dirstate[abstarget]
437
437
438 scmutil.checkportable(ui, abstarget)
438 scmutil.checkportable(ui, abstarget)
439
439
440 # check for collisions
440 # check for collisions
441 prevsrc = targets.get(abstarget)
441 prevsrc = targets.get(abstarget)
442 if prevsrc is not None:
442 if prevsrc is not None:
443 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
443 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
444 (reltarget, repo.pathto(abssrc, cwd),
444 (reltarget, repo.pathto(abssrc, cwd),
445 repo.pathto(prevsrc, cwd)))
445 repo.pathto(prevsrc, cwd)))
446 return
446 return
447
447
448 # check for overwrites
448 # check for overwrites
449 exists = os.path.lexists(target)
449 exists = os.path.lexists(target)
450 if not after and exists or after and state in 'mn':
450 if not after and exists or after and state in 'mn':
451 if not opts['force']:
451 if not opts['force']:
452 ui.warn(_('%s: not overwriting - file exists\n') %
452 ui.warn(_('%s: not overwriting - file exists\n') %
453 reltarget)
453 reltarget)
454 return
454 return
455
455
456 if after:
456 if after:
457 if not exists:
457 if not exists:
458 if rename:
458 if rename:
459 ui.warn(_('%s: not recording move - %s does not exist\n') %
459 ui.warn(_('%s: not recording move - %s does not exist\n') %
460 (relsrc, reltarget))
460 (relsrc, reltarget))
461 else:
461 else:
462 ui.warn(_('%s: not recording copy - %s does not exist\n') %
462 ui.warn(_('%s: not recording copy - %s does not exist\n') %
463 (relsrc, reltarget))
463 (relsrc, reltarget))
464 return
464 return
465 elif not dryrun:
465 elif not dryrun:
466 try:
466 try:
467 if exists:
467 if exists:
468 os.unlink(target)
468 os.unlink(target)
469 targetdir = os.path.dirname(target) or '.'
469 targetdir = os.path.dirname(target) or '.'
470 if not os.path.isdir(targetdir):
470 if not os.path.isdir(targetdir):
471 os.makedirs(targetdir)
471 os.makedirs(targetdir)
472 util.copyfile(src, target)
472 util.copyfile(src, target)
473 except IOError, inst:
473 except IOError, inst:
474 if inst.errno == errno.ENOENT:
474 if inst.errno == errno.ENOENT:
475 ui.warn(_('%s: deleted in working copy\n') % relsrc)
475 ui.warn(_('%s: deleted in working copy\n') % relsrc)
476 else:
476 else:
477 ui.warn(_('%s: cannot copy - %s\n') %
477 ui.warn(_('%s: cannot copy - %s\n') %
478 (relsrc, inst.strerror))
478 (relsrc, inst.strerror))
479 return True # report a failure
479 return True # report a failure
480
480
481 if ui.verbose or not exact:
481 if ui.verbose or not exact:
482 if rename:
482 if rename:
483 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
483 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
484 else:
484 else:
485 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
485 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
486
486
487 targets[abstarget] = abssrc
487 targets[abstarget] = abssrc
488
488
489 # fix up dirstate
489 # fix up dirstate
490 dirstatecopy(ui, repo, wctx, abssrc, abstarget, dryrun=dryrun, cwd=cwd)
490 dirstatecopy(ui, repo, wctx, abssrc, abstarget, dryrun=dryrun, cwd=cwd)
491 if rename and not dryrun:
491 if rename and not dryrun:
492 wctx.remove([abssrc], not after)
492 wctx.remove([abssrc], not after)
493
493
494 # pat: ossep
494 # pat: ossep
495 # dest ossep
495 # dest ossep
496 # srcs: list of (hgsep, hgsep, ossep, bool)
496 # srcs: list of (hgsep, hgsep, ossep, bool)
497 # return: function that takes hgsep and returns ossep
497 # return: function that takes hgsep and returns ossep
498 def targetpathfn(pat, dest, srcs):
498 def targetpathfn(pat, dest, srcs):
499 if os.path.isdir(pat):
499 if os.path.isdir(pat):
500 abspfx = scmutil.canonpath(repo.root, cwd, pat)
500 abspfx = scmutil.canonpath(repo.root, cwd, pat)
501 abspfx = util.localpath(abspfx)
501 abspfx = util.localpath(abspfx)
502 if destdirexists:
502 if destdirexists:
503 striplen = len(os.path.split(abspfx)[0])
503 striplen = len(os.path.split(abspfx)[0])
504 else:
504 else:
505 striplen = len(abspfx)
505 striplen = len(abspfx)
506 if striplen:
506 if striplen:
507 striplen += len(os.sep)
507 striplen += len(os.sep)
508 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
508 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
509 elif destdirexists:
509 elif destdirexists:
510 res = lambda p: os.path.join(dest,
510 res = lambda p: os.path.join(dest,
511 os.path.basename(util.localpath(p)))
511 os.path.basename(util.localpath(p)))
512 else:
512 else:
513 res = lambda p: dest
513 res = lambda p: dest
514 return res
514 return res
515
515
516 # pat: ossep
516 # pat: ossep
517 # dest ossep
517 # dest ossep
518 # srcs: list of (hgsep, hgsep, ossep, bool)
518 # srcs: list of (hgsep, hgsep, ossep, bool)
519 # return: function that takes hgsep and returns ossep
519 # return: function that takes hgsep and returns ossep
520 def targetpathafterfn(pat, dest, srcs):
520 def targetpathafterfn(pat, dest, srcs):
521 if matchmod.patkind(pat):
521 if matchmod.patkind(pat):
522 # a mercurial pattern
522 # a mercurial pattern
523 res = lambda p: os.path.join(dest,
523 res = lambda p: os.path.join(dest,
524 os.path.basename(util.localpath(p)))
524 os.path.basename(util.localpath(p)))
525 else:
525 else:
526 abspfx = scmutil.canonpath(repo.root, cwd, pat)
526 abspfx = scmutil.canonpath(repo.root, cwd, pat)
527 if len(abspfx) < len(srcs[0][0]):
527 if len(abspfx) < len(srcs[0][0]):
528 # A directory. Either the target path contains the last
528 # A directory. Either the target path contains the last
529 # component of the source path or it does not.
529 # component of the source path or it does not.
530 def evalpath(striplen):
530 def evalpath(striplen):
531 score = 0
531 score = 0
532 for s in srcs:
532 for s in srcs:
533 t = os.path.join(dest, util.localpath(s[0])[striplen:])
533 t = os.path.join(dest, util.localpath(s[0])[striplen:])
534 if os.path.lexists(t):
534 if os.path.lexists(t):
535 score += 1
535 score += 1
536 return score
536 return score
537
537
538 abspfx = util.localpath(abspfx)
538 abspfx = util.localpath(abspfx)
539 striplen = len(abspfx)
539 striplen = len(abspfx)
540 if striplen:
540 if striplen:
541 striplen += len(os.sep)
541 striplen += len(os.sep)
542 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
542 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
543 score = evalpath(striplen)
543 score = evalpath(striplen)
544 striplen1 = len(os.path.split(abspfx)[0])
544 striplen1 = len(os.path.split(abspfx)[0])
545 if striplen1:
545 if striplen1:
546 striplen1 += len(os.sep)
546 striplen1 += len(os.sep)
547 if evalpath(striplen1) > score:
547 if evalpath(striplen1) > score:
548 striplen = striplen1
548 striplen = striplen1
549 res = lambda p: os.path.join(dest,
549 res = lambda p: os.path.join(dest,
550 util.localpath(p)[striplen:])
550 util.localpath(p)[striplen:])
551 else:
551 else:
552 # a file
552 # a file
553 if destdirexists:
553 if destdirexists:
554 res = lambda p: os.path.join(dest,
554 res = lambda p: os.path.join(dest,
555 os.path.basename(util.localpath(p)))
555 os.path.basename(util.localpath(p)))
556 else:
556 else:
557 res = lambda p: dest
557 res = lambda p: dest
558 return res
558 return res
559
559
560
560
561 pats = expandpats(pats)
561 pats = expandpats(pats)
562 if not pats:
562 if not pats:
563 raise util.Abort(_('no source or destination specified'))
563 raise util.Abort(_('no source or destination specified'))
564 if len(pats) == 1:
564 if len(pats) == 1:
565 raise util.Abort(_('no destination specified'))
565 raise util.Abort(_('no destination specified'))
566 dest = pats.pop()
566 dest = pats.pop()
567 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
567 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
568 if not destdirexists:
568 if not destdirexists:
569 if len(pats) > 1 or matchmod.patkind(pats[0]):
569 if len(pats) > 1 or matchmod.patkind(pats[0]):
570 raise util.Abort(_('with multiple sources, destination must be an '
570 raise util.Abort(_('with multiple sources, destination must be an '
571 'existing directory'))
571 'existing directory'))
572 if util.endswithsep(dest):
572 if util.endswithsep(dest):
573 raise util.Abort(_('destination %s is not a directory') % dest)
573 raise util.Abort(_('destination %s is not a directory') % dest)
574
574
575 tfn = targetpathfn
575 tfn = targetpathfn
576 if after:
576 if after:
577 tfn = targetpathafterfn
577 tfn = targetpathafterfn
578 copylist = []
578 copylist = []
579 for pat in pats:
579 for pat in pats:
580 srcs = walkpat(pat)
580 srcs = walkpat(pat)
581 if not srcs:
581 if not srcs:
582 continue
582 continue
583 copylist.append((tfn(pat, dest, srcs), srcs))
583 copylist.append((tfn(pat, dest, srcs), srcs))
584 if not copylist:
584 if not copylist:
585 raise util.Abort(_('no files to copy'))
585 raise util.Abort(_('no files to copy'))
586
586
587 errors = 0
587 errors = 0
588 for targetpath, srcs in copylist:
588 for targetpath, srcs in copylist:
589 for abssrc, relsrc, exact in srcs:
589 for abssrc, relsrc, exact in srcs:
590 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
590 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
591 errors += 1
591 errors += 1
592
592
593 if errors:
593 if errors:
594 ui.warn(_('(consider using --after)\n'))
594 ui.warn(_('(consider using --after)\n'))
595
595
596 return errors != 0
596 return errors != 0
597
597
598 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
598 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
599 runargs=None, appendpid=False):
599 runargs=None, appendpid=False):
600 '''Run a command as a service.'''
600 '''Run a command as a service.'''
601
601
602 if opts['daemon'] and not opts['daemon_pipefds']:
602 if opts['daemon'] and not opts['daemon_pipefds']:
603 # Signal child process startup with file removal
603 # Signal child process startup with file removal
604 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
604 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
605 os.close(lockfd)
605 os.close(lockfd)
606 try:
606 try:
607 if not runargs:
607 if not runargs:
608 runargs = util.hgcmd() + sys.argv[1:]
608 runargs = util.hgcmd() + sys.argv[1:]
609 runargs.append('--daemon-pipefds=%s' % lockpath)
609 runargs.append('--daemon-pipefds=%s' % lockpath)
610 # Don't pass --cwd to the child process, because we've already
610 # Don't pass --cwd to the child process, because we've already
611 # changed directory.
611 # changed directory.
612 for i in xrange(1, len(runargs)):
612 for i in xrange(1, len(runargs)):
613 if runargs[i].startswith('--cwd='):
613 if runargs[i].startswith('--cwd='):
614 del runargs[i]
614 del runargs[i]
615 break
615 break
616 elif runargs[i].startswith('--cwd'):
616 elif runargs[i].startswith('--cwd'):
617 del runargs[i:i + 2]
617 del runargs[i:i + 2]
618 break
618 break
619 def condfn():
619 def condfn():
620 return not os.path.exists(lockpath)
620 return not os.path.exists(lockpath)
621 pid = util.rundetached(runargs, condfn)
621 pid = util.rundetached(runargs, condfn)
622 if pid < 0:
622 if pid < 0:
623 raise util.Abort(_('child process failed to start'))
623 raise util.Abort(_('child process failed to start'))
624 finally:
624 finally:
625 try:
625 try:
626 os.unlink(lockpath)
626 os.unlink(lockpath)
627 except OSError, e:
627 except OSError, e:
628 if e.errno != errno.ENOENT:
628 if e.errno != errno.ENOENT:
629 raise
629 raise
630 if parentfn:
630 if parentfn:
631 return parentfn(pid)
631 return parentfn(pid)
632 else:
632 else:
633 return
633 return
634
634
635 if initfn:
635 if initfn:
636 initfn()
636 initfn()
637
637
638 if opts['pid_file']:
638 if opts['pid_file']:
639 mode = appendpid and 'a' or 'w'
639 mode = appendpid and 'a' or 'w'
640 fp = open(opts['pid_file'], mode)
640 fp = open(opts['pid_file'], mode)
641 fp.write(str(os.getpid()) + '\n')
641 fp.write(str(os.getpid()) + '\n')
642 fp.close()
642 fp.close()
643
643
644 if opts['daemon_pipefds']:
644 if opts['daemon_pipefds']:
645 lockpath = opts['daemon_pipefds']
645 lockpath = opts['daemon_pipefds']
646 try:
646 try:
647 os.setsid()
647 os.setsid()
648 except AttributeError:
648 except AttributeError:
649 pass
649 pass
650 os.unlink(lockpath)
650 os.unlink(lockpath)
651 util.hidewindow()
651 util.hidewindow()
652 sys.stdout.flush()
652 sys.stdout.flush()
653 sys.stderr.flush()
653 sys.stderr.flush()
654
654
655 nullfd = os.open(util.nulldev, os.O_RDWR)
655 nullfd = os.open(util.nulldev, os.O_RDWR)
656 logfilefd = nullfd
656 logfilefd = nullfd
657 if logfile:
657 if logfile:
658 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
658 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
659 os.dup2(nullfd, 0)
659 os.dup2(nullfd, 0)
660 os.dup2(logfilefd, 1)
660 os.dup2(logfilefd, 1)
661 os.dup2(logfilefd, 2)
661 os.dup2(logfilefd, 2)
662 if nullfd not in (0, 1, 2):
662 if nullfd not in (0, 1, 2):
663 os.close(nullfd)
663 os.close(nullfd)
664 if logfile and logfilefd not in (0, 1, 2):
664 if logfile and logfilefd not in (0, 1, 2):
665 os.close(logfilefd)
665 os.close(logfilefd)
666
666
667 if runfn:
667 if runfn:
668 return runfn()
668 return runfn()
669
669
670 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
670 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
671 opts=None):
671 opts=None):
672 '''export changesets as hg patches.'''
672 '''export changesets as hg patches.'''
673
673
674 total = len(revs)
674 total = len(revs)
675 revwidth = max([len(str(rev)) for rev in revs])
675 revwidth = max([len(str(rev)) for rev in revs])
676
676
677 def single(rev, seqno, fp):
677 def single(rev, seqno, fp):
678 ctx = repo[rev]
678 ctx = repo[rev]
679 node = ctx.node()
679 node = ctx.node()
680 parents = [p.node() for p in ctx.parents() if p]
680 parents = [p.node() for p in ctx.parents() if p]
681 branch = ctx.branch()
681 branch = ctx.branch()
682 if switch_parent:
682 if switch_parent:
683 parents.reverse()
683 parents.reverse()
684 prev = (parents and parents[0]) or nullid
684 prev = (parents and parents[0]) or nullid
685
685
686 shouldclose = False
686 shouldclose = False
687 if not fp:
687 if not fp:
688 fp = make_file(repo, template, node, total=total, seqno=seqno,
688 fp = make_file(repo, template, node, total=total, seqno=seqno,
689 revwidth=revwidth, mode='ab')
689 revwidth=revwidth, mode='ab')
690 if fp != template:
690 if fp != template:
691 shouldclose = True
691 shouldclose = True
692 if fp != sys.stdout and hasattr(fp, 'name'):
692 if fp != sys.stdout and hasattr(fp, 'name'):
693 repo.ui.note("%s\n" % fp.name)
693 repo.ui.note("%s\n" % fp.name)
694
694
695 fp.write("# HG changeset patch\n")
695 fp.write("# HG changeset patch\n")
696 fp.write("# User %s\n" % ctx.user())
696 fp.write("# User %s\n" % ctx.user())
697 fp.write("# Date %d %d\n" % ctx.date())
697 fp.write("# Date %d %d\n" % ctx.date())
698 if branch and branch != 'default':
698 if branch and branch != 'default':
699 fp.write("# Branch %s\n" % branch)
699 fp.write("# Branch %s\n" % branch)
700 fp.write("# Node ID %s\n" % hex(node))
700 fp.write("# Node ID %s\n" % hex(node))
701 fp.write("# Parent %s\n" % hex(prev))
701 fp.write("# Parent %s\n" % hex(prev))
702 if len(parents) > 1:
702 if len(parents) > 1:
703 fp.write("# Parent %s\n" % hex(parents[1]))
703 fp.write("# Parent %s\n" % hex(parents[1]))
704 fp.write(ctx.description().rstrip())
704 fp.write(ctx.description().rstrip())
705 fp.write("\n\n")
705 fp.write("\n\n")
706
706
707 for chunk in patch.diff(repo, prev, node, opts=opts):
707 for chunk in patch.diff(repo, prev, node, opts=opts):
708 fp.write(chunk)
708 fp.write(chunk)
709
709
710 if shouldclose:
710 if shouldclose:
711 fp.close()
711 fp.close()
712
712
713 for seqno, rev in enumerate(revs):
713 for seqno, rev in enumerate(revs):
714 single(rev, seqno + 1, fp)
714 single(rev, seqno + 1, fp)
715
715
716 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
716 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
717 changes=None, stat=False, fp=None, prefix='',
717 changes=None, stat=False, fp=None, prefix='',
718 listsubrepos=False):
718 listsubrepos=False):
719 '''show diff or diffstat.'''
719 '''show diff or diffstat.'''
720 if fp is None:
720 if fp is None:
721 write = ui.write
721 write = ui.write
722 else:
722 else:
723 def write(s, **kw):
723 def write(s, **kw):
724 fp.write(s)
724 fp.write(s)
725
725
726 if stat:
726 if stat:
727 diffopts = diffopts.copy(context=0)
727 diffopts = diffopts.copy(context=0)
728 width = 80
728 width = 80
729 if not ui.plain():
729 if not ui.plain():
730 width = ui.termwidth()
730 width = ui.termwidth()
731 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
731 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
732 prefix=prefix)
732 prefix=prefix)
733 for chunk, label in patch.diffstatui(util.iterlines(chunks),
733 for chunk, label in patch.diffstatui(util.iterlines(chunks),
734 width=width,
734 width=width,
735 git=diffopts.git):
735 git=diffopts.git):
736 write(chunk, label=label)
736 write(chunk, label=label)
737 else:
737 else:
738 for chunk, label in patch.diffui(repo, node1, node2, match,
738 for chunk, label in patch.diffui(repo, node1, node2, match,
739 changes, diffopts, prefix=prefix):
739 changes, diffopts, prefix=prefix):
740 write(chunk, label=label)
740 write(chunk, label=label)
741
741
742 if listsubrepos:
742 if listsubrepos:
743 ctx1 = repo[node1]
743 ctx1 = repo[node1]
744 ctx2 = repo[node2]
744 ctx2 = repo[node2]
745 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
745 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
746 if node2 is not None:
746 if node2 is not None:
747 node2 = ctx2.substate[subpath][1]
747 node2 = ctx2.substate[subpath][1]
748 submatch = matchmod.narrowmatcher(subpath, match)
748 submatch = matchmod.narrowmatcher(subpath, match)
749 sub.diff(diffopts, node2, submatch, changes=changes,
749 sub.diff(diffopts, node2, submatch, changes=changes,
750 stat=stat, fp=fp, prefix=prefix)
750 stat=stat, fp=fp, prefix=prefix)
751
751
752 class changeset_printer(object):
752 class changeset_printer(object):
753 '''show changeset information when templating not requested.'''
753 '''show changeset information when templating not requested.'''
754
754
755 def __init__(self, ui, repo, patch, diffopts, buffered):
755 def __init__(self, ui, repo, patch, diffopts, buffered):
756 self.ui = ui
756 self.ui = ui
757 self.repo = repo
757 self.repo = repo
758 self.buffered = buffered
758 self.buffered = buffered
759 self.patch = patch
759 self.patch = patch
760 self.diffopts = diffopts
760 self.diffopts = diffopts
761 self.header = {}
761 self.header = {}
762 self.hunk = {}
762 self.hunk = {}
763 self.lastheader = None
763 self.lastheader = None
764 self.footer = None
764 self.footer = None
765
765
766 def flush(self, rev):
766 def flush(self, rev):
767 if rev in self.header:
767 if rev in self.header:
768 h = self.header[rev]
768 h = self.header[rev]
769 if h != self.lastheader:
769 if h != self.lastheader:
770 self.lastheader = h
770 self.lastheader = h
771 self.ui.write(h)
771 self.ui.write(h)
772 del self.header[rev]
772 del self.header[rev]
773 if rev in self.hunk:
773 if rev in self.hunk:
774 self.ui.write(self.hunk[rev])
774 self.ui.write(self.hunk[rev])
775 del self.hunk[rev]
775 del self.hunk[rev]
776 return 1
776 return 1
777 return 0
777 return 0
778
778
779 def close(self):
779 def close(self):
780 if self.footer:
780 if self.footer:
781 self.ui.write(self.footer)
781 self.ui.write(self.footer)
782
782
783 def show(self, ctx, copies=None, matchfn=None, **props):
783 def show(self, ctx, copies=None, matchfn=None, **props):
784 if self.buffered:
784 if self.buffered:
785 self.ui.pushbuffer()
785 self.ui.pushbuffer()
786 self._show(ctx, copies, matchfn, props)
786 self._show(ctx, copies, matchfn, props)
787 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
787 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
788 else:
788 else:
789 self._show(ctx, copies, matchfn, props)
789 self._show(ctx, copies, matchfn, props)
790
790
791 def _show(self, ctx, copies, matchfn, props):
791 def _show(self, ctx, copies, matchfn, props):
792 '''show a single changeset or file revision'''
792 '''show a single changeset or file revision'''
793 changenode = ctx.node()
793 changenode = ctx.node()
794 rev = ctx.rev()
794 rev = ctx.rev()
795
795
796 if self.ui.quiet:
796 if self.ui.quiet:
797 self.ui.write("%d:%s\n" % (rev, short(changenode)),
797 self.ui.write("%d:%s\n" % (rev, short(changenode)),
798 label='log.node')
798 label='log.node')
799 return
799 return
800
800
801 log = self.repo.changelog
801 log = self.repo.changelog
802 date = util.datestr(ctx.date())
802 date = util.datestr(ctx.date())
803
803
804 hexfunc = self.ui.debugflag and hex or short
804 hexfunc = self.ui.debugflag and hex or short
805
805
806 parents = [(p, hexfunc(log.node(p)))
806 parents = [(p, hexfunc(log.node(p)))
807 for p in self._meaningful_parentrevs(log, rev)]
807 for p in self._meaningful_parentrevs(log, rev)]
808
808
809 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
809 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
810 label='log.changeset')
810 label='log.changeset')
811
811
812 branch = ctx.branch()
812 branch = ctx.branch()
813 # don't show the default branch name
813 # don't show the default branch name
814 if branch != 'default':
814 if branch != 'default':
815 self.ui.write(_("branch: %s\n") % branch,
815 self.ui.write(_("branch: %s\n") % branch,
816 label='log.branch')
816 label='log.branch')
817 for bookmark in self.repo.nodebookmarks(changenode):
817 for bookmark in self.repo.nodebookmarks(changenode):
818 self.ui.write(_("bookmark: %s\n") % bookmark,
818 self.ui.write(_("bookmark: %s\n") % bookmark,
819 label='log.bookmark')
819 label='log.bookmark')
820 for tag in self.repo.nodetags(changenode):
820 for tag in self.repo.nodetags(changenode):
821 self.ui.write(_("tag: %s\n") % tag,
821 self.ui.write(_("tag: %s\n") % tag,
822 label='log.tag')
822 label='log.tag')
823 for parent in parents:
823 for parent in parents:
824 self.ui.write(_("parent: %d:%s\n") % parent,
824 self.ui.write(_("parent: %d:%s\n") % parent,
825 label='log.parent')
825 label='log.parent')
826
826
827 if self.ui.debugflag:
827 if self.ui.debugflag:
828 mnode = ctx.manifestnode()
828 mnode = ctx.manifestnode()
829 self.ui.write(_("manifest: %d:%s\n") %
829 self.ui.write(_("manifest: %d:%s\n") %
830 (self.repo.manifest.rev(mnode), hex(mnode)),
830 (self.repo.manifest.rev(mnode), hex(mnode)),
831 label='ui.debug log.manifest')
831 label='ui.debug log.manifest')
832 self.ui.write(_("user: %s\n") % ctx.user(),
832 self.ui.write(_("user: %s\n") % ctx.user(),
833 label='log.user')
833 label='log.user')
834 self.ui.write(_("date: %s\n") % date,
834 self.ui.write(_("date: %s\n") % date,
835 label='log.date')
835 label='log.date')
836
836
837 if self.ui.debugflag:
837 if self.ui.debugflag:
838 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
838 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
839 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
839 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
840 files):
840 files):
841 if value:
841 if value:
842 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
842 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
843 label='ui.debug log.files')
843 label='ui.debug log.files')
844 elif ctx.files() and self.ui.verbose:
844 elif ctx.files() and self.ui.verbose:
845 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
845 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
846 label='ui.note log.files')
846 label='ui.note log.files')
847 if copies and self.ui.verbose:
847 if copies and self.ui.verbose:
848 copies = ['%s (%s)' % c for c in copies]
848 copies = ['%s (%s)' % c for c in copies]
849 self.ui.write(_("copies: %s\n") % ' '.join(copies),
849 self.ui.write(_("copies: %s\n") % ' '.join(copies),
850 label='ui.note log.copies')
850 label='ui.note log.copies')
851
851
852 extra = ctx.extra()
852 extra = ctx.extra()
853 if extra and self.ui.debugflag:
853 if extra and self.ui.debugflag:
854 for key, value in sorted(extra.items()):
854 for key, value in sorted(extra.items()):
855 self.ui.write(_("extra: %s=%s\n")
855 self.ui.write(_("extra: %s=%s\n")
856 % (key, value.encode('string_escape')),
856 % (key, value.encode('string_escape')),
857 label='ui.debug log.extra')
857 label='ui.debug log.extra')
858
858
859 description = ctx.description().strip()
859 description = ctx.description().strip()
860 if description:
860 if description:
861 if self.ui.verbose:
861 if self.ui.verbose:
862 self.ui.write(_("description:\n"),
862 self.ui.write(_("description:\n"),
863 label='ui.note log.description')
863 label='ui.note log.description')
864 self.ui.write(description,
864 self.ui.write(description,
865 label='ui.note log.description')
865 label='ui.note log.description')
866 self.ui.write("\n\n")
866 self.ui.write("\n\n")
867 else:
867 else:
868 self.ui.write(_("summary: %s\n") %
868 self.ui.write(_("summary: %s\n") %
869 description.splitlines()[0],
869 description.splitlines()[0],
870 label='log.summary')
870 label='log.summary')
871 self.ui.write("\n")
871 self.ui.write("\n")
872
872
873 self.showpatch(changenode, matchfn)
873 self.showpatch(changenode, matchfn)
874
874
875 def showpatch(self, node, matchfn):
875 def showpatch(self, node, matchfn):
876 if not matchfn:
876 if not matchfn:
877 matchfn = self.patch
877 matchfn = self.patch
878 if matchfn:
878 if matchfn:
879 stat = self.diffopts.get('stat')
879 stat = self.diffopts.get('stat')
880 diff = self.diffopts.get('patch')
880 diff = self.diffopts.get('patch')
881 diffopts = patch.diffopts(self.ui, self.diffopts)
881 diffopts = patch.diffopts(self.ui, self.diffopts)
882 prev = self.repo.changelog.parents(node)[0]
882 prev = self.repo.changelog.parents(node)[0]
883 if stat:
883 if stat:
884 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
884 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
885 match=matchfn, stat=True)
885 match=matchfn, stat=True)
886 if diff:
886 if diff:
887 if stat:
887 if stat:
888 self.ui.write("\n")
888 self.ui.write("\n")
889 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
889 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
890 match=matchfn, stat=False)
890 match=matchfn, stat=False)
891 self.ui.write("\n")
891 self.ui.write("\n")
892
892
893 def _meaningful_parentrevs(self, log, rev):
893 def _meaningful_parentrevs(self, log, rev):
894 """Return list of meaningful (or all if debug) parentrevs for rev.
894 """Return list of meaningful (or all if debug) parentrevs for rev.
895
895
896 For merges (two non-nullrev revisions) both parents are meaningful.
896 For merges (two non-nullrev revisions) both parents are meaningful.
897 Otherwise the first parent revision is considered meaningful if it
897 Otherwise the first parent revision is considered meaningful if it
898 is not the preceding revision.
898 is not the preceding revision.
899 """
899 """
900 parents = log.parentrevs(rev)
900 parents = log.parentrevs(rev)
901 if not self.ui.debugflag and parents[1] == nullrev:
901 if not self.ui.debugflag and parents[1] == nullrev:
902 if parents[0] >= rev - 1:
902 if parents[0] >= rev - 1:
903 parents = []
903 parents = []
904 else:
904 else:
905 parents = [parents[0]]
905 parents = [parents[0]]
906 return parents
906 return parents
907
907
908
908
909 class changeset_templater(changeset_printer):
909 class changeset_templater(changeset_printer):
910 '''format changeset information.'''
910 '''format changeset information.'''
911
911
912 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
912 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
913 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
913 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
914 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
914 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
915 defaulttempl = {
915 defaulttempl = {
916 'parent': '{rev}:{node|formatnode} ',
916 'parent': '{rev}:{node|formatnode} ',
917 'manifest': '{rev}:{node|formatnode}',
917 'manifest': '{rev}:{node|formatnode}',
918 'file_copy': '{name} ({source})',
918 'file_copy': '{name} ({source})',
919 'extra': '{key}={value|stringescape}'
919 'extra': '{key}={value|stringescape}'
920 }
920 }
921 # filecopy is preserved for compatibility reasons
921 # filecopy is preserved for compatibility reasons
922 defaulttempl['filecopy'] = defaulttempl['file_copy']
922 defaulttempl['filecopy'] = defaulttempl['file_copy']
923 self.t = templater.templater(mapfile, {'formatnode': formatnode},
923 self.t = templater.templater(mapfile, {'formatnode': formatnode},
924 cache=defaulttempl)
924 cache=defaulttempl)
925 self.cache = {}
925 self.cache = {}
926
926
927 def use_template(self, t):
927 def use_template(self, t):
928 '''set template string to use'''
928 '''set template string to use'''
929 self.t.cache['changeset'] = t
929 self.t.cache['changeset'] = t
930
930
931 def _meaningful_parentrevs(self, ctx):
931 def _meaningful_parentrevs(self, ctx):
932 """Return list of meaningful (or all if debug) parentrevs for rev.
932 """Return list of meaningful (or all if debug) parentrevs for rev.
933 """
933 """
934 parents = ctx.parents()
934 parents = ctx.parents()
935 if len(parents) > 1:
935 if len(parents) > 1:
936 return parents
936 return parents
937 if self.ui.debugflag:
937 if self.ui.debugflag:
938 return [parents[0], self.repo['null']]
938 return [parents[0], self.repo['null']]
939 if parents[0].rev() >= ctx.rev() - 1:
939 if parents[0].rev() >= ctx.rev() - 1:
940 return []
940 return []
941 return parents
941 return parents
942
942
943 def _show(self, ctx, copies, matchfn, props):
943 def _show(self, ctx, copies, matchfn, props):
944 '''show a single changeset or file revision'''
944 '''show a single changeset or file revision'''
945
945
946 showlist = templatekw.showlist
946 showlist = templatekw.showlist
947
947
948 # showparents() behaviour depends on ui trace level which
948 # showparents() behaviour depends on ui trace level which
949 # causes unexpected behaviours at templating level and makes
949 # causes unexpected behaviours at templating level and makes
950 # it harder to extract it in a standalone function. Its
950 # it harder to extract it in a standalone function. Its
951 # behaviour cannot be changed so leave it here for now.
951 # behaviour cannot be changed so leave it here for now.
952 def showparents(**args):
952 def showparents(**args):
953 ctx = args['ctx']
953 ctx = args['ctx']
954 parents = [[('rev', p.rev()), ('node', p.hex())]
954 parents = [[('rev', p.rev()), ('node', p.hex())]
955 for p in self._meaningful_parentrevs(ctx)]
955 for p in self._meaningful_parentrevs(ctx)]
956 return showlist('parent', parents, **args)
956 return showlist('parent', parents, **args)
957
957
958 props = props.copy()
958 props = props.copy()
959 props.update(templatekw.keywords)
959 props.update(templatekw.keywords)
960 props['parents'] = showparents
960 props['parents'] = showparents
961 props['templ'] = self.t
961 props['templ'] = self.t
962 props['ctx'] = ctx
962 props['ctx'] = ctx
963 props['repo'] = self.repo
963 props['repo'] = self.repo
964 props['revcache'] = {'copies': copies}
964 props['revcache'] = {'copies': copies}
965 props['cache'] = self.cache
965 props['cache'] = self.cache
966
966
967 # find correct templates for current mode
967 # find correct templates for current mode
968
968
969 tmplmodes = [
969 tmplmodes = [
970 (True, None),
970 (True, None),
971 (self.ui.verbose, 'verbose'),
971 (self.ui.verbose, 'verbose'),
972 (self.ui.quiet, 'quiet'),
972 (self.ui.quiet, 'quiet'),
973 (self.ui.debugflag, 'debug'),
973 (self.ui.debugflag, 'debug'),
974 ]
974 ]
975
975
976 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
976 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
977 for mode, postfix in tmplmodes:
977 for mode, postfix in tmplmodes:
978 for type in types:
978 for type in types:
979 cur = postfix and ('%s_%s' % (type, postfix)) or type
979 cur = postfix and ('%s_%s' % (type, postfix)) or type
980 if mode and cur in self.t:
980 if mode and cur in self.t:
981 types[type] = cur
981 types[type] = cur
982
982
983 try:
983 try:
984
984
985 # write header
985 # write header
986 if types['header']:
986 if types['header']:
987 h = templater.stringify(self.t(types['header'], **props))
987 h = templater.stringify(self.t(types['header'], **props))
988 if self.buffered:
988 if self.buffered:
989 self.header[ctx.rev()] = h
989 self.header[ctx.rev()] = h
990 else:
990 else:
991 if self.lastheader != h:
991 if self.lastheader != h:
992 self.lastheader = h
992 self.lastheader = h
993 self.ui.write(h)
993 self.ui.write(h)
994
994
995 # write changeset metadata, then patch if requested
995 # write changeset metadata, then patch if requested
996 key = types['changeset']
996 key = types['changeset']
997 self.ui.write(templater.stringify(self.t(key, **props)))
997 self.ui.write(templater.stringify(self.t(key, **props)))
998 self.showpatch(ctx.node(), matchfn)
998 self.showpatch(ctx.node(), matchfn)
999
999
1000 if types['footer']:
1000 if types['footer']:
1001 if not self.footer:
1001 if not self.footer:
1002 self.footer = templater.stringify(self.t(types['footer'],
1002 self.footer = templater.stringify(self.t(types['footer'],
1003 **props))
1003 **props))
1004
1004
1005 except KeyError, inst:
1005 except KeyError, inst:
1006 msg = _("%s: no key named '%s'")
1006 msg = _("%s: no key named '%s'")
1007 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
1007 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
1008 except SyntaxError, inst:
1008 except SyntaxError, inst:
1009 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
1009 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
1010
1010
1011 def show_changeset(ui, repo, opts, buffered=False):
1011 def show_changeset(ui, repo, opts, buffered=False):
1012 """show one changeset using template or regular display.
1012 """show one changeset using template or regular display.
1013
1013
1014 Display format will be the first non-empty hit of:
1014 Display format will be the first non-empty hit of:
1015 1. option 'template'
1015 1. option 'template'
1016 2. option 'style'
1016 2. option 'style'
1017 3. [ui] setting 'logtemplate'
1017 3. [ui] setting 'logtemplate'
1018 4. [ui] setting 'style'
1018 4. [ui] setting 'style'
1019 If all of these values are either the unset or the empty string,
1019 If all of these values are either the unset or the empty string,
1020 regular display via changeset_printer() is done.
1020 regular display via changeset_printer() is done.
1021 """
1021 """
1022 # options
1022 # options
1023 patch = False
1023 patch = False
1024 if opts.get('patch') or opts.get('stat'):
1024 if opts.get('patch') or opts.get('stat'):
1025 patch = matchall(repo)
1025 patch = matchall(repo)
1026
1026
1027 tmpl = opts.get('template')
1027 tmpl = opts.get('template')
1028 style = None
1028 style = None
1029 if tmpl:
1029 if tmpl:
1030 tmpl = templater.parsestring(tmpl, quoted=False)
1030 tmpl = templater.parsestring(tmpl, quoted=False)
1031 else:
1031 else:
1032 style = opts.get('style')
1032 style = opts.get('style')
1033
1033
1034 # ui settings
1034 # ui settings
1035 if not (tmpl or style):
1035 if not (tmpl or style):
1036 tmpl = ui.config('ui', 'logtemplate')
1036 tmpl = ui.config('ui', 'logtemplate')
1037 if tmpl:
1037 if tmpl:
1038 tmpl = templater.parsestring(tmpl)
1038 tmpl = templater.parsestring(tmpl)
1039 else:
1039 else:
1040 style = util.expandpath(ui.config('ui', 'style', ''))
1040 style = util.expandpath(ui.config('ui', 'style', ''))
1041
1041
1042 if not (tmpl or style):
1042 if not (tmpl or style):
1043 return changeset_printer(ui, repo, patch, opts, buffered)
1043 return changeset_printer(ui, repo, patch, opts, buffered)
1044
1044
1045 mapfile = None
1045 mapfile = None
1046 if style and not tmpl:
1046 if style and not tmpl:
1047 mapfile = style
1047 mapfile = style
1048 if not os.path.split(mapfile)[0]:
1048 if not os.path.split(mapfile)[0]:
1049 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1049 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1050 or templater.templatepath(mapfile))
1050 or templater.templatepath(mapfile))
1051 if mapname:
1051 if mapname:
1052 mapfile = mapname
1052 mapfile = mapname
1053
1053
1054 try:
1054 try:
1055 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
1055 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
1056 except SyntaxError, inst:
1056 except SyntaxError, inst:
1057 raise util.Abort(inst.args[0])
1057 raise util.Abort(inst.args[0])
1058 if tmpl:
1058 if tmpl:
1059 t.use_template(tmpl)
1059 t.use_template(tmpl)
1060 return t
1060 return t
1061
1061
1062 def finddate(ui, repo, date):
1062 def finddate(ui, repo, date):
1063 """Find the tipmost changeset that matches the given date spec"""
1063 """Find the tipmost changeset that matches the given date spec"""
1064
1064
1065 df = util.matchdate(date)
1065 df = util.matchdate(date)
1066 m = matchall(repo)
1066 m = matchall(repo)
1067 results = {}
1067 results = {}
1068
1068
1069 def prep(ctx, fns):
1069 def prep(ctx, fns):
1070 d = ctx.date()
1070 d = ctx.date()
1071 if df(d[0]):
1071 if df(d[0]):
1072 results[ctx.rev()] = d
1072 results[ctx.rev()] = d
1073
1073
1074 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1074 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1075 rev = ctx.rev()
1075 rev = ctx.rev()
1076 if rev in results:
1076 if rev in results:
1077 ui.status(_("Found revision %s from %s\n") %
1077 ui.status(_("Found revision %s from %s\n") %
1078 (rev, util.datestr(results[rev])))
1078 (rev, util.datestr(results[rev])))
1079 return str(rev)
1079 return str(rev)
1080
1080
1081 raise util.Abort(_("revision matching date not found"))
1081 raise util.Abort(_("revision matching date not found"))
1082
1082
1083 def walkchangerevs(repo, match, opts, prepare):
1083 def walkchangerevs(repo, match, opts, prepare):
1084 '''Iterate over files and the revs in which they changed.
1084 '''Iterate over files and the revs in which they changed.
1085
1085
1086 Callers most commonly need to iterate backwards over the history
1086 Callers most commonly need to iterate backwards over the history
1087 in which they are interested. Doing so has awful (quadratic-looking)
1087 in which they are interested. Doing so has awful (quadratic-looking)
1088 performance, so we use iterators in a "windowed" way.
1088 performance, so we use iterators in a "windowed" way.
1089
1089
1090 We walk a window of revisions in the desired order. Within the
1090 We walk a window of revisions in the desired order. Within the
1091 window, we first walk forwards to gather data, then in the desired
1091 window, we first walk forwards to gather data, then in the desired
1092 order (usually backwards) to display it.
1092 order (usually backwards) to display it.
1093
1093
1094 This function returns an iterator yielding contexts. Before
1094 This function returns an iterator yielding contexts. Before
1095 yielding each context, the iterator will first call the prepare
1095 yielding each context, the iterator will first call the prepare
1096 function on each context in the window in forward order.'''
1096 function on each context in the window in forward order.'''
1097
1097
1098 def increasing_windows(start, end, windowsize=8, sizelimit=512):
1098 def increasing_windows(start, end, windowsize=8, sizelimit=512):
1099 if start < end:
1099 if start < end:
1100 while start < end:
1100 while start < end:
1101 yield start, min(windowsize, end - start)
1101 yield start, min(windowsize, end - start)
1102 start += windowsize
1102 start += windowsize
1103 if windowsize < sizelimit:
1103 if windowsize < sizelimit:
1104 windowsize *= 2
1104 windowsize *= 2
1105 else:
1105 else:
1106 while start > end:
1106 while start > end:
1107 yield start, min(windowsize, start - end - 1)
1107 yield start, min(windowsize, start - end - 1)
1108 start -= windowsize
1108 start -= windowsize
1109 if windowsize < sizelimit:
1109 if windowsize < sizelimit:
1110 windowsize *= 2
1110 windowsize *= 2
1111
1111
1112 follow = opts.get('follow') or opts.get('follow_first')
1112 follow = opts.get('follow') or opts.get('follow_first')
1113
1113
1114 if not len(repo):
1114 if not len(repo):
1115 return []
1115 return []
1116
1116
1117 if follow:
1117 if follow:
1118 defrange = '%s:0' % repo['.'].rev()
1118 defrange = '%s:0' % repo['.'].rev()
1119 else:
1119 else:
1120 defrange = '-1:0'
1120 defrange = '-1:0'
1121 revs = revrange(repo, opts['rev'] or [defrange])
1121 revs = revrange(repo, opts['rev'] or [defrange])
1122 if not revs:
1122 if not revs:
1123 return []
1123 return []
1124 wanted = set()
1124 wanted = set()
1125 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1125 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1126 fncache = {}
1126 fncache = {}
1127 change = util.cachefunc(repo.changectx)
1127 change = util.cachefunc(repo.changectx)
1128
1128
1129 # First step is to fill wanted, the set of revisions that we want to yield.
1129 # First step is to fill wanted, the set of revisions that we want to yield.
1130 # When it does not induce extra cost, we also fill fncache for revisions in
1130 # When it does not induce extra cost, we also fill fncache for revisions in
1131 # wanted: a cache of filenames that were changed (ctx.files()) and that
1131 # wanted: a cache of filenames that were changed (ctx.files()) and that
1132 # match the file filtering conditions.
1132 # match the file filtering conditions.
1133
1133
1134 if not slowpath and not match.files():
1134 if not slowpath and not match.files():
1135 # No files, no patterns. Display all revs.
1135 # No files, no patterns. Display all revs.
1136 wanted = set(revs)
1136 wanted = set(revs)
1137 copies = []
1137 copies = []
1138
1138
1139 if not slowpath:
1139 if not slowpath:
1140 # We only have to read through the filelog to find wanted revisions
1140 # We only have to read through the filelog to find wanted revisions
1141
1141
1142 minrev, maxrev = min(revs), max(revs)
1142 minrev, maxrev = min(revs), max(revs)
1143 def filerevgen(filelog, last):
1143 def filerevgen(filelog, last):
1144 """
1144 """
1145 Only files, no patterns. Check the history of each file.
1145 Only files, no patterns. Check the history of each file.
1146
1146
1147 Examines filelog entries within minrev, maxrev linkrev range
1147 Examines filelog entries within minrev, maxrev linkrev range
1148 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1148 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1149 tuples in backwards order
1149 tuples in backwards order
1150 """
1150 """
1151 cl_count = len(repo)
1151 cl_count = len(repo)
1152 revs = []
1152 revs = []
1153 for j in xrange(0, last + 1):
1153 for j in xrange(0, last + 1):
1154 linkrev = filelog.linkrev(j)
1154 linkrev = filelog.linkrev(j)
1155 if linkrev < minrev:
1155 if linkrev < minrev:
1156 continue
1156 continue
1157 # only yield rev for which we have the changelog, it can
1157 # only yield rev for which we have the changelog, it can
1158 # happen while doing "hg log" during a pull or commit
1158 # happen while doing "hg log" during a pull or commit
1159 if linkrev >= cl_count:
1159 if linkrev >= cl_count:
1160 break
1160 break
1161
1161
1162 parentlinkrevs = []
1162 parentlinkrevs = []
1163 for p in filelog.parentrevs(j):
1163 for p in filelog.parentrevs(j):
1164 if p != nullrev:
1164 if p != nullrev:
1165 parentlinkrevs.append(filelog.linkrev(p))
1165 parentlinkrevs.append(filelog.linkrev(p))
1166 n = filelog.node(j)
1166 n = filelog.node(j)
1167 revs.append((linkrev, parentlinkrevs,
1167 revs.append((linkrev, parentlinkrevs,
1168 follow and filelog.renamed(n)))
1168 follow and filelog.renamed(n)))
1169
1169
1170 return reversed(revs)
1170 return reversed(revs)
1171 def iterfiles():
1171 def iterfiles():
1172 for filename in match.files():
1172 for filename in match.files():
1173 yield filename, None
1173 yield filename, None
1174 for filename_node in copies:
1174 for filename_node in copies:
1175 yield filename_node
1175 yield filename_node
1176 for file_, node in iterfiles():
1176 for file_, node in iterfiles():
1177 filelog = repo.file(file_)
1177 filelog = repo.file(file_)
1178 if not len(filelog):
1178 if not len(filelog):
1179 if node is None:
1179 if node is None:
1180 # A zero count may be a directory or deleted file, so
1180 # A zero count may be a directory or deleted file, so
1181 # try to find matching entries on the slow path.
1181 # try to find matching entries on the slow path.
1182 if follow:
1182 if follow:
1183 raise util.Abort(
1183 raise util.Abort(
1184 _('cannot follow nonexistent file: "%s"') % file_)
1184 _('cannot follow nonexistent file: "%s"') % file_)
1185 slowpath = True
1185 slowpath = True
1186 break
1186 break
1187 else:
1187 else:
1188 continue
1188 continue
1189
1189
1190 if node is None:
1190 if node is None:
1191 last = len(filelog) - 1
1191 last = len(filelog) - 1
1192 else:
1192 else:
1193 last = filelog.rev(node)
1193 last = filelog.rev(node)
1194
1194
1195
1195
1196 # keep track of all ancestors of the file
1196 # keep track of all ancestors of the file
1197 ancestors = set([filelog.linkrev(last)])
1197 ancestors = set([filelog.linkrev(last)])
1198
1198
1199 # iterate from latest to oldest revision
1199 # iterate from latest to oldest revision
1200 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1200 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1201 if not follow:
1201 if not follow:
1202 if rev > maxrev:
1202 if rev > maxrev:
1203 continue
1203 continue
1204 else:
1204 else:
1205 # Note that last might not be the first interesting
1205 # Note that last might not be the first interesting
1206 # rev to us:
1206 # rev to us:
1207 # if the file has been changed after maxrev, we'll
1207 # if the file has been changed after maxrev, we'll
1208 # have linkrev(last) > maxrev, and we still need
1208 # have linkrev(last) > maxrev, and we still need
1209 # to explore the file graph
1209 # to explore the file graph
1210 if rev not in ancestors:
1210 if rev not in ancestors:
1211 continue
1211 continue
1212 # XXX insert 1327 fix here
1212 # XXX insert 1327 fix here
1213 if flparentlinkrevs:
1213 if flparentlinkrevs:
1214 ancestors.update(flparentlinkrevs)
1214 ancestors.update(flparentlinkrevs)
1215
1215
1216 fncache.setdefault(rev, []).append(file_)
1216 fncache.setdefault(rev, []).append(file_)
1217 wanted.add(rev)
1217 wanted.add(rev)
1218 if copied:
1218 if copied:
1219 copies.append(copied)
1219 copies.append(copied)
1220 if slowpath:
1220 if slowpath:
1221 # We have to read the changelog to match filenames against
1221 # We have to read the changelog to match filenames against
1222 # changed files
1222 # changed files
1223
1223
1224 if follow:
1224 if follow:
1225 raise util.Abort(_('can only follow copies/renames for explicit '
1225 raise util.Abort(_('can only follow copies/renames for explicit '
1226 'filenames'))
1226 'filenames'))
1227
1227
1228 # The slow path checks files modified in every changeset.
1228 # The slow path checks files modified in every changeset.
1229 for i in sorted(revs):
1229 for i in sorted(revs):
1230 ctx = change(i)
1230 ctx = change(i)
1231 matches = filter(match, ctx.files())
1231 matches = filter(match, ctx.files())
1232 if matches:
1232 if matches:
1233 fncache[i] = matches
1233 fncache[i] = matches
1234 wanted.add(i)
1234 wanted.add(i)
1235
1235
1236 class followfilter(object):
1236 class followfilter(object):
1237 def __init__(self, onlyfirst=False):
1237 def __init__(self, onlyfirst=False):
1238 self.startrev = nullrev
1238 self.startrev = nullrev
1239 self.roots = set()
1239 self.roots = set()
1240 self.onlyfirst = onlyfirst
1240 self.onlyfirst = onlyfirst
1241
1241
1242 def match(self, rev):
1242 def match(self, rev):
1243 def realparents(rev):
1243 def realparents(rev):
1244 if self.onlyfirst:
1244 if self.onlyfirst:
1245 return repo.changelog.parentrevs(rev)[0:1]
1245 return repo.changelog.parentrevs(rev)[0:1]
1246 else:
1246 else:
1247 return filter(lambda x: x != nullrev,
1247 return filter(lambda x: x != nullrev,
1248 repo.changelog.parentrevs(rev))
1248 repo.changelog.parentrevs(rev))
1249
1249
1250 if self.startrev == nullrev:
1250 if self.startrev == nullrev:
1251 self.startrev = rev
1251 self.startrev = rev
1252 return True
1252 return True
1253
1253
1254 if rev > self.startrev:
1254 if rev > self.startrev:
1255 # forward: all descendants
1255 # forward: all descendants
1256 if not self.roots:
1256 if not self.roots:
1257 self.roots.add(self.startrev)
1257 self.roots.add(self.startrev)
1258 for parent in realparents(rev):
1258 for parent in realparents(rev):
1259 if parent in self.roots:
1259 if parent in self.roots:
1260 self.roots.add(rev)
1260 self.roots.add(rev)
1261 return True
1261 return True
1262 else:
1262 else:
1263 # backwards: all parents
1263 # backwards: all parents
1264 if not self.roots:
1264 if not self.roots:
1265 self.roots.update(realparents(self.startrev))
1265 self.roots.update(realparents(self.startrev))
1266 if rev in self.roots:
1266 if rev in self.roots:
1267 self.roots.remove(rev)
1267 self.roots.remove(rev)
1268 self.roots.update(realparents(rev))
1268 self.roots.update(realparents(rev))
1269 return True
1269 return True
1270
1270
1271 return False
1271 return False
1272
1272
1273 # it might be worthwhile to do this in the iterator if the rev range
1273 # it might be worthwhile to do this in the iterator if the rev range
1274 # is descending and the prune args are all within that range
1274 # is descending and the prune args are all within that range
1275 for rev in opts.get('prune', ()):
1275 for rev in opts.get('prune', ()):
1276 rev = repo.changelog.rev(repo.lookup(rev))
1276 rev = repo.changelog.rev(repo.lookup(rev))
1277 ff = followfilter()
1277 ff = followfilter()
1278 stop = min(revs[0], revs[-1])
1278 stop = min(revs[0], revs[-1])
1279 for x in xrange(rev, stop - 1, -1):
1279 for x in xrange(rev, stop - 1, -1):
1280 if ff.match(x):
1280 if ff.match(x):
1281 wanted.discard(x)
1281 wanted.discard(x)
1282
1282
1283 # Now that wanted is correctly initialized, we can iterate over the
1283 # Now that wanted is correctly initialized, we can iterate over the
1284 # revision range, yielding only revisions in wanted.
1284 # revision range, yielding only revisions in wanted.
1285 def iterate():
1285 def iterate():
1286 if follow and not match.files():
1286 if follow and not match.files():
1287 ff = followfilter(onlyfirst=opts.get('follow_first'))
1287 ff = followfilter(onlyfirst=opts.get('follow_first'))
1288 def want(rev):
1288 def want(rev):
1289 return ff.match(rev) and rev in wanted
1289 return ff.match(rev) and rev in wanted
1290 else:
1290 else:
1291 def want(rev):
1291 def want(rev):
1292 return rev in wanted
1292 return rev in wanted
1293
1293
1294 for i, window in increasing_windows(0, len(revs)):
1294 for i, window in increasing_windows(0, len(revs)):
1295 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1295 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1296 for rev in sorted(nrevs):
1296 for rev in sorted(nrevs):
1297 fns = fncache.get(rev)
1297 fns = fncache.get(rev)
1298 ctx = change(rev)
1298 ctx = change(rev)
1299 if not fns:
1299 if not fns:
1300 def fns_generator():
1300 def fns_generator():
1301 for f in ctx.files():
1301 for f in ctx.files():
1302 if match(f):
1302 if match(f):
1303 yield f
1303 yield f
1304 fns = fns_generator()
1304 fns = fns_generator()
1305 prepare(ctx, fns)
1305 prepare(ctx, fns)
1306 for rev in nrevs:
1306 for rev in nrevs:
1307 yield change(rev)
1307 yield change(rev)
1308 return iterate()
1308 return iterate()
1309
1309
1310 def add(ui, repo, match, dryrun, listsubrepos, prefix):
1310 def add(ui, repo, match, dryrun, listsubrepos, prefix):
1311 join = lambda f: os.path.join(prefix, f)
1311 join = lambda f: os.path.join(prefix, f)
1312 bad = []
1312 bad = []
1313 oldbad = match.bad
1313 oldbad = match.bad
1314 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1314 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1315 names = []
1315 names = []
1316 wctx = repo[None]
1316 wctx = repo[None]
1317 wctx.status(clean=True)
1317 wctx.status(clean=True)
1318 existing = None
1318 existing = None
1319 if scmutil.showportabilityalert(ui):
1319 if scmutil.showportabilityalert(ui):
1320 existing = dict([(fn.lower(), fn) for fn in
1320 existing = dict([(fn.lower(), fn) for fn in
1321 wctx.added() + wctx.clean() + wctx.modified()])
1321 wctx.added() + wctx.clean() + wctx.modified()])
1322 for f in repo.walk(match):
1322 for f in repo.walk(match):
1323 exact = match.exact(f)
1323 exact = match.exact(f)
1324 if exact or f not in repo.dirstate:
1324 if exact or f not in repo.dirstate:
1325 if existing:
1325 if existing:
1326 scmutil.checkcasecollision(ui, f, existing)
1326 scmutil.checkcasecollision(ui, f, existing)
1327 names.append(f)
1327 names.append(f)
1328 if ui.verbose or not exact:
1328 if ui.verbose or not exact:
1329 ui.status(_('adding %s\n') % match.rel(join(f)))
1329 ui.status(_('adding %s\n') % match.rel(join(f)))
1330
1330
1331 if listsubrepos:
1331 if listsubrepos:
1332 for subpath in wctx.substate:
1332 for subpath in wctx.substate:
1333 sub = wctx.sub(subpath)
1333 sub = wctx.sub(subpath)
1334 try:
1334 try:
1335 submatch = matchmod.narrowmatcher(subpath, match)
1335 submatch = matchmod.narrowmatcher(subpath, match)
1336 bad.extend(sub.add(ui, submatch, dryrun, prefix))
1336 bad.extend(sub.add(ui, submatch, dryrun, prefix))
1337 except error.LookupError:
1337 except error.LookupError:
1338 ui.status(_("skipping missing subrepository: %s\n")
1338 ui.status(_("skipping missing subrepository: %s\n")
1339 % join(subpath))
1339 % join(subpath))
1340
1340
1341 if not dryrun:
1341 if not dryrun:
1342 rejected = wctx.add(names, prefix)
1342 rejected = wctx.add(names, prefix)
1343 bad.extend(f for f in rejected if f in match.files())
1343 bad.extend(f for f in rejected if f in match.files())
1344 return bad
1344 return bad
1345
1345
1346 def commit(ui, repo, commitfunc, pats, opts):
1346 def commit(ui, repo, commitfunc, pats, opts):
1347 '''commit the specified files or all outstanding changes'''
1347 '''commit the specified files or all outstanding changes'''
1348 date = opts.get('date')
1348 date = opts.get('date')
1349 if date:
1349 if date:
1350 opts['date'] = util.parsedate(date)
1350 opts['date'] = util.parsedate(date)
1351 message = logmessage(opts)
1351 message = logmessage(opts)
1352
1352
1353 # extract addremove carefully -- this function can be called from a command
1353 # extract addremove carefully -- this function can be called from a command
1354 # that doesn't support addremove
1354 # that doesn't support addremove
1355 if opts.get('addremove'):
1355 if opts.get('addremove'):
1356 addremove(repo, pats, opts)
1356 addremove(repo, pats, opts)
1357
1357
1358 return commitfunc(ui, repo, message, match(repo, pats, opts), opts)
1358 return commitfunc(ui, repo, message, match(repo, pats, opts), opts)
1359
1359
1360 def commiteditor(repo, ctx, subs):
1360 def commiteditor(repo, ctx, subs):
1361 if ctx.description():
1361 if ctx.description():
1362 return ctx.description()
1362 return ctx.description()
1363 return commitforceeditor(repo, ctx, subs)
1363 return commitforceeditor(repo, ctx, subs)
1364
1364
1365 def commitforceeditor(repo, ctx, subs):
1365 def commitforceeditor(repo, ctx, subs):
1366 edittext = []
1366 edittext = []
1367 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1367 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1368 if ctx.description():
1368 if ctx.description():
1369 edittext.append(ctx.description())
1369 edittext.append(ctx.description())
1370 edittext.append("")
1370 edittext.append("")
1371 edittext.append("") # Empty line between message and comments.
1371 edittext.append("") # Empty line between message and comments.
1372 edittext.append(_("HG: Enter commit message."
1372 edittext.append(_("HG: Enter commit message."
1373 " Lines beginning with 'HG:' are removed."))
1373 " Lines beginning with 'HG:' are removed."))
1374 edittext.append(_("HG: Leave message empty to abort commit."))
1374 edittext.append(_("HG: Leave message empty to abort commit."))
1375 edittext.append("HG: --")
1375 edittext.append("HG: --")
1376 edittext.append(_("HG: user: %s") % ctx.user())
1376 edittext.append(_("HG: user: %s") % ctx.user())
1377 if ctx.p2():
1377 if ctx.p2():
1378 edittext.append(_("HG: branch merge"))
1378 edittext.append(_("HG: branch merge"))
1379 if ctx.branch():
1379 if ctx.branch():
1380 edittext.append(_("HG: branch '%s'") % ctx.branch())
1380 edittext.append(_("HG: branch '%s'") % ctx.branch())
1381 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1381 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1382 edittext.extend([_("HG: added %s") % f for f in added])
1382 edittext.extend([_("HG: added %s") % f for f in added])
1383 edittext.extend([_("HG: changed %s") % f for f in modified])
1383 edittext.extend([_("HG: changed %s") % f for f in modified])
1384 edittext.extend([_("HG: removed %s") % f for f in removed])
1384 edittext.extend([_("HG: removed %s") % f for f in removed])
1385 if not added and not modified and not removed:
1385 if not added and not modified and not removed:
1386 edittext.append(_("HG: no files changed"))
1386 edittext.append(_("HG: no files changed"))
1387 edittext.append("")
1387 edittext.append("")
1388 # run editor in the repository root
1388 # run editor in the repository root
1389 olddir = os.getcwd()
1389 olddir = os.getcwd()
1390 os.chdir(repo.root)
1390 os.chdir(repo.root)
1391 text = repo.ui.edit("\n".join(edittext), ctx.user())
1391 text = repo.ui.edit("\n".join(edittext), ctx.user())
1392 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1392 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1393 os.chdir(olddir)
1393 os.chdir(olddir)
1394
1394
1395 if not text.strip():
1395 if not text.strip():
1396 raise util.Abort(_("empty commit message"))
1396 raise util.Abort(_("empty commit message"))
1397
1397
1398 return text
1398 return text
@@ -1,4872 +1,4875
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, sys, difflib, time, tempfile
11 import os, re, sys, difflib, time, tempfile
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
15 import merge as mergemod
15 import merge as mergemod
16 import minirst, revset, templatefilters
16 import minirst, revset, templatefilters
17 import dagparser
17 import dagparser
18
18
19 # Commands start here, listed alphabetically
19 # Commands start here, listed alphabetically
20
20
21 def add(ui, repo, *pats, **opts):
21 def add(ui, repo, *pats, **opts):
22 """add the specified files on the next commit
22 """add the specified files on the next commit
23
23
24 Schedule files to be version controlled and added to the
24 Schedule files to be version controlled and added to the
25 repository.
25 repository.
26
26
27 The files will be added to the repository at the next commit. To
27 The files will be added to the repository at the next commit. To
28 undo an add before that, see :hg:`forget`.
28 undo an add before that, see :hg:`forget`.
29
29
30 If no names are given, add all files to the repository.
30 If no names are given, add all files to the repository.
31
31
32 .. container:: verbose
32 .. container:: verbose
33
33
34 An example showing how new (unknown) files are added
34 An example showing how new (unknown) files are added
35 automatically by :hg:`add`::
35 automatically by :hg:`add`::
36
36
37 $ ls
37 $ ls
38 foo.c
38 foo.c
39 $ hg status
39 $ hg status
40 ? foo.c
40 ? foo.c
41 $ hg add
41 $ hg add
42 adding foo.c
42 adding foo.c
43 $ hg status
43 $ hg status
44 A foo.c
44 A foo.c
45
45
46 Returns 0 if all files are successfully added.
46 Returns 0 if all files are successfully added.
47 """
47 """
48
48
49 m = cmdutil.match(repo, pats, opts)
49 m = cmdutil.match(repo, pats, opts)
50 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
50 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
51 opts.get('subrepos'), prefix="")
51 opts.get('subrepos'), prefix="")
52 return rejected and 1 or 0
52 return rejected and 1 or 0
53
53
54 def addremove(ui, repo, *pats, **opts):
54 def addremove(ui, repo, *pats, **opts):
55 """add all new files, delete all missing files
55 """add all new files, delete all missing files
56
56
57 Add all new files and remove all missing files from the
57 Add all new files and remove all missing files from the
58 repository.
58 repository.
59
59
60 New files are ignored if they match any of the patterns in
60 New files are ignored if they match any of the patterns in
61 ``.hgignore``. As with add, these changes take effect at the next
61 ``.hgignore``. As with add, these changes take effect at the next
62 commit.
62 commit.
63
63
64 Use the -s/--similarity option to detect renamed files. With a
64 Use the -s/--similarity option to detect renamed files. With a
65 parameter greater than 0, this compares every removed file with
65 parameter greater than 0, this compares every removed file with
66 every added file and records those similar enough as renames. This
66 every added file and records those similar enough as renames. This
67 option takes a percentage between 0 (disabled) and 100 (files must
67 option takes a percentage between 0 (disabled) and 100 (files must
68 be identical) as its parameter. Detecting renamed files this way
68 be identical) as its parameter. Detecting renamed files this way
69 can be expensive. After using this option, :hg:`status -C` can be
69 can be expensive. After using this option, :hg:`status -C` can be
70 used to check which files were identified as moved or renamed.
70 used to check which files were identified as moved or renamed.
71
71
72 Returns 0 if all files are successfully added.
72 Returns 0 if all files are successfully added.
73 """
73 """
74 try:
74 try:
75 sim = float(opts.get('similarity') or 100)
75 sim = float(opts.get('similarity') or 100)
76 except ValueError:
76 except ValueError:
77 raise util.Abort(_('similarity must be a number'))
77 raise util.Abort(_('similarity must be a number'))
78 if sim < 0 or sim > 100:
78 if sim < 0 or sim > 100:
79 raise util.Abort(_('similarity must be between 0 and 100'))
79 raise util.Abort(_('similarity must be between 0 and 100'))
80 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
80 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
81
81
82 def annotate(ui, repo, *pats, **opts):
82 def annotate(ui, repo, *pats, **opts):
83 """show changeset information by line for each file
83 """show changeset information by line for each file
84
84
85 List changes in files, showing the revision id responsible for
85 List changes in files, showing the revision id responsible for
86 each line
86 each line
87
87
88 This command is useful for discovering when a change was made and
88 This command is useful for discovering when a change was made and
89 by whom.
89 by whom.
90
90
91 Without the -a/--text option, annotate will avoid processing files
91 Without the -a/--text option, annotate will avoid processing files
92 it detects as binary. With -a, annotate will annotate the file
92 it detects as binary. With -a, annotate will annotate the file
93 anyway, although the results will probably be neither useful
93 anyway, although the results will probably be neither useful
94 nor desirable.
94 nor desirable.
95
95
96 Returns 0 on success.
96 Returns 0 on success.
97 """
97 """
98 if opts.get('follow'):
98 if opts.get('follow'):
99 # --follow is deprecated and now just an alias for -f/--file
99 # --follow is deprecated and now just an alias for -f/--file
100 # to mimic the behavior of Mercurial before version 1.5
100 # to mimic the behavior of Mercurial before version 1.5
101 opts['file'] = 1
101 opts['file'] = 1
102
102
103 datefunc = ui.quiet and util.shortdate or util.datestr
103 datefunc = ui.quiet and util.shortdate or util.datestr
104 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
104 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
105
105
106 if not pats:
106 if not pats:
107 raise util.Abort(_('at least one filename or pattern is required'))
107 raise util.Abort(_('at least one filename or pattern is required'))
108
108
109 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
109 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
110 ('number', lambda x: str(x[0].rev())),
110 ('number', lambda x: str(x[0].rev())),
111 ('changeset', lambda x: short(x[0].node())),
111 ('changeset', lambda x: short(x[0].node())),
112 ('date', getdate),
112 ('date', getdate),
113 ('file', lambda x: x[0].path()),
113 ('file', lambda x: x[0].path()),
114 ]
114 ]
115
115
116 if (not opts.get('user') and not opts.get('changeset')
116 if (not opts.get('user') and not opts.get('changeset')
117 and not opts.get('date') and not opts.get('file')):
117 and not opts.get('date') and not opts.get('file')):
118 opts['number'] = 1
118 opts['number'] = 1
119
119
120 linenumber = opts.get('line_number') is not None
120 linenumber = opts.get('line_number') is not None
121 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
121 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
122 raise util.Abort(_('at least one of -n/-c is required for -l'))
122 raise util.Abort(_('at least one of -n/-c is required for -l'))
123
123
124 funcmap = [func for op, func in opmap if opts.get(op)]
124 funcmap = [func for op, func in opmap if opts.get(op)]
125 if linenumber:
125 if linenumber:
126 lastfunc = funcmap[-1]
126 lastfunc = funcmap[-1]
127 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
127 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
128
128
129 def bad(x, y):
129 def bad(x, y):
130 raise util.Abort("%s: %s" % (x, y))
130 raise util.Abort("%s: %s" % (x, y))
131
131
132 ctx = cmdutil.revsingle(repo, opts.get('rev'))
132 ctx = cmdutil.revsingle(repo, opts.get('rev'))
133 m = cmdutil.match(repo, pats, opts)
133 m = cmdutil.match(repo, pats, opts)
134 m.bad = bad
134 m.bad = bad
135 follow = not opts.get('no_follow')
135 follow = not opts.get('no_follow')
136 for abs in ctx.walk(m):
136 for abs in ctx.walk(m):
137 fctx = ctx[abs]
137 fctx = ctx[abs]
138 if not opts.get('text') and util.binary(fctx.data()):
138 if not opts.get('text') and util.binary(fctx.data()):
139 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
139 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
140 continue
140 continue
141
141
142 lines = fctx.annotate(follow=follow, linenumber=linenumber)
142 lines = fctx.annotate(follow=follow, linenumber=linenumber)
143 pieces = []
143 pieces = []
144
144
145 for f in funcmap:
145 for f in funcmap:
146 l = [f(n) for n, dummy in lines]
146 l = [f(n) for n, dummy in lines]
147 if l:
147 if l:
148 sized = [(x, encoding.colwidth(x)) for x in l]
148 sized = [(x, encoding.colwidth(x)) for x in l]
149 ml = max([w for x, w in sized])
149 ml = max([w for x, w in sized])
150 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
150 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
151
151
152 if pieces:
152 if pieces:
153 for p, l in zip(zip(*pieces), lines):
153 for p, l in zip(zip(*pieces), lines):
154 ui.write("%s: %s" % (" ".join(p), l[1]))
154 ui.write("%s: %s" % (" ".join(p), l[1]))
155
155
156 def archive(ui, repo, dest, **opts):
156 def archive(ui, repo, dest, **opts):
157 '''create an unversioned archive of a repository revision
157 '''create an unversioned archive of a repository revision
158
158
159 By default, the revision used is the parent of the working
159 By default, the revision used is the parent of the working
160 directory; use -r/--rev to specify a different revision.
160 directory; use -r/--rev to specify a different revision.
161
161
162 The archive type is automatically detected based on file
162 The archive type is automatically detected based on file
163 extension (or override using -t/--type).
163 extension (or override using -t/--type).
164
164
165 Valid types are:
165 Valid types are:
166
166
167 :``files``: a directory full of files (default)
167 :``files``: a directory full of files (default)
168 :``tar``: tar archive, uncompressed
168 :``tar``: tar archive, uncompressed
169 :``tbz2``: tar archive, compressed using bzip2
169 :``tbz2``: tar archive, compressed using bzip2
170 :``tgz``: tar archive, compressed using gzip
170 :``tgz``: tar archive, compressed using gzip
171 :``uzip``: zip archive, uncompressed
171 :``uzip``: zip archive, uncompressed
172 :``zip``: zip archive, compressed using deflate
172 :``zip``: zip archive, compressed using deflate
173
173
174 The exact name of the destination archive or directory is given
174 The exact name of the destination archive or directory is given
175 using a format string; see :hg:`help export` for details.
175 using a format string; see :hg:`help export` for details.
176
176
177 Each member added to an archive file has a directory prefix
177 Each member added to an archive file has a directory prefix
178 prepended. Use -p/--prefix to specify a format string for the
178 prepended. Use -p/--prefix to specify a format string for the
179 prefix. The default is the basename of the archive, with suffixes
179 prefix. The default is the basename of the archive, with suffixes
180 removed.
180 removed.
181
181
182 Returns 0 on success.
182 Returns 0 on success.
183 '''
183 '''
184
184
185 ctx = cmdutil.revsingle(repo, opts.get('rev'))
185 ctx = cmdutil.revsingle(repo, opts.get('rev'))
186 if not ctx:
186 if not ctx:
187 raise util.Abort(_('no working directory: please specify a revision'))
187 raise util.Abort(_('no working directory: please specify a revision'))
188 node = ctx.node()
188 node = ctx.node()
189 dest = cmdutil.make_filename(repo, dest, node)
189 dest = cmdutil.make_filename(repo, dest, node)
190 if os.path.realpath(dest) == repo.root:
190 if os.path.realpath(dest) == repo.root:
191 raise util.Abort(_('repository root cannot be destination'))
191 raise util.Abort(_('repository root cannot be destination'))
192
192
193 kind = opts.get('type') or archival.guesskind(dest) or 'files'
193 kind = opts.get('type') or archival.guesskind(dest) or 'files'
194 prefix = opts.get('prefix')
194 prefix = opts.get('prefix')
195
195
196 if dest == '-':
196 if dest == '-':
197 if kind == 'files':
197 if kind == 'files':
198 raise util.Abort(_('cannot archive plain files to stdout'))
198 raise util.Abort(_('cannot archive plain files to stdout'))
199 dest = sys.stdout
199 dest = sys.stdout
200 if not prefix:
200 if not prefix:
201 prefix = os.path.basename(repo.root) + '-%h'
201 prefix = os.path.basename(repo.root) + '-%h'
202
202
203 prefix = cmdutil.make_filename(repo, prefix, node)
203 prefix = cmdutil.make_filename(repo, prefix, node)
204 matchfn = cmdutil.match(repo, [], opts)
204 matchfn = cmdutil.match(repo, [], opts)
205 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
205 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
206 matchfn, prefix, subrepos=opts.get('subrepos'))
206 matchfn, prefix, subrepos=opts.get('subrepos'))
207
207
208 def backout(ui, repo, node=None, rev=None, **opts):
208 def backout(ui, repo, node=None, rev=None, **opts):
209 '''reverse effect of earlier changeset
209 '''reverse effect of earlier changeset
210
210
211 Prepare a new changeset with the effect of REV undone in the
211 Prepare a new changeset with the effect of REV undone in the
212 current working directory.
212 current working directory.
213
213
214 If REV is the parent of the working directory, then this new changeset
214 If REV is the parent of the working directory, then this new changeset
215 is committed automatically. Otherwise, hg needs to merge the
215 is committed automatically. Otherwise, hg needs to merge the
216 changes and the merged result is left uncommitted.
216 changes and the merged result is left uncommitted.
217
217
218 By default, the pending changeset will have one parent,
218 By default, the pending changeset will have one parent,
219 maintaining a linear history. With --merge, the pending changeset
219 maintaining a linear history. With --merge, the pending changeset
220 will instead have two parents: the old parent of the working
220 will instead have two parents: the old parent of the working
221 directory and a new child of REV that simply undoes REV.
221 directory and a new child of REV that simply undoes REV.
222
222
223 Before version 1.7, the behavior without --merge was equivalent to
223 Before version 1.7, the behavior without --merge was equivalent to
224 specifying --merge followed by :hg:`update --clean .` to cancel
224 specifying --merge followed by :hg:`update --clean .` to cancel
225 the merge and leave the child of REV as a head to be merged
225 the merge and leave the child of REV as a head to be merged
226 separately.
226 separately.
227
227
228 See :hg:`help dates` for a list of formats valid for -d/--date.
228 See :hg:`help dates` for a list of formats valid for -d/--date.
229
229
230 Returns 0 on success.
230 Returns 0 on success.
231 '''
231 '''
232 if rev and node:
232 if rev and node:
233 raise util.Abort(_("please specify just one revision"))
233 raise util.Abort(_("please specify just one revision"))
234
234
235 if not rev:
235 if not rev:
236 rev = node
236 rev = node
237
237
238 if not rev:
238 if not rev:
239 raise util.Abort(_("please specify a revision to backout"))
239 raise util.Abort(_("please specify a revision to backout"))
240
240
241 date = opts.get('date')
241 date = opts.get('date')
242 if date:
242 if date:
243 opts['date'] = util.parsedate(date)
243 opts['date'] = util.parsedate(date)
244
244
245 cmdutil.bail_if_changed(repo)
245 cmdutil.bail_if_changed(repo)
246 node = cmdutil.revsingle(repo, rev).node()
246 node = cmdutil.revsingle(repo, rev).node()
247
247
248 op1, op2 = repo.dirstate.parents()
248 op1, op2 = repo.dirstate.parents()
249 a = repo.changelog.ancestor(op1, node)
249 a = repo.changelog.ancestor(op1, node)
250 if a != node:
250 if a != node:
251 raise util.Abort(_('cannot backout change on a different branch'))
251 raise util.Abort(_('cannot backout change on a different branch'))
252
252
253 p1, p2 = repo.changelog.parents(node)
253 p1, p2 = repo.changelog.parents(node)
254 if p1 == nullid:
254 if p1 == nullid:
255 raise util.Abort(_('cannot backout a change with no parents'))
255 raise util.Abort(_('cannot backout a change with no parents'))
256 if p2 != nullid:
256 if p2 != nullid:
257 if not opts.get('parent'):
257 if not opts.get('parent'):
258 raise util.Abort(_('cannot backout a merge changeset without '
258 raise util.Abort(_('cannot backout a merge changeset without '
259 '--parent'))
259 '--parent'))
260 p = repo.lookup(opts['parent'])
260 p = repo.lookup(opts['parent'])
261 if p not in (p1, p2):
261 if p not in (p1, p2):
262 raise util.Abort(_('%s is not a parent of %s') %
262 raise util.Abort(_('%s is not a parent of %s') %
263 (short(p), short(node)))
263 (short(p), short(node)))
264 parent = p
264 parent = p
265 else:
265 else:
266 if opts.get('parent'):
266 if opts.get('parent'):
267 raise util.Abort(_('cannot use --parent on non-merge changeset'))
267 raise util.Abort(_('cannot use --parent on non-merge changeset'))
268 parent = p1
268 parent = p1
269
269
270 # the backout should appear on the same branch
270 # the backout should appear on the same branch
271 branch = repo.dirstate.branch()
271 branch = repo.dirstate.branch()
272 hg.clean(repo, node, show_stats=False)
272 hg.clean(repo, node, show_stats=False)
273 repo.dirstate.setbranch(branch)
273 repo.dirstate.setbranch(branch)
274 revert_opts = opts.copy()
274 revert_opts = opts.copy()
275 revert_opts['date'] = None
275 revert_opts['date'] = None
276 revert_opts['all'] = True
276 revert_opts['all'] = True
277 revert_opts['rev'] = hex(parent)
277 revert_opts['rev'] = hex(parent)
278 revert_opts['no_backup'] = None
278 revert_opts['no_backup'] = None
279 revert(ui, repo, **revert_opts)
279 revert(ui, repo, **revert_opts)
280 if not opts.get('merge') and op1 != node:
280 if not opts.get('merge') and op1 != node:
281 try:
281 try:
282 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
282 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
283 return hg.update(repo, op1)
283 return hg.update(repo, op1)
284 finally:
284 finally:
285 ui.setconfig('ui', 'forcemerge', '')
285 ui.setconfig('ui', 'forcemerge', '')
286
286
287 commit_opts = opts.copy()
287 commit_opts = opts.copy()
288 commit_opts['addremove'] = False
288 commit_opts['addremove'] = False
289 if not commit_opts['message'] and not commit_opts['logfile']:
289 if not commit_opts['message'] and not commit_opts['logfile']:
290 # we don't translate commit messages
290 # we don't translate commit messages
291 commit_opts['message'] = "Backed out changeset %s" % short(node)
291 commit_opts['message'] = "Backed out changeset %s" % short(node)
292 commit_opts['force_editor'] = True
292 commit_opts['force_editor'] = True
293 commit(ui, repo, **commit_opts)
293 commit(ui, repo, **commit_opts)
294 def nice(node):
294 def nice(node):
295 return '%d:%s' % (repo.changelog.rev(node), short(node))
295 return '%d:%s' % (repo.changelog.rev(node), short(node))
296 ui.status(_('changeset %s backs out changeset %s\n') %
296 ui.status(_('changeset %s backs out changeset %s\n') %
297 (nice(repo.changelog.tip()), nice(node)))
297 (nice(repo.changelog.tip()), nice(node)))
298 if opts.get('merge') and op1 != node:
298 if opts.get('merge') and op1 != node:
299 hg.clean(repo, op1, show_stats=False)
299 hg.clean(repo, op1, show_stats=False)
300 ui.status(_('merging with changeset %s\n')
300 ui.status(_('merging with changeset %s\n')
301 % nice(repo.changelog.tip()))
301 % nice(repo.changelog.tip()))
302 try:
302 try:
303 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
303 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
304 return hg.merge(repo, hex(repo.changelog.tip()))
304 return hg.merge(repo, hex(repo.changelog.tip()))
305 finally:
305 finally:
306 ui.setconfig('ui', 'forcemerge', '')
306 ui.setconfig('ui', 'forcemerge', '')
307 return 0
307 return 0
308
308
309 def bisect(ui, repo, rev=None, extra=None, command=None,
309 def bisect(ui, repo, rev=None, extra=None, command=None,
310 reset=None, good=None, bad=None, skip=None, extend=None,
310 reset=None, good=None, bad=None, skip=None, extend=None,
311 noupdate=None):
311 noupdate=None):
312 """subdivision search of changesets
312 """subdivision search of changesets
313
313
314 This command helps to find changesets which introduce problems. To
314 This command helps to find changesets which introduce problems. To
315 use, mark the earliest changeset you know exhibits the problem as
315 use, mark the earliest changeset you know exhibits the problem as
316 bad, then mark the latest changeset which is free from the problem
316 bad, then mark the latest changeset which is free from the problem
317 as good. Bisect will update your working directory to a revision
317 as good. Bisect will update your working directory to a revision
318 for testing (unless the -U/--noupdate option is specified). Once
318 for testing (unless the -U/--noupdate option is specified). Once
319 you have performed tests, mark the working directory as good or
319 you have performed tests, mark the working directory as good or
320 bad, and bisect will either update to another candidate changeset
320 bad, and bisect will either update to another candidate changeset
321 or announce that it has found the bad revision.
321 or announce that it has found the bad revision.
322
322
323 As a shortcut, you can also use the revision argument to mark a
323 As a shortcut, you can also use the revision argument to mark a
324 revision as good or bad without checking it out first.
324 revision as good or bad without checking it out first.
325
325
326 If you supply a command, it will be used for automatic bisection.
326 If you supply a command, it will be used for automatic bisection.
327 Its exit status will be used to mark revisions as good or bad:
327 Its exit status will be used to mark revisions as good or bad:
328 status 0 means good, 125 means to skip the revision, 127
328 status 0 means good, 125 means to skip the revision, 127
329 (command not found) will abort the bisection, and any other
329 (command not found) will abort the bisection, and any other
330 non-zero exit status means the revision is bad.
330 non-zero exit status means the revision is bad.
331
331
332 Returns 0 on success.
332 Returns 0 on success.
333 """
333 """
334 def extendbisectrange(nodes, good):
334 def extendbisectrange(nodes, good):
335 # bisect is incomplete when it ends on a merge node and
335 # bisect is incomplete when it ends on a merge node and
336 # one of the parent was not checked.
336 # one of the parent was not checked.
337 parents = repo[nodes[0]].parents()
337 parents = repo[nodes[0]].parents()
338 if len(parents) > 1:
338 if len(parents) > 1:
339 side = good and state['bad'] or state['good']
339 side = good and state['bad'] or state['good']
340 num = len(set(i.node() for i in parents) & set(side))
340 num = len(set(i.node() for i in parents) & set(side))
341 if num == 1:
341 if num == 1:
342 return parents[0].ancestor(parents[1])
342 return parents[0].ancestor(parents[1])
343 return None
343 return None
344
344
345 def print_result(nodes, good):
345 def print_result(nodes, good):
346 displayer = cmdutil.show_changeset(ui, repo, {})
346 displayer = cmdutil.show_changeset(ui, repo, {})
347 if len(nodes) == 1:
347 if len(nodes) == 1:
348 # narrowed it down to a single revision
348 # narrowed it down to a single revision
349 if good:
349 if good:
350 ui.write(_("The first good revision is:\n"))
350 ui.write(_("The first good revision is:\n"))
351 else:
351 else:
352 ui.write(_("The first bad revision is:\n"))
352 ui.write(_("The first bad revision is:\n"))
353 displayer.show(repo[nodes[0]])
353 displayer.show(repo[nodes[0]])
354 extendnode = extendbisectrange(nodes, good)
354 extendnode = extendbisectrange(nodes, good)
355 if extendnode is not None:
355 if extendnode is not None:
356 ui.write(_('Not all ancestors of this changeset have been'
356 ui.write(_('Not all ancestors of this changeset have been'
357 ' checked.\nUse bisect --extend to continue the '
357 ' checked.\nUse bisect --extend to continue the '
358 'bisection from\nthe common ancestor, %s.\n')
358 'bisection from\nthe common ancestor, %s.\n')
359 % extendnode)
359 % extendnode)
360 else:
360 else:
361 # multiple possible revisions
361 # multiple possible revisions
362 if good:
362 if good:
363 ui.write(_("Due to skipped revisions, the first "
363 ui.write(_("Due to skipped revisions, the first "
364 "good revision could be any of:\n"))
364 "good revision could be any of:\n"))
365 else:
365 else:
366 ui.write(_("Due to skipped revisions, the first "
366 ui.write(_("Due to skipped revisions, the first "
367 "bad revision could be any of:\n"))
367 "bad revision could be any of:\n"))
368 for n in nodes:
368 for n in nodes:
369 displayer.show(repo[n])
369 displayer.show(repo[n])
370 displayer.close()
370 displayer.close()
371
371
372 def check_state(state, interactive=True):
372 def check_state(state, interactive=True):
373 if not state['good'] or not state['bad']:
373 if not state['good'] or not state['bad']:
374 if (good or bad or skip or reset) and interactive:
374 if (good or bad or skip or reset) and interactive:
375 return
375 return
376 if not state['good']:
376 if not state['good']:
377 raise util.Abort(_('cannot bisect (no known good revisions)'))
377 raise util.Abort(_('cannot bisect (no known good revisions)'))
378 else:
378 else:
379 raise util.Abort(_('cannot bisect (no known bad revisions)'))
379 raise util.Abort(_('cannot bisect (no known bad revisions)'))
380 return True
380 return True
381
381
382 # backward compatibility
382 # backward compatibility
383 if rev in "good bad reset init".split():
383 if rev in "good bad reset init".split():
384 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
384 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
385 cmd, rev, extra = rev, extra, None
385 cmd, rev, extra = rev, extra, None
386 if cmd == "good":
386 if cmd == "good":
387 good = True
387 good = True
388 elif cmd == "bad":
388 elif cmd == "bad":
389 bad = True
389 bad = True
390 else:
390 else:
391 reset = True
391 reset = True
392 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
392 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
393 raise util.Abort(_('incompatible arguments'))
393 raise util.Abort(_('incompatible arguments'))
394
394
395 if reset:
395 if reset:
396 p = repo.join("bisect.state")
396 p = repo.join("bisect.state")
397 if os.path.exists(p):
397 if os.path.exists(p):
398 os.unlink(p)
398 os.unlink(p)
399 return
399 return
400
400
401 state = hbisect.load_state(repo)
401 state = hbisect.load_state(repo)
402
402
403 if command:
403 if command:
404 changesets = 1
404 changesets = 1
405 try:
405 try:
406 while changesets:
406 while changesets:
407 # update state
407 # update state
408 status = util.system(command)
408 status = util.system(command)
409 if status == 125:
409 if status == 125:
410 transition = "skip"
410 transition = "skip"
411 elif status == 0:
411 elif status == 0:
412 transition = "good"
412 transition = "good"
413 # status < 0 means process was killed
413 # status < 0 means process was killed
414 elif status == 127:
414 elif status == 127:
415 raise util.Abort(_("failed to execute %s") % command)
415 raise util.Abort(_("failed to execute %s") % command)
416 elif status < 0:
416 elif status < 0:
417 raise util.Abort(_("%s killed") % command)
417 raise util.Abort(_("%s killed") % command)
418 else:
418 else:
419 transition = "bad"
419 transition = "bad"
420 ctx = cmdutil.revsingle(repo, rev)
420 ctx = cmdutil.revsingle(repo, rev)
421 rev = None # clear for future iterations
421 rev = None # clear for future iterations
422 state[transition].append(ctx.node())
422 state[transition].append(ctx.node())
423 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
423 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
424 check_state(state, interactive=False)
424 check_state(state, interactive=False)
425 # bisect
425 # bisect
426 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
426 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
427 # update to next check
427 # update to next check
428 cmdutil.bail_if_changed(repo)
428 cmdutil.bail_if_changed(repo)
429 hg.clean(repo, nodes[0], show_stats=False)
429 hg.clean(repo, nodes[0], show_stats=False)
430 finally:
430 finally:
431 hbisect.save_state(repo, state)
431 hbisect.save_state(repo, state)
432 print_result(nodes, good)
432 print_result(nodes, good)
433 return
433 return
434
434
435 # update state
435 # update state
436
436
437 if rev:
437 if rev:
438 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
438 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
439 else:
439 else:
440 nodes = [repo.lookup('.')]
440 nodes = [repo.lookup('.')]
441
441
442 if good or bad or skip:
442 if good or bad or skip:
443 if good:
443 if good:
444 state['good'] += nodes
444 state['good'] += nodes
445 elif bad:
445 elif bad:
446 state['bad'] += nodes
446 state['bad'] += nodes
447 elif skip:
447 elif skip:
448 state['skip'] += nodes
448 state['skip'] += nodes
449 hbisect.save_state(repo, state)
449 hbisect.save_state(repo, state)
450
450
451 if not check_state(state):
451 if not check_state(state):
452 return
452 return
453
453
454 # actually bisect
454 # actually bisect
455 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
455 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
456 if extend:
456 if extend:
457 if not changesets:
457 if not changesets:
458 extendnode = extendbisectrange(nodes, good)
458 extendnode = extendbisectrange(nodes, good)
459 if extendnode is not None:
459 if extendnode is not None:
460 ui.write(_("Extending search to changeset %d:%s\n"
460 ui.write(_("Extending search to changeset %d:%s\n"
461 % (extendnode.rev(), extendnode)))
461 % (extendnode.rev(), extendnode)))
462 if noupdate:
462 if noupdate:
463 return
463 return
464 cmdutil.bail_if_changed(repo)
464 cmdutil.bail_if_changed(repo)
465 return hg.clean(repo, extendnode.node())
465 return hg.clean(repo, extendnode.node())
466 raise util.Abort(_("nothing to extend"))
466 raise util.Abort(_("nothing to extend"))
467
467
468 if changesets == 0:
468 if changesets == 0:
469 print_result(nodes, good)
469 print_result(nodes, good)
470 else:
470 else:
471 assert len(nodes) == 1 # only a single node can be tested next
471 assert len(nodes) == 1 # only a single node can be tested next
472 node = nodes[0]
472 node = nodes[0]
473 # compute the approximate number of remaining tests
473 # compute the approximate number of remaining tests
474 tests, size = 0, 2
474 tests, size = 0, 2
475 while size <= changesets:
475 while size <= changesets:
476 tests, size = tests + 1, size * 2
476 tests, size = tests + 1, size * 2
477 rev = repo.changelog.rev(node)
477 rev = repo.changelog.rev(node)
478 ui.write(_("Testing changeset %d:%s "
478 ui.write(_("Testing changeset %d:%s "
479 "(%d changesets remaining, ~%d tests)\n")
479 "(%d changesets remaining, ~%d tests)\n")
480 % (rev, short(node), changesets, tests))
480 % (rev, short(node), changesets, tests))
481 if not noupdate:
481 if not noupdate:
482 cmdutil.bail_if_changed(repo)
482 cmdutil.bail_if_changed(repo)
483 return hg.clean(repo, node)
483 return hg.clean(repo, node)
484
484
485 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None):
485 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None):
486 '''track a line of development with movable markers
486 '''track a line of development with movable markers
487
487
488 Bookmarks are pointers to certain commits that move when
488 Bookmarks are pointers to certain commits that move when
489 committing. Bookmarks are local. They can be renamed, copied and
489 committing. Bookmarks are local. They can be renamed, copied and
490 deleted. It is possible to use bookmark names in :hg:`merge` and
490 deleted. It is possible to use bookmark names in :hg:`merge` and
491 :hg:`update` to merge and update respectively to a given bookmark.
491 :hg:`update` to merge and update respectively to a given bookmark.
492
492
493 You can use :hg:`bookmark NAME` to set a bookmark on the working
493 You can use :hg:`bookmark NAME` to set a bookmark on the working
494 directory's parent revision with the given name. If you specify
494 directory's parent revision with the given name. If you specify
495 a revision using -r REV (where REV may be an existing bookmark),
495 a revision using -r REV (where REV may be an existing bookmark),
496 the bookmark is assigned to that revision.
496 the bookmark is assigned to that revision.
497
497
498 Bookmarks can be pushed and pulled between repositories (see :hg:`help
498 Bookmarks can be pushed and pulled between repositories (see :hg:`help
499 push` and :hg:`help pull`). This requires both the local and remote
499 push` and :hg:`help pull`). This requires both the local and remote
500 repositories to support bookmarks. For versions prior to 1.8, this means
500 repositories to support bookmarks. For versions prior to 1.8, this means
501 the bookmarks extension must be enabled.
501 the bookmarks extension must be enabled.
502 '''
502 '''
503 hexfn = ui.debugflag and hex or short
503 hexfn = ui.debugflag and hex or short
504 marks = repo._bookmarks
504 marks = repo._bookmarks
505 cur = repo.changectx('.').node()
505 cur = repo.changectx('.').node()
506
506
507 if rename:
507 if rename:
508 if rename not in marks:
508 if rename not in marks:
509 raise util.Abort(_("bookmark '%s' does not exist") % rename)
509 raise util.Abort(_("bookmark '%s' does not exist") % rename)
510 if mark in marks and not force:
510 if mark in marks and not force:
511 raise util.Abort(_("bookmark '%s' already exists "
511 raise util.Abort(_("bookmark '%s' already exists "
512 "(use -f to force)") % mark)
512 "(use -f to force)") % mark)
513 if mark is None:
513 if mark is None:
514 raise util.Abort(_("new bookmark name required"))
514 raise util.Abort(_("new bookmark name required"))
515 marks[mark] = marks[rename]
515 marks[mark] = marks[rename]
516 if repo._bookmarkcurrent == rename:
516 if repo._bookmarkcurrent == rename:
517 bookmarks.setcurrent(repo, mark)
517 bookmarks.setcurrent(repo, mark)
518 del marks[rename]
518 del marks[rename]
519 bookmarks.write(repo)
519 bookmarks.write(repo)
520 return
520 return
521
521
522 if delete:
522 if delete:
523 if mark is None:
523 if mark is None:
524 raise util.Abort(_("bookmark name required"))
524 raise util.Abort(_("bookmark name required"))
525 if mark not in marks:
525 if mark not in marks:
526 raise util.Abort(_("bookmark '%s' does not exist") % mark)
526 raise util.Abort(_("bookmark '%s' does not exist") % mark)
527 if mark == repo._bookmarkcurrent:
527 if mark == repo._bookmarkcurrent:
528 bookmarks.setcurrent(repo, None)
528 bookmarks.setcurrent(repo, None)
529 del marks[mark]
529 del marks[mark]
530 bookmarks.write(repo)
530 bookmarks.write(repo)
531 return
531 return
532
532
533 if mark is not None:
533 if mark is not None:
534 if "\n" in mark:
534 if "\n" in mark:
535 raise util.Abort(_("bookmark name cannot contain newlines"))
535 raise util.Abort(_("bookmark name cannot contain newlines"))
536 mark = mark.strip()
536 mark = mark.strip()
537 if not mark:
537 if not mark:
538 raise util.Abort(_("bookmark names cannot consist entirely of "
538 raise util.Abort(_("bookmark names cannot consist entirely of "
539 "whitespace"))
539 "whitespace"))
540 if mark in marks and not force:
540 if mark in marks and not force:
541 raise util.Abort(_("bookmark '%s' already exists "
541 raise util.Abort(_("bookmark '%s' already exists "
542 "(use -f to force)") % mark)
542 "(use -f to force)") % mark)
543 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
543 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
544 and not force):
544 and not force):
545 raise util.Abort(
545 raise util.Abort(
546 _("a bookmark cannot have the name of an existing branch"))
546 _("a bookmark cannot have the name of an existing branch"))
547 if rev:
547 if rev:
548 marks[mark] = repo.lookup(rev)
548 marks[mark] = repo.lookup(rev)
549 else:
549 else:
550 marks[mark] = repo.changectx('.').node()
550 marks[mark] = repo.changectx('.').node()
551 if repo.changectx('.').node() == marks[mark]:
551 if repo.changectx('.').node() == marks[mark]:
552 bookmarks.setcurrent(repo, mark)
552 bookmarks.setcurrent(repo, mark)
553 bookmarks.write(repo)
553 bookmarks.write(repo)
554 return
554 return
555
555
556 if mark is None:
556 if mark is None:
557 if rev:
557 if rev:
558 raise util.Abort(_("bookmark name required"))
558 raise util.Abort(_("bookmark name required"))
559 if len(marks) == 0:
559 if len(marks) == 0:
560 ui.status(_("no bookmarks set\n"))
560 ui.status(_("no bookmarks set\n"))
561 else:
561 else:
562 for bmark, n in sorted(marks.iteritems()):
562 for bmark, n in sorted(marks.iteritems()):
563 current = repo._bookmarkcurrent
563 current = repo._bookmarkcurrent
564 if bmark == current and n == cur:
564 if bmark == current and n == cur:
565 prefix, label = '*', 'bookmarks.current'
565 prefix, label = '*', 'bookmarks.current'
566 else:
566 else:
567 prefix, label = ' ', ''
567 prefix, label = ' ', ''
568
568
569 if ui.quiet:
569 if ui.quiet:
570 ui.write("%s\n" % bmark, label=label)
570 ui.write("%s\n" % bmark, label=label)
571 else:
571 else:
572 ui.write(" %s %-25s %d:%s\n" % (
572 ui.write(" %s %-25s %d:%s\n" % (
573 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
573 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
574 label=label)
574 label=label)
575 return
575 return
576
576
577 def branch(ui, repo, label=None, **opts):
577 def branch(ui, repo, label=None, **opts):
578 """set or show the current branch name
578 """set or show the current branch name
579
579
580 With no argument, show the current branch name. With one argument,
580 With no argument, show the current branch name. With one argument,
581 set the working directory branch name (the branch will not exist
581 set the working directory branch name (the branch will not exist
582 in the repository until the next commit). Standard practice
582 in the repository until the next commit). Standard practice
583 recommends that primary development take place on the 'default'
583 recommends that primary development take place on the 'default'
584 branch.
584 branch.
585
585
586 Unless -f/--force is specified, branch will not let you set a
586 Unless -f/--force is specified, branch will not let you set a
587 branch name that already exists, even if it's inactive.
587 branch name that already exists, even if it's inactive.
588
588
589 Use -C/--clean to reset the working directory branch to that of
589 Use -C/--clean to reset the working directory branch to that of
590 the parent of the working directory, negating a previous branch
590 the parent of the working directory, negating a previous branch
591 change.
591 change.
592
592
593 Use the command :hg:`update` to switch to an existing branch. Use
593 Use the command :hg:`update` to switch to an existing branch. Use
594 :hg:`commit --close-branch` to mark this branch as closed.
594 :hg:`commit --close-branch` to mark this branch as closed.
595
595
596 Returns 0 on success.
596 Returns 0 on success.
597 """
597 """
598
598
599 if opts.get('clean'):
599 if opts.get('clean'):
600 label = repo[None].p1().branch()
600 label = repo[None].p1().branch()
601 repo.dirstate.setbranch(label)
601 repo.dirstate.setbranch(label)
602 ui.status(_('reset working directory to branch %s\n') % label)
602 ui.status(_('reset working directory to branch %s\n') % label)
603 elif label:
603 elif label:
604 if not opts.get('force') and label in repo.branchtags():
604 if not opts.get('force') and label in repo.branchtags():
605 if label not in [p.branch() for p in repo.parents()]:
605 if label not in [p.branch() for p in repo.parents()]:
606 raise util.Abort(_('a branch of the same name already exists'
606 raise util.Abort(_('a branch of the same name already exists'
607 " (use 'hg update' to switch to it)"))
607 " (use 'hg update' to switch to it)"))
608 repo.dirstate.setbranch(label)
608 repo.dirstate.setbranch(label)
609 ui.status(_('marked working directory as branch %s\n') % label)
609 ui.status(_('marked working directory as branch %s\n') % label)
610 else:
610 else:
611 ui.write("%s\n" % repo.dirstate.branch())
611 ui.write("%s\n" % repo.dirstate.branch())
612
612
613 def branches(ui, repo, active=False, closed=False):
613 def branches(ui, repo, active=False, closed=False):
614 """list repository named branches
614 """list repository named branches
615
615
616 List the repository's named branches, indicating which ones are
616 List the repository's named branches, indicating which ones are
617 inactive. If -c/--closed is specified, also list branches which have
617 inactive. If -c/--closed is specified, also list branches which have
618 been marked closed (see :hg:`commit --close-branch`).
618 been marked closed (see :hg:`commit --close-branch`).
619
619
620 If -a/--active is specified, only show active branches. A branch
620 If -a/--active is specified, only show active branches. A branch
621 is considered active if it contains repository heads.
621 is considered active if it contains repository heads.
622
622
623 Use the command :hg:`update` to switch to an existing branch.
623 Use the command :hg:`update` to switch to an existing branch.
624
624
625 Returns 0.
625 Returns 0.
626 """
626 """
627
627
628 hexfunc = ui.debugflag and hex or short
628 hexfunc = ui.debugflag and hex or short
629 activebranches = [repo[n].branch() for n in repo.heads()]
629 activebranches = [repo[n].branch() for n in repo.heads()]
630 def testactive(tag, node):
630 def testactive(tag, node):
631 realhead = tag in activebranches
631 realhead = tag in activebranches
632 open = node in repo.branchheads(tag, closed=False)
632 open = node in repo.branchheads(tag, closed=False)
633 return realhead and open
633 return realhead and open
634 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
634 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
635 for tag, node in repo.branchtags().items()],
635 for tag, node in repo.branchtags().items()],
636 reverse=True)
636 reverse=True)
637
637
638 for isactive, node, tag in branches:
638 for isactive, node, tag in branches:
639 if (not active) or isactive:
639 if (not active) or isactive:
640 if ui.quiet:
640 if ui.quiet:
641 ui.write("%s\n" % tag)
641 ui.write("%s\n" % tag)
642 else:
642 else:
643 hn = repo.lookup(node)
643 hn = repo.lookup(node)
644 if isactive:
644 if isactive:
645 label = 'branches.active'
645 label = 'branches.active'
646 notice = ''
646 notice = ''
647 elif hn not in repo.branchheads(tag, closed=False):
647 elif hn not in repo.branchheads(tag, closed=False):
648 if not closed:
648 if not closed:
649 continue
649 continue
650 label = 'branches.closed'
650 label = 'branches.closed'
651 notice = _(' (closed)')
651 notice = _(' (closed)')
652 else:
652 else:
653 label = 'branches.inactive'
653 label = 'branches.inactive'
654 notice = _(' (inactive)')
654 notice = _(' (inactive)')
655 if tag == repo.dirstate.branch():
655 if tag == repo.dirstate.branch():
656 label = 'branches.current'
656 label = 'branches.current'
657 rev = str(node).rjust(31 - encoding.colwidth(tag))
657 rev = str(node).rjust(31 - encoding.colwidth(tag))
658 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
658 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
659 tag = ui.label(tag, label)
659 tag = ui.label(tag, label)
660 ui.write("%s %s%s\n" % (tag, rev, notice))
660 ui.write("%s %s%s\n" % (tag, rev, notice))
661
661
662 def bundle(ui, repo, fname, dest=None, **opts):
662 def bundle(ui, repo, fname, dest=None, **opts):
663 """create a changegroup file
663 """create a changegroup file
664
664
665 Generate a compressed changegroup file collecting changesets not
665 Generate a compressed changegroup file collecting changesets not
666 known to be in another repository.
666 known to be in another repository.
667
667
668 If you omit the destination repository, then hg assumes the
668 If you omit the destination repository, then hg assumes the
669 destination will have all the nodes you specify with --base
669 destination will have all the nodes you specify with --base
670 parameters. To create a bundle containing all changesets, use
670 parameters. To create a bundle containing all changesets, use
671 -a/--all (or --base null).
671 -a/--all (or --base null).
672
672
673 You can change compression method with the -t/--type option.
673 You can change compression method with the -t/--type option.
674 The available compression methods are: none, bzip2, and
674 The available compression methods are: none, bzip2, and
675 gzip (by default, bundles are compressed using bzip2).
675 gzip (by default, bundles are compressed using bzip2).
676
676
677 The bundle file can then be transferred using conventional means
677 The bundle file can then be transferred using conventional means
678 and applied to another repository with the unbundle or pull
678 and applied to another repository with the unbundle or pull
679 command. This is useful when direct push and pull are not
679 command. This is useful when direct push and pull are not
680 available or when exporting an entire repository is undesirable.
680 available or when exporting an entire repository is undesirable.
681
681
682 Applying bundles preserves all changeset contents including
682 Applying bundles preserves all changeset contents including
683 permissions, copy/rename information, and revision history.
683 permissions, copy/rename information, and revision history.
684
684
685 Returns 0 on success, 1 if no changes found.
685 Returns 0 on success, 1 if no changes found.
686 """
686 """
687 revs = None
687 revs = None
688 if 'rev' in opts:
688 if 'rev' in opts:
689 revs = cmdutil.revrange(repo, opts['rev'])
689 revs = cmdutil.revrange(repo, opts['rev'])
690
690
691 if opts.get('all'):
691 if opts.get('all'):
692 base = ['null']
692 base = ['null']
693 else:
693 else:
694 base = cmdutil.revrange(repo, opts.get('base'))
694 base = cmdutil.revrange(repo, opts.get('base'))
695 if base:
695 if base:
696 if dest:
696 if dest:
697 raise util.Abort(_("--base is incompatible with specifying "
697 raise util.Abort(_("--base is incompatible with specifying "
698 "a destination"))
698 "a destination"))
699 common = [repo.lookup(rev) for rev in base]
699 common = [repo.lookup(rev) for rev in base]
700 else:
700 else:
701 dest = ui.expandpath(dest or 'default-push', dest or 'default')
701 dest = ui.expandpath(dest or 'default-push', dest or 'default')
702 dest, branches = hg.parseurl(dest, opts.get('branch'))
702 dest, branches = hg.parseurl(dest, opts.get('branch'))
703 other = hg.repository(hg.remoteui(repo, opts), dest)
703 other = hg.repository(hg.remoteui(repo, opts), dest)
704 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
704 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
705 inc = discovery.findcommonincoming(repo, other, force=opts.get('force'))
705 inc = discovery.findcommonincoming(repo, other, force=opts.get('force'))
706 common, _anyinc, _heads = inc
706 common, _anyinc, _heads = inc
707
707
708 nodes = revs and map(repo.lookup, revs) or revs
708 nodes = revs and map(repo.lookup, revs) or revs
709 cg = repo.getbundle('bundle', common=common, heads=nodes)
709 cg = repo.getbundle('bundle', common=common, heads=nodes)
710 if not cg:
710 if not cg:
711 ui.status(_("no changes found\n"))
711 ui.status(_("no changes found\n"))
712 return 1
712 return 1
713
713
714 bundletype = opts.get('type', 'bzip2').lower()
714 bundletype = opts.get('type', 'bzip2').lower()
715 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
715 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
716 bundletype = btypes.get(bundletype)
716 bundletype = btypes.get(bundletype)
717 if bundletype not in changegroup.bundletypes:
717 if bundletype not in changegroup.bundletypes:
718 raise util.Abort(_('unknown bundle type specified with --type'))
718 raise util.Abort(_('unknown bundle type specified with --type'))
719
719
720 changegroup.writebundle(cg, fname, bundletype)
720 changegroup.writebundle(cg, fname, bundletype)
721
721
722 def cat(ui, repo, file1, *pats, **opts):
722 def cat(ui, repo, file1, *pats, **opts):
723 """output the current or given revision of files
723 """output the current or given revision of files
724
724
725 Print the specified files as they were at the given revision. If
725 Print the specified files as they were at the given revision. If
726 no revision is given, the parent of the working directory is used,
726 no revision is given, the parent of the working directory is used,
727 or tip if no revision is checked out.
727 or tip if no revision is checked out.
728
728
729 Output may be to a file, in which case the name of the file is
729 Output may be to a file, in which case the name of the file is
730 given using a format string. The formatting rules are the same as
730 given using a format string. The formatting rules are the same as
731 for the export command, with the following additions:
731 for the export command, with the following additions:
732
732
733 :``%s``: basename of file being printed
733 :``%s``: basename of file being printed
734 :``%d``: dirname of file being printed, or '.' if in repository root
734 :``%d``: dirname of file being printed, or '.' if in repository root
735 :``%p``: root-relative path name of file being printed
735 :``%p``: root-relative path name of file being printed
736
736
737 Returns 0 on success.
737 Returns 0 on success.
738 """
738 """
739 ctx = cmdutil.revsingle(repo, opts.get('rev'))
739 ctx = cmdutil.revsingle(repo, opts.get('rev'))
740 err = 1
740 err = 1
741 m = cmdutil.match(repo, (file1,) + pats, opts)
741 m = cmdutil.match(repo, (file1,) + pats, opts)
742 for abs in ctx.walk(m):
742 for abs in ctx.walk(m):
743 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
743 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
744 data = ctx[abs].data()
744 data = ctx[abs].data()
745 if opts.get('decode'):
745 if opts.get('decode'):
746 data = repo.wwritedata(abs, data)
746 data = repo.wwritedata(abs, data)
747 fp.write(data)
747 fp.write(data)
748 fp.close()
748 fp.close()
749 err = 0
749 err = 0
750 return err
750 return err
751
751
752 def clone(ui, source, dest=None, **opts):
752 def clone(ui, source, dest=None, **opts):
753 """make a copy of an existing repository
753 """make a copy of an existing repository
754
754
755 Create a copy of an existing repository in a new directory.
755 Create a copy of an existing repository in a new directory.
756
756
757 If no destination directory name is specified, it defaults to the
757 If no destination directory name is specified, it defaults to the
758 basename of the source.
758 basename of the source.
759
759
760 The location of the source is added to the new repository's
760 The location of the source is added to the new repository's
761 ``.hg/hgrc`` file, as the default to be used for future pulls.
761 ``.hg/hgrc`` file, as the default to be used for future pulls.
762
762
763 See :hg:`help urls` for valid source format details.
763 See :hg:`help urls` for valid source format details.
764
764
765 It is possible to specify an ``ssh://`` URL as the destination, but no
765 It is possible to specify an ``ssh://`` URL as the destination, but no
766 ``.hg/hgrc`` and working directory will be created on the remote side.
766 ``.hg/hgrc`` and working directory will be created on the remote side.
767 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
767 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
768
768
769 A set of changesets (tags, or branch names) to pull may be specified
769 A set of changesets (tags, or branch names) to pull may be specified
770 by listing each changeset (tag, or branch name) with -r/--rev.
770 by listing each changeset (tag, or branch name) with -r/--rev.
771 If -r/--rev is used, the cloned repository will contain only a subset
771 If -r/--rev is used, the cloned repository will contain only a subset
772 of the changesets of the source repository. Only the set of changesets
772 of the changesets of the source repository. Only the set of changesets
773 defined by all -r/--rev options (including all their ancestors)
773 defined by all -r/--rev options (including all their ancestors)
774 will be pulled into the destination repository.
774 will be pulled into the destination repository.
775 No subsequent changesets (including subsequent tags) will be present
775 No subsequent changesets (including subsequent tags) will be present
776 in the destination.
776 in the destination.
777
777
778 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
778 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
779 local source repositories.
779 local source repositories.
780
780
781 For efficiency, hardlinks are used for cloning whenever the source
781 For efficiency, hardlinks are used for cloning whenever the source
782 and destination are on the same filesystem (note this applies only
782 and destination are on the same filesystem (note this applies only
783 to the repository data, not to the working directory). Some
783 to the repository data, not to the working directory). Some
784 filesystems, such as AFS, implement hardlinking incorrectly, but
784 filesystems, such as AFS, implement hardlinking incorrectly, but
785 do not report errors. In these cases, use the --pull option to
785 do not report errors. In these cases, use the --pull option to
786 avoid hardlinking.
786 avoid hardlinking.
787
787
788 In some cases, you can clone repositories and the working directory
788 In some cases, you can clone repositories and the working directory
789 using full hardlinks with ::
789 using full hardlinks with ::
790
790
791 $ cp -al REPO REPOCLONE
791 $ cp -al REPO REPOCLONE
792
792
793 This is the fastest way to clone, but it is not always safe. The
793 This is the fastest way to clone, but it is not always safe. The
794 operation is not atomic (making sure REPO is not modified during
794 operation is not atomic (making sure REPO is not modified during
795 the operation is up to you) and you have to make sure your editor
795 the operation is up to you) and you have to make sure your editor
796 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
796 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
797 this is not compatible with certain extensions that place their
797 this is not compatible with certain extensions that place their
798 metadata under the .hg directory, such as mq.
798 metadata under the .hg directory, such as mq.
799
799
800 Mercurial will update the working directory to the first applicable
800 Mercurial will update the working directory to the first applicable
801 revision from this list:
801 revision from this list:
802
802
803 a) null if -U or the source repository has no changesets
803 a) null if -U or the source repository has no changesets
804 b) if -u . and the source repository is local, the first parent of
804 b) if -u . and the source repository is local, the first parent of
805 the source repository's working directory
805 the source repository's working directory
806 c) the changeset specified with -u (if a branch name, this means the
806 c) the changeset specified with -u (if a branch name, this means the
807 latest head of that branch)
807 latest head of that branch)
808 d) the changeset specified with -r
808 d) the changeset specified with -r
809 e) the tipmost head specified with -b
809 e) the tipmost head specified with -b
810 f) the tipmost head specified with the url#branch source syntax
810 f) the tipmost head specified with the url#branch source syntax
811 g) the tipmost head of the default branch
811 g) the tipmost head of the default branch
812 h) tip
812 h) tip
813
813
814 Returns 0 on success.
814 Returns 0 on success.
815 """
815 """
816 if opts.get('noupdate') and opts.get('updaterev'):
816 if opts.get('noupdate') and opts.get('updaterev'):
817 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
817 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
818
818
819 r = hg.clone(hg.remoteui(ui, opts), source, dest,
819 r = hg.clone(hg.remoteui(ui, opts), source, dest,
820 pull=opts.get('pull'),
820 pull=opts.get('pull'),
821 stream=opts.get('uncompressed'),
821 stream=opts.get('uncompressed'),
822 rev=opts.get('rev'),
822 rev=opts.get('rev'),
823 update=opts.get('updaterev') or not opts.get('noupdate'),
823 update=opts.get('updaterev') or not opts.get('noupdate'),
824 branch=opts.get('branch'))
824 branch=opts.get('branch'))
825
825
826 return r is None
826 return r is None
827
827
828 def commit(ui, repo, *pats, **opts):
828 def commit(ui, repo, *pats, **opts):
829 """commit the specified files or all outstanding changes
829 """commit the specified files or all outstanding changes
830
830
831 Commit changes to the given files into the repository. Unlike a
831 Commit changes to the given files into the repository. Unlike a
832 centralized SCM, this operation is a local operation. See
832 centralized SCM, this operation is a local operation. See
833 :hg:`push` for a way to actively distribute your changes.
833 :hg:`push` for a way to actively distribute your changes.
834
834
835 If a list of files is omitted, all changes reported by :hg:`status`
835 If a list of files is omitted, all changes reported by :hg:`status`
836 will be committed.
836 will be committed.
837
837
838 If you are committing the result of a merge, do not provide any
838 If you are committing the result of a merge, do not provide any
839 filenames or -I/-X filters.
839 filenames or -I/-X filters.
840
840
841 If no commit message is specified, Mercurial starts your
841 If no commit message is specified, Mercurial starts your
842 configured editor where you can enter a message. In case your
842 configured editor where you can enter a message. In case your
843 commit fails, you will find a backup of your message in
843 commit fails, you will find a backup of your message in
844 ``.hg/last-message.txt``.
844 ``.hg/last-message.txt``.
845
845
846 See :hg:`help dates` for a list of formats valid for -d/--date.
846 See :hg:`help dates` for a list of formats valid for -d/--date.
847
847
848 Returns 0 on success, 1 if nothing changed.
848 Returns 0 on success, 1 if nothing changed.
849 """
849 """
850 extra = {}
850 extra = {}
851 if opts.get('close_branch'):
851 if opts.get('close_branch'):
852 if repo['.'].node() not in repo.branchheads():
852 if repo['.'].node() not in repo.branchheads():
853 # The topo heads set is included in the branch heads set of the
853 # The topo heads set is included in the branch heads set of the
854 # current branch, so it's sufficient to test branchheads
854 # current branch, so it's sufficient to test branchheads
855 raise util.Abort(_('can only close branch heads'))
855 raise util.Abort(_('can only close branch heads'))
856 extra['close'] = 1
856 extra['close'] = 1
857 e = cmdutil.commiteditor
857 e = cmdutil.commiteditor
858 if opts.get('force_editor'):
858 if opts.get('force_editor'):
859 e = cmdutil.commitforceeditor
859 e = cmdutil.commitforceeditor
860
860
861 def commitfunc(ui, repo, message, match, opts):
861 def commitfunc(ui, repo, message, match, opts):
862 return repo.commit(message, opts.get('user'), opts.get('date'), match,
862 return repo.commit(message, opts.get('user'), opts.get('date'), match,
863 editor=e, extra=extra)
863 editor=e, extra=extra)
864
864
865 branch = repo[None].branch()
865 branch = repo[None].branch()
866 bheads = repo.branchheads(branch)
866 bheads = repo.branchheads(branch)
867
867
868 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
868 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
869 if not node:
869 if not node:
870 stat = repo.status(match=cmdutil.match(repo, pats, opts))
870 stat = repo.status(match=cmdutil.match(repo, pats, opts))
871 if stat[3]:
871 if stat[3]:
872 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
872 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
873 % len(stat[3]))
873 % len(stat[3]))
874 else:
874 else:
875 ui.status(_("nothing changed\n"))
875 ui.status(_("nothing changed\n"))
876 return 1
876 return 1
877
877
878 ctx = repo[node]
878 ctx = repo[node]
879 parents = ctx.parents()
879 parents = ctx.parents()
880
880
881 if bheads and not [x for x in parents
881 if bheads and not [x for x in parents
882 if x.node() in bheads and x.branch() == branch]:
882 if x.node() in bheads and x.branch() == branch]:
883 ui.status(_('created new head\n'))
883 ui.status(_('created new head\n'))
884 # The message is not printed for initial roots. For the other
884 # The message is not printed for initial roots. For the other
885 # changesets, it is printed in the following situations:
885 # changesets, it is printed in the following situations:
886 #
886 #
887 # Par column: for the 2 parents with ...
887 # Par column: for the 2 parents with ...
888 # N: null or no parent
888 # N: null or no parent
889 # B: parent is on another named branch
889 # B: parent is on another named branch
890 # C: parent is a regular non head changeset
890 # C: parent is a regular non head changeset
891 # H: parent was a branch head of the current branch
891 # H: parent was a branch head of the current branch
892 # Msg column: whether we print "created new head" message
892 # Msg column: whether we print "created new head" message
893 # In the following, it is assumed that there already exists some
893 # In the following, it is assumed that there already exists some
894 # initial branch heads of the current branch, otherwise nothing is
894 # initial branch heads of the current branch, otherwise nothing is
895 # printed anyway.
895 # printed anyway.
896 #
896 #
897 # Par Msg Comment
897 # Par Msg Comment
898 # NN y additional topo root
898 # NN y additional topo root
899 #
899 #
900 # BN y additional branch root
900 # BN y additional branch root
901 # CN y additional topo head
901 # CN y additional topo head
902 # HN n usual case
902 # HN n usual case
903 #
903 #
904 # BB y weird additional branch root
904 # BB y weird additional branch root
905 # CB y branch merge
905 # CB y branch merge
906 # HB n merge with named branch
906 # HB n merge with named branch
907 #
907 #
908 # CC y additional head from merge
908 # CC y additional head from merge
909 # CH n merge with a head
909 # CH n merge with a head
910 #
910 #
911 # HH n head merge: head count decreases
911 # HH n head merge: head count decreases
912
912
913 if not opts.get('close_branch'):
913 if not opts.get('close_branch'):
914 for r in parents:
914 for r in parents:
915 if r.extra().get('close') and r.branch() == branch:
915 if r.extra().get('close') and r.branch() == branch:
916 ui.status(_('reopening closed branch head %d\n') % r)
916 ui.status(_('reopening closed branch head %d\n') % r)
917
917
918 if ui.debugflag:
918 if ui.debugflag:
919 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
919 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
920 elif ui.verbose:
920 elif ui.verbose:
921 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
921 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
922
922
923 def copy(ui, repo, *pats, **opts):
923 def copy(ui, repo, *pats, **opts):
924 """mark files as copied for the next commit
924 """mark files as copied for the next commit
925
925
926 Mark dest as having copies of source files. If dest is a
926 Mark dest as having copies of source files. If dest is a
927 directory, copies are put in that directory. If dest is a file,
927 directory, copies are put in that directory. If dest is a file,
928 the source must be a single file.
928 the source must be a single file.
929
929
930 By default, this command copies the contents of files as they
930 By default, this command copies the contents of files as they
931 exist in the working directory. If invoked with -A/--after, the
931 exist in the working directory. If invoked with -A/--after, the
932 operation is recorded, but no copying is performed.
932 operation is recorded, but no copying is performed.
933
933
934 This command takes effect with the next commit. To undo a copy
934 This command takes effect with the next commit. To undo a copy
935 before that, see :hg:`revert`.
935 before that, see :hg:`revert`.
936
936
937 Returns 0 on success, 1 if errors are encountered.
937 Returns 0 on success, 1 if errors are encountered.
938 """
938 """
939 wlock = repo.wlock(False)
939 wlock = repo.wlock(False)
940 try:
940 try:
941 return cmdutil.copy(ui, repo, pats, opts)
941 return cmdutil.copy(ui, repo, pats, opts)
942 finally:
942 finally:
943 wlock.release()
943 wlock.release()
944
944
945 def debugancestor(ui, repo, *args):
945 def debugancestor(ui, repo, *args):
946 """find the ancestor revision of two revisions in a given index"""
946 """find the ancestor revision of two revisions in a given index"""
947 if len(args) == 3:
947 if len(args) == 3:
948 index, rev1, rev2 = args
948 index, rev1, rev2 = args
949 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
949 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
950 lookup = r.lookup
950 lookup = r.lookup
951 elif len(args) == 2:
951 elif len(args) == 2:
952 if not repo:
952 if not repo:
953 raise util.Abort(_("there is no Mercurial repository here "
953 raise util.Abort(_("there is no Mercurial repository here "
954 "(.hg not found)"))
954 "(.hg not found)"))
955 rev1, rev2 = args
955 rev1, rev2 = args
956 r = repo.changelog
956 r = repo.changelog
957 lookup = repo.lookup
957 lookup = repo.lookup
958 else:
958 else:
959 raise util.Abort(_('either two or three arguments required'))
959 raise util.Abort(_('either two or three arguments required'))
960 a = r.ancestor(lookup(rev1), lookup(rev2))
960 a = r.ancestor(lookup(rev1), lookup(rev2))
961 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
961 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
962
962
963 def debugbuilddag(ui, repo, text,
963 def debugbuilddag(ui, repo, text,
964 mergeable_file=False,
964 mergeable_file=False,
965 appended_file=False,
965 appended_file=False,
966 overwritten_file=False,
966 overwritten_file=False,
967 new_file=False):
967 new_file=False):
968 """builds a repo with a given dag from scratch in the current empty repo
968 """builds a repo with a given dag from scratch in the current empty repo
969
969
970 Elements:
970 Elements:
971
971
972 - "+n" is a linear run of n nodes based on the current default parent
972 - "+n" is a linear run of n nodes based on the current default parent
973 - "." is a single node based on the current default parent
973 - "." is a single node based on the current default parent
974 - "$" resets the default parent to null (implied at the start);
974 - "$" resets the default parent to null (implied at the start);
975 otherwise the default parent is always the last node created
975 otherwise the default parent is always the last node created
976 - "<p" sets the default parent to the backref p
976 - "<p" sets the default parent to the backref p
977 - "*p" is a fork at parent p, which is a backref
977 - "*p" is a fork at parent p, which is a backref
978 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
978 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
979 - "/p2" is a merge of the preceding node and p2
979 - "/p2" is a merge of the preceding node and p2
980 - ":tag" defines a local tag for the preceding node
980 - ":tag" defines a local tag for the preceding node
981 - "@branch" sets the named branch for subsequent nodes
981 - "@branch" sets the named branch for subsequent nodes
982 - "!command" runs the command using your shell
982 - "!command" runs the command using your shell
983 - "!!my command\\n" is like "!", but to the end of the line
983 - "!!my command\\n" is like "!", but to the end of the line
984 - "#...\\n" is a comment up to the end of the line
984 - "#...\\n" is a comment up to the end of the line
985
985
986 Whitespace between the above elements is ignored.
986 Whitespace between the above elements is ignored.
987
987
988 A backref is either
988 A backref is either
989
989
990 - a number n, which references the node curr-n, where curr is the current
990 - a number n, which references the node curr-n, where curr is the current
991 node, or
991 node, or
992 - the name of a local tag you placed earlier using ":tag", or
992 - the name of a local tag you placed earlier using ":tag", or
993 - empty to denote the default parent.
993 - empty to denote the default parent.
994
994
995 All string valued-elements are either strictly alphanumeric, or must
995 All string valued-elements are either strictly alphanumeric, or must
996 be enclosed in double quotes ("..."), with "\\" as escape character.
996 be enclosed in double quotes ("..."), with "\\" as escape character.
997
997
998 Note that the --overwritten-file and --appended-file options imply the
998 Note that the --overwritten-file and --appended-file options imply the
999 use of "HGMERGE=internal:local" during DAG buildup.
999 use of "HGMERGE=internal:local" during DAG buildup.
1000 """
1000 """
1001
1001
1002 if not (mergeable_file or appended_file or overwritten_file or new_file):
1002 if not (mergeable_file or appended_file or overwritten_file or new_file):
1003 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
1003 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
1004
1004
1005 if len(repo.changelog) > 0:
1005 if len(repo.changelog) > 0:
1006 raise util.Abort(_('repository is not empty'))
1006 raise util.Abort(_('repository is not empty'))
1007
1007
1008 if overwritten_file or appended_file:
1008 if overwritten_file or appended_file:
1009 # we don't want to fail in merges during buildup
1009 # we don't want to fail in merges during buildup
1010 os.environ['HGMERGE'] = 'internal:local'
1010 os.environ['HGMERGE'] = 'internal:local'
1011
1011
1012 def writefile(fname, text, fmode="wb"):
1012 def writefile(fname, text, fmode="wb"):
1013 f = open(fname, fmode)
1013 f = open(fname, fmode)
1014 try:
1014 try:
1015 f.write(text)
1015 f.write(text)
1016 finally:
1016 finally:
1017 f.close()
1017 f.close()
1018
1018
1019 if mergeable_file:
1019 if mergeable_file:
1020 linesperrev = 2
1020 linesperrev = 2
1021 # determine number of revs in DAG
1021 # determine number of revs in DAG
1022 n = 0
1022 n = 0
1023 for type, data in dagparser.parsedag(text):
1023 for type, data in dagparser.parsedag(text):
1024 if type == 'n':
1024 if type == 'n':
1025 n += 1
1025 n += 1
1026 # make a file with k lines per rev
1026 # make a file with k lines per rev
1027 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
1027 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
1028 + "\n")
1028 + "\n")
1029
1029
1030 at = -1
1030 at = -1
1031 atbranch = 'default'
1031 atbranch = 'default'
1032 for type, data in dagparser.parsedag(text):
1032 for type, data in dagparser.parsedag(text):
1033 if type == 'n':
1033 if type == 'n':
1034 ui.status('node %s\n' % str(data))
1034 ui.status('node %s\n' % str(data))
1035 id, ps = data
1035 id, ps = data
1036 p1 = ps[0]
1036 p1 = ps[0]
1037 if p1 != at:
1037 if p1 != at:
1038 update(ui, repo, node=str(p1), clean=True)
1038 update(ui, repo, node=str(p1), clean=True)
1039 at = p1
1039 at = p1
1040 if repo.dirstate.branch() != atbranch:
1040 if repo.dirstate.branch() != atbranch:
1041 branch(ui, repo, atbranch, force=True)
1041 branch(ui, repo, atbranch, force=True)
1042 if len(ps) > 1:
1042 if len(ps) > 1:
1043 p2 = ps[1]
1043 p2 = ps[1]
1044 merge(ui, repo, node=p2)
1044 merge(ui, repo, node=p2)
1045
1045
1046 if mergeable_file:
1046 if mergeable_file:
1047 f = open("mf", "rb+")
1047 f = open("mf", "rb+")
1048 try:
1048 try:
1049 lines = f.read().split("\n")
1049 lines = f.read().split("\n")
1050 lines[id * linesperrev] += " r%i" % id
1050 lines[id * linesperrev] += " r%i" % id
1051 f.seek(0)
1051 f.seek(0)
1052 f.write("\n".join(lines))
1052 f.write("\n".join(lines))
1053 finally:
1053 finally:
1054 f.close()
1054 f.close()
1055
1055
1056 if appended_file:
1056 if appended_file:
1057 writefile("af", "r%i\n" % id, "ab")
1057 writefile("af", "r%i\n" % id, "ab")
1058
1058
1059 if overwritten_file:
1059 if overwritten_file:
1060 writefile("of", "r%i\n" % id)
1060 writefile("of", "r%i\n" % id)
1061
1061
1062 if new_file:
1062 if new_file:
1063 writefile("nf%i" % id, "r%i\n" % id)
1063 writefile("nf%i" % id, "r%i\n" % id)
1064
1064
1065 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
1065 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
1066 at = id
1066 at = id
1067 elif type == 'l':
1067 elif type == 'l':
1068 id, name = data
1068 id, name = data
1069 ui.status('tag %s\n' % name)
1069 ui.status('tag %s\n' % name)
1070 tag(ui, repo, name, local=True)
1070 tag(ui, repo, name, local=True)
1071 elif type == 'a':
1071 elif type == 'a':
1072 ui.status('branch %s\n' % data)
1072 ui.status('branch %s\n' % data)
1073 atbranch = data
1073 atbranch = data
1074 elif type in 'cC':
1074 elif type in 'cC':
1075 r = util.system(data, cwd=repo.root)
1075 r = util.system(data, cwd=repo.root)
1076 if r:
1076 if r:
1077 desc, r = util.explain_exit(r)
1077 desc, r = util.explain_exit(r)
1078 raise util.Abort(_('%s command %s') % (data, desc))
1078 raise util.Abort(_('%s command %s') % (data, desc))
1079
1079
1080 def debugcommands(ui, cmd='', *args):
1080 def debugcommands(ui, cmd='', *args):
1081 """list all available commands and options"""
1081 """list all available commands and options"""
1082 for cmd, vals in sorted(table.iteritems()):
1082 for cmd, vals in sorted(table.iteritems()):
1083 cmd = cmd.split('|')[0].strip('^')
1083 cmd = cmd.split('|')[0].strip('^')
1084 opts = ', '.join([i[1] for i in vals[1]])
1084 opts = ', '.join([i[1] for i in vals[1]])
1085 ui.write('%s: %s\n' % (cmd, opts))
1085 ui.write('%s: %s\n' % (cmd, opts))
1086
1086
1087 def debugcomplete(ui, cmd='', **opts):
1087 def debugcomplete(ui, cmd='', **opts):
1088 """returns the completion list associated with the given command"""
1088 """returns the completion list associated with the given command"""
1089
1089
1090 if opts.get('options'):
1090 if opts.get('options'):
1091 options = []
1091 options = []
1092 otables = [globalopts]
1092 otables = [globalopts]
1093 if cmd:
1093 if cmd:
1094 aliases, entry = cmdutil.findcmd(cmd, table, False)
1094 aliases, entry = cmdutil.findcmd(cmd, table, False)
1095 otables.append(entry[1])
1095 otables.append(entry[1])
1096 for t in otables:
1096 for t in otables:
1097 for o in t:
1097 for o in t:
1098 if "(DEPRECATED)" in o[3]:
1098 if "(DEPRECATED)" in o[3]:
1099 continue
1099 continue
1100 if o[0]:
1100 if o[0]:
1101 options.append('-%s' % o[0])
1101 options.append('-%s' % o[0])
1102 options.append('--%s' % o[1])
1102 options.append('--%s' % o[1])
1103 ui.write("%s\n" % "\n".join(options))
1103 ui.write("%s\n" % "\n".join(options))
1104 return
1104 return
1105
1105
1106 cmdlist = cmdutil.findpossible(cmd, table)
1106 cmdlist = cmdutil.findpossible(cmd, table)
1107 if ui.verbose:
1107 if ui.verbose:
1108 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1108 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1109 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1109 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1110
1110
1111 def debugfsinfo(ui, path = "."):
1111 def debugfsinfo(ui, path = "."):
1112 """show information detected about current filesystem"""
1112 """show information detected about current filesystem"""
1113 open('.debugfsinfo', 'w').write('')
1113 open('.debugfsinfo', 'w').write('')
1114 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1114 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1115 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1115 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1116 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1116 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1117 and 'yes' or 'no'))
1117 and 'yes' or 'no'))
1118 os.unlink('.debugfsinfo')
1118 os.unlink('.debugfsinfo')
1119
1119
1120 def debugrebuildstate(ui, repo, rev="tip"):
1120 def debugrebuildstate(ui, repo, rev="tip"):
1121 """rebuild the dirstate as it would look like for the given revision"""
1121 """rebuild the dirstate as it would look like for the given revision"""
1122 ctx = cmdutil.revsingle(repo, rev)
1122 ctx = cmdutil.revsingle(repo, rev)
1123 wlock = repo.wlock()
1123 wlock = repo.wlock()
1124 try:
1124 try:
1125 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1125 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1126 finally:
1126 finally:
1127 wlock.release()
1127 wlock.release()
1128
1128
1129 def debugcheckstate(ui, repo):
1129 def debugcheckstate(ui, repo):
1130 """validate the correctness of the current dirstate"""
1130 """validate the correctness of the current dirstate"""
1131 parent1, parent2 = repo.dirstate.parents()
1131 parent1, parent2 = repo.dirstate.parents()
1132 m1 = repo[parent1].manifest()
1132 m1 = repo[parent1].manifest()
1133 m2 = repo[parent2].manifest()
1133 m2 = repo[parent2].manifest()
1134 errors = 0
1134 errors = 0
1135 for f in repo.dirstate:
1135 for f in repo.dirstate:
1136 state = repo.dirstate[f]
1136 state = repo.dirstate[f]
1137 if state in "nr" and f not in m1:
1137 if state in "nr" and f not in m1:
1138 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1138 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1139 errors += 1
1139 errors += 1
1140 if state in "a" and f in m1:
1140 if state in "a" and f in m1:
1141 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1141 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1142 errors += 1
1142 errors += 1
1143 if state in "m" and f not in m1 and f not in m2:
1143 if state in "m" and f not in m1 and f not in m2:
1144 ui.warn(_("%s in state %s, but not in either manifest\n") %
1144 ui.warn(_("%s in state %s, but not in either manifest\n") %
1145 (f, state))
1145 (f, state))
1146 errors += 1
1146 errors += 1
1147 for f in m1:
1147 for f in m1:
1148 state = repo.dirstate[f]
1148 state = repo.dirstate[f]
1149 if state not in "nrm":
1149 if state not in "nrm":
1150 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1150 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1151 errors += 1
1151 errors += 1
1152 if errors:
1152 if errors:
1153 error = _(".hg/dirstate inconsistent with current parent's manifest")
1153 error = _(".hg/dirstate inconsistent with current parent's manifest")
1154 raise util.Abort(error)
1154 raise util.Abort(error)
1155
1155
1156 def showconfig(ui, repo, *values, **opts):
1156 def showconfig(ui, repo, *values, **opts):
1157 """show combined config settings from all hgrc files
1157 """show combined config settings from all hgrc files
1158
1158
1159 With no arguments, print names and values of all config items.
1159 With no arguments, print names and values of all config items.
1160
1160
1161 With one argument of the form section.name, print just the value
1161 With one argument of the form section.name, print just the value
1162 of that config item.
1162 of that config item.
1163
1163
1164 With multiple arguments, print names and values of all config
1164 With multiple arguments, print names and values of all config
1165 items with matching section names.
1165 items with matching section names.
1166
1166
1167 With --debug, the source (filename and line number) is printed
1167 With --debug, the source (filename and line number) is printed
1168 for each config item.
1168 for each config item.
1169
1169
1170 Returns 0 on success.
1170 Returns 0 on success.
1171 """
1171 """
1172
1172
1173 for f in scmutil.rcpath():
1173 for f in scmutil.rcpath():
1174 ui.debug(_('read config from: %s\n') % f)
1174 ui.debug(_('read config from: %s\n') % f)
1175 untrusted = bool(opts.get('untrusted'))
1175 untrusted = bool(opts.get('untrusted'))
1176 if values:
1176 if values:
1177 sections = [v for v in values if '.' not in v]
1177 sections = [v for v in values if '.' not in v]
1178 items = [v for v in values if '.' in v]
1178 items = [v for v in values if '.' in v]
1179 if len(items) > 1 or items and sections:
1179 if len(items) > 1 or items and sections:
1180 raise util.Abort(_('only one config item permitted'))
1180 raise util.Abort(_('only one config item permitted'))
1181 for section, name, value in ui.walkconfig(untrusted=untrusted):
1181 for section, name, value in ui.walkconfig(untrusted=untrusted):
1182 value = str(value).replace('\n', '\\n')
1182 value = str(value).replace('\n', '\\n')
1183 sectname = section + '.' + name
1183 sectname = section + '.' + name
1184 if values:
1184 if values:
1185 for v in values:
1185 for v in values:
1186 if v == section:
1186 if v == section:
1187 ui.debug('%s: ' %
1187 ui.debug('%s: ' %
1188 ui.configsource(section, name, untrusted))
1188 ui.configsource(section, name, untrusted))
1189 ui.write('%s=%s\n' % (sectname, value))
1189 ui.write('%s=%s\n' % (sectname, value))
1190 elif v == sectname:
1190 elif v == sectname:
1191 ui.debug('%s: ' %
1191 ui.debug('%s: ' %
1192 ui.configsource(section, name, untrusted))
1192 ui.configsource(section, name, untrusted))
1193 ui.write(value, '\n')
1193 ui.write(value, '\n')
1194 else:
1194 else:
1195 ui.debug('%s: ' %
1195 ui.debug('%s: ' %
1196 ui.configsource(section, name, untrusted))
1196 ui.configsource(section, name, untrusted))
1197 ui.write('%s=%s\n' % (sectname, value))
1197 ui.write('%s=%s\n' % (sectname, value))
1198
1198
1199 def debugknown(ui, repopath, *ids, **opts):
1199 def debugknown(ui, repopath, *ids, **opts):
1200 """test whether node ids are known to a repo
1200 """test whether node ids are known to a repo
1201
1201
1202 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1202 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1203 indicating unknown/known.
1203 indicating unknown/known.
1204 """
1204 """
1205 repo = hg.repository(ui, repopath)
1205 repo = hg.repository(ui, repopath)
1206 if not repo.capable('known'):
1206 if not repo.capable('known'):
1207 raise util.Abort("known() not supported by target repository")
1207 raise util.Abort("known() not supported by target repository")
1208 flags = repo.known([bin(s) for s in ids])
1208 flags = repo.known([bin(s) for s in ids])
1209 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1209 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1210
1210
1211 def debugbundle(ui, bundlepath, all=None, **opts):
1211 def debugbundle(ui, bundlepath, all=None, **opts):
1212 """lists the contents of a bundle"""
1212 """lists the contents of a bundle"""
1213 f = url.open(ui, bundlepath)
1213 f = url.open(ui, bundlepath)
1214 try:
1214 try:
1215 gen = changegroup.readbundle(f, bundlepath)
1215 gen = changegroup.readbundle(f, bundlepath)
1216 if all:
1216 if all:
1217 ui.write("format: id, p1, p2, cset, len(delta)\n")
1217 ui.write("format: id, p1, p2, cset, len(delta)\n")
1218
1218
1219 def showchunks(named):
1219 def showchunks(named):
1220 ui.write("\n%s\n" % named)
1220 ui.write("\n%s\n" % named)
1221 while 1:
1221 while 1:
1222 chunkdata = gen.parsechunk()
1222 chunkdata = gen.parsechunk()
1223 if not chunkdata:
1223 if not chunkdata:
1224 break
1224 break
1225 node = chunkdata['node']
1225 node = chunkdata['node']
1226 p1 = chunkdata['p1']
1226 p1 = chunkdata['p1']
1227 p2 = chunkdata['p2']
1227 p2 = chunkdata['p2']
1228 cs = chunkdata['cs']
1228 cs = chunkdata['cs']
1229 delta = chunkdata['data']
1229 delta = chunkdata['data']
1230 ui.write("%s %s %s %s %s\n" %
1230 ui.write("%s %s %s %s %s\n" %
1231 (hex(node), hex(p1), hex(p2),
1231 (hex(node), hex(p1), hex(p2),
1232 hex(cs), len(delta)))
1232 hex(cs), len(delta)))
1233
1233
1234 showchunks("changelog")
1234 showchunks("changelog")
1235 showchunks("manifest")
1235 showchunks("manifest")
1236 while 1:
1236 while 1:
1237 fname = gen.chunk()
1237 fname = gen.chunk()
1238 if not fname:
1238 if not fname:
1239 break
1239 break
1240 showchunks(fname)
1240 showchunks(fname)
1241 else:
1241 else:
1242 while 1:
1242 while 1:
1243 chunkdata = gen.parsechunk()
1243 chunkdata = gen.parsechunk()
1244 if not chunkdata:
1244 if not chunkdata:
1245 break
1245 break
1246 node = chunkdata['node']
1246 node = chunkdata['node']
1247 ui.write("%s\n" % hex(node))
1247 ui.write("%s\n" % hex(node))
1248 finally:
1248 finally:
1249 f.close()
1249 f.close()
1250
1250
1251 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1251 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1252 """retrieves a bundle from a repo
1252 """retrieves a bundle from a repo
1253
1253
1254 Every ID must be a full-length hex node id string. Saves the bundle to the
1254 Every ID must be a full-length hex node id string. Saves the bundle to the
1255 given file.
1255 given file.
1256 """
1256 """
1257 repo = hg.repository(ui, repopath)
1257 repo = hg.repository(ui, repopath)
1258 if not repo.capable('getbundle'):
1258 if not repo.capable('getbundle'):
1259 raise util.Abort("getbundle() not supported by target repository")
1259 raise util.Abort("getbundle() not supported by target repository")
1260 args = {}
1260 args = {}
1261 if common:
1261 if common:
1262 args['common'] = [bin(s) for s in common]
1262 args['common'] = [bin(s) for s in common]
1263 if head:
1263 if head:
1264 args['heads'] = [bin(s) for s in head]
1264 args['heads'] = [bin(s) for s in head]
1265 bundle = repo.getbundle('debug', **args)
1265 bundle = repo.getbundle('debug', **args)
1266
1266
1267 bundletype = opts.get('type', 'bzip2').lower()
1267 bundletype = opts.get('type', 'bzip2').lower()
1268 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1268 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1269 bundletype = btypes.get(bundletype)
1269 bundletype = btypes.get(bundletype)
1270 if bundletype not in changegroup.bundletypes:
1270 if bundletype not in changegroup.bundletypes:
1271 raise util.Abort(_('unknown bundle type specified with --type'))
1271 raise util.Abort(_('unknown bundle type specified with --type'))
1272 changegroup.writebundle(bundle, bundlepath, bundletype)
1272 changegroup.writebundle(bundle, bundlepath, bundletype)
1273
1273
1274 def debugpushkey(ui, repopath, namespace, *keyinfo):
1274 def debugpushkey(ui, repopath, namespace, *keyinfo):
1275 '''access the pushkey key/value protocol
1275 '''access the pushkey key/value protocol
1276
1276
1277 With two args, list the keys in the given namespace.
1277 With two args, list the keys in the given namespace.
1278
1278
1279 With five args, set a key to new if it currently is set to old.
1279 With five args, set a key to new if it currently is set to old.
1280 Reports success or failure.
1280 Reports success or failure.
1281 '''
1281 '''
1282
1282
1283 target = hg.repository(ui, repopath)
1283 target = hg.repository(ui, repopath)
1284 if keyinfo:
1284 if keyinfo:
1285 key, old, new = keyinfo
1285 key, old, new = keyinfo
1286 r = target.pushkey(namespace, key, old, new)
1286 r = target.pushkey(namespace, key, old, new)
1287 ui.status(str(r) + '\n')
1287 ui.status(str(r) + '\n')
1288 return not r
1288 return not r
1289 else:
1289 else:
1290 for k, v in target.listkeys(namespace).iteritems():
1290 for k, v in target.listkeys(namespace).iteritems():
1291 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1291 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1292 v.encode('string-escape')))
1292 v.encode('string-escape')))
1293
1293
1294 def debugrevspec(ui, repo, expr):
1294 def debugrevspec(ui, repo, expr):
1295 '''parse and apply a revision specification'''
1295 '''parse and apply a revision specification'''
1296 if ui.verbose:
1296 if ui.verbose:
1297 tree = revset.parse(expr)[0]
1297 tree = revset.parse(expr)[0]
1298 ui.note(tree, "\n")
1298 ui.note(tree, "\n")
1299 func = revset.match(expr)
1299 newtree = revset.findaliases(ui, tree)
1300 if newtree != tree:
1301 ui.note(newtree, "\n")
1302 func = revset.match(ui, expr)
1300 for c in func(repo, range(len(repo))):
1303 for c in func(repo, range(len(repo))):
1301 ui.write("%s\n" % c)
1304 ui.write("%s\n" % c)
1302
1305
1303 def debugsetparents(ui, repo, rev1, rev2=None):
1306 def debugsetparents(ui, repo, rev1, rev2=None):
1304 """manually set the parents of the current working directory
1307 """manually set the parents of the current working directory
1305
1308
1306 This is useful for writing repository conversion tools, but should
1309 This is useful for writing repository conversion tools, but should
1307 be used with care.
1310 be used with care.
1308
1311
1309 Returns 0 on success.
1312 Returns 0 on success.
1310 """
1313 """
1311
1314
1312 r1 = cmdutil.revsingle(repo, rev1).node()
1315 r1 = cmdutil.revsingle(repo, rev1).node()
1313 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1316 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1314
1317
1315 wlock = repo.wlock()
1318 wlock = repo.wlock()
1316 try:
1319 try:
1317 repo.dirstate.setparents(r1, r2)
1320 repo.dirstate.setparents(r1, r2)
1318 finally:
1321 finally:
1319 wlock.release()
1322 wlock.release()
1320
1323
1321 def debugstate(ui, repo, nodates=None, datesort=None):
1324 def debugstate(ui, repo, nodates=None, datesort=None):
1322 """show the contents of the current dirstate"""
1325 """show the contents of the current dirstate"""
1323 timestr = ""
1326 timestr = ""
1324 showdate = not nodates
1327 showdate = not nodates
1325 if datesort:
1328 if datesort:
1326 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
1329 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
1327 else:
1330 else:
1328 keyfunc = None # sort by filename
1331 keyfunc = None # sort by filename
1329 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
1332 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
1330 if showdate:
1333 if showdate:
1331 if ent[3] == -1:
1334 if ent[3] == -1:
1332 # Pad or slice to locale representation
1335 # Pad or slice to locale representation
1333 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1336 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1334 time.localtime(0)))
1337 time.localtime(0)))
1335 timestr = 'unset'
1338 timestr = 'unset'
1336 timestr = (timestr[:locale_len] +
1339 timestr = (timestr[:locale_len] +
1337 ' ' * (locale_len - len(timestr)))
1340 ' ' * (locale_len - len(timestr)))
1338 else:
1341 else:
1339 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1342 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1340 time.localtime(ent[3]))
1343 time.localtime(ent[3]))
1341 if ent[1] & 020000:
1344 if ent[1] & 020000:
1342 mode = 'lnk'
1345 mode = 'lnk'
1343 else:
1346 else:
1344 mode = '%3o' % (ent[1] & 0777)
1347 mode = '%3o' % (ent[1] & 0777)
1345 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1348 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1346 for f in repo.dirstate.copies():
1349 for f in repo.dirstate.copies():
1347 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1350 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1348
1351
1349 def debugsub(ui, repo, rev=None):
1352 def debugsub(ui, repo, rev=None):
1350 ctx = cmdutil.revsingle(repo, rev, None)
1353 ctx = cmdutil.revsingle(repo, rev, None)
1351 for k, v in sorted(ctx.substate.items()):
1354 for k, v in sorted(ctx.substate.items()):
1352 ui.write('path %s\n' % k)
1355 ui.write('path %s\n' % k)
1353 ui.write(' source %s\n' % v[0])
1356 ui.write(' source %s\n' % v[0])
1354 ui.write(' revision %s\n' % v[1])
1357 ui.write(' revision %s\n' % v[1])
1355
1358
1356 def debugdag(ui, repo, file_=None, *revs, **opts):
1359 def debugdag(ui, repo, file_=None, *revs, **opts):
1357 """format the changelog or an index DAG as a concise textual description
1360 """format the changelog or an index DAG as a concise textual description
1358
1361
1359 If you pass a revlog index, the revlog's DAG is emitted. If you list
1362 If you pass a revlog index, the revlog's DAG is emitted. If you list
1360 revision numbers, they get labelled in the output as rN.
1363 revision numbers, they get labelled in the output as rN.
1361
1364
1362 Otherwise, the changelog DAG of the current repo is emitted.
1365 Otherwise, the changelog DAG of the current repo is emitted.
1363 """
1366 """
1364 spaces = opts.get('spaces')
1367 spaces = opts.get('spaces')
1365 dots = opts.get('dots')
1368 dots = opts.get('dots')
1366 if file_:
1369 if file_:
1367 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1370 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1368 revs = set((int(r) for r in revs))
1371 revs = set((int(r) for r in revs))
1369 def events():
1372 def events():
1370 for r in rlog:
1373 for r in rlog:
1371 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1374 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1372 if r in revs:
1375 if r in revs:
1373 yield 'l', (r, "r%i" % r)
1376 yield 'l', (r, "r%i" % r)
1374 elif repo:
1377 elif repo:
1375 cl = repo.changelog
1378 cl = repo.changelog
1376 tags = opts.get('tags')
1379 tags = opts.get('tags')
1377 branches = opts.get('branches')
1380 branches = opts.get('branches')
1378 if tags:
1381 if tags:
1379 labels = {}
1382 labels = {}
1380 for l, n in repo.tags().items():
1383 for l, n in repo.tags().items():
1381 labels.setdefault(cl.rev(n), []).append(l)
1384 labels.setdefault(cl.rev(n), []).append(l)
1382 def events():
1385 def events():
1383 b = "default"
1386 b = "default"
1384 for r in cl:
1387 for r in cl:
1385 if branches:
1388 if branches:
1386 newb = cl.read(cl.node(r))[5]['branch']
1389 newb = cl.read(cl.node(r))[5]['branch']
1387 if newb != b:
1390 if newb != b:
1388 yield 'a', newb
1391 yield 'a', newb
1389 b = newb
1392 b = newb
1390 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1393 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1391 if tags:
1394 if tags:
1392 ls = labels.get(r)
1395 ls = labels.get(r)
1393 if ls:
1396 if ls:
1394 for l in ls:
1397 for l in ls:
1395 yield 'l', (r, l)
1398 yield 'l', (r, l)
1396 else:
1399 else:
1397 raise util.Abort(_('need repo for changelog dag'))
1400 raise util.Abort(_('need repo for changelog dag'))
1398
1401
1399 for line in dagparser.dagtextlines(events(),
1402 for line in dagparser.dagtextlines(events(),
1400 addspaces=spaces,
1403 addspaces=spaces,
1401 wraplabels=True,
1404 wraplabels=True,
1402 wrapannotations=True,
1405 wrapannotations=True,
1403 wrapnonlinear=dots,
1406 wrapnonlinear=dots,
1404 usedots=dots,
1407 usedots=dots,
1405 maxlinewidth=70):
1408 maxlinewidth=70):
1406 ui.write(line)
1409 ui.write(line)
1407 ui.write("\n")
1410 ui.write("\n")
1408
1411
1409 def debugdata(ui, repo, file_, rev):
1412 def debugdata(ui, repo, file_, rev):
1410 """dump the contents of a data file revision"""
1413 """dump the contents of a data file revision"""
1411 r = None
1414 r = None
1412 if repo:
1415 if repo:
1413 filelog = repo.file(file_)
1416 filelog = repo.file(file_)
1414 if len(filelog):
1417 if len(filelog):
1415 r = filelog
1418 r = filelog
1416 if not r:
1419 if not r:
1417 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
1420 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
1418 file_[:-2] + ".i")
1421 file_[:-2] + ".i")
1419 try:
1422 try:
1420 ui.write(r.revision(r.lookup(rev)))
1423 ui.write(r.revision(r.lookup(rev)))
1421 except KeyError:
1424 except KeyError:
1422 raise util.Abort(_('invalid revision identifier %s') % rev)
1425 raise util.Abort(_('invalid revision identifier %s') % rev)
1423
1426
1424 def debugdate(ui, date, range=None, **opts):
1427 def debugdate(ui, date, range=None, **opts):
1425 """parse and display a date"""
1428 """parse and display a date"""
1426 if opts["extended"]:
1429 if opts["extended"]:
1427 d = util.parsedate(date, util.extendeddateformats)
1430 d = util.parsedate(date, util.extendeddateformats)
1428 else:
1431 else:
1429 d = util.parsedate(date)
1432 d = util.parsedate(date)
1430 ui.write("internal: %s %s\n" % d)
1433 ui.write("internal: %s %s\n" % d)
1431 ui.write("standard: %s\n" % util.datestr(d))
1434 ui.write("standard: %s\n" % util.datestr(d))
1432 if range:
1435 if range:
1433 m = util.matchdate(range)
1436 m = util.matchdate(range)
1434 ui.write("match: %s\n" % m(d[0]))
1437 ui.write("match: %s\n" % m(d[0]))
1435
1438
1436 def debugignore(ui, repo, *values, **opts):
1439 def debugignore(ui, repo, *values, **opts):
1437 """display the combined ignore pattern"""
1440 """display the combined ignore pattern"""
1438 ignore = repo.dirstate._ignore
1441 ignore = repo.dirstate._ignore
1439 if hasattr(ignore, 'includepat'):
1442 if hasattr(ignore, 'includepat'):
1440 ui.write("%s\n" % ignore.includepat)
1443 ui.write("%s\n" % ignore.includepat)
1441 else:
1444 else:
1442 raise util.Abort(_("no ignore patterns found"))
1445 raise util.Abort(_("no ignore patterns found"))
1443
1446
1444 def debugindex(ui, repo, file_, **opts):
1447 def debugindex(ui, repo, file_, **opts):
1445 """dump the contents of an index file"""
1448 """dump the contents of an index file"""
1446 r = None
1449 r = None
1447 if repo:
1450 if repo:
1448 filelog = repo.file(file_)
1451 filelog = repo.file(file_)
1449 if len(filelog):
1452 if len(filelog):
1450 r = filelog
1453 r = filelog
1451
1454
1452 format = opts.get('format', 0)
1455 format = opts.get('format', 0)
1453 if format not in (0, 1):
1456 if format not in (0, 1):
1454 raise util.Abort(_("unknown format %d") % format)
1457 raise util.Abort(_("unknown format %d") % format)
1455
1458
1456 if not r:
1459 if not r:
1457 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1460 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1458
1461
1459 if format == 0:
1462 if format == 0:
1460 ui.write(" rev offset length base linkrev"
1463 ui.write(" rev offset length base linkrev"
1461 " nodeid p1 p2\n")
1464 " nodeid p1 p2\n")
1462 elif format == 1:
1465 elif format == 1:
1463 ui.write(" rev flag offset length"
1466 ui.write(" rev flag offset length"
1464 " size base link p1 p2 nodeid\n")
1467 " size base link p1 p2 nodeid\n")
1465
1468
1466 for i in r:
1469 for i in r:
1467 node = r.node(i)
1470 node = r.node(i)
1468 if format == 0:
1471 if format == 0:
1469 try:
1472 try:
1470 pp = r.parents(node)
1473 pp = r.parents(node)
1471 except:
1474 except:
1472 pp = [nullid, nullid]
1475 pp = [nullid, nullid]
1473 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1476 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1474 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1477 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1475 short(node), short(pp[0]), short(pp[1])))
1478 short(node), short(pp[0]), short(pp[1])))
1476 elif format == 1:
1479 elif format == 1:
1477 pr = r.parentrevs(i)
1480 pr = r.parentrevs(i)
1478 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1481 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1479 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1482 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1480 r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
1483 r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
1481
1484
1482 def debugindexdot(ui, repo, file_):
1485 def debugindexdot(ui, repo, file_):
1483 """dump an index DAG as a graphviz dot file"""
1486 """dump an index DAG as a graphviz dot file"""
1484 r = None
1487 r = None
1485 if repo:
1488 if repo:
1486 filelog = repo.file(file_)
1489 filelog = repo.file(file_)
1487 if len(filelog):
1490 if len(filelog):
1488 r = filelog
1491 r = filelog
1489 if not r:
1492 if not r:
1490 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1493 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1491 ui.write("digraph G {\n")
1494 ui.write("digraph G {\n")
1492 for i in r:
1495 for i in r:
1493 node = r.node(i)
1496 node = r.node(i)
1494 pp = r.parents(node)
1497 pp = r.parents(node)
1495 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1498 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1496 if pp[1] != nullid:
1499 if pp[1] != nullid:
1497 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1500 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1498 ui.write("}\n")
1501 ui.write("}\n")
1499
1502
1500 def debuginstall(ui):
1503 def debuginstall(ui):
1501 '''test Mercurial installation
1504 '''test Mercurial installation
1502
1505
1503 Returns 0 on success.
1506 Returns 0 on success.
1504 '''
1507 '''
1505
1508
1506 def writetemp(contents):
1509 def writetemp(contents):
1507 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1510 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1508 f = os.fdopen(fd, "wb")
1511 f = os.fdopen(fd, "wb")
1509 f.write(contents)
1512 f.write(contents)
1510 f.close()
1513 f.close()
1511 return name
1514 return name
1512
1515
1513 problems = 0
1516 problems = 0
1514
1517
1515 # encoding
1518 # encoding
1516 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1519 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1517 try:
1520 try:
1518 encoding.fromlocal("test")
1521 encoding.fromlocal("test")
1519 except util.Abort, inst:
1522 except util.Abort, inst:
1520 ui.write(" %s\n" % inst)
1523 ui.write(" %s\n" % inst)
1521 ui.write(_(" (check that your locale is properly set)\n"))
1524 ui.write(_(" (check that your locale is properly set)\n"))
1522 problems += 1
1525 problems += 1
1523
1526
1524 # compiled modules
1527 # compiled modules
1525 ui.status(_("Checking installed modules (%s)...\n")
1528 ui.status(_("Checking installed modules (%s)...\n")
1526 % os.path.dirname(__file__))
1529 % os.path.dirname(__file__))
1527 try:
1530 try:
1528 import bdiff, mpatch, base85, osutil
1531 import bdiff, mpatch, base85, osutil
1529 except Exception, inst:
1532 except Exception, inst:
1530 ui.write(" %s\n" % inst)
1533 ui.write(" %s\n" % inst)
1531 ui.write(_(" One or more extensions could not be found"))
1534 ui.write(_(" One or more extensions could not be found"))
1532 ui.write(_(" (check that you compiled the extensions)\n"))
1535 ui.write(_(" (check that you compiled the extensions)\n"))
1533 problems += 1
1536 problems += 1
1534
1537
1535 # templates
1538 # templates
1536 ui.status(_("Checking templates...\n"))
1539 ui.status(_("Checking templates...\n"))
1537 try:
1540 try:
1538 import templater
1541 import templater
1539 templater.templater(templater.templatepath("map-cmdline.default"))
1542 templater.templater(templater.templatepath("map-cmdline.default"))
1540 except Exception, inst:
1543 except Exception, inst:
1541 ui.write(" %s\n" % inst)
1544 ui.write(" %s\n" % inst)
1542 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1545 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1543 problems += 1
1546 problems += 1
1544
1547
1545 # editor
1548 # editor
1546 ui.status(_("Checking commit editor...\n"))
1549 ui.status(_("Checking commit editor...\n"))
1547 editor = ui.geteditor()
1550 editor = ui.geteditor()
1548 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1551 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1549 if not cmdpath:
1552 if not cmdpath:
1550 if editor == 'vi':
1553 if editor == 'vi':
1551 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1554 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1552 ui.write(_(" (specify a commit editor in your configuration"
1555 ui.write(_(" (specify a commit editor in your configuration"
1553 " file)\n"))
1556 " file)\n"))
1554 else:
1557 else:
1555 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1558 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1556 ui.write(_(" (specify a commit editor in your configuration"
1559 ui.write(_(" (specify a commit editor in your configuration"
1557 " file)\n"))
1560 " file)\n"))
1558 problems += 1
1561 problems += 1
1559
1562
1560 # check username
1563 # check username
1561 ui.status(_("Checking username...\n"))
1564 ui.status(_("Checking username...\n"))
1562 try:
1565 try:
1563 ui.username()
1566 ui.username()
1564 except util.Abort, e:
1567 except util.Abort, e:
1565 ui.write(" %s\n" % e)
1568 ui.write(" %s\n" % e)
1566 ui.write(_(" (specify a username in your configuration file)\n"))
1569 ui.write(_(" (specify a username in your configuration file)\n"))
1567 problems += 1
1570 problems += 1
1568
1571
1569 if not problems:
1572 if not problems:
1570 ui.status(_("No problems detected\n"))
1573 ui.status(_("No problems detected\n"))
1571 else:
1574 else:
1572 ui.write(_("%s problems detected,"
1575 ui.write(_("%s problems detected,"
1573 " please check your install!\n") % problems)
1576 " please check your install!\n") % problems)
1574
1577
1575 return problems
1578 return problems
1576
1579
1577 def debugrename(ui, repo, file1, *pats, **opts):
1580 def debugrename(ui, repo, file1, *pats, **opts):
1578 """dump rename information"""
1581 """dump rename information"""
1579
1582
1580 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1583 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1581 m = cmdutil.match(repo, (file1,) + pats, opts)
1584 m = cmdutil.match(repo, (file1,) + pats, opts)
1582 for abs in ctx.walk(m):
1585 for abs in ctx.walk(m):
1583 fctx = ctx[abs]
1586 fctx = ctx[abs]
1584 o = fctx.filelog().renamed(fctx.filenode())
1587 o = fctx.filelog().renamed(fctx.filenode())
1585 rel = m.rel(abs)
1588 rel = m.rel(abs)
1586 if o:
1589 if o:
1587 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1590 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1588 else:
1591 else:
1589 ui.write(_("%s not renamed\n") % rel)
1592 ui.write(_("%s not renamed\n") % rel)
1590
1593
1591 def debugwalk(ui, repo, *pats, **opts):
1594 def debugwalk(ui, repo, *pats, **opts):
1592 """show how files match on given patterns"""
1595 """show how files match on given patterns"""
1593 m = cmdutil.match(repo, pats, opts)
1596 m = cmdutil.match(repo, pats, opts)
1594 items = list(repo.walk(m))
1597 items = list(repo.walk(m))
1595 if not items:
1598 if not items:
1596 return
1599 return
1597 fmt = 'f %%-%ds %%-%ds %%s' % (
1600 fmt = 'f %%-%ds %%-%ds %%s' % (
1598 max([len(abs) for abs in items]),
1601 max([len(abs) for abs in items]),
1599 max([len(m.rel(abs)) for abs in items]))
1602 max([len(m.rel(abs)) for abs in items]))
1600 for abs in items:
1603 for abs in items:
1601 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1604 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1602 ui.write("%s\n" % line.rstrip())
1605 ui.write("%s\n" % line.rstrip())
1603
1606
1604 def debugwireargs(ui, repopath, *vals, **opts):
1607 def debugwireargs(ui, repopath, *vals, **opts):
1605 repo = hg.repository(hg.remoteui(ui, opts), repopath)
1608 repo = hg.repository(hg.remoteui(ui, opts), repopath)
1606 for opt in remoteopts:
1609 for opt in remoteopts:
1607 del opts[opt[1]]
1610 del opts[opt[1]]
1608 args = {}
1611 args = {}
1609 for k, v in opts.iteritems():
1612 for k, v in opts.iteritems():
1610 if v:
1613 if v:
1611 args[k] = v
1614 args[k] = v
1612 # run twice to check that we don't mess up the stream for the next command
1615 # run twice to check that we don't mess up the stream for the next command
1613 res1 = repo.debugwireargs(*vals, **args)
1616 res1 = repo.debugwireargs(*vals, **args)
1614 res2 = repo.debugwireargs(*vals, **args)
1617 res2 = repo.debugwireargs(*vals, **args)
1615 ui.write("%s\n" % res1)
1618 ui.write("%s\n" % res1)
1616 if res1 != res2:
1619 if res1 != res2:
1617 ui.warn("%s\n" % res2)
1620 ui.warn("%s\n" % res2)
1618
1621
1619 def diff(ui, repo, *pats, **opts):
1622 def diff(ui, repo, *pats, **opts):
1620 """diff repository (or selected files)
1623 """diff repository (or selected files)
1621
1624
1622 Show differences between revisions for the specified files.
1625 Show differences between revisions for the specified files.
1623
1626
1624 Differences between files are shown using the unified diff format.
1627 Differences between files are shown using the unified diff format.
1625
1628
1626 .. note::
1629 .. note::
1627 diff may generate unexpected results for merges, as it will
1630 diff may generate unexpected results for merges, as it will
1628 default to comparing against the working directory's first
1631 default to comparing against the working directory's first
1629 parent changeset if no revisions are specified.
1632 parent changeset if no revisions are specified.
1630
1633
1631 When two revision arguments are given, then changes are shown
1634 When two revision arguments are given, then changes are shown
1632 between those revisions. If only one revision is specified then
1635 between those revisions. If only one revision is specified then
1633 that revision is compared to the working directory, and, when no
1636 that revision is compared to the working directory, and, when no
1634 revisions are specified, the working directory files are compared
1637 revisions are specified, the working directory files are compared
1635 to its parent.
1638 to its parent.
1636
1639
1637 Alternatively you can specify -c/--change with a revision to see
1640 Alternatively you can specify -c/--change with a revision to see
1638 the changes in that changeset relative to its first parent.
1641 the changes in that changeset relative to its first parent.
1639
1642
1640 Without the -a/--text option, diff will avoid generating diffs of
1643 Without the -a/--text option, diff will avoid generating diffs of
1641 files it detects as binary. With -a, diff will generate a diff
1644 files it detects as binary. With -a, diff will generate a diff
1642 anyway, probably with undesirable results.
1645 anyway, probably with undesirable results.
1643
1646
1644 Use the -g/--git option to generate diffs in the git extended diff
1647 Use the -g/--git option to generate diffs in the git extended diff
1645 format. For more information, read :hg:`help diffs`.
1648 format. For more information, read :hg:`help diffs`.
1646
1649
1647 Returns 0 on success.
1650 Returns 0 on success.
1648 """
1651 """
1649
1652
1650 revs = opts.get('rev')
1653 revs = opts.get('rev')
1651 change = opts.get('change')
1654 change = opts.get('change')
1652 stat = opts.get('stat')
1655 stat = opts.get('stat')
1653 reverse = opts.get('reverse')
1656 reverse = opts.get('reverse')
1654
1657
1655 if revs and change:
1658 if revs and change:
1656 msg = _('cannot specify --rev and --change at the same time')
1659 msg = _('cannot specify --rev and --change at the same time')
1657 raise util.Abort(msg)
1660 raise util.Abort(msg)
1658 elif change:
1661 elif change:
1659 node2 = cmdutil.revsingle(repo, change, None).node()
1662 node2 = cmdutil.revsingle(repo, change, None).node()
1660 node1 = repo[node2].p1().node()
1663 node1 = repo[node2].p1().node()
1661 else:
1664 else:
1662 node1, node2 = cmdutil.revpair(repo, revs)
1665 node1, node2 = cmdutil.revpair(repo, revs)
1663
1666
1664 if reverse:
1667 if reverse:
1665 node1, node2 = node2, node1
1668 node1, node2 = node2, node1
1666
1669
1667 diffopts = patch.diffopts(ui, opts)
1670 diffopts = patch.diffopts(ui, opts)
1668 m = cmdutil.match(repo, pats, opts)
1671 m = cmdutil.match(repo, pats, opts)
1669 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1672 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1670 listsubrepos=opts.get('subrepos'))
1673 listsubrepos=opts.get('subrepos'))
1671
1674
1672 def export(ui, repo, *changesets, **opts):
1675 def export(ui, repo, *changesets, **opts):
1673 """dump the header and diffs for one or more changesets
1676 """dump the header and diffs for one or more changesets
1674
1677
1675 Print the changeset header and diffs for one or more revisions.
1678 Print the changeset header and diffs for one or more revisions.
1676
1679
1677 The information shown in the changeset header is: author, date,
1680 The information shown in the changeset header is: author, date,
1678 branch name (if non-default), changeset hash, parent(s) and commit
1681 branch name (if non-default), changeset hash, parent(s) and commit
1679 comment.
1682 comment.
1680
1683
1681 .. note::
1684 .. note::
1682 export may generate unexpected diff output for merge
1685 export may generate unexpected diff output for merge
1683 changesets, as it will compare the merge changeset against its
1686 changesets, as it will compare the merge changeset against its
1684 first parent only.
1687 first parent only.
1685
1688
1686 Output may be to a file, in which case the name of the file is
1689 Output may be to a file, in which case the name of the file is
1687 given using a format string. The formatting rules are as follows:
1690 given using a format string. The formatting rules are as follows:
1688
1691
1689 :``%%``: literal "%" character
1692 :``%%``: literal "%" character
1690 :``%H``: changeset hash (40 hexadecimal digits)
1693 :``%H``: changeset hash (40 hexadecimal digits)
1691 :``%N``: number of patches being generated
1694 :``%N``: number of patches being generated
1692 :``%R``: changeset revision number
1695 :``%R``: changeset revision number
1693 :``%b``: basename of the exporting repository
1696 :``%b``: basename of the exporting repository
1694 :``%h``: short-form changeset hash (12 hexadecimal digits)
1697 :``%h``: short-form changeset hash (12 hexadecimal digits)
1695 :``%n``: zero-padded sequence number, starting at 1
1698 :``%n``: zero-padded sequence number, starting at 1
1696 :``%r``: zero-padded changeset revision number
1699 :``%r``: zero-padded changeset revision number
1697
1700
1698 Without the -a/--text option, export will avoid generating diffs
1701 Without the -a/--text option, export will avoid generating diffs
1699 of files it detects as binary. With -a, export will generate a
1702 of files it detects as binary. With -a, export will generate a
1700 diff anyway, probably with undesirable results.
1703 diff anyway, probably with undesirable results.
1701
1704
1702 Use the -g/--git option to generate diffs in the git extended diff
1705 Use the -g/--git option to generate diffs in the git extended diff
1703 format. See :hg:`help diffs` for more information.
1706 format. See :hg:`help diffs` for more information.
1704
1707
1705 With the --switch-parent option, the diff will be against the
1708 With the --switch-parent option, the diff will be against the
1706 second parent. It can be useful to review a merge.
1709 second parent. It can be useful to review a merge.
1707
1710
1708 Returns 0 on success.
1711 Returns 0 on success.
1709 """
1712 """
1710 changesets += tuple(opts.get('rev', []))
1713 changesets += tuple(opts.get('rev', []))
1711 if not changesets:
1714 if not changesets:
1712 raise util.Abort(_("export requires at least one changeset"))
1715 raise util.Abort(_("export requires at least one changeset"))
1713 revs = cmdutil.revrange(repo, changesets)
1716 revs = cmdutil.revrange(repo, changesets)
1714 if len(revs) > 1:
1717 if len(revs) > 1:
1715 ui.note(_('exporting patches:\n'))
1718 ui.note(_('exporting patches:\n'))
1716 else:
1719 else:
1717 ui.note(_('exporting patch:\n'))
1720 ui.note(_('exporting patch:\n'))
1718 cmdutil.export(repo, revs, template=opts.get('output'),
1721 cmdutil.export(repo, revs, template=opts.get('output'),
1719 switch_parent=opts.get('switch_parent'),
1722 switch_parent=opts.get('switch_parent'),
1720 opts=patch.diffopts(ui, opts))
1723 opts=patch.diffopts(ui, opts))
1721
1724
1722 def forget(ui, repo, *pats, **opts):
1725 def forget(ui, repo, *pats, **opts):
1723 """forget the specified files on the next commit
1726 """forget the specified files on the next commit
1724
1727
1725 Mark the specified files so they will no longer be tracked
1728 Mark the specified files so they will no longer be tracked
1726 after the next commit.
1729 after the next commit.
1727
1730
1728 This only removes files from the current branch, not from the
1731 This only removes files from the current branch, not from the
1729 entire project history, and it does not delete them from the
1732 entire project history, and it does not delete them from the
1730 working directory.
1733 working directory.
1731
1734
1732 To undo a forget before the next commit, see :hg:`add`.
1735 To undo a forget before the next commit, see :hg:`add`.
1733
1736
1734 Returns 0 on success.
1737 Returns 0 on success.
1735 """
1738 """
1736
1739
1737 if not pats:
1740 if not pats:
1738 raise util.Abort(_('no files specified'))
1741 raise util.Abort(_('no files specified'))
1739
1742
1740 m = cmdutil.match(repo, pats, opts)
1743 m = cmdutil.match(repo, pats, opts)
1741 s = repo.status(match=m, clean=True)
1744 s = repo.status(match=m, clean=True)
1742 forget = sorted(s[0] + s[1] + s[3] + s[6])
1745 forget = sorted(s[0] + s[1] + s[3] + s[6])
1743 errs = 0
1746 errs = 0
1744
1747
1745 for f in m.files():
1748 for f in m.files():
1746 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1749 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1747 ui.warn(_('not removing %s: file is already untracked\n')
1750 ui.warn(_('not removing %s: file is already untracked\n')
1748 % m.rel(f))
1751 % m.rel(f))
1749 errs = 1
1752 errs = 1
1750
1753
1751 for f in forget:
1754 for f in forget:
1752 if ui.verbose or not m.exact(f):
1755 if ui.verbose or not m.exact(f):
1753 ui.status(_('removing %s\n') % m.rel(f))
1756 ui.status(_('removing %s\n') % m.rel(f))
1754
1757
1755 repo[None].remove(forget, unlink=False)
1758 repo[None].remove(forget, unlink=False)
1756 return errs
1759 return errs
1757
1760
1758 def grep(ui, repo, pattern, *pats, **opts):
1761 def grep(ui, repo, pattern, *pats, **opts):
1759 """search for a pattern in specified files and revisions
1762 """search for a pattern in specified files and revisions
1760
1763
1761 Search revisions of files for a regular expression.
1764 Search revisions of files for a regular expression.
1762
1765
1763 This command behaves differently than Unix grep. It only accepts
1766 This command behaves differently than Unix grep. It only accepts
1764 Python/Perl regexps. It searches repository history, not the
1767 Python/Perl regexps. It searches repository history, not the
1765 working directory. It always prints the revision number in which a
1768 working directory. It always prints the revision number in which a
1766 match appears.
1769 match appears.
1767
1770
1768 By default, grep only prints output for the first revision of a
1771 By default, grep only prints output for the first revision of a
1769 file in which it finds a match. To get it to print every revision
1772 file in which it finds a match. To get it to print every revision
1770 that contains a change in match status ("-" for a match that
1773 that contains a change in match status ("-" for a match that
1771 becomes a non-match, or "+" for a non-match that becomes a match),
1774 becomes a non-match, or "+" for a non-match that becomes a match),
1772 use the --all flag.
1775 use the --all flag.
1773
1776
1774 Returns 0 if a match is found, 1 otherwise.
1777 Returns 0 if a match is found, 1 otherwise.
1775 """
1778 """
1776 reflags = 0
1779 reflags = 0
1777 if opts.get('ignore_case'):
1780 if opts.get('ignore_case'):
1778 reflags |= re.I
1781 reflags |= re.I
1779 try:
1782 try:
1780 regexp = re.compile(pattern, reflags)
1783 regexp = re.compile(pattern, reflags)
1781 except re.error, inst:
1784 except re.error, inst:
1782 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1785 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1783 return 1
1786 return 1
1784 sep, eol = ':', '\n'
1787 sep, eol = ':', '\n'
1785 if opts.get('print0'):
1788 if opts.get('print0'):
1786 sep = eol = '\0'
1789 sep = eol = '\0'
1787
1790
1788 getfile = util.lrucachefunc(repo.file)
1791 getfile = util.lrucachefunc(repo.file)
1789
1792
1790 def matchlines(body):
1793 def matchlines(body):
1791 begin = 0
1794 begin = 0
1792 linenum = 0
1795 linenum = 0
1793 while True:
1796 while True:
1794 match = regexp.search(body, begin)
1797 match = regexp.search(body, begin)
1795 if not match:
1798 if not match:
1796 break
1799 break
1797 mstart, mend = match.span()
1800 mstart, mend = match.span()
1798 linenum += body.count('\n', begin, mstart) + 1
1801 linenum += body.count('\n', begin, mstart) + 1
1799 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1802 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1800 begin = body.find('\n', mend) + 1 or len(body)
1803 begin = body.find('\n', mend) + 1 or len(body)
1801 lend = begin - 1
1804 lend = begin - 1
1802 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1805 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1803
1806
1804 class linestate(object):
1807 class linestate(object):
1805 def __init__(self, line, linenum, colstart, colend):
1808 def __init__(self, line, linenum, colstart, colend):
1806 self.line = line
1809 self.line = line
1807 self.linenum = linenum
1810 self.linenum = linenum
1808 self.colstart = colstart
1811 self.colstart = colstart
1809 self.colend = colend
1812 self.colend = colend
1810
1813
1811 def __hash__(self):
1814 def __hash__(self):
1812 return hash((self.linenum, self.line))
1815 return hash((self.linenum, self.line))
1813
1816
1814 def __eq__(self, other):
1817 def __eq__(self, other):
1815 return self.line == other.line
1818 return self.line == other.line
1816
1819
1817 matches = {}
1820 matches = {}
1818 copies = {}
1821 copies = {}
1819 def grepbody(fn, rev, body):
1822 def grepbody(fn, rev, body):
1820 matches[rev].setdefault(fn, [])
1823 matches[rev].setdefault(fn, [])
1821 m = matches[rev][fn]
1824 m = matches[rev][fn]
1822 for lnum, cstart, cend, line in matchlines(body):
1825 for lnum, cstart, cend, line in matchlines(body):
1823 s = linestate(line, lnum, cstart, cend)
1826 s = linestate(line, lnum, cstart, cend)
1824 m.append(s)
1827 m.append(s)
1825
1828
1826 def difflinestates(a, b):
1829 def difflinestates(a, b):
1827 sm = difflib.SequenceMatcher(None, a, b)
1830 sm = difflib.SequenceMatcher(None, a, b)
1828 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1831 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1829 if tag == 'insert':
1832 if tag == 'insert':
1830 for i in xrange(blo, bhi):
1833 for i in xrange(blo, bhi):
1831 yield ('+', b[i])
1834 yield ('+', b[i])
1832 elif tag == 'delete':
1835 elif tag == 'delete':
1833 for i in xrange(alo, ahi):
1836 for i in xrange(alo, ahi):
1834 yield ('-', a[i])
1837 yield ('-', a[i])
1835 elif tag == 'replace':
1838 elif tag == 'replace':
1836 for i in xrange(alo, ahi):
1839 for i in xrange(alo, ahi):
1837 yield ('-', a[i])
1840 yield ('-', a[i])
1838 for i in xrange(blo, bhi):
1841 for i in xrange(blo, bhi):
1839 yield ('+', b[i])
1842 yield ('+', b[i])
1840
1843
1841 def display(fn, ctx, pstates, states):
1844 def display(fn, ctx, pstates, states):
1842 rev = ctx.rev()
1845 rev = ctx.rev()
1843 datefunc = ui.quiet and util.shortdate or util.datestr
1846 datefunc = ui.quiet and util.shortdate or util.datestr
1844 found = False
1847 found = False
1845 filerevmatches = {}
1848 filerevmatches = {}
1846 def binary():
1849 def binary():
1847 flog = getfile(fn)
1850 flog = getfile(fn)
1848 return util.binary(flog.read(ctx.filenode(fn)))
1851 return util.binary(flog.read(ctx.filenode(fn)))
1849
1852
1850 if opts.get('all'):
1853 if opts.get('all'):
1851 iter = difflinestates(pstates, states)
1854 iter = difflinestates(pstates, states)
1852 else:
1855 else:
1853 iter = [('', l) for l in states]
1856 iter = [('', l) for l in states]
1854 for change, l in iter:
1857 for change, l in iter:
1855 cols = [fn, str(rev)]
1858 cols = [fn, str(rev)]
1856 before, match, after = None, None, None
1859 before, match, after = None, None, None
1857 if opts.get('line_number'):
1860 if opts.get('line_number'):
1858 cols.append(str(l.linenum))
1861 cols.append(str(l.linenum))
1859 if opts.get('all'):
1862 if opts.get('all'):
1860 cols.append(change)
1863 cols.append(change)
1861 if opts.get('user'):
1864 if opts.get('user'):
1862 cols.append(ui.shortuser(ctx.user()))
1865 cols.append(ui.shortuser(ctx.user()))
1863 if opts.get('date'):
1866 if opts.get('date'):
1864 cols.append(datefunc(ctx.date()))
1867 cols.append(datefunc(ctx.date()))
1865 if opts.get('files_with_matches'):
1868 if opts.get('files_with_matches'):
1866 c = (fn, rev)
1869 c = (fn, rev)
1867 if c in filerevmatches:
1870 if c in filerevmatches:
1868 continue
1871 continue
1869 filerevmatches[c] = 1
1872 filerevmatches[c] = 1
1870 else:
1873 else:
1871 before = l.line[:l.colstart]
1874 before = l.line[:l.colstart]
1872 match = l.line[l.colstart:l.colend]
1875 match = l.line[l.colstart:l.colend]
1873 after = l.line[l.colend:]
1876 after = l.line[l.colend:]
1874 ui.write(sep.join(cols))
1877 ui.write(sep.join(cols))
1875 if before is not None:
1878 if before is not None:
1876 if not opts.get('text') and binary():
1879 if not opts.get('text') and binary():
1877 ui.write(sep + " Binary file matches")
1880 ui.write(sep + " Binary file matches")
1878 else:
1881 else:
1879 ui.write(sep + before)
1882 ui.write(sep + before)
1880 ui.write(match, label='grep.match')
1883 ui.write(match, label='grep.match')
1881 ui.write(after)
1884 ui.write(after)
1882 ui.write(eol)
1885 ui.write(eol)
1883 found = True
1886 found = True
1884 return found
1887 return found
1885
1888
1886 skip = {}
1889 skip = {}
1887 revfiles = {}
1890 revfiles = {}
1888 matchfn = cmdutil.match(repo, pats, opts)
1891 matchfn = cmdutil.match(repo, pats, opts)
1889 found = False
1892 found = False
1890 follow = opts.get('follow')
1893 follow = opts.get('follow')
1891
1894
1892 def prep(ctx, fns):
1895 def prep(ctx, fns):
1893 rev = ctx.rev()
1896 rev = ctx.rev()
1894 pctx = ctx.p1()
1897 pctx = ctx.p1()
1895 parent = pctx.rev()
1898 parent = pctx.rev()
1896 matches.setdefault(rev, {})
1899 matches.setdefault(rev, {})
1897 matches.setdefault(parent, {})
1900 matches.setdefault(parent, {})
1898 files = revfiles.setdefault(rev, [])
1901 files = revfiles.setdefault(rev, [])
1899 for fn in fns:
1902 for fn in fns:
1900 flog = getfile(fn)
1903 flog = getfile(fn)
1901 try:
1904 try:
1902 fnode = ctx.filenode(fn)
1905 fnode = ctx.filenode(fn)
1903 except error.LookupError:
1906 except error.LookupError:
1904 continue
1907 continue
1905
1908
1906 copied = flog.renamed(fnode)
1909 copied = flog.renamed(fnode)
1907 copy = follow and copied and copied[0]
1910 copy = follow and copied and copied[0]
1908 if copy:
1911 if copy:
1909 copies.setdefault(rev, {})[fn] = copy
1912 copies.setdefault(rev, {})[fn] = copy
1910 if fn in skip:
1913 if fn in skip:
1911 if copy:
1914 if copy:
1912 skip[copy] = True
1915 skip[copy] = True
1913 continue
1916 continue
1914 files.append(fn)
1917 files.append(fn)
1915
1918
1916 if fn not in matches[rev]:
1919 if fn not in matches[rev]:
1917 grepbody(fn, rev, flog.read(fnode))
1920 grepbody(fn, rev, flog.read(fnode))
1918
1921
1919 pfn = copy or fn
1922 pfn = copy or fn
1920 if pfn not in matches[parent]:
1923 if pfn not in matches[parent]:
1921 try:
1924 try:
1922 fnode = pctx.filenode(pfn)
1925 fnode = pctx.filenode(pfn)
1923 grepbody(pfn, parent, flog.read(fnode))
1926 grepbody(pfn, parent, flog.read(fnode))
1924 except error.LookupError:
1927 except error.LookupError:
1925 pass
1928 pass
1926
1929
1927 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1930 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1928 rev = ctx.rev()
1931 rev = ctx.rev()
1929 parent = ctx.p1().rev()
1932 parent = ctx.p1().rev()
1930 for fn in sorted(revfiles.get(rev, [])):
1933 for fn in sorted(revfiles.get(rev, [])):
1931 states = matches[rev][fn]
1934 states = matches[rev][fn]
1932 copy = copies.get(rev, {}).get(fn)
1935 copy = copies.get(rev, {}).get(fn)
1933 if fn in skip:
1936 if fn in skip:
1934 if copy:
1937 if copy:
1935 skip[copy] = True
1938 skip[copy] = True
1936 continue
1939 continue
1937 pstates = matches.get(parent, {}).get(copy or fn, [])
1940 pstates = matches.get(parent, {}).get(copy or fn, [])
1938 if pstates or states:
1941 if pstates or states:
1939 r = display(fn, ctx, pstates, states)
1942 r = display(fn, ctx, pstates, states)
1940 found = found or r
1943 found = found or r
1941 if r and not opts.get('all'):
1944 if r and not opts.get('all'):
1942 skip[fn] = True
1945 skip[fn] = True
1943 if copy:
1946 if copy:
1944 skip[copy] = True
1947 skip[copy] = True
1945 del matches[rev]
1948 del matches[rev]
1946 del revfiles[rev]
1949 del revfiles[rev]
1947
1950
1948 return not found
1951 return not found
1949
1952
1950 def heads(ui, repo, *branchrevs, **opts):
1953 def heads(ui, repo, *branchrevs, **opts):
1951 """show current repository heads or show branch heads
1954 """show current repository heads or show branch heads
1952
1955
1953 With no arguments, show all repository branch heads.
1956 With no arguments, show all repository branch heads.
1954
1957
1955 Repository "heads" are changesets with no child changesets. They are
1958 Repository "heads" are changesets with no child changesets. They are
1956 where development generally takes place and are the usual targets
1959 where development generally takes place and are the usual targets
1957 for update and merge operations. Branch heads are changesets that have
1960 for update and merge operations. Branch heads are changesets that have
1958 no child changeset on the same branch.
1961 no child changeset on the same branch.
1959
1962
1960 If one or more REVs are given, only branch heads on the branches
1963 If one or more REVs are given, only branch heads on the branches
1961 associated with the specified changesets are shown.
1964 associated with the specified changesets are shown.
1962
1965
1963 If -c/--closed is specified, also show branch heads marked closed
1966 If -c/--closed is specified, also show branch heads marked closed
1964 (see :hg:`commit --close-branch`).
1967 (see :hg:`commit --close-branch`).
1965
1968
1966 If STARTREV is specified, only those heads that are descendants of
1969 If STARTREV is specified, only those heads that are descendants of
1967 STARTREV will be displayed.
1970 STARTREV will be displayed.
1968
1971
1969 If -t/--topo is specified, named branch mechanics will be ignored and only
1972 If -t/--topo is specified, named branch mechanics will be ignored and only
1970 changesets without children will be shown.
1973 changesets without children will be shown.
1971
1974
1972 Returns 0 if matching heads are found, 1 if not.
1975 Returns 0 if matching heads are found, 1 if not.
1973 """
1976 """
1974
1977
1975 start = None
1978 start = None
1976 if 'rev' in opts:
1979 if 'rev' in opts:
1977 start = cmdutil.revsingle(repo, opts['rev'], None).node()
1980 start = cmdutil.revsingle(repo, opts['rev'], None).node()
1978
1981
1979 if opts.get('topo'):
1982 if opts.get('topo'):
1980 heads = [repo[h] for h in repo.heads(start)]
1983 heads = [repo[h] for h in repo.heads(start)]
1981 else:
1984 else:
1982 heads = []
1985 heads = []
1983 for b, ls in repo.branchmap().iteritems():
1986 for b, ls in repo.branchmap().iteritems():
1984 if start is None:
1987 if start is None:
1985 heads += [repo[h] for h in ls]
1988 heads += [repo[h] for h in ls]
1986 continue
1989 continue
1987 startrev = repo.changelog.rev(start)
1990 startrev = repo.changelog.rev(start)
1988 descendants = set(repo.changelog.descendants(startrev))
1991 descendants = set(repo.changelog.descendants(startrev))
1989 descendants.add(startrev)
1992 descendants.add(startrev)
1990 rev = repo.changelog.rev
1993 rev = repo.changelog.rev
1991 heads += [repo[h] for h in ls if rev(h) in descendants]
1994 heads += [repo[h] for h in ls if rev(h) in descendants]
1992
1995
1993 if branchrevs:
1996 if branchrevs:
1994 branches = set(repo[br].branch() for br in branchrevs)
1997 branches = set(repo[br].branch() for br in branchrevs)
1995 heads = [h for h in heads if h.branch() in branches]
1998 heads = [h for h in heads if h.branch() in branches]
1996
1999
1997 if not opts.get('closed'):
2000 if not opts.get('closed'):
1998 heads = [h for h in heads if not h.extra().get('close')]
2001 heads = [h for h in heads if not h.extra().get('close')]
1999
2002
2000 if opts.get('active') and branchrevs:
2003 if opts.get('active') and branchrevs:
2001 dagheads = repo.heads(start)
2004 dagheads = repo.heads(start)
2002 heads = [h for h in heads if h.node() in dagheads]
2005 heads = [h for h in heads if h.node() in dagheads]
2003
2006
2004 if branchrevs:
2007 if branchrevs:
2005 haveheads = set(h.branch() for h in heads)
2008 haveheads = set(h.branch() for h in heads)
2006 if branches - haveheads:
2009 if branches - haveheads:
2007 headless = ', '.join(b for b in branches - haveheads)
2010 headless = ', '.join(b for b in branches - haveheads)
2008 msg = _('no open branch heads found on branches %s')
2011 msg = _('no open branch heads found on branches %s')
2009 if opts.get('rev'):
2012 if opts.get('rev'):
2010 msg += _(' (started at %s)' % opts['rev'])
2013 msg += _(' (started at %s)' % opts['rev'])
2011 ui.warn((msg + '\n') % headless)
2014 ui.warn((msg + '\n') % headless)
2012
2015
2013 if not heads:
2016 if not heads:
2014 return 1
2017 return 1
2015
2018
2016 heads = sorted(heads, key=lambda x: -x.rev())
2019 heads = sorted(heads, key=lambda x: -x.rev())
2017 displayer = cmdutil.show_changeset(ui, repo, opts)
2020 displayer = cmdutil.show_changeset(ui, repo, opts)
2018 for ctx in heads:
2021 for ctx in heads:
2019 displayer.show(ctx)
2022 displayer.show(ctx)
2020 displayer.close()
2023 displayer.close()
2021
2024
2022 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True):
2025 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True):
2023 """show help for a given topic or a help overview
2026 """show help for a given topic or a help overview
2024
2027
2025 With no arguments, print a list of commands with short help messages.
2028 With no arguments, print a list of commands with short help messages.
2026
2029
2027 Given a topic, extension, or command name, print help for that
2030 Given a topic, extension, or command name, print help for that
2028 topic.
2031 topic.
2029
2032
2030 Returns 0 if successful.
2033 Returns 0 if successful.
2031 """
2034 """
2032 option_lists = []
2035 option_lists = []
2033 textwidth = min(ui.termwidth(), 80) - 2
2036 textwidth = min(ui.termwidth(), 80) - 2
2034
2037
2035 def addglobalopts(aliases):
2038 def addglobalopts(aliases):
2036 if ui.verbose:
2039 if ui.verbose:
2037 option_lists.append((_("global options:"), globalopts))
2040 option_lists.append((_("global options:"), globalopts))
2038 if name == 'shortlist':
2041 if name == 'shortlist':
2039 option_lists.append((_('use "hg help" for the full list '
2042 option_lists.append((_('use "hg help" for the full list '
2040 'of commands'), ()))
2043 'of commands'), ()))
2041 else:
2044 else:
2042 if name == 'shortlist':
2045 if name == 'shortlist':
2043 msg = _('use "hg help" for the full list of commands '
2046 msg = _('use "hg help" for the full list of commands '
2044 'or "hg -v" for details')
2047 'or "hg -v" for details')
2045 elif name and not full:
2048 elif name and not full:
2046 msg = _('use "hg help %s" to show the full help text' % name)
2049 msg = _('use "hg help %s" to show the full help text' % name)
2047 elif aliases:
2050 elif aliases:
2048 msg = _('use "hg -v help%s" to show builtin aliases and '
2051 msg = _('use "hg -v help%s" to show builtin aliases and '
2049 'global options') % (name and " " + name or "")
2052 'global options') % (name and " " + name or "")
2050 else:
2053 else:
2051 msg = _('use "hg -v help %s" to show global options') % name
2054 msg = _('use "hg -v help %s" to show global options') % name
2052 option_lists.append((msg, ()))
2055 option_lists.append((msg, ()))
2053
2056
2054 def helpcmd(name):
2057 def helpcmd(name):
2055 if with_version:
2058 if with_version:
2056 version_(ui)
2059 version_(ui)
2057 ui.write('\n')
2060 ui.write('\n')
2058
2061
2059 try:
2062 try:
2060 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2063 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2061 except error.AmbiguousCommand, inst:
2064 except error.AmbiguousCommand, inst:
2062 # py3k fix: except vars can't be used outside the scope of the
2065 # py3k fix: except vars can't be used outside the scope of the
2063 # except block, nor can be used inside a lambda. python issue4617
2066 # except block, nor can be used inside a lambda. python issue4617
2064 prefix = inst.args[0]
2067 prefix = inst.args[0]
2065 select = lambda c: c.lstrip('^').startswith(prefix)
2068 select = lambda c: c.lstrip('^').startswith(prefix)
2066 helplist(_('list of commands:\n\n'), select)
2069 helplist(_('list of commands:\n\n'), select)
2067 return
2070 return
2068
2071
2069 # check if it's an invalid alias and display its error if it is
2072 # check if it's an invalid alias and display its error if it is
2070 if getattr(entry[0], 'badalias', False):
2073 if getattr(entry[0], 'badalias', False):
2071 if not unknowncmd:
2074 if not unknowncmd:
2072 entry[0](ui)
2075 entry[0](ui)
2073 return
2076 return
2074
2077
2075 # synopsis
2078 # synopsis
2076 if len(entry) > 2:
2079 if len(entry) > 2:
2077 if entry[2].startswith('hg'):
2080 if entry[2].startswith('hg'):
2078 ui.write("%s\n" % entry[2])
2081 ui.write("%s\n" % entry[2])
2079 else:
2082 else:
2080 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2083 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2081 else:
2084 else:
2082 ui.write('hg %s\n' % aliases[0])
2085 ui.write('hg %s\n' % aliases[0])
2083
2086
2084 # aliases
2087 # aliases
2085 if full and not ui.quiet and len(aliases) > 1:
2088 if full and not ui.quiet and len(aliases) > 1:
2086 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2089 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2087
2090
2088 # description
2091 # description
2089 doc = gettext(entry[0].__doc__)
2092 doc = gettext(entry[0].__doc__)
2090 if not doc:
2093 if not doc:
2091 doc = _("(no help text available)")
2094 doc = _("(no help text available)")
2092 if hasattr(entry[0], 'definition'): # aliased command
2095 if hasattr(entry[0], 'definition'): # aliased command
2093 if entry[0].definition.startswith('!'): # shell alias
2096 if entry[0].definition.startswith('!'): # shell alias
2094 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2097 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2095 else:
2098 else:
2096 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2099 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2097 if ui.quiet or not full:
2100 if ui.quiet or not full:
2098 doc = doc.splitlines()[0]
2101 doc = doc.splitlines()[0]
2099 keep = ui.verbose and ['verbose'] or []
2102 keep = ui.verbose and ['verbose'] or []
2100 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2103 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2101 ui.write("\n%s\n" % formatted)
2104 ui.write("\n%s\n" % formatted)
2102 if pruned:
2105 if pruned:
2103 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2106 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2104
2107
2105 if not ui.quiet:
2108 if not ui.quiet:
2106 # options
2109 # options
2107 if entry[1]:
2110 if entry[1]:
2108 option_lists.append((_("options:\n"), entry[1]))
2111 option_lists.append((_("options:\n"), entry[1]))
2109
2112
2110 addglobalopts(False)
2113 addglobalopts(False)
2111
2114
2112 def helplist(header, select=None):
2115 def helplist(header, select=None):
2113 h = {}
2116 h = {}
2114 cmds = {}
2117 cmds = {}
2115 for c, e in table.iteritems():
2118 for c, e in table.iteritems():
2116 f = c.split("|", 1)[0]
2119 f = c.split("|", 1)[0]
2117 if select and not select(f):
2120 if select and not select(f):
2118 continue
2121 continue
2119 if (not select and name != 'shortlist' and
2122 if (not select and name != 'shortlist' and
2120 e[0].__module__ != __name__):
2123 e[0].__module__ != __name__):
2121 continue
2124 continue
2122 if name == "shortlist" and not f.startswith("^"):
2125 if name == "shortlist" and not f.startswith("^"):
2123 continue
2126 continue
2124 f = f.lstrip("^")
2127 f = f.lstrip("^")
2125 if not ui.debugflag and f.startswith("debug"):
2128 if not ui.debugflag and f.startswith("debug"):
2126 continue
2129 continue
2127 doc = e[0].__doc__
2130 doc = e[0].__doc__
2128 if doc and 'DEPRECATED' in doc and not ui.verbose:
2131 if doc and 'DEPRECATED' in doc and not ui.verbose:
2129 continue
2132 continue
2130 doc = gettext(doc)
2133 doc = gettext(doc)
2131 if not doc:
2134 if not doc:
2132 doc = _("(no help text available)")
2135 doc = _("(no help text available)")
2133 h[f] = doc.splitlines()[0].rstrip()
2136 h[f] = doc.splitlines()[0].rstrip()
2134 cmds[f] = c.lstrip("^")
2137 cmds[f] = c.lstrip("^")
2135
2138
2136 if not h:
2139 if not h:
2137 ui.status(_('no commands defined\n'))
2140 ui.status(_('no commands defined\n'))
2138 return
2141 return
2139
2142
2140 ui.status(header)
2143 ui.status(header)
2141 fns = sorted(h)
2144 fns = sorted(h)
2142 m = max(map(len, fns))
2145 m = max(map(len, fns))
2143 for f in fns:
2146 for f in fns:
2144 if ui.verbose:
2147 if ui.verbose:
2145 commands = cmds[f].replace("|",", ")
2148 commands = cmds[f].replace("|",", ")
2146 ui.write(" %s:\n %s\n"%(commands, h[f]))
2149 ui.write(" %s:\n %s\n"%(commands, h[f]))
2147 else:
2150 else:
2148 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2151 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2149 initindent=' %-*s ' % (m, f),
2152 initindent=' %-*s ' % (m, f),
2150 hangindent=' ' * (m + 4))))
2153 hangindent=' ' * (m + 4))))
2151
2154
2152 if not ui.quiet:
2155 if not ui.quiet:
2153 addglobalopts(True)
2156 addglobalopts(True)
2154
2157
2155 def helptopic(name):
2158 def helptopic(name):
2156 for names, header, doc in help.helptable:
2159 for names, header, doc in help.helptable:
2157 if name in names:
2160 if name in names:
2158 break
2161 break
2159 else:
2162 else:
2160 raise error.UnknownCommand(name)
2163 raise error.UnknownCommand(name)
2161
2164
2162 # description
2165 # description
2163 if not doc:
2166 if not doc:
2164 doc = _("(no help text available)")
2167 doc = _("(no help text available)")
2165 if hasattr(doc, '__call__'):
2168 if hasattr(doc, '__call__'):
2166 doc = doc()
2169 doc = doc()
2167
2170
2168 ui.write("%s\n\n" % header)
2171 ui.write("%s\n\n" % header)
2169 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2172 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2170
2173
2171 def helpext(name):
2174 def helpext(name):
2172 try:
2175 try:
2173 mod = extensions.find(name)
2176 mod = extensions.find(name)
2174 doc = gettext(mod.__doc__) or _('no help text available')
2177 doc = gettext(mod.__doc__) or _('no help text available')
2175 except KeyError:
2178 except KeyError:
2176 mod = None
2179 mod = None
2177 doc = extensions.disabledext(name)
2180 doc = extensions.disabledext(name)
2178 if not doc:
2181 if not doc:
2179 raise error.UnknownCommand(name)
2182 raise error.UnknownCommand(name)
2180
2183
2181 if '\n' not in doc:
2184 if '\n' not in doc:
2182 head, tail = doc, ""
2185 head, tail = doc, ""
2183 else:
2186 else:
2184 head, tail = doc.split('\n', 1)
2187 head, tail = doc.split('\n', 1)
2185 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2188 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2186 if tail:
2189 if tail:
2187 ui.write(minirst.format(tail, textwidth))
2190 ui.write(minirst.format(tail, textwidth))
2188 ui.status('\n\n')
2191 ui.status('\n\n')
2189
2192
2190 if mod:
2193 if mod:
2191 try:
2194 try:
2192 ct = mod.cmdtable
2195 ct = mod.cmdtable
2193 except AttributeError:
2196 except AttributeError:
2194 ct = {}
2197 ct = {}
2195 modcmds = set([c.split('|', 1)[0] for c in ct])
2198 modcmds = set([c.split('|', 1)[0] for c in ct])
2196 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2199 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2197 else:
2200 else:
2198 ui.write(_('use "hg help extensions" for information on enabling '
2201 ui.write(_('use "hg help extensions" for information on enabling '
2199 'extensions\n'))
2202 'extensions\n'))
2200
2203
2201 def helpextcmd(name):
2204 def helpextcmd(name):
2202 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2205 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2203 doc = gettext(mod.__doc__).splitlines()[0]
2206 doc = gettext(mod.__doc__).splitlines()[0]
2204
2207
2205 msg = help.listexts(_("'%s' is provided by the following "
2208 msg = help.listexts(_("'%s' is provided by the following "
2206 "extension:") % cmd, {ext: doc}, len(ext),
2209 "extension:") % cmd, {ext: doc}, len(ext),
2207 indent=4)
2210 indent=4)
2208 ui.write(minirst.format(msg, textwidth))
2211 ui.write(minirst.format(msg, textwidth))
2209 ui.write('\n\n')
2212 ui.write('\n\n')
2210 ui.write(_('use "hg help extensions" for information on enabling '
2213 ui.write(_('use "hg help extensions" for information on enabling '
2211 'extensions\n'))
2214 'extensions\n'))
2212
2215
2213 help.addtopichook('revsets', revset.makedoc)
2216 help.addtopichook('revsets', revset.makedoc)
2214 help.addtopichook('templates', templatekw.makedoc)
2217 help.addtopichook('templates', templatekw.makedoc)
2215 help.addtopichook('templates', templatefilters.makedoc)
2218 help.addtopichook('templates', templatefilters.makedoc)
2216
2219
2217 if name and name != 'shortlist':
2220 if name and name != 'shortlist':
2218 i = None
2221 i = None
2219 if unknowncmd:
2222 if unknowncmd:
2220 queries = (helpextcmd,)
2223 queries = (helpextcmd,)
2221 else:
2224 else:
2222 queries = (helptopic, helpcmd, helpext, helpextcmd)
2225 queries = (helptopic, helpcmd, helpext, helpextcmd)
2223 for f in queries:
2226 for f in queries:
2224 try:
2227 try:
2225 f(name)
2228 f(name)
2226 i = None
2229 i = None
2227 break
2230 break
2228 except error.UnknownCommand, inst:
2231 except error.UnknownCommand, inst:
2229 i = inst
2232 i = inst
2230 if i:
2233 if i:
2231 raise i
2234 raise i
2232
2235
2233 else:
2236 else:
2234 # program name
2237 # program name
2235 if ui.verbose or with_version:
2238 if ui.verbose or with_version:
2236 version_(ui)
2239 version_(ui)
2237 else:
2240 else:
2238 ui.status(_("Mercurial Distributed SCM\n"))
2241 ui.status(_("Mercurial Distributed SCM\n"))
2239 ui.status('\n')
2242 ui.status('\n')
2240
2243
2241 # list of commands
2244 # list of commands
2242 if name == "shortlist":
2245 if name == "shortlist":
2243 header = _('basic commands:\n\n')
2246 header = _('basic commands:\n\n')
2244 else:
2247 else:
2245 header = _('list of commands:\n\n')
2248 header = _('list of commands:\n\n')
2246
2249
2247 helplist(header)
2250 helplist(header)
2248 if name != 'shortlist':
2251 if name != 'shortlist':
2249 exts, maxlength = extensions.enabled()
2252 exts, maxlength = extensions.enabled()
2250 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2253 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2251 if text:
2254 if text:
2252 ui.write("\n%s\n" % minirst.format(text, textwidth))
2255 ui.write("\n%s\n" % minirst.format(text, textwidth))
2253
2256
2254 # list all option lists
2257 # list all option lists
2255 opt_output = []
2258 opt_output = []
2256 multioccur = False
2259 multioccur = False
2257 for title, options in option_lists:
2260 for title, options in option_lists:
2258 opt_output.append(("\n%s" % title, None))
2261 opt_output.append(("\n%s" % title, None))
2259 for option in options:
2262 for option in options:
2260 if len(option) == 5:
2263 if len(option) == 5:
2261 shortopt, longopt, default, desc, optlabel = option
2264 shortopt, longopt, default, desc, optlabel = option
2262 else:
2265 else:
2263 shortopt, longopt, default, desc = option
2266 shortopt, longopt, default, desc = option
2264 optlabel = _("VALUE") # default label
2267 optlabel = _("VALUE") # default label
2265
2268
2266 if _("DEPRECATED") in desc and not ui.verbose:
2269 if _("DEPRECATED") in desc and not ui.verbose:
2267 continue
2270 continue
2268 if isinstance(default, list):
2271 if isinstance(default, list):
2269 numqualifier = " %s [+]" % optlabel
2272 numqualifier = " %s [+]" % optlabel
2270 multioccur = True
2273 multioccur = True
2271 elif (default is not None) and not isinstance(default, bool):
2274 elif (default is not None) and not isinstance(default, bool):
2272 numqualifier = " %s" % optlabel
2275 numqualifier = " %s" % optlabel
2273 else:
2276 else:
2274 numqualifier = ""
2277 numqualifier = ""
2275 opt_output.append(("%2s%s" %
2278 opt_output.append(("%2s%s" %
2276 (shortopt and "-%s" % shortopt,
2279 (shortopt and "-%s" % shortopt,
2277 longopt and " --%s%s" %
2280 longopt and " --%s%s" %
2278 (longopt, numqualifier)),
2281 (longopt, numqualifier)),
2279 "%s%s" % (desc,
2282 "%s%s" % (desc,
2280 default
2283 default
2281 and _(" (default: %s)") % default
2284 and _(" (default: %s)") % default
2282 or "")))
2285 or "")))
2283 if multioccur:
2286 if multioccur:
2284 msg = _("\n[+] marked option can be specified multiple times")
2287 msg = _("\n[+] marked option can be specified multiple times")
2285 if ui.verbose and name != 'shortlist':
2288 if ui.verbose and name != 'shortlist':
2286 opt_output.append((msg, None))
2289 opt_output.append((msg, None))
2287 else:
2290 else:
2288 opt_output.insert(-1, (msg, None))
2291 opt_output.insert(-1, (msg, None))
2289
2292
2290 if not name:
2293 if not name:
2291 ui.write(_("\nadditional help topics:\n\n"))
2294 ui.write(_("\nadditional help topics:\n\n"))
2292 topics = []
2295 topics = []
2293 for names, header, doc in help.helptable:
2296 for names, header, doc in help.helptable:
2294 topics.append((sorted(names, key=len, reverse=True)[0], header))
2297 topics.append((sorted(names, key=len, reverse=True)[0], header))
2295 topics_len = max([len(s[0]) for s in topics])
2298 topics_len = max([len(s[0]) for s in topics])
2296 for t, desc in topics:
2299 for t, desc in topics:
2297 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2300 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2298
2301
2299 if opt_output:
2302 if opt_output:
2300 colwidth = encoding.colwidth
2303 colwidth = encoding.colwidth
2301 # normalize: (opt or message, desc or None, width of opt)
2304 # normalize: (opt or message, desc or None, width of opt)
2302 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2305 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2303 for opt, desc in opt_output]
2306 for opt, desc in opt_output]
2304 hanging = max([e[2] for e in entries])
2307 hanging = max([e[2] for e in entries])
2305 for opt, desc, width in entries:
2308 for opt, desc, width in entries:
2306 if desc:
2309 if desc:
2307 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2310 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2308 hangindent = ' ' * (hanging + 3)
2311 hangindent = ' ' * (hanging + 3)
2309 ui.write('%s\n' % (util.wrap(desc, textwidth,
2312 ui.write('%s\n' % (util.wrap(desc, textwidth,
2310 initindent=initindent,
2313 initindent=initindent,
2311 hangindent=hangindent)))
2314 hangindent=hangindent)))
2312 else:
2315 else:
2313 ui.write("%s\n" % opt)
2316 ui.write("%s\n" % opt)
2314
2317
2315 def identify(ui, repo, source=None, rev=None,
2318 def identify(ui, repo, source=None, rev=None,
2316 num=None, id=None, branch=None, tags=None, bookmarks=None):
2319 num=None, id=None, branch=None, tags=None, bookmarks=None):
2317 """identify the working copy or specified revision
2320 """identify the working copy or specified revision
2318
2321
2319 Print a summary identifying the repository state at REV using one or
2322 Print a summary identifying the repository state at REV using one or
2320 two parent hash identifiers, followed by a "+" if the working
2323 two parent hash identifiers, followed by a "+" if the working
2321 directory has uncommitted changes, the branch name (if not default),
2324 directory has uncommitted changes, the branch name (if not default),
2322 a list of tags, and a list of bookmarks.
2325 a list of tags, and a list of bookmarks.
2323
2326
2324 When REV is not given, print a summary of the current state of the
2327 When REV is not given, print a summary of the current state of the
2325 repository.
2328 repository.
2326
2329
2327 Specifying a path to a repository root or Mercurial bundle will
2330 Specifying a path to a repository root or Mercurial bundle will
2328 cause lookup to operate on that repository/bundle.
2331 cause lookup to operate on that repository/bundle.
2329
2332
2330 Returns 0 if successful.
2333 Returns 0 if successful.
2331 """
2334 """
2332
2335
2333 if not repo and not source:
2336 if not repo and not source:
2334 raise util.Abort(_("there is no Mercurial repository here "
2337 raise util.Abort(_("there is no Mercurial repository here "
2335 "(.hg not found)"))
2338 "(.hg not found)"))
2336
2339
2337 hexfunc = ui.debugflag and hex or short
2340 hexfunc = ui.debugflag and hex or short
2338 default = not (num or id or branch or tags or bookmarks)
2341 default = not (num or id or branch or tags or bookmarks)
2339 output = []
2342 output = []
2340 revs = []
2343 revs = []
2341
2344
2342 if source:
2345 if source:
2343 source, branches = hg.parseurl(ui.expandpath(source))
2346 source, branches = hg.parseurl(ui.expandpath(source))
2344 repo = hg.repository(ui, source)
2347 repo = hg.repository(ui, source)
2345 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2348 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2346
2349
2347 if not repo.local():
2350 if not repo.local():
2348 if num or branch or tags:
2351 if num or branch or tags:
2349 raise util.Abort(
2352 raise util.Abort(
2350 _("can't query remote revision number, branch, or tags"))
2353 _("can't query remote revision number, branch, or tags"))
2351 if not rev and revs:
2354 if not rev and revs:
2352 rev = revs[0]
2355 rev = revs[0]
2353 if not rev:
2356 if not rev:
2354 rev = "tip"
2357 rev = "tip"
2355
2358
2356 remoterev = repo.lookup(rev)
2359 remoterev = repo.lookup(rev)
2357 if default or id:
2360 if default or id:
2358 output = [hexfunc(remoterev)]
2361 output = [hexfunc(remoterev)]
2359
2362
2360 def getbms():
2363 def getbms():
2361 bms = []
2364 bms = []
2362
2365
2363 if 'bookmarks' in repo.listkeys('namespaces'):
2366 if 'bookmarks' in repo.listkeys('namespaces'):
2364 hexremoterev = hex(remoterev)
2367 hexremoterev = hex(remoterev)
2365 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2368 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2366 if bmr == hexremoterev]
2369 if bmr == hexremoterev]
2367
2370
2368 return bms
2371 return bms
2369
2372
2370 if bookmarks:
2373 if bookmarks:
2371 output.extend(getbms())
2374 output.extend(getbms())
2372 elif default and not ui.quiet:
2375 elif default and not ui.quiet:
2373 # multiple bookmarks for a single parent separated by '/'
2376 # multiple bookmarks for a single parent separated by '/'
2374 bm = '/'.join(getbms())
2377 bm = '/'.join(getbms())
2375 if bm:
2378 if bm:
2376 output.append(bm)
2379 output.append(bm)
2377 else:
2380 else:
2378 if not rev:
2381 if not rev:
2379 ctx = repo[None]
2382 ctx = repo[None]
2380 parents = ctx.parents()
2383 parents = ctx.parents()
2381 changed = ""
2384 changed = ""
2382 if default or id or num:
2385 if default or id or num:
2383 changed = util.any(repo.status()) and "+" or ""
2386 changed = util.any(repo.status()) and "+" or ""
2384 if default or id:
2387 if default or id:
2385 output = ["%s%s" %
2388 output = ["%s%s" %
2386 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2389 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2387 if num:
2390 if num:
2388 output.append("%s%s" %
2391 output.append("%s%s" %
2389 ('+'.join([str(p.rev()) for p in parents]), changed))
2392 ('+'.join([str(p.rev()) for p in parents]), changed))
2390 else:
2393 else:
2391 ctx = cmdutil.revsingle(repo, rev)
2394 ctx = cmdutil.revsingle(repo, rev)
2392 if default or id:
2395 if default or id:
2393 output = [hexfunc(ctx.node())]
2396 output = [hexfunc(ctx.node())]
2394 if num:
2397 if num:
2395 output.append(str(ctx.rev()))
2398 output.append(str(ctx.rev()))
2396
2399
2397 if default and not ui.quiet:
2400 if default and not ui.quiet:
2398 b = ctx.branch()
2401 b = ctx.branch()
2399 if b != 'default':
2402 if b != 'default':
2400 output.append("(%s)" % b)
2403 output.append("(%s)" % b)
2401
2404
2402 # multiple tags for a single parent separated by '/'
2405 # multiple tags for a single parent separated by '/'
2403 t = '/'.join(ctx.tags())
2406 t = '/'.join(ctx.tags())
2404 if t:
2407 if t:
2405 output.append(t)
2408 output.append(t)
2406
2409
2407 # multiple bookmarks for a single parent separated by '/'
2410 # multiple bookmarks for a single parent separated by '/'
2408 bm = '/'.join(ctx.bookmarks())
2411 bm = '/'.join(ctx.bookmarks())
2409 if bm:
2412 if bm:
2410 output.append(bm)
2413 output.append(bm)
2411 else:
2414 else:
2412 if branch:
2415 if branch:
2413 output.append(ctx.branch())
2416 output.append(ctx.branch())
2414
2417
2415 if tags:
2418 if tags:
2416 output.extend(ctx.tags())
2419 output.extend(ctx.tags())
2417
2420
2418 if bookmarks:
2421 if bookmarks:
2419 output.extend(ctx.bookmarks())
2422 output.extend(ctx.bookmarks())
2420
2423
2421 ui.write("%s\n" % ' '.join(output))
2424 ui.write("%s\n" % ' '.join(output))
2422
2425
2423 def import_(ui, repo, patch1, *patches, **opts):
2426 def import_(ui, repo, patch1, *patches, **opts):
2424 """import an ordered set of patches
2427 """import an ordered set of patches
2425
2428
2426 Import a list of patches and commit them individually (unless
2429 Import a list of patches and commit them individually (unless
2427 --no-commit is specified).
2430 --no-commit is specified).
2428
2431
2429 If there are outstanding changes in the working directory, import
2432 If there are outstanding changes in the working directory, import
2430 will abort unless given the -f/--force flag.
2433 will abort unless given the -f/--force flag.
2431
2434
2432 You can import a patch straight from a mail message. Even patches
2435 You can import a patch straight from a mail message. Even patches
2433 as attachments work (to use the body part, it must have type
2436 as attachments work (to use the body part, it must have type
2434 text/plain or text/x-patch). From and Subject headers of email
2437 text/plain or text/x-patch). From and Subject headers of email
2435 message are used as default committer and commit message. All
2438 message are used as default committer and commit message. All
2436 text/plain body parts before first diff are added to commit
2439 text/plain body parts before first diff are added to commit
2437 message.
2440 message.
2438
2441
2439 If the imported patch was generated by :hg:`export`, user and
2442 If the imported patch was generated by :hg:`export`, user and
2440 description from patch override values from message headers and
2443 description from patch override values from message headers and
2441 body. Values given on command line with -m/--message and -u/--user
2444 body. Values given on command line with -m/--message and -u/--user
2442 override these.
2445 override these.
2443
2446
2444 If --exact is specified, import will set the working directory to
2447 If --exact is specified, import will set the working directory to
2445 the parent of each patch before applying it, and will abort if the
2448 the parent of each patch before applying it, and will abort if the
2446 resulting changeset has a different ID than the one recorded in
2449 resulting changeset has a different ID than the one recorded in
2447 the patch. This may happen due to character set problems or other
2450 the patch. This may happen due to character set problems or other
2448 deficiencies in the text patch format.
2451 deficiencies in the text patch format.
2449
2452
2450 With -s/--similarity, hg will attempt to discover renames and
2453 With -s/--similarity, hg will attempt to discover renames and
2451 copies in the patch in the same way as 'addremove'.
2454 copies in the patch in the same way as 'addremove'.
2452
2455
2453 To read a patch from standard input, use "-" as the patch name. If
2456 To read a patch from standard input, use "-" as the patch name. If
2454 a URL is specified, the patch will be downloaded from it.
2457 a URL is specified, the patch will be downloaded from it.
2455 See :hg:`help dates` for a list of formats valid for -d/--date.
2458 See :hg:`help dates` for a list of formats valid for -d/--date.
2456
2459
2457 Returns 0 on success.
2460 Returns 0 on success.
2458 """
2461 """
2459 patches = (patch1,) + patches
2462 patches = (patch1,) + patches
2460
2463
2461 date = opts.get('date')
2464 date = opts.get('date')
2462 if date:
2465 if date:
2463 opts['date'] = util.parsedate(date)
2466 opts['date'] = util.parsedate(date)
2464
2467
2465 try:
2468 try:
2466 sim = float(opts.get('similarity') or 0)
2469 sim = float(opts.get('similarity') or 0)
2467 except ValueError:
2470 except ValueError:
2468 raise util.Abort(_('similarity must be a number'))
2471 raise util.Abort(_('similarity must be a number'))
2469 if sim < 0 or sim > 100:
2472 if sim < 0 or sim > 100:
2470 raise util.Abort(_('similarity must be between 0 and 100'))
2473 raise util.Abort(_('similarity must be between 0 and 100'))
2471
2474
2472 if opts.get('exact') or not opts.get('force'):
2475 if opts.get('exact') or not opts.get('force'):
2473 cmdutil.bail_if_changed(repo)
2476 cmdutil.bail_if_changed(repo)
2474
2477
2475 d = opts["base"]
2478 d = opts["base"]
2476 strip = opts["strip"]
2479 strip = opts["strip"]
2477 wlock = lock = None
2480 wlock = lock = None
2478 msgs = []
2481 msgs = []
2479
2482
2480 def tryone(ui, hunk):
2483 def tryone(ui, hunk):
2481 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2484 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2482 patch.extract(ui, hunk)
2485 patch.extract(ui, hunk)
2483
2486
2484 if not tmpname:
2487 if not tmpname:
2485 return None
2488 return None
2486 commitid = _('to working directory')
2489 commitid = _('to working directory')
2487
2490
2488 try:
2491 try:
2489 cmdline_message = cmdutil.logmessage(opts)
2492 cmdline_message = cmdutil.logmessage(opts)
2490 if cmdline_message:
2493 if cmdline_message:
2491 # pickup the cmdline msg
2494 # pickup the cmdline msg
2492 message = cmdline_message
2495 message = cmdline_message
2493 elif message:
2496 elif message:
2494 # pickup the patch msg
2497 # pickup the patch msg
2495 message = message.strip()
2498 message = message.strip()
2496 else:
2499 else:
2497 # launch the editor
2500 # launch the editor
2498 message = None
2501 message = None
2499 ui.debug('message:\n%s\n' % message)
2502 ui.debug('message:\n%s\n' % message)
2500
2503
2501 wp = repo.parents()
2504 wp = repo.parents()
2502 if opts.get('exact'):
2505 if opts.get('exact'):
2503 if not nodeid or not p1:
2506 if not nodeid or not p1:
2504 raise util.Abort(_('not a Mercurial patch'))
2507 raise util.Abort(_('not a Mercurial patch'))
2505 p1 = repo.lookup(p1)
2508 p1 = repo.lookup(p1)
2506 p2 = repo.lookup(p2 or hex(nullid))
2509 p2 = repo.lookup(p2 or hex(nullid))
2507
2510
2508 if p1 != wp[0].node():
2511 if p1 != wp[0].node():
2509 hg.clean(repo, p1)
2512 hg.clean(repo, p1)
2510 repo.dirstate.setparents(p1, p2)
2513 repo.dirstate.setparents(p1, p2)
2511 elif p2:
2514 elif p2:
2512 try:
2515 try:
2513 p1 = repo.lookup(p1)
2516 p1 = repo.lookup(p1)
2514 p2 = repo.lookup(p2)
2517 p2 = repo.lookup(p2)
2515 if p1 == wp[0].node():
2518 if p1 == wp[0].node():
2516 repo.dirstate.setparents(p1, p2)
2519 repo.dirstate.setparents(p1, p2)
2517 except error.RepoError:
2520 except error.RepoError:
2518 pass
2521 pass
2519 if opts.get('exact') or opts.get('import_branch'):
2522 if opts.get('exact') or opts.get('import_branch'):
2520 repo.dirstate.setbranch(branch or 'default')
2523 repo.dirstate.setbranch(branch or 'default')
2521
2524
2522 files = {}
2525 files = {}
2523 try:
2526 try:
2524 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2527 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2525 files=files, eolmode=None)
2528 files=files, eolmode=None)
2526 finally:
2529 finally:
2527 files = cmdutil.updatedir(ui, repo, files,
2530 files = cmdutil.updatedir(ui, repo, files,
2528 similarity=sim / 100.0)
2531 similarity=sim / 100.0)
2529 if opts.get('no_commit'):
2532 if opts.get('no_commit'):
2530 if message:
2533 if message:
2531 msgs.append(message)
2534 msgs.append(message)
2532 else:
2535 else:
2533 if opts.get('exact'):
2536 if opts.get('exact'):
2534 m = None
2537 m = None
2535 else:
2538 else:
2536 m = cmdutil.matchfiles(repo, files or [])
2539 m = cmdutil.matchfiles(repo, files or [])
2537 n = repo.commit(message, opts.get('user') or user,
2540 n = repo.commit(message, opts.get('user') or user,
2538 opts.get('date') or date, match=m,
2541 opts.get('date') or date, match=m,
2539 editor=cmdutil.commiteditor)
2542 editor=cmdutil.commiteditor)
2540 if opts.get('exact'):
2543 if opts.get('exact'):
2541 if hex(n) != nodeid:
2544 if hex(n) != nodeid:
2542 repo.rollback()
2545 repo.rollback()
2543 raise util.Abort(_('patch is damaged'
2546 raise util.Abort(_('patch is damaged'
2544 ' or loses information'))
2547 ' or loses information'))
2545 # Force a dirstate write so that the next transaction
2548 # Force a dirstate write so that the next transaction
2546 # backups an up-do-date file.
2549 # backups an up-do-date file.
2547 repo.dirstate.write()
2550 repo.dirstate.write()
2548 if n:
2551 if n:
2549 commitid = short(n)
2552 commitid = short(n)
2550
2553
2551 return commitid
2554 return commitid
2552 finally:
2555 finally:
2553 os.unlink(tmpname)
2556 os.unlink(tmpname)
2554
2557
2555 try:
2558 try:
2556 wlock = repo.wlock()
2559 wlock = repo.wlock()
2557 lock = repo.lock()
2560 lock = repo.lock()
2558 lastcommit = None
2561 lastcommit = None
2559 for p in patches:
2562 for p in patches:
2560 pf = os.path.join(d, p)
2563 pf = os.path.join(d, p)
2561
2564
2562 if pf == '-':
2565 if pf == '-':
2563 ui.status(_("applying patch from stdin\n"))
2566 ui.status(_("applying patch from stdin\n"))
2564 pf = sys.stdin
2567 pf = sys.stdin
2565 else:
2568 else:
2566 ui.status(_("applying %s\n") % p)
2569 ui.status(_("applying %s\n") % p)
2567 pf = url.open(ui, pf)
2570 pf = url.open(ui, pf)
2568
2571
2569 haspatch = False
2572 haspatch = False
2570 for hunk in patch.split(pf):
2573 for hunk in patch.split(pf):
2571 commitid = tryone(ui, hunk)
2574 commitid = tryone(ui, hunk)
2572 if commitid:
2575 if commitid:
2573 haspatch = True
2576 haspatch = True
2574 if lastcommit:
2577 if lastcommit:
2575 ui.status(_('applied %s\n') % lastcommit)
2578 ui.status(_('applied %s\n') % lastcommit)
2576 lastcommit = commitid
2579 lastcommit = commitid
2577
2580
2578 if not haspatch:
2581 if not haspatch:
2579 raise util.Abort(_('no diffs found'))
2582 raise util.Abort(_('no diffs found'))
2580
2583
2581 if msgs:
2584 if msgs:
2582 repo.opener('last-message.txt', 'wb').write('\n* * *\n'.join(msgs))
2585 repo.opener('last-message.txt', 'wb').write('\n* * *\n'.join(msgs))
2583 finally:
2586 finally:
2584 release(lock, wlock)
2587 release(lock, wlock)
2585
2588
2586 def incoming(ui, repo, source="default", **opts):
2589 def incoming(ui, repo, source="default", **opts):
2587 """show new changesets found in source
2590 """show new changesets found in source
2588
2591
2589 Show new changesets found in the specified path/URL or the default
2592 Show new changesets found in the specified path/URL or the default
2590 pull location. These are the changesets that would have been pulled
2593 pull location. These are the changesets that would have been pulled
2591 if a pull at the time you issued this command.
2594 if a pull at the time you issued this command.
2592
2595
2593 For remote repository, using --bundle avoids downloading the
2596 For remote repository, using --bundle avoids downloading the
2594 changesets twice if the incoming is followed by a pull.
2597 changesets twice if the incoming is followed by a pull.
2595
2598
2596 See pull for valid source format details.
2599 See pull for valid source format details.
2597
2600
2598 Returns 0 if there are incoming changes, 1 otherwise.
2601 Returns 0 if there are incoming changes, 1 otherwise.
2599 """
2602 """
2600 if opts.get('bundle') and opts.get('subrepos'):
2603 if opts.get('bundle') and opts.get('subrepos'):
2601 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2604 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2602
2605
2603 if opts.get('bookmarks'):
2606 if opts.get('bookmarks'):
2604 source, branches = hg.parseurl(ui.expandpath(source),
2607 source, branches = hg.parseurl(ui.expandpath(source),
2605 opts.get('branch'))
2608 opts.get('branch'))
2606 other = hg.repository(hg.remoteui(repo, opts), source)
2609 other = hg.repository(hg.remoteui(repo, opts), source)
2607 if 'bookmarks' not in other.listkeys('namespaces'):
2610 if 'bookmarks' not in other.listkeys('namespaces'):
2608 ui.warn(_("remote doesn't support bookmarks\n"))
2611 ui.warn(_("remote doesn't support bookmarks\n"))
2609 return 0
2612 return 0
2610 ui.status(_('comparing with %s\n') % util.hidepassword(source))
2613 ui.status(_('comparing with %s\n') % util.hidepassword(source))
2611 return bookmarks.diff(ui, repo, other)
2614 return bookmarks.diff(ui, repo, other)
2612
2615
2613 ret = hg.incoming(ui, repo, source, opts)
2616 ret = hg.incoming(ui, repo, source, opts)
2614 return ret
2617 return ret
2615
2618
2616 def init(ui, dest=".", **opts):
2619 def init(ui, dest=".", **opts):
2617 """create a new repository in the given directory
2620 """create a new repository in the given directory
2618
2621
2619 Initialize a new repository in the given directory. If the given
2622 Initialize a new repository in the given directory. If the given
2620 directory does not exist, it will be created.
2623 directory does not exist, it will be created.
2621
2624
2622 If no directory is given, the current directory is used.
2625 If no directory is given, the current directory is used.
2623
2626
2624 It is possible to specify an ``ssh://`` URL as the destination.
2627 It is possible to specify an ``ssh://`` URL as the destination.
2625 See :hg:`help urls` for more information.
2628 See :hg:`help urls` for more information.
2626
2629
2627 Returns 0 on success.
2630 Returns 0 on success.
2628 """
2631 """
2629 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2632 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2630
2633
2631 def locate(ui, repo, *pats, **opts):
2634 def locate(ui, repo, *pats, **opts):
2632 """locate files matching specific patterns
2635 """locate files matching specific patterns
2633
2636
2634 Print files under Mercurial control in the working directory whose
2637 Print files under Mercurial control in the working directory whose
2635 names match the given patterns.
2638 names match the given patterns.
2636
2639
2637 By default, this command searches all directories in the working
2640 By default, this command searches all directories in the working
2638 directory. To search just the current directory and its
2641 directory. To search just the current directory and its
2639 subdirectories, use "--include .".
2642 subdirectories, use "--include .".
2640
2643
2641 If no patterns are given to match, this command prints the names
2644 If no patterns are given to match, this command prints the names
2642 of all files under Mercurial control in the working directory.
2645 of all files under Mercurial control in the working directory.
2643
2646
2644 If you want to feed the output of this command into the "xargs"
2647 If you want to feed the output of this command into the "xargs"
2645 command, use the -0 option to both this command and "xargs". This
2648 command, use the -0 option to both this command and "xargs". This
2646 will avoid the problem of "xargs" treating single filenames that
2649 will avoid the problem of "xargs" treating single filenames that
2647 contain whitespace as multiple filenames.
2650 contain whitespace as multiple filenames.
2648
2651
2649 Returns 0 if a match is found, 1 otherwise.
2652 Returns 0 if a match is found, 1 otherwise.
2650 """
2653 """
2651 end = opts.get('print0') and '\0' or '\n'
2654 end = opts.get('print0') and '\0' or '\n'
2652 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2655 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2653
2656
2654 ret = 1
2657 ret = 1
2655 m = cmdutil.match(repo, pats, opts, default='relglob')
2658 m = cmdutil.match(repo, pats, opts, default='relglob')
2656 m.bad = lambda x, y: False
2659 m.bad = lambda x, y: False
2657 for abs in repo[rev].walk(m):
2660 for abs in repo[rev].walk(m):
2658 if not rev and abs not in repo.dirstate:
2661 if not rev and abs not in repo.dirstate:
2659 continue
2662 continue
2660 if opts.get('fullpath'):
2663 if opts.get('fullpath'):
2661 ui.write(repo.wjoin(abs), end)
2664 ui.write(repo.wjoin(abs), end)
2662 else:
2665 else:
2663 ui.write(((pats and m.rel(abs)) or abs), end)
2666 ui.write(((pats and m.rel(abs)) or abs), end)
2664 ret = 0
2667 ret = 0
2665
2668
2666 return ret
2669 return ret
2667
2670
2668 def log(ui, repo, *pats, **opts):
2671 def log(ui, repo, *pats, **opts):
2669 """show revision history of entire repository or files
2672 """show revision history of entire repository or files
2670
2673
2671 Print the revision history of the specified files or the entire
2674 Print the revision history of the specified files or the entire
2672 project.
2675 project.
2673
2676
2674 File history is shown without following rename or copy history of
2677 File history is shown without following rename or copy history of
2675 files. Use -f/--follow with a filename to follow history across
2678 files. Use -f/--follow with a filename to follow history across
2676 renames and copies. --follow without a filename will only show
2679 renames and copies. --follow without a filename will only show
2677 ancestors or descendants of the starting revision. --follow-first
2680 ancestors or descendants of the starting revision. --follow-first
2678 only follows the first parent of merge revisions.
2681 only follows the first parent of merge revisions.
2679
2682
2680 If no revision range is specified, the default is ``tip:0`` unless
2683 If no revision range is specified, the default is ``tip:0`` unless
2681 --follow is set, in which case the working directory parent is
2684 --follow is set, in which case the working directory parent is
2682 used as the starting revision. You can specify a revision set for
2685 used as the starting revision. You can specify a revision set for
2683 log, see :hg:`help revsets` for more information.
2686 log, see :hg:`help revsets` for more information.
2684
2687
2685 See :hg:`help dates` for a list of formats valid for -d/--date.
2688 See :hg:`help dates` for a list of formats valid for -d/--date.
2686
2689
2687 By default this command prints revision number and changeset id,
2690 By default this command prints revision number and changeset id,
2688 tags, non-trivial parents, user, date and time, and a summary for
2691 tags, non-trivial parents, user, date and time, and a summary for
2689 each commit. When the -v/--verbose switch is used, the list of
2692 each commit. When the -v/--verbose switch is used, the list of
2690 changed files and full commit message are shown.
2693 changed files and full commit message are shown.
2691
2694
2692 .. note::
2695 .. note::
2693 log -p/--patch may generate unexpected diff output for merge
2696 log -p/--patch may generate unexpected diff output for merge
2694 changesets, as it will only compare the merge changeset against
2697 changesets, as it will only compare the merge changeset against
2695 its first parent. Also, only files different from BOTH parents
2698 its first parent. Also, only files different from BOTH parents
2696 will appear in files:.
2699 will appear in files:.
2697
2700
2698 Returns 0 on success.
2701 Returns 0 on success.
2699 """
2702 """
2700
2703
2701 matchfn = cmdutil.match(repo, pats, opts)
2704 matchfn = cmdutil.match(repo, pats, opts)
2702 limit = cmdutil.loglimit(opts)
2705 limit = cmdutil.loglimit(opts)
2703 count = 0
2706 count = 0
2704
2707
2705 endrev = None
2708 endrev = None
2706 if opts.get('copies') and opts.get('rev'):
2709 if opts.get('copies') and opts.get('rev'):
2707 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2710 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2708
2711
2709 df = False
2712 df = False
2710 if opts["date"]:
2713 if opts["date"]:
2711 df = util.matchdate(opts["date"])
2714 df = util.matchdate(opts["date"])
2712
2715
2713 branches = opts.get('branch', []) + opts.get('only_branch', [])
2716 branches = opts.get('branch', []) + opts.get('only_branch', [])
2714 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2717 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2715
2718
2716 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2719 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2717 def prep(ctx, fns):
2720 def prep(ctx, fns):
2718 rev = ctx.rev()
2721 rev = ctx.rev()
2719 parents = [p for p in repo.changelog.parentrevs(rev)
2722 parents = [p for p in repo.changelog.parentrevs(rev)
2720 if p != nullrev]
2723 if p != nullrev]
2721 if opts.get('no_merges') and len(parents) == 2:
2724 if opts.get('no_merges') and len(parents) == 2:
2722 return
2725 return
2723 if opts.get('only_merges') and len(parents) != 2:
2726 if opts.get('only_merges') and len(parents) != 2:
2724 return
2727 return
2725 if opts.get('branch') and ctx.branch() not in opts['branch']:
2728 if opts.get('branch') and ctx.branch() not in opts['branch']:
2726 return
2729 return
2727 if df and not df(ctx.date()[0]):
2730 if df and not df(ctx.date()[0]):
2728 return
2731 return
2729 if opts['user'] and not [k for k in opts['user']
2732 if opts['user'] and not [k for k in opts['user']
2730 if k.lower() in ctx.user().lower()]:
2733 if k.lower() in ctx.user().lower()]:
2731 return
2734 return
2732 if opts.get('keyword'):
2735 if opts.get('keyword'):
2733 for k in [kw.lower() for kw in opts['keyword']]:
2736 for k in [kw.lower() for kw in opts['keyword']]:
2734 if (k in ctx.user().lower() or
2737 if (k in ctx.user().lower() or
2735 k in ctx.description().lower() or
2738 k in ctx.description().lower() or
2736 k in " ".join(ctx.files()).lower()):
2739 k in " ".join(ctx.files()).lower()):
2737 break
2740 break
2738 else:
2741 else:
2739 return
2742 return
2740
2743
2741 copies = None
2744 copies = None
2742 if opts.get('copies') and rev:
2745 if opts.get('copies') and rev:
2743 copies = []
2746 copies = []
2744 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2747 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2745 for fn in ctx.files():
2748 for fn in ctx.files():
2746 rename = getrenamed(fn, rev)
2749 rename = getrenamed(fn, rev)
2747 if rename:
2750 if rename:
2748 copies.append((fn, rename[0]))
2751 copies.append((fn, rename[0]))
2749
2752
2750 revmatchfn = None
2753 revmatchfn = None
2751 if opts.get('patch') or opts.get('stat'):
2754 if opts.get('patch') or opts.get('stat'):
2752 if opts.get('follow') or opts.get('follow_first'):
2755 if opts.get('follow') or opts.get('follow_first'):
2753 # note: this might be wrong when following through merges
2756 # note: this might be wrong when following through merges
2754 revmatchfn = cmdutil.match(repo, fns, default='path')
2757 revmatchfn = cmdutil.match(repo, fns, default='path')
2755 else:
2758 else:
2756 revmatchfn = matchfn
2759 revmatchfn = matchfn
2757
2760
2758 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2761 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2759
2762
2760 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2763 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2761 if count == limit:
2764 if count == limit:
2762 break
2765 break
2763 if displayer.flush(ctx.rev()):
2766 if displayer.flush(ctx.rev()):
2764 count += 1
2767 count += 1
2765 displayer.close()
2768 displayer.close()
2766
2769
2767 def manifest(ui, repo, node=None, rev=None):
2770 def manifest(ui, repo, node=None, rev=None):
2768 """output the current or given revision of the project manifest
2771 """output the current or given revision of the project manifest
2769
2772
2770 Print a list of version controlled files for the given revision.
2773 Print a list of version controlled files for the given revision.
2771 If no revision is given, the first parent of the working directory
2774 If no revision is given, the first parent of the working directory
2772 is used, or the null revision if no revision is checked out.
2775 is used, or the null revision if no revision is checked out.
2773
2776
2774 With -v, print file permissions, symlink and executable bits.
2777 With -v, print file permissions, symlink and executable bits.
2775 With --debug, print file revision hashes.
2778 With --debug, print file revision hashes.
2776
2779
2777 Returns 0 on success.
2780 Returns 0 on success.
2778 """
2781 """
2779
2782
2780 if rev and node:
2783 if rev and node:
2781 raise util.Abort(_("please specify just one revision"))
2784 raise util.Abort(_("please specify just one revision"))
2782
2785
2783 if not node:
2786 if not node:
2784 node = rev
2787 node = rev
2785
2788
2786 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2789 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2787 ctx = cmdutil.revsingle(repo, node)
2790 ctx = cmdutil.revsingle(repo, node)
2788 for f in ctx:
2791 for f in ctx:
2789 if ui.debugflag:
2792 if ui.debugflag:
2790 ui.write("%40s " % hex(ctx.manifest()[f]))
2793 ui.write("%40s " % hex(ctx.manifest()[f]))
2791 if ui.verbose:
2794 if ui.verbose:
2792 ui.write(decor[ctx.flags(f)])
2795 ui.write(decor[ctx.flags(f)])
2793 ui.write("%s\n" % f)
2796 ui.write("%s\n" % f)
2794
2797
2795 def merge(ui, repo, node=None, **opts):
2798 def merge(ui, repo, node=None, **opts):
2796 """merge working directory with another revision
2799 """merge working directory with another revision
2797
2800
2798 The current working directory is updated with all changes made in
2801 The current working directory is updated with all changes made in
2799 the requested revision since the last common predecessor revision.
2802 the requested revision since the last common predecessor revision.
2800
2803
2801 Files that changed between either parent are marked as changed for
2804 Files that changed between either parent are marked as changed for
2802 the next commit and a commit must be performed before any further
2805 the next commit and a commit must be performed before any further
2803 updates to the repository are allowed. The next commit will have
2806 updates to the repository are allowed. The next commit will have
2804 two parents.
2807 two parents.
2805
2808
2806 ``--tool`` can be used to specify the merge tool used for file
2809 ``--tool`` can be used to specify the merge tool used for file
2807 merges. It overrides the HGMERGE environment variable and your
2810 merges. It overrides the HGMERGE environment variable and your
2808 configuration files. See :hg:`help merge-tools` for options.
2811 configuration files. See :hg:`help merge-tools` for options.
2809
2812
2810 If no revision is specified, the working directory's parent is a
2813 If no revision is specified, the working directory's parent is a
2811 head revision, and the current branch contains exactly one other
2814 head revision, and the current branch contains exactly one other
2812 head, the other head is merged with by default. Otherwise, an
2815 head, the other head is merged with by default. Otherwise, an
2813 explicit revision with which to merge with must be provided.
2816 explicit revision with which to merge with must be provided.
2814
2817
2815 :hg:`resolve` must be used to resolve unresolved files.
2818 :hg:`resolve` must be used to resolve unresolved files.
2816
2819
2817 To undo an uncommitted merge, use :hg:`update --clean .` which
2820 To undo an uncommitted merge, use :hg:`update --clean .` which
2818 will check out a clean copy of the original merge parent, losing
2821 will check out a clean copy of the original merge parent, losing
2819 all changes.
2822 all changes.
2820
2823
2821 Returns 0 on success, 1 if there are unresolved files.
2824 Returns 0 on success, 1 if there are unresolved files.
2822 """
2825 """
2823
2826
2824 if opts.get('rev') and node:
2827 if opts.get('rev') and node:
2825 raise util.Abort(_("please specify just one revision"))
2828 raise util.Abort(_("please specify just one revision"))
2826 if not node:
2829 if not node:
2827 node = opts.get('rev')
2830 node = opts.get('rev')
2828
2831
2829 if not node:
2832 if not node:
2830 branch = repo[None].branch()
2833 branch = repo[None].branch()
2831 bheads = repo.branchheads(branch)
2834 bheads = repo.branchheads(branch)
2832 if len(bheads) > 2:
2835 if len(bheads) > 2:
2833 raise util.Abort(_(
2836 raise util.Abort(_(
2834 'branch \'%s\' has %d heads - '
2837 'branch \'%s\' has %d heads - '
2835 'please merge with an explicit rev\n'
2838 'please merge with an explicit rev\n'
2836 '(run \'hg heads .\' to see heads)')
2839 '(run \'hg heads .\' to see heads)')
2837 % (branch, len(bheads)))
2840 % (branch, len(bheads)))
2838
2841
2839 parent = repo.dirstate.p1()
2842 parent = repo.dirstate.p1()
2840 if len(bheads) == 1:
2843 if len(bheads) == 1:
2841 if len(repo.heads()) > 1:
2844 if len(repo.heads()) > 1:
2842 raise util.Abort(_(
2845 raise util.Abort(_(
2843 'branch \'%s\' has one head - '
2846 'branch \'%s\' has one head - '
2844 'please merge with an explicit rev\n'
2847 'please merge with an explicit rev\n'
2845 '(run \'hg heads\' to see all heads)')
2848 '(run \'hg heads\' to see all heads)')
2846 % branch)
2849 % branch)
2847 msg = _('there is nothing to merge')
2850 msg = _('there is nothing to merge')
2848 if parent != repo.lookup(repo[None].branch()):
2851 if parent != repo.lookup(repo[None].branch()):
2849 msg = _('%s - use "hg update" instead') % msg
2852 msg = _('%s - use "hg update" instead') % msg
2850 raise util.Abort(msg)
2853 raise util.Abort(msg)
2851
2854
2852 if parent not in bheads:
2855 if parent not in bheads:
2853 raise util.Abort(_('working dir not at a head rev - '
2856 raise util.Abort(_('working dir not at a head rev - '
2854 'use "hg update" or merge with an explicit rev'))
2857 'use "hg update" or merge with an explicit rev'))
2855 node = parent == bheads[0] and bheads[-1] or bheads[0]
2858 node = parent == bheads[0] and bheads[-1] or bheads[0]
2856 else:
2859 else:
2857 node = cmdutil.revsingle(repo, node).node()
2860 node = cmdutil.revsingle(repo, node).node()
2858
2861
2859 if opts.get('preview'):
2862 if opts.get('preview'):
2860 # find nodes that are ancestors of p2 but not of p1
2863 # find nodes that are ancestors of p2 but not of p1
2861 p1 = repo.lookup('.')
2864 p1 = repo.lookup('.')
2862 p2 = repo.lookup(node)
2865 p2 = repo.lookup(node)
2863 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2866 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2864
2867
2865 displayer = cmdutil.show_changeset(ui, repo, opts)
2868 displayer = cmdutil.show_changeset(ui, repo, opts)
2866 for node in nodes:
2869 for node in nodes:
2867 displayer.show(repo[node])
2870 displayer.show(repo[node])
2868 displayer.close()
2871 displayer.close()
2869 return 0
2872 return 0
2870
2873
2871 try:
2874 try:
2872 # ui.forcemerge is an internal variable, do not document
2875 # ui.forcemerge is an internal variable, do not document
2873 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2876 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2874 return hg.merge(repo, node, force=opts.get('force'))
2877 return hg.merge(repo, node, force=opts.get('force'))
2875 finally:
2878 finally:
2876 ui.setconfig('ui', 'forcemerge', '')
2879 ui.setconfig('ui', 'forcemerge', '')
2877
2880
2878 def outgoing(ui, repo, dest=None, **opts):
2881 def outgoing(ui, repo, dest=None, **opts):
2879 """show changesets not found in the destination
2882 """show changesets not found in the destination
2880
2883
2881 Show changesets not found in the specified destination repository
2884 Show changesets not found in the specified destination repository
2882 or the default push location. These are the changesets that would
2885 or the default push location. These are the changesets that would
2883 be pushed if a push was requested.
2886 be pushed if a push was requested.
2884
2887
2885 See pull for details of valid destination formats.
2888 See pull for details of valid destination formats.
2886
2889
2887 Returns 0 if there are outgoing changes, 1 otherwise.
2890 Returns 0 if there are outgoing changes, 1 otherwise.
2888 """
2891 """
2889
2892
2890 if opts.get('bookmarks'):
2893 if opts.get('bookmarks'):
2891 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2894 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2892 dest, branches = hg.parseurl(dest, opts.get('branch'))
2895 dest, branches = hg.parseurl(dest, opts.get('branch'))
2893 other = hg.repository(hg.remoteui(repo, opts), dest)
2896 other = hg.repository(hg.remoteui(repo, opts), dest)
2894 if 'bookmarks' not in other.listkeys('namespaces'):
2897 if 'bookmarks' not in other.listkeys('namespaces'):
2895 ui.warn(_("remote doesn't support bookmarks\n"))
2898 ui.warn(_("remote doesn't support bookmarks\n"))
2896 return 0
2899 return 0
2897 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
2900 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
2898 return bookmarks.diff(ui, other, repo)
2901 return bookmarks.diff(ui, other, repo)
2899
2902
2900 ret = hg.outgoing(ui, repo, dest, opts)
2903 ret = hg.outgoing(ui, repo, dest, opts)
2901 return ret
2904 return ret
2902
2905
2903 def parents(ui, repo, file_=None, **opts):
2906 def parents(ui, repo, file_=None, **opts):
2904 """show the parents of the working directory or revision
2907 """show the parents of the working directory or revision
2905
2908
2906 Print the working directory's parent revisions. If a revision is
2909 Print the working directory's parent revisions. If a revision is
2907 given via -r/--rev, the parent of that revision will be printed.
2910 given via -r/--rev, the parent of that revision will be printed.
2908 If a file argument is given, the revision in which the file was
2911 If a file argument is given, the revision in which the file was
2909 last changed (before the working directory revision or the
2912 last changed (before the working directory revision or the
2910 argument to --rev if given) is printed.
2913 argument to --rev if given) is printed.
2911
2914
2912 Returns 0 on success.
2915 Returns 0 on success.
2913 """
2916 """
2914
2917
2915 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
2918 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
2916
2919
2917 if file_:
2920 if file_:
2918 m = cmdutil.match(repo, (file_,), opts)
2921 m = cmdutil.match(repo, (file_,), opts)
2919 if m.anypats() or len(m.files()) != 1:
2922 if m.anypats() or len(m.files()) != 1:
2920 raise util.Abort(_('can only specify an explicit filename'))
2923 raise util.Abort(_('can only specify an explicit filename'))
2921 file_ = m.files()[0]
2924 file_ = m.files()[0]
2922 filenodes = []
2925 filenodes = []
2923 for cp in ctx.parents():
2926 for cp in ctx.parents():
2924 if not cp:
2927 if not cp:
2925 continue
2928 continue
2926 try:
2929 try:
2927 filenodes.append(cp.filenode(file_))
2930 filenodes.append(cp.filenode(file_))
2928 except error.LookupError:
2931 except error.LookupError:
2929 pass
2932 pass
2930 if not filenodes:
2933 if not filenodes:
2931 raise util.Abort(_("'%s' not found in manifest!") % file_)
2934 raise util.Abort(_("'%s' not found in manifest!") % file_)
2932 fl = repo.file(file_)
2935 fl = repo.file(file_)
2933 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2936 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2934 else:
2937 else:
2935 p = [cp.node() for cp in ctx.parents()]
2938 p = [cp.node() for cp in ctx.parents()]
2936
2939
2937 displayer = cmdutil.show_changeset(ui, repo, opts)
2940 displayer = cmdutil.show_changeset(ui, repo, opts)
2938 for n in p:
2941 for n in p:
2939 if n != nullid:
2942 if n != nullid:
2940 displayer.show(repo[n])
2943 displayer.show(repo[n])
2941 displayer.close()
2944 displayer.close()
2942
2945
2943 def paths(ui, repo, search=None):
2946 def paths(ui, repo, search=None):
2944 """show aliases for remote repositories
2947 """show aliases for remote repositories
2945
2948
2946 Show definition of symbolic path name NAME. If no name is given,
2949 Show definition of symbolic path name NAME. If no name is given,
2947 show definition of all available names.
2950 show definition of all available names.
2948
2951
2949 Path names are defined in the [paths] section of your
2952 Path names are defined in the [paths] section of your
2950 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2953 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2951 repository, ``.hg/hgrc`` is used, too.
2954 repository, ``.hg/hgrc`` is used, too.
2952
2955
2953 The path names ``default`` and ``default-push`` have a special
2956 The path names ``default`` and ``default-push`` have a special
2954 meaning. When performing a push or pull operation, they are used
2957 meaning. When performing a push or pull operation, they are used
2955 as fallbacks if no location is specified on the command-line.
2958 as fallbacks if no location is specified on the command-line.
2956 When ``default-push`` is set, it will be used for push and
2959 When ``default-push`` is set, it will be used for push and
2957 ``default`` will be used for pull; otherwise ``default`` is used
2960 ``default`` will be used for pull; otherwise ``default`` is used
2958 as the fallback for both. When cloning a repository, the clone
2961 as the fallback for both. When cloning a repository, the clone
2959 source is written as ``default`` in ``.hg/hgrc``. Note that
2962 source is written as ``default`` in ``.hg/hgrc``. Note that
2960 ``default`` and ``default-push`` apply to all inbound (e.g.
2963 ``default`` and ``default-push`` apply to all inbound (e.g.
2961 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2964 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2962 :hg:`bundle`) operations.
2965 :hg:`bundle`) operations.
2963
2966
2964 See :hg:`help urls` for more information.
2967 See :hg:`help urls` for more information.
2965
2968
2966 Returns 0 on success.
2969 Returns 0 on success.
2967 """
2970 """
2968 if search:
2971 if search:
2969 for name, path in ui.configitems("paths"):
2972 for name, path in ui.configitems("paths"):
2970 if name == search:
2973 if name == search:
2971 ui.write("%s\n" % util.hidepassword(path))
2974 ui.write("%s\n" % util.hidepassword(path))
2972 return
2975 return
2973 ui.warn(_("not found!\n"))
2976 ui.warn(_("not found!\n"))
2974 return 1
2977 return 1
2975 else:
2978 else:
2976 for name, path in ui.configitems("paths"):
2979 for name, path in ui.configitems("paths"):
2977 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
2980 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
2978
2981
2979 def postincoming(ui, repo, modheads, optupdate, checkout):
2982 def postincoming(ui, repo, modheads, optupdate, checkout):
2980 if modheads == 0:
2983 if modheads == 0:
2981 return
2984 return
2982 if optupdate:
2985 if optupdate:
2983 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2986 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2984 return hg.update(repo, checkout)
2987 return hg.update(repo, checkout)
2985 else:
2988 else:
2986 ui.status(_("not updating, since new heads added\n"))
2989 ui.status(_("not updating, since new heads added\n"))
2987 if modheads > 1:
2990 if modheads > 1:
2988 currentbranchheads = len(repo.branchheads())
2991 currentbranchheads = len(repo.branchheads())
2989 if currentbranchheads == modheads:
2992 if currentbranchheads == modheads:
2990 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2993 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2991 elif currentbranchheads > 1:
2994 elif currentbranchheads > 1:
2992 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
2995 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
2993 else:
2996 else:
2994 ui.status(_("(run 'hg heads' to see heads)\n"))
2997 ui.status(_("(run 'hg heads' to see heads)\n"))
2995 else:
2998 else:
2996 ui.status(_("(run 'hg update' to get a working copy)\n"))
2999 ui.status(_("(run 'hg update' to get a working copy)\n"))
2997
3000
2998 def pull(ui, repo, source="default", **opts):
3001 def pull(ui, repo, source="default", **opts):
2999 """pull changes from the specified source
3002 """pull changes from the specified source
3000
3003
3001 Pull changes from a remote repository to a local one.
3004 Pull changes from a remote repository to a local one.
3002
3005
3003 This finds all changes from the repository at the specified path
3006 This finds all changes from the repository at the specified path
3004 or URL and adds them to a local repository (the current one unless
3007 or URL and adds them to a local repository (the current one unless
3005 -R is specified). By default, this does not update the copy of the
3008 -R is specified). By default, this does not update the copy of the
3006 project in the working directory.
3009 project in the working directory.
3007
3010
3008 Use :hg:`incoming` if you want to see what would have been added
3011 Use :hg:`incoming` if you want to see what would have been added
3009 by a pull at the time you issued this command. If you then decide
3012 by a pull at the time you issued this command. If you then decide
3010 to add those changes to the repository, you should use :hg:`pull
3013 to add those changes to the repository, you should use :hg:`pull
3011 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3014 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3012
3015
3013 If SOURCE is omitted, the 'default' path will be used.
3016 If SOURCE is omitted, the 'default' path will be used.
3014 See :hg:`help urls` for more information.
3017 See :hg:`help urls` for more information.
3015
3018
3016 Returns 0 on success, 1 if an update had unresolved files.
3019 Returns 0 on success, 1 if an update had unresolved files.
3017 """
3020 """
3018 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3021 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3019 other = hg.repository(hg.remoteui(repo, opts), source)
3022 other = hg.repository(hg.remoteui(repo, opts), source)
3020 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3023 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3021 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3024 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3022
3025
3023 if opts.get('bookmark'):
3026 if opts.get('bookmark'):
3024 if not revs:
3027 if not revs:
3025 revs = []
3028 revs = []
3026 rb = other.listkeys('bookmarks')
3029 rb = other.listkeys('bookmarks')
3027 for b in opts['bookmark']:
3030 for b in opts['bookmark']:
3028 if b not in rb:
3031 if b not in rb:
3029 raise util.Abort(_('remote bookmark %s not found!') % b)
3032 raise util.Abort(_('remote bookmark %s not found!') % b)
3030 revs.append(rb[b])
3033 revs.append(rb[b])
3031
3034
3032 if revs:
3035 if revs:
3033 try:
3036 try:
3034 revs = [other.lookup(rev) for rev in revs]
3037 revs = [other.lookup(rev) for rev in revs]
3035 except error.CapabilityError:
3038 except error.CapabilityError:
3036 err = _("other repository doesn't support revision lookup, "
3039 err = _("other repository doesn't support revision lookup, "
3037 "so a rev cannot be specified.")
3040 "so a rev cannot be specified.")
3038 raise util.Abort(err)
3041 raise util.Abort(err)
3039
3042
3040 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3043 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3041 bookmarks.updatefromremote(ui, repo, other)
3044 bookmarks.updatefromremote(ui, repo, other)
3042 if checkout:
3045 if checkout:
3043 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3046 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3044 repo._subtoppath = source
3047 repo._subtoppath = source
3045 try:
3048 try:
3046 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3049 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3047
3050
3048 finally:
3051 finally:
3049 del repo._subtoppath
3052 del repo._subtoppath
3050
3053
3051 # update specified bookmarks
3054 # update specified bookmarks
3052 if opts.get('bookmark'):
3055 if opts.get('bookmark'):
3053 for b in opts['bookmark']:
3056 for b in opts['bookmark']:
3054 # explicit pull overrides local bookmark if any
3057 # explicit pull overrides local bookmark if any
3055 ui.status(_("importing bookmark %s\n") % b)
3058 ui.status(_("importing bookmark %s\n") % b)
3056 repo._bookmarks[b] = repo[rb[b]].node()
3059 repo._bookmarks[b] = repo[rb[b]].node()
3057 bookmarks.write(repo)
3060 bookmarks.write(repo)
3058
3061
3059 return ret
3062 return ret
3060
3063
3061 def push(ui, repo, dest=None, **opts):
3064 def push(ui, repo, dest=None, **opts):
3062 """push changes to the specified destination
3065 """push changes to the specified destination
3063
3066
3064 Push changesets from the local repository to the specified
3067 Push changesets from the local repository to the specified
3065 destination.
3068 destination.
3066
3069
3067 This operation is symmetrical to pull: it is identical to a pull
3070 This operation is symmetrical to pull: it is identical to a pull
3068 in the destination repository from the current one.
3071 in the destination repository from the current one.
3069
3072
3070 By default, push will not allow creation of new heads at the
3073 By default, push will not allow creation of new heads at the
3071 destination, since multiple heads would make it unclear which head
3074 destination, since multiple heads would make it unclear which head
3072 to use. In this situation, it is recommended to pull and merge
3075 to use. In this situation, it is recommended to pull and merge
3073 before pushing.
3076 before pushing.
3074
3077
3075 Use --new-branch if you want to allow push to create a new named
3078 Use --new-branch if you want to allow push to create a new named
3076 branch that is not present at the destination. This allows you to
3079 branch that is not present at the destination. This allows you to
3077 only create a new branch without forcing other changes.
3080 only create a new branch without forcing other changes.
3078
3081
3079 Use -f/--force to override the default behavior and push all
3082 Use -f/--force to override the default behavior and push all
3080 changesets on all branches.
3083 changesets on all branches.
3081
3084
3082 If -r/--rev is used, the specified revision and all its ancestors
3085 If -r/--rev is used, the specified revision and all its ancestors
3083 will be pushed to the remote repository.
3086 will be pushed to the remote repository.
3084
3087
3085 Please see :hg:`help urls` for important details about ``ssh://``
3088 Please see :hg:`help urls` for important details about ``ssh://``
3086 URLs. If DESTINATION is omitted, a default path will be used.
3089 URLs. If DESTINATION is omitted, a default path will be used.
3087
3090
3088 Returns 0 if push was successful, 1 if nothing to push.
3091 Returns 0 if push was successful, 1 if nothing to push.
3089 """
3092 """
3090
3093
3091 if opts.get('bookmark'):
3094 if opts.get('bookmark'):
3092 for b in opts['bookmark']:
3095 for b in opts['bookmark']:
3093 # translate -B options to -r so changesets get pushed
3096 # translate -B options to -r so changesets get pushed
3094 if b in repo._bookmarks:
3097 if b in repo._bookmarks:
3095 opts.setdefault('rev', []).append(b)
3098 opts.setdefault('rev', []).append(b)
3096 else:
3099 else:
3097 # if we try to push a deleted bookmark, translate it to null
3100 # if we try to push a deleted bookmark, translate it to null
3098 # this lets simultaneous -r, -b options continue working
3101 # this lets simultaneous -r, -b options continue working
3099 opts.setdefault('rev', []).append("null")
3102 opts.setdefault('rev', []).append("null")
3100
3103
3101 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3104 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3102 dest, branches = hg.parseurl(dest, opts.get('branch'))
3105 dest, branches = hg.parseurl(dest, opts.get('branch'))
3103 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3106 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3104 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3107 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3105 other = hg.repository(hg.remoteui(repo, opts), dest)
3108 other = hg.repository(hg.remoteui(repo, opts), dest)
3106 if revs:
3109 if revs:
3107 revs = [repo.lookup(rev) for rev in revs]
3110 revs = [repo.lookup(rev) for rev in revs]
3108
3111
3109 repo._subtoppath = dest
3112 repo._subtoppath = dest
3110 try:
3113 try:
3111 # push subrepos depth-first for coherent ordering
3114 # push subrepos depth-first for coherent ordering
3112 c = repo['']
3115 c = repo['']
3113 subs = c.substate # only repos that are committed
3116 subs = c.substate # only repos that are committed
3114 for s in sorted(subs):
3117 for s in sorted(subs):
3115 if not c.sub(s).push(opts.get('force')):
3118 if not c.sub(s).push(opts.get('force')):
3116 return False
3119 return False
3117 finally:
3120 finally:
3118 del repo._subtoppath
3121 del repo._subtoppath
3119 result = repo.push(other, opts.get('force'), revs=revs,
3122 result = repo.push(other, opts.get('force'), revs=revs,
3120 newbranch=opts.get('new_branch'))
3123 newbranch=opts.get('new_branch'))
3121
3124
3122 result = (result == 0)
3125 result = (result == 0)
3123
3126
3124 if opts.get('bookmark'):
3127 if opts.get('bookmark'):
3125 rb = other.listkeys('bookmarks')
3128 rb = other.listkeys('bookmarks')
3126 for b in opts['bookmark']:
3129 for b in opts['bookmark']:
3127 # explicit push overrides remote bookmark if any
3130 # explicit push overrides remote bookmark if any
3128 if b in repo._bookmarks:
3131 if b in repo._bookmarks:
3129 ui.status(_("exporting bookmark %s\n") % b)
3132 ui.status(_("exporting bookmark %s\n") % b)
3130 new = repo[b].hex()
3133 new = repo[b].hex()
3131 elif b in rb:
3134 elif b in rb:
3132 ui.status(_("deleting remote bookmark %s\n") % b)
3135 ui.status(_("deleting remote bookmark %s\n") % b)
3133 new = '' # delete
3136 new = '' # delete
3134 else:
3137 else:
3135 ui.warn(_('bookmark %s does not exist on the local '
3138 ui.warn(_('bookmark %s does not exist on the local '
3136 'or remote repository!\n') % b)
3139 'or remote repository!\n') % b)
3137 return 2
3140 return 2
3138 old = rb.get(b, '')
3141 old = rb.get(b, '')
3139 r = other.pushkey('bookmarks', b, old, new)
3142 r = other.pushkey('bookmarks', b, old, new)
3140 if not r:
3143 if not r:
3141 ui.warn(_('updating bookmark %s failed!\n') % b)
3144 ui.warn(_('updating bookmark %s failed!\n') % b)
3142 if not result:
3145 if not result:
3143 result = 2
3146 result = 2
3144
3147
3145 return result
3148 return result
3146
3149
3147 def recover(ui, repo):
3150 def recover(ui, repo):
3148 """roll back an interrupted transaction
3151 """roll back an interrupted transaction
3149
3152
3150 Recover from an interrupted commit or pull.
3153 Recover from an interrupted commit or pull.
3151
3154
3152 This command tries to fix the repository status after an
3155 This command tries to fix the repository status after an
3153 interrupted operation. It should only be necessary when Mercurial
3156 interrupted operation. It should only be necessary when Mercurial
3154 suggests it.
3157 suggests it.
3155
3158
3156 Returns 0 if successful, 1 if nothing to recover or verify fails.
3159 Returns 0 if successful, 1 if nothing to recover or verify fails.
3157 """
3160 """
3158 if repo.recover():
3161 if repo.recover():
3159 return hg.verify(repo)
3162 return hg.verify(repo)
3160 return 1
3163 return 1
3161
3164
3162 def remove(ui, repo, *pats, **opts):
3165 def remove(ui, repo, *pats, **opts):
3163 """remove the specified files on the next commit
3166 """remove the specified files on the next commit
3164
3167
3165 Schedule the indicated files for removal from the repository.
3168 Schedule the indicated files for removal from the repository.
3166
3169
3167 This only removes files from the current branch, not from the
3170 This only removes files from the current branch, not from the
3168 entire project history. -A/--after can be used to remove only
3171 entire project history. -A/--after can be used to remove only
3169 files that have already been deleted, -f/--force can be used to
3172 files that have already been deleted, -f/--force can be used to
3170 force deletion, and -Af can be used to remove files from the next
3173 force deletion, and -Af can be used to remove files from the next
3171 revision without deleting them from the working directory.
3174 revision without deleting them from the working directory.
3172
3175
3173 The following table details the behavior of remove for different
3176 The following table details the behavior of remove for different
3174 file states (columns) and option combinations (rows). The file
3177 file states (columns) and option combinations (rows). The file
3175 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3178 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3176 reported by :hg:`status`). The actions are Warn, Remove (from
3179 reported by :hg:`status`). The actions are Warn, Remove (from
3177 branch) and Delete (from disk)::
3180 branch) and Delete (from disk)::
3178
3181
3179 A C M !
3182 A C M !
3180 none W RD W R
3183 none W RD W R
3181 -f R RD RD R
3184 -f R RD RD R
3182 -A W W W R
3185 -A W W W R
3183 -Af R R R R
3186 -Af R R R R
3184
3187
3185 This command schedules the files to be removed at the next commit.
3188 This command schedules the files to be removed at the next commit.
3186 To undo a remove before that, see :hg:`revert`.
3189 To undo a remove before that, see :hg:`revert`.
3187
3190
3188 Returns 0 on success, 1 if any warnings encountered.
3191 Returns 0 on success, 1 if any warnings encountered.
3189 """
3192 """
3190
3193
3191 ret = 0
3194 ret = 0
3192 after, force = opts.get('after'), opts.get('force')
3195 after, force = opts.get('after'), opts.get('force')
3193 if not pats and not after:
3196 if not pats and not after:
3194 raise util.Abort(_('no files specified'))
3197 raise util.Abort(_('no files specified'))
3195
3198
3196 m = cmdutil.match(repo, pats, opts)
3199 m = cmdutil.match(repo, pats, opts)
3197 s = repo.status(match=m, clean=True)
3200 s = repo.status(match=m, clean=True)
3198 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3201 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3199
3202
3200 for f in m.files():
3203 for f in m.files():
3201 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3204 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3202 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3205 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3203 ret = 1
3206 ret = 1
3204
3207
3205 if force:
3208 if force:
3206 remove, forget = modified + deleted + clean, added
3209 remove, forget = modified + deleted + clean, added
3207 elif after:
3210 elif after:
3208 remove, forget = deleted, []
3211 remove, forget = deleted, []
3209 for f in modified + added + clean:
3212 for f in modified + added + clean:
3210 ui.warn(_('not removing %s: file still exists (use -f'
3213 ui.warn(_('not removing %s: file still exists (use -f'
3211 ' to force removal)\n') % m.rel(f))
3214 ' to force removal)\n') % m.rel(f))
3212 ret = 1
3215 ret = 1
3213 else:
3216 else:
3214 remove, forget = deleted + clean, []
3217 remove, forget = deleted + clean, []
3215 for f in modified:
3218 for f in modified:
3216 ui.warn(_('not removing %s: file is modified (use -f'
3219 ui.warn(_('not removing %s: file is modified (use -f'
3217 ' to force removal)\n') % m.rel(f))
3220 ' to force removal)\n') % m.rel(f))
3218 ret = 1
3221 ret = 1
3219 for f in added:
3222 for f in added:
3220 ui.warn(_('not removing %s: file has been marked for add (use -f'
3223 ui.warn(_('not removing %s: file has been marked for add (use -f'
3221 ' to force removal)\n') % m.rel(f))
3224 ' to force removal)\n') % m.rel(f))
3222 ret = 1
3225 ret = 1
3223
3226
3224 for f in sorted(remove + forget):
3227 for f in sorted(remove + forget):
3225 if ui.verbose or not m.exact(f):
3228 if ui.verbose or not m.exact(f):
3226 ui.status(_('removing %s\n') % m.rel(f))
3229 ui.status(_('removing %s\n') % m.rel(f))
3227
3230
3228 repo[None].forget(forget)
3231 repo[None].forget(forget)
3229 repo[None].remove(remove, unlink=not after)
3232 repo[None].remove(remove, unlink=not after)
3230 return ret
3233 return ret
3231
3234
3232 def rename(ui, repo, *pats, **opts):
3235 def rename(ui, repo, *pats, **opts):
3233 """rename files; equivalent of copy + remove
3236 """rename files; equivalent of copy + remove
3234
3237
3235 Mark dest as copies of sources; mark sources for deletion. If dest
3238 Mark dest as copies of sources; mark sources for deletion. If dest
3236 is a directory, copies are put in that directory. If dest is a
3239 is a directory, copies are put in that directory. If dest is a
3237 file, there can only be one source.
3240 file, there can only be one source.
3238
3241
3239 By default, this command copies the contents of files as they
3242 By default, this command copies the contents of files as they
3240 exist in the working directory. If invoked with -A/--after, the
3243 exist in the working directory. If invoked with -A/--after, the
3241 operation is recorded, but no copying is performed.
3244 operation is recorded, but no copying is performed.
3242
3245
3243 This command takes effect at the next commit. To undo a rename
3246 This command takes effect at the next commit. To undo a rename
3244 before that, see :hg:`revert`.
3247 before that, see :hg:`revert`.
3245
3248
3246 Returns 0 on success, 1 if errors are encountered.
3249 Returns 0 on success, 1 if errors are encountered.
3247 """
3250 """
3248 wlock = repo.wlock(False)
3251 wlock = repo.wlock(False)
3249 try:
3252 try:
3250 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3253 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3251 finally:
3254 finally:
3252 wlock.release()
3255 wlock.release()
3253
3256
3254 def resolve(ui, repo, *pats, **opts):
3257 def resolve(ui, repo, *pats, **opts):
3255 """redo merges or set/view the merge status of files
3258 """redo merges or set/view the merge status of files
3256
3259
3257 Merges with unresolved conflicts are often the result of
3260 Merges with unresolved conflicts are often the result of
3258 non-interactive merging using the ``internal:merge`` configuration
3261 non-interactive merging using the ``internal:merge`` configuration
3259 setting, or a command-line merge tool like ``diff3``. The resolve
3262 setting, or a command-line merge tool like ``diff3``. The resolve
3260 command is used to manage the files involved in a merge, after
3263 command is used to manage the files involved in a merge, after
3261 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3264 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3262 working directory must have two parents).
3265 working directory must have two parents).
3263
3266
3264 The resolve command can be used in the following ways:
3267 The resolve command can be used in the following ways:
3265
3268
3266 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3269 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3267 files, discarding any previous merge attempts. Re-merging is not
3270 files, discarding any previous merge attempts. Re-merging is not
3268 performed for files already marked as resolved. Use ``--all/-a``
3271 performed for files already marked as resolved. Use ``--all/-a``
3269 to selects all unresolved files. ``--tool`` can be used to specify
3272 to selects all unresolved files. ``--tool`` can be used to specify
3270 the merge tool used for the given files. It overrides the HGMERGE
3273 the merge tool used for the given files. It overrides the HGMERGE
3271 environment variable and your configuration files.
3274 environment variable and your configuration files.
3272
3275
3273 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3276 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3274 (e.g. after having manually fixed-up the files). The default is
3277 (e.g. after having manually fixed-up the files). The default is
3275 to mark all unresolved files.
3278 to mark all unresolved files.
3276
3279
3277 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3280 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3278 default is to mark all resolved files.
3281 default is to mark all resolved files.
3279
3282
3280 - :hg:`resolve -l`: list files which had or still have conflicts.
3283 - :hg:`resolve -l`: list files which had or still have conflicts.
3281 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3284 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3282
3285
3283 Note that Mercurial will not let you commit files with unresolved
3286 Note that Mercurial will not let you commit files with unresolved
3284 merge conflicts. You must use :hg:`resolve -m ...` before you can
3287 merge conflicts. You must use :hg:`resolve -m ...` before you can
3285 commit after a conflicting merge.
3288 commit after a conflicting merge.
3286
3289
3287 Returns 0 on success, 1 if any files fail a resolve attempt.
3290 Returns 0 on success, 1 if any files fail a resolve attempt.
3288 """
3291 """
3289
3292
3290 all, mark, unmark, show, nostatus = \
3293 all, mark, unmark, show, nostatus = \
3291 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3294 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3292
3295
3293 if (show and (mark or unmark)) or (mark and unmark):
3296 if (show and (mark or unmark)) or (mark and unmark):
3294 raise util.Abort(_("too many options specified"))
3297 raise util.Abort(_("too many options specified"))
3295 if pats and all:
3298 if pats and all:
3296 raise util.Abort(_("can't specify --all and patterns"))
3299 raise util.Abort(_("can't specify --all and patterns"))
3297 if not (all or pats or show or mark or unmark):
3300 if not (all or pats or show or mark or unmark):
3298 raise util.Abort(_('no files or directories specified; '
3301 raise util.Abort(_('no files or directories specified; '
3299 'use --all to remerge all files'))
3302 'use --all to remerge all files'))
3300
3303
3301 ms = mergemod.mergestate(repo)
3304 ms = mergemod.mergestate(repo)
3302 m = cmdutil.match(repo, pats, opts)
3305 m = cmdutil.match(repo, pats, opts)
3303 ret = 0
3306 ret = 0
3304
3307
3305 for f in ms:
3308 for f in ms:
3306 if m(f):
3309 if m(f):
3307 if show:
3310 if show:
3308 if nostatus:
3311 if nostatus:
3309 ui.write("%s\n" % f)
3312 ui.write("%s\n" % f)
3310 else:
3313 else:
3311 ui.write("%s %s\n" % (ms[f].upper(), f),
3314 ui.write("%s %s\n" % (ms[f].upper(), f),
3312 label='resolve.' +
3315 label='resolve.' +
3313 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3316 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3314 elif mark:
3317 elif mark:
3315 ms.mark(f, "r")
3318 ms.mark(f, "r")
3316 elif unmark:
3319 elif unmark:
3317 ms.mark(f, "u")
3320 ms.mark(f, "u")
3318 else:
3321 else:
3319 wctx = repo[None]
3322 wctx = repo[None]
3320 mctx = wctx.parents()[-1]
3323 mctx = wctx.parents()[-1]
3321
3324
3322 # backup pre-resolve (merge uses .orig for its own purposes)
3325 # backup pre-resolve (merge uses .orig for its own purposes)
3323 a = repo.wjoin(f)
3326 a = repo.wjoin(f)
3324 util.copyfile(a, a + ".resolve")
3327 util.copyfile(a, a + ".resolve")
3325
3328
3326 try:
3329 try:
3327 # resolve file
3330 # resolve file
3328 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3331 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3329 if ms.resolve(f, wctx, mctx):
3332 if ms.resolve(f, wctx, mctx):
3330 ret = 1
3333 ret = 1
3331 finally:
3334 finally:
3332 ui.setconfig('ui', 'forcemerge', '')
3335 ui.setconfig('ui', 'forcemerge', '')
3333
3336
3334 # replace filemerge's .orig file with our resolve file
3337 # replace filemerge's .orig file with our resolve file
3335 util.rename(a + ".resolve", a + ".orig")
3338 util.rename(a + ".resolve", a + ".orig")
3336
3339
3337 ms.commit()
3340 ms.commit()
3338 return ret
3341 return ret
3339
3342
3340 def revert(ui, repo, *pats, **opts):
3343 def revert(ui, repo, *pats, **opts):
3341 """restore individual files or directories to an earlier state
3344 """restore individual files or directories to an earlier state
3342
3345
3343 .. note::
3346 .. note::
3344 This command is most likely not what you are looking for.
3347 This command is most likely not what you are looking for.
3345 Revert will partially overwrite content in the working
3348 Revert will partially overwrite content in the working
3346 directory without changing the working directory parents. Use
3349 directory without changing the working directory parents. Use
3347 :hg:`update -r rev` to check out earlier revisions, or
3350 :hg:`update -r rev` to check out earlier revisions, or
3348 :hg:`update --clean .` to undo a merge which has added another
3351 :hg:`update --clean .` to undo a merge which has added another
3349 parent.
3352 parent.
3350
3353
3351 With no revision specified, revert the named files or directories
3354 With no revision specified, revert the named files or directories
3352 to the contents they had in the parent of the working directory.
3355 to the contents they had in the parent of the working directory.
3353 This restores the contents of the affected files to an unmodified
3356 This restores the contents of the affected files to an unmodified
3354 state and unschedules adds, removes, copies, and renames. If the
3357 state and unschedules adds, removes, copies, and renames. If the
3355 working directory has two parents, you must explicitly specify a
3358 working directory has two parents, you must explicitly specify a
3356 revision.
3359 revision.
3357
3360
3358 Using the -r/--rev option, revert the given files or directories
3361 Using the -r/--rev option, revert the given files or directories
3359 to their contents as of a specific revision. This can be helpful
3362 to their contents as of a specific revision. This can be helpful
3360 to "roll back" some or all of an earlier change. See :hg:`help
3363 to "roll back" some or all of an earlier change. See :hg:`help
3361 dates` for a list of formats valid for -d/--date.
3364 dates` for a list of formats valid for -d/--date.
3362
3365
3363 Revert modifies the working directory. It does not commit any
3366 Revert modifies the working directory. It does not commit any
3364 changes, or change the parent of the working directory. If you
3367 changes, or change the parent of the working directory. If you
3365 revert to a revision other than the parent of the working
3368 revert to a revision other than the parent of the working
3366 directory, the reverted files will thus appear modified
3369 directory, the reverted files will thus appear modified
3367 afterwards.
3370 afterwards.
3368
3371
3369 If a file has been deleted, it is restored. Files scheduled for
3372 If a file has been deleted, it is restored. Files scheduled for
3370 addition are just unscheduled and left as they are. If the
3373 addition are just unscheduled and left as they are. If the
3371 executable mode of a file was changed, it is reset.
3374 executable mode of a file was changed, it is reset.
3372
3375
3373 If names are given, all files matching the names are reverted.
3376 If names are given, all files matching the names are reverted.
3374 If no arguments are given, no files are reverted.
3377 If no arguments are given, no files are reverted.
3375
3378
3376 Modified files are saved with a .orig suffix before reverting.
3379 Modified files are saved with a .orig suffix before reverting.
3377 To disable these backups, use --no-backup.
3380 To disable these backups, use --no-backup.
3378
3381
3379 Returns 0 on success.
3382 Returns 0 on success.
3380 """
3383 """
3381
3384
3382 if opts.get("date"):
3385 if opts.get("date"):
3383 if opts.get("rev"):
3386 if opts.get("rev"):
3384 raise util.Abort(_("you can't specify a revision and a date"))
3387 raise util.Abort(_("you can't specify a revision and a date"))
3385 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3388 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3386
3389
3387 parent, p2 = repo.dirstate.parents()
3390 parent, p2 = repo.dirstate.parents()
3388 if not opts.get('rev') and p2 != nullid:
3391 if not opts.get('rev') and p2 != nullid:
3389 raise util.Abort(_('uncommitted merge - '
3392 raise util.Abort(_('uncommitted merge - '
3390 'use "hg update", see "hg help revert"'))
3393 'use "hg update", see "hg help revert"'))
3391
3394
3392 if not pats and not opts.get('all'):
3395 if not pats and not opts.get('all'):
3393 raise util.Abort(_('no files or directories specified; '
3396 raise util.Abort(_('no files or directories specified; '
3394 'use --all to revert the whole repo'))
3397 'use --all to revert the whole repo'))
3395
3398
3396 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3399 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3397 node = ctx.node()
3400 node = ctx.node()
3398 mf = ctx.manifest()
3401 mf = ctx.manifest()
3399 if node == parent:
3402 if node == parent:
3400 pmf = mf
3403 pmf = mf
3401 else:
3404 else:
3402 pmf = None
3405 pmf = None
3403
3406
3404 # need all matching names in dirstate and manifest of target rev,
3407 # need all matching names in dirstate and manifest of target rev,
3405 # so have to walk both. do not print errors if files exist in one
3408 # so have to walk both. do not print errors if files exist in one
3406 # but not other.
3409 # but not other.
3407
3410
3408 names = {}
3411 names = {}
3409
3412
3410 wlock = repo.wlock()
3413 wlock = repo.wlock()
3411 try:
3414 try:
3412 # walk dirstate.
3415 # walk dirstate.
3413
3416
3414 m = cmdutil.match(repo, pats, opts)
3417 m = cmdutil.match(repo, pats, opts)
3415 m.bad = lambda x, y: False
3418 m.bad = lambda x, y: False
3416 for abs in repo.walk(m):
3419 for abs in repo.walk(m):
3417 names[abs] = m.rel(abs), m.exact(abs)
3420 names[abs] = m.rel(abs), m.exact(abs)
3418
3421
3419 # walk target manifest.
3422 # walk target manifest.
3420
3423
3421 def badfn(path, msg):
3424 def badfn(path, msg):
3422 if path in names:
3425 if path in names:
3423 return
3426 return
3424 path_ = path + '/'
3427 path_ = path + '/'
3425 for f in names:
3428 for f in names:
3426 if f.startswith(path_):
3429 if f.startswith(path_):
3427 return
3430 return
3428 ui.warn("%s: %s\n" % (m.rel(path), msg))
3431 ui.warn("%s: %s\n" % (m.rel(path), msg))
3429
3432
3430 m = cmdutil.match(repo, pats, opts)
3433 m = cmdutil.match(repo, pats, opts)
3431 m.bad = badfn
3434 m.bad = badfn
3432 for abs in repo[node].walk(m):
3435 for abs in repo[node].walk(m):
3433 if abs not in names:
3436 if abs not in names:
3434 names[abs] = m.rel(abs), m.exact(abs)
3437 names[abs] = m.rel(abs), m.exact(abs)
3435
3438
3436 m = cmdutil.matchfiles(repo, names)
3439 m = cmdutil.matchfiles(repo, names)
3437 changes = repo.status(match=m)[:4]
3440 changes = repo.status(match=m)[:4]
3438 modified, added, removed, deleted = map(set, changes)
3441 modified, added, removed, deleted = map(set, changes)
3439
3442
3440 # if f is a rename, also revert the source
3443 # if f is a rename, also revert the source
3441 cwd = repo.getcwd()
3444 cwd = repo.getcwd()
3442 for f in added:
3445 for f in added:
3443 src = repo.dirstate.copied(f)
3446 src = repo.dirstate.copied(f)
3444 if src and src not in names and repo.dirstate[src] == 'r':
3447 if src and src not in names and repo.dirstate[src] == 'r':
3445 removed.add(src)
3448 removed.add(src)
3446 names[src] = (repo.pathto(src, cwd), True)
3449 names[src] = (repo.pathto(src, cwd), True)
3447
3450
3448 def removeforget(abs):
3451 def removeforget(abs):
3449 if repo.dirstate[abs] == 'a':
3452 if repo.dirstate[abs] == 'a':
3450 return _('forgetting %s\n')
3453 return _('forgetting %s\n')
3451 return _('removing %s\n')
3454 return _('removing %s\n')
3452
3455
3453 revert = ([], _('reverting %s\n'))
3456 revert = ([], _('reverting %s\n'))
3454 add = ([], _('adding %s\n'))
3457 add = ([], _('adding %s\n'))
3455 remove = ([], removeforget)
3458 remove = ([], removeforget)
3456 undelete = ([], _('undeleting %s\n'))
3459 undelete = ([], _('undeleting %s\n'))
3457
3460
3458 disptable = (
3461 disptable = (
3459 # dispatch table:
3462 # dispatch table:
3460 # file state
3463 # file state
3461 # action if in target manifest
3464 # action if in target manifest
3462 # action if not in target manifest
3465 # action if not in target manifest
3463 # make backup if in target manifest
3466 # make backup if in target manifest
3464 # make backup if not in target manifest
3467 # make backup if not in target manifest
3465 (modified, revert, remove, True, True),
3468 (modified, revert, remove, True, True),
3466 (added, revert, remove, True, False),
3469 (added, revert, remove, True, False),
3467 (removed, undelete, None, False, False),
3470 (removed, undelete, None, False, False),
3468 (deleted, revert, remove, False, False),
3471 (deleted, revert, remove, False, False),
3469 )
3472 )
3470
3473
3471 for abs, (rel, exact) in sorted(names.items()):
3474 for abs, (rel, exact) in sorted(names.items()):
3472 mfentry = mf.get(abs)
3475 mfentry = mf.get(abs)
3473 target = repo.wjoin(abs)
3476 target = repo.wjoin(abs)
3474 def handle(xlist, dobackup):
3477 def handle(xlist, dobackup):
3475 xlist[0].append(abs)
3478 xlist[0].append(abs)
3476 if (dobackup and not opts.get('no_backup') and
3479 if (dobackup and not opts.get('no_backup') and
3477 os.path.lexists(target)):
3480 os.path.lexists(target)):
3478 bakname = "%s.orig" % rel
3481 bakname = "%s.orig" % rel
3479 ui.note(_('saving current version of %s as %s\n') %
3482 ui.note(_('saving current version of %s as %s\n') %
3480 (rel, bakname))
3483 (rel, bakname))
3481 if not opts.get('dry_run'):
3484 if not opts.get('dry_run'):
3482 util.rename(target, bakname)
3485 util.rename(target, bakname)
3483 if ui.verbose or not exact:
3486 if ui.verbose or not exact:
3484 msg = xlist[1]
3487 msg = xlist[1]
3485 if not isinstance(msg, basestring):
3488 if not isinstance(msg, basestring):
3486 msg = msg(abs)
3489 msg = msg(abs)
3487 ui.status(msg % rel)
3490 ui.status(msg % rel)
3488 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3491 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3489 if abs not in table:
3492 if abs not in table:
3490 continue
3493 continue
3491 # file has changed in dirstate
3494 # file has changed in dirstate
3492 if mfentry:
3495 if mfentry:
3493 handle(hitlist, backuphit)
3496 handle(hitlist, backuphit)
3494 elif misslist is not None:
3497 elif misslist is not None:
3495 handle(misslist, backupmiss)
3498 handle(misslist, backupmiss)
3496 break
3499 break
3497 else:
3500 else:
3498 if abs not in repo.dirstate:
3501 if abs not in repo.dirstate:
3499 if mfentry:
3502 if mfentry:
3500 handle(add, True)
3503 handle(add, True)
3501 elif exact:
3504 elif exact:
3502 ui.warn(_('file not managed: %s\n') % rel)
3505 ui.warn(_('file not managed: %s\n') % rel)
3503 continue
3506 continue
3504 # file has not changed in dirstate
3507 # file has not changed in dirstate
3505 if node == parent:
3508 if node == parent:
3506 if exact:
3509 if exact:
3507 ui.warn(_('no changes needed to %s\n') % rel)
3510 ui.warn(_('no changes needed to %s\n') % rel)
3508 continue
3511 continue
3509 if pmf is None:
3512 if pmf is None:
3510 # only need parent manifest in this unlikely case,
3513 # only need parent manifest in this unlikely case,
3511 # so do not read by default
3514 # so do not read by default
3512 pmf = repo[parent].manifest()
3515 pmf = repo[parent].manifest()
3513 if abs in pmf:
3516 if abs in pmf:
3514 if mfentry:
3517 if mfentry:
3515 # if version of file is same in parent and target
3518 # if version of file is same in parent and target
3516 # manifests, do nothing
3519 # manifests, do nothing
3517 if (pmf[abs] != mfentry or
3520 if (pmf[abs] != mfentry or
3518 pmf.flags(abs) != mf.flags(abs)):
3521 pmf.flags(abs) != mf.flags(abs)):
3519 handle(revert, False)
3522 handle(revert, False)
3520 else:
3523 else:
3521 handle(remove, False)
3524 handle(remove, False)
3522
3525
3523 if not opts.get('dry_run'):
3526 if not opts.get('dry_run'):
3524 def checkout(f):
3527 def checkout(f):
3525 fc = ctx[f]
3528 fc = ctx[f]
3526 repo.wwrite(f, fc.data(), fc.flags())
3529 repo.wwrite(f, fc.data(), fc.flags())
3527
3530
3528 audit_path = scmutil.path_auditor(repo.root)
3531 audit_path = scmutil.path_auditor(repo.root)
3529 for f in remove[0]:
3532 for f in remove[0]:
3530 if repo.dirstate[f] == 'a':
3533 if repo.dirstate[f] == 'a':
3531 repo.dirstate.forget(f)
3534 repo.dirstate.forget(f)
3532 continue
3535 continue
3533 audit_path(f)
3536 audit_path(f)
3534 try:
3537 try:
3535 util.unlinkpath(repo.wjoin(f))
3538 util.unlinkpath(repo.wjoin(f))
3536 except OSError:
3539 except OSError:
3537 pass
3540 pass
3538 repo.dirstate.remove(f)
3541 repo.dirstate.remove(f)
3539
3542
3540 normal = None
3543 normal = None
3541 if node == parent:
3544 if node == parent:
3542 # We're reverting to our parent. If possible, we'd like status
3545 # We're reverting to our parent. If possible, we'd like status
3543 # to report the file as clean. We have to use normallookup for
3546 # to report the file as clean. We have to use normallookup for
3544 # merges to avoid losing information about merged/dirty files.
3547 # merges to avoid losing information about merged/dirty files.
3545 if p2 != nullid:
3548 if p2 != nullid:
3546 normal = repo.dirstate.normallookup
3549 normal = repo.dirstate.normallookup
3547 else:
3550 else:
3548 normal = repo.dirstate.normal
3551 normal = repo.dirstate.normal
3549 for f in revert[0]:
3552 for f in revert[0]:
3550 checkout(f)
3553 checkout(f)
3551 if normal:
3554 if normal:
3552 normal(f)
3555 normal(f)
3553
3556
3554 for f in add[0]:
3557 for f in add[0]:
3555 checkout(f)
3558 checkout(f)
3556 repo.dirstate.add(f)
3559 repo.dirstate.add(f)
3557
3560
3558 normal = repo.dirstate.normallookup
3561 normal = repo.dirstate.normallookup
3559 if node == parent and p2 == nullid:
3562 if node == parent and p2 == nullid:
3560 normal = repo.dirstate.normal
3563 normal = repo.dirstate.normal
3561 for f in undelete[0]:
3564 for f in undelete[0]:
3562 checkout(f)
3565 checkout(f)
3563 normal(f)
3566 normal(f)
3564
3567
3565 finally:
3568 finally:
3566 wlock.release()
3569 wlock.release()
3567
3570
3568 def rollback(ui, repo, **opts):
3571 def rollback(ui, repo, **opts):
3569 """roll back the last transaction (dangerous)
3572 """roll back the last transaction (dangerous)
3570
3573
3571 This command should be used with care. There is only one level of
3574 This command should be used with care. There is only one level of
3572 rollback, and there is no way to undo a rollback. It will also
3575 rollback, and there is no way to undo a rollback. It will also
3573 restore the dirstate at the time of the last transaction, losing
3576 restore the dirstate at the time of the last transaction, losing
3574 any dirstate changes since that time. This command does not alter
3577 any dirstate changes since that time. This command does not alter
3575 the working directory.
3578 the working directory.
3576
3579
3577 Transactions are used to encapsulate the effects of all commands
3580 Transactions are used to encapsulate the effects of all commands
3578 that create new changesets or propagate existing changesets into a
3581 that create new changesets or propagate existing changesets into a
3579 repository. For example, the following commands are transactional,
3582 repository. For example, the following commands are transactional,
3580 and their effects can be rolled back:
3583 and their effects can be rolled back:
3581
3584
3582 - commit
3585 - commit
3583 - import
3586 - import
3584 - pull
3587 - pull
3585 - push (with this repository as the destination)
3588 - push (with this repository as the destination)
3586 - unbundle
3589 - unbundle
3587
3590
3588 This command is not intended for use on public repositories. Once
3591 This command is not intended for use on public repositories. Once
3589 changes are visible for pull by other users, rolling a transaction
3592 changes are visible for pull by other users, rolling a transaction
3590 back locally is ineffective (someone else may already have pulled
3593 back locally is ineffective (someone else may already have pulled
3591 the changes). Furthermore, a race is possible with readers of the
3594 the changes). Furthermore, a race is possible with readers of the
3592 repository; for example an in-progress pull from the repository
3595 repository; for example an in-progress pull from the repository
3593 may fail if a rollback is performed.
3596 may fail if a rollback is performed.
3594
3597
3595 Returns 0 on success, 1 if no rollback data is available.
3598 Returns 0 on success, 1 if no rollback data is available.
3596 """
3599 """
3597 return repo.rollback(opts.get('dry_run'))
3600 return repo.rollback(opts.get('dry_run'))
3598
3601
3599 def root(ui, repo):
3602 def root(ui, repo):
3600 """print the root (top) of the current working directory
3603 """print the root (top) of the current working directory
3601
3604
3602 Print the root directory of the current repository.
3605 Print the root directory of the current repository.
3603
3606
3604 Returns 0 on success.
3607 Returns 0 on success.
3605 """
3608 """
3606 ui.write(repo.root + "\n")
3609 ui.write(repo.root + "\n")
3607
3610
3608 def serve(ui, repo, **opts):
3611 def serve(ui, repo, **opts):
3609 """start stand-alone webserver
3612 """start stand-alone webserver
3610
3613
3611 Start a local HTTP repository browser and pull server. You can use
3614 Start a local HTTP repository browser and pull server. You can use
3612 this for ad-hoc sharing and browsing of repositories. It is
3615 this for ad-hoc sharing and browsing of repositories. It is
3613 recommended to use a real web server to serve a repository for
3616 recommended to use a real web server to serve a repository for
3614 longer periods of time.
3617 longer periods of time.
3615
3618
3616 Please note that the server does not implement access control.
3619 Please note that the server does not implement access control.
3617 This means that, by default, anybody can read from the server and
3620 This means that, by default, anybody can read from the server and
3618 nobody can write to it by default. Set the ``web.allow_push``
3621 nobody can write to it by default. Set the ``web.allow_push``
3619 option to ``*`` to allow everybody to push to the server. You
3622 option to ``*`` to allow everybody to push to the server. You
3620 should use a real web server if you need to authenticate users.
3623 should use a real web server if you need to authenticate users.
3621
3624
3622 By default, the server logs accesses to stdout and errors to
3625 By default, the server logs accesses to stdout and errors to
3623 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3626 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3624 files.
3627 files.
3625
3628
3626 To have the server choose a free port number to listen on, specify
3629 To have the server choose a free port number to listen on, specify
3627 a port number of 0; in this case, the server will print the port
3630 a port number of 0; in this case, the server will print the port
3628 number it uses.
3631 number it uses.
3629
3632
3630 Returns 0 on success.
3633 Returns 0 on success.
3631 """
3634 """
3632
3635
3633 if opts["stdio"]:
3636 if opts["stdio"]:
3634 if repo is None:
3637 if repo is None:
3635 raise error.RepoError(_("There is no Mercurial repository here"
3638 raise error.RepoError(_("There is no Mercurial repository here"
3636 " (.hg not found)"))
3639 " (.hg not found)"))
3637 s = sshserver.sshserver(ui, repo)
3640 s = sshserver.sshserver(ui, repo)
3638 s.serve_forever()
3641 s.serve_forever()
3639
3642
3640 # this way we can check if something was given in the command-line
3643 # this way we can check if something was given in the command-line
3641 if opts.get('port'):
3644 if opts.get('port'):
3642 opts['port'] = util.getport(opts.get('port'))
3645 opts['port'] = util.getport(opts.get('port'))
3643
3646
3644 baseui = repo and repo.baseui or ui
3647 baseui = repo and repo.baseui or ui
3645 optlist = ("name templates style address port prefix ipv6"
3648 optlist = ("name templates style address port prefix ipv6"
3646 " accesslog errorlog certificate encoding")
3649 " accesslog errorlog certificate encoding")
3647 for o in optlist.split():
3650 for o in optlist.split():
3648 val = opts.get(o, '')
3651 val = opts.get(o, '')
3649 if val in (None, ''): # should check against default options instead
3652 if val in (None, ''): # should check against default options instead
3650 continue
3653 continue
3651 baseui.setconfig("web", o, val)
3654 baseui.setconfig("web", o, val)
3652 if repo and repo.ui != baseui:
3655 if repo and repo.ui != baseui:
3653 repo.ui.setconfig("web", o, val)
3656 repo.ui.setconfig("web", o, val)
3654
3657
3655 o = opts.get('web_conf') or opts.get('webdir_conf')
3658 o = opts.get('web_conf') or opts.get('webdir_conf')
3656 if not o:
3659 if not o:
3657 if not repo:
3660 if not repo:
3658 raise error.RepoError(_("There is no Mercurial repository"
3661 raise error.RepoError(_("There is no Mercurial repository"
3659 " here (.hg not found)"))
3662 " here (.hg not found)"))
3660 o = repo.root
3663 o = repo.root
3661
3664
3662 app = hgweb.hgweb(o, baseui=ui)
3665 app = hgweb.hgweb(o, baseui=ui)
3663
3666
3664 class service(object):
3667 class service(object):
3665 def init(self):
3668 def init(self):
3666 util.set_signal_handler()
3669 util.set_signal_handler()
3667 self.httpd = hgweb.server.create_server(ui, app)
3670 self.httpd = hgweb.server.create_server(ui, app)
3668
3671
3669 if opts['port'] and not ui.verbose:
3672 if opts['port'] and not ui.verbose:
3670 return
3673 return
3671
3674
3672 if self.httpd.prefix:
3675 if self.httpd.prefix:
3673 prefix = self.httpd.prefix.strip('/') + '/'
3676 prefix = self.httpd.prefix.strip('/') + '/'
3674 else:
3677 else:
3675 prefix = ''
3678 prefix = ''
3676
3679
3677 port = ':%d' % self.httpd.port
3680 port = ':%d' % self.httpd.port
3678 if port == ':80':
3681 if port == ':80':
3679 port = ''
3682 port = ''
3680
3683
3681 bindaddr = self.httpd.addr
3684 bindaddr = self.httpd.addr
3682 if bindaddr == '0.0.0.0':
3685 if bindaddr == '0.0.0.0':
3683 bindaddr = '*'
3686 bindaddr = '*'
3684 elif ':' in bindaddr: # IPv6
3687 elif ':' in bindaddr: # IPv6
3685 bindaddr = '[%s]' % bindaddr
3688 bindaddr = '[%s]' % bindaddr
3686
3689
3687 fqaddr = self.httpd.fqaddr
3690 fqaddr = self.httpd.fqaddr
3688 if ':' in fqaddr:
3691 if ':' in fqaddr:
3689 fqaddr = '[%s]' % fqaddr
3692 fqaddr = '[%s]' % fqaddr
3690 if opts['port']:
3693 if opts['port']:
3691 write = ui.status
3694 write = ui.status
3692 else:
3695 else:
3693 write = ui.write
3696 write = ui.write
3694 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3697 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3695 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3698 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3696
3699
3697 def run(self):
3700 def run(self):
3698 self.httpd.serve_forever()
3701 self.httpd.serve_forever()
3699
3702
3700 service = service()
3703 service = service()
3701
3704
3702 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3705 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3703
3706
3704 def status(ui, repo, *pats, **opts):
3707 def status(ui, repo, *pats, **opts):
3705 """show changed files in the working directory
3708 """show changed files in the working directory
3706
3709
3707 Show status of files in the repository. If names are given, only
3710 Show status of files in the repository. If names are given, only
3708 files that match are shown. Files that are clean or ignored or
3711 files that match are shown. Files that are clean or ignored or
3709 the source of a copy/move operation, are not listed unless
3712 the source of a copy/move operation, are not listed unless
3710 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3713 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3711 Unless options described with "show only ..." are given, the
3714 Unless options described with "show only ..." are given, the
3712 options -mardu are used.
3715 options -mardu are used.
3713
3716
3714 Option -q/--quiet hides untracked (unknown and ignored) files
3717 Option -q/--quiet hides untracked (unknown and ignored) files
3715 unless explicitly requested with -u/--unknown or -i/--ignored.
3718 unless explicitly requested with -u/--unknown or -i/--ignored.
3716
3719
3717 .. note::
3720 .. note::
3718 status may appear to disagree with diff if permissions have
3721 status may appear to disagree with diff if permissions have
3719 changed or a merge has occurred. The standard diff format does
3722 changed or a merge has occurred. The standard diff format does
3720 not report permission changes and diff only reports changes
3723 not report permission changes and diff only reports changes
3721 relative to one merge parent.
3724 relative to one merge parent.
3722
3725
3723 If one revision is given, it is used as the base revision.
3726 If one revision is given, it is used as the base revision.
3724 If two revisions are given, the differences between them are
3727 If two revisions are given, the differences between them are
3725 shown. The --change option can also be used as a shortcut to list
3728 shown. The --change option can also be used as a shortcut to list
3726 the changed files of a revision from its first parent.
3729 the changed files of a revision from its first parent.
3727
3730
3728 The codes used to show the status of files are::
3731 The codes used to show the status of files are::
3729
3732
3730 M = modified
3733 M = modified
3731 A = added
3734 A = added
3732 R = removed
3735 R = removed
3733 C = clean
3736 C = clean
3734 ! = missing (deleted by non-hg command, but still tracked)
3737 ! = missing (deleted by non-hg command, but still tracked)
3735 ? = not tracked
3738 ? = not tracked
3736 I = ignored
3739 I = ignored
3737 = origin of the previous file listed as A (added)
3740 = origin of the previous file listed as A (added)
3738
3741
3739 Returns 0 on success.
3742 Returns 0 on success.
3740 """
3743 """
3741
3744
3742 revs = opts.get('rev')
3745 revs = opts.get('rev')
3743 change = opts.get('change')
3746 change = opts.get('change')
3744
3747
3745 if revs and change:
3748 if revs and change:
3746 msg = _('cannot specify --rev and --change at the same time')
3749 msg = _('cannot specify --rev and --change at the same time')
3747 raise util.Abort(msg)
3750 raise util.Abort(msg)
3748 elif change:
3751 elif change:
3749 node2 = repo.lookup(change)
3752 node2 = repo.lookup(change)
3750 node1 = repo[node2].p1().node()
3753 node1 = repo[node2].p1().node()
3751 else:
3754 else:
3752 node1, node2 = cmdutil.revpair(repo, revs)
3755 node1, node2 = cmdutil.revpair(repo, revs)
3753
3756
3754 cwd = (pats and repo.getcwd()) or ''
3757 cwd = (pats and repo.getcwd()) or ''
3755 end = opts.get('print0') and '\0' or '\n'
3758 end = opts.get('print0') and '\0' or '\n'
3756 copy = {}
3759 copy = {}
3757 states = 'modified added removed deleted unknown ignored clean'.split()
3760 states = 'modified added removed deleted unknown ignored clean'.split()
3758 show = [k for k in states if opts.get(k)]
3761 show = [k for k in states if opts.get(k)]
3759 if opts.get('all'):
3762 if opts.get('all'):
3760 show += ui.quiet and (states[:4] + ['clean']) or states
3763 show += ui.quiet and (states[:4] + ['clean']) or states
3761 if not show:
3764 if not show:
3762 show = ui.quiet and states[:4] or states[:5]
3765 show = ui.quiet and states[:4] or states[:5]
3763
3766
3764 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3767 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3765 'ignored' in show, 'clean' in show, 'unknown' in show,
3768 'ignored' in show, 'clean' in show, 'unknown' in show,
3766 opts.get('subrepos'))
3769 opts.get('subrepos'))
3767 changestates = zip(states, 'MAR!?IC', stat)
3770 changestates = zip(states, 'MAR!?IC', stat)
3768
3771
3769 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3772 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3770 ctxn = repo[nullid]
3773 ctxn = repo[nullid]
3771 ctx1 = repo[node1]
3774 ctx1 = repo[node1]
3772 ctx2 = repo[node2]
3775 ctx2 = repo[node2]
3773 added = stat[1]
3776 added = stat[1]
3774 if node2 is None:
3777 if node2 is None:
3775 added = stat[0] + stat[1] # merged?
3778 added = stat[0] + stat[1] # merged?
3776
3779
3777 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3780 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3778 if k in added:
3781 if k in added:
3779 copy[k] = v
3782 copy[k] = v
3780 elif v in added:
3783 elif v in added:
3781 copy[v] = k
3784 copy[v] = k
3782
3785
3783 for state, char, files in changestates:
3786 for state, char, files in changestates:
3784 if state in show:
3787 if state in show:
3785 format = "%s %%s%s" % (char, end)
3788 format = "%s %%s%s" % (char, end)
3786 if opts.get('no_status'):
3789 if opts.get('no_status'):
3787 format = "%%s%s" % end
3790 format = "%%s%s" % end
3788
3791
3789 for f in files:
3792 for f in files:
3790 ui.write(format % repo.pathto(f, cwd),
3793 ui.write(format % repo.pathto(f, cwd),
3791 label='status.' + state)
3794 label='status.' + state)
3792 if f in copy:
3795 if f in copy:
3793 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3796 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3794 label='status.copied')
3797 label='status.copied')
3795
3798
3796 def summary(ui, repo, **opts):
3799 def summary(ui, repo, **opts):
3797 """summarize working directory state
3800 """summarize working directory state
3798
3801
3799 This generates a brief summary of the working directory state,
3802 This generates a brief summary of the working directory state,
3800 including parents, branch, commit status, and available updates.
3803 including parents, branch, commit status, and available updates.
3801
3804
3802 With the --remote option, this will check the default paths for
3805 With the --remote option, this will check the default paths for
3803 incoming and outgoing changes. This can be time-consuming.
3806 incoming and outgoing changes. This can be time-consuming.
3804
3807
3805 Returns 0 on success.
3808 Returns 0 on success.
3806 """
3809 """
3807
3810
3808 ctx = repo[None]
3811 ctx = repo[None]
3809 parents = ctx.parents()
3812 parents = ctx.parents()
3810 pnode = parents[0].node()
3813 pnode = parents[0].node()
3811
3814
3812 for p in parents:
3815 for p in parents:
3813 # label with log.changeset (instead of log.parent) since this
3816 # label with log.changeset (instead of log.parent) since this
3814 # shows a working directory parent *changeset*:
3817 # shows a working directory parent *changeset*:
3815 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3818 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3816 label='log.changeset')
3819 label='log.changeset')
3817 ui.write(' '.join(p.tags()), label='log.tag')
3820 ui.write(' '.join(p.tags()), label='log.tag')
3818 if p.bookmarks():
3821 if p.bookmarks():
3819 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
3822 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
3820 if p.rev() == -1:
3823 if p.rev() == -1:
3821 if not len(repo):
3824 if not len(repo):
3822 ui.write(_(' (empty repository)'))
3825 ui.write(_(' (empty repository)'))
3823 else:
3826 else:
3824 ui.write(_(' (no revision checked out)'))
3827 ui.write(_(' (no revision checked out)'))
3825 ui.write('\n')
3828 ui.write('\n')
3826 if p.description():
3829 if p.description():
3827 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3830 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3828 label='log.summary')
3831 label='log.summary')
3829
3832
3830 branch = ctx.branch()
3833 branch = ctx.branch()
3831 bheads = repo.branchheads(branch)
3834 bheads = repo.branchheads(branch)
3832 m = _('branch: %s\n') % branch
3835 m = _('branch: %s\n') % branch
3833 if branch != 'default':
3836 if branch != 'default':
3834 ui.write(m, label='log.branch')
3837 ui.write(m, label='log.branch')
3835 else:
3838 else:
3836 ui.status(m, label='log.branch')
3839 ui.status(m, label='log.branch')
3837
3840
3838 st = list(repo.status(unknown=True))[:6]
3841 st = list(repo.status(unknown=True))[:6]
3839
3842
3840 c = repo.dirstate.copies()
3843 c = repo.dirstate.copies()
3841 copied, renamed = [], []
3844 copied, renamed = [], []
3842 for d, s in c.iteritems():
3845 for d, s in c.iteritems():
3843 if s in st[2]:
3846 if s in st[2]:
3844 st[2].remove(s)
3847 st[2].remove(s)
3845 renamed.append(d)
3848 renamed.append(d)
3846 else:
3849 else:
3847 copied.append(d)
3850 copied.append(d)
3848 if d in st[1]:
3851 if d in st[1]:
3849 st[1].remove(d)
3852 st[1].remove(d)
3850 st.insert(3, renamed)
3853 st.insert(3, renamed)
3851 st.insert(4, copied)
3854 st.insert(4, copied)
3852
3855
3853 ms = mergemod.mergestate(repo)
3856 ms = mergemod.mergestate(repo)
3854 st.append([f for f in ms if ms[f] == 'u'])
3857 st.append([f for f in ms if ms[f] == 'u'])
3855
3858
3856 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3859 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3857 st.append(subs)
3860 st.append(subs)
3858
3861
3859 labels = [ui.label(_('%d modified'), 'status.modified'),
3862 labels = [ui.label(_('%d modified'), 'status.modified'),
3860 ui.label(_('%d added'), 'status.added'),
3863 ui.label(_('%d added'), 'status.added'),
3861 ui.label(_('%d removed'), 'status.removed'),
3864 ui.label(_('%d removed'), 'status.removed'),
3862 ui.label(_('%d renamed'), 'status.copied'),
3865 ui.label(_('%d renamed'), 'status.copied'),
3863 ui.label(_('%d copied'), 'status.copied'),
3866 ui.label(_('%d copied'), 'status.copied'),
3864 ui.label(_('%d deleted'), 'status.deleted'),
3867 ui.label(_('%d deleted'), 'status.deleted'),
3865 ui.label(_('%d unknown'), 'status.unknown'),
3868 ui.label(_('%d unknown'), 'status.unknown'),
3866 ui.label(_('%d ignored'), 'status.ignored'),
3869 ui.label(_('%d ignored'), 'status.ignored'),
3867 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3870 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3868 ui.label(_('%d subrepos'), 'status.modified')]
3871 ui.label(_('%d subrepos'), 'status.modified')]
3869 t = []
3872 t = []
3870 for s, l in zip(st, labels):
3873 for s, l in zip(st, labels):
3871 if s:
3874 if s:
3872 t.append(l % len(s))
3875 t.append(l % len(s))
3873
3876
3874 t = ', '.join(t)
3877 t = ', '.join(t)
3875 cleanworkdir = False
3878 cleanworkdir = False
3876
3879
3877 if len(parents) > 1:
3880 if len(parents) > 1:
3878 t += _(' (merge)')
3881 t += _(' (merge)')
3879 elif branch != parents[0].branch():
3882 elif branch != parents[0].branch():
3880 t += _(' (new branch)')
3883 t += _(' (new branch)')
3881 elif (parents[0].extra().get('close') and
3884 elif (parents[0].extra().get('close') and
3882 pnode in repo.branchheads(branch, closed=True)):
3885 pnode in repo.branchheads(branch, closed=True)):
3883 t += _(' (head closed)')
3886 t += _(' (head closed)')
3884 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3887 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3885 t += _(' (clean)')
3888 t += _(' (clean)')
3886 cleanworkdir = True
3889 cleanworkdir = True
3887 elif pnode not in bheads:
3890 elif pnode not in bheads:
3888 t += _(' (new branch head)')
3891 t += _(' (new branch head)')
3889
3892
3890 if cleanworkdir:
3893 if cleanworkdir:
3891 ui.status(_('commit: %s\n') % t.strip())
3894 ui.status(_('commit: %s\n') % t.strip())
3892 else:
3895 else:
3893 ui.write(_('commit: %s\n') % t.strip())
3896 ui.write(_('commit: %s\n') % t.strip())
3894
3897
3895 # all ancestors of branch heads - all ancestors of parent = new csets
3898 # all ancestors of branch heads - all ancestors of parent = new csets
3896 new = [0] * len(repo)
3899 new = [0] * len(repo)
3897 cl = repo.changelog
3900 cl = repo.changelog
3898 for a in [cl.rev(n) for n in bheads]:
3901 for a in [cl.rev(n) for n in bheads]:
3899 new[a] = 1
3902 new[a] = 1
3900 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3903 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3901 new[a] = 1
3904 new[a] = 1
3902 for a in [p.rev() for p in parents]:
3905 for a in [p.rev() for p in parents]:
3903 if a >= 0:
3906 if a >= 0:
3904 new[a] = 0
3907 new[a] = 0
3905 for a in cl.ancestors(*[p.rev() for p in parents]):
3908 for a in cl.ancestors(*[p.rev() for p in parents]):
3906 new[a] = 0
3909 new[a] = 0
3907 new = sum(new)
3910 new = sum(new)
3908
3911
3909 if new == 0:
3912 if new == 0:
3910 ui.status(_('update: (current)\n'))
3913 ui.status(_('update: (current)\n'))
3911 elif pnode not in bheads:
3914 elif pnode not in bheads:
3912 ui.write(_('update: %d new changesets (update)\n') % new)
3915 ui.write(_('update: %d new changesets (update)\n') % new)
3913 else:
3916 else:
3914 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3917 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3915 (new, len(bheads)))
3918 (new, len(bheads)))
3916
3919
3917 if opts.get('remote'):
3920 if opts.get('remote'):
3918 t = []
3921 t = []
3919 source, branches = hg.parseurl(ui.expandpath('default'))
3922 source, branches = hg.parseurl(ui.expandpath('default'))
3920 other = hg.repository(hg.remoteui(repo, {}), source)
3923 other = hg.repository(hg.remoteui(repo, {}), source)
3921 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3924 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3922 ui.debug('comparing with %s\n' % util.hidepassword(source))
3925 ui.debug('comparing with %s\n' % util.hidepassword(source))
3923 repo.ui.pushbuffer()
3926 repo.ui.pushbuffer()
3924 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3927 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3925 repo.ui.popbuffer()
3928 repo.ui.popbuffer()
3926 if incoming:
3929 if incoming:
3927 t.append(_('1 or more incoming'))
3930 t.append(_('1 or more incoming'))
3928
3931
3929 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3932 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3930 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3933 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3931 other = hg.repository(hg.remoteui(repo, {}), dest)
3934 other = hg.repository(hg.remoteui(repo, {}), dest)
3932 ui.debug('comparing with %s\n' % util.hidepassword(dest))
3935 ui.debug('comparing with %s\n' % util.hidepassword(dest))
3933 repo.ui.pushbuffer()
3936 repo.ui.pushbuffer()
3934 common, _anyinc, _heads = discovery.findcommonincoming(repo, other)
3937 common, _anyinc, _heads = discovery.findcommonincoming(repo, other)
3935 repo.ui.popbuffer()
3938 repo.ui.popbuffer()
3936 o = repo.changelog.findmissing(common=common)
3939 o = repo.changelog.findmissing(common=common)
3937 if o:
3940 if o:
3938 t.append(_('%d outgoing') % len(o))
3941 t.append(_('%d outgoing') % len(o))
3939 if 'bookmarks' in other.listkeys('namespaces'):
3942 if 'bookmarks' in other.listkeys('namespaces'):
3940 lmarks = repo.listkeys('bookmarks')
3943 lmarks = repo.listkeys('bookmarks')
3941 rmarks = other.listkeys('bookmarks')
3944 rmarks = other.listkeys('bookmarks')
3942 diff = set(rmarks) - set(lmarks)
3945 diff = set(rmarks) - set(lmarks)
3943 if len(diff) > 0:
3946 if len(diff) > 0:
3944 t.append(_('%d incoming bookmarks') % len(diff))
3947 t.append(_('%d incoming bookmarks') % len(diff))
3945 diff = set(lmarks) - set(rmarks)
3948 diff = set(lmarks) - set(rmarks)
3946 if len(diff) > 0:
3949 if len(diff) > 0:
3947 t.append(_('%d outgoing bookmarks') % len(diff))
3950 t.append(_('%d outgoing bookmarks') % len(diff))
3948
3951
3949 if t:
3952 if t:
3950 ui.write(_('remote: %s\n') % (', '.join(t)))
3953 ui.write(_('remote: %s\n') % (', '.join(t)))
3951 else:
3954 else:
3952 ui.status(_('remote: (synced)\n'))
3955 ui.status(_('remote: (synced)\n'))
3953
3956
3954 def tag(ui, repo, name1, *names, **opts):
3957 def tag(ui, repo, name1, *names, **opts):
3955 """add one or more tags for the current or given revision
3958 """add one or more tags for the current or given revision
3956
3959
3957 Name a particular revision using <name>.
3960 Name a particular revision using <name>.
3958
3961
3959 Tags are used to name particular revisions of the repository and are
3962 Tags are used to name particular revisions of the repository and are
3960 very useful to compare different revisions, to go back to significant
3963 very useful to compare different revisions, to go back to significant
3961 earlier versions or to mark branch points as releases, etc. Changing
3964 earlier versions or to mark branch points as releases, etc. Changing
3962 an existing tag is normally disallowed; use -f/--force to override.
3965 an existing tag is normally disallowed; use -f/--force to override.
3963
3966
3964 If no revision is given, the parent of the working directory is
3967 If no revision is given, the parent of the working directory is
3965 used, or tip if no revision is checked out.
3968 used, or tip if no revision is checked out.
3966
3969
3967 To facilitate version control, distribution, and merging of tags,
3970 To facilitate version control, distribution, and merging of tags,
3968 they are stored as a file named ".hgtags" which is managed similarly
3971 they are stored as a file named ".hgtags" which is managed similarly
3969 to other project files and can be hand-edited if necessary. This
3972 to other project files and can be hand-edited if necessary. This
3970 also means that tagging creates a new commit. The file
3973 also means that tagging creates a new commit. The file
3971 ".hg/localtags" is used for local tags (not shared among
3974 ".hg/localtags" is used for local tags (not shared among
3972 repositories).
3975 repositories).
3973
3976
3974 Tag commits are usually made at the head of a branch. If the parent
3977 Tag commits are usually made at the head of a branch. If the parent
3975 of the working directory is not a branch head, :hg:`tag` aborts; use
3978 of the working directory is not a branch head, :hg:`tag` aborts; use
3976 -f/--force to force the tag commit to be based on a non-head
3979 -f/--force to force the tag commit to be based on a non-head
3977 changeset.
3980 changeset.
3978
3981
3979 See :hg:`help dates` for a list of formats valid for -d/--date.
3982 See :hg:`help dates` for a list of formats valid for -d/--date.
3980
3983
3981 Since tag names have priority over branch names during revision
3984 Since tag names have priority over branch names during revision
3982 lookup, using an existing branch name as a tag name is discouraged.
3985 lookup, using an existing branch name as a tag name is discouraged.
3983
3986
3984 Returns 0 on success.
3987 Returns 0 on success.
3985 """
3988 """
3986
3989
3987 rev_ = "."
3990 rev_ = "."
3988 names = [t.strip() for t in (name1,) + names]
3991 names = [t.strip() for t in (name1,) + names]
3989 if len(names) != len(set(names)):
3992 if len(names) != len(set(names)):
3990 raise util.Abort(_('tag names must be unique'))
3993 raise util.Abort(_('tag names must be unique'))
3991 for n in names:
3994 for n in names:
3992 if n in ['tip', '.', 'null']:
3995 if n in ['tip', '.', 'null']:
3993 raise util.Abort(_('the name \'%s\' is reserved') % n)
3996 raise util.Abort(_('the name \'%s\' is reserved') % n)
3994 if not n:
3997 if not n:
3995 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3998 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3996 if opts.get('rev') and opts.get('remove'):
3999 if opts.get('rev') and opts.get('remove'):
3997 raise util.Abort(_("--rev and --remove are incompatible"))
4000 raise util.Abort(_("--rev and --remove are incompatible"))
3998 if opts.get('rev'):
4001 if opts.get('rev'):
3999 rev_ = opts['rev']
4002 rev_ = opts['rev']
4000 message = opts.get('message')
4003 message = opts.get('message')
4001 if opts.get('remove'):
4004 if opts.get('remove'):
4002 expectedtype = opts.get('local') and 'local' or 'global'
4005 expectedtype = opts.get('local') and 'local' or 'global'
4003 for n in names:
4006 for n in names:
4004 if not repo.tagtype(n):
4007 if not repo.tagtype(n):
4005 raise util.Abort(_('tag \'%s\' does not exist') % n)
4008 raise util.Abort(_('tag \'%s\' does not exist') % n)
4006 if repo.tagtype(n) != expectedtype:
4009 if repo.tagtype(n) != expectedtype:
4007 if expectedtype == 'global':
4010 if expectedtype == 'global':
4008 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
4011 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
4009 else:
4012 else:
4010 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
4013 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
4011 rev_ = nullid
4014 rev_ = nullid
4012 if not message:
4015 if not message:
4013 # we don't translate commit messages
4016 # we don't translate commit messages
4014 message = 'Removed tag %s' % ', '.join(names)
4017 message = 'Removed tag %s' % ', '.join(names)
4015 elif not opts.get('force'):
4018 elif not opts.get('force'):
4016 for n in names:
4019 for n in names:
4017 if n in repo.tags():
4020 if n in repo.tags():
4018 raise util.Abort(_('tag \'%s\' already exists '
4021 raise util.Abort(_('tag \'%s\' already exists '
4019 '(use -f to force)') % n)
4022 '(use -f to force)') % n)
4020 if not opts.get('local'):
4023 if not opts.get('local'):
4021 p1, p2 = repo.dirstate.parents()
4024 p1, p2 = repo.dirstate.parents()
4022 if p2 != nullid:
4025 if p2 != nullid:
4023 raise util.Abort(_('uncommitted merge'))
4026 raise util.Abort(_('uncommitted merge'))
4024 bheads = repo.branchheads()
4027 bheads = repo.branchheads()
4025 if not opts.get('force') and bheads and p1 not in bheads:
4028 if not opts.get('force') and bheads and p1 not in bheads:
4026 raise util.Abort(_('not at a branch head (use -f to force)'))
4029 raise util.Abort(_('not at a branch head (use -f to force)'))
4027 r = cmdutil.revsingle(repo, rev_).node()
4030 r = cmdutil.revsingle(repo, rev_).node()
4028
4031
4029 if not message:
4032 if not message:
4030 # we don't translate commit messages
4033 # we don't translate commit messages
4031 message = ('Added tag %s for changeset %s' %
4034 message = ('Added tag %s for changeset %s' %
4032 (', '.join(names), short(r)))
4035 (', '.join(names), short(r)))
4033
4036
4034 date = opts.get('date')
4037 date = opts.get('date')
4035 if date:
4038 if date:
4036 date = util.parsedate(date)
4039 date = util.parsedate(date)
4037
4040
4038 if opts.get('edit'):
4041 if opts.get('edit'):
4039 message = ui.edit(message, ui.username())
4042 message = ui.edit(message, ui.username())
4040
4043
4041 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4044 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4042
4045
4043 def tags(ui, repo):
4046 def tags(ui, repo):
4044 """list repository tags
4047 """list repository tags
4045
4048
4046 This lists both regular and local tags. When the -v/--verbose
4049 This lists both regular and local tags. When the -v/--verbose
4047 switch is used, a third column "local" is printed for local tags.
4050 switch is used, a third column "local" is printed for local tags.
4048
4051
4049 Returns 0 on success.
4052 Returns 0 on success.
4050 """
4053 """
4051
4054
4052 hexfunc = ui.debugflag and hex or short
4055 hexfunc = ui.debugflag and hex or short
4053 tagtype = ""
4056 tagtype = ""
4054
4057
4055 for t, n in reversed(repo.tagslist()):
4058 for t, n in reversed(repo.tagslist()):
4056 if ui.quiet:
4059 if ui.quiet:
4057 ui.write("%s\n" % t)
4060 ui.write("%s\n" % t)
4058 continue
4061 continue
4059
4062
4060 hn = hexfunc(n)
4063 hn = hexfunc(n)
4061 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4064 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4062 spaces = " " * (30 - encoding.colwidth(t))
4065 spaces = " " * (30 - encoding.colwidth(t))
4063
4066
4064 if ui.verbose:
4067 if ui.verbose:
4065 if repo.tagtype(t) == 'local':
4068 if repo.tagtype(t) == 'local':
4066 tagtype = " local"
4069 tagtype = " local"
4067 else:
4070 else:
4068 tagtype = ""
4071 tagtype = ""
4069 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4072 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4070
4073
4071 def tip(ui, repo, **opts):
4074 def tip(ui, repo, **opts):
4072 """show the tip revision
4075 """show the tip revision
4073
4076
4074 The tip revision (usually just called the tip) is the changeset
4077 The tip revision (usually just called the tip) is the changeset
4075 most recently added to the repository (and therefore the most
4078 most recently added to the repository (and therefore the most
4076 recently changed head).
4079 recently changed head).
4077
4080
4078 If you have just made a commit, that commit will be the tip. If
4081 If you have just made a commit, that commit will be the tip. If
4079 you have just pulled changes from another repository, the tip of
4082 you have just pulled changes from another repository, the tip of
4080 that repository becomes the current tip. The "tip" tag is special
4083 that repository becomes the current tip. The "tip" tag is special
4081 and cannot be renamed or assigned to a different changeset.
4084 and cannot be renamed or assigned to a different changeset.
4082
4085
4083 Returns 0 on success.
4086 Returns 0 on success.
4084 """
4087 """
4085 displayer = cmdutil.show_changeset(ui, repo, opts)
4088 displayer = cmdutil.show_changeset(ui, repo, opts)
4086 displayer.show(repo[len(repo) - 1])
4089 displayer.show(repo[len(repo) - 1])
4087 displayer.close()
4090 displayer.close()
4088
4091
4089 def unbundle(ui, repo, fname1, *fnames, **opts):
4092 def unbundle(ui, repo, fname1, *fnames, **opts):
4090 """apply one or more changegroup files
4093 """apply one or more changegroup files
4091
4094
4092 Apply one or more compressed changegroup files generated by the
4095 Apply one or more compressed changegroup files generated by the
4093 bundle command.
4096 bundle command.
4094
4097
4095 Returns 0 on success, 1 if an update has unresolved files.
4098 Returns 0 on success, 1 if an update has unresolved files.
4096 """
4099 """
4097 fnames = (fname1,) + fnames
4100 fnames = (fname1,) + fnames
4098
4101
4099 lock = repo.lock()
4102 lock = repo.lock()
4100 wc = repo['.']
4103 wc = repo['.']
4101 try:
4104 try:
4102 for fname in fnames:
4105 for fname in fnames:
4103 f = url.open(ui, fname)
4106 f = url.open(ui, fname)
4104 gen = changegroup.readbundle(f, fname)
4107 gen = changegroup.readbundle(f, fname)
4105 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4108 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4106 lock=lock)
4109 lock=lock)
4107 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
4110 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
4108 finally:
4111 finally:
4109 lock.release()
4112 lock.release()
4110 return postincoming(ui, repo, modheads, opts.get('update'), None)
4113 return postincoming(ui, repo, modheads, opts.get('update'), None)
4111
4114
4112 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4115 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4113 """update working directory (or switch revisions)
4116 """update working directory (or switch revisions)
4114
4117
4115 Update the repository's working directory to the specified
4118 Update the repository's working directory to the specified
4116 changeset. If no changeset is specified, update to the tip of the
4119 changeset. If no changeset is specified, update to the tip of the
4117 current named branch.
4120 current named branch.
4118
4121
4119 If the changeset is not a descendant of the working directory's
4122 If the changeset is not a descendant of the working directory's
4120 parent, the update is aborted. With the -c/--check option, the
4123 parent, the update is aborted. With the -c/--check option, the
4121 working directory is checked for uncommitted changes; if none are
4124 working directory is checked for uncommitted changes; if none are
4122 found, the working directory is updated to the specified
4125 found, the working directory is updated to the specified
4123 changeset.
4126 changeset.
4124
4127
4125 The following rules apply when the working directory contains
4128 The following rules apply when the working directory contains
4126 uncommitted changes:
4129 uncommitted changes:
4127
4130
4128 1. If neither -c/--check nor -C/--clean is specified, and if
4131 1. If neither -c/--check nor -C/--clean is specified, and if
4129 the requested changeset is an ancestor or descendant of
4132 the requested changeset is an ancestor or descendant of
4130 the working directory's parent, the uncommitted changes
4133 the working directory's parent, the uncommitted changes
4131 are merged into the requested changeset and the merged
4134 are merged into the requested changeset and the merged
4132 result is left uncommitted. If the requested changeset is
4135 result is left uncommitted. If the requested changeset is
4133 not an ancestor or descendant (that is, it is on another
4136 not an ancestor or descendant (that is, it is on another
4134 branch), the update is aborted and the uncommitted changes
4137 branch), the update is aborted and the uncommitted changes
4135 are preserved.
4138 are preserved.
4136
4139
4137 2. With the -c/--check option, the update is aborted and the
4140 2. With the -c/--check option, the update is aborted and the
4138 uncommitted changes are preserved.
4141 uncommitted changes are preserved.
4139
4142
4140 3. With the -C/--clean option, uncommitted changes are discarded and
4143 3. With the -C/--clean option, uncommitted changes are discarded and
4141 the working directory is updated to the requested changeset.
4144 the working directory is updated to the requested changeset.
4142
4145
4143 Use null as the changeset to remove the working directory (like
4146 Use null as the changeset to remove the working directory (like
4144 :hg:`clone -U`).
4147 :hg:`clone -U`).
4145
4148
4146 If you want to update just one file to an older changeset, use
4149 If you want to update just one file to an older changeset, use
4147 :hg:`revert`.
4150 :hg:`revert`.
4148
4151
4149 See :hg:`help dates` for a list of formats valid for -d/--date.
4152 See :hg:`help dates` for a list of formats valid for -d/--date.
4150
4153
4151 Returns 0 on success, 1 if there are unresolved files.
4154 Returns 0 on success, 1 if there are unresolved files.
4152 """
4155 """
4153 if rev and node:
4156 if rev and node:
4154 raise util.Abort(_("please specify just one revision"))
4157 raise util.Abort(_("please specify just one revision"))
4155
4158
4156 if rev is None or rev == '':
4159 if rev is None or rev == '':
4157 rev = node
4160 rev = node
4158
4161
4159 # if we defined a bookmark, we have to remember the original bookmark name
4162 # if we defined a bookmark, we have to remember the original bookmark name
4160 brev = rev
4163 brev = rev
4161 rev = cmdutil.revsingle(repo, rev, rev).rev()
4164 rev = cmdutil.revsingle(repo, rev, rev).rev()
4162
4165
4163 if check and clean:
4166 if check and clean:
4164 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4167 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4165
4168
4166 if check:
4169 if check:
4167 # we could use dirty() but we can ignore merge and branch trivia
4170 # we could use dirty() but we can ignore merge and branch trivia
4168 c = repo[None]
4171 c = repo[None]
4169 if c.modified() or c.added() or c.removed():
4172 if c.modified() or c.added() or c.removed():
4170 raise util.Abort(_("uncommitted local changes"))
4173 raise util.Abort(_("uncommitted local changes"))
4171
4174
4172 if date:
4175 if date:
4173 if rev is not None:
4176 if rev is not None:
4174 raise util.Abort(_("you can't specify a revision and a date"))
4177 raise util.Abort(_("you can't specify a revision and a date"))
4175 rev = cmdutil.finddate(ui, repo, date)
4178 rev = cmdutil.finddate(ui, repo, date)
4176
4179
4177 if clean or check:
4180 if clean or check:
4178 ret = hg.clean(repo, rev)
4181 ret = hg.clean(repo, rev)
4179 else:
4182 else:
4180 ret = hg.update(repo, rev)
4183 ret = hg.update(repo, rev)
4181
4184
4182 if brev in repo._bookmarks:
4185 if brev in repo._bookmarks:
4183 bookmarks.setcurrent(repo, brev)
4186 bookmarks.setcurrent(repo, brev)
4184
4187
4185 return ret
4188 return ret
4186
4189
4187 def verify(ui, repo):
4190 def verify(ui, repo):
4188 """verify the integrity of the repository
4191 """verify the integrity of the repository
4189
4192
4190 Verify the integrity of the current repository.
4193 Verify the integrity of the current repository.
4191
4194
4192 This will perform an extensive check of the repository's
4195 This will perform an extensive check of the repository's
4193 integrity, validating the hashes and checksums of each entry in
4196 integrity, validating the hashes and checksums of each entry in
4194 the changelog, manifest, and tracked files, as well as the
4197 the changelog, manifest, and tracked files, as well as the
4195 integrity of their crosslinks and indices.
4198 integrity of their crosslinks and indices.
4196
4199
4197 Returns 0 on success, 1 if errors are encountered.
4200 Returns 0 on success, 1 if errors are encountered.
4198 """
4201 """
4199 return hg.verify(repo)
4202 return hg.verify(repo)
4200
4203
4201 def version_(ui):
4204 def version_(ui):
4202 """output version and copyright information"""
4205 """output version and copyright information"""
4203 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4206 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4204 % util.version())
4207 % util.version())
4205 ui.status(_(
4208 ui.status(_(
4206 "(see http://mercurial.selenic.com for more information)\n"
4209 "(see http://mercurial.selenic.com for more information)\n"
4207 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
4210 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
4208 "This is free software; see the source for copying conditions. "
4211 "This is free software; see the source for copying conditions. "
4209 "There is NO\nwarranty; "
4212 "There is NO\nwarranty; "
4210 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
4213 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
4211 ))
4214 ))
4212
4215
4213 # Command options and aliases are listed here, alphabetically
4216 # Command options and aliases are listed here, alphabetically
4214
4217
4215 globalopts = [
4218 globalopts = [
4216 ('R', 'repository', '',
4219 ('R', 'repository', '',
4217 _('repository root directory or name of overlay bundle file'),
4220 _('repository root directory or name of overlay bundle file'),
4218 _('REPO')),
4221 _('REPO')),
4219 ('', 'cwd', '',
4222 ('', 'cwd', '',
4220 _('change working directory'), _('DIR')),
4223 _('change working directory'), _('DIR')),
4221 ('y', 'noninteractive', None,
4224 ('y', 'noninteractive', None,
4222 _('do not prompt, assume \'yes\' for any required answers')),
4225 _('do not prompt, assume \'yes\' for any required answers')),
4223 ('q', 'quiet', None, _('suppress output')),
4226 ('q', 'quiet', None, _('suppress output')),
4224 ('v', 'verbose', None, _('enable additional output')),
4227 ('v', 'verbose', None, _('enable additional output')),
4225 ('', 'config', [],
4228 ('', 'config', [],
4226 _('set/override config option (use \'section.name=value\')'),
4229 _('set/override config option (use \'section.name=value\')'),
4227 _('CONFIG')),
4230 _('CONFIG')),
4228 ('', 'debug', None, _('enable debugging output')),
4231 ('', 'debug', None, _('enable debugging output')),
4229 ('', 'debugger', None, _('start debugger')),
4232 ('', 'debugger', None, _('start debugger')),
4230 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
4233 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
4231 _('ENCODE')),
4234 _('ENCODE')),
4232 ('', 'encodingmode', encoding.encodingmode,
4235 ('', 'encodingmode', encoding.encodingmode,
4233 _('set the charset encoding mode'), _('MODE')),
4236 _('set the charset encoding mode'), _('MODE')),
4234 ('', 'traceback', None, _('always print a traceback on exception')),
4237 ('', 'traceback', None, _('always print a traceback on exception')),
4235 ('', 'time', None, _('time how long the command takes')),
4238 ('', 'time', None, _('time how long the command takes')),
4236 ('', 'profile', None, _('print command execution profile')),
4239 ('', 'profile', None, _('print command execution profile')),
4237 ('', 'version', None, _('output version information and exit')),
4240 ('', 'version', None, _('output version information and exit')),
4238 ('h', 'help', None, _('display help and exit')),
4241 ('h', 'help', None, _('display help and exit')),
4239 ]
4242 ]
4240
4243
4241 dryrunopts = [('n', 'dry-run', None,
4244 dryrunopts = [('n', 'dry-run', None,
4242 _('do not perform actions, just print output'))]
4245 _('do not perform actions, just print output'))]
4243
4246
4244 remoteopts = [
4247 remoteopts = [
4245 ('e', 'ssh', '',
4248 ('e', 'ssh', '',
4246 _('specify ssh command to use'), _('CMD')),
4249 _('specify ssh command to use'), _('CMD')),
4247 ('', 'remotecmd', '',
4250 ('', 'remotecmd', '',
4248 _('specify hg command to run on the remote side'), _('CMD')),
4251 _('specify hg command to run on the remote side'), _('CMD')),
4249 ('', 'insecure', None,
4252 ('', 'insecure', None,
4250 _('do not verify server certificate (ignoring web.cacerts config)')),
4253 _('do not verify server certificate (ignoring web.cacerts config)')),
4251 ]
4254 ]
4252
4255
4253 walkopts = [
4256 walkopts = [
4254 ('I', 'include', [],
4257 ('I', 'include', [],
4255 _('include names matching the given patterns'), _('PATTERN')),
4258 _('include names matching the given patterns'), _('PATTERN')),
4256 ('X', 'exclude', [],
4259 ('X', 'exclude', [],
4257 _('exclude names matching the given patterns'), _('PATTERN')),
4260 _('exclude names matching the given patterns'), _('PATTERN')),
4258 ]
4261 ]
4259
4262
4260 commitopts = [
4263 commitopts = [
4261 ('m', 'message', '',
4264 ('m', 'message', '',
4262 _('use text as commit message'), _('TEXT')),
4265 _('use text as commit message'), _('TEXT')),
4263 ('l', 'logfile', '',
4266 ('l', 'logfile', '',
4264 _('read commit message from file'), _('FILE')),
4267 _('read commit message from file'), _('FILE')),
4265 ]
4268 ]
4266
4269
4267 commitopts2 = [
4270 commitopts2 = [
4268 ('d', 'date', '',
4271 ('d', 'date', '',
4269 _('record the specified date as commit date'), _('DATE')),
4272 _('record the specified date as commit date'), _('DATE')),
4270 ('u', 'user', '',
4273 ('u', 'user', '',
4271 _('record the specified user as committer'), _('USER')),
4274 _('record the specified user as committer'), _('USER')),
4272 ]
4275 ]
4273
4276
4274 templateopts = [
4277 templateopts = [
4275 ('', 'style', '',
4278 ('', 'style', '',
4276 _('display using template map file'), _('STYLE')),
4279 _('display using template map file'), _('STYLE')),
4277 ('', 'template', '',
4280 ('', 'template', '',
4278 _('display with template'), _('TEMPLATE')),
4281 _('display with template'), _('TEMPLATE')),
4279 ]
4282 ]
4280
4283
4281 logopts = [
4284 logopts = [
4282 ('p', 'patch', None, _('show patch')),
4285 ('p', 'patch', None, _('show patch')),
4283 ('g', 'git', None, _('use git extended diff format')),
4286 ('g', 'git', None, _('use git extended diff format')),
4284 ('l', 'limit', '',
4287 ('l', 'limit', '',
4285 _('limit number of changes displayed'), _('NUM')),
4288 _('limit number of changes displayed'), _('NUM')),
4286 ('M', 'no-merges', None, _('do not show merges')),
4289 ('M', 'no-merges', None, _('do not show merges')),
4287 ('', 'stat', None, _('output diffstat-style summary of changes')),
4290 ('', 'stat', None, _('output diffstat-style summary of changes')),
4288 ] + templateopts
4291 ] + templateopts
4289
4292
4290 diffopts = [
4293 diffopts = [
4291 ('a', 'text', None, _('treat all files as text')),
4294 ('a', 'text', None, _('treat all files as text')),
4292 ('g', 'git', None, _('use git extended diff format')),
4295 ('g', 'git', None, _('use git extended diff format')),
4293 ('', 'nodates', None, _('omit dates from diff headers'))
4296 ('', 'nodates', None, _('omit dates from diff headers'))
4294 ]
4297 ]
4295
4298
4296 diffopts2 = [
4299 diffopts2 = [
4297 ('p', 'show-function', None, _('show which function each change is in')),
4300 ('p', 'show-function', None, _('show which function each change is in')),
4298 ('', 'reverse', None, _('produce a diff that undoes the changes')),
4301 ('', 'reverse', None, _('produce a diff that undoes the changes')),
4299 ('w', 'ignore-all-space', None,
4302 ('w', 'ignore-all-space', None,
4300 _('ignore white space when comparing lines')),
4303 _('ignore white space when comparing lines')),
4301 ('b', 'ignore-space-change', None,
4304 ('b', 'ignore-space-change', None,
4302 _('ignore changes in the amount of white space')),
4305 _('ignore changes in the amount of white space')),
4303 ('B', 'ignore-blank-lines', None,
4306 ('B', 'ignore-blank-lines', None,
4304 _('ignore changes whose lines are all blank')),
4307 _('ignore changes whose lines are all blank')),
4305 ('U', 'unified', '',
4308 ('U', 'unified', '',
4306 _('number of lines of context to show'), _('NUM')),
4309 _('number of lines of context to show'), _('NUM')),
4307 ('', 'stat', None, _('output diffstat-style summary of changes')),
4310 ('', 'stat', None, _('output diffstat-style summary of changes')),
4308 ]
4311 ]
4309
4312
4310 similarityopts = [
4313 similarityopts = [
4311 ('s', 'similarity', '',
4314 ('s', 'similarity', '',
4312 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4315 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4313 ]
4316 ]
4314
4317
4315 subrepoopts = [
4318 subrepoopts = [
4316 ('S', 'subrepos', None,
4319 ('S', 'subrepos', None,
4317 _('recurse into subrepositories'))
4320 _('recurse into subrepositories'))
4318 ]
4321 ]
4319
4322
4320 table = {
4323 table = {
4321 "^add": (add, walkopts + subrepoopts + dryrunopts,
4324 "^add": (add, walkopts + subrepoopts + dryrunopts,
4322 _('[OPTION]... [FILE]...')),
4325 _('[OPTION]... [FILE]...')),
4323 "addremove":
4326 "addremove":
4324 (addremove, similarityopts + walkopts + dryrunopts,
4327 (addremove, similarityopts + walkopts + dryrunopts,
4325 _('[OPTION]... [FILE]...')),
4328 _('[OPTION]... [FILE]...')),
4326 "^annotate|blame":
4329 "^annotate|blame":
4327 (annotate,
4330 (annotate,
4328 [('r', 'rev', '',
4331 [('r', 'rev', '',
4329 _('annotate the specified revision'), _('REV')),
4332 _('annotate the specified revision'), _('REV')),
4330 ('', 'follow', None,
4333 ('', 'follow', None,
4331 _('follow copies/renames and list the filename (DEPRECATED)')),
4334 _('follow copies/renames and list the filename (DEPRECATED)')),
4332 ('', 'no-follow', None, _("don't follow copies and renames")),
4335 ('', 'no-follow', None, _("don't follow copies and renames")),
4333 ('a', 'text', None, _('treat all files as text')),
4336 ('a', 'text', None, _('treat all files as text')),
4334 ('u', 'user', None, _('list the author (long with -v)')),
4337 ('u', 'user', None, _('list the author (long with -v)')),
4335 ('f', 'file', None, _('list the filename')),
4338 ('f', 'file', None, _('list the filename')),
4336 ('d', 'date', None, _('list the date (short with -q)')),
4339 ('d', 'date', None, _('list the date (short with -q)')),
4337 ('n', 'number', None, _('list the revision number (default)')),
4340 ('n', 'number', None, _('list the revision number (default)')),
4338 ('c', 'changeset', None, _('list the changeset')),
4341 ('c', 'changeset', None, _('list the changeset')),
4339 ('l', 'line-number', None,
4342 ('l', 'line-number', None,
4340 _('show line number at the first appearance'))
4343 _('show line number at the first appearance'))
4341 ] + walkopts,
4344 ] + walkopts,
4342 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4345 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4343 "archive":
4346 "archive":
4344 (archive,
4347 (archive,
4345 [('', 'no-decode', None, _('do not pass files through decoders')),
4348 [('', 'no-decode', None, _('do not pass files through decoders')),
4346 ('p', 'prefix', '',
4349 ('p', 'prefix', '',
4347 _('directory prefix for files in archive'), _('PREFIX')),
4350 _('directory prefix for files in archive'), _('PREFIX')),
4348 ('r', 'rev', '',
4351 ('r', 'rev', '',
4349 _('revision to distribute'), _('REV')),
4352 _('revision to distribute'), _('REV')),
4350 ('t', 'type', '',
4353 ('t', 'type', '',
4351 _('type of distribution to create'), _('TYPE')),
4354 _('type of distribution to create'), _('TYPE')),
4352 ] + subrepoopts + walkopts,
4355 ] + subrepoopts + walkopts,
4353 _('[OPTION]... DEST')),
4356 _('[OPTION]... DEST')),
4354 "backout":
4357 "backout":
4355 (backout,
4358 (backout,
4356 [('', 'merge', None,
4359 [('', 'merge', None,
4357 _('merge with old dirstate parent after backout')),
4360 _('merge with old dirstate parent after backout')),
4358 ('', 'parent', '',
4361 ('', 'parent', '',
4359 _('parent to choose when backing out merge'), _('REV')),
4362 _('parent to choose when backing out merge'), _('REV')),
4360 ('t', 'tool', '',
4363 ('t', 'tool', '',
4361 _('specify merge tool')),
4364 _('specify merge tool')),
4362 ('r', 'rev', '',
4365 ('r', 'rev', '',
4363 _('revision to backout'), _('REV')),
4366 _('revision to backout'), _('REV')),
4364 ] + walkopts + commitopts + commitopts2,
4367 ] + walkopts + commitopts + commitopts2,
4365 _('[OPTION]... [-r] REV')),
4368 _('[OPTION]... [-r] REV')),
4366 "bisect":
4369 "bisect":
4367 (bisect,
4370 (bisect,
4368 [('r', 'reset', False, _('reset bisect state')),
4371 [('r', 'reset', False, _('reset bisect state')),
4369 ('g', 'good', False, _('mark changeset good')),
4372 ('g', 'good', False, _('mark changeset good')),
4370 ('b', 'bad', False, _('mark changeset bad')),
4373 ('b', 'bad', False, _('mark changeset bad')),
4371 ('s', 'skip', False, _('skip testing changeset')),
4374 ('s', 'skip', False, _('skip testing changeset')),
4372 ('e', 'extend', False, _('extend the bisect range')),
4375 ('e', 'extend', False, _('extend the bisect range')),
4373 ('c', 'command', '',
4376 ('c', 'command', '',
4374 _('use command to check changeset state'), _('CMD')),
4377 _('use command to check changeset state'), _('CMD')),
4375 ('U', 'noupdate', False, _('do not update to target'))],
4378 ('U', 'noupdate', False, _('do not update to target'))],
4376 _("[-gbsr] [-U] [-c CMD] [REV]")),
4379 _("[-gbsr] [-U] [-c CMD] [REV]")),
4377 "bookmarks":
4380 "bookmarks":
4378 (bookmark,
4381 (bookmark,
4379 [('f', 'force', False, _('force')),
4382 [('f', 'force', False, _('force')),
4380 ('r', 'rev', '', _('revision'), _('REV')),
4383 ('r', 'rev', '', _('revision'), _('REV')),
4381 ('d', 'delete', False, _('delete a given bookmark')),
4384 ('d', 'delete', False, _('delete a given bookmark')),
4382 ('m', 'rename', '', _('rename a given bookmark'), _('NAME'))],
4385 ('m', 'rename', '', _('rename a given bookmark'), _('NAME'))],
4383 _('hg bookmarks [-f] [-d] [-m NAME] [-r REV] [NAME]')),
4386 _('hg bookmarks [-f] [-d] [-m NAME] [-r REV] [NAME]')),
4384 "branch":
4387 "branch":
4385 (branch,
4388 (branch,
4386 [('f', 'force', None,
4389 [('f', 'force', None,
4387 _('set branch name even if it shadows an existing branch')),
4390 _('set branch name even if it shadows an existing branch')),
4388 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4391 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4389 _('[-fC] [NAME]')),
4392 _('[-fC] [NAME]')),
4390 "branches":
4393 "branches":
4391 (branches,
4394 (branches,
4392 [('a', 'active', False,
4395 [('a', 'active', False,
4393 _('show only branches that have unmerged heads')),
4396 _('show only branches that have unmerged heads')),
4394 ('c', 'closed', False,
4397 ('c', 'closed', False,
4395 _('show normal and closed branches'))],
4398 _('show normal and closed branches'))],
4396 _('[-ac]')),
4399 _('[-ac]')),
4397 "bundle":
4400 "bundle":
4398 (bundle,
4401 (bundle,
4399 [('f', 'force', None,
4402 [('f', 'force', None,
4400 _('run even when the destination is unrelated')),
4403 _('run even when the destination is unrelated')),
4401 ('r', 'rev', [],
4404 ('r', 'rev', [],
4402 _('a changeset intended to be added to the destination'),
4405 _('a changeset intended to be added to the destination'),
4403 _('REV')),
4406 _('REV')),
4404 ('b', 'branch', [],
4407 ('b', 'branch', [],
4405 _('a specific branch you would like to bundle'),
4408 _('a specific branch you would like to bundle'),
4406 _('BRANCH')),
4409 _('BRANCH')),
4407 ('', 'base', [],
4410 ('', 'base', [],
4408 _('a base changeset assumed to be available at the destination'),
4411 _('a base changeset assumed to be available at the destination'),
4409 _('REV')),
4412 _('REV')),
4410 ('a', 'all', None, _('bundle all changesets in the repository')),
4413 ('a', 'all', None, _('bundle all changesets in the repository')),
4411 ('t', 'type', 'bzip2',
4414 ('t', 'type', 'bzip2',
4412 _('bundle compression type to use'), _('TYPE')),
4415 _('bundle compression type to use'), _('TYPE')),
4413 ] + remoteopts,
4416 ] + remoteopts,
4414 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4417 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4415 "cat":
4418 "cat":
4416 (cat,
4419 (cat,
4417 [('o', 'output', '',
4420 [('o', 'output', '',
4418 _('print output to file with formatted name'), _('FORMAT')),
4421 _('print output to file with formatted name'), _('FORMAT')),
4419 ('r', 'rev', '',
4422 ('r', 'rev', '',
4420 _('print the given revision'), _('REV')),
4423 _('print the given revision'), _('REV')),
4421 ('', 'decode', None, _('apply any matching decode filter')),
4424 ('', 'decode', None, _('apply any matching decode filter')),
4422 ] + walkopts,
4425 ] + walkopts,
4423 _('[OPTION]... FILE...')),
4426 _('[OPTION]... FILE...')),
4424 "^clone":
4427 "^clone":
4425 (clone,
4428 (clone,
4426 [('U', 'noupdate', None,
4429 [('U', 'noupdate', None,
4427 _('the clone will include an empty working copy (only a repository)')),
4430 _('the clone will include an empty working copy (only a repository)')),
4428 ('u', 'updaterev', '',
4431 ('u', 'updaterev', '',
4429 _('revision, tag or branch to check out'), _('REV')),
4432 _('revision, tag or branch to check out'), _('REV')),
4430 ('r', 'rev', [],
4433 ('r', 'rev', [],
4431 _('include the specified changeset'), _('REV')),
4434 _('include the specified changeset'), _('REV')),
4432 ('b', 'branch', [],
4435 ('b', 'branch', [],
4433 _('clone only the specified branch'), _('BRANCH')),
4436 _('clone only the specified branch'), _('BRANCH')),
4434 ('', 'pull', None, _('use pull protocol to copy metadata')),
4437 ('', 'pull', None, _('use pull protocol to copy metadata')),
4435 ('', 'uncompressed', None,
4438 ('', 'uncompressed', None,
4436 _('use uncompressed transfer (fast over LAN)')),
4439 _('use uncompressed transfer (fast over LAN)')),
4437 ] + remoteopts,
4440 ] + remoteopts,
4438 _('[OPTION]... SOURCE [DEST]')),
4441 _('[OPTION]... SOURCE [DEST]')),
4439 "^commit|ci":
4442 "^commit|ci":
4440 (commit,
4443 (commit,
4441 [('A', 'addremove', None,
4444 [('A', 'addremove', None,
4442 _('mark new/missing files as added/removed before committing')),
4445 _('mark new/missing files as added/removed before committing')),
4443 ('', 'close-branch', None,
4446 ('', 'close-branch', None,
4444 _('mark a branch as closed, hiding it from the branch list')),
4447 _('mark a branch as closed, hiding it from the branch list')),
4445 ] + walkopts + commitopts + commitopts2,
4448 ] + walkopts + commitopts + commitopts2,
4446 _('[OPTION]... [FILE]...')),
4449 _('[OPTION]... [FILE]...')),
4447 "copy|cp":
4450 "copy|cp":
4448 (copy,
4451 (copy,
4449 [('A', 'after', None, _('record a copy that has already occurred')),
4452 [('A', 'after', None, _('record a copy that has already occurred')),
4450 ('f', 'force', None,
4453 ('f', 'force', None,
4451 _('forcibly copy over an existing managed file')),
4454 _('forcibly copy over an existing managed file')),
4452 ] + walkopts + dryrunopts,
4455 ] + walkopts + dryrunopts,
4453 _('[OPTION]... [SOURCE]... DEST')),
4456 _('[OPTION]... [SOURCE]... DEST')),
4454 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4457 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4455 "debugbuilddag":
4458 "debugbuilddag":
4456 (debugbuilddag,
4459 (debugbuilddag,
4457 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4460 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4458 ('a', 'appended-file', None, _('add single file all revs append to')),
4461 ('a', 'appended-file', None, _('add single file all revs append to')),
4459 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4462 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4460 ('n', 'new-file', None, _('add new file at each rev')),
4463 ('n', 'new-file', None, _('add new file at each rev')),
4461 ],
4464 ],
4462 _('[OPTION]... TEXT')),
4465 _('[OPTION]... TEXT')),
4463 "debugbundle":
4466 "debugbundle":
4464 (debugbundle,
4467 (debugbundle,
4465 [('a', 'all', None, _('show all details')),
4468 [('a', 'all', None, _('show all details')),
4466 ],
4469 ],
4467 _('FILE')),
4470 _('FILE')),
4468 "debugcheckstate": (debugcheckstate, [], ''),
4471 "debugcheckstate": (debugcheckstate, [], ''),
4469 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4472 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4470 "debugcomplete":
4473 "debugcomplete":
4471 (debugcomplete,
4474 (debugcomplete,
4472 [('o', 'options', None, _('show the command options'))],
4475 [('o', 'options', None, _('show the command options'))],
4473 _('[-o] CMD')),
4476 _('[-o] CMD')),
4474 "debugdag":
4477 "debugdag":
4475 (debugdag,
4478 (debugdag,
4476 [('t', 'tags', None, _('use tags as labels')),
4479 [('t', 'tags', None, _('use tags as labels')),
4477 ('b', 'branches', None, _('annotate with branch names')),
4480 ('b', 'branches', None, _('annotate with branch names')),
4478 ('', 'dots', None, _('use dots for runs')),
4481 ('', 'dots', None, _('use dots for runs')),
4479 ('s', 'spaces', None, _('separate elements by spaces')),
4482 ('s', 'spaces', None, _('separate elements by spaces')),
4480 ],
4483 ],
4481 _('[OPTION]... [FILE [REV]...]')),
4484 _('[OPTION]... [FILE [REV]...]')),
4482 "debugdate":
4485 "debugdate":
4483 (debugdate,
4486 (debugdate,
4484 [('e', 'extended', None, _('try extended date formats'))],
4487 [('e', 'extended', None, _('try extended date formats'))],
4485 _('[-e] DATE [RANGE]')),
4488 _('[-e] DATE [RANGE]')),
4486 "debugdata": (debugdata, [], _('FILE REV')),
4489 "debugdata": (debugdata, [], _('FILE REV')),
4487 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4490 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4488 "debuggetbundle":
4491 "debuggetbundle":
4489 (debuggetbundle,
4492 (debuggetbundle,
4490 [('H', 'head', [], _('id of head node'), _('ID')),
4493 [('H', 'head', [], _('id of head node'), _('ID')),
4491 ('C', 'common', [], _('id of common node'), _('ID')),
4494 ('C', 'common', [], _('id of common node'), _('ID')),
4492 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
4495 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
4493 ],
4496 ],
4494 _('REPO FILE [-H|-C ID]...')),
4497 _('REPO FILE [-H|-C ID]...')),
4495 "debugignore": (debugignore, [], ''),
4498 "debugignore": (debugignore, [], ''),
4496 "debugindex": (debugindex,
4499 "debugindex": (debugindex,
4497 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4500 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4498 _('FILE')),
4501 _('FILE')),
4499 "debugindexdot": (debugindexdot, [], _('FILE')),
4502 "debugindexdot": (debugindexdot, [], _('FILE')),
4500 "debuginstall": (debuginstall, [], ''),
4503 "debuginstall": (debuginstall, [], ''),
4501 "debugknown": (debugknown, [], _('REPO ID...')),
4504 "debugknown": (debugknown, [], _('REPO ID...')),
4502 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4505 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4503 "debugrebuildstate":
4506 "debugrebuildstate":
4504 (debugrebuildstate,
4507 (debugrebuildstate,
4505 [('r', 'rev', '',
4508 [('r', 'rev', '',
4506 _('revision to rebuild to'), _('REV'))],
4509 _('revision to rebuild to'), _('REV'))],
4507 _('[-r REV] [REV]')),
4510 _('[-r REV] [REV]')),
4508 "debugrename":
4511 "debugrename":
4509 (debugrename,
4512 (debugrename,
4510 [('r', 'rev', '',
4513 [('r', 'rev', '',
4511 _('revision to debug'), _('REV'))],
4514 _('revision to debug'), _('REV'))],
4512 _('[-r REV] FILE')),
4515 _('[-r REV] FILE')),
4513 "debugrevspec":
4516 "debugrevspec":
4514 (debugrevspec, [], ('REVSPEC')),
4517 (debugrevspec, [], ('REVSPEC')),
4515 "debugsetparents":
4518 "debugsetparents":
4516 (debugsetparents, [], _('REV1 [REV2]')),
4519 (debugsetparents, [], _('REV1 [REV2]')),
4517 "debugstate":
4520 "debugstate":
4518 (debugstate,
4521 (debugstate,
4519 [('', 'nodates', None, _('do not display the saved mtime')),
4522 [('', 'nodates', None, _('do not display the saved mtime')),
4520 ('', 'datesort', None, _('sort by saved mtime'))],
4523 ('', 'datesort', None, _('sort by saved mtime'))],
4521 _('[OPTION]...')),
4524 _('[OPTION]...')),
4522 "debugsub":
4525 "debugsub":
4523 (debugsub,
4526 (debugsub,
4524 [('r', 'rev', '',
4527 [('r', 'rev', '',
4525 _('revision to check'), _('REV'))],
4528 _('revision to check'), _('REV'))],
4526 _('[-r REV] [REV]')),
4529 _('[-r REV] [REV]')),
4527 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4530 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4528 "debugwireargs":
4531 "debugwireargs":
4529 (debugwireargs,
4532 (debugwireargs,
4530 [('', 'three', '', 'three'),
4533 [('', 'three', '', 'three'),
4531 ('', 'four', '', 'four'),
4534 ('', 'four', '', 'four'),
4532 ('', 'five', '', 'five'),
4535 ('', 'five', '', 'five'),
4533 ] + remoteopts,
4536 ] + remoteopts,
4534 _('REPO [OPTIONS]... [ONE [TWO]]')),
4537 _('REPO [OPTIONS]... [ONE [TWO]]')),
4535 "^diff":
4538 "^diff":
4536 (diff,
4539 (diff,
4537 [('r', 'rev', [],
4540 [('r', 'rev', [],
4538 _('revision'), _('REV')),
4541 _('revision'), _('REV')),
4539 ('c', 'change', '',
4542 ('c', 'change', '',
4540 _('change made by revision'), _('REV'))
4543 _('change made by revision'), _('REV'))
4541 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4544 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4542 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4545 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4543 "^export":
4546 "^export":
4544 (export,
4547 (export,
4545 [('o', 'output', '',
4548 [('o', 'output', '',
4546 _('print output to file with formatted name'), _('FORMAT')),
4549 _('print output to file with formatted name'), _('FORMAT')),
4547 ('', 'switch-parent', None, _('diff against the second parent')),
4550 ('', 'switch-parent', None, _('diff against the second parent')),
4548 ('r', 'rev', [],
4551 ('r', 'rev', [],
4549 _('revisions to export'), _('REV')),
4552 _('revisions to export'), _('REV')),
4550 ] + diffopts,
4553 ] + diffopts,
4551 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4554 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4552 "^forget":
4555 "^forget":
4553 (forget,
4556 (forget,
4554 [] + walkopts,
4557 [] + walkopts,
4555 _('[OPTION]... FILE...')),
4558 _('[OPTION]... FILE...')),
4556 "grep":
4559 "grep":
4557 (grep,
4560 (grep,
4558 [('0', 'print0', None, _('end fields with NUL')),
4561 [('0', 'print0', None, _('end fields with NUL')),
4559 ('', 'all', None, _('print all revisions that match')),
4562 ('', 'all', None, _('print all revisions that match')),
4560 ('a', 'text', None, _('treat all files as text')),
4563 ('a', 'text', None, _('treat all files as text')),
4561 ('f', 'follow', None,
4564 ('f', 'follow', None,
4562 _('follow changeset history,'
4565 _('follow changeset history,'
4563 ' or file history across copies and renames')),
4566 ' or file history across copies and renames')),
4564 ('i', 'ignore-case', None, _('ignore case when matching')),
4567 ('i', 'ignore-case', None, _('ignore case when matching')),
4565 ('l', 'files-with-matches', None,
4568 ('l', 'files-with-matches', None,
4566 _('print only filenames and revisions that match')),
4569 _('print only filenames and revisions that match')),
4567 ('n', 'line-number', None, _('print matching line numbers')),
4570 ('n', 'line-number', None, _('print matching line numbers')),
4568 ('r', 'rev', [],
4571 ('r', 'rev', [],
4569 _('only search files changed within revision range'), _('REV')),
4572 _('only search files changed within revision range'), _('REV')),
4570 ('u', 'user', None, _('list the author (long with -v)')),
4573 ('u', 'user', None, _('list the author (long with -v)')),
4571 ('d', 'date', None, _('list the date (short with -q)')),
4574 ('d', 'date', None, _('list the date (short with -q)')),
4572 ] + walkopts,
4575 ] + walkopts,
4573 _('[OPTION]... PATTERN [FILE]...')),
4576 _('[OPTION]... PATTERN [FILE]...')),
4574 "heads":
4577 "heads":
4575 (heads,
4578 (heads,
4576 [('r', 'rev', '',
4579 [('r', 'rev', '',
4577 _('show only heads which are descendants of STARTREV'),
4580 _('show only heads which are descendants of STARTREV'),
4578 _('STARTREV')),
4581 _('STARTREV')),
4579 ('t', 'topo', False, _('show topological heads only')),
4582 ('t', 'topo', False, _('show topological heads only')),
4580 ('a', 'active', False,
4583 ('a', 'active', False,
4581 _('show active branchheads only (DEPRECATED)')),
4584 _('show active branchheads only (DEPRECATED)')),
4582 ('c', 'closed', False,
4585 ('c', 'closed', False,
4583 _('show normal and closed branch heads')),
4586 _('show normal and closed branch heads')),
4584 ] + templateopts,
4587 ] + templateopts,
4585 _('[-ac] [-r STARTREV] [REV]...')),
4588 _('[-ac] [-r STARTREV] [REV]...')),
4586 "help": (help_, [], _('[TOPIC]')),
4589 "help": (help_, [], _('[TOPIC]')),
4587 "identify|id":
4590 "identify|id":
4588 (identify,
4591 (identify,
4589 [('r', 'rev', '',
4592 [('r', 'rev', '',
4590 _('identify the specified revision'), _('REV')),
4593 _('identify the specified revision'), _('REV')),
4591 ('n', 'num', None, _('show local revision number')),
4594 ('n', 'num', None, _('show local revision number')),
4592 ('i', 'id', None, _('show global revision id')),
4595 ('i', 'id', None, _('show global revision id')),
4593 ('b', 'branch', None, _('show branch')),
4596 ('b', 'branch', None, _('show branch')),
4594 ('t', 'tags', None, _('show tags')),
4597 ('t', 'tags', None, _('show tags')),
4595 ('B', 'bookmarks', None, _('show bookmarks'))],
4598 ('B', 'bookmarks', None, _('show bookmarks'))],
4596 _('[-nibtB] [-r REV] [SOURCE]')),
4599 _('[-nibtB] [-r REV] [SOURCE]')),
4597 "import|patch":
4600 "import|patch":
4598 (import_,
4601 (import_,
4599 [('p', 'strip', 1,
4602 [('p', 'strip', 1,
4600 _('directory strip option for patch. This has the same '
4603 _('directory strip option for patch. This has the same '
4601 'meaning as the corresponding patch option'),
4604 'meaning as the corresponding patch option'),
4602 _('NUM')),
4605 _('NUM')),
4603 ('b', 'base', '',
4606 ('b', 'base', '',
4604 _('base path'), _('PATH')),
4607 _('base path'), _('PATH')),
4605 ('f', 'force', None,
4608 ('f', 'force', None,
4606 _('skip check for outstanding uncommitted changes')),
4609 _('skip check for outstanding uncommitted changes')),
4607 ('', 'no-commit', None,
4610 ('', 'no-commit', None,
4608 _("don't commit, just update the working directory")),
4611 _("don't commit, just update the working directory")),
4609 ('', 'exact', None,
4612 ('', 'exact', None,
4610 _('apply patch to the nodes from which it was generated')),
4613 _('apply patch to the nodes from which it was generated')),
4611 ('', 'import-branch', None,
4614 ('', 'import-branch', None,
4612 _('use any branch information in patch (implied by --exact)'))] +
4615 _('use any branch information in patch (implied by --exact)'))] +
4613 commitopts + commitopts2 + similarityopts,
4616 commitopts + commitopts2 + similarityopts,
4614 _('[OPTION]... PATCH...')),
4617 _('[OPTION]... PATCH...')),
4615 "incoming|in":
4618 "incoming|in":
4616 (incoming,
4619 (incoming,
4617 [('f', 'force', None,
4620 [('f', 'force', None,
4618 _('run even if remote repository is unrelated')),
4621 _('run even if remote repository is unrelated')),
4619 ('n', 'newest-first', None, _('show newest record first')),
4622 ('n', 'newest-first', None, _('show newest record first')),
4620 ('', 'bundle', '',
4623 ('', 'bundle', '',
4621 _('file to store the bundles into'), _('FILE')),
4624 _('file to store the bundles into'), _('FILE')),
4622 ('r', 'rev', [],
4625 ('r', 'rev', [],
4623 _('a remote changeset intended to be added'), _('REV')),
4626 _('a remote changeset intended to be added'), _('REV')),
4624 ('B', 'bookmarks', False, _("compare bookmarks")),
4627 ('B', 'bookmarks', False, _("compare bookmarks")),
4625 ('b', 'branch', [],
4628 ('b', 'branch', [],
4626 _('a specific branch you would like to pull'), _('BRANCH')),
4629 _('a specific branch you would like to pull'), _('BRANCH')),
4627 ] + logopts + remoteopts + subrepoopts,
4630 ] + logopts + remoteopts + subrepoopts,
4628 _('[-p] [-n] [-M] [-f] [-r REV]...'
4631 _('[-p] [-n] [-M] [-f] [-r REV]...'
4629 ' [--bundle FILENAME] [SOURCE]')),
4632 ' [--bundle FILENAME] [SOURCE]')),
4630 "^init":
4633 "^init":
4631 (init,
4634 (init,
4632 remoteopts,
4635 remoteopts,
4633 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4636 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4634 "locate":
4637 "locate":
4635 (locate,
4638 (locate,
4636 [('r', 'rev', '',
4639 [('r', 'rev', '',
4637 _('search the repository as it is in REV'), _('REV')),
4640 _('search the repository as it is in REV'), _('REV')),
4638 ('0', 'print0', None,
4641 ('0', 'print0', None,
4639 _('end filenames with NUL, for use with xargs')),
4642 _('end filenames with NUL, for use with xargs')),
4640 ('f', 'fullpath', None,
4643 ('f', 'fullpath', None,
4641 _('print complete paths from the filesystem root')),
4644 _('print complete paths from the filesystem root')),
4642 ] + walkopts,
4645 ] + walkopts,
4643 _('[OPTION]... [PATTERN]...')),
4646 _('[OPTION]... [PATTERN]...')),
4644 "^log|history":
4647 "^log|history":
4645 (log,
4648 (log,
4646 [('f', 'follow', None,
4649 [('f', 'follow', None,
4647 _('follow changeset history,'
4650 _('follow changeset history,'
4648 ' or file history across copies and renames')),
4651 ' or file history across copies and renames')),
4649 ('', 'follow-first', None,
4652 ('', 'follow-first', None,
4650 _('only follow the first parent of merge changesets')),
4653 _('only follow the first parent of merge changesets')),
4651 ('d', 'date', '',
4654 ('d', 'date', '',
4652 _('show revisions matching date spec'), _('DATE')),
4655 _('show revisions matching date spec'), _('DATE')),
4653 ('C', 'copies', None, _('show copied files')),
4656 ('C', 'copies', None, _('show copied files')),
4654 ('k', 'keyword', [],
4657 ('k', 'keyword', [],
4655 _('do case-insensitive search for a given text'), _('TEXT')),
4658 _('do case-insensitive search for a given text'), _('TEXT')),
4656 ('r', 'rev', [],
4659 ('r', 'rev', [],
4657 _('show the specified revision or range'), _('REV')),
4660 _('show the specified revision or range'), _('REV')),
4658 ('', 'removed', None, _('include revisions where files were removed')),
4661 ('', 'removed', None, _('include revisions where files were removed')),
4659 ('m', 'only-merges', None, _('show only merges')),
4662 ('m', 'only-merges', None, _('show only merges')),
4660 ('u', 'user', [],
4663 ('u', 'user', [],
4661 _('revisions committed by user'), _('USER')),
4664 _('revisions committed by user'), _('USER')),
4662 ('', 'only-branch', [],
4665 ('', 'only-branch', [],
4663 _('show only changesets within the given named branch (DEPRECATED)'),
4666 _('show only changesets within the given named branch (DEPRECATED)'),
4664 _('BRANCH')),
4667 _('BRANCH')),
4665 ('b', 'branch', [],
4668 ('b', 'branch', [],
4666 _('show changesets within the given named branch'), _('BRANCH')),
4669 _('show changesets within the given named branch'), _('BRANCH')),
4667 ('P', 'prune', [],
4670 ('P', 'prune', [],
4668 _('do not display revision or any of its ancestors'), _('REV')),
4671 _('do not display revision or any of its ancestors'), _('REV')),
4669 ] + logopts + walkopts,
4672 ] + logopts + walkopts,
4670 _('[OPTION]... [FILE]')),
4673 _('[OPTION]... [FILE]')),
4671 "manifest":
4674 "manifest":
4672 (manifest,
4675 (manifest,
4673 [('r', 'rev', '',
4676 [('r', 'rev', '',
4674 _('revision to display'), _('REV'))],
4677 _('revision to display'), _('REV'))],
4675 _('[-r REV]')),
4678 _('[-r REV]')),
4676 "^merge":
4679 "^merge":
4677 (merge,
4680 (merge,
4678 [('f', 'force', None, _('force a merge with outstanding changes')),
4681 [('f', 'force', None, _('force a merge with outstanding changes')),
4679 ('t', 'tool', '', _('specify merge tool')),
4682 ('t', 'tool', '', _('specify merge tool')),
4680 ('r', 'rev', '',
4683 ('r', 'rev', '',
4681 _('revision to merge'), _('REV')),
4684 _('revision to merge'), _('REV')),
4682 ('P', 'preview', None,
4685 ('P', 'preview', None,
4683 _('review revisions to merge (no merge is performed)'))],
4686 _('review revisions to merge (no merge is performed)'))],
4684 _('[-P] [-f] [[-r] REV]')),
4687 _('[-P] [-f] [[-r] REV]')),
4685 "outgoing|out":
4688 "outgoing|out":
4686 (outgoing,
4689 (outgoing,
4687 [('f', 'force', None,
4690 [('f', 'force', None,
4688 _('run even when the destination is unrelated')),
4691 _('run even when the destination is unrelated')),
4689 ('r', 'rev', [],
4692 ('r', 'rev', [],
4690 _('a changeset intended to be included in the destination'),
4693 _('a changeset intended to be included in the destination'),
4691 _('REV')),
4694 _('REV')),
4692 ('n', 'newest-first', None, _('show newest record first')),
4695 ('n', 'newest-first', None, _('show newest record first')),
4693 ('B', 'bookmarks', False, _("compare bookmarks")),
4696 ('B', 'bookmarks', False, _("compare bookmarks")),
4694 ('b', 'branch', [],
4697 ('b', 'branch', [],
4695 _('a specific branch you would like to push'), _('BRANCH')),
4698 _('a specific branch you would like to push'), _('BRANCH')),
4696 ] + logopts + remoteopts + subrepoopts,
4699 ] + logopts + remoteopts + subrepoopts,
4697 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4700 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4698 "parents":
4701 "parents":
4699 (parents,
4702 (parents,
4700 [('r', 'rev', '',
4703 [('r', 'rev', '',
4701 _('show parents of the specified revision'), _('REV')),
4704 _('show parents of the specified revision'), _('REV')),
4702 ] + templateopts,
4705 ] + templateopts,
4703 _('[-r REV] [FILE]')),
4706 _('[-r REV] [FILE]')),
4704 "paths": (paths, [], _('[NAME]')),
4707 "paths": (paths, [], _('[NAME]')),
4705 "^pull":
4708 "^pull":
4706 (pull,
4709 (pull,
4707 [('u', 'update', None,
4710 [('u', 'update', None,
4708 _('update to new branch head if changesets were pulled')),
4711 _('update to new branch head if changesets were pulled')),
4709 ('f', 'force', None,
4712 ('f', 'force', None,
4710 _('run even when remote repository is unrelated')),
4713 _('run even when remote repository is unrelated')),
4711 ('r', 'rev', [],
4714 ('r', 'rev', [],
4712 _('a remote changeset intended to be added'), _('REV')),
4715 _('a remote changeset intended to be added'), _('REV')),
4713 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4716 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4714 ('b', 'branch', [],
4717 ('b', 'branch', [],
4715 _('a specific branch you would like to pull'), _('BRANCH')),
4718 _('a specific branch you would like to pull'), _('BRANCH')),
4716 ] + remoteopts,
4719 ] + remoteopts,
4717 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4720 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4718 "^push":
4721 "^push":
4719 (push,
4722 (push,
4720 [('f', 'force', None, _('force push')),
4723 [('f', 'force', None, _('force push')),
4721 ('r', 'rev', [],
4724 ('r', 'rev', [],
4722 _('a changeset intended to be included in the destination'),
4725 _('a changeset intended to be included in the destination'),
4723 _('REV')),
4726 _('REV')),
4724 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4727 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4725 ('b', 'branch', [],
4728 ('b', 'branch', [],
4726 _('a specific branch you would like to push'), _('BRANCH')),
4729 _('a specific branch you would like to push'), _('BRANCH')),
4727 ('', 'new-branch', False, _('allow pushing a new branch')),
4730 ('', 'new-branch', False, _('allow pushing a new branch')),
4728 ] + remoteopts,
4731 ] + remoteopts,
4729 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4732 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4730 "recover": (recover, []),
4733 "recover": (recover, []),
4731 "^remove|rm":
4734 "^remove|rm":
4732 (remove,
4735 (remove,
4733 [('A', 'after', None, _('record delete for missing files')),
4736 [('A', 'after', None, _('record delete for missing files')),
4734 ('f', 'force', None,
4737 ('f', 'force', None,
4735 _('remove (and delete) file even if added or modified')),
4738 _('remove (and delete) file even if added or modified')),
4736 ] + walkopts,
4739 ] + walkopts,
4737 _('[OPTION]... FILE...')),
4740 _('[OPTION]... FILE...')),
4738 "rename|move|mv":
4741 "rename|move|mv":
4739 (rename,
4742 (rename,
4740 [('A', 'after', None, _('record a rename that has already occurred')),
4743 [('A', 'after', None, _('record a rename that has already occurred')),
4741 ('f', 'force', None,
4744 ('f', 'force', None,
4742 _('forcibly copy over an existing managed file')),
4745 _('forcibly copy over an existing managed file')),
4743 ] + walkopts + dryrunopts,
4746 ] + walkopts + dryrunopts,
4744 _('[OPTION]... SOURCE... DEST')),
4747 _('[OPTION]... SOURCE... DEST')),
4745 "resolve":
4748 "resolve":
4746 (resolve,
4749 (resolve,
4747 [('a', 'all', None, _('select all unresolved files')),
4750 [('a', 'all', None, _('select all unresolved files')),
4748 ('l', 'list', None, _('list state of files needing merge')),
4751 ('l', 'list', None, _('list state of files needing merge')),
4749 ('m', 'mark', None, _('mark files as resolved')),
4752 ('m', 'mark', None, _('mark files as resolved')),
4750 ('u', 'unmark', None, _('mark files as unresolved')),
4753 ('u', 'unmark', None, _('mark files as unresolved')),
4751 ('t', 'tool', '', _('specify merge tool')),
4754 ('t', 'tool', '', _('specify merge tool')),
4752 ('n', 'no-status', None, _('hide status prefix'))]
4755 ('n', 'no-status', None, _('hide status prefix'))]
4753 + walkopts,
4756 + walkopts,
4754 _('[OPTION]... [FILE]...')),
4757 _('[OPTION]... [FILE]...')),
4755 "revert":
4758 "revert":
4756 (revert,
4759 (revert,
4757 [('a', 'all', None, _('revert all changes when no arguments given')),
4760 [('a', 'all', None, _('revert all changes when no arguments given')),
4758 ('d', 'date', '',
4761 ('d', 'date', '',
4759 _('tipmost revision matching date'), _('DATE')),
4762 _('tipmost revision matching date'), _('DATE')),
4760 ('r', 'rev', '',
4763 ('r', 'rev', '',
4761 _('revert to the specified revision'), _('REV')),
4764 _('revert to the specified revision'), _('REV')),
4762 ('', 'no-backup', None, _('do not save backup copies of files')),
4765 ('', 'no-backup', None, _('do not save backup copies of files')),
4763 ] + walkopts + dryrunopts,
4766 ] + walkopts + dryrunopts,
4764 _('[OPTION]... [-r REV] [NAME]...')),
4767 _('[OPTION]... [-r REV] [NAME]...')),
4765 "rollback": (rollback, dryrunopts),
4768 "rollback": (rollback, dryrunopts),
4766 "root": (root, []),
4769 "root": (root, []),
4767 "^serve":
4770 "^serve":
4768 (serve,
4771 (serve,
4769 [('A', 'accesslog', '',
4772 [('A', 'accesslog', '',
4770 _('name of access log file to write to'), _('FILE')),
4773 _('name of access log file to write to'), _('FILE')),
4771 ('d', 'daemon', None, _('run server in background')),
4774 ('d', 'daemon', None, _('run server in background')),
4772 ('', 'daemon-pipefds', '',
4775 ('', 'daemon-pipefds', '',
4773 _('used internally by daemon mode'), _('NUM')),
4776 _('used internally by daemon mode'), _('NUM')),
4774 ('E', 'errorlog', '',
4777 ('E', 'errorlog', '',
4775 _('name of error log file to write to'), _('FILE')),
4778 _('name of error log file to write to'), _('FILE')),
4776 # use string type, then we can check if something was passed
4779 # use string type, then we can check if something was passed
4777 ('p', 'port', '',
4780 ('p', 'port', '',
4778 _('port to listen on (default: 8000)'), _('PORT')),
4781 _('port to listen on (default: 8000)'), _('PORT')),
4779 ('a', 'address', '',
4782 ('a', 'address', '',
4780 _('address to listen on (default: all interfaces)'), _('ADDR')),
4783 _('address to listen on (default: all interfaces)'), _('ADDR')),
4781 ('', 'prefix', '',
4784 ('', 'prefix', '',
4782 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4785 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4783 ('n', 'name', '',
4786 ('n', 'name', '',
4784 _('name to show in web pages (default: working directory)'),
4787 _('name to show in web pages (default: working directory)'),
4785 _('NAME')),
4788 _('NAME')),
4786 ('', 'web-conf', '',
4789 ('', 'web-conf', '',
4787 _('name of the hgweb config file (see "hg help hgweb")'),
4790 _('name of the hgweb config file (see "hg help hgweb")'),
4788 _('FILE')),
4791 _('FILE')),
4789 ('', 'webdir-conf', '',
4792 ('', 'webdir-conf', '',
4790 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4793 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4791 ('', 'pid-file', '',
4794 ('', 'pid-file', '',
4792 _('name of file to write process ID to'), _('FILE')),
4795 _('name of file to write process ID to'), _('FILE')),
4793 ('', 'stdio', None, _('for remote clients')),
4796 ('', 'stdio', None, _('for remote clients')),
4794 ('t', 'templates', '',
4797 ('t', 'templates', '',
4795 _('web templates to use'), _('TEMPLATE')),
4798 _('web templates to use'), _('TEMPLATE')),
4796 ('', 'style', '',
4799 ('', 'style', '',
4797 _('template style to use'), _('STYLE')),
4800 _('template style to use'), _('STYLE')),
4798 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4801 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4799 ('', 'certificate', '',
4802 ('', 'certificate', '',
4800 _('SSL certificate file'), _('FILE'))],
4803 _('SSL certificate file'), _('FILE'))],
4801 _('[OPTION]...')),
4804 _('[OPTION]...')),
4802 "showconfig|debugconfig":
4805 "showconfig|debugconfig":
4803 (showconfig,
4806 (showconfig,
4804 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4807 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4805 _('[-u] [NAME]...')),
4808 _('[-u] [NAME]...')),
4806 "^summary|sum":
4809 "^summary|sum":
4807 (summary,
4810 (summary,
4808 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4811 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4809 "^status|st":
4812 "^status|st":
4810 (status,
4813 (status,
4811 [('A', 'all', None, _('show status of all files')),
4814 [('A', 'all', None, _('show status of all files')),
4812 ('m', 'modified', None, _('show only modified files')),
4815 ('m', 'modified', None, _('show only modified files')),
4813 ('a', 'added', None, _('show only added files')),
4816 ('a', 'added', None, _('show only added files')),
4814 ('r', 'removed', None, _('show only removed files')),
4817 ('r', 'removed', None, _('show only removed files')),
4815 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4818 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4816 ('c', 'clean', None, _('show only files without changes')),
4819 ('c', 'clean', None, _('show only files without changes')),
4817 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4820 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4818 ('i', 'ignored', None, _('show only ignored files')),
4821 ('i', 'ignored', None, _('show only ignored files')),
4819 ('n', 'no-status', None, _('hide status prefix')),
4822 ('n', 'no-status', None, _('hide status prefix')),
4820 ('C', 'copies', None, _('show source of copied files')),
4823 ('C', 'copies', None, _('show source of copied files')),
4821 ('0', 'print0', None,
4824 ('0', 'print0', None,
4822 _('end filenames with NUL, for use with xargs')),
4825 _('end filenames with NUL, for use with xargs')),
4823 ('', 'rev', [],
4826 ('', 'rev', [],
4824 _('show difference from revision'), _('REV')),
4827 _('show difference from revision'), _('REV')),
4825 ('', 'change', '',
4828 ('', 'change', '',
4826 _('list the changed files of a revision'), _('REV')),
4829 _('list the changed files of a revision'), _('REV')),
4827 ] + walkopts + subrepoopts,
4830 ] + walkopts + subrepoopts,
4828 _('[OPTION]... [FILE]...')),
4831 _('[OPTION]... [FILE]...')),
4829 "tag":
4832 "tag":
4830 (tag,
4833 (tag,
4831 [('f', 'force', None, _('force tag')),
4834 [('f', 'force', None, _('force tag')),
4832 ('l', 'local', None, _('make the tag local')),
4835 ('l', 'local', None, _('make the tag local')),
4833 ('r', 'rev', '',
4836 ('r', 'rev', '',
4834 _('revision to tag'), _('REV')),
4837 _('revision to tag'), _('REV')),
4835 ('', 'remove', None, _('remove a tag')),
4838 ('', 'remove', None, _('remove a tag')),
4836 # -l/--local is already there, commitopts cannot be used
4839 # -l/--local is already there, commitopts cannot be used
4837 ('e', 'edit', None, _('edit commit message')),
4840 ('e', 'edit', None, _('edit commit message')),
4838 ('m', 'message', '',
4841 ('m', 'message', '',
4839 _('use <text> as commit message'), _('TEXT')),
4842 _('use <text> as commit message'), _('TEXT')),
4840 ] + commitopts2,
4843 ] + commitopts2,
4841 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4844 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4842 "tags": (tags, [], ''),
4845 "tags": (tags, [], ''),
4843 "tip":
4846 "tip":
4844 (tip,
4847 (tip,
4845 [('p', 'patch', None, _('show patch')),
4848 [('p', 'patch', None, _('show patch')),
4846 ('g', 'git', None, _('use git extended diff format')),
4849 ('g', 'git', None, _('use git extended diff format')),
4847 ] + templateopts,
4850 ] + templateopts,
4848 _('[-p] [-g]')),
4851 _('[-p] [-g]')),
4849 "unbundle":
4852 "unbundle":
4850 (unbundle,
4853 (unbundle,
4851 [('u', 'update', None,
4854 [('u', 'update', None,
4852 _('update to new branch head if changesets were unbundled'))],
4855 _('update to new branch head if changesets were unbundled'))],
4853 _('[-u] FILE...')),
4856 _('[-u] FILE...')),
4854 "^update|up|checkout|co":
4857 "^update|up|checkout|co":
4855 (update,
4858 (update,
4856 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4859 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4857 ('c', 'check', None,
4860 ('c', 'check', None,
4858 _('update across branches if no uncommitted changes')),
4861 _('update across branches if no uncommitted changes')),
4859 ('d', 'date', '',
4862 ('d', 'date', '',
4860 _('tipmost revision matching date'), _('DATE')),
4863 _('tipmost revision matching date'), _('DATE')),
4861 ('r', 'rev', '',
4864 ('r', 'rev', '',
4862 _('revision'), _('REV'))],
4865 _('revision'), _('REV'))],
4863 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4866 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4864 "verify": (verify, []),
4867 "verify": (verify, []),
4865 "version": (version_, []),
4868 "version": (version_, []),
4866 }
4869 }
4867
4870
4868 norepo = ("clone init version help debugcommands debugcomplete"
4871 norepo = ("clone init version help debugcommands debugcomplete"
4869 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
4872 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
4870 " debugknown debuggetbundle debugbundle")
4873 " debugknown debuggetbundle debugbundle")
4871 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4874 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4872 " debugdata debugindex debugindexdot")
4875 " debugdata debugindex debugindexdot")
@@ -1,101 +1,121
1 Mercurial supports a functional language for selecting a set of
1 Mercurial supports a functional language for selecting a set of
2 revisions.
2 revisions.
3
3
4 The language supports a number of predicates which are joined by infix
4 The language supports a number of predicates which are joined by infix
5 operators. Parenthesis can be used for grouping.
5 operators. Parenthesis can be used for grouping.
6
6
7 Identifiers such as branch names must be quoted with single or double
7 Identifiers such as branch names must be quoted with single or double
8 quotes if they contain characters outside of
8 quotes if they contain characters outside of
9 ``[._a-zA-Z0-9\x80-\xff]`` or if they match one of the predefined
9 ``[._a-zA-Z0-9\x80-\xff]`` or if they match one of the predefined
10 predicates.
10 predicates.
11
11
12 Special characters can be used in quoted identifiers by escaping them,
12 Special characters can be used in quoted identifiers by escaping them,
13 e.g., ``\n`` is interpreted as a newline. To prevent them from being
13 e.g., ``\n`` is interpreted as a newline. To prevent them from being
14 interpreted, strings can be prefixed with ``r``, e.g. ``r'...'``.
14 interpreted, strings can be prefixed with ``r``, e.g. ``r'...'``.
15
15
16 There is a single prefix operator:
16 There is a single prefix operator:
17
17
18 ``not x``
18 ``not x``
19 Changesets not in x. Short form is ``! x``.
19 Changesets not in x. Short form is ``! x``.
20
20
21 These are the supported infix operators:
21 These are the supported infix operators:
22
22
23 ``x::y``
23 ``x::y``
24 A DAG range, meaning all changesets that are descendants of x and
24 A DAG range, meaning all changesets that are descendants of x and
25 ancestors of y, including x and y themselves. If the first endpoint
25 ancestors of y, including x and y themselves. If the first endpoint
26 is left out, this is equivalent to ``ancestors(y)``, if the second
26 is left out, this is equivalent to ``ancestors(y)``, if the second
27 is left out it is equivalent to ``descendants(x)``.
27 is left out it is equivalent to ``descendants(x)``.
28
28
29 An alternative syntax is ``x..y``.
29 An alternative syntax is ``x..y``.
30
30
31 ``x:y``
31 ``x:y``
32 All changesets with revision numbers between x and y, both
32 All changesets with revision numbers between x and y, both
33 inclusive. Either endpoint can be left out, they default to 0 and
33 inclusive. Either endpoint can be left out, they default to 0 and
34 tip.
34 tip.
35
35
36 ``x and y``
36 ``x and y``
37 The intersection of changesets in x and y. Short form is ``x & y``.
37 The intersection of changesets in x and y. Short form is ``x & y``.
38
38
39 ``x or y``
39 ``x or y``
40 The union of changesets in x and y. There are two alternative short
40 The union of changesets in x and y. There are two alternative short
41 forms: ``x | y`` and ``x + y``.
41 forms: ``x | y`` and ``x + y``.
42
42
43 ``x - y``
43 ``x - y``
44 Changesets in x but not in y.
44 Changesets in x but not in y.
45
45
46 ``x^n``
46 ``x^n``
47 The nth parent of x, n == 0, 1, or 2.
47 The nth parent of x, n == 0, 1, or 2.
48 For n == 0, x; for n == 1, the first parent of each changeset in x;
48 For n == 0, x; for n == 1, the first parent of each changeset in x;
49 for n == 2, the second parent of changeset in x.
49 for n == 2, the second parent of changeset in x.
50
50
51 ``x~n``
51 ``x~n``
52 The nth first ancestor of x; ``x~0`` is x; ``x~3`` is ``x^^^``.
52 The nth first ancestor of x; ``x~0`` is x; ``x~3`` is ``x^^^``.
53
53
54 There is a single postfix operator:
54 There is a single postfix operator:
55
55
56 ``x^``
56 ``x^``
57 Equivalent to ``x^1``, the first parent of each changeset in x.
57 Equivalent to ``x^1``, the first parent of each changeset in x.
58
58
59
59
60 The following predicates are supported:
60 The following predicates are supported:
61
61
62 .. predicatesmarker
62 .. predicatesmarker
63
63
64 New predicates (known as "aliases") can be defined, using any combination of
65 existing predicates or other aliases. An alias definition looks like::
66
67 <alias> = <definition>
68
69 in the ``revsetalias`` section of ``.hgrc``. Arguments of the form `$1`, `$2`,
70 etc. are substituted from the alias into the definition.
71
72 For example,
73
74 ::
75
76 [revsetalias]
77 h = heads()
78 d($1) = sort($1, date)
79 rs($1, $2) = reverse(sort($1, $2))
80
81 defines three aliases, ``h``, ``d``, and ``rs``. ``rs(0:tip, author)`` is
82 exactly equivalent to ``reverse(sort(0:tip, author))``.
83
64 Command line equivalents for :hg:`log`::
84 Command line equivalents for :hg:`log`::
65
85
66 -f -> ::.
86 -f -> ::.
67 -d x -> date(x)
87 -d x -> date(x)
68 -k x -> keyword(x)
88 -k x -> keyword(x)
69 -m -> merge()
89 -m -> merge()
70 -u x -> user(x)
90 -u x -> user(x)
71 -b x -> branch(x)
91 -b x -> branch(x)
72 -P x -> !::x
92 -P x -> !::x
73 -l x -> limit(expr, x)
93 -l x -> limit(expr, x)
74
94
75 Some sample queries:
95 Some sample queries:
76
96
77 - Changesets on the default branch::
97 - Changesets on the default branch::
78
98
79 hg log -r "branch(default)"
99 hg log -r "branch(default)"
80
100
81 - Changesets on the default branch since tag 1.5 (excluding merges)::
101 - Changesets on the default branch since tag 1.5 (excluding merges)::
82
102
83 hg log -r "branch(default) and 1.5:: and not merge()"
103 hg log -r "branch(default) and 1.5:: and not merge()"
84
104
85 - Open branch heads::
105 - Open branch heads::
86
106
87 hg log -r "head() and not closed()"
107 hg log -r "head() and not closed()"
88
108
89 - Changesets between tags 1.3 and 1.5 mentioning "bug" that affect
109 - Changesets between tags 1.3 and 1.5 mentioning "bug" that affect
90 ``hgext/*``::
110 ``hgext/*``::
91
111
92 hg log -r "1.3::1.5 and keyword(bug) and file('hgext/*')"
112 hg log -r "1.3::1.5 and keyword(bug) and file('hgext/*')"
93
113
94 - Changesets committed in May 2008, sorted by user::
114 - Changesets committed in May 2008, sorted by user::
95
115
96 hg log -r "sort(date('May 2008'), user)"
116 hg log -r "sort(date('May 2008'), user)"
97
117
98 - Changesets mentioning "bug" or "issue" that are not in a tagged
118 - Changesets mentioning "bug" or "issue" that are not in a tagged
99 release::
119 release::
100
120
101 hg log -r "(keyword(bug) or keyword(issue)) and not ancestors(tagged())"
121 hg log -r "(keyword(bug) or keyword(issue)) and not ancestors(tagged())"
@@ -1,909 +1,984
1 # revset.py - revision set queries for mercurial
1 # revset.py - revision set queries for mercurial
2 #
2 #
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import re
8 import re
9 import parser, util, error, discovery, help, hbisect
9 import parser, util, error, discovery, help, hbisect
10 import bookmarks as bookmarksmod
10 import bookmarks as bookmarksmod
11 import match as matchmod
11 import match as matchmod
12 from i18n import _
12 from i18n import _
13
13
14 elements = {
14 elements = {
15 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
15 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
16 "~": (18, None, ("ancestor", 18)),
16 "~": (18, None, ("ancestor", 18)),
17 "^": (18, None, ("parent", 18), ("parentpost", 18)),
17 "^": (18, None, ("parent", 18), ("parentpost", 18)),
18 "-": (5, ("negate", 19), ("minus", 5)),
18 "-": (5, ("negate", 19), ("minus", 5)),
19 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
19 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
20 ("dagrangepost", 17)),
20 ("dagrangepost", 17)),
21 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
21 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
22 ("dagrangepost", 17)),
22 ("dagrangepost", 17)),
23 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
23 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
24 "not": (10, ("not", 10)),
24 "not": (10, ("not", 10)),
25 "!": (10, ("not", 10)),
25 "!": (10, ("not", 10)),
26 "and": (5, None, ("and", 5)),
26 "and": (5, None, ("and", 5)),
27 "&": (5, None, ("and", 5)),
27 "&": (5, None, ("and", 5)),
28 "or": (4, None, ("or", 4)),
28 "or": (4, None, ("or", 4)),
29 "|": (4, None, ("or", 4)),
29 "|": (4, None, ("or", 4)),
30 "+": (4, None, ("or", 4)),
30 "+": (4, None, ("or", 4)),
31 ",": (2, None, ("list", 2)),
31 ",": (2, None, ("list", 2)),
32 ")": (0, None, None),
32 ")": (0, None, None),
33 "symbol": (0, ("symbol",), None),
33 "symbol": (0, ("symbol",), None),
34 "string": (0, ("string",), None),
34 "string": (0, ("string",), None),
35 "end": (0, None, None),
35 "end": (0, None, None),
36 }
36 }
37
37
38 keywords = set(['and', 'or', 'not'])
38 keywords = set(['and', 'or', 'not'])
39
39
40 def tokenize(program):
40 def tokenize(program):
41 pos, l = 0, len(program)
41 pos, l = 0, len(program)
42 while pos < l:
42 while pos < l:
43 c = program[pos]
43 c = program[pos]
44 if c.isspace(): # skip inter-token whitespace
44 if c.isspace(): # skip inter-token whitespace
45 pass
45 pass
46 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
46 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
47 yield ('::', None, pos)
47 yield ('::', None, pos)
48 pos += 1 # skip ahead
48 pos += 1 # skip ahead
49 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
49 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
50 yield ('..', None, pos)
50 yield ('..', None, pos)
51 pos += 1 # skip ahead
51 pos += 1 # skip ahead
52 elif c in "():,-|&+!~^": # handle simple operators
52 elif c in "():,-|&+!~^": # handle simple operators
53 yield (c, None, pos)
53 yield (c, None, pos)
54 elif (c in '"\'' or c == 'r' and
54 elif (c in '"\'' or c == 'r' and
55 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
55 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
56 if c == 'r':
56 if c == 'r':
57 pos += 1
57 pos += 1
58 c = program[pos]
58 c = program[pos]
59 decode = lambda x: x
59 decode = lambda x: x
60 else:
60 else:
61 decode = lambda x: x.decode('string-escape')
61 decode = lambda x: x.decode('string-escape')
62 pos += 1
62 pos += 1
63 s = pos
63 s = pos
64 while pos < l: # find closing quote
64 while pos < l: # find closing quote
65 d = program[pos]
65 d = program[pos]
66 if d == '\\': # skip over escaped characters
66 if d == '\\': # skip over escaped characters
67 pos += 2
67 pos += 2
68 continue
68 continue
69 if d == c:
69 if d == c:
70 yield ('string', decode(program[s:pos]), s)
70 yield ('string', decode(program[s:pos]), s)
71 break
71 break
72 pos += 1
72 pos += 1
73 else:
73 else:
74 raise error.ParseError(_("unterminated string"), s)
74 raise error.ParseError(_("unterminated string"), s)
75 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
75 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
76 s = pos
76 s = pos
77 pos += 1
77 pos += 1
78 while pos < l: # find end of symbol
78 while pos < l: # find end of symbol
79 d = program[pos]
79 d = program[pos]
80 if not (d.isalnum() or d in "._" or ord(d) > 127):
80 if not (d.isalnum() or d in "._" or ord(d) > 127):
81 break
81 break
82 if d == '.' and program[pos - 1] == '.': # special case for ..
82 if d == '.' and program[pos - 1] == '.': # special case for ..
83 pos -= 1
83 pos -= 1
84 break
84 break
85 pos += 1
85 pos += 1
86 sym = program[s:pos]
86 sym = program[s:pos]
87 if sym in keywords: # operator keywords
87 if sym in keywords: # operator keywords
88 yield (sym, None, s)
88 yield (sym, None, s)
89 else:
89 else:
90 yield ('symbol', sym, s)
90 yield ('symbol', sym, s)
91 pos -= 1
91 pos -= 1
92 else:
92 else:
93 raise error.ParseError(_("syntax error"), pos)
93 raise error.ParseError(_("syntax error"), pos)
94 pos += 1
94 pos += 1
95 yield ('end', None, pos)
95 yield ('end', None, pos)
96
96
97 # helpers
97 # helpers
98
98
99 def getstring(x, err):
99 def getstring(x, err):
100 if x and (x[0] == 'string' or x[0] == 'symbol'):
100 if x and (x[0] == 'string' or x[0] == 'symbol'):
101 return x[1]
101 return x[1]
102 raise error.ParseError(err)
102 raise error.ParseError(err)
103
103
104 def getlist(x):
104 def getlist(x):
105 if not x:
105 if not x:
106 return []
106 return []
107 if x[0] == 'list':
107 if x[0] == 'list':
108 return getlist(x[1]) + [x[2]]
108 return getlist(x[1]) + [x[2]]
109 return [x]
109 return [x]
110
110
111 def getargs(x, min, max, err):
111 def getargs(x, min, max, err):
112 l = getlist(x)
112 l = getlist(x)
113 if len(l) < min or len(l) > max:
113 if len(l) < min or len(l) > max:
114 raise error.ParseError(err)
114 raise error.ParseError(err)
115 return l
115 return l
116
116
117 def getset(repo, subset, x):
117 def getset(repo, subset, x):
118 if not x:
118 if not x:
119 raise error.ParseError(_("missing argument"))
119 raise error.ParseError(_("missing argument"))
120 return methods[x[0]](repo, subset, *x[1:])
120 return methods[x[0]](repo, subset, *x[1:])
121
121
122 # operator methods
122 # operator methods
123
123
124 def stringset(repo, subset, x):
124 def stringset(repo, subset, x):
125 x = repo[x].rev()
125 x = repo[x].rev()
126 if x == -1 and len(subset) == len(repo):
126 if x == -1 and len(subset) == len(repo):
127 return [-1]
127 return [-1]
128 if len(subset) == len(repo) or x in subset:
128 if len(subset) == len(repo) or x in subset:
129 return [x]
129 return [x]
130 return []
130 return []
131
131
132 def symbolset(repo, subset, x):
132 def symbolset(repo, subset, x):
133 if x in symbols:
133 if x in symbols:
134 raise error.ParseError(_("can't use %s here") % x)
134 raise error.ParseError(_("can't use %s here") % x)
135 return stringset(repo, subset, x)
135 return stringset(repo, subset, x)
136
136
137 def rangeset(repo, subset, x, y):
137 def rangeset(repo, subset, x, y):
138 m = getset(repo, subset, x)
138 m = getset(repo, subset, x)
139 if not m:
139 if not m:
140 m = getset(repo, range(len(repo)), x)
140 m = getset(repo, range(len(repo)), x)
141
141
142 n = getset(repo, subset, y)
142 n = getset(repo, subset, y)
143 if not n:
143 if not n:
144 n = getset(repo, range(len(repo)), y)
144 n = getset(repo, range(len(repo)), y)
145
145
146 if not m or not n:
146 if not m or not n:
147 return []
147 return []
148 m, n = m[0], n[-1]
148 m, n = m[0], n[-1]
149
149
150 if m < n:
150 if m < n:
151 r = range(m, n + 1)
151 r = range(m, n + 1)
152 else:
152 else:
153 r = range(m, n - 1, -1)
153 r = range(m, n - 1, -1)
154 s = set(subset)
154 s = set(subset)
155 return [x for x in r if x in s]
155 return [x for x in r if x in s]
156
156
157 def andset(repo, subset, x, y):
157 def andset(repo, subset, x, y):
158 return getset(repo, getset(repo, subset, x), y)
158 return getset(repo, getset(repo, subset, x), y)
159
159
160 def orset(repo, subset, x, y):
160 def orset(repo, subset, x, y):
161 xl = getset(repo, subset, x)
161 xl = getset(repo, subset, x)
162 s = set(xl)
162 s = set(xl)
163 yl = getset(repo, [r for r in subset if r not in s], y)
163 yl = getset(repo, [r for r in subset if r not in s], y)
164 return xl + yl
164 return xl + yl
165
165
166 def notset(repo, subset, x):
166 def notset(repo, subset, x):
167 s = set(getset(repo, subset, x))
167 s = set(getset(repo, subset, x))
168 return [r for r in subset if r not in s]
168 return [r for r in subset if r not in s]
169
169
170 def listset(repo, subset, a, b):
170 def listset(repo, subset, a, b):
171 raise error.ParseError(_("can't use a list in this context"))
171 raise error.ParseError(_("can't use a list in this context"))
172
172
173 def func(repo, subset, a, b):
173 def func(repo, subset, a, b):
174 if a[0] == 'symbol' and a[1] in symbols:
174 if a[0] == 'symbol' and a[1] in symbols:
175 return symbols[a[1]](repo, subset, b)
175 return symbols[a[1]](repo, subset, b)
176 raise error.ParseError(_("not a function: %s") % a[1])
176 raise error.ParseError(_("not a function: %s") % a[1])
177
177
178 # functions
178 # functions
179
179
180 def adds(repo, subset, x):
180 def adds(repo, subset, x):
181 """``adds(pattern)``
181 """``adds(pattern)``
182 Changesets that add a file matching pattern.
182 Changesets that add a file matching pattern.
183 """
183 """
184 # i18n: "adds" is a keyword
184 # i18n: "adds" is a keyword
185 pat = getstring(x, _("adds requires a pattern"))
185 pat = getstring(x, _("adds requires a pattern"))
186 return checkstatus(repo, subset, pat, 1)
186 return checkstatus(repo, subset, pat, 1)
187
187
188 def ancestor(repo, subset, x):
188 def ancestor(repo, subset, x):
189 """``ancestor(single, single)``
189 """``ancestor(single, single)``
190 Greatest common ancestor of the two changesets.
190 Greatest common ancestor of the two changesets.
191 """
191 """
192 # i18n: "ancestor" is a keyword
192 # i18n: "ancestor" is a keyword
193 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
193 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
194 r = range(len(repo))
194 r = range(len(repo))
195 a = getset(repo, r, l[0])
195 a = getset(repo, r, l[0])
196 b = getset(repo, r, l[1])
196 b = getset(repo, r, l[1])
197 if len(a) != 1 or len(b) != 1:
197 if len(a) != 1 or len(b) != 1:
198 # i18n: "ancestor" is a keyword
198 # i18n: "ancestor" is a keyword
199 raise error.ParseError(_("ancestor arguments must be single revisions"))
199 raise error.ParseError(_("ancestor arguments must be single revisions"))
200 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
200 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
201
201
202 return [r for r in an if r in subset]
202 return [r for r in an if r in subset]
203
203
204 def ancestors(repo, subset, x):
204 def ancestors(repo, subset, x):
205 """``ancestors(set)``
205 """``ancestors(set)``
206 Changesets that are ancestors of a changeset in set.
206 Changesets that are ancestors of a changeset in set.
207 """
207 """
208 args = getset(repo, range(len(repo)), x)
208 args = getset(repo, range(len(repo)), x)
209 if not args:
209 if not args:
210 return []
210 return []
211 s = set(repo.changelog.ancestors(*args)) | set(args)
211 s = set(repo.changelog.ancestors(*args)) | set(args)
212 return [r for r in subset if r in s]
212 return [r for r in subset if r in s]
213
213
214 def ancestorspec(repo, subset, x, n):
214 def ancestorspec(repo, subset, x, n):
215 """``set~n``
215 """``set~n``
216 Changesets that are the Nth ancestor (first parents only) of a changeset in set.
216 Changesets that are the Nth ancestor (first parents only) of a changeset in set.
217 """
217 """
218 try:
218 try:
219 n = int(n[1])
219 n = int(n[1])
220 except ValueError:
220 except ValueError:
221 raise error.ParseError(_("~ expects a number"))
221 raise error.ParseError(_("~ expects a number"))
222 ps = set()
222 ps = set()
223 cl = repo.changelog
223 cl = repo.changelog
224 for r in getset(repo, subset, x):
224 for r in getset(repo, subset, x):
225 for i in range(n):
225 for i in range(n):
226 r = cl.parentrevs(r)[0]
226 r = cl.parentrevs(r)[0]
227 ps.add(r)
227 ps.add(r)
228 return [r for r in subset if r in ps]
228 return [r for r in subset if r in ps]
229
229
230 def author(repo, subset, x):
230 def author(repo, subset, x):
231 """``author(string)``
231 """``author(string)``
232 Alias for ``user(string)``.
232 Alias for ``user(string)``.
233 """
233 """
234 # i18n: "author" is a keyword
234 # i18n: "author" is a keyword
235 n = getstring(x, _("author requires a string")).lower()
235 n = getstring(x, _("author requires a string")).lower()
236 return [r for r in subset if n in repo[r].user().lower()]
236 return [r for r in subset if n in repo[r].user().lower()]
237
237
238 def bisected(repo, subset, x):
238 def bisected(repo, subset, x):
239 """``bisected(string)``
239 """``bisected(string)``
240 Changesets marked in the specified bisect state (good, bad, skip).
240 Changesets marked in the specified bisect state (good, bad, skip).
241 """
241 """
242 state = getstring(x, _("bisect requires a string")).lower()
242 state = getstring(x, _("bisect requires a string")).lower()
243 if state not in ('good', 'bad', 'skip', 'unknown'):
243 if state not in ('good', 'bad', 'skip', 'unknown'):
244 raise error.ParseError(_('invalid bisect state'))
244 raise error.ParseError(_('invalid bisect state'))
245 marked = set(repo.changelog.rev(n) for n in hbisect.load_state(repo)[state])
245 marked = set(repo.changelog.rev(n) for n in hbisect.load_state(repo)[state])
246 return [r for r in subset if r in marked]
246 return [r for r in subset if r in marked]
247
247
248 def bookmark(repo, subset, x):
248 def bookmark(repo, subset, x):
249 """``bookmark([name])``
249 """``bookmark([name])``
250 The named bookmark or all bookmarks.
250 The named bookmark or all bookmarks.
251 """
251 """
252 # i18n: "bookmark" is a keyword
252 # i18n: "bookmark" is a keyword
253 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
253 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
254 if args:
254 if args:
255 bm = getstring(args[0],
255 bm = getstring(args[0],
256 # i18n: "bookmark" is a keyword
256 # i18n: "bookmark" is a keyword
257 _('the argument to bookmark must be a string'))
257 _('the argument to bookmark must be a string'))
258 bmrev = bookmarksmod.listbookmarks(repo).get(bm, None)
258 bmrev = bookmarksmod.listbookmarks(repo).get(bm, None)
259 if not bmrev:
259 if not bmrev:
260 raise util.Abort(_("bookmark '%s' does not exist") % bm)
260 raise util.Abort(_("bookmark '%s' does not exist") % bm)
261 bmrev = repo[bmrev].rev()
261 bmrev = repo[bmrev].rev()
262 return [r for r in subset if r == bmrev]
262 return [r for r in subset if r == bmrev]
263 bms = set([repo[r].rev()
263 bms = set([repo[r].rev()
264 for r in bookmarksmod.listbookmarks(repo).values()])
264 for r in bookmarksmod.listbookmarks(repo).values()])
265 return [r for r in subset if r in bms]
265 return [r for r in subset if r in bms]
266
266
267 def branch(repo, subset, x):
267 def branch(repo, subset, x):
268 """``branch(string or set)``
268 """``branch(string or set)``
269 All changesets belonging to the given branch or the branches of the given
269 All changesets belonging to the given branch or the branches of the given
270 changesets.
270 changesets.
271 """
271 """
272 try:
272 try:
273 b = getstring(x, '')
273 b = getstring(x, '')
274 if b in repo.branchmap():
274 if b in repo.branchmap():
275 return [r for r in subset if repo[r].branch() == b]
275 return [r for r in subset if repo[r].branch() == b]
276 except error.ParseError:
276 except error.ParseError:
277 # not a string, but another revspec, e.g. tip()
277 # not a string, but another revspec, e.g. tip()
278 pass
278 pass
279
279
280 s = getset(repo, range(len(repo)), x)
280 s = getset(repo, range(len(repo)), x)
281 b = set()
281 b = set()
282 for r in s:
282 for r in s:
283 b.add(repo[r].branch())
283 b.add(repo[r].branch())
284 s = set(s)
284 s = set(s)
285 return [r for r in subset if r in s or repo[r].branch() in b]
285 return [r for r in subset if r in s or repo[r].branch() in b]
286
286
287 def checkstatus(repo, subset, pat, field):
287 def checkstatus(repo, subset, pat, field):
288 m = matchmod.match(repo.root, repo.getcwd(), [pat])
288 m = matchmod.match(repo.root, repo.getcwd(), [pat])
289 s = []
289 s = []
290 fast = (m.files() == [pat])
290 fast = (m.files() == [pat])
291 for r in subset:
291 for r in subset:
292 c = repo[r]
292 c = repo[r]
293 if fast:
293 if fast:
294 if pat not in c.files():
294 if pat not in c.files():
295 continue
295 continue
296 else:
296 else:
297 for f in c.files():
297 for f in c.files():
298 if m(f):
298 if m(f):
299 break
299 break
300 else:
300 else:
301 continue
301 continue
302 files = repo.status(c.p1().node(), c.node())[field]
302 files = repo.status(c.p1().node(), c.node())[field]
303 if fast:
303 if fast:
304 if pat in files:
304 if pat in files:
305 s.append(r)
305 s.append(r)
306 else:
306 else:
307 for f in files:
307 for f in files:
308 if m(f):
308 if m(f):
309 s.append(r)
309 s.append(r)
310 break
310 break
311 return s
311 return s
312
312
313 def children(repo, subset, x):
313 def children(repo, subset, x):
314 """``children(set)``
314 """``children(set)``
315 Child changesets of changesets in set.
315 Child changesets of changesets in set.
316 """
316 """
317 cs = set()
317 cs = set()
318 cl = repo.changelog
318 cl = repo.changelog
319 s = set(getset(repo, range(len(repo)), x))
319 s = set(getset(repo, range(len(repo)), x))
320 for r in xrange(0, len(repo)):
320 for r in xrange(0, len(repo)):
321 for p in cl.parentrevs(r):
321 for p in cl.parentrevs(r):
322 if p in s:
322 if p in s:
323 cs.add(r)
323 cs.add(r)
324 return [r for r in subset if r in cs]
324 return [r for r in subset if r in cs]
325
325
326 def closed(repo, subset, x):
326 def closed(repo, subset, x):
327 """``closed()``
327 """``closed()``
328 Changeset is closed.
328 Changeset is closed.
329 """
329 """
330 # i18n: "closed" is a keyword
330 # i18n: "closed" is a keyword
331 getargs(x, 0, 0, _("closed takes no arguments"))
331 getargs(x, 0, 0, _("closed takes no arguments"))
332 return [r for r in subset if repo[r].extra().get('close')]
332 return [r for r in subset if repo[r].extra().get('close')]
333
333
334 def contains(repo, subset, x):
334 def contains(repo, subset, x):
335 """``contains(pattern)``
335 """``contains(pattern)``
336 Revision contains pattern.
336 Revision contains pattern.
337 """
337 """
338 # i18n: "contains" is a keyword
338 # i18n: "contains" is a keyword
339 pat = getstring(x, _("contains requires a pattern"))
339 pat = getstring(x, _("contains requires a pattern"))
340 m = matchmod.match(repo.root, repo.getcwd(), [pat])
340 m = matchmod.match(repo.root, repo.getcwd(), [pat])
341 s = []
341 s = []
342 if m.files() == [pat]:
342 if m.files() == [pat]:
343 for r in subset:
343 for r in subset:
344 if pat in repo[r]:
344 if pat in repo[r]:
345 s.append(r)
345 s.append(r)
346 else:
346 else:
347 for r in subset:
347 for r in subset:
348 for f in repo[r].manifest():
348 for f in repo[r].manifest():
349 if m(f):
349 if m(f):
350 s.append(r)
350 s.append(r)
351 break
351 break
352 return s
352 return s
353
353
354 def date(repo, subset, x):
354 def date(repo, subset, x):
355 """``date(interval)``
355 """``date(interval)``
356 Changesets within the interval, see :hg:`help dates`.
356 Changesets within the interval, see :hg:`help dates`.
357 """
357 """
358 # i18n: "date" is a keyword
358 # i18n: "date" is a keyword
359 ds = getstring(x, _("date requires a string"))
359 ds = getstring(x, _("date requires a string"))
360 dm = util.matchdate(ds)
360 dm = util.matchdate(ds)
361 return [r for r in subset if dm(repo[r].date()[0])]
361 return [r for r in subset if dm(repo[r].date()[0])]
362
362
363 def descendants(repo, subset, x):
363 def descendants(repo, subset, x):
364 """``descendants(set)``
364 """``descendants(set)``
365 Changesets which are descendants of changesets in set.
365 Changesets which are descendants of changesets in set.
366 """
366 """
367 args = getset(repo, range(len(repo)), x)
367 args = getset(repo, range(len(repo)), x)
368 if not args:
368 if not args:
369 return []
369 return []
370 s = set(repo.changelog.descendants(*args)) | set(args)
370 s = set(repo.changelog.descendants(*args)) | set(args)
371 return [r for r in subset if r in s]
371 return [r for r in subset if r in s]
372
372
373 def follow(repo, subset, x):
373 def follow(repo, subset, x):
374 """``follow()``
374 """``follow()``
375 An alias for ``::.`` (ancestors of the working copy's first parent).
375 An alias for ``::.`` (ancestors of the working copy's first parent).
376 """
376 """
377 # i18n: "follow" is a keyword
377 # i18n: "follow" is a keyword
378 getargs(x, 0, 0, _("follow takes no arguments"))
378 getargs(x, 0, 0, _("follow takes no arguments"))
379 p = repo['.'].rev()
379 p = repo['.'].rev()
380 s = set(repo.changelog.ancestors(p)) | set([p])
380 s = set(repo.changelog.ancestors(p)) | set([p])
381 return [r for r in subset if r in s]
381 return [r for r in subset if r in s]
382
382
383 def getall(repo, subset, x):
383 def getall(repo, subset, x):
384 """``all()``
384 """``all()``
385 All changesets, the same as ``0:tip``.
385 All changesets, the same as ``0:tip``.
386 """
386 """
387 # i18n: "all" is a keyword
387 # i18n: "all" is a keyword
388 getargs(x, 0, 0, _("all takes no arguments"))
388 getargs(x, 0, 0, _("all takes no arguments"))
389 return subset
389 return subset
390
390
391 def grep(repo, subset, x):
391 def grep(repo, subset, x):
392 """``grep(regex)``
392 """``grep(regex)``
393 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
393 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
394 to ensure special escape characters are handled correctly.
394 to ensure special escape characters are handled correctly.
395 """
395 """
396 try:
396 try:
397 # i18n: "grep" is a keyword
397 # i18n: "grep" is a keyword
398 gr = re.compile(getstring(x, _("grep requires a string")))
398 gr = re.compile(getstring(x, _("grep requires a string")))
399 except re.error, e:
399 except re.error, e:
400 raise error.ParseError(_('invalid match pattern: %s') % e)
400 raise error.ParseError(_('invalid match pattern: %s') % e)
401 l = []
401 l = []
402 for r in subset:
402 for r in subset:
403 c = repo[r]
403 c = repo[r]
404 for e in c.files() + [c.user(), c.description()]:
404 for e in c.files() + [c.user(), c.description()]:
405 if gr.search(e):
405 if gr.search(e):
406 l.append(r)
406 l.append(r)
407 break
407 break
408 return l
408 return l
409
409
410 def hasfile(repo, subset, x):
410 def hasfile(repo, subset, x):
411 """``file(pattern)``
411 """``file(pattern)``
412 Changesets affecting files matched by pattern.
412 Changesets affecting files matched by pattern.
413 """
413 """
414 # i18n: "file" is a keyword
414 # i18n: "file" is a keyword
415 pat = getstring(x, _("file requires a pattern"))
415 pat = getstring(x, _("file requires a pattern"))
416 m = matchmod.match(repo.root, repo.getcwd(), [pat])
416 m = matchmod.match(repo.root, repo.getcwd(), [pat])
417 s = []
417 s = []
418 for r in subset:
418 for r in subset:
419 for f in repo[r].files():
419 for f in repo[r].files():
420 if m(f):
420 if m(f):
421 s.append(r)
421 s.append(r)
422 break
422 break
423 return s
423 return s
424
424
425 def head(repo, subset, x):
425 def head(repo, subset, x):
426 """``head()``
426 """``head()``
427 Changeset is a named branch head.
427 Changeset is a named branch head.
428 """
428 """
429 # i18n: "head" is a keyword
429 # i18n: "head" is a keyword
430 getargs(x, 0, 0, _("head takes no arguments"))
430 getargs(x, 0, 0, _("head takes no arguments"))
431 hs = set()
431 hs = set()
432 for b, ls in repo.branchmap().iteritems():
432 for b, ls in repo.branchmap().iteritems():
433 hs.update(repo[h].rev() for h in ls)
433 hs.update(repo[h].rev() for h in ls)
434 return [r for r in subset if r in hs]
434 return [r for r in subset if r in hs]
435
435
436 def heads(repo, subset, x):
436 def heads(repo, subset, x):
437 """``heads(set)``
437 """``heads(set)``
438 Members of set with no children in set.
438 Members of set with no children in set.
439 """
439 """
440 s = getset(repo, subset, x)
440 s = getset(repo, subset, x)
441 ps = set(parents(repo, subset, x))
441 ps = set(parents(repo, subset, x))
442 return [r for r in s if r not in ps]
442 return [r for r in s if r not in ps]
443
443
444 def keyword(repo, subset, x):
444 def keyword(repo, subset, x):
445 """``keyword(string)``
445 """``keyword(string)``
446 Search commit message, user name, and names of changed files for
446 Search commit message, user name, and names of changed files for
447 string.
447 string.
448 """
448 """
449 # i18n: "keyword" is a keyword
449 # i18n: "keyword" is a keyword
450 kw = getstring(x, _("keyword requires a string")).lower()
450 kw = getstring(x, _("keyword requires a string")).lower()
451 l = []
451 l = []
452 for r in subset:
452 for r in subset:
453 c = repo[r]
453 c = repo[r]
454 t = " ".join(c.files() + [c.user(), c.description()])
454 t = " ".join(c.files() + [c.user(), c.description()])
455 if kw in t.lower():
455 if kw in t.lower():
456 l.append(r)
456 l.append(r)
457 return l
457 return l
458
458
459 def limit(repo, subset, x):
459 def limit(repo, subset, x):
460 """``limit(set, n)``
460 """``limit(set, n)``
461 First n members of set.
461 First n members of set.
462 """
462 """
463 # i18n: "limit" is a keyword
463 # i18n: "limit" is a keyword
464 l = getargs(x, 2, 2, _("limit requires two arguments"))
464 l = getargs(x, 2, 2, _("limit requires two arguments"))
465 try:
465 try:
466 # i18n: "limit" is a keyword
466 # i18n: "limit" is a keyword
467 lim = int(getstring(l[1], _("limit requires a number")))
467 lim = int(getstring(l[1], _("limit requires a number")))
468 except ValueError:
468 except ValueError:
469 # i18n: "limit" is a keyword
469 # i18n: "limit" is a keyword
470 raise error.ParseError(_("limit expects a number"))
470 raise error.ParseError(_("limit expects a number"))
471 return getset(repo, subset, l[0])[:lim]
471 return getset(repo, subset, l[0])[:lim]
472
472
473 def last(repo, subset, x):
473 def last(repo, subset, x):
474 """``last(set, n)``
474 """``last(set, n)``
475 Last n members of set.
475 Last n members of set.
476 """
476 """
477 # i18n: "last" is a keyword
477 # i18n: "last" is a keyword
478 l = getargs(x, 2, 2, _("last requires two arguments"))
478 l = getargs(x, 2, 2, _("last requires two arguments"))
479 try:
479 try:
480 # i18n: "last" is a keyword
480 # i18n: "last" is a keyword
481 lim = int(getstring(l[1], _("last requires a number")))
481 lim = int(getstring(l[1], _("last requires a number")))
482 except ValueError:
482 except ValueError:
483 # i18n: "last" is a keyword
483 # i18n: "last" is a keyword
484 raise error.ParseError(_("last expects a number"))
484 raise error.ParseError(_("last expects a number"))
485 return getset(repo, subset, l[0])[-lim:]
485 return getset(repo, subset, l[0])[-lim:]
486
486
487 def maxrev(repo, subset, x):
487 def maxrev(repo, subset, x):
488 """``max(set)``
488 """``max(set)``
489 Changeset with highest revision number in set.
489 Changeset with highest revision number in set.
490 """
490 """
491 s = getset(repo, subset, x)
491 s = getset(repo, subset, x)
492 if s:
492 if s:
493 m = max(s)
493 m = max(s)
494 if m in subset:
494 if m in subset:
495 return [m]
495 return [m]
496 return []
496 return []
497
497
498 def merge(repo, subset, x):
498 def merge(repo, subset, x):
499 """``merge()``
499 """``merge()``
500 Changeset is a merge changeset.
500 Changeset is a merge changeset.
501 """
501 """
502 # i18n: "merge" is a keyword
502 # i18n: "merge" is a keyword
503 getargs(x, 0, 0, _("merge takes no arguments"))
503 getargs(x, 0, 0, _("merge takes no arguments"))
504 cl = repo.changelog
504 cl = repo.changelog
505 return [r for r in subset if cl.parentrevs(r)[1] != -1]
505 return [r for r in subset if cl.parentrevs(r)[1] != -1]
506
506
507 def minrev(repo, subset, x):
507 def minrev(repo, subset, x):
508 """``min(set)``
508 """``min(set)``
509 Changeset with lowest revision number in set.
509 Changeset with lowest revision number in set.
510 """
510 """
511 s = getset(repo, subset, x)
511 s = getset(repo, subset, x)
512 if s:
512 if s:
513 m = min(s)
513 m = min(s)
514 if m in subset:
514 if m in subset:
515 return [m]
515 return [m]
516 return []
516 return []
517
517
518 def modifies(repo, subset, x):
518 def modifies(repo, subset, x):
519 """``modifies(pattern)``
519 """``modifies(pattern)``
520 Changesets modifying files matched by pattern.
520 Changesets modifying files matched by pattern.
521 """
521 """
522 # i18n: "modifies" is a keyword
522 # i18n: "modifies" is a keyword
523 pat = getstring(x, _("modifies requires a pattern"))
523 pat = getstring(x, _("modifies requires a pattern"))
524 return checkstatus(repo, subset, pat, 0)
524 return checkstatus(repo, subset, pat, 0)
525
525
526 def node(repo, subset, x):
526 def node(repo, subset, x):
527 """``id(string)``
527 """``id(string)``
528 Revision non-ambiguously specified by the given hex string prefix.
528 Revision non-ambiguously specified by the given hex string prefix.
529 """
529 """
530 # i18n: "id" is a keyword
530 # i18n: "id" is a keyword
531 l = getargs(x, 1, 1, _("id requires one argument"))
531 l = getargs(x, 1, 1, _("id requires one argument"))
532 # i18n: "id" is a keyword
532 # i18n: "id" is a keyword
533 n = getstring(l[0], _("id requires a string"))
533 n = getstring(l[0], _("id requires a string"))
534 if len(n) == 40:
534 if len(n) == 40:
535 rn = repo[n].rev()
535 rn = repo[n].rev()
536 else:
536 else:
537 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
537 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
538 return [r for r in subset if r == rn]
538 return [r for r in subset if r == rn]
539
539
540 def outgoing(repo, subset, x):
540 def outgoing(repo, subset, x):
541 """``outgoing([path])``
541 """``outgoing([path])``
542 Changesets not found in the specified destination repository, or the
542 Changesets not found in the specified destination repository, or the
543 default push location.
543 default push location.
544 """
544 """
545 import hg # avoid start-up nasties
545 import hg # avoid start-up nasties
546 # i18n: "outgoing" is a keyword
546 # i18n: "outgoing" is a keyword
547 l = getargs(x, 0, 1, _("outgoing requires a repository path"))
547 l = getargs(x, 0, 1, _("outgoing requires a repository path"))
548 # i18n: "outgoing" is a keyword
548 # i18n: "outgoing" is a keyword
549 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
549 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
550 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
550 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
551 dest, branches = hg.parseurl(dest)
551 dest, branches = hg.parseurl(dest)
552 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
552 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
553 if revs:
553 if revs:
554 revs = [repo.lookup(rev) for rev in revs]
554 revs = [repo.lookup(rev) for rev in revs]
555 other = hg.repository(hg.remoteui(repo, {}), dest)
555 other = hg.repository(hg.remoteui(repo, {}), dest)
556 repo.ui.pushbuffer()
556 repo.ui.pushbuffer()
557 common, _anyinc, _heads = discovery.findcommonincoming(repo, other)
557 common, _anyinc, _heads = discovery.findcommonincoming(repo, other)
558 repo.ui.popbuffer()
558 repo.ui.popbuffer()
559 cl = repo.changelog
559 cl = repo.changelog
560 o = set([cl.rev(r) for r in repo.changelog.findmissing(common, revs)])
560 o = set([cl.rev(r) for r in repo.changelog.findmissing(common, revs)])
561 return [r for r in subset if r in o]
561 return [r for r in subset if r in o]
562
562
563 def p1(repo, subset, x):
563 def p1(repo, subset, x):
564 """``p1([set])``
564 """``p1([set])``
565 First parent of changesets in set, or the working directory.
565 First parent of changesets in set, or the working directory.
566 """
566 """
567 if x is None:
567 if x is None:
568 p = repo[x].p1().rev()
568 p = repo[x].p1().rev()
569 return [r for r in subset if r == p]
569 return [r for r in subset if r == p]
570
570
571 ps = set()
571 ps = set()
572 cl = repo.changelog
572 cl = repo.changelog
573 for r in getset(repo, range(len(repo)), x):
573 for r in getset(repo, range(len(repo)), x):
574 ps.add(cl.parentrevs(r)[0])
574 ps.add(cl.parentrevs(r)[0])
575 return [r for r in subset if r in ps]
575 return [r for r in subset if r in ps]
576
576
577 def p2(repo, subset, x):
577 def p2(repo, subset, x):
578 """``p2([set])``
578 """``p2([set])``
579 Second parent of changesets in set, or the working directory.
579 Second parent of changesets in set, or the working directory.
580 """
580 """
581 if x is None:
581 if x is None:
582 ps = repo[x].parents()
582 ps = repo[x].parents()
583 try:
583 try:
584 p = ps[1].rev()
584 p = ps[1].rev()
585 return [r for r in subset if r == p]
585 return [r for r in subset if r == p]
586 except IndexError:
586 except IndexError:
587 return []
587 return []
588
588
589 ps = set()
589 ps = set()
590 cl = repo.changelog
590 cl = repo.changelog
591 for r in getset(repo, range(len(repo)), x):
591 for r in getset(repo, range(len(repo)), x):
592 ps.add(cl.parentrevs(r)[1])
592 ps.add(cl.parentrevs(r)[1])
593 return [r for r in subset if r in ps]
593 return [r for r in subset if r in ps]
594
594
595 def parents(repo, subset, x):
595 def parents(repo, subset, x):
596 """``parents([set])``
596 """``parents([set])``
597 The set of all parents for all changesets in set, or the working directory.
597 The set of all parents for all changesets in set, or the working directory.
598 """
598 """
599 if x is None:
599 if x is None:
600 ps = tuple(p.rev() for p in repo[x].parents())
600 ps = tuple(p.rev() for p in repo[x].parents())
601 return [r for r in subset if r in ps]
601 return [r for r in subset if r in ps]
602
602
603 ps = set()
603 ps = set()
604 cl = repo.changelog
604 cl = repo.changelog
605 for r in getset(repo, range(len(repo)), x):
605 for r in getset(repo, range(len(repo)), x):
606 ps.update(cl.parentrevs(r))
606 ps.update(cl.parentrevs(r))
607 return [r for r in subset if r in ps]
607 return [r for r in subset if r in ps]
608
608
609 def parentspec(repo, subset, x, n):
609 def parentspec(repo, subset, x, n):
610 """``set^0``
610 """``set^0``
611 The set.
611 The set.
612 ``set^1`` (or ``set^``), ``set^2``
612 ``set^1`` (or ``set^``), ``set^2``
613 First or second parent, respectively, of all changesets in set.
613 First or second parent, respectively, of all changesets in set.
614 """
614 """
615 try:
615 try:
616 n = int(n[1])
616 n = int(n[1])
617 if n not in (0, 1, 2):
617 if n not in (0, 1, 2):
618 raise ValueError
618 raise ValueError
619 except ValueError:
619 except ValueError:
620 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
620 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
621 ps = set()
621 ps = set()
622 cl = repo.changelog
622 cl = repo.changelog
623 for r in getset(repo, subset, x):
623 for r in getset(repo, subset, x):
624 if n == 0:
624 if n == 0:
625 ps.add(r)
625 ps.add(r)
626 elif n == 1:
626 elif n == 1:
627 ps.add(cl.parentrevs(r)[0])
627 ps.add(cl.parentrevs(r)[0])
628 elif n == 2:
628 elif n == 2:
629 parents = cl.parentrevs(r)
629 parents = cl.parentrevs(r)
630 if len(parents) > 1:
630 if len(parents) > 1:
631 ps.add(parents[1])
631 ps.add(parents[1])
632 return [r for r in subset if r in ps]
632 return [r for r in subset if r in ps]
633
633
634 def present(repo, subset, x):
634 def present(repo, subset, x):
635 """``present(set)``
635 """``present(set)``
636 An empty set, if any revision in set isn't found; otherwise,
636 An empty set, if any revision in set isn't found; otherwise,
637 all revisions in set.
637 all revisions in set.
638 """
638 """
639 try:
639 try:
640 return getset(repo, subset, x)
640 return getset(repo, subset, x)
641 except error.RepoLookupError:
641 except error.RepoLookupError:
642 return []
642 return []
643
643
644 def removes(repo, subset, x):
644 def removes(repo, subset, x):
645 """``removes(pattern)``
645 """``removes(pattern)``
646 Changesets which remove files matching pattern.
646 Changesets which remove files matching pattern.
647 """
647 """
648 # i18n: "removes" is a keyword
648 # i18n: "removes" is a keyword
649 pat = getstring(x, _("removes requires a pattern"))
649 pat = getstring(x, _("removes requires a pattern"))
650 return checkstatus(repo, subset, pat, 2)
650 return checkstatus(repo, subset, pat, 2)
651
651
652 def rev(repo, subset, x):
652 def rev(repo, subset, x):
653 """``rev(number)``
653 """``rev(number)``
654 Revision with the given numeric identifier.
654 Revision with the given numeric identifier.
655 """
655 """
656 # i18n: "rev" is a keyword
656 # i18n: "rev" is a keyword
657 l = getargs(x, 1, 1, _("rev requires one argument"))
657 l = getargs(x, 1, 1, _("rev requires one argument"))
658 try:
658 try:
659 # i18n: "rev" is a keyword
659 # i18n: "rev" is a keyword
660 l = int(getstring(l[0], _("rev requires a number")))
660 l = int(getstring(l[0], _("rev requires a number")))
661 except ValueError:
661 except ValueError:
662 # i18n: "rev" is a keyword
662 # i18n: "rev" is a keyword
663 raise error.ParseError(_("rev expects a number"))
663 raise error.ParseError(_("rev expects a number"))
664 return [r for r in subset if r == l]
664 return [r for r in subset if r == l]
665
665
666 def reverse(repo, subset, x):
666 def reverse(repo, subset, x):
667 """``reverse(set)``
667 """``reverse(set)``
668 Reverse order of set.
668 Reverse order of set.
669 """
669 """
670 l = getset(repo, subset, x)
670 l = getset(repo, subset, x)
671 l.reverse()
671 l.reverse()
672 return l
672 return l
673
673
674 def roots(repo, subset, x):
674 def roots(repo, subset, x):
675 """``roots(set)``
675 """``roots(set)``
676 Changesets with no parent changeset in set.
676 Changesets with no parent changeset in set.
677 """
677 """
678 s = getset(repo, subset, x)
678 s = getset(repo, subset, x)
679 cs = set(children(repo, subset, x))
679 cs = set(children(repo, subset, x))
680 return [r for r in s if r not in cs]
680 return [r for r in s if r not in cs]
681
681
682 def sort(repo, subset, x):
682 def sort(repo, subset, x):
683 """``sort(set[, [-]key...])``
683 """``sort(set[, [-]key...])``
684 Sort set by keys. The default sort order is ascending, specify a key
684 Sort set by keys. The default sort order is ascending, specify a key
685 as ``-key`` to sort in descending order.
685 as ``-key`` to sort in descending order.
686
686
687 The keys can be:
687 The keys can be:
688
688
689 - ``rev`` for the revision number,
689 - ``rev`` for the revision number,
690 - ``branch`` for the branch name,
690 - ``branch`` for the branch name,
691 - ``desc`` for the commit message (description),
691 - ``desc`` for the commit message (description),
692 - ``user`` for user name (``author`` can be used as an alias),
692 - ``user`` for user name (``author`` can be used as an alias),
693 - ``date`` for the commit date
693 - ``date`` for the commit date
694 """
694 """
695 # i18n: "sort" is a keyword
695 # i18n: "sort" is a keyword
696 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
696 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
697 keys = "rev"
697 keys = "rev"
698 if len(l) == 2:
698 if len(l) == 2:
699 keys = getstring(l[1], _("sort spec must be a string"))
699 keys = getstring(l[1], _("sort spec must be a string"))
700
700
701 s = l[0]
701 s = l[0]
702 keys = keys.split()
702 keys = keys.split()
703 l = []
703 l = []
704 def invert(s):
704 def invert(s):
705 return "".join(chr(255 - ord(c)) for c in s)
705 return "".join(chr(255 - ord(c)) for c in s)
706 for r in getset(repo, subset, s):
706 for r in getset(repo, subset, s):
707 c = repo[r]
707 c = repo[r]
708 e = []
708 e = []
709 for k in keys:
709 for k in keys:
710 if k == 'rev':
710 if k == 'rev':
711 e.append(r)
711 e.append(r)
712 elif k == '-rev':
712 elif k == '-rev':
713 e.append(-r)
713 e.append(-r)
714 elif k == 'branch':
714 elif k == 'branch':
715 e.append(c.branch())
715 e.append(c.branch())
716 elif k == '-branch':
716 elif k == '-branch':
717 e.append(invert(c.branch()))
717 e.append(invert(c.branch()))
718 elif k == 'desc':
718 elif k == 'desc':
719 e.append(c.description())
719 e.append(c.description())
720 elif k == '-desc':
720 elif k == '-desc':
721 e.append(invert(c.description()))
721 e.append(invert(c.description()))
722 elif k in 'user author':
722 elif k in 'user author':
723 e.append(c.user())
723 e.append(c.user())
724 elif k in '-user -author':
724 elif k in '-user -author':
725 e.append(invert(c.user()))
725 e.append(invert(c.user()))
726 elif k == 'date':
726 elif k == 'date':
727 e.append(c.date()[0])
727 e.append(c.date()[0])
728 elif k == '-date':
728 elif k == '-date':
729 e.append(-c.date()[0])
729 e.append(-c.date()[0])
730 else:
730 else:
731 raise error.ParseError(_("unknown sort key %r") % k)
731 raise error.ParseError(_("unknown sort key %r") % k)
732 e.append(r)
732 e.append(r)
733 l.append(e)
733 l.append(e)
734 l.sort()
734 l.sort()
735 return [e[-1] for e in l]
735 return [e[-1] for e in l]
736
736
737 def tag(repo, subset, x):
737 def tag(repo, subset, x):
738 """``tag(name)``
738 """``tag(name)``
739 The specified tag by name, or all tagged revisions if no name is given.
739 The specified tag by name, or all tagged revisions if no name is given.
740 """
740 """
741 # i18n: "tag" is a keyword
741 # i18n: "tag" is a keyword
742 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
742 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
743 cl = repo.changelog
743 cl = repo.changelog
744 if args:
744 if args:
745 tn = getstring(args[0],
745 tn = getstring(args[0],
746 # i18n: "tag" is a keyword
746 # i18n: "tag" is a keyword
747 _('the argument to tag must be a string'))
747 _('the argument to tag must be a string'))
748 if not repo.tags().get(tn, None):
748 if not repo.tags().get(tn, None):
749 raise util.Abort(_("tag '%s' does not exist") % tn)
749 raise util.Abort(_("tag '%s' does not exist") % tn)
750 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
750 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
751 else:
751 else:
752 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
752 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
753 return [r for r in subset if r in s]
753 return [r for r in subset if r in s]
754
754
755 def tagged(repo, subset, x):
755 def tagged(repo, subset, x):
756 return tag(repo, subset, x)
756 return tag(repo, subset, x)
757
757
758 def user(repo, subset, x):
758 def user(repo, subset, x):
759 """``user(string)``
759 """``user(string)``
760 User name is string.
760 User name is string.
761 """
761 """
762 return author(repo, subset, x)
762 return author(repo, subset, x)
763
763
764 symbols = {
764 symbols = {
765 "adds": adds,
765 "adds": adds,
766 "all": getall,
766 "all": getall,
767 "ancestor": ancestor,
767 "ancestor": ancestor,
768 "ancestors": ancestors,
768 "ancestors": ancestors,
769 "author": author,
769 "author": author,
770 "bisected": bisected,
770 "bisected": bisected,
771 "bookmark": bookmark,
771 "bookmark": bookmark,
772 "branch": branch,
772 "branch": branch,
773 "children": children,
773 "children": children,
774 "closed": closed,
774 "closed": closed,
775 "contains": contains,
775 "contains": contains,
776 "date": date,
776 "date": date,
777 "descendants": descendants,
777 "descendants": descendants,
778 "file": hasfile,
778 "file": hasfile,
779 "follow": follow,
779 "follow": follow,
780 "grep": grep,
780 "grep": grep,
781 "head": head,
781 "head": head,
782 "heads": heads,
782 "heads": heads,
783 "keyword": keyword,
783 "keyword": keyword,
784 "last": last,
784 "last": last,
785 "limit": limit,
785 "limit": limit,
786 "max": maxrev,
786 "max": maxrev,
787 "min": minrev,
787 "min": minrev,
788 "merge": merge,
788 "merge": merge,
789 "modifies": modifies,
789 "modifies": modifies,
790 "id": node,
790 "id": node,
791 "outgoing": outgoing,
791 "outgoing": outgoing,
792 "p1": p1,
792 "p1": p1,
793 "p2": p2,
793 "p2": p2,
794 "parents": parents,
794 "parents": parents,
795 "present": present,
795 "present": present,
796 "removes": removes,
796 "removes": removes,
797 "reverse": reverse,
797 "reverse": reverse,
798 "rev": rev,
798 "rev": rev,
799 "roots": roots,
799 "roots": roots,
800 "sort": sort,
800 "sort": sort,
801 "tag": tag,
801 "tag": tag,
802 "tagged": tagged,
802 "tagged": tagged,
803 "user": user,
803 "user": user,
804 }
804 }
805
805
806 methods = {
806 methods = {
807 "range": rangeset,
807 "range": rangeset,
808 "string": stringset,
808 "string": stringset,
809 "symbol": symbolset,
809 "symbol": symbolset,
810 "and": andset,
810 "and": andset,
811 "or": orset,
811 "or": orset,
812 "not": notset,
812 "not": notset,
813 "list": listset,
813 "list": listset,
814 "func": func,
814 "func": func,
815 "ancestor": ancestorspec,
815 "ancestor": ancestorspec,
816 "parent": parentspec,
816 "parent": parentspec,
817 "parentpost": p1,
817 "parentpost": p1,
818 }
818 }
819
819
820 def optimize(x, small):
820 def optimize(x, small):
821 if x is None:
821 if x is None:
822 return 0, x
822 return 0, x
823
823
824 smallbonus = 1
824 smallbonus = 1
825 if small:
825 if small:
826 smallbonus = .5
826 smallbonus = .5
827
827
828 op = x[0]
828 op = x[0]
829 if op == 'minus':
829 if op == 'minus':
830 return optimize(('and', x[1], ('not', x[2])), small)
830 return optimize(('and', x[1], ('not', x[2])), small)
831 elif op == 'dagrange':
831 elif op == 'dagrange':
832 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
832 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
833 ('func', ('symbol', 'ancestors'), x[2])), small)
833 ('func', ('symbol', 'ancestors'), x[2])), small)
834 elif op == 'dagrangepre':
834 elif op == 'dagrangepre':
835 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
835 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
836 elif op == 'dagrangepost':
836 elif op == 'dagrangepost':
837 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
837 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
838 elif op == 'rangepre':
838 elif op == 'rangepre':
839 return optimize(('range', ('string', '0'), x[1]), small)
839 return optimize(('range', ('string', '0'), x[1]), small)
840 elif op == 'rangepost':
840 elif op == 'rangepost':
841 return optimize(('range', x[1], ('string', 'tip')), small)
841 return optimize(('range', x[1], ('string', 'tip')), small)
842 elif op == 'negate':
842 elif op == 'negate':
843 return optimize(('string',
843 return optimize(('string',
844 '-' + getstring(x[1], _("can't negate that"))), small)
844 '-' + getstring(x[1], _("can't negate that"))), small)
845 elif op in 'string symbol negate':
845 elif op in 'string symbol negate':
846 return smallbonus, x # single revisions are small
846 return smallbonus, x # single revisions are small
847 elif op == 'and' or op == 'dagrange':
847 elif op == 'and' or op == 'dagrange':
848 wa, ta = optimize(x[1], True)
848 wa, ta = optimize(x[1], True)
849 wb, tb = optimize(x[2], True)
849 wb, tb = optimize(x[2], True)
850 w = min(wa, wb)
850 w = min(wa, wb)
851 if wa > wb:
851 if wa > wb:
852 return w, (op, tb, ta)
852 return w, (op, tb, ta)
853 return w, (op, ta, tb)
853 return w, (op, ta, tb)
854 elif op == 'or':
854 elif op == 'or':
855 wa, ta = optimize(x[1], False)
855 wa, ta = optimize(x[1], False)
856 wb, tb = optimize(x[2], False)
856 wb, tb = optimize(x[2], False)
857 if wb < wa:
857 if wb < wa:
858 wb, wa = wa, wb
858 wb, wa = wa, wb
859 return max(wa, wb), (op, ta, tb)
859 return max(wa, wb), (op, ta, tb)
860 elif op == 'not':
860 elif op == 'not':
861 o = optimize(x[1], not small)
861 o = optimize(x[1], not small)
862 return o[0], (op, o[1])
862 return o[0], (op, o[1])
863 elif op == 'parentpost':
863 elif op == 'parentpost':
864 o = optimize(x[1], small)
864 o = optimize(x[1], small)
865 return o[0], (op, o[1])
865 return o[0], (op, o[1])
866 elif op == 'group':
866 elif op == 'group':
867 return optimize(x[1], small)
867 return optimize(x[1], small)
868 elif op in 'range list parent ancestorspec':
868 elif op in 'range list parent ancestorspec':
869 wa, ta = optimize(x[1], small)
869 wa, ta = optimize(x[1], small)
870 wb, tb = optimize(x[2], small)
870 wb, tb = optimize(x[2], small)
871 return wa + wb, (op, ta, tb)
871 return wa + wb, (op, ta, tb)
872 elif op == 'func':
872 elif op == 'func':
873 f = getstring(x[1], _("not a symbol"))
873 f = getstring(x[1], _("not a symbol"))
874 wa, ta = optimize(x[2], small)
874 wa, ta = optimize(x[2], small)
875 if f in "grep date user author keyword branch file outgoing closed":
875 if f in "grep date user author keyword branch file outgoing closed":
876 w = 10 # slow
876 w = 10 # slow
877 elif f in "modifies adds removes":
877 elif f in "modifies adds removes":
878 w = 30 # slower
878 w = 30 # slower
879 elif f == "contains":
879 elif f == "contains":
880 w = 100 # very slow
880 w = 100 # very slow
881 elif f == "ancestor":
881 elif f == "ancestor":
882 w = 1 * smallbonus
882 w = 1 * smallbonus
883 elif f in "reverse limit":
883 elif f in "reverse limit":
884 w = 0
884 w = 0
885 elif f in "sort":
885 elif f in "sort":
886 w = 10 # assume most sorts look at changelog
886 w = 10 # assume most sorts look at changelog
887 else:
887 else:
888 w = 1
888 w = 1
889 return w + wa, (op, x[1], ta)
889 return w + wa, (op, x[1], ta)
890 return 1, x
890 return 1, x
891
891
892 class revsetalias(object):
893 funcre = re.compile('^([^(]+)\(([^)]+)\)$')
894 args = ()
895
896 def __init__(self, token, value):
897 '''Aliases like:
898
899 h = heads(default)
900 b($1) = ancestors($1) - ancestors(default)
901 '''
902 if isinstance(token, tuple):
903 self.type, self.name = token
904 else:
905 m = self.funcre.search(token)
906 if m:
907 self.type = 'func'
908 self.name = m.group(1)
909 self.args = [x.strip() for x in m.group(2).split(',')]
910 else:
911 self.type = 'symbol'
912 self.name = token
913
914 if isinstance(value, str):
915 for arg in self.args:
916 value = value.replace(arg, repr(arg))
917 self.replacement, pos = parse(value)
918 if pos != len(value):
919 raise error.ParseError('invalid token', pos)
920 else:
921 self.replacement = value
922
923 def match(self, tree):
924 if not tree:
925 return False
926 if tree == (self.type, self.name):
927 return True
928 if tree[0] != self.type:
929 return False
930 if len(tree) > 1 and tree[1] != ('symbol', self.name):
931 return False
932 # 'func' + funcname + args
933 if ((self.args and len(tree) != 3) or
934 (len(self.args) == 1 and tree[2][0] == 'list') or
935 (len(self.args) > 1 and (tree[2][0] != 'list' or
936 len(tree[2]) - 1 != len(self.args)))):
937 raise error.ParseError('invalid amount of arguments', len(tree) - 2)
938 return True
939
940 def replace(self, tree):
941 if tree == (self.type, self.name):
942 return self.replacement
943 result = self.replacement
944 def getsubtree(i):
945 if tree[2][0] == 'list':
946 return tree[2][i + 1]
947 return tree[i + 2]
948 for i, v in enumerate(self.args):
949 valalias = revsetalias(('string', v), getsubtree(i))
950 result = valalias.process(result)
951 return result
952
953 def process(self, tree):
954 if self.match(tree):
955 return self.replace(tree)
956 if isinstance(tree, tuple):
957 return tuple(map(self.process, tree))
958 return tree
959
960 def findaliases(ui, tree):
961 for k, v in ui.configitems('revsetalias'):
962 alias = revsetalias(k, v)
963 tree = alias.process(tree)
964 return tree
965
892 parse = parser.parser(tokenize, elements).parse
966 parse = parser.parser(tokenize, elements).parse
893
967
894 def match(spec):
968 def match(ui, spec):
895 if not spec:
969 if not spec:
896 raise error.ParseError(_("empty query"))
970 raise error.ParseError(_("empty query"))
897 tree, pos = parse(spec)
971 tree, pos = parse(spec)
898 if (pos != len(spec)):
972 if (pos != len(spec)):
899 raise error.ParseError("invalid token", pos)
973 raise error.ParseError("invalid token", pos)
974 tree = findaliases(ui, tree)
900 weight, tree = optimize(tree, True)
975 weight, tree = optimize(tree, True)
901 def mfunc(repo, subset):
976 def mfunc(repo, subset):
902 return getset(repo, subset, tree)
977 return getset(repo, subset, tree)
903 return mfunc
978 return mfunc
904
979
905 def makedoc(topic, doc):
980 def makedoc(topic, doc):
906 return help.makeitemsdoc(topic, doc, '.. predicatesmarker', symbols)
981 return help.makeitemsdoc(topic, doc, '.. predicatesmarker', symbols)
907
982
908 # tell hggettext to extract docstrings from these functions:
983 # tell hggettext to extract docstrings from these functions:
909 i18nfunctions = symbols.values()
984 i18nfunctions = symbols.values()
@@ -1,413 +1,437
1 $ HGENCODING=utf-8
1 $ HGENCODING=utf-8
2 $ export HGENCODING
2 $ export HGENCODING
3
3
4 $ try() {
4 $ try() {
5 > hg debugrevspec --debug $@
5 > hg debugrevspec --debug "$@"
6 > }
6 > }
7
7
8 $ log() {
8 $ log() {
9 > hg log --template '{rev}\n' -r "$1"
9 > hg log --template '{rev}\n' -r "$1"
10 > }
10 > }
11
11
12 $ hg init repo
12 $ hg init repo
13 $ cd repo
13 $ cd repo
14
14
15 $ echo a > a
15 $ echo a > a
16 $ hg branch a
16 $ hg branch a
17 marked working directory as branch a
17 marked working directory as branch a
18 $ hg ci -Aqm0
18 $ hg ci -Aqm0
19
19
20 $ echo b > b
20 $ echo b > b
21 $ hg branch b
21 $ hg branch b
22 marked working directory as branch b
22 marked working directory as branch b
23 $ hg ci -Aqm1
23 $ hg ci -Aqm1
24
24
25 $ rm a
25 $ rm a
26 $ hg branch a-b-c-
26 $ hg branch a-b-c-
27 marked working directory as branch a-b-c-
27 marked working directory as branch a-b-c-
28 $ hg ci -Aqm2 -u Bob
28 $ hg ci -Aqm2 -u Bob
29
29
30 $ hg co 1
30 $ hg co 1
31 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
31 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
32 $ hg branch +a+b+c+
32 $ hg branch +a+b+c+
33 marked working directory as branch +a+b+c+
33 marked working directory as branch +a+b+c+
34 $ hg ci -Aqm3
34 $ hg ci -Aqm3
35
35
36 $ hg co 2 # interleave
36 $ hg co 2 # interleave
37 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
37 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
38 $ echo bb > b
38 $ echo bb > b
39 $ hg branch -- -a-b-c-
39 $ hg branch -- -a-b-c-
40 marked working directory as branch -a-b-c-
40 marked working directory as branch -a-b-c-
41 $ hg ci -Aqm4 -d "May 12 2005"
41 $ hg ci -Aqm4 -d "May 12 2005"
42
42
43 $ hg co 3
43 $ hg co 3
44 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
44 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 $ hg branch /a/b/c/
45 $ hg branch /a/b/c/
46 marked working directory as branch /a/b/c/
46 marked working directory as branch /a/b/c/
47 $ hg ci -Aqm"5 bug"
47 $ hg ci -Aqm"5 bug"
48
48
49 $ hg merge 4
49 $ hg merge 4
50 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
50 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
51 (branch merge, don't forget to commit)
51 (branch merge, don't forget to commit)
52 $ hg branch _a_b_c_
52 $ hg branch _a_b_c_
53 marked working directory as branch _a_b_c_
53 marked working directory as branch _a_b_c_
54 $ hg ci -Aqm"6 issue619"
54 $ hg ci -Aqm"6 issue619"
55
55
56 $ hg branch .a.b.c.
56 $ hg branch .a.b.c.
57 marked working directory as branch .a.b.c.
57 marked working directory as branch .a.b.c.
58 $ hg ci -Aqm7
58 $ hg ci -Aqm7
59
59
60 $ hg branch all
60 $ hg branch all
61 marked working directory as branch all
61 marked working directory as branch all
62 $ hg ci --close-branch -Aqm8
62 $ hg ci --close-branch -Aqm8
63 abort: can only close branch heads
63 abort: can only close branch heads
64 [255]
64 [255]
65
65
66 $ hg co 4
66 $ hg co 4
67 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
67 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
68 $ hg branch Γ©
68 $ hg branch Γ©
69 marked working directory as branch \xc3\xa9 (esc)
69 marked working directory as branch \xc3\xa9 (esc)
70 $ hg ci -Aqm9
70 $ hg ci -Aqm9
71
71
72 $ hg tag -r6 1.0
72 $ hg tag -r6 1.0
73
73
74 $ hg clone --quiet -U -r 7 . ../remote1
74 $ hg clone --quiet -U -r 7 . ../remote1
75 $ hg clone --quiet -U -r 8 . ../remote2
75 $ hg clone --quiet -U -r 8 . ../remote2
76 $ echo "[paths]" >> .hg/hgrc
76 $ echo "[paths]" >> .hg/hgrc
77 $ echo "default = ../remote1" >> .hg/hgrc
77 $ echo "default = ../remote1" >> .hg/hgrc
78
78
79 names that should work without quoting
79 names that should work without quoting
80
80
81 $ try a
81 $ try a
82 ('symbol', 'a')
82 ('symbol', 'a')
83 0
83 0
84 $ try b-a
84 $ try b-a
85 ('minus', ('symbol', 'b'), ('symbol', 'a'))
85 ('minus', ('symbol', 'b'), ('symbol', 'a'))
86 1
86 1
87 $ try _a_b_c_
87 $ try _a_b_c_
88 ('symbol', '_a_b_c_')
88 ('symbol', '_a_b_c_')
89 6
89 6
90 $ try _a_b_c_-a
90 $ try _a_b_c_-a
91 ('minus', ('symbol', '_a_b_c_'), ('symbol', 'a'))
91 ('minus', ('symbol', '_a_b_c_'), ('symbol', 'a'))
92 6
92 6
93 $ try .a.b.c.
93 $ try .a.b.c.
94 ('symbol', '.a.b.c.')
94 ('symbol', '.a.b.c.')
95 7
95 7
96 $ try .a.b.c.-a
96 $ try .a.b.c.-a
97 ('minus', ('symbol', '.a.b.c.'), ('symbol', 'a'))
97 ('minus', ('symbol', '.a.b.c.'), ('symbol', 'a'))
98 7
98 7
99 $ try -- '-a-b-c-' # complains
99 $ try -- '-a-b-c-' # complains
100 hg: parse error at 7: not a prefix: end
100 hg: parse error at 7: not a prefix: end
101 [255]
101 [255]
102 $ log -a-b-c- # succeeds with fallback
102 $ log -a-b-c- # succeeds with fallback
103 4
103 4
104 $ try -- -a-b-c--a # complains
104 $ try -- -a-b-c--a # complains
105 ('minus', ('minus', ('minus', ('negate', ('symbol', 'a')), ('symbol', 'b')), ('symbol', 'c')), ('negate', ('symbol', 'a')))
105 ('minus', ('minus', ('minus', ('negate', ('symbol', 'a')), ('symbol', 'b')), ('symbol', 'c')), ('negate', ('symbol', 'a')))
106 abort: unknown revision '-a'!
106 abort: unknown revision '-a'!
107 [255]
107 [255]
108 $ try Γ©
108 $ try Γ©
109 ('symbol', '\xc3\xa9')
109 ('symbol', '\xc3\xa9')
110 9
110 9
111
111
112 quoting needed
112 quoting needed
113
113
114 $ try '"-a-b-c-"-a'
114 $ try '"-a-b-c-"-a'
115 ('minus', ('string', '-a-b-c-'), ('symbol', 'a'))
115 ('minus', ('string', '-a-b-c-'), ('symbol', 'a'))
116 4
116 4
117
117
118 $ log '1 or 2'
118 $ log '1 or 2'
119 1
119 1
120 2
120 2
121 $ log '1|2'
121 $ log '1|2'
122 1
122 1
123 2
123 2
124 $ log '1 and 2'
124 $ log '1 and 2'
125 $ log '1&2'
125 $ log '1&2'
126 $ try '1&2|3' # precedence - and is higher
126 $ try '1&2|3' # precedence - and is higher
127 ('or', ('and', ('symbol', '1'), ('symbol', '2')), ('symbol', '3'))
127 ('or', ('and', ('symbol', '1'), ('symbol', '2')), ('symbol', '3'))
128 3
128 3
129 $ try '1|2&3'
129 $ try '1|2&3'
130 ('or', ('symbol', '1'), ('and', ('symbol', '2'), ('symbol', '3')))
130 ('or', ('symbol', '1'), ('and', ('symbol', '2'), ('symbol', '3')))
131 1
131 1
132 $ try '1&2&3' # associativity
132 $ try '1&2&3' # associativity
133 ('and', ('and', ('symbol', '1'), ('symbol', '2')), ('symbol', '3'))
133 ('and', ('and', ('symbol', '1'), ('symbol', '2')), ('symbol', '3'))
134 $ try '1|(2|3)'
134 $ try '1|(2|3)'
135 ('or', ('symbol', '1'), ('group', ('or', ('symbol', '2'), ('symbol', '3'))))
135 ('or', ('symbol', '1'), ('group', ('or', ('symbol', '2'), ('symbol', '3'))))
136 1
136 1
137 2
137 2
138 3
138 3
139 $ log '1.0' # tag
139 $ log '1.0' # tag
140 6
140 6
141 $ log 'a' # branch
141 $ log 'a' # branch
142 0
142 0
143 $ log '2785f51ee'
143 $ log '2785f51ee'
144 0
144 0
145 $ log 'date(2005)'
145 $ log 'date(2005)'
146 4
146 4
147 $ log 'date(this is a test)'
147 $ log 'date(this is a test)'
148 hg: parse error at 10: unexpected token: symbol
148 hg: parse error at 10: unexpected token: symbol
149 [255]
149 [255]
150 $ log 'date()'
150 $ log 'date()'
151 hg: parse error: date requires a string
151 hg: parse error: date requires a string
152 [255]
152 [255]
153 $ log 'date'
153 $ log 'date'
154 hg: parse error: can't use date here
154 hg: parse error: can't use date here
155 [255]
155 [255]
156 $ log 'date('
156 $ log 'date('
157 hg: parse error at 5: not a prefix: end
157 hg: parse error at 5: not a prefix: end
158 [255]
158 [255]
159 $ log 'date(tip)'
159 $ log 'date(tip)'
160 abort: invalid date: 'tip'
160 abort: invalid date: 'tip'
161 [255]
161 [255]
162 $ log '"date"'
162 $ log '"date"'
163 abort: unknown revision 'date'!
163 abort: unknown revision 'date'!
164 [255]
164 [255]
165 $ log 'date(2005) and 1::'
165 $ log 'date(2005) and 1::'
166 4
166 4
167
167
168 $ log 'ancestor(1)'
168 $ log 'ancestor(1)'
169 hg: parse error: ancestor requires two arguments
169 hg: parse error: ancestor requires two arguments
170 [255]
170 [255]
171 $ log 'ancestor(4,5)'
171 $ log 'ancestor(4,5)'
172 1
172 1
173 $ log 'ancestor(4,5) and 4'
173 $ log 'ancestor(4,5) and 4'
174 $ log 'ancestors(5)'
174 $ log 'ancestors(5)'
175 0
175 0
176 1
176 1
177 3
177 3
178 5
178 5
179 $ log 'author(bob)'
179 $ log 'author(bob)'
180 2
180 2
181 $ log 'branch(Γ©)'
181 $ log 'branch(Γ©)'
182 8
182 8
183 9
183 9
184 $ log 'children(ancestor(4,5))'
184 $ log 'children(ancestor(4,5))'
185 2
185 2
186 3
186 3
187 $ log 'closed()'
187 $ log 'closed()'
188 $ log 'contains(a)'
188 $ log 'contains(a)'
189 0
189 0
190 1
190 1
191 3
191 3
192 5
192 5
193 $ log 'descendants(2 or 3)'
193 $ log 'descendants(2 or 3)'
194 2
194 2
195 3
195 3
196 4
196 4
197 5
197 5
198 6
198 6
199 7
199 7
200 8
200 8
201 9
201 9
202 $ log 'file(b)'
202 $ log 'file(b)'
203 1
203 1
204 4
204 4
205 $ log 'follow()'
205 $ log 'follow()'
206 0
206 0
207 1
207 1
208 2
208 2
209 4
209 4
210 8
210 8
211 9
211 9
212 $ log 'grep("issue\d+")'
212 $ log 'grep("issue\d+")'
213 6
213 6
214 $ try 'grep("(")' # invalid regular expression
214 $ try 'grep("(")' # invalid regular expression
215 ('func', ('symbol', 'grep'), ('string', '('))
215 ('func', ('symbol', 'grep'), ('string', '('))
216 hg: parse error: invalid match pattern: unbalanced parenthesis
216 hg: parse error: invalid match pattern: unbalanced parenthesis
217 [255]
217 [255]
218 $ try 'grep("\bissue\d+")'
218 $ try 'grep("\bissue\d+")'
219 ('func', ('symbol', 'grep'), ('string', '\x08issue\\d+'))
219 ('func', ('symbol', 'grep'), ('string', '\x08issue\\d+'))
220 $ try 'grep(r"\bissue\d+")'
220 $ try 'grep(r"\bissue\d+")'
221 ('func', ('symbol', 'grep'), ('string', '\\bissue\\d+'))
221 ('func', ('symbol', 'grep'), ('string', '\\bissue\\d+'))
222 6
222 6
223 $ try 'grep(r"\")'
223 $ try 'grep(r"\")'
224 hg: parse error at 7: unterminated string
224 hg: parse error at 7: unterminated string
225 [255]
225 [255]
226 $ log 'head()'
226 $ log 'head()'
227 0
227 0
228 1
228 1
229 2
229 2
230 3
230 3
231 4
231 4
232 5
232 5
233 6
233 6
234 7
234 7
235 9
235 9
236 $ log 'heads(6::)'
236 $ log 'heads(6::)'
237 7
237 7
238 $ log 'keyword(issue)'
238 $ log 'keyword(issue)'
239 6
239 6
240 $ log 'limit(head(), 1)'
240 $ log 'limit(head(), 1)'
241 0
241 0
242 $ log 'max(contains(a))'
242 $ log 'max(contains(a))'
243 5
243 5
244 $ log 'min(contains(a))'
244 $ log 'min(contains(a))'
245 0
245 0
246 $ log 'merge()'
246 $ log 'merge()'
247 6
247 6
248 $ log 'modifies(b)'
248 $ log 'modifies(b)'
249 4
249 4
250 $ log 'id(5)'
250 $ log 'id(5)'
251 2
251 2
252 $ log 'outgoing()'
252 $ log 'outgoing()'
253 8
253 8
254 9
254 9
255 $ log 'outgoing("../remote1")'
255 $ log 'outgoing("../remote1")'
256 8
256 8
257 9
257 9
258 $ log 'outgoing("../remote2")'
258 $ log 'outgoing("../remote2")'
259 3
259 3
260 5
260 5
261 6
261 6
262 7
262 7
263 9
263 9
264 $ log 'p1(merge())'
264 $ log 'p1(merge())'
265 5
265 5
266 $ log 'p2(merge())'
266 $ log 'p2(merge())'
267 4
267 4
268 $ log 'parents(merge())'
268 $ log 'parents(merge())'
269 4
269 4
270 5
270 5
271 $ log 'removes(a)'
271 $ log 'removes(a)'
272 2
272 2
273 6
273 6
274 $ log 'roots(all())'
274 $ log 'roots(all())'
275 0
275 0
276 $ log 'reverse(2 or 3 or 4 or 5)'
276 $ log 'reverse(2 or 3 or 4 or 5)'
277 5
277 5
278 4
278 4
279 3
279 3
280 2
280 2
281 $ log 'rev(5)'
281 $ log 'rev(5)'
282 5
282 5
283 $ log 'sort(limit(reverse(all()), 3))'
283 $ log 'sort(limit(reverse(all()), 3))'
284 7
284 7
285 8
285 8
286 9
286 9
287 $ log 'sort(2 or 3 or 4 or 5, date)'
287 $ log 'sort(2 or 3 or 4 or 5, date)'
288 2
288 2
289 3
289 3
290 5
290 5
291 4
291 4
292 $ log 'tagged()'
292 $ log 'tagged()'
293 6
293 6
294 $ log 'tag()'
294 $ log 'tag()'
295 6
295 6
296 $ log 'tag(1.0)'
296 $ log 'tag(1.0)'
297 6
297 6
298 $ log 'tag(tip)'
298 $ log 'tag(tip)'
299 9
299 9
300 $ log 'tag(unknown)'
300 $ log 'tag(unknown)'
301 abort: tag 'unknown' does not exist
301 abort: tag 'unknown' does not exist
302 [255]
302 [255]
303 $ log 'branch(unknown)'
303 $ log 'branch(unknown)'
304 abort: unknown revision 'unknown'!
304 abort: unknown revision 'unknown'!
305 [255]
305 [255]
306 $ log 'user(bob)'
306 $ log 'user(bob)'
307 2
307 2
308
308
309 $ log '4::8'
309 $ log '4::8'
310 4
310 4
311 8
311 8
312 $ log '4:8'
312 $ log '4:8'
313 4
313 4
314 5
314 5
315 6
315 6
316 7
316 7
317 8
317 8
318
318
319 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
319 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
320 4
320 4
321 2
321 2
322 5
322 5
323
323
324 $ log 'not 0 and 0:2'
324 $ log 'not 0 and 0:2'
325 1
325 1
326 2
326 2
327 $ log 'not 1 and 0:2'
327 $ log 'not 1 and 0:2'
328 0
328 0
329 2
329 2
330 $ log 'not 2 and 0:2'
330 $ log 'not 2 and 0:2'
331 0
331 0
332 1
332 1
333 $ log '(1 and 2)::'
333 $ log '(1 and 2)::'
334 $ log '(1 and 2):'
334 $ log '(1 and 2):'
335 $ log '(1 and 2):3'
335 $ log '(1 and 2):3'
336 $ log 'sort(head(), -rev)'
336 $ log 'sort(head(), -rev)'
337 9
337 9
338 7
338 7
339 6
339 6
340 5
340 5
341 4
341 4
342 3
342 3
343 2
343 2
344 1
344 1
345 0
345 0
346 $ log '4::8 - 8'
346 $ log '4::8 - 8'
347 4
347 4
348
348
349 issue2437
349 issue2437
350
350
351 $ log '3 and p1(5)'
351 $ log '3 and p1(5)'
352 3
352 3
353 $ log '4 and p2(6)'
353 $ log '4 and p2(6)'
354 4
354 4
355 $ log '1 and parents(:2)'
355 $ log '1 and parents(:2)'
356 1
356 1
357 $ log '2 and children(1:)'
357 $ log '2 and children(1:)'
358 2
358 2
359 $ log 'roots(all()) or roots(all())'
359 $ log 'roots(all()) or roots(all())'
360 0
360 0
361 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
361 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
362 9
362 9
363 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
363 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
364 4
364 4
365
365
366 issue2654: report a parse error if the revset was not completely parsed
366 issue2654: report a parse error if the revset was not completely parsed
367
367
368 $ log '1 OR 2'
368 $ log '1 OR 2'
369 hg: parse error at 2: invalid token
369 hg: parse error at 2: invalid token
370 [255]
370 [255]
371
371
372 or operator should preserve ordering:
372 or operator should preserve ordering:
373 $ log 'reverse(2::4) or tip'
373 $ log 'reverse(2::4) or tip'
374 4
374 4
375 2
375 2
376 9
376 9
377
377
378 parentrevspec
378 parentrevspec
379
379
380 $ log 'merge()^0'
380 $ log 'merge()^0'
381 6
381 6
382 $ log 'merge()^'
382 $ log 'merge()^'
383 5
383 5
384 $ log 'merge()^1'
384 $ log 'merge()^1'
385 5
385 5
386 $ log 'merge()^2'
386 $ log 'merge()^2'
387 4
387 4
388 $ log 'merge()^^'
388 $ log 'merge()^^'
389 3
389 3
390 $ log 'merge()^1^'
390 $ log 'merge()^1^'
391 3
391 3
392 $ log 'merge()^^^'
392 $ log 'merge()^^^'
393 1
393 1
394
394
395 $ log 'merge()~0'
395 $ log 'merge()~0'
396 6
396 6
397 $ log 'merge()~1'
397 $ log 'merge()~1'
398 5
398 5
399 $ log 'merge()~2'
399 $ log 'merge()~2'
400 3
400 3
401 $ log 'merge()~2^1'
401 $ log 'merge()~2^1'
402 1
402 1
403 $ log 'merge()~3'
403 $ log 'merge()~3'
404 1
404 1
405
405
406 $ log '(-3:tip)^'
406 $ log '(-3:tip)^'
407 4
407 4
408 6
408 6
409 8
409 8
410
410
411 $ log 'tip^foo'
411 $ log 'tip^foo'
412 hg: parse error: ^ expects a number 0, 1, or 2
412 hg: parse error: ^ expects a number 0, 1, or 2
413 [255]
413 [255]
414
415 aliases:
416
417 $ echo '[revsetalias]' >> .hg/hgrc
418 $ echo 'm = merge()' >> .hg/hgrc
419 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
420 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
421
422 $ try m
423 ('symbol', 'm')
424 ('func', ('symbol', 'merge'), None)
425 6
426 $ try 'd(2:5)'
427 ('func', ('symbol', 'd'), ('range', ('symbol', '2'), ('symbol', '5')))
428 ('func', ('symbol', 'reverse'), ('func', ('symbol', 'sort'), ('list', ('range', ('symbol', '2'), ('symbol', '5')), ('symbol', 'date'))))
429 4
430 5
431 3
432 2
433 $ try 'rs(2 or 3, date)'
434 ('func', ('symbol', 'rs'), ('list', ('or', ('symbol', '2'), ('symbol', '3')), ('symbol', 'date')))
435 ('func', ('symbol', 'reverse'), ('func', ('symbol', 'sort'), ('list', ('or', ('symbol', '2'), ('symbol', '3')), ('symbol', 'date'))))
436 3
437 2
General Comments 0
You need to be logged in to leave comments. Login now