##// END OF EJS Templates
add: recurse into subrepositories with --subrepos/-S flag
Martin Geisler -
r12270:166b9866 default
parent child Browse files
Show More
@@ -1,1352 +1,1365 b''
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, templater, patch, error, encoding, templatekw
11 import util, templater, patch, error, encoding, 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.parents()[1] != nullid:
75 if repo.dirstate.parents()[1] != 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 revpair(repo, revs):
114 def revpair(repo, revs):
115 '''return pair of nodes, given list of revisions. second item can
115 '''return pair of nodes, given list of revisions. second item can
116 be None, meaning use working dir.'''
116 be None, meaning use working dir.'''
117
117
118 def revfix(repo, val, defval):
118 def revfix(repo, val, defval):
119 if not val and val != 0 and defval is not None:
119 if not val and val != 0 and defval is not None:
120 val = defval
120 val = defval
121 return repo.lookup(val)
121 return repo.lookup(val)
122
122
123 if not revs:
123 if not revs:
124 return repo.dirstate.parents()[0], None
124 return repo.dirstate.parents()[0], None
125 end = None
125 end = None
126 if len(revs) == 1:
126 if len(revs) == 1:
127 if revrangesep in revs[0]:
127 if revrangesep in revs[0]:
128 start, end = revs[0].split(revrangesep, 1)
128 start, end = revs[0].split(revrangesep, 1)
129 start = revfix(repo, start, 0)
129 start = revfix(repo, start, 0)
130 end = revfix(repo, end, len(repo) - 1)
130 end = revfix(repo, end, len(repo) - 1)
131 else:
131 else:
132 start = revfix(repo, revs[0], None)
132 start = revfix(repo, revs[0], None)
133 elif len(revs) == 2:
133 elif len(revs) == 2:
134 if revrangesep in revs[0] or revrangesep in revs[1]:
134 if revrangesep in revs[0] or revrangesep in revs[1]:
135 raise util.Abort(_('too many revisions specified'))
135 raise util.Abort(_('too many revisions specified'))
136 start = revfix(repo, revs[0], None)
136 start = revfix(repo, revs[0], None)
137 end = revfix(repo, revs[1], None)
137 end = revfix(repo, revs[1], None)
138 else:
138 else:
139 raise util.Abort(_('too many revisions specified'))
139 raise util.Abort(_('too many revisions specified'))
140 return start, end
140 return start, end
141
141
142 def revrange(repo, revs):
142 def revrange(repo, revs):
143 """Yield revision as strings from a list of revision specifications."""
143 """Yield revision as strings from a list of revision specifications."""
144
144
145 def revfix(repo, val, defval):
145 def revfix(repo, val, defval):
146 if not val and val != 0 and defval is not None:
146 if not val and val != 0 and defval is not None:
147 return defval
147 return defval
148 return repo.changelog.rev(repo.lookup(val))
148 return repo.changelog.rev(repo.lookup(val))
149
149
150 seen, l = set(), []
150 seen, l = set(), []
151 for spec in revs:
151 for spec in revs:
152 # attempt to parse old-style ranges first to deal with
152 # attempt to parse old-style ranges first to deal with
153 # things like old-tag which contain query metacharacters
153 # things like old-tag which contain query metacharacters
154 try:
154 try:
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(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 = 'w' in mode or 'a' in mode
233 writable = 'w' in mode or 'a' in mode
234
234
235 if not pat or pat == '-':
235 if not pat or pat == '-':
236 return writable and sys.stdout or sys.stdin
236 return writable and sys.stdout or sys.stdin
237 if hasattr(pat, 'write') and writable:
237 if hasattr(pat, 'write') and writable:
238 return pat
238 return pat
239 if hasattr(pat, 'read') and 'r' in mode:
239 if hasattr(pat, 'read') and 'r' in mode:
240 return pat
240 return pat
241 return open(make_filename(repo, pat, node, total, seqno, revwidth,
241 return open(make_filename(repo, pat, node, total, seqno, revwidth,
242 pathname),
242 pathname),
243 mode)
243 mode)
244
244
245 def expandpats(pats):
245 def expandpats(pats):
246 if not util.expandglobs:
246 if not util.expandglobs:
247 return list(pats)
247 return list(pats)
248 ret = []
248 ret = []
249 for p in pats:
249 for p in pats:
250 kind, name = matchmod._patsplit(p, None)
250 kind, name = matchmod._patsplit(p, None)
251 if kind is None:
251 if kind is None:
252 try:
252 try:
253 globbed = glob.glob(name)
253 globbed = glob.glob(name)
254 except re.error:
254 except re.error:
255 globbed = [name]
255 globbed = [name]
256 if globbed:
256 if globbed:
257 ret.extend(globbed)
257 ret.extend(globbed)
258 continue
258 continue
259 ret.append(p)
259 ret.append(p)
260 return ret
260 return ret
261
261
262 def match(repo, pats=[], opts={}, globbed=False, default='relpath'):
262 def match(repo, pats=[], opts={}, globbed=False, default='relpath'):
263 if not globbed and default == 'relpath':
263 if not globbed and default == 'relpath':
264 pats = expandpats(pats or [])
264 pats = expandpats(pats or [])
265 m = matchmod.match(repo.root, repo.getcwd(), pats,
265 m = matchmod.match(repo.root, repo.getcwd(), pats,
266 opts.get('include'), opts.get('exclude'), default,
266 opts.get('include'), opts.get('exclude'), default,
267 auditor=repo.auditor)
267 auditor=repo.auditor)
268 def badfn(f, msg):
268 def badfn(f, msg):
269 repo.ui.warn("%s: %s\n" % (m.rel(f), msg))
269 repo.ui.warn("%s: %s\n" % (m.rel(f), msg))
270 m.bad = badfn
270 m.bad = badfn
271 return m
271 return m
272
272
273 def matchall(repo):
273 def matchall(repo):
274 return matchmod.always(repo.root, repo.getcwd())
274 return matchmod.always(repo.root, repo.getcwd())
275
275
276 def matchfiles(repo, files):
276 def matchfiles(repo, files):
277 return matchmod.exact(repo.root, repo.getcwd(), files)
277 return matchmod.exact(repo.root, repo.getcwd(), files)
278
278
279 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
279 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
280 if dry_run is None:
280 if dry_run is None:
281 dry_run = opts.get('dry_run')
281 dry_run = opts.get('dry_run')
282 if similarity is None:
282 if similarity is None:
283 similarity = float(opts.get('similarity') or 0)
283 similarity = float(opts.get('similarity') or 0)
284 # we'd use status here, except handling of symlinks and ignore is tricky
284 # we'd use status here, except handling of symlinks and ignore is tricky
285 added, unknown, deleted, removed = [], [], [], []
285 added, unknown, deleted, removed = [], [], [], []
286 audit_path = util.path_auditor(repo.root)
286 audit_path = util.path_auditor(repo.root)
287 m = match(repo, pats, opts)
287 m = match(repo, pats, opts)
288 for abs in repo.walk(m):
288 for abs in repo.walk(m):
289 target = repo.wjoin(abs)
289 target = repo.wjoin(abs)
290 good = True
290 good = True
291 try:
291 try:
292 audit_path(abs)
292 audit_path(abs)
293 except:
293 except:
294 good = False
294 good = False
295 rel = m.rel(abs)
295 rel = m.rel(abs)
296 exact = m.exact(abs)
296 exact = m.exact(abs)
297 if good and abs not in repo.dirstate:
297 if good and abs not in repo.dirstate:
298 unknown.append(abs)
298 unknown.append(abs)
299 if repo.ui.verbose or not exact:
299 if repo.ui.verbose or not exact:
300 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
300 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
301 elif repo.dirstate[abs] != 'r' and (not good or not os.path.lexists(target)
301 elif repo.dirstate[abs] != 'r' and (not good or not os.path.lexists(target)
302 or (os.path.isdir(target) and not os.path.islink(target))):
302 or (os.path.isdir(target) and not os.path.islink(target))):
303 deleted.append(abs)
303 deleted.append(abs)
304 if repo.ui.verbose or not exact:
304 if repo.ui.verbose or not exact:
305 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
305 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
306 # for finding renames
306 # for finding renames
307 elif repo.dirstate[abs] == 'r':
307 elif repo.dirstate[abs] == 'r':
308 removed.append(abs)
308 removed.append(abs)
309 elif repo.dirstate[abs] == 'a':
309 elif repo.dirstate[abs] == 'a':
310 added.append(abs)
310 added.append(abs)
311 copies = {}
311 copies = {}
312 if similarity > 0:
312 if similarity > 0:
313 for old, new, score in similar.findrenames(repo,
313 for old, new, score in similar.findrenames(repo,
314 added + unknown, removed + deleted, similarity):
314 added + unknown, removed + deleted, similarity):
315 if repo.ui.verbose or not m.exact(old) or not m.exact(new):
315 if repo.ui.verbose or not m.exact(old) or not m.exact(new):
316 repo.ui.status(_('recording removal of %s as rename to %s '
316 repo.ui.status(_('recording removal of %s as rename to %s '
317 '(%d%% similar)\n') %
317 '(%d%% similar)\n') %
318 (m.rel(old), m.rel(new), score * 100))
318 (m.rel(old), m.rel(new), score * 100))
319 copies[new] = old
319 copies[new] = old
320
320
321 if not dry_run:
321 if not dry_run:
322 wctx = repo[None]
322 wctx = repo[None]
323 wlock = repo.wlock()
323 wlock = repo.wlock()
324 try:
324 try:
325 wctx.remove(deleted)
325 wctx.remove(deleted)
326 wctx.add(unknown)
326 wctx.add(unknown)
327 for new, old in copies.iteritems():
327 for new, old in copies.iteritems():
328 wctx.copy(old, new)
328 wctx.copy(old, new)
329 finally:
329 finally:
330 wlock.release()
330 wlock.release()
331
331
332 def updatedir(ui, repo, patches, similarity=0):
332 def updatedir(ui, repo, patches, similarity=0):
333 '''Update dirstate after patch application according to metadata'''
333 '''Update dirstate after patch application according to metadata'''
334 if not patches:
334 if not patches:
335 return
335 return
336 copies = []
336 copies = []
337 removes = set()
337 removes = set()
338 cfiles = patches.keys()
338 cfiles = patches.keys()
339 cwd = repo.getcwd()
339 cwd = repo.getcwd()
340 if cwd:
340 if cwd:
341 cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()]
341 cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()]
342 for f in patches:
342 for f in patches:
343 gp = patches[f]
343 gp = patches[f]
344 if not gp:
344 if not gp:
345 continue
345 continue
346 if gp.op == 'RENAME':
346 if gp.op == 'RENAME':
347 copies.append((gp.oldpath, gp.path))
347 copies.append((gp.oldpath, gp.path))
348 removes.add(gp.oldpath)
348 removes.add(gp.oldpath)
349 elif gp.op == 'COPY':
349 elif gp.op == 'COPY':
350 copies.append((gp.oldpath, gp.path))
350 copies.append((gp.oldpath, gp.path))
351 elif gp.op == 'DELETE':
351 elif gp.op == 'DELETE':
352 removes.add(gp.path)
352 removes.add(gp.path)
353
353
354 wctx = repo[None]
354 wctx = repo[None]
355 for src, dst in copies:
355 for src, dst in copies:
356 wctx.copy(src, dst)
356 wctx.copy(src, dst)
357 if (not similarity) and removes:
357 if (not similarity) and removes:
358 wctx.remove(sorted(removes), True)
358 wctx.remove(sorted(removes), True)
359
359
360 for f in patches:
360 for f in patches:
361 gp = patches[f]
361 gp = patches[f]
362 if gp and gp.mode:
362 if gp and gp.mode:
363 islink, isexec = gp.mode
363 islink, isexec = gp.mode
364 dst = repo.wjoin(gp.path)
364 dst = repo.wjoin(gp.path)
365 # patch won't create empty files
365 # patch won't create empty files
366 if gp.op == 'ADD' and not os.path.exists(dst):
366 if gp.op == 'ADD' and not os.path.exists(dst):
367 flags = (isexec and 'x' or '') + (islink and 'l' or '')
367 flags = (isexec and 'x' or '') + (islink and 'l' or '')
368 repo.wwrite(gp.path, '', flags)
368 repo.wwrite(gp.path, '', flags)
369 util.set_flags(dst, islink, isexec)
369 util.set_flags(dst, islink, isexec)
370 addremove(repo, cfiles, similarity=similarity)
370 addremove(repo, cfiles, similarity=similarity)
371 files = patches.keys()
371 files = patches.keys()
372 files.extend([r for r in removes if r not in files])
372 files.extend([r for r in removes if r not in files])
373 return sorted(files)
373 return sorted(files)
374
374
375 def copy(ui, repo, pats, opts, rename=False):
375 def copy(ui, repo, pats, opts, rename=False):
376 # called with the repo lock held
376 # called with the repo lock held
377 #
377 #
378 # hgsep => pathname that uses "/" to separate directories
378 # hgsep => pathname that uses "/" to separate directories
379 # ossep => pathname that uses os.sep to separate directories
379 # ossep => pathname that uses os.sep to separate directories
380 cwd = repo.getcwd()
380 cwd = repo.getcwd()
381 targets = {}
381 targets = {}
382 after = opts.get("after")
382 after = opts.get("after")
383 dryrun = opts.get("dry_run")
383 dryrun = opts.get("dry_run")
384 wctx = repo[None]
384 wctx = repo[None]
385
385
386 def walkpat(pat):
386 def walkpat(pat):
387 srcs = []
387 srcs = []
388 badstates = after and '?' or '?r'
388 badstates = after and '?' or '?r'
389 m = match(repo, [pat], opts, globbed=True)
389 m = match(repo, [pat], opts, globbed=True)
390 for abs in repo.walk(m):
390 for abs in repo.walk(m):
391 state = repo.dirstate[abs]
391 state = repo.dirstate[abs]
392 rel = m.rel(abs)
392 rel = m.rel(abs)
393 exact = m.exact(abs)
393 exact = m.exact(abs)
394 if state in badstates:
394 if state in badstates:
395 if exact and state == '?':
395 if exact and state == '?':
396 ui.warn(_('%s: not copying - file is not managed\n') % rel)
396 ui.warn(_('%s: not copying - file is not managed\n') % rel)
397 if exact and state == 'r':
397 if exact and state == 'r':
398 ui.warn(_('%s: not copying - file has been marked for'
398 ui.warn(_('%s: not copying - file has been marked for'
399 ' remove\n') % rel)
399 ' remove\n') % rel)
400 continue
400 continue
401 # abs: hgsep
401 # abs: hgsep
402 # rel: ossep
402 # rel: ossep
403 srcs.append((abs, rel, exact))
403 srcs.append((abs, rel, exact))
404 return srcs
404 return srcs
405
405
406 # abssrc: hgsep
406 # abssrc: hgsep
407 # relsrc: ossep
407 # relsrc: ossep
408 # otarget: ossep
408 # otarget: ossep
409 def copyfile(abssrc, relsrc, otarget, exact):
409 def copyfile(abssrc, relsrc, otarget, exact):
410 abstarget = util.canonpath(repo.root, cwd, otarget)
410 abstarget = util.canonpath(repo.root, cwd, otarget)
411 reltarget = repo.pathto(abstarget, cwd)
411 reltarget = repo.pathto(abstarget, cwd)
412 target = repo.wjoin(abstarget)
412 target = repo.wjoin(abstarget)
413 src = repo.wjoin(abssrc)
413 src = repo.wjoin(abssrc)
414 state = repo.dirstate[abstarget]
414 state = repo.dirstate[abstarget]
415
415
416 # check for collisions
416 # check for collisions
417 prevsrc = targets.get(abstarget)
417 prevsrc = targets.get(abstarget)
418 if prevsrc is not None:
418 if prevsrc is not None:
419 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
419 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
420 (reltarget, repo.pathto(abssrc, cwd),
420 (reltarget, repo.pathto(abssrc, cwd),
421 repo.pathto(prevsrc, cwd)))
421 repo.pathto(prevsrc, cwd)))
422 return
422 return
423
423
424 # check for overwrites
424 # check for overwrites
425 exists = os.path.exists(target)
425 exists = os.path.exists(target)
426 if not after and exists or after and state in 'mn':
426 if not after and exists or after and state in 'mn':
427 if not opts['force']:
427 if not opts['force']:
428 ui.warn(_('%s: not overwriting - file exists\n') %
428 ui.warn(_('%s: not overwriting - file exists\n') %
429 reltarget)
429 reltarget)
430 return
430 return
431
431
432 if after:
432 if after:
433 if not exists:
433 if not exists:
434 if rename:
434 if rename:
435 ui.warn(_('%s: not recording move - %s does not exist\n') %
435 ui.warn(_('%s: not recording move - %s does not exist\n') %
436 (relsrc, reltarget))
436 (relsrc, reltarget))
437 else:
437 else:
438 ui.warn(_('%s: not recording copy - %s does not exist\n') %
438 ui.warn(_('%s: not recording copy - %s does not exist\n') %
439 (relsrc, reltarget))
439 (relsrc, reltarget))
440 return
440 return
441 elif not dryrun:
441 elif not dryrun:
442 try:
442 try:
443 if exists:
443 if exists:
444 os.unlink(target)
444 os.unlink(target)
445 targetdir = os.path.dirname(target) or '.'
445 targetdir = os.path.dirname(target) or '.'
446 if not os.path.isdir(targetdir):
446 if not os.path.isdir(targetdir):
447 os.makedirs(targetdir)
447 os.makedirs(targetdir)
448 util.copyfile(src, target)
448 util.copyfile(src, target)
449 except IOError, inst:
449 except IOError, inst:
450 if inst.errno == errno.ENOENT:
450 if inst.errno == errno.ENOENT:
451 ui.warn(_('%s: deleted in working copy\n') % relsrc)
451 ui.warn(_('%s: deleted in working copy\n') % relsrc)
452 else:
452 else:
453 ui.warn(_('%s: cannot copy - %s\n') %
453 ui.warn(_('%s: cannot copy - %s\n') %
454 (relsrc, inst.strerror))
454 (relsrc, inst.strerror))
455 return True # report a failure
455 return True # report a failure
456
456
457 if ui.verbose or not exact:
457 if ui.verbose or not exact:
458 if rename:
458 if rename:
459 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
459 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
460 else:
460 else:
461 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
461 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
462
462
463 targets[abstarget] = abssrc
463 targets[abstarget] = abssrc
464
464
465 # fix up dirstate
465 # fix up dirstate
466 origsrc = repo.dirstate.copied(abssrc) or abssrc
466 origsrc = repo.dirstate.copied(abssrc) or abssrc
467 if abstarget == origsrc: # copying back a copy?
467 if abstarget == origsrc: # copying back a copy?
468 if state not in 'mn' and not dryrun:
468 if state not in 'mn' and not dryrun:
469 repo.dirstate.normallookup(abstarget)
469 repo.dirstate.normallookup(abstarget)
470 else:
470 else:
471 if repo.dirstate[origsrc] == 'a' and origsrc == abssrc:
471 if repo.dirstate[origsrc] == 'a' and origsrc == abssrc:
472 if not ui.quiet:
472 if not ui.quiet:
473 ui.warn(_("%s has not been committed yet, so no copy "
473 ui.warn(_("%s has not been committed yet, so no copy "
474 "data will be stored for %s.\n")
474 "data will be stored for %s.\n")
475 % (repo.pathto(origsrc, cwd), reltarget))
475 % (repo.pathto(origsrc, cwd), reltarget))
476 if repo.dirstate[abstarget] in '?r' and not dryrun:
476 if repo.dirstate[abstarget] in '?r' and not dryrun:
477 wctx.add([abstarget])
477 wctx.add([abstarget])
478 elif not dryrun:
478 elif not dryrun:
479 wctx.copy(origsrc, abstarget)
479 wctx.copy(origsrc, abstarget)
480
480
481 if rename and not dryrun:
481 if rename and not dryrun:
482 wctx.remove([abssrc], not after)
482 wctx.remove([abssrc], not after)
483
483
484 # pat: ossep
484 # pat: ossep
485 # dest ossep
485 # dest ossep
486 # srcs: list of (hgsep, hgsep, ossep, bool)
486 # srcs: list of (hgsep, hgsep, ossep, bool)
487 # return: function that takes hgsep and returns ossep
487 # return: function that takes hgsep and returns ossep
488 def targetpathfn(pat, dest, srcs):
488 def targetpathfn(pat, dest, srcs):
489 if os.path.isdir(pat):
489 if os.path.isdir(pat):
490 abspfx = util.canonpath(repo.root, cwd, pat)
490 abspfx = util.canonpath(repo.root, cwd, pat)
491 abspfx = util.localpath(abspfx)
491 abspfx = util.localpath(abspfx)
492 if destdirexists:
492 if destdirexists:
493 striplen = len(os.path.split(abspfx)[0])
493 striplen = len(os.path.split(abspfx)[0])
494 else:
494 else:
495 striplen = len(abspfx)
495 striplen = len(abspfx)
496 if striplen:
496 if striplen:
497 striplen += len(os.sep)
497 striplen += len(os.sep)
498 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
498 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
499 elif destdirexists:
499 elif destdirexists:
500 res = lambda p: os.path.join(dest,
500 res = lambda p: os.path.join(dest,
501 os.path.basename(util.localpath(p)))
501 os.path.basename(util.localpath(p)))
502 else:
502 else:
503 res = lambda p: dest
503 res = lambda p: dest
504 return res
504 return res
505
505
506 # pat: ossep
506 # pat: ossep
507 # dest ossep
507 # dest ossep
508 # srcs: list of (hgsep, hgsep, ossep, bool)
508 # srcs: list of (hgsep, hgsep, ossep, bool)
509 # return: function that takes hgsep and returns ossep
509 # return: function that takes hgsep and returns ossep
510 def targetpathafterfn(pat, dest, srcs):
510 def targetpathafterfn(pat, dest, srcs):
511 if matchmod.patkind(pat):
511 if matchmod.patkind(pat):
512 # a mercurial pattern
512 # a mercurial pattern
513 res = lambda p: os.path.join(dest,
513 res = lambda p: os.path.join(dest,
514 os.path.basename(util.localpath(p)))
514 os.path.basename(util.localpath(p)))
515 else:
515 else:
516 abspfx = util.canonpath(repo.root, cwd, pat)
516 abspfx = util.canonpath(repo.root, cwd, pat)
517 if len(abspfx) < len(srcs[0][0]):
517 if len(abspfx) < len(srcs[0][0]):
518 # A directory. Either the target path contains the last
518 # A directory. Either the target path contains the last
519 # component of the source path or it does not.
519 # component of the source path or it does not.
520 def evalpath(striplen):
520 def evalpath(striplen):
521 score = 0
521 score = 0
522 for s in srcs:
522 for s in srcs:
523 t = os.path.join(dest, util.localpath(s[0])[striplen:])
523 t = os.path.join(dest, util.localpath(s[0])[striplen:])
524 if os.path.exists(t):
524 if os.path.exists(t):
525 score += 1
525 score += 1
526 return score
526 return score
527
527
528 abspfx = util.localpath(abspfx)
528 abspfx = util.localpath(abspfx)
529 striplen = len(abspfx)
529 striplen = len(abspfx)
530 if striplen:
530 if striplen:
531 striplen += len(os.sep)
531 striplen += len(os.sep)
532 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
532 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
533 score = evalpath(striplen)
533 score = evalpath(striplen)
534 striplen1 = len(os.path.split(abspfx)[0])
534 striplen1 = len(os.path.split(abspfx)[0])
535 if striplen1:
535 if striplen1:
536 striplen1 += len(os.sep)
536 striplen1 += len(os.sep)
537 if evalpath(striplen1) > score:
537 if evalpath(striplen1) > score:
538 striplen = striplen1
538 striplen = striplen1
539 res = lambda p: os.path.join(dest,
539 res = lambda p: os.path.join(dest,
540 util.localpath(p)[striplen:])
540 util.localpath(p)[striplen:])
541 else:
541 else:
542 # a file
542 # a file
543 if destdirexists:
543 if destdirexists:
544 res = lambda p: os.path.join(dest,
544 res = lambda p: os.path.join(dest,
545 os.path.basename(util.localpath(p)))
545 os.path.basename(util.localpath(p)))
546 else:
546 else:
547 res = lambda p: dest
547 res = lambda p: dest
548 return res
548 return res
549
549
550
550
551 pats = expandpats(pats)
551 pats = expandpats(pats)
552 if not pats:
552 if not pats:
553 raise util.Abort(_('no source or destination specified'))
553 raise util.Abort(_('no source or destination specified'))
554 if len(pats) == 1:
554 if len(pats) == 1:
555 raise util.Abort(_('no destination specified'))
555 raise util.Abort(_('no destination specified'))
556 dest = pats.pop()
556 dest = pats.pop()
557 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
557 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
558 if not destdirexists:
558 if not destdirexists:
559 if len(pats) > 1 or matchmod.patkind(pats[0]):
559 if len(pats) > 1 or matchmod.patkind(pats[0]):
560 raise util.Abort(_('with multiple sources, destination must be an '
560 raise util.Abort(_('with multiple sources, destination must be an '
561 'existing directory'))
561 'existing directory'))
562 if util.endswithsep(dest):
562 if util.endswithsep(dest):
563 raise util.Abort(_('destination %s is not a directory') % dest)
563 raise util.Abort(_('destination %s is not a directory') % dest)
564
564
565 tfn = targetpathfn
565 tfn = targetpathfn
566 if after:
566 if after:
567 tfn = targetpathafterfn
567 tfn = targetpathafterfn
568 copylist = []
568 copylist = []
569 for pat in pats:
569 for pat in pats:
570 srcs = walkpat(pat)
570 srcs = walkpat(pat)
571 if not srcs:
571 if not srcs:
572 continue
572 continue
573 copylist.append((tfn(pat, dest, srcs), srcs))
573 copylist.append((tfn(pat, dest, srcs), srcs))
574 if not copylist:
574 if not copylist:
575 raise util.Abort(_('no files to copy'))
575 raise util.Abort(_('no files to copy'))
576
576
577 errors = 0
577 errors = 0
578 for targetpath, srcs in copylist:
578 for targetpath, srcs in copylist:
579 for abssrc, relsrc, exact in srcs:
579 for abssrc, relsrc, exact in srcs:
580 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
580 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
581 errors += 1
581 errors += 1
582
582
583 if errors:
583 if errors:
584 ui.warn(_('(consider using --after)\n'))
584 ui.warn(_('(consider using --after)\n'))
585
585
586 return errors != 0
586 return errors != 0
587
587
588 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
588 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
589 runargs=None, appendpid=False):
589 runargs=None, appendpid=False):
590 '''Run a command as a service.'''
590 '''Run a command as a service.'''
591
591
592 if opts['daemon'] and not opts['daemon_pipefds']:
592 if opts['daemon'] and not opts['daemon_pipefds']:
593 # Signal child process startup with file removal
593 # Signal child process startup with file removal
594 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
594 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
595 os.close(lockfd)
595 os.close(lockfd)
596 try:
596 try:
597 if not runargs:
597 if not runargs:
598 runargs = util.hgcmd() + sys.argv[1:]
598 runargs = util.hgcmd() + sys.argv[1:]
599 runargs.append('--daemon-pipefds=%s' % lockpath)
599 runargs.append('--daemon-pipefds=%s' % lockpath)
600 # Don't pass --cwd to the child process, because we've already
600 # Don't pass --cwd to the child process, because we've already
601 # changed directory.
601 # changed directory.
602 for i in xrange(1, len(runargs)):
602 for i in xrange(1, len(runargs)):
603 if runargs[i].startswith('--cwd='):
603 if runargs[i].startswith('--cwd='):
604 del runargs[i]
604 del runargs[i]
605 break
605 break
606 elif runargs[i].startswith('--cwd'):
606 elif runargs[i].startswith('--cwd'):
607 del runargs[i:i + 2]
607 del runargs[i:i + 2]
608 break
608 break
609 def condfn():
609 def condfn():
610 return not os.path.exists(lockpath)
610 return not os.path.exists(lockpath)
611 pid = util.rundetached(runargs, condfn)
611 pid = util.rundetached(runargs, condfn)
612 if pid < 0:
612 if pid < 0:
613 raise util.Abort(_('child process failed to start'))
613 raise util.Abort(_('child process failed to start'))
614 finally:
614 finally:
615 try:
615 try:
616 os.unlink(lockpath)
616 os.unlink(lockpath)
617 except OSError, e:
617 except OSError, e:
618 if e.errno != errno.ENOENT:
618 if e.errno != errno.ENOENT:
619 raise
619 raise
620 if parentfn:
620 if parentfn:
621 return parentfn(pid)
621 return parentfn(pid)
622 else:
622 else:
623 return
623 return
624
624
625 if initfn:
625 if initfn:
626 initfn()
626 initfn()
627
627
628 if opts['pid_file']:
628 if opts['pid_file']:
629 mode = appendpid and 'a' or 'w'
629 mode = appendpid and 'a' or 'w'
630 fp = open(opts['pid_file'], mode)
630 fp = open(opts['pid_file'], mode)
631 fp.write(str(os.getpid()) + '\n')
631 fp.write(str(os.getpid()) + '\n')
632 fp.close()
632 fp.close()
633
633
634 if opts['daemon_pipefds']:
634 if opts['daemon_pipefds']:
635 lockpath = opts['daemon_pipefds']
635 lockpath = opts['daemon_pipefds']
636 try:
636 try:
637 os.setsid()
637 os.setsid()
638 except AttributeError:
638 except AttributeError:
639 pass
639 pass
640 os.unlink(lockpath)
640 os.unlink(lockpath)
641 util.hidewindow()
641 util.hidewindow()
642 sys.stdout.flush()
642 sys.stdout.flush()
643 sys.stderr.flush()
643 sys.stderr.flush()
644
644
645 nullfd = os.open(util.nulldev, os.O_RDWR)
645 nullfd = os.open(util.nulldev, os.O_RDWR)
646 logfilefd = nullfd
646 logfilefd = nullfd
647 if logfile:
647 if logfile:
648 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
648 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
649 os.dup2(nullfd, 0)
649 os.dup2(nullfd, 0)
650 os.dup2(logfilefd, 1)
650 os.dup2(logfilefd, 1)
651 os.dup2(logfilefd, 2)
651 os.dup2(logfilefd, 2)
652 if nullfd not in (0, 1, 2):
652 if nullfd not in (0, 1, 2):
653 os.close(nullfd)
653 os.close(nullfd)
654 if logfile and logfilefd not in (0, 1, 2):
654 if logfile and logfilefd not in (0, 1, 2):
655 os.close(logfilefd)
655 os.close(logfilefd)
656
656
657 if runfn:
657 if runfn:
658 return runfn()
658 return runfn()
659
659
660 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
660 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
661 opts=None):
661 opts=None):
662 '''export changesets as hg patches.'''
662 '''export changesets as hg patches.'''
663
663
664 total = len(revs)
664 total = len(revs)
665 revwidth = max([len(str(rev)) for rev in revs])
665 revwidth = max([len(str(rev)) for rev in revs])
666
666
667 def single(rev, seqno, fp):
667 def single(rev, seqno, fp):
668 ctx = repo[rev]
668 ctx = repo[rev]
669 node = ctx.node()
669 node = ctx.node()
670 parents = [p.node() for p in ctx.parents() if p]
670 parents = [p.node() for p in ctx.parents() if p]
671 branch = ctx.branch()
671 branch = ctx.branch()
672 if switch_parent:
672 if switch_parent:
673 parents.reverse()
673 parents.reverse()
674 prev = (parents and parents[0]) or nullid
674 prev = (parents and parents[0]) or nullid
675
675
676 if not fp:
676 if not fp:
677 fp = make_file(repo, template, node, total=total, seqno=seqno,
677 fp = make_file(repo, template, node, total=total, seqno=seqno,
678 revwidth=revwidth, mode='ab')
678 revwidth=revwidth, mode='ab')
679 if fp != sys.stdout and hasattr(fp, 'name'):
679 if fp != sys.stdout and hasattr(fp, 'name'):
680 repo.ui.note("%s\n" % fp.name)
680 repo.ui.note("%s\n" % fp.name)
681
681
682 fp.write("# HG changeset patch\n")
682 fp.write("# HG changeset patch\n")
683 fp.write("# User %s\n" % ctx.user())
683 fp.write("# User %s\n" % ctx.user())
684 fp.write("# Date %d %d\n" % ctx.date())
684 fp.write("# Date %d %d\n" % ctx.date())
685 if branch and branch != 'default':
685 if branch and branch != 'default':
686 fp.write("# Branch %s\n" % branch)
686 fp.write("# Branch %s\n" % branch)
687 fp.write("# Node ID %s\n" % hex(node))
687 fp.write("# Node ID %s\n" % hex(node))
688 fp.write("# Parent %s\n" % hex(prev))
688 fp.write("# Parent %s\n" % hex(prev))
689 if len(parents) > 1:
689 if len(parents) > 1:
690 fp.write("# Parent %s\n" % hex(parents[1]))
690 fp.write("# Parent %s\n" % hex(parents[1]))
691 fp.write(ctx.description().rstrip())
691 fp.write(ctx.description().rstrip())
692 fp.write("\n\n")
692 fp.write("\n\n")
693
693
694 for chunk in patch.diff(repo, prev, node, opts=opts):
694 for chunk in patch.diff(repo, prev, node, opts=opts):
695 fp.write(chunk)
695 fp.write(chunk)
696
696
697 for seqno, rev in enumerate(revs):
697 for seqno, rev in enumerate(revs):
698 single(rev, seqno + 1, fp)
698 single(rev, seqno + 1, fp)
699
699
700 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
700 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
701 changes=None, stat=False, fp=None, prefix='',
701 changes=None, stat=False, fp=None, prefix='',
702 listsubrepos=False):
702 listsubrepos=False):
703 '''show diff or diffstat.'''
703 '''show diff or diffstat.'''
704 if fp is None:
704 if fp is None:
705 write = ui.write
705 write = ui.write
706 else:
706 else:
707 def write(s, **kw):
707 def write(s, **kw):
708 fp.write(s)
708 fp.write(s)
709
709
710 if stat:
710 if stat:
711 diffopts = diffopts.copy(context=0)
711 diffopts = diffopts.copy(context=0)
712 width = 80
712 width = 80
713 if not ui.plain():
713 if not ui.plain():
714 width = util.termwidth()
714 width = util.termwidth()
715 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
715 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
716 prefix=prefix)
716 prefix=prefix)
717 for chunk, label in patch.diffstatui(util.iterlines(chunks),
717 for chunk, label in patch.diffstatui(util.iterlines(chunks),
718 width=width,
718 width=width,
719 git=diffopts.git):
719 git=diffopts.git):
720 write(chunk, label=label)
720 write(chunk, label=label)
721 else:
721 else:
722 for chunk, label in patch.diffui(repo, node1, node2, match,
722 for chunk, label in patch.diffui(repo, node1, node2, match,
723 changes, diffopts, prefix=prefix):
723 changes, diffopts, prefix=prefix):
724 write(chunk, label=label)
724 write(chunk, label=label)
725
725
726 if listsubrepos:
726 if listsubrepos:
727 ctx1 = repo[node1]
727 ctx1 = repo[node1]
728 ctx2 = repo[node2]
728 ctx2 = repo[node2]
729 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
729 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
730 if node2 is not None:
730 if node2 is not None:
731 node2 = ctx2.substate[subpath][1]
731 node2 = ctx2.substate[subpath][1]
732 submatch = matchmod.narrowmatcher(subpath, match)
732 submatch = matchmod.narrowmatcher(subpath, match)
733 sub.diff(diffopts, node2, submatch, changes=changes,
733 sub.diff(diffopts, node2, submatch, changes=changes,
734 stat=stat, fp=fp, prefix=prefix)
734 stat=stat, fp=fp, prefix=prefix)
735
735
736 class changeset_printer(object):
736 class changeset_printer(object):
737 '''show changeset information when templating not requested.'''
737 '''show changeset information when templating not requested.'''
738
738
739 def __init__(self, ui, repo, patch, diffopts, buffered):
739 def __init__(self, ui, repo, patch, diffopts, buffered):
740 self.ui = ui
740 self.ui = ui
741 self.repo = repo
741 self.repo = repo
742 self.buffered = buffered
742 self.buffered = buffered
743 self.patch = patch
743 self.patch = patch
744 self.diffopts = diffopts
744 self.diffopts = diffopts
745 self.header = {}
745 self.header = {}
746 self.hunk = {}
746 self.hunk = {}
747 self.lastheader = None
747 self.lastheader = None
748 self.footer = None
748 self.footer = None
749
749
750 def flush(self, rev):
750 def flush(self, rev):
751 if rev in self.header:
751 if rev in self.header:
752 h = self.header[rev]
752 h = self.header[rev]
753 if h != self.lastheader:
753 if h != self.lastheader:
754 self.lastheader = h
754 self.lastheader = h
755 self.ui.write(h)
755 self.ui.write(h)
756 del self.header[rev]
756 del self.header[rev]
757 if rev in self.hunk:
757 if rev in self.hunk:
758 self.ui.write(self.hunk[rev])
758 self.ui.write(self.hunk[rev])
759 del self.hunk[rev]
759 del self.hunk[rev]
760 return 1
760 return 1
761 return 0
761 return 0
762
762
763 def close(self):
763 def close(self):
764 if self.footer:
764 if self.footer:
765 self.ui.write(self.footer)
765 self.ui.write(self.footer)
766
766
767 def show(self, ctx, copies=None, matchfn=None, **props):
767 def show(self, ctx, copies=None, matchfn=None, **props):
768 if self.buffered:
768 if self.buffered:
769 self.ui.pushbuffer()
769 self.ui.pushbuffer()
770 self._show(ctx, copies, matchfn, props)
770 self._show(ctx, copies, matchfn, props)
771 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
771 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
772 else:
772 else:
773 self._show(ctx, copies, matchfn, props)
773 self._show(ctx, copies, matchfn, props)
774
774
775 def _show(self, ctx, copies, matchfn, props):
775 def _show(self, ctx, copies, matchfn, props):
776 '''show a single changeset or file revision'''
776 '''show a single changeset or file revision'''
777 changenode = ctx.node()
777 changenode = ctx.node()
778 rev = ctx.rev()
778 rev = ctx.rev()
779
779
780 if self.ui.quiet:
780 if self.ui.quiet:
781 self.ui.write("%d:%s\n" % (rev, short(changenode)),
781 self.ui.write("%d:%s\n" % (rev, short(changenode)),
782 label='log.node')
782 label='log.node')
783 return
783 return
784
784
785 log = self.repo.changelog
785 log = self.repo.changelog
786 date = util.datestr(ctx.date())
786 date = util.datestr(ctx.date())
787
787
788 hexfunc = self.ui.debugflag and hex or short
788 hexfunc = self.ui.debugflag and hex or short
789
789
790 parents = [(p, hexfunc(log.node(p)))
790 parents = [(p, hexfunc(log.node(p)))
791 for p in self._meaningful_parentrevs(log, rev)]
791 for p in self._meaningful_parentrevs(log, rev)]
792
792
793 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
793 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
794 label='log.changeset')
794 label='log.changeset')
795
795
796 branch = ctx.branch()
796 branch = ctx.branch()
797 # don't show the default branch name
797 # don't show the default branch name
798 if branch != 'default':
798 if branch != 'default':
799 branch = encoding.tolocal(branch)
799 branch = encoding.tolocal(branch)
800 self.ui.write(_("branch: %s\n") % branch,
800 self.ui.write(_("branch: %s\n") % branch,
801 label='log.branch')
801 label='log.branch')
802 for tag in self.repo.nodetags(changenode):
802 for tag in self.repo.nodetags(changenode):
803 self.ui.write(_("tag: %s\n") % tag,
803 self.ui.write(_("tag: %s\n") % tag,
804 label='log.tag')
804 label='log.tag')
805 for parent in parents:
805 for parent in parents:
806 self.ui.write(_("parent: %d:%s\n") % parent,
806 self.ui.write(_("parent: %d:%s\n") % parent,
807 label='log.parent')
807 label='log.parent')
808
808
809 if self.ui.debugflag:
809 if self.ui.debugflag:
810 mnode = ctx.manifestnode()
810 mnode = ctx.manifestnode()
811 self.ui.write(_("manifest: %d:%s\n") %
811 self.ui.write(_("manifest: %d:%s\n") %
812 (self.repo.manifest.rev(mnode), hex(mnode)),
812 (self.repo.manifest.rev(mnode), hex(mnode)),
813 label='ui.debug log.manifest')
813 label='ui.debug log.manifest')
814 self.ui.write(_("user: %s\n") % ctx.user(),
814 self.ui.write(_("user: %s\n") % ctx.user(),
815 label='log.user')
815 label='log.user')
816 self.ui.write(_("date: %s\n") % date,
816 self.ui.write(_("date: %s\n") % date,
817 label='log.date')
817 label='log.date')
818
818
819 if self.ui.debugflag:
819 if self.ui.debugflag:
820 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
820 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
821 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
821 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
822 files):
822 files):
823 if value:
823 if value:
824 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
824 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
825 label='ui.debug log.files')
825 label='ui.debug log.files')
826 elif ctx.files() and self.ui.verbose:
826 elif ctx.files() and self.ui.verbose:
827 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
827 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
828 label='ui.note log.files')
828 label='ui.note log.files')
829 if copies and self.ui.verbose:
829 if copies and self.ui.verbose:
830 copies = ['%s (%s)' % c for c in copies]
830 copies = ['%s (%s)' % c for c in copies]
831 self.ui.write(_("copies: %s\n") % ' '.join(copies),
831 self.ui.write(_("copies: %s\n") % ' '.join(copies),
832 label='ui.note log.copies')
832 label='ui.note log.copies')
833
833
834 extra = ctx.extra()
834 extra = ctx.extra()
835 if extra and self.ui.debugflag:
835 if extra and self.ui.debugflag:
836 for key, value in sorted(extra.items()):
836 for key, value in sorted(extra.items()):
837 self.ui.write(_("extra: %s=%s\n")
837 self.ui.write(_("extra: %s=%s\n")
838 % (key, value.encode('string_escape')),
838 % (key, value.encode('string_escape')),
839 label='ui.debug log.extra')
839 label='ui.debug log.extra')
840
840
841 description = ctx.description().strip()
841 description = ctx.description().strip()
842 if description:
842 if description:
843 if self.ui.verbose:
843 if self.ui.verbose:
844 self.ui.write(_("description:\n"),
844 self.ui.write(_("description:\n"),
845 label='ui.note log.description')
845 label='ui.note log.description')
846 self.ui.write(description,
846 self.ui.write(description,
847 label='ui.note log.description')
847 label='ui.note log.description')
848 self.ui.write("\n\n")
848 self.ui.write("\n\n")
849 else:
849 else:
850 self.ui.write(_("summary: %s\n") %
850 self.ui.write(_("summary: %s\n") %
851 description.splitlines()[0],
851 description.splitlines()[0],
852 label='log.summary')
852 label='log.summary')
853 self.ui.write("\n")
853 self.ui.write("\n")
854
854
855 self.showpatch(changenode, matchfn)
855 self.showpatch(changenode, matchfn)
856
856
857 def showpatch(self, node, matchfn):
857 def showpatch(self, node, matchfn):
858 if not matchfn:
858 if not matchfn:
859 matchfn = self.patch
859 matchfn = self.patch
860 if matchfn:
860 if matchfn:
861 stat = self.diffopts.get('stat')
861 stat = self.diffopts.get('stat')
862 diff = self.diffopts.get('patch')
862 diff = self.diffopts.get('patch')
863 diffopts = patch.diffopts(self.ui, self.diffopts)
863 diffopts = patch.diffopts(self.ui, self.diffopts)
864 prev = self.repo.changelog.parents(node)[0]
864 prev = self.repo.changelog.parents(node)[0]
865 if stat:
865 if stat:
866 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
866 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
867 match=matchfn, stat=True)
867 match=matchfn, stat=True)
868 if diff:
868 if diff:
869 if stat:
869 if stat:
870 self.ui.write("\n")
870 self.ui.write("\n")
871 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
871 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
872 match=matchfn, stat=False)
872 match=matchfn, stat=False)
873 self.ui.write("\n")
873 self.ui.write("\n")
874
874
875 def _meaningful_parentrevs(self, log, rev):
875 def _meaningful_parentrevs(self, log, rev):
876 """Return list of meaningful (or all if debug) parentrevs for rev.
876 """Return list of meaningful (or all if debug) parentrevs for rev.
877
877
878 For merges (two non-nullrev revisions) both parents are meaningful.
878 For merges (two non-nullrev revisions) both parents are meaningful.
879 Otherwise the first parent revision is considered meaningful if it
879 Otherwise the first parent revision is considered meaningful if it
880 is not the preceding revision.
880 is not the preceding revision.
881 """
881 """
882 parents = log.parentrevs(rev)
882 parents = log.parentrevs(rev)
883 if not self.ui.debugflag and parents[1] == nullrev:
883 if not self.ui.debugflag and parents[1] == nullrev:
884 if parents[0] >= rev - 1:
884 if parents[0] >= rev - 1:
885 parents = []
885 parents = []
886 else:
886 else:
887 parents = [parents[0]]
887 parents = [parents[0]]
888 return parents
888 return parents
889
889
890
890
891 class changeset_templater(changeset_printer):
891 class changeset_templater(changeset_printer):
892 '''format changeset information.'''
892 '''format changeset information.'''
893
893
894 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
894 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
895 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
895 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
896 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
896 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
897 defaulttempl = {
897 defaulttempl = {
898 'parent': '{rev}:{node|formatnode} ',
898 'parent': '{rev}:{node|formatnode} ',
899 'manifest': '{rev}:{node|formatnode}',
899 'manifest': '{rev}:{node|formatnode}',
900 'file_copy': '{name} ({source})',
900 'file_copy': '{name} ({source})',
901 'extra': '{key}={value|stringescape}'
901 'extra': '{key}={value|stringescape}'
902 }
902 }
903 # filecopy is preserved for compatibility reasons
903 # filecopy is preserved for compatibility reasons
904 defaulttempl['filecopy'] = defaulttempl['file_copy']
904 defaulttempl['filecopy'] = defaulttempl['file_copy']
905 self.t = templater.templater(mapfile, {'formatnode': formatnode},
905 self.t = templater.templater(mapfile, {'formatnode': formatnode},
906 cache=defaulttempl)
906 cache=defaulttempl)
907 self.cache = {}
907 self.cache = {}
908
908
909 def use_template(self, t):
909 def use_template(self, t):
910 '''set template string to use'''
910 '''set template string to use'''
911 self.t.cache['changeset'] = t
911 self.t.cache['changeset'] = t
912
912
913 def _meaningful_parentrevs(self, ctx):
913 def _meaningful_parentrevs(self, ctx):
914 """Return list of meaningful (or all if debug) parentrevs for rev.
914 """Return list of meaningful (or all if debug) parentrevs for rev.
915 """
915 """
916 parents = ctx.parents()
916 parents = ctx.parents()
917 if len(parents) > 1:
917 if len(parents) > 1:
918 return parents
918 return parents
919 if self.ui.debugflag:
919 if self.ui.debugflag:
920 return [parents[0], self.repo['null']]
920 return [parents[0], self.repo['null']]
921 if parents[0].rev() >= ctx.rev() - 1:
921 if parents[0].rev() >= ctx.rev() - 1:
922 return []
922 return []
923 return parents
923 return parents
924
924
925 def _show(self, ctx, copies, matchfn, props):
925 def _show(self, ctx, copies, matchfn, props):
926 '''show a single changeset or file revision'''
926 '''show a single changeset or file revision'''
927
927
928 showlist = templatekw.showlist
928 showlist = templatekw.showlist
929
929
930 # showparents() behaviour depends on ui trace level which
930 # showparents() behaviour depends on ui trace level which
931 # causes unexpected behaviours at templating level and makes
931 # causes unexpected behaviours at templating level and makes
932 # it harder to extract it in a standalone function. Its
932 # it harder to extract it in a standalone function. Its
933 # behaviour cannot be changed so leave it here for now.
933 # behaviour cannot be changed so leave it here for now.
934 def showparents(**args):
934 def showparents(**args):
935 ctx = args['ctx']
935 ctx = args['ctx']
936 parents = [[('rev', p.rev()), ('node', p.hex())]
936 parents = [[('rev', p.rev()), ('node', p.hex())]
937 for p in self._meaningful_parentrevs(ctx)]
937 for p in self._meaningful_parentrevs(ctx)]
938 return showlist('parent', parents, **args)
938 return showlist('parent', parents, **args)
939
939
940 props = props.copy()
940 props = props.copy()
941 props.update(templatekw.keywords)
941 props.update(templatekw.keywords)
942 props['parents'] = showparents
942 props['parents'] = showparents
943 props['templ'] = self.t
943 props['templ'] = self.t
944 props['ctx'] = ctx
944 props['ctx'] = ctx
945 props['repo'] = self.repo
945 props['repo'] = self.repo
946 props['revcache'] = {'copies': copies}
946 props['revcache'] = {'copies': copies}
947 props['cache'] = self.cache
947 props['cache'] = self.cache
948
948
949 # find correct templates for current mode
949 # find correct templates for current mode
950
950
951 tmplmodes = [
951 tmplmodes = [
952 (True, None),
952 (True, None),
953 (self.ui.verbose, 'verbose'),
953 (self.ui.verbose, 'verbose'),
954 (self.ui.quiet, 'quiet'),
954 (self.ui.quiet, 'quiet'),
955 (self.ui.debugflag, 'debug'),
955 (self.ui.debugflag, 'debug'),
956 ]
956 ]
957
957
958 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
958 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
959 for mode, postfix in tmplmodes:
959 for mode, postfix in tmplmodes:
960 for type in types:
960 for type in types:
961 cur = postfix and ('%s_%s' % (type, postfix)) or type
961 cur = postfix and ('%s_%s' % (type, postfix)) or type
962 if mode and cur in self.t:
962 if mode and cur in self.t:
963 types[type] = cur
963 types[type] = cur
964
964
965 try:
965 try:
966
966
967 # write header
967 # write header
968 if types['header']:
968 if types['header']:
969 h = templater.stringify(self.t(types['header'], **props))
969 h = templater.stringify(self.t(types['header'], **props))
970 if self.buffered:
970 if self.buffered:
971 self.header[ctx.rev()] = h
971 self.header[ctx.rev()] = h
972 else:
972 else:
973 if self.lastheader != h:
973 if self.lastheader != h:
974 self.lastheader = h
974 self.lastheader = h
975 self.ui.write(h)
975 self.ui.write(h)
976
976
977 # write changeset metadata, then patch if requested
977 # write changeset metadata, then patch if requested
978 key = types['changeset']
978 key = types['changeset']
979 self.ui.write(templater.stringify(self.t(key, **props)))
979 self.ui.write(templater.stringify(self.t(key, **props)))
980 self.showpatch(ctx.node(), matchfn)
980 self.showpatch(ctx.node(), matchfn)
981
981
982 if types['footer']:
982 if types['footer']:
983 if not self.footer:
983 if not self.footer:
984 self.footer = templater.stringify(self.t(types['footer'],
984 self.footer = templater.stringify(self.t(types['footer'],
985 **props))
985 **props))
986
986
987 except KeyError, inst:
987 except KeyError, inst:
988 msg = _("%s: no key named '%s'")
988 msg = _("%s: no key named '%s'")
989 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
989 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
990 except SyntaxError, inst:
990 except SyntaxError, inst:
991 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
991 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
992
992
993 def show_changeset(ui, repo, opts, buffered=False):
993 def show_changeset(ui, repo, opts, buffered=False):
994 """show one changeset using template or regular display.
994 """show one changeset using template or regular display.
995
995
996 Display format will be the first non-empty hit of:
996 Display format will be the first non-empty hit of:
997 1. option 'template'
997 1. option 'template'
998 2. option 'style'
998 2. option 'style'
999 3. [ui] setting 'logtemplate'
999 3. [ui] setting 'logtemplate'
1000 4. [ui] setting 'style'
1000 4. [ui] setting 'style'
1001 If all of these values are either the unset or the empty string,
1001 If all of these values are either the unset or the empty string,
1002 regular display via changeset_printer() is done.
1002 regular display via changeset_printer() is done.
1003 """
1003 """
1004 # options
1004 # options
1005 patch = False
1005 patch = False
1006 if opts.get('patch') or opts.get('stat'):
1006 if opts.get('patch') or opts.get('stat'):
1007 patch = matchall(repo)
1007 patch = matchall(repo)
1008
1008
1009 tmpl = opts.get('template')
1009 tmpl = opts.get('template')
1010 style = None
1010 style = None
1011 if tmpl:
1011 if tmpl:
1012 tmpl = templater.parsestring(tmpl, quoted=False)
1012 tmpl = templater.parsestring(tmpl, quoted=False)
1013 else:
1013 else:
1014 style = opts.get('style')
1014 style = opts.get('style')
1015
1015
1016 # ui settings
1016 # ui settings
1017 if not (tmpl or style):
1017 if not (tmpl or style):
1018 tmpl = ui.config('ui', 'logtemplate')
1018 tmpl = ui.config('ui', 'logtemplate')
1019 if tmpl:
1019 if tmpl:
1020 tmpl = templater.parsestring(tmpl)
1020 tmpl = templater.parsestring(tmpl)
1021 else:
1021 else:
1022 style = util.expandpath(ui.config('ui', 'style', ''))
1022 style = util.expandpath(ui.config('ui', 'style', ''))
1023
1023
1024 if not (tmpl or style):
1024 if not (tmpl or style):
1025 return changeset_printer(ui, repo, patch, opts, buffered)
1025 return changeset_printer(ui, repo, patch, opts, buffered)
1026
1026
1027 mapfile = None
1027 mapfile = None
1028 if style and not tmpl:
1028 if style and not tmpl:
1029 mapfile = style
1029 mapfile = style
1030 if not os.path.split(mapfile)[0]:
1030 if not os.path.split(mapfile)[0]:
1031 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1031 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1032 or templater.templatepath(mapfile))
1032 or templater.templatepath(mapfile))
1033 if mapname:
1033 if mapname:
1034 mapfile = mapname
1034 mapfile = mapname
1035
1035
1036 try:
1036 try:
1037 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
1037 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
1038 except SyntaxError, inst:
1038 except SyntaxError, inst:
1039 raise util.Abort(inst.args[0])
1039 raise util.Abort(inst.args[0])
1040 if tmpl:
1040 if tmpl:
1041 t.use_template(tmpl)
1041 t.use_template(tmpl)
1042 return t
1042 return t
1043
1043
1044 def finddate(ui, repo, date):
1044 def finddate(ui, repo, date):
1045 """Find the tipmost changeset that matches the given date spec"""
1045 """Find the tipmost changeset that matches the given date spec"""
1046
1046
1047 df = util.matchdate(date)
1047 df = util.matchdate(date)
1048 m = matchall(repo)
1048 m = matchall(repo)
1049 results = {}
1049 results = {}
1050
1050
1051 def prep(ctx, fns):
1051 def prep(ctx, fns):
1052 d = ctx.date()
1052 d = ctx.date()
1053 if df(d[0]):
1053 if df(d[0]):
1054 results[ctx.rev()] = d
1054 results[ctx.rev()] = d
1055
1055
1056 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1056 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1057 rev = ctx.rev()
1057 rev = ctx.rev()
1058 if rev in results:
1058 if rev in results:
1059 ui.status(_("Found revision %s from %s\n") %
1059 ui.status(_("Found revision %s from %s\n") %
1060 (rev, util.datestr(results[rev])))
1060 (rev, util.datestr(results[rev])))
1061 return str(rev)
1061 return str(rev)
1062
1062
1063 raise util.Abort(_("revision matching date not found"))
1063 raise util.Abort(_("revision matching date not found"))
1064
1064
1065 def walkchangerevs(repo, match, opts, prepare):
1065 def walkchangerevs(repo, match, opts, prepare):
1066 '''Iterate over files and the revs in which they changed.
1066 '''Iterate over files and the revs in which they changed.
1067
1067
1068 Callers most commonly need to iterate backwards over the history
1068 Callers most commonly need to iterate backwards over the history
1069 in which they are interested. Doing so has awful (quadratic-looking)
1069 in which they are interested. Doing so has awful (quadratic-looking)
1070 performance, so we use iterators in a "windowed" way.
1070 performance, so we use iterators in a "windowed" way.
1071
1071
1072 We walk a window of revisions in the desired order. Within the
1072 We walk a window of revisions in the desired order. Within the
1073 window, we first walk forwards to gather data, then in the desired
1073 window, we first walk forwards to gather data, then in the desired
1074 order (usually backwards) to display it.
1074 order (usually backwards) to display it.
1075
1075
1076 This function returns an iterator yielding contexts. Before
1076 This function returns an iterator yielding contexts. Before
1077 yielding each context, the iterator will first call the prepare
1077 yielding each context, the iterator will first call the prepare
1078 function on each context in the window in forward order.'''
1078 function on each context in the window in forward order.'''
1079
1079
1080 def increasing_windows(start, end, windowsize=8, sizelimit=512):
1080 def increasing_windows(start, end, windowsize=8, sizelimit=512):
1081 if start < end:
1081 if start < end:
1082 while start < end:
1082 while start < end:
1083 yield start, min(windowsize, end - start)
1083 yield start, min(windowsize, end - start)
1084 start += windowsize
1084 start += windowsize
1085 if windowsize < sizelimit:
1085 if windowsize < sizelimit:
1086 windowsize *= 2
1086 windowsize *= 2
1087 else:
1087 else:
1088 while start > end:
1088 while start > end:
1089 yield start, min(windowsize, start - end - 1)
1089 yield start, min(windowsize, start - end - 1)
1090 start -= windowsize
1090 start -= windowsize
1091 if windowsize < sizelimit:
1091 if windowsize < sizelimit:
1092 windowsize *= 2
1092 windowsize *= 2
1093
1093
1094 follow = opts.get('follow') or opts.get('follow_first')
1094 follow = opts.get('follow') or opts.get('follow_first')
1095
1095
1096 if not len(repo):
1096 if not len(repo):
1097 return []
1097 return []
1098
1098
1099 if follow:
1099 if follow:
1100 defrange = '%s:0' % repo['.'].rev()
1100 defrange = '%s:0' % repo['.'].rev()
1101 else:
1101 else:
1102 defrange = '-1:0'
1102 defrange = '-1:0'
1103 revs = revrange(repo, opts['rev'] or [defrange])
1103 revs = revrange(repo, opts['rev'] or [defrange])
1104 if not revs:
1104 if not revs:
1105 return []
1105 return []
1106 wanted = set()
1106 wanted = set()
1107 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1107 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1108 fncache = {}
1108 fncache = {}
1109 change = util.cachefunc(repo.changectx)
1109 change = util.cachefunc(repo.changectx)
1110
1110
1111 # First step is to fill wanted, the set of revisions that we want to yield.
1111 # First step is to fill wanted, the set of revisions that we want to yield.
1112 # When it does not induce extra cost, we also fill fncache for revisions in
1112 # When it does not induce extra cost, we also fill fncache for revisions in
1113 # wanted: a cache of filenames that were changed (ctx.files()) and that
1113 # wanted: a cache of filenames that were changed (ctx.files()) and that
1114 # match the file filtering conditions.
1114 # match the file filtering conditions.
1115
1115
1116 if not slowpath and not match.files():
1116 if not slowpath and not match.files():
1117 # No files, no patterns. Display all revs.
1117 # No files, no patterns. Display all revs.
1118 wanted = set(revs)
1118 wanted = set(revs)
1119 copies = []
1119 copies = []
1120
1120
1121 if not slowpath:
1121 if not slowpath:
1122 # We only have to read through the filelog to find wanted revisions
1122 # We only have to read through the filelog to find wanted revisions
1123
1123
1124 minrev, maxrev = min(revs), max(revs)
1124 minrev, maxrev = min(revs), max(revs)
1125 def filerevgen(filelog, last):
1125 def filerevgen(filelog, last):
1126 """
1126 """
1127 Only files, no patterns. Check the history of each file.
1127 Only files, no patterns. Check the history of each file.
1128
1128
1129 Examines filelog entries within minrev, maxrev linkrev range
1129 Examines filelog entries within minrev, maxrev linkrev range
1130 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1130 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1131 tuples in backwards order
1131 tuples in backwards order
1132 """
1132 """
1133 cl_count = len(repo)
1133 cl_count = len(repo)
1134 revs = []
1134 revs = []
1135 for j in xrange(0, last + 1):
1135 for j in xrange(0, last + 1):
1136 linkrev = filelog.linkrev(j)
1136 linkrev = filelog.linkrev(j)
1137 if linkrev < minrev:
1137 if linkrev < minrev:
1138 continue
1138 continue
1139 # only yield rev for which we have the changelog, it can
1139 # only yield rev for which we have the changelog, it can
1140 # happen while doing "hg log" during a pull or commit
1140 # happen while doing "hg log" during a pull or commit
1141 if linkrev > maxrev or linkrev >= cl_count:
1141 if linkrev > maxrev or linkrev >= cl_count:
1142 break
1142 break
1143
1143
1144 parentlinkrevs = []
1144 parentlinkrevs = []
1145 for p in filelog.parentrevs(j):
1145 for p in filelog.parentrevs(j):
1146 if p != nullrev:
1146 if p != nullrev:
1147 parentlinkrevs.append(filelog.linkrev(p))
1147 parentlinkrevs.append(filelog.linkrev(p))
1148 n = filelog.node(j)
1148 n = filelog.node(j)
1149 revs.append((linkrev, parentlinkrevs,
1149 revs.append((linkrev, parentlinkrevs,
1150 follow and filelog.renamed(n)))
1150 follow and filelog.renamed(n)))
1151
1151
1152 return reversed(revs)
1152 return reversed(revs)
1153 def iterfiles():
1153 def iterfiles():
1154 for filename in match.files():
1154 for filename in match.files():
1155 yield filename, None
1155 yield filename, None
1156 for filename_node in copies:
1156 for filename_node in copies:
1157 yield filename_node
1157 yield filename_node
1158 for file_, node in iterfiles():
1158 for file_, node in iterfiles():
1159 filelog = repo.file(file_)
1159 filelog = repo.file(file_)
1160 if not len(filelog):
1160 if not len(filelog):
1161 if node is None:
1161 if node is None:
1162 # A zero count may be a directory or deleted file, so
1162 # A zero count may be a directory or deleted file, so
1163 # try to find matching entries on the slow path.
1163 # try to find matching entries on the slow path.
1164 if follow:
1164 if follow:
1165 raise util.Abort(
1165 raise util.Abort(
1166 _('cannot follow nonexistent file: "%s"') % file_)
1166 _('cannot follow nonexistent file: "%s"') % file_)
1167 slowpath = True
1167 slowpath = True
1168 break
1168 break
1169 else:
1169 else:
1170 continue
1170 continue
1171
1171
1172 if node is None:
1172 if node is None:
1173 last = len(filelog) - 1
1173 last = len(filelog) - 1
1174 else:
1174 else:
1175 last = filelog.rev(node)
1175 last = filelog.rev(node)
1176
1176
1177
1177
1178 # keep track of all ancestors of the file
1178 # keep track of all ancestors of the file
1179 ancestors = set([filelog.linkrev(last)])
1179 ancestors = set([filelog.linkrev(last)])
1180
1180
1181 # iterate from latest to oldest revision
1181 # iterate from latest to oldest revision
1182 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1182 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1183 if rev not in ancestors:
1183 if rev not in ancestors:
1184 continue
1184 continue
1185 # XXX insert 1327 fix here
1185 # XXX insert 1327 fix here
1186 if flparentlinkrevs:
1186 if flparentlinkrevs:
1187 ancestors.update(flparentlinkrevs)
1187 ancestors.update(flparentlinkrevs)
1188
1188
1189 fncache.setdefault(rev, []).append(file_)
1189 fncache.setdefault(rev, []).append(file_)
1190 wanted.add(rev)
1190 wanted.add(rev)
1191 if copied:
1191 if copied:
1192 copies.append(copied)
1192 copies.append(copied)
1193 if slowpath:
1193 if slowpath:
1194 # We have to read the changelog to match filenames against
1194 # We have to read the changelog to match filenames against
1195 # changed files
1195 # changed files
1196
1196
1197 if follow:
1197 if follow:
1198 raise util.Abort(_('can only follow copies/renames for explicit '
1198 raise util.Abort(_('can only follow copies/renames for explicit '
1199 'filenames'))
1199 'filenames'))
1200
1200
1201 # The slow path checks files modified in every changeset.
1201 # The slow path checks files modified in every changeset.
1202 for i in sorted(revs):
1202 for i in sorted(revs):
1203 ctx = change(i)
1203 ctx = change(i)
1204 matches = filter(match, ctx.files())
1204 matches = filter(match, ctx.files())
1205 if matches:
1205 if matches:
1206 fncache[i] = matches
1206 fncache[i] = matches
1207 wanted.add(i)
1207 wanted.add(i)
1208
1208
1209 class followfilter(object):
1209 class followfilter(object):
1210 def __init__(self, onlyfirst=False):
1210 def __init__(self, onlyfirst=False):
1211 self.startrev = nullrev
1211 self.startrev = nullrev
1212 self.roots = set()
1212 self.roots = set()
1213 self.onlyfirst = onlyfirst
1213 self.onlyfirst = onlyfirst
1214
1214
1215 def match(self, rev):
1215 def match(self, rev):
1216 def realparents(rev):
1216 def realparents(rev):
1217 if self.onlyfirst:
1217 if self.onlyfirst:
1218 return repo.changelog.parentrevs(rev)[0:1]
1218 return repo.changelog.parentrevs(rev)[0:1]
1219 else:
1219 else:
1220 return filter(lambda x: x != nullrev,
1220 return filter(lambda x: x != nullrev,
1221 repo.changelog.parentrevs(rev))
1221 repo.changelog.parentrevs(rev))
1222
1222
1223 if self.startrev == nullrev:
1223 if self.startrev == nullrev:
1224 self.startrev = rev
1224 self.startrev = rev
1225 return True
1225 return True
1226
1226
1227 if rev > self.startrev:
1227 if rev > self.startrev:
1228 # forward: all descendants
1228 # forward: all descendants
1229 if not self.roots:
1229 if not self.roots:
1230 self.roots.add(self.startrev)
1230 self.roots.add(self.startrev)
1231 for parent in realparents(rev):
1231 for parent in realparents(rev):
1232 if parent in self.roots:
1232 if parent in self.roots:
1233 self.roots.add(rev)
1233 self.roots.add(rev)
1234 return True
1234 return True
1235 else:
1235 else:
1236 # backwards: all parents
1236 # backwards: all parents
1237 if not self.roots:
1237 if not self.roots:
1238 self.roots.update(realparents(self.startrev))
1238 self.roots.update(realparents(self.startrev))
1239 if rev in self.roots:
1239 if rev in self.roots:
1240 self.roots.remove(rev)
1240 self.roots.remove(rev)
1241 self.roots.update(realparents(rev))
1241 self.roots.update(realparents(rev))
1242 return True
1242 return True
1243
1243
1244 return False
1244 return False
1245
1245
1246 # it might be worthwhile to do this in the iterator if the rev range
1246 # it might be worthwhile to do this in the iterator if the rev range
1247 # is descending and the prune args are all within that range
1247 # is descending and the prune args are all within that range
1248 for rev in opts.get('prune', ()):
1248 for rev in opts.get('prune', ()):
1249 rev = repo.changelog.rev(repo.lookup(rev))
1249 rev = repo.changelog.rev(repo.lookup(rev))
1250 ff = followfilter()
1250 ff = followfilter()
1251 stop = min(revs[0], revs[-1])
1251 stop = min(revs[0], revs[-1])
1252 for x in xrange(rev, stop - 1, -1):
1252 for x in xrange(rev, stop - 1, -1):
1253 if ff.match(x):
1253 if ff.match(x):
1254 wanted.discard(x)
1254 wanted.discard(x)
1255
1255
1256 # Now that wanted is correctly initialized, we can iterate over the
1256 # Now that wanted is correctly initialized, we can iterate over the
1257 # revision range, yielding only revisions in wanted.
1257 # revision range, yielding only revisions in wanted.
1258 def iterate():
1258 def iterate():
1259 if follow and not match.files():
1259 if follow and not match.files():
1260 ff = followfilter(onlyfirst=opts.get('follow_first'))
1260 ff = followfilter(onlyfirst=opts.get('follow_first'))
1261 def want(rev):
1261 def want(rev):
1262 return ff.match(rev) and rev in wanted
1262 return ff.match(rev) and rev in wanted
1263 else:
1263 else:
1264 def want(rev):
1264 def want(rev):
1265 return rev in wanted
1265 return rev in wanted
1266
1266
1267 for i, window in increasing_windows(0, len(revs)):
1267 for i, window in increasing_windows(0, len(revs)):
1268 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1268 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1269 for rev in sorted(nrevs):
1269 for rev in sorted(nrevs):
1270 fns = fncache.get(rev)
1270 fns = fncache.get(rev)
1271 ctx = change(rev)
1271 ctx = change(rev)
1272 if not fns:
1272 if not fns:
1273 def fns_generator():
1273 def fns_generator():
1274 for f in ctx.files():
1274 for f in ctx.files():
1275 if match(f):
1275 if match(f):
1276 yield f
1276 yield f
1277 fns = fns_generator()
1277 fns = fns_generator()
1278 prepare(ctx, fns)
1278 prepare(ctx, fns)
1279 for rev in nrevs:
1279 for rev in nrevs:
1280 yield change(rev)
1280 yield change(rev)
1281 return iterate()
1281 return iterate()
1282
1282
1283 def add(ui, repo, match, dryrun):
1283 def add(ui, repo, match, dryrun, listsubrepos, prefix):
1284 join = lambda f: os.path.join(prefix, f)
1284 bad = []
1285 bad = []
1285 oldbad = match.bad
1286 oldbad = match.bad
1286 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1287 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1287 names = []
1288 names = []
1289 wctx = repo[None]
1288 for f in repo.walk(match):
1290 for f in repo.walk(match):
1289 exact = match.exact(f)
1291 exact = match.exact(f)
1290 if exact or f not in repo.dirstate:
1292 if exact or f not in repo.dirstate:
1291 names.append(f)
1293 names.append(f)
1292 if ui.verbose or not exact:
1294 if ui.verbose or not exact:
1293 ui.status(_('adding %s\n') % match.rel(f))
1295 ui.status(_('adding %s\n') % match.rel(join(f)))
1296
1297 if listsubrepos:
1298 for subpath in wctx.substate:
1299 sub = wctx.sub(subpath)
1300 try:
1301 submatch = matchmod.narrowmatcher(subpath, match)
1302 bad.extend(sub.add(ui, submatch, dryrun, prefix))
1303 except error.LookupError:
1304 ui.status(_("skipping missing subrepository: %s\n")
1305 % join(subpath))
1306
1294 if not dryrun:
1307 if not dryrun:
1295 rejected = repo[None].add(names)
1308 rejected = wctx.add(names, prefix)
1296 bad.extend(f for f in rejected if f in match.files())
1309 bad.extend(f for f in rejected if f in match.files())
1297 return bad
1310 return bad
1298
1311
1299 def commit(ui, repo, commitfunc, pats, opts):
1312 def commit(ui, repo, commitfunc, pats, opts):
1300 '''commit the specified files or all outstanding changes'''
1313 '''commit the specified files or all outstanding changes'''
1301 date = opts.get('date')
1314 date = opts.get('date')
1302 if date:
1315 if date:
1303 opts['date'] = util.parsedate(date)
1316 opts['date'] = util.parsedate(date)
1304 message = logmessage(opts)
1317 message = logmessage(opts)
1305
1318
1306 # extract addremove carefully -- this function can be called from a command
1319 # extract addremove carefully -- this function can be called from a command
1307 # that doesn't support addremove
1320 # that doesn't support addremove
1308 if opts.get('addremove'):
1321 if opts.get('addremove'):
1309 addremove(repo, pats, opts)
1322 addremove(repo, pats, opts)
1310
1323
1311 return commitfunc(ui, repo, message, match(repo, pats, opts), opts)
1324 return commitfunc(ui, repo, message, match(repo, pats, opts), opts)
1312
1325
1313 def commiteditor(repo, ctx, subs):
1326 def commiteditor(repo, ctx, subs):
1314 if ctx.description():
1327 if ctx.description():
1315 return ctx.description()
1328 return ctx.description()
1316 return commitforceeditor(repo, ctx, subs)
1329 return commitforceeditor(repo, ctx, subs)
1317
1330
1318 def commitforceeditor(repo, ctx, subs):
1331 def commitforceeditor(repo, ctx, subs):
1319 edittext = []
1332 edittext = []
1320 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1333 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1321 if ctx.description():
1334 if ctx.description():
1322 edittext.append(ctx.description())
1335 edittext.append(ctx.description())
1323 edittext.append("")
1336 edittext.append("")
1324 edittext.append("") # Empty line between message and comments.
1337 edittext.append("") # Empty line between message and comments.
1325 edittext.append(_("HG: Enter commit message."
1338 edittext.append(_("HG: Enter commit message."
1326 " Lines beginning with 'HG:' are removed."))
1339 " Lines beginning with 'HG:' are removed."))
1327 edittext.append(_("HG: Leave message empty to abort commit."))
1340 edittext.append(_("HG: Leave message empty to abort commit."))
1328 edittext.append("HG: --")
1341 edittext.append("HG: --")
1329 edittext.append(_("HG: user: %s") % ctx.user())
1342 edittext.append(_("HG: user: %s") % ctx.user())
1330 if ctx.p2():
1343 if ctx.p2():
1331 edittext.append(_("HG: branch merge"))
1344 edittext.append(_("HG: branch merge"))
1332 if ctx.branch():
1345 if ctx.branch():
1333 edittext.append(_("HG: branch '%s'")
1346 edittext.append(_("HG: branch '%s'")
1334 % encoding.tolocal(ctx.branch()))
1347 % encoding.tolocal(ctx.branch()))
1335 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1348 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1336 edittext.extend([_("HG: added %s") % f for f in added])
1349 edittext.extend([_("HG: added %s") % f for f in added])
1337 edittext.extend([_("HG: changed %s") % f for f in modified])
1350 edittext.extend([_("HG: changed %s") % f for f in modified])
1338 edittext.extend([_("HG: removed %s") % f for f in removed])
1351 edittext.extend([_("HG: removed %s") % f for f in removed])
1339 if not added and not modified and not removed:
1352 if not added and not modified and not removed:
1340 edittext.append(_("HG: no files changed"))
1353 edittext.append(_("HG: no files changed"))
1341 edittext.append("")
1354 edittext.append("")
1342 # run editor in the repository root
1355 # run editor in the repository root
1343 olddir = os.getcwd()
1356 olddir = os.getcwd()
1344 os.chdir(repo.root)
1357 os.chdir(repo.root)
1345 text = repo.ui.edit("\n".join(edittext), ctx.user())
1358 text = repo.ui.edit("\n".join(edittext), ctx.user())
1346 text = re.sub("(?m)^HG:.*\n", "", text)
1359 text = re.sub("(?m)^HG:.*\n", "", text)
1347 os.chdir(olddir)
1360 os.chdir(olddir)
1348
1361
1349 if not text.strip():
1362 if not text.strip():
1350 raise util.Abort(_("empty commit message"))
1363 raise util.Abort(_("empty commit message"))
1351
1364
1352 return text
1365 return text
@@ -1,4509 +1,4511 b''
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, nullid, nullrev, short
8 from node import hex, 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, util, revlog, bundlerepo, extensions, copies, error
12 import hg, util, revlog, bundlerepo, extensions, copies, error
13 import patch, help, mdiff, url, encoding, templatekw, discovery
13 import patch, help, mdiff, 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
16 import minirst, revset
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 return rejected and 1 or 0
52 return rejected and 1 or 0
52
53
53 def addremove(ui, repo, *pats, **opts):
54 def addremove(ui, repo, *pats, **opts):
54 """add all new files, delete all missing files
55 """add all new files, delete all missing files
55
56
56 Add all new files and remove all missing files from the
57 Add all new files and remove all missing files from the
57 repository.
58 repository.
58
59
59 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
60 .hgignore. As with add, these changes take effect at the next
61 .hgignore. As with add, these changes take effect at the next
61 commit.
62 commit.
62
63
63 Use the -s/--similarity option to detect renamed files. With a
64 Use the -s/--similarity option to detect renamed files. With a
64 parameter greater than 0, this compares every removed file with
65 parameter greater than 0, this compares every removed file with
65 every added file and records those similar enough as renames. This
66 every added file and records those similar enough as renames. This
66 option takes a percentage between 0 (disabled) and 100 (files must
67 option takes a percentage between 0 (disabled) and 100 (files must
67 be identical) as its parameter. Detecting renamed files this way
68 be identical) as its parameter. Detecting renamed files this way
68 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
69 used to check which files were identified as moved or renamed.
70 used to check which files were identified as moved or renamed.
70
71
71 Returns 0 if all files are successfully added.
72 Returns 0 if all files are successfully added.
72 """
73 """
73 try:
74 try:
74 sim = float(opts.get('similarity') or 100)
75 sim = float(opts.get('similarity') or 100)
75 except ValueError:
76 except ValueError:
76 raise util.Abort(_('similarity must be a number'))
77 raise util.Abort(_('similarity must be a number'))
77 if sim < 0 or sim > 100:
78 if sim < 0 or sim > 100:
78 raise util.Abort(_('similarity must be between 0 and 100'))
79 raise util.Abort(_('similarity must be between 0 and 100'))
79 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
80 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
80
81
81 def annotate(ui, repo, *pats, **opts):
82 def annotate(ui, repo, *pats, **opts):
82 """show changeset information by line for each file
83 """show changeset information by line for each file
83
84
84 List changes in files, showing the revision id responsible for
85 List changes in files, showing the revision id responsible for
85 each line
86 each line
86
87
87 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
88 by whom.
89 by whom.
89
90
90 Without the -a/--text option, annotate will avoid processing files
91 Without the -a/--text option, annotate will avoid processing files
91 it detects as binary. With -a, annotate will annotate the file
92 it detects as binary. With -a, annotate will annotate the file
92 anyway, although the results will probably be neither useful
93 anyway, although the results will probably be neither useful
93 nor desirable.
94 nor desirable.
94
95
95 Returns 0 on success.
96 Returns 0 on success.
96 """
97 """
97 if opts.get('follow'):
98 if opts.get('follow'):
98 # --follow is deprecated and now just an alias for -f/--file
99 # --follow is deprecated and now just an alias for -f/--file
99 # to mimic the behavior of Mercurial before version 1.5
100 # to mimic the behavior of Mercurial before version 1.5
100 opts['file'] = 1
101 opts['file'] = 1
101
102
102 datefunc = ui.quiet and util.shortdate or util.datestr
103 datefunc = ui.quiet and util.shortdate or util.datestr
103 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
104 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
104
105
105 if not pats:
106 if not pats:
106 raise util.Abort(_('at least one filename or pattern is required'))
107 raise util.Abort(_('at least one filename or pattern is required'))
107
108
108 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
109 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
109 ('number', lambda x: str(x[0].rev())),
110 ('number', lambda x: str(x[0].rev())),
110 ('changeset', lambda x: short(x[0].node())),
111 ('changeset', lambda x: short(x[0].node())),
111 ('date', getdate),
112 ('date', getdate),
112 ('file', lambda x: x[0].path()),
113 ('file', lambda x: x[0].path()),
113 ]
114 ]
114
115
115 if (not opts.get('user') and not opts.get('changeset')
116 if (not opts.get('user') and not opts.get('changeset')
116 and not opts.get('date') and not opts.get('file')):
117 and not opts.get('date') and not opts.get('file')):
117 opts['number'] = 1
118 opts['number'] = 1
118
119
119 linenumber = opts.get('line_number') is not None
120 linenumber = opts.get('line_number') is not None
120 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')):
121 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'))
122
123
123 funcmap = [func for op, func in opmap if opts.get(op)]
124 funcmap = [func for op, func in opmap if opts.get(op)]
124 if linenumber:
125 if linenumber:
125 lastfunc = funcmap[-1]
126 lastfunc = funcmap[-1]
126 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
127 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
127
128
128 ctx = repo[opts.get('rev')]
129 ctx = repo[opts.get('rev')]
129 m = cmdutil.match(repo, pats, opts)
130 m = cmdutil.match(repo, pats, opts)
130 follow = not opts.get('no_follow')
131 follow = not opts.get('no_follow')
131 for abs in ctx.walk(m):
132 for abs in ctx.walk(m):
132 fctx = ctx[abs]
133 fctx = ctx[abs]
133 if not opts.get('text') and util.binary(fctx.data()):
134 if not opts.get('text') and util.binary(fctx.data()):
134 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
135 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
135 continue
136 continue
136
137
137 lines = fctx.annotate(follow=follow, linenumber=linenumber)
138 lines = fctx.annotate(follow=follow, linenumber=linenumber)
138 pieces = []
139 pieces = []
139
140
140 for f in funcmap:
141 for f in funcmap:
141 l = [f(n) for n, dummy in lines]
142 l = [f(n) for n, dummy in lines]
142 if l:
143 if l:
143 sized = [(x, encoding.colwidth(x)) for x in l]
144 sized = [(x, encoding.colwidth(x)) for x in l]
144 ml = max([w for x, w in sized])
145 ml = max([w for x, w in sized])
145 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
146 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
146
147
147 if pieces:
148 if pieces:
148 for p, l in zip(zip(*pieces), lines):
149 for p, l in zip(zip(*pieces), lines):
149 ui.write("%s: %s" % (" ".join(p), l[1]))
150 ui.write("%s: %s" % (" ".join(p), l[1]))
150
151
151 def archive(ui, repo, dest, **opts):
152 def archive(ui, repo, dest, **opts):
152 '''create an unversioned archive of a repository revision
153 '''create an unversioned archive of a repository revision
153
154
154 By default, the revision used is the parent of the working
155 By default, the revision used is the parent of the working
155 directory; use -r/--rev to specify a different revision.
156 directory; use -r/--rev to specify a different revision.
156
157
157 The archive type is automatically detected based on file
158 The archive type is automatically detected based on file
158 extension (or override using -t/--type).
159 extension (or override using -t/--type).
159
160
160 Valid types are:
161 Valid types are:
161
162
162 :``files``: a directory full of files (default)
163 :``files``: a directory full of files (default)
163 :``tar``: tar archive, uncompressed
164 :``tar``: tar archive, uncompressed
164 :``tbz2``: tar archive, compressed using bzip2
165 :``tbz2``: tar archive, compressed using bzip2
165 :``tgz``: tar archive, compressed using gzip
166 :``tgz``: tar archive, compressed using gzip
166 :``uzip``: zip archive, uncompressed
167 :``uzip``: zip archive, uncompressed
167 :``zip``: zip archive, compressed using deflate
168 :``zip``: zip archive, compressed using deflate
168
169
169 The exact name of the destination archive or directory is given
170 The exact name of the destination archive or directory is given
170 using a format string; see :hg:`help export` for details.
171 using a format string; see :hg:`help export` for details.
171
172
172 Each member added to an archive file has a directory prefix
173 Each member added to an archive file has a directory prefix
173 prepended. Use -p/--prefix to specify a format string for the
174 prepended. Use -p/--prefix to specify a format string for the
174 prefix. The default is the basename of the archive, with suffixes
175 prefix. The default is the basename of the archive, with suffixes
175 removed.
176 removed.
176
177
177 Returns 0 on success.
178 Returns 0 on success.
178 '''
179 '''
179
180
180 ctx = repo[opts.get('rev')]
181 ctx = repo[opts.get('rev')]
181 if not ctx:
182 if not ctx:
182 raise util.Abort(_('no working directory: please specify a revision'))
183 raise util.Abort(_('no working directory: please specify a revision'))
183 node = ctx.node()
184 node = ctx.node()
184 dest = cmdutil.make_filename(repo, dest, node)
185 dest = cmdutil.make_filename(repo, dest, node)
185 if os.path.realpath(dest) == repo.root:
186 if os.path.realpath(dest) == repo.root:
186 raise util.Abort(_('repository root cannot be destination'))
187 raise util.Abort(_('repository root cannot be destination'))
187
188
188 kind = opts.get('type') or archival.guesskind(dest) or 'files'
189 kind = opts.get('type') or archival.guesskind(dest) or 'files'
189 prefix = opts.get('prefix')
190 prefix = opts.get('prefix')
190
191
191 if dest == '-':
192 if dest == '-':
192 if kind == 'files':
193 if kind == 'files':
193 raise util.Abort(_('cannot archive plain files to stdout'))
194 raise util.Abort(_('cannot archive plain files to stdout'))
194 dest = sys.stdout
195 dest = sys.stdout
195 if not prefix:
196 if not prefix:
196 prefix = os.path.basename(repo.root) + '-%h'
197 prefix = os.path.basename(repo.root) + '-%h'
197
198
198 prefix = cmdutil.make_filename(repo, prefix, node)
199 prefix = cmdutil.make_filename(repo, prefix, node)
199 matchfn = cmdutil.match(repo, [], opts)
200 matchfn = cmdutil.match(repo, [], opts)
200 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
201 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
201 matchfn, prefix)
202 matchfn, prefix)
202
203
203 def backout(ui, repo, node=None, rev=None, **opts):
204 def backout(ui, repo, node=None, rev=None, **opts):
204 '''reverse effect of earlier changeset
205 '''reverse effect of earlier changeset
205
206
206 Commit the backed out changes as a new changeset. The new
207 Commit the backed out changes as a new changeset. The new
207 changeset is a child of the backed out changeset.
208 changeset is a child of the backed out changeset.
208
209
209 If you backout a changeset other than the tip, a new head is
210 If you backout a changeset other than the tip, a new head is
210 created. This head will be the new tip and you should merge this
211 created. This head will be the new tip and you should merge this
211 backout changeset with another head.
212 backout changeset with another head.
212
213
213 The --merge option remembers the parent of the working directory
214 The --merge option remembers the parent of the working directory
214 before starting the backout, then merges the new head with that
215 before starting the backout, then merges the new head with that
215 changeset afterwards. This saves you from doing the merge by hand.
216 changeset afterwards. This saves you from doing the merge by hand.
216 The result of this merge is not committed, as with a normal merge.
217 The result of this merge is not committed, as with a normal merge.
217
218
218 See :hg:`help dates` for a list of formats valid for -d/--date.
219 See :hg:`help dates` for a list of formats valid for -d/--date.
219
220
220 Returns 0 on success.
221 Returns 0 on success.
221 '''
222 '''
222 if rev and node:
223 if rev and node:
223 raise util.Abort(_("please specify just one revision"))
224 raise util.Abort(_("please specify just one revision"))
224
225
225 if not rev:
226 if not rev:
226 rev = node
227 rev = node
227
228
228 if not rev:
229 if not rev:
229 raise util.Abort(_("please specify a revision to backout"))
230 raise util.Abort(_("please specify a revision to backout"))
230
231
231 date = opts.get('date')
232 date = opts.get('date')
232 if date:
233 if date:
233 opts['date'] = util.parsedate(date)
234 opts['date'] = util.parsedate(date)
234
235
235 cmdutil.bail_if_changed(repo)
236 cmdutil.bail_if_changed(repo)
236 node = repo.lookup(rev)
237 node = repo.lookup(rev)
237
238
238 op1, op2 = repo.dirstate.parents()
239 op1, op2 = repo.dirstate.parents()
239 a = repo.changelog.ancestor(op1, node)
240 a = repo.changelog.ancestor(op1, node)
240 if a != node:
241 if a != node:
241 raise util.Abort(_('cannot backout change on a different branch'))
242 raise util.Abort(_('cannot backout change on a different branch'))
242
243
243 p1, p2 = repo.changelog.parents(node)
244 p1, p2 = repo.changelog.parents(node)
244 if p1 == nullid:
245 if p1 == nullid:
245 raise util.Abort(_('cannot backout a change with no parents'))
246 raise util.Abort(_('cannot backout a change with no parents'))
246 if p2 != nullid:
247 if p2 != nullid:
247 if not opts.get('parent'):
248 if not opts.get('parent'):
248 raise util.Abort(_('cannot backout a merge changeset without '
249 raise util.Abort(_('cannot backout a merge changeset without '
249 '--parent'))
250 '--parent'))
250 p = repo.lookup(opts['parent'])
251 p = repo.lookup(opts['parent'])
251 if p not in (p1, p2):
252 if p not in (p1, p2):
252 raise util.Abort(_('%s is not a parent of %s') %
253 raise util.Abort(_('%s is not a parent of %s') %
253 (short(p), short(node)))
254 (short(p), short(node)))
254 parent = p
255 parent = p
255 else:
256 else:
256 if opts.get('parent'):
257 if opts.get('parent'):
257 raise util.Abort(_('cannot use --parent on non-merge changeset'))
258 raise util.Abort(_('cannot use --parent on non-merge changeset'))
258 parent = p1
259 parent = p1
259
260
260 # the backout should appear on the same branch
261 # the backout should appear on the same branch
261 branch = repo.dirstate.branch()
262 branch = repo.dirstate.branch()
262 hg.clean(repo, node, show_stats=False)
263 hg.clean(repo, node, show_stats=False)
263 repo.dirstate.setbranch(branch)
264 repo.dirstate.setbranch(branch)
264 revert_opts = opts.copy()
265 revert_opts = opts.copy()
265 revert_opts['date'] = None
266 revert_opts['date'] = None
266 revert_opts['all'] = True
267 revert_opts['all'] = True
267 revert_opts['rev'] = hex(parent)
268 revert_opts['rev'] = hex(parent)
268 revert_opts['no_backup'] = None
269 revert_opts['no_backup'] = None
269 revert(ui, repo, **revert_opts)
270 revert(ui, repo, **revert_opts)
270 commit_opts = opts.copy()
271 commit_opts = opts.copy()
271 commit_opts['addremove'] = False
272 commit_opts['addremove'] = False
272 if not commit_opts['message'] and not commit_opts['logfile']:
273 if not commit_opts['message'] and not commit_opts['logfile']:
273 # we don't translate commit messages
274 # we don't translate commit messages
274 commit_opts['message'] = "Backed out changeset %s" % short(node)
275 commit_opts['message'] = "Backed out changeset %s" % short(node)
275 commit_opts['force_editor'] = True
276 commit_opts['force_editor'] = True
276 commit(ui, repo, **commit_opts)
277 commit(ui, repo, **commit_opts)
277 def nice(node):
278 def nice(node):
278 return '%d:%s' % (repo.changelog.rev(node), short(node))
279 return '%d:%s' % (repo.changelog.rev(node), short(node))
279 ui.status(_('changeset %s backs out changeset %s\n') %
280 ui.status(_('changeset %s backs out changeset %s\n') %
280 (nice(repo.changelog.tip()), nice(node)))
281 (nice(repo.changelog.tip()), nice(node)))
281 if op1 != node:
282 if op1 != node:
282 hg.clean(repo, op1, show_stats=False)
283 hg.clean(repo, op1, show_stats=False)
283 if opts.get('merge'):
284 if opts.get('merge'):
284 ui.status(_('merging with changeset %s\n')
285 ui.status(_('merging with changeset %s\n')
285 % nice(repo.changelog.tip()))
286 % nice(repo.changelog.tip()))
286 hg.merge(repo, hex(repo.changelog.tip()))
287 hg.merge(repo, hex(repo.changelog.tip()))
287 else:
288 else:
288 ui.status(_('the backout changeset is a new head - '
289 ui.status(_('the backout changeset is a new head - '
289 'do not forget to merge\n'))
290 'do not forget to merge\n'))
290 ui.status(_('(use "backout --merge" '
291 ui.status(_('(use "backout --merge" '
291 'if you want to auto-merge)\n'))
292 'if you want to auto-merge)\n'))
292
293
293 def bisect(ui, repo, rev=None, extra=None, command=None,
294 def bisect(ui, repo, rev=None, extra=None, command=None,
294 reset=None, good=None, bad=None, skip=None, noupdate=None):
295 reset=None, good=None, bad=None, skip=None, noupdate=None):
295 """subdivision search of changesets
296 """subdivision search of changesets
296
297
297 This command helps to find changesets which introduce problems. To
298 This command helps to find changesets which introduce problems. To
298 use, mark the earliest changeset you know exhibits the problem as
299 use, mark the earliest changeset you know exhibits the problem as
299 bad, then mark the latest changeset which is free from the problem
300 bad, then mark the latest changeset which is free from the problem
300 as good. Bisect will update your working directory to a revision
301 as good. Bisect will update your working directory to a revision
301 for testing (unless the -U/--noupdate option is specified). Once
302 for testing (unless the -U/--noupdate option is specified). Once
302 you have performed tests, mark the working directory as good or
303 you have performed tests, mark the working directory as good or
303 bad, and bisect will either update to another candidate changeset
304 bad, and bisect will either update to another candidate changeset
304 or announce that it has found the bad revision.
305 or announce that it has found the bad revision.
305
306
306 As a shortcut, you can also use the revision argument to mark a
307 As a shortcut, you can also use the revision argument to mark a
307 revision as good or bad without checking it out first.
308 revision as good or bad without checking it out first.
308
309
309 If you supply a command, it will be used for automatic bisection.
310 If you supply a command, it will be used for automatic bisection.
310 Its exit status will be used to mark revisions as good or bad:
311 Its exit status will be used to mark revisions as good or bad:
311 status 0 means good, 125 means to skip the revision, 127
312 status 0 means good, 125 means to skip the revision, 127
312 (command not found) will abort the bisection, and any other
313 (command not found) will abort the bisection, and any other
313 non-zero exit status means the revision is bad.
314 non-zero exit status means the revision is bad.
314
315
315 Returns 0 on success.
316 Returns 0 on success.
316 """
317 """
317 def print_result(nodes, good):
318 def print_result(nodes, good):
318 displayer = cmdutil.show_changeset(ui, repo, {})
319 displayer = cmdutil.show_changeset(ui, repo, {})
319 if len(nodes) == 1:
320 if len(nodes) == 1:
320 # narrowed it down to a single revision
321 # narrowed it down to a single revision
321 if good:
322 if good:
322 ui.write(_("The first good revision is:\n"))
323 ui.write(_("The first good revision is:\n"))
323 else:
324 else:
324 ui.write(_("The first bad revision is:\n"))
325 ui.write(_("The first bad revision is:\n"))
325 displayer.show(repo[nodes[0]])
326 displayer.show(repo[nodes[0]])
326 parents = repo[nodes[0]].parents()
327 parents = repo[nodes[0]].parents()
327 if len(parents) > 1:
328 if len(parents) > 1:
328 side = good and state['bad'] or state['good']
329 side = good and state['bad'] or state['good']
329 num = len(set(i.node() for i in parents) & set(side))
330 num = len(set(i.node() for i in parents) & set(side))
330 if num == 1:
331 if num == 1:
331 common = parents[0].ancestor(parents[1])
332 common = parents[0].ancestor(parents[1])
332 ui.write(_('Not all ancestors of this changeset have been'
333 ui.write(_('Not all ancestors of this changeset have been'
333 ' checked.\nTo check the other ancestors, start'
334 ' checked.\nTo check the other ancestors, start'
334 ' from the common ancestor, %s.\n' % common))
335 ' from the common ancestor, %s.\n' % common))
335 else:
336 else:
336 # multiple possible revisions
337 # multiple possible revisions
337 if good:
338 if good:
338 ui.write(_("Due to skipped revisions, the first "
339 ui.write(_("Due to skipped revisions, the first "
339 "good revision could be any of:\n"))
340 "good revision could be any of:\n"))
340 else:
341 else:
341 ui.write(_("Due to skipped revisions, the first "
342 ui.write(_("Due to skipped revisions, the first "
342 "bad revision could be any of:\n"))
343 "bad revision could be any of:\n"))
343 for n in nodes:
344 for n in nodes:
344 displayer.show(repo[n])
345 displayer.show(repo[n])
345 displayer.close()
346 displayer.close()
346
347
347 def check_state(state, interactive=True):
348 def check_state(state, interactive=True):
348 if not state['good'] or not state['bad']:
349 if not state['good'] or not state['bad']:
349 if (good or bad or skip or reset) and interactive:
350 if (good or bad or skip or reset) and interactive:
350 return
351 return
351 if not state['good']:
352 if not state['good']:
352 raise util.Abort(_('cannot bisect (no known good revisions)'))
353 raise util.Abort(_('cannot bisect (no known good revisions)'))
353 else:
354 else:
354 raise util.Abort(_('cannot bisect (no known bad revisions)'))
355 raise util.Abort(_('cannot bisect (no known bad revisions)'))
355 return True
356 return True
356
357
357 # backward compatibility
358 # backward compatibility
358 if rev in "good bad reset init".split():
359 if rev in "good bad reset init".split():
359 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
360 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
360 cmd, rev, extra = rev, extra, None
361 cmd, rev, extra = rev, extra, None
361 if cmd == "good":
362 if cmd == "good":
362 good = True
363 good = True
363 elif cmd == "bad":
364 elif cmd == "bad":
364 bad = True
365 bad = True
365 else:
366 else:
366 reset = True
367 reset = True
367 elif extra or good + bad + skip + reset + bool(command) > 1:
368 elif extra or good + bad + skip + reset + bool(command) > 1:
368 raise util.Abort(_('incompatible arguments'))
369 raise util.Abort(_('incompatible arguments'))
369
370
370 if reset:
371 if reset:
371 p = repo.join("bisect.state")
372 p = repo.join("bisect.state")
372 if os.path.exists(p):
373 if os.path.exists(p):
373 os.unlink(p)
374 os.unlink(p)
374 return
375 return
375
376
376 state = hbisect.load_state(repo)
377 state = hbisect.load_state(repo)
377
378
378 if command:
379 if command:
379 changesets = 1
380 changesets = 1
380 try:
381 try:
381 while changesets:
382 while changesets:
382 # update state
383 # update state
383 status = util.system(command)
384 status = util.system(command)
384 if status == 125:
385 if status == 125:
385 transition = "skip"
386 transition = "skip"
386 elif status == 0:
387 elif status == 0:
387 transition = "good"
388 transition = "good"
388 # status < 0 means process was killed
389 # status < 0 means process was killed
389 elif status == 127:
390 elif status == 127:
390 raise util.Abort(_("failed to execute %s") % command)
391 raise util.Abort(_("failed to execute %s") % command)
391 elif status < 0:
392 elif status < 0:
392 raise util.Abort(_("%s killed") % command)
393 raise util.Abort(_("%s killed") % command)
393 else:
394 else:
394 transition = "bad"
395 transition = "bad"
395 ctx = repo[rev or '.']
396 ctx = repo[rev or '.']
396 state[transition].append(ctx.node())
397 state[transition].append(ctx.node())
397 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
398 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
398 check_state(state, interactive=False)
399 check_state(state, interactive=False)
399 # bisect
400 # bisect
400 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
401 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
401 # update to next check
402 # update to next check
402 cmdutil.bail_if_changed(repo)
403 cmdutil.bail_if_changed(repo)
403 hg.clean(repo, nodes[0], show_stats=False)
404 hg.clean(repo, nodes[0], show_stats=False)
404 finally:
405 finally:
405 hbisect.save_state(repo, state)
406 hbisect.save_state(repo, state)
406 print_result(nodes, good)
407 print_result(nodes, good)
407 return
408 return
408
409
409 # update state
410 # update state
410
411
411 if rev:
412 if rev:
412 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
413 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
413 else:
414 else:
414 nodes = [repo.lookup('.')]
415 nodes = [repo.lookup('.')]
415
416
416 if good or bad or skip:
417 if good or bad or skip:
417 if good:
418 if good:
418 state['good'] += nodes
419 state['good'] += nodes
419 elif bad:
420 elif bad:
420 state['bad'] += nodes
421 state['bad'] += nodes
421 elif skip:
422 elif skip:
422 state['skip'] += nodes
423 state['skip'] += nodes
423 hbisect.save_state(repo, state)
424 hbisect.save_state(repo, state)
424
425
425 if not check_state(state):
426 if not check_state(state):
426 return
427 return
427
428
428 # actually bisect
429 # actually bisect
429 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
430 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
430 if changesets == 0:
431 if changesets == 0:
431 print_result(nodes, good)
432 print_result(nodes, good)
432 else:
433 else:
433 assert len(nodes) == 1 # only a single node can be tested next
434 assert len(nodes) == 1 # only a single node can be tested next
434 node = nodes[0]
435 node = nodes[0]
435 # compute the approximate number of remaining tests
436 # compute the approximate number of remaining tests
436 tests, size = 0, 2
437 tests, size = 0, 2
437 while size <= changesets:
438 while size <= changesets:
438 tests, size = tests + 1, size * 2
439 tests, size = tests + 1, size * 2
439 rev = repo.changelog.rev(node)
440 rev = repo.changelog.rev(node)
440 ui.write(_("Testing changeset %d:%s "
441 ui.write(_("Testing changeset %d:%s "
441 "(%d changesets remaining, ~%d tests)\n")
442 "(%d changesets remaining, ~%d tests)\n")
442 % (rev, short(node), changesets, tests))
443 % (rev, short(node), changesets, tests))
443 if not noupdate:
444 if not noupdate:
444 cmdutil.bail_if_changed(repo)
445 cmdutil.bail_if_changed(repo)
445 return hg.clean(repo, node)
446 return hg.clean(repo, node)
446
447
447 def branch(ui, repo, label=None, **opts):
448 def branch(ui, repo, label=None, **opts):
448 """set or show the current branch name
449 """set or show the current branch name
449
450
450 With no argument, show the current branch name. With one argument,
451 With no argument, show the current branch name. With one argument,
451 set the working directory branch name (the branch will not exist
452 set the working directory branch name (the branch will not exist
452 in the repository until the next commit). Standard practice
453 in the repository until the next commit). Standard practice
453 recommends that primary development take place on the 'default'
454 recommends that primary development take place on the 'default'
454 branch.
455 branch.
455
456
456 Unless -f/--force is specified, branch will not let you set a
457 Unless -f/--force is specified, branch will not let you set a
457 branch name that already exists, even if it's inactive.
458 branch name that already exists, even if it's inactive.
458
459
459 Use -C/--clean to reset the working directory branch to that of
460 Use -C/--clean to reset the working directory branch to that of
460 the parent of the working directory, negating a previous branch
461 the parent of the working directory, negating a previous branch
461 change.
462 change.
462
463
463 Use the command :hg:`update` to switch to an existing branch. Use
464 Use the command :hg:`update` to switch to an existing branch. Use
464 :hg:`commit --close-branch` to mark this branch as closed.
465 :hg:`commit --close-branch` to mark this branch as closed.
465
466
466 Returns 0 on success.
467 Returns 0 on success.
467 """
468 """
468
469
469 if opts.get('clean'):
470 if opts.get('clean'):
470 label = repo[None].parents()[0].branch()
471 label = repo[None].parents()[0].branch()
471 repo.dirstate.setbranch(label)
472 repo.dirstate.setbranch(label)
472 ui.status(_('reset working directory to branch %s\n') % label)
473 ui.status(_('reset working directory to branch %s\n') % label)
473 elif label:
474 elif label:
474 utflabel = encoding.fromlocal(label)
475 utflabel = encoding.fromlocal(label)
475 if not opts.get('force') and utflabel in repo.branchtags():
476 if not opts.get('force') and utflabel in repo.branchtags():
476 if label not in [p.branch() for p in repo.parents()]:
477 if label not in [p.branch() for p in repo.parents()]:
477 raise util.Abort(_('a branch of the same name already exists'
478 raise util.Abort(_('a branch of the same name already exists'
478 " (use 'hg update' to switch to it)"))
479 " (use 'hg update' to switch to it)"))
479 repo.dirstate.setbranch(utflabel)
480 repo.dirstate.setbranch(utflabel)
480 ui.status(_('marked working directory as branch %s\n') % label)
481 ui.status(_('marked working directory as branch %s\n') % label)
481 else:
482 else:
482 ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
483 ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
483
484
484 def branches(ui, repo, active=False, closed=False):
485 def branches(ui, repo, active=False, closed=False):
485 """list repository named branches
486 """list repository named branches
486
487
487 List the repository's named branches, indicating which ones are
488 List the repository's named branches, indicating which ones are
488 inactive. If -c/--closed is specified, also list branches which have
489 inactive. If -c/--closed is specified, also list branches which have
489 been marked closed (see :hg:`commit --close-branch`).
490 been marked closed (see :hg:`commit --close-branch`).
490
491
491 If -a/--active is specified, only show active branches. A branch
492 If -a/--active is specified, only show active branches. A branch
492 is considered active if it contains repository heads.
493 is considered active if it contains repository heads.
493
494
494 Use the command :hg:`update` to switch to an existing branch.
495 Use the command :hg:`update` to switch to an existing branch.
495
496
496 Returns 0.
497 Returns 0.
497 """
498 """
498
499
499 hexfunc = ui.debugflag and hex or short
500 hexfunc = ui.debugflag and hex or short
500 activebranches = [repo[n].branch() for n in repo.heads()]
501 activebranches = [repo[n].branch() for n in repo.heads()]
501 def testactive(tag, node):
502 def testactive(tag, node):
502 realhead = tag in activebranches
503 realhead = tag in activebranches
503 open = node in repo.branchheads(tag, closed=False)
504 open = node in repo.branchheads(tag, closed=False)
504 return realhead and open
505 return realhead and open
505 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
506 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
506 for tag, node in repo.branchtags().items()],
507 for tag, node in repo.branchtags().items()],
507 reverse=True)
508 reverse=True)
508
509
509 for isactive, node, tag in branches:
510 for isactive, node, tag in branches:
510 if (not active) or isactive:
511 if (not active) or isactive:
511 encodedtag = encoding.tolocal(tag)
512 encodedtag = encoding.tolocal(tag)
512 if ui.quiet:
513 if ui.quiet:
513 ui.write("%s\n" % encodedtag)
514 ui.write("%s\n" % encodedtag)
514 else:
515 else:
515 hn = repo.lookup(node)
516 hn = repo.lookup(node)
516 if isactive:
517 if isactive:
517 label = 'branches.active'
518 label = 'branches.active'
518 notice = ''
519 notice = ''
519 elif hn not in repo.branchheads(tag, closed=False):
520 elif hn not in repo.branchheads(tag, closed=False):
520 if not closed:
521 if not closed:
521 continue
522 continue
522 label = 'branches.closed'
523 label = 'branches.closed'
523 notice = _(' (closed)')
524 notice = _(' (closed)')
524 else:
525 else:
525 label = 'branches.inactive'
526 label = 'branches.inactive'
526 notice = _(' (inactive)')
527 notice = _(' (inactive)')
527 if tag == repo.dirstate.branch():
528 if tag == repo.dirstate.branch():
528 label = 'branches.current'
529 label = 'branches.current'
529 rev = str(node).rjust(31 - encoding.colwidth(encodedtag))
530 rev = str(node).rjust(31 - encoding.colwidth(encodedtag))
530 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
531 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
531 encodedtag = ui.label(encodedtag, label)
532 encodedtag = ui.label(encodedtag, label)
532 ui.write("%s %s%s\n" % (encodedtag, rev, notice))
533 ui.write("%s %s%s\n" % (encodedtag, rev, notice))
533
534
534 def bundle(ui, repo, fname, dest=None, **opts):
535 def bundle(ui, repo, fname, dest=None, **opts):
535 """create a changegroup file
536 """create a changegroup file
536
537
537 Generate a compressed changegroup file collecting changesets not
538 Generate a compressed changegroup file collecting changesets not
538 known to be in another repository.
539 known to be in another repository.
539
540
540 If you omit the destination repository, then hg assumes the
541 If you omit the destination repository, then hg assumes the
541 destination will have all the nodes you specify with --base
542 destination will have all the nodes you specify with --base
542 parameters. To create a bundle containing all changesets, use
543 parameters. To create a bundle containing all changesets, use
543 -a/--all (or --base null).
544 -a/--all (or --base null).
544
545
545 You can change compression method with the -t/--type option.
546 You can change compression method with the -t/--type option.
546 The available compression methods are: none, bzip2, and
547 The available compression methods are: none, bzip2, and
547 gzip (by default, bundles are compressed using bzip2).
548 gzip (by default, bundles are compressed using bzip2).
548
549
549 The bundle file can then be transferred using conventional means
550 The bundle file can then be transferred using conventional means
550 and applied to another repository with the unbundle or pull
551 and applied to another repository with the unbundle or pull
551 command. This is useful when direct push and pull are not
552 command. This is useful when direct push and pull are not
552 available or when exporting an entire repository is undesirable.
553 available or when exporting an entire repository is undesirable.
553
554
554 Applying bundles preserves all changeset contents including
555 Applying bundles preserves all changeset contents including
555 permissions, copy/rename information, and revision history.
556 permissions, copy/rename information, and revision history.
556
557
557 Returns 0 on success, 1 if no changes found.
558 Returns 0 on success, 1 if no changes found.
558 """
559 """
559 revs = opts.get('rev') or None
560 revs = opts.get('rev') or None
560 if opts.get('all'):
561 if opts.get('all'):
561 base = ['null']
562 base = ['null']
562 else:
563 else:
563 base = opts.get('base')
564 base = opts.get('base')
564 if base:
565 if base:
565 if dest:
566 if dest:
566 raise util.Abort(_("--base is incompatible with specifying "
567 raise util.Abort(_("--base is incompatible with specifying "
567 "a destination"))
568 "a destination"))
568 base = [repo.lookup(rev) for rev in base]
569 base = [repo.lookup(rev) for rev in base]
569 # create the right base
570 # create the right base
570 # XXX: nodesbetween / changegroup* should be "fixed" instead
571 # XXX: nodesbetween / changegroup* should be "fixed" instead
571 o = []
572 o = []
572 has = set((nullid,))
573 has = set((nullid,))
573 for n in base:
574 for n in base:
574 has.update(repo.changelog.reachable(n))
575 has.update(repo.changelog.reachable(n))
575 if revs:
576 if revs:
576 revs = [repo.lookup(rev) for rev in revs]
577 revs = [repo.lookup(rev) for rev in revs]
577 visit = revs[:]
578 visit = revs[:]
578 has.difference_update(visit)
579 has.difference_update(visit)
579 else:
580 else:
580 visit = repo.changelog.heads()
581 visit = repo.changelog.heads()
581 seen = {}
582 seen = {}
582 while visit:
583 while visit:
583 n = visit.pop(0)
584 n = visit.pop(0)
584 parents = [p for p in repo.changelog.parents(n) if p not in has]
585 parents = [p for p in repo.changelog.parents(n) if p not in has]
585 if len(parents) == 0:
586 if len(parents) == 0:
586 if n not in has:
587 if n not in has:
587 o.append(n)
588 o.append(n)
588 else:
589 else:
589 for p in parents:
590 for p in parents:
590 if p not in seen:
591 if p not in seen:
591 seen[p] = 1
592 seen[p] = 1
592 visit.append(p)
593 visit.append(p)
593 else:
594 else:
594 dest = ui.expandpath(dest or 'default-push', dest or 'default')
595 dest = ui.expandpath(dest or 'default-push', dest or 'default')
595 dest, branches = hg.parseurl(dest, opts.get('branch'))
596 dest, branches = hg.parseurl(dest, opts.get('branch'))
596 other = hg.repository(hg.remoteui(repo, opts), dest)
597 other = hg.repository(hg.remoteui(repo, opts), dest)
597 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
598 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
598 if revs:
599 if revs:
599 revs = [repo.lookup(rev) for rev in revs]
600 revs = [repo.lookup(rev) for rev in revs]
600 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
601 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
601
602
602 if not o:
603 if not o:
603 ui.status(_("no changes found\n"))
604 ui.status(_("no changes found\n"))
604 return 1
605 return 1
605
606
606 if revs:
607 if revs:
607 cg = repo.changegroupsubset(o, revs, 'bundle')
608 cg = repo.changegroupsubset(o, revs, 'bundle')
608 else:
609 else:
609 cg = repo.changegroup(o, 'bundle')
610 cg = repo.changegroup(o, 'bundle')
610
611
611 bundletype = opts.get('type', 'bzip2').lower()
612 bundletype = opts.get('type', 'bzip2').lower()
612 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
613 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
613 bundletype = btypes.get(bundletype)
614 bundletype = btypes.get(bundletype)
614 if bundletype not in changegroup.bundletypes:
615 if bundletype not in changegroup.bundletypes:
615 raise util.Abort(_('unknown bundle type specified with --type'))
616 raise util.Abort(_('unknown bundle type specified with --type'))
616
617
617 changegroup.writebundle(cg, fname, bundletype)
618 changegroup.writebundle(cg, fname, bundletype)
618
619
619 def cat(ui, repo, file1, *pats, **opts):
620 def cat(ui, repo, file1, *pats, **opts):
620 """output the current or given revision of files
621 """output the current or given revision of files
621
622
622 Print the specified files as they were at the given revision. If
623 Print the specified files as they were at the given revision. If
623 no revision is given, the parent of the working directory is used,
624 no revision is given, the parent of the working directory is used,
624 or tip if no revision is checked out.
625 or tip if no revision is checked out.
625
626
626 Output may be to a file, in which case the name of the file is
627 Output may be to a file, in which case the name of the file is
627 given using a format string. The formatting rules are the same as
628 given using a format string. The formatting rules are the same as
628 for the export command, with the following additions:
629 for the export command, with the following additions:
629
630
630 :``%s``: basename of file being printed
631 :``%s``: basename of file being printed
631 :``%d``: dirname of file being printed, or '.' if in repository root
632 :``%d``: dirname of file being printed, or '.' if in repository root
632 :``%p``: root-relative path name of file being printed
633 :``%p``: root-relative path name of file being printed
633
634
634 Returns 0 on success.
635 Returns 0 on success.
635 """
636 """
636 ctx = repo[opts.get('rev')]
637 ctx = repo[opts.get('rev')]
637 err = 1
638 err = 1
638 m = cmdutil.match(repo, (file1,) + pats, opts)
639 m = cmdutil.match(repo, (file1,) + pats, opts)
639 for abs in ctx.walk(m):
640 for abs in ctx.walk(m):
640 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
641 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
641 data = ctx[abs].data()
642 data = ctx[abs].data()
642 if opts.get('decode'):
643 if opts.get('decode'):
643 data = repo.wwritedata(abs, data)
644 data = repo.wwritedata(abs, data)
644 fp.write(data)
645 fp.write(data)
645 err = 0
646 err = 0
646 return err
647 return err
647
648
648 def clone(ui, source, dest=None, **opts):
649 def clone(ui, source, dest=None, **opts):
649 """make a copy of an existing repository
650 """make a copy of an existing repository
650
651
651 Create a copy of an existing repository in a new directory.
652 Create a copy of an existing repository in a new directory.
652
653
653 If no destination directory name is specified, it defaults to the
654 If no destination directory name is specified, it defaults to the
654 basename of the source.
655 basename of the source.
655
656
656 The location of the source is added to the new repository's
657 The location of the source is added to the new repository's
657 .hg/hgrc file, as the default to be used for future pulls.
658 .hg/hgrc file, as the default to be used for future pulls.
658
659
659 See :hg:`help urls` for valid source format details.
660 See :hg:`help urls` for valid source format details.
660
661
661 It is possible to specify an ``ssh://`` URL as the destination, but no
662 It is possible to specify an ``ssh://`` URL as the destination, but no
662 .hg/hgrc and working directory will be created on the remote side.
663 .hg/hgrc and working directory will be created on the remote side.
663 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
664 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
664
665
665 A set of changesets (tags, or branch names) to pull may be specified
666 A set of changesets (tags, or branch names) to pull may be specified
666 by listing each changeset (tag, or branch name) with -r/--rev.
667 by listing each changeset (tag, or branch name) with -r/--rev.
667 If -r/--rev is used, the cloned repository will contain only a subset
668 If -r/--rev is used, the cloned repository will contain only a subset
668 of the changesets of the source repository. Only the set of changesets
669 of the changesets of the source repository. Only the set of changesets
669 defined by all -r/--rev options (including all their ancestors)
670 defined by all -r/--rev options (including all their ancestors)
670 will be pulled into the destination repository.
671 will be pulled into the destination repository.
671 No subsequent changesets (including subsequent tags) will be present
672 No subsequent changesets (including subsequent tags) will be present
672 in the destination.
673 in the destination.
673
674
674 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
675 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
675 local source repositories.
676 local source repositories.
676
677
677 For efficiency, hardlinks are used for cloning whenever the source
678 For efficiency, hardlinks are used for cloning whenever the source
678 and destination are on the same filesystem (note this applies only
679 and destination are on the same filesystem (note this applies only
679 to the repository data, not to the working directory). Some
680 to the repository data, not to the working directory). Some
680 filesystems, such as AFS, implement hardlinking incorrectly, but
681 filesystems, such as AFS, implement hardlinking incorrectly, but
681 do not report errors. In these cases, use the --pull option to
682 do not report errors. In these cases, use the --pull option to
682 avoid hardlinking.
683 avoid hardlinking.
683
684
684 In some cases, you can clone repositories and the working directory
685 In some cases, you can clone repositories and the working directory
685 using full hardlinks with ::
686 using full hardlinks with ::
686
687
687 $ cp -al REPO REPOCLONE
688 $ cp -al REPO REPOCLONE
688
689
689 This is the fastest way to clone, but it is not always safe. The
690 This is the fastest way to clone, but it is not always safe. The
690 operation is not atomic (making sure REPO is not modified during
691 operation is not atomic (making sure REPO is not modified during
691 the operation is up to you) and you have to make sure your editor
692 the operation is up to you) and you have to make sure your editor
692 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
693 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
693 this is not compatible with certain extensions that place their
694 this is not compatible with certain extensions that place their
694 metadata under the .hg directory, such as mq.
695 metadata under the .hg directory, such as mq.
695
696
696 Mercurial will update the working directory to the first applicable
697 Mercurial will update the working directory to the first applicable
697 revision from this list:
698 revision from this list:
698
699
699 a) null if -U or the source repository has no changesets
700 a) null if -U or the source repository has no changesets
700 b) if -u . and the source repository is local, the first parent of
701 b) if -u . and the source repository is local, the first parent of
701 the source repository's working directory
702 the source repository's working directory
702 c) the changeset specified with -u (if a branch name, this means the
703 c) the changeset specified with -u (if a branch name, this means the
703 latest head of that branch)
704 latest head of that branch)
704 d) the changeset specified with -r
705 d) the changeset specified with -r
705 e) the tipmost head specified with -b
706 e) the tipmost head specified with -b
706 f) the tipmost head specified with the url#branch source syntax
707 f) the tipmost head specified with the url#branch source syntax
707 g) the tipmost head of the default branch
708 g) the tipmost head of the default branch
708 h) tip
709 h) tip
709
710
710 Returns 0 on success.
711 Returns 0 on success.
711 """
712 """
712 if opts.get('noupdate') and opts.get('updaterev'):
713 if opts.get('noupdate') and opts.get('updaterev'):
713 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
714 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
714
715
715 r = hg.clone(hg.remoteui(ui, opts), source, dest,
716 r = hg.clone(hg.remoteui(ui, opts), source, dest,
716 pull=opts.get('pull'),
717 pull=opts.get('pull'),
717 stream=opts.get('uncompressed'),
718 stream=opts.get('uncompressed'),
718 rev=opts.get('rev'),
719 rev=opts.get('rev'),
719 update=opts.get('updaterev') or not opts.get('noupdate'),
720 update=opts.get('updaterev') or not opts.get('noupdate'),
720 branch=opts.get('branch'))
721 branch=opts.get('branch'))
721
722
722 return r is None
723 return r is None
723
724
724 def commit(ui, repo, *pats, **opts):
725 def commit(ui, repo, *pats, **opts):
725 """commit the specified files or all outstanding changes
726 """commit the specified files or all outstanding changes
726
727
727 Commit changes to the given files into the repository. Unlike a
728 Commit changes to the given files into the repository. Unlike a
728 centralized RCS, this operation is a local operation. See
729 centralized RCS, this operation is a local operation. See
729 :hg:`push` for a way to actively distribute your changes.
730 :hg:`push` for a way to actively distribute your changes.
730
731
731 If a list of files is omitted, all changes reported by :hg:`status`
732 If a list of files is omitted, all changes reported by :hg:`status`
732 will be committed.
733 will be committed.
733
734
734 If you are committing the result of a merge, do not provide any
735 If you are committing the result of a merge, do not provide any
735 filenames or -I/-X filters.
736 filenames or -I/-X filters.
736
737
737 If no commit message is specified, Mercurial starts your
738 If no commit message is specified, Mercurial starts your
738 configured editor where you can enter a message. In case your
739 configured editor where you can enter a message. In case your
739 commit fails, you will find a backup of your message in
740 commit fails, you will find a backup of your message in
740 ``.hg/last-message.txt``.
741 ``.hg/last-message.txt``.
741
742
742 See :hg:`help dates` for a list of formats valid for -d/--date.
743 See :hg:`help dates` for a list of formats valid for -d/--date.
743
744
744 Returns 0 on success, 1 if nothing changed.
745 Returns 0 on success, 1 if nothing changed.
745 """
746 """
746 extra = {}
747 extra = {}
747 if opts.get('close_branch'):
748 if opts.get('close_branch'):
748 if repo['.'].node() not in repo.branchheads():
749 if repo['.'].node() not in repo.branchheads():
749 # The topo heads set is included in the branch heads set of the
750 # The topo heads set is included in the branch heads set of the
750 # current branch, so it's sufficient to test branchheads
751 # current branch, so it's sufficient to test branchheads
751 raise util.Abort(_('can only close branch heads'))
752 raise util.Abort(_('can only close branch heads'))
752 extra['close'] = 1
753 extra['close'] = 1
753 e = cmdutil.commiteditor
754 e = cmdutil.commiteditor
754 if opts.get('force_editor'):
755 if opts.get('force_editor'):
755 e = cmdutil.commitforceeditor
756 e = cmdutil.commitforceeditor
756
757
757 def commitfunc(ui, repo, message, match, opts):
758 def commitfunc(ui, repo, message, match, opts):
758 return repo.commit(message, opts.get('user'), opts.get('date'), match,
759 return repo.commit(message, opts.get('user'), opts.get('date'), match,
759 editor=e, extra=extra)
760 editor=e, extra=extra)
760
761
761 branch = repo[None].branch()
762 branch = repo[None].branch()
762 bheads = repo.branchheads(branch)
763 bheads = repo.branchheads(branch)
763
764
764 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
765 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
765 if not node:
766 if not node:
766 ui.status(_("nothing changed\n"))
767 ui.status(_("nothing changed\n"))
767 return 1
768 return 1
768
769
769 ctx = repo[node]
770 ctx = repo[node]
770 parents = ctx.parents()
771 parents = ctx.parents()
771
772
772 if bheads and not [x for x in parents
773 if bheads and not [x for x in parents
773 if x.node() in bheads and x.branch() == branch]:
774 if x.node() in bheads and x.branch() == branch]:
774 ui.status(_('created new head\n'))
775 ui.status(_('created new head\n'))
775 # The message is not printed for initial roots. For the other
776 # The message is not printed for initial roots. For the other
776 # changesets, it is printed in the following situations:
777 # changesets, it is printed in the following situations:
777 #
778 #
778 # Par column: for the 2 parents with ...
779 # Par column: for the 2 parents with ...
779 # N: null or no parent
780 # N: null or no parent
780 # B: parent is on another named branch
781 # B: parent is on another named branch
781 # C: parent is a regular non head changeset
782 # C: parent is a regular non head changeset
782 # H: parent was a branch head of the current branch
783 # H: parent was a branch head of the current branch
783 # Msg column: whether we print "created new head" message
784 # Msg column: whether we print "created new head" message
784 # In the following, it is assumed that there already exists some
785 # In the following, it is assumed that there already exists some
785 # initial branch heads of the current branch, otherwise nothing is
786 # initial branch heads of the current branch, otherwise nothing is
786 # printed anyway.
787 # printed anyway.
787 #
788 #
788 # Par Msg Comment
789 # Par Msg Comment
789 # NN y additional topo root
790 # NN y additional topo root
790 #
791 #
791 # BN y additional branch root
792 # BN y additional branch root
792 # CN y additional topo head
793 # CN y additional topo head
793 # HN n usual case
794 # HN n usual case
794 #
795 #
795 # BB y weird additional branch root
796 # BB y weird additional branch root
796 # CB y branch merge
797 # CB y branch merge
797 # HB n merge with named branch
798 # HB n merge with named branch
798 #
799 #
799 # CC y additional head from merge
800 # CC y additional head from merge
800 # CH n merge with a head
801 # CH n merge with a head
801 #
802 #
802 # HH n head merge: head count decreases
803 # HH n head merge: head count decreases
803
804
804 if not opts.get('close_branch'):
805 if not opts.get('close_branch'):
805 for r in parents:
806 for r in parents:
806 if r.extra().get('close') and r.branch() == branch:
807 if r.extra().get('close') and r.branch() == branch:
807 ui.status(_('reopening closed branch head %d\n') % r)
808 ui.status(_('reopening closed branch head %d\n') % r)
808
809
809 if ui.debugflag:
810 if ui.debugflag:
810 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
811 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
811 elif ui.verbose:
812 elif ui.verbose:
812 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
813 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
813
814
814 def copy(ui, repo, *pats, **opts):
815 def copy(ui, repo, *pats, **opts):
815 """mark files as copied for the next commit
816 """mark files as copied for the next commit
816
817
817 Mark dest as having copies of source files. If dest is a
818 Mark dest as having copies of source files. If dest is a
818 directory, copies are put in that directory. If dest is a file,
819 directory, copies are put in that directory. If dest is a file,
819 the source must be a single file.
820 the source must be a single file.
820
821
821 By default, this command copies the contents of files as they
822 By default, this command copies the contents of files as they
822 exist in the working directory. If invoked with -A/--after, the
823 exist in the working directory. If invoked with -A/--after, the
823 operation is recorded, but no copying is performed.
824 operation is recorded, but no copying is performed.
824
825
825 This command takes effect with the next commit. To undo a copy
826 This command takes effect with the next commit. To undo a copy
826 before that, see :hg:`revert`.
827 before that, see :hg:`revert`.
827
828
828 Returns 0 on success, 1 if errors are encountered.
829 Returns 0 on success, 1 if errors are encountered.
829 """
830 """
830 wlock = repo.wlock(False)
831 wlock = repo.wlock(False)
831 try:
832 try:
832 return cmdutil.copy(ui, repo, pats, opts)
833 return cmdutil.copy(ui, repo, pats, opts)
833 finally:
834 finally:
834 wlock.release()
835 wlock.release()
835
836
836 def debugancestor(ui, repo, *args):
837 def debugancestor(ui, repo, *args):
837 """find the ancestor revision of two revisions in a given index"""
838 """find the ancestor revision of two revisions in a given index"""
838 if len(args) == 3:
839 if len(args) == 3:
839 index, rev1, rev2 = args
840 index, rev1, rev2 = args
840 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
841 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
841 lookup = r.lookup
842 lookup = r.lookup
842 elif len(args) == 2:
843 elif len(args) == 2:
843 if not repo:
844 if not repo:
844 raise util.Abort(_("there is no Mercurial repository here "
845 raise util.Abort(_("there is no Mercurial repository here "
845 "(.hg not found)"))
846 "(.hg not found)"))
846 rev1, rev2 = args
847 rev1, rev2 = args
847 r = repo.changelog
848 r = repo.changelog
848 lookup = repo.lookup
849 lookup = repo.lookup
849 else:
850 else:
850 raise util.Abort(_('either two or three arguments required'))
851 raise util.Abort(_('either two or three arguments required'))
851 a = r.ancestor(lookup(rev1), lookup(rev2))
852 a = r.ancestor(lookup(rev1), lookup(rev2))
852 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
853 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
853
854
854 def debugbuilddag(ui, repo, text,
855 def debugbuilddag(ui, repo, text,
855 mergeable_file=False,
856 mergeable_file=False,
856 appended_file=False,
857 appended_file=False,
857 overwritten_file=False,
858 overwritten_file=False,
858 new_file=False):
859 new_file=False):
859 """builds a repo with a given dag from scratch in the current empty repo
860 """builds a repo with a given dag from scratch in the current empty repo
860
861
861 Elements:
862 Elements:
862
863
863 - "+n" is a linear run of n nodes based on the current default parent
864 - "+n" is a linear run of n nodes based on the current default parent
864 - "." is a single node based on the current default parent
865 - "." is a single node based on the current default parent
865 - "$" resets the default parent to null (implied at the start);
866 - "$" resets the default parent to null (implied at the start);
866 otherwise the default parent is always the last node created
867 otherwise the default parent is always the last node created
867 - "<p" sets the default parent to the backref p
868 - "<p" sets the default parent to the backref p
868 - "*p" is a fork at parent p, which is a backref
869 - "*p" is a fork at parent p, which is a backref
869 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
870 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
870 - "/p2" is a merge of the preceding node and p2
871 - "/p2" is a merge of the preceding node and p2
871 - ":tag" defines a local tag for the preceding node
872 - ":tag" defines a local tag for the preceding node
872 - "@branch" sets the named branch for subsequent nodes
873 - "@branch" sets the named branch for subsequent nodes
873 - "!command" runs the command using your shell
874 - "!command" runs the command using your shell
874 - "!!my command\\n" is like "!", but to the end of the line
875 - "!!my command\\n" is like "!", but to the end of the line
875 - "#...\\n" is a comment up to the end of the line
876 - "#...\\n" is a comment up to the end of the line
876
877
877 Whitespace between the above elements is ignored.
878 Whitespace between the above elements is ignored.
878
879
879 A backref is either
880 A backref is either
880
881
881 - a number n, which references the node curr-n, where curr is the current
882 - a number n, which references the node curr-n, where curr is the current
882 node, or
883 node, or
883 - the name of a local tag you placed earlier using ":tag", or
884 - the name of a local tag you placed earlier using ":tag", or
884 - empty to denote the default parent.
885 - empty to denote the default parent.
885
886
886 All string valued-elements are either strictly alphanumeric, or must
887 All string valued-elements are either strictly alphanumeric, or must
887 be enclosed in double quotes ("..."), with "\\" as escape character.
888 be enclosed in double quotes ("..."), with "\\" as escape character.
888
889
889 Note that the --overwritten-file and --appended-file options imply the
890 Note that the --overwritten-file and --appended-file options imply the
890 use of "HGMERGE=internal:local" during DAG buildup.
891 use of "HGMERGE=internal:local" during DAG buildup.
891 """
892 """
892
893
893 if not (mergeable_file or appended_file or overwritten_file or new_file):
894 if not (mergeable_file or appended_file or overwritten_file or new_file):
894 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
895 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
895
896
896 if len(repo.changelog) > 0:
897 if len(repo.changelog) > 0:
897 raise util.Abort(_('repository is not empty'))
898 raise util.Abort(_('repository is not empty'))
898
899
899 if overwritten_file or appended_file:
900 if overwritten_file or appended_file:
900 # we don't want to fail in merges during buildup
901 # we don't want to fail in merges during buildup
901 os.environ['HGMERGE'] = 'internal:local'
902 os.environ['HGMERGE'] = 'internal:local'
902
903
903 def writefile(fname, text, fmode="wb"):
904 def writefile(fname, text, fmode="wb"):
904 f = open(fname, fmode)
905 f = open(fname, fmode)
905 try:
906 try:
906 f.write(text)
907 f.write(text)
907 finally:
908 finally:
908 f.close()
909 f.close()
909
910
910 if mergeable_file:
911 if mergeable_file:
911 linesperrev = 2
912 linesperrev = 2
912 # determine number of revs in DAG
913 # determine number of revs in DAG
913 n = 0
914 n = 0
914 for type, data in dagparser.parsedag(text):
915 for type, data in dagparser.parsedag(text):
915 if type == 'n':
916 if type == 'n':
916 n += 1
917 n += 1
917 # make a file with k lines per rev
918 # make a file with k lines per rev
918 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
919 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
919 + "\n")
920 + "\n")
920
921
921 at = -1
922 at = -1
922 atbranch = 'default'
923 atbranch = 'default'
923 for type, data in dagparser.parsedag(text):
924 for type, data in dagparser.parsedag(text):
924 if type == 'n':
925 if type == 'n':
925 ui.status('node %s\n' % str(data))
926 ui.status('node %s\n' % str(data))
926 id, ps = data
927 id, ps = data
927 p1 = ps[0]
928 p1 = ps[0]
928 if p1 != at:
929 if p1 != at:
929 update(ui, repo, node=p1, clean=True)
930 update(ui, repo, node=p1, clean=True)
930 at = p1
931 at = p1
931 if repo.dirstate.branch() != atbranch:
932 if repo.dirstate.branch() != atbranch:
932 branch(ui, repo, atbranch, force=True)
933 branch(ui, repo, atbranch, force=True)
933 if len(ps) > 1:
934 if len(ps) > 1:
934 p2 = ps[1]
935 p2 = ps[1]
935 merge(ui, repo, node=p2)
936 merge(ui, repo, node=p2)
936
937
937 if mergeable_file:
938 if mergeable_file:
938 f = open("mf", "rb+")
939 f = open("mf", "rb+")
939 try:
940 try:
940 lines = f.read().split("\n")
941 lines = f.read().split("\n")
941 lines[id * linesperrev] += " r%i" % id
942 lines[id * linesperrev] += " r%i" % id
942 f.seek(0)
943 f.seek(0)
943 f.write("\n".join(lines))
944 f.write("\n".join(lines))
944 finally:
945 finally:
945 f.close()
946 f.close()
946
947
947 if appended_file:
948 if appended_file:
948 writefile("af", "r%i\n" % id, "ab")
949 writefile("af", "r%i\n" % id, "ab")
949
950
950 if overwritten_file:
951 if overwritten_file:
951 writefile("of", "r%i\n" % id)
952 writefile("of", "r%i\n" % id)
952
953
953 if new_file:
954 if new_file:
954 writefile("nf%i" % id, "r%i\n" % id)
955 writefile("nf%i" % id, "r%i\n" % id)
955
956
956 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
957 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
957 at = id
958 at = id
958 elif type == 'l':
959 elif type == 'l':
959 id, name = data
960 id, name = data
960 ui.status('tag %s\n' % name)
961 ui.status('tag %s\n' % name)
961 tag(ui, repo, name, local=True)
962 tag(ui, repo, name, local=True)
962 elif type == 'a':
963 elif type == 'a':
963 ui.status('branch %s\n' % data)
964 ui.status('branch %s\n' % data)
964 atbranch = data
965 atbranch = data
965 elif type in 'cC':
966 elif type in 'cC':
966 r = util.system(data, cwd=repo.root)
967 r = util.system(data, cwd=repo.root)
967 if r:
968 if r:
968 desc, r = util.explain_exit(r)
969 desc, r = util.explain_exit(r)
969 raise util.Abort(_('%s command %s') % (data, desc))
970 raise util.Abort(_('%s command %s') % (data, desc))
970
971
971 def debugcommands(ui, cmd='', *args):
972 def debugcommands(ui, cmd='', *args):
972 """list all available commands and options"""
973 """list all available commands and options"""
973 for cmd, vals in sorted(table.iteritems()):
974 for cmd, vals in sorted(table.iteritems()):
974 cmd = cmd.split('|')[0].strip('^')
975 cmd = cmd.split('|')[0].strip('^')
975 opts = ', '.join([i[1] for i in vals[1]])
976 opts = ', '.join([i[1] for i in vals[1]])
976 ui.write('%s: %s\n' % (cmd, opts))
977 ui.write('%s: %s\n' % (cmd, opts))
977
978
978 def debugcomplete(ui, cmd='', **opts):
979 def debugcomplete(ui, cmd='', **opts):
979 """returns the completion list associated with the given command"""
980 """returns the completion list associated with the given command"""
980
981
981 if opts.get('options'):
982 if opts.get('options'):
982 options = []
983 options = []
983 otables = [globalopts]
984 otables = [globalopts]
984 if cmd:
985 if cmd:
985 aliases, entry = cmdutil.findcmd(cmd, table, False)
986 aliases, entry = cmdutil.findcmd(cmd, table, False)
986 otables.append(entry[1])
987 otables.append(entry[1])
987 for t in otables:
988 for t in otables:
988 for o in t:
989 for o in t:
989 if "(DEPRECATED)" in o[3]:
990 if "(DEPRECATED)" in o[3]:
990 continue
991 continue
991 if o[0]:
992 if o[0]:
992 options.append('-%s' % o[0])
993 options.append('-%s' % o[0])
993 options.append('--%s' % o[1])
994 options.append('--%s' % o[1])
994 ui.write("%s\n" % "\n".join(options))
995 ui.write("%s\n" % "\n".join(options))
995 return
996 return
996
997
997 cmdlist = cmdutil.findpossible(cmd, table)
998 cmdlist = cmdutil.findpossible(cmd, table)
998 if ui.verbose:
999 if ui.verbose:
999 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1000 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1000 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1001 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1001
1002
1002 def debugfsinfo(ui, path = "."):
1003 def debugfsinfo(ui, path = "."):
1003 """show information detected about current filesystem"""
1004 """show information detected about current filesystem"""
1004 open('.debugfsinfo', 'w').write('')
1005 open('.debugfsinfo', 'w').write('')
1005 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1006 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1006 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1007 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1007 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1008 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1008 and 'yes' or 'no'))
1009 and 'yes' or 'no'))
1009 os.unlink('.debugfsinfo')
1010 os.unlink('.debugfsinfo')
1010
1011
1011 def debugrebuildstate(ui, repo, rev="tip"):
1012 def debugrebuildstate(ui, repo, rev="tip"):
1012 """rebuild the dirstate as it would look like for the given revision"""
1013 """rebuild the dirstate as it would look like for the given revision"""
1013 ctx = repo[rev]
1014 ctx = repo[rev]
1014 wlock = repo.wlock()
1015 wlock = repo.wlock()
1015 try:
1016 try:
1016 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1017 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1017 finally:
1018 finally:
1018 wlock.release()
1019 wlock.release()
1019
1020
1020 def debugcheckstate(ui, repo):
1021 def debugcheckstate(ui, repo):
1021 """validate the correctness of the current dirstate"""
1022 """validate the correctness of the current dirstate"""
1022 parent1, parent2 = repo.dirstate.parents()
1023 parent1, parent2 = repo.dirstate.parents()
1023 m1 = repo[parent1].manifest()
1024 m1 = repo[parent1].manifest()
1024 m2 = repo[parent2].manifest()
1025 m2 = repo[parent2].manifest()
1025 errors = 0
1026 errors = 0
1026 for f in repo.dirstate:
1027 for f in repo.dirstate:
1027 state = repo.dirstate[f]
1028 state = repo.dirstate[f]
1028 if state in "nr" and f not in m1:
1029 if state in "nr" and f not in m1:
1029 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1030 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1030 errors += 1
1031 errors += 1
1031 if state in "a" and f in m1:
1032 if state in "a" and f in m1:
1032 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1033 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1033 errors += 1
1034 errors += 1
1034 if state in "m" and f not in m1 and f not in m2:
1035 if state in "m" and f not in m1 and f not in m2:
1035 ui.warn(_("%s in state %s, but not in either manifest\n") %
1036 ui.warn(_("%s in state %s, but not in either manifest\n") %
1036 (f, state))
1037 (f, state))
1037 errors += 1
1038 errors += 1
1038 for f in m1:
1039 for f in m1:
1039 state = repo.dirstate[f]
1040 state = repo.dirstate[f]
1040 if state not in "nrm":
1041 if state not in "nrm":
1041 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1042 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1042 errors += 1
1043 errors += 1
1043 if errors:
1044 if errors:
1044 error = _(".hg/dirstate inconsistent with current parent's manifest")
1045 error = _(".hg/dirstate inconsistent with current parent's manifest")
1045 raise util.Abort(error)
1046 raise util.Abort(error)
1046
1047
1047 def showconfig(ui, repo, *values, **opts):
1048 def showconfig(ui, repo, *values, **opts):
1048 """show combined config settings from all hgrc files
1049 """show combined config settings from all hgrc files
1049
1050
1050 With no arguments, print names and values of all config items.
1051 With no arguments, print names and values of all config items.
1051
1052
1052 With one argument of the form section.name, print just the value
1053 With one argument of the form section.name, print just the value
1053 of that config item.
1054 of that config item.
1054
1055
1055 With multiple arguments, print names and values of all config
1056 With multiple arguments, print names and values of all config
1056 items with matching section names.
1057 items with matching section names.
1057
1058
1058 With --debug, the source (filename and line number) is printed
1059 With --debug, the source (filename and line number) is printed
1059 for each config item.
1060 for each config item.
1060
1061
1061 Returns 0 on success.
1062 Returns 0 on success.
1062 """
1063 """
1063
1064
1064 for f in util.rcpath():
1065 for f in util.rcpath():
1065 ui.debug(_('read config from: %s\n') % f)
1066 ui.debug(_('read config from: %s\n') % f)
1066 untrusted = bool(opts.get('untrusted'))
1067 untrusted = bool(opts.get('untrusted'))
1067 if values:
1068 if values:
1068 if len([v for v in values if '.' in v]) > 1:
1069 if len([v for v in values if '.' in v]) > 1:
1069 raise util.Abort(_('only one config item permitted'))
1070 raise util.Abort(_('only one config item permitted'))
1070 for section, name, value in ui.walkconfig(untrusted=untrusted):
1071 for section, name, value in ui.walkconfig(untrusted=untrusted):
1071 sectname = section + '.' + name
1072 sectname = section + '.' + name
1072 if values:
1073 if values:
1073 for v in values:
1074 for v in values:
1074 if v == section:
1075 if v == section:
1075 ui.debug('%s: ' %
1076 ui.debug('%s: ' %
1076 ui.configsource(section, name, untrusted))
1077 ui.configsource(section, name, untrusted))
1077 ui.write('%s=%s\n' % (sectname, value))
1078 ui.write('%s=%s\n' % (sectname, value))
1078 elif v == sectname:
1079 elif v == sectname:
1079 ui.debug('%s: ' %
1080 ui.debug('%s: ' %
1080 ui.configsource(section, name, untrusted))
1081 ui.configsource(section, name, untrusted))
1081 ui.write(value, '\n')
1082 ui.write(value, '\n')
1082 else:
1083 else:
1083 ui.debug('%s: ' %
1084 ui.debug('%s: ' %
1084 ui.configsource(section, name, untrusted))
1085 ui.configsource(section, name, untrusted))
1085 ui.write('%s=%s\n' % (sectname, value))
1086 ui.write('%s=%s\n' % (sectname, value))
1086
1087
1087 def debugpushkey(ui, repopath, namespace, *keyinfo):
1088 def debugpushkey(ui, repopath, namespace, *keyinfo):
1088 '''access the pushkey key/value protocol
1089 '''access the pushkey key/value protocol
1089
1090
1090 With two args, list the keys in the given namespace.
1091 With two args, list the keys in the given namespace.
1091
1092
1092 With five args, set a key to new if it currently is set to old.
1093 With five args, set a key to new if it currently is set to old.
1093 Reports success or failure.
1094 Reports success or failure.
1094 '''
1095 '''
1095
1096
1096 target = hg.repository(ui, repopath)
1097 target = hg.repository(ui, repopath)
1097 if keyinfo:
1098 if keyinfo:
1098 key, old, new = keyinfo
1099 key, old, new = keyinfo
1099 r = target.pushkey(namespace, key, old, new)
1100 r = target.pushkey(namespace, key, old, new)
1100 ui.status(str(r) + '\n')
1101 ui.status(str(r) + '\n')
1101 return not(r)
1102 return not(r)
1102 else:
1103 else:
1103 for k, v in target.listkeys(namespace).iteritems():
1104 for k, v in target.listkeys(namespace).iteritems():
1104 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1105 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1105 v.encode('string-escape')))
1106 v.encode('string-escape')))
1106
1107
1107 def debugrevspec(ui, repo, expr):
1108 def debugrevspec(ui, repo, expr):
1108 '''parse and apply a revision specification'''
1109 '''parse and apply a revision specification'''
1109 if ui.verbose:
1110 if ui.verbose:
1110 tree = revset.parse(expr)
1111 tree = revset.parse(expr)
1111 ui.note(tree, "\n")
1112 ui.note(tree, "\n")
1112 func = revset.match(expr)
1113 func = revset.match(expr)
1113 for c in func(repo, range(len(repo))):
1114 for c in func(repo, range(len(repo))):
1114 ui.write("%s\n" % c)
1115 ui.write("%s\n" % c)
1115
1116
1116 def debugsetparents(ui, repo, rev1, rev2=None):
1117 def debugsetparents(ui, repo, rev1, rev2=None):
1117 """manually set the parents of the current working directory
1118 """manually set the parents of the current working directory
1118
1119
1119 This is useful for writing repository conversion tools, but should
1120 This is useful for writing repository conversion tools, but should
1120 be used with care.
1121 be used with care.
1121
1122
1122 Returns 0 on success.
1123 Returns 0 on success.
1123 """
1124 """
1124
1125
1125 if not rev2:
1126 if not rev2:
1126 rev2 = hex(nullid)
1127 rev2 = hex(nullid)
1127
1128
1128 wlock = repo.wlock()
1129 wlock = repo.wlock()
1129 try:
1130 try:
1130 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1131 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1131 finally:
1132 finally:
1132 wlock.release()
1133 wlock.release()
1133
1134
1134 def debugstate(ui, repo, nodates=None):
1135 def debugstate(ui, repo, nodates=None):
1135 """show the contents of the current dirstate"""
1136 """show the contents of the current dirstate"""
1136 timestr = ""
1137 timestr = ""
1137 showdate = not nodates
1138 showdate = not nodates
1138 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1139 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1139 if showdate:
1140 if showdate:
1140 if ent[3] == -1:
1141 if ent[3] == -1:
1141 # Pad or slice to locale representation
1142 # Pad or slice to locale representation
1142 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1143 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1143 time.localtime(0)))
1144 time.localtime(0)))
1144 timestr = 'unset'
1145 timestr = 'unset'
1145 timestr = (timestr[:locale_len] +
1146 timestr = (timestr[:locale_len] +
1146 ' ' * (locale_len - len(timestr)))
1147 ' ' * (locale_len - len(timestr)))
1147 else:
1148 else:
1148 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1149 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1149 time.localtime(ent[3]))
1150 time.localtime(ent[3]))
1150 if ent[1] & 020000:
1151 if ent[1] & 020000:
1151 mode = 'lnk'
1152 mode = 'lnk'
1152 else:
1153 else:
1153 mode = '%3o' % (ent[1] & 0777)
1154 mode = '%3o' % (ent[1] & 0777)
1154 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1155 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1155 for f in repo.dirstate.copies():
1156 for f in repo.dirstate.copies():
1156 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1157 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1157
1158
1158 def debugsub(ui, repo, rev=None):
1159 def debugsub(ui, repo, rev=None):
1159 if rev == '':
1160 if rev == '':
1160 rev = None
1161 rev = None
1161 for k, v in sorted(repo[rev].substate.items()):
1162 for k, v in sorted(repo[rev].substate.items()):
1162 ui.write('path %s\n' % k)
1163 ui.write('path %s\n' % k)
1163 ui.write(' source %s\n' % v[0])
1164 ui.write(' source %s\n' % v[0])
1164 ui.write(' revision %s\n' % v[1])
1165 ui.write(' revision %s\n' % v[1])
1165
1166
1166 def debugdag(ui, repo, file_=None, *revs, **opts):
1167 def debugdag(ui, repo, file_=None, *revs, **opts):
1167 """format the changelog or an index DAG as a concise textual description
1168 """format the changelog or an index DAG as a concise textual description
1168
1169
1169 If you pass a revlog index, the revlog's DAG is emitted. If you list
1170 If you pass a revlog index, the revlog's DAG is emitted. If you list
1170 revision numbers, they get labelled in the output as rN.
1171 revision numbers, they get labelled in the output as rN.
1171
1172
1172 Otherwise, the changelog DAG of the current repo is emitted.
1173 Otherwise, the changelog DAG of the current repo is emitted.
1173 """
1174 """
1174 spaces = opts.get('spaces')
1175 spaces = opts.get('spaces')
1175 dots = opts.get('dots')
1176 dots = opts.get('dots')
1176 if file_:
1177 if file_:
1177 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1178 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1178 revs = set((int(r) for r in revs))
1179 revs = set((int(r) for r in revs))
1179 def events():
1180 def events():
1180 for r in rlog:
1181 for r in rlog:
1181 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1182 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1182 if r in revs:
1183 if r in revs:
1183 yield 'l', (r, "r%i" % r)
1184 yield 'l', (r, "r%i" % r)
1184 elif repo:
1185 elif repo:
1185 cl = repo.changelog
1186 cl = repo.changelog
1186 tags = opts.get('tags')
1187 tags = opts.get('tags')
1187 branches = opts.get('branches')
1188 branches = opts.get('branches')
1188 if tags:
1189 if tags:
1189 labels = {}
1190 labels = {}
1190 for l, n in repo.tags().items():
1191 for l, n in repo.tags().items():
1191 labels.setdefault(cl.rev(n), []).append(l)
1192 labels.setdefault(cl.rev(n), []).append(l)
1192 def events():
1193 def events():
1193 b = "default"
1194 b = "default"
1194 for r in cl:
1195 for r in cl:
1195 if branches:
1196 if branches:
1196 newb = cl.read(cl.node(r))[5]['branch']
1197 newb = cl.read(cl.node(r))[5]['branch']
1197 if newb != b:
1198 if newb != b:
1198 yield 'a', newb
1199 yield 'a', newb
1199 b = newb
1200 b = newb
1200 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1201 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1201 if tags:
1202 if tags:
1202 ls = labels.get(r)
1203 ls = labels.get(r)
1203 if ls:
1204 if ls:
1204 for l in ls:
1205 for l in ls:
1205 yield 'l', (r, l)
1206 yield 'l', (r, l)
1206 else:
1207 else:
1207 raise util.Abort(_('need repo for changelog dag'))
1208 raise util.Abort(_('need repo for changelog dag'))
1208
1209
1209 for line in dagparser.dagtextlines(events(),
1210 for line in dagparser.dagtextlines(events(),
1210 addspaces=spaces,
1211 addspaces=spaces,
1211 wraplabels=True,
1212 wraplabels=True,
1212 wrapannotations=True,
1213 wrapannotations=True,
1213 wrapnonlinear=dots,
1214 wrapnonlinear=dots,
1214 usedots=dots,
1215 usedots=dots,
1215 maxlinewidth=70):
1216 maxlinewidth=70):
1216 ui.write(line)
1217 ui.write(line)
1217 ui.write("\n")
1218 ui.write("\n")
1218
1219
1219 def debugdata(ui, repo, file_, rev):
1220 def debugdata(ui, repo, file_, rev):
1220 """dump the contents of a data file revision"""
1221 """dump the contents of a data file revision"""
1221 r = None
1222 r = None
1222 if repo:
1223 if repo:
1223 filelog = repo.file(file_)
1224 filelog = repo.file(file_)
1224 if len(filelog):
1225 if len(filelog):
1225 r = filelog
1226 r = filelog
1226 if not r:
1227 if not r:
1227 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1228 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1228 try:
1229 try:
1229 ui.write(r.revision(r.lookup(rev)))
1230 ui.write(r.revision(r.lookup(rev)))
1230 except KeyError:
1231 except KeyError:
1231 raise util.Abort(_('invalid revision identifier %s') % rev)
1232 raise util.Abort(_('invalid revision identifier %s') % rev)
1232
1233
1233 def debugdate(ui, date, range=None, **opts):
1234 def debugdate(ui, date, range=None, **opts):
1234 """parse and display a date"""
1235 """parse and display a date"""
1235 if opts["extended"]:
1236 if opts["extended"]:
1236 d = util.parsedate(date, util.extendeddateformats)
1237 d = util.parsedate(date, util.extendeddateformats)
1237 else:
1238 else:
1238 d = util.parsedate(date)
1239 d = util.parsedate(date)
1239 ui.write("internal: %s %s\n" % d)
1240 ui.write("internal: %s %s\n" % d)
1240 ui.write("standard: %s\n" % util.datestr(d))
1241 ui.write("standard: %s\n" % util.datestr(d))
1241 if range:
1242 if range:
1242 m = util.matchdate(range)
1243 m = util.matchdate(range)
1243 ui.write("match: %s\n" % m(d[0]))
1244 ui.write("match: %s\n" % m(d[0]))
1244
1245
1245 def debugindex(ui, repo, file_):
1246 def debugindex(ui, repo, file_):
1246 """dump the contents of an index file"""
1247 """dump the contents of an index file"""
1247 r = None
1248 r = None
1248 if repo:
1249 if repo:
1249 filelog = repo.file(file_)
1250 filelog = repo.file(file_)
1250 if len(filelog):
1251 if len(filelog):
1251 r = filelog
1252 r = filelog
1252 if not r:
1253 if not r:
1253 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1254 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1254 ui.write(" rev offset length base linkrev"
1255 ui.write(" rev offset length base linkrev"
1255 " nodeid p1 p2\n")
1256 " nodeid p1 p2\n")
1256 for i in r:
1257 for i in r:
1257 node = r.node(i)
1258 node = r.node(i)
1258 try:
1259 try:
1259 pp = r.parents(node)
1260 pp = r.parents(node)
1260 except:
1261 except:
1261 pp = [nullid, nullid]
1262 pp = [nullid, nullid]
1262 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1263 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1263 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1264 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1264 short(node), short(pp[0]), short(pp[1])))
1265 short(node), short(pp[0]), short(pp[1])))
1265
1266
1266 def debugindexdot(ui, repo, file_):
1267 def debugindexdot(ui, repo, file_):
1267 """dump an index DAG as a graphviz dot file"""
1268 """dump an index DAG as a graphviz dot file"""
1268 r = None
1269 r = None
1269 if repo:
1270 if repo:
1270 filelog = repo.file(file_)
1271 filelog = repo.file(file_)
1271 if len(filelog):
1272 if len(filelog):
1272 r = filelog
1273 r = filelog
1273 if not r:
1274 if not r:
1274 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1275 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1275 ui.write("digraph G {\n")
1276 ui.write("digraph G {\n")
1276 for i in r:
1277 for i in r:
1277 node = r.node(i)
1278 node = r.node(i)
1278 pp = r.parents(node)
1279 pp = r.parents(node)
1279 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1280 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1280 if pp[1] != nullid:
1281 if pp[1] != nullid:
1281 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1282 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1282 ui.write("}\n")
1283 ui.write("}\n")
1283
1284
1284 def debuginstall(ui):
1285 def debuginstall(ui):
1285 '''test Mercurial installation
1286 '''test Mercurial installation
1286
1287
1287 Returns 0 on success.
1288 Returns 0 on success.
1288 '''
1289 '''
1289
1290
1290 def writetemp(contents):
1291 def writetemp(contents):
1291 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1292 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1292 f = os.fdopen(fd, "wb")
1293 f = os.fdopen(fd, "wb")
1293 f.write(contents)
1294 f.write(contents)
1294 f.close()
1295 f.close()
1295 return name
1296 return name
1296
1297
1297 problems = 0
1298 problems = 0
1298
1299
1299 # encoding
1300 # encoding
1300 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1301 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1301 try:
1302 try:
1302 encoding.fromlocal("test")
1303 encoding.fromlocal("test")
1303 except util.Abort, inst:
1304 except util.Abort, inst:
1304 ui.write(" %s\n" % inst)
1305 ui.write(" %s\n" % inst)
1305 ui.write(_(" (check that your locale is properly set)\n"))
1306 ui.write(_(" (check that your locale is properly set)\n"))
1306 problems += 1
1307 problems += 1
1307
1308
1308 # compiled modules
1309 # compiled modules
1309 ui.status(_("Checking installed modules (%s)...\n")
1310 ui.status(_("Checking installed modules (%s)...\n")
1310 % os.path.dirname(__file__))
1311 % os.path.dirname(__file__))
1311 try:
1312 try:
1312 import bdiff, mpatch, base85, osutil
1313 import bdiff, mpatch, base85, osutil
1313 except Exception, inst:
1314 except Exception, inst:
1314 ui.write(" %s\n" % inst)
1315 ui.write(" %s\n" % inst)
1315 ui.write(_(" One or more extensions could not be found"))
1316 ui.write(_(" One or more extensions could not be found"))
1316 ui.write(_(" (check that you compiled the extensions)\n"))
1317 ui.write(_(" (check that you compiled the extensions)\n"))
1317 problems += 1
1318 problems += 1
1318
1319
1319 # templates
1320 # templates
1320 ui.status(_("Checking templates...\n"))
1321 ui.status(_("Checking templates...\n"))
1321 try:
1322 try:
1322 import templater
1323 import templater
1323 templater.templater(templater.templatepath("map-cmdline.default"))
1324 templater.templater(templater.templatepath("map-cmdline.default"))
1324 except Exception, inst:
1325 except Exception, inst:
1325 ui.write(" %s\n" % inst)
1326 ui.write(" %s\n" % inst)
1326 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1327 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1327 problems += 1
1328 problems += 1
1328
1329
1329 # patch
1330 # patch
1330 ui.status(_("Checking patch...\n"))
1331 ui.status(_("Checking patch...\n"))
1331 patchproblems = 0
1332 patchproblems = 0
1332 a = "1\n2\n3\n4\n"
1333 a = "1\n2\n3\n4\n"
1333 b = "1\n2\n3\ninsert\n4\n"
1334 b = "1\n2\n3\ninsert\n4\n"
1334 fa = writetemp(a)
1335 fa = writetemp(a)
1335 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1336 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1336 os.path.basename(fa))
1337 os.path.basename(fa))
1337 fd = writetemp(d)
1338 fd = writetemp(d)
1338
1339
1339 files = {}
1340 files = {}
1340 try:
1341 try:
1341 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1342 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1342 except util.Abort, e:
1343 except util.Abort, e:
1343 ui.write(_(" patch call failed:\n"))
1344 ui.write(_(" patch call failed:\n"))
1344 ui.write(" " + str(e) + "\n")
1345 ui.write(" " + str(e) + "\n")
1345 patchproblems += 1
1346 patchproblems += 1
1346 else:
1347 else:
1347 if list(files) != [os.path.basename(fa)]:
1348 if list(files) != [os.path.basename(fa)]:
1348 ui.write(_(" unexpected patch output!\n"))
1349 ui.write(_(" unexpected patch output!\n"))
1349 patchproblems += 1
1350 patchproblems += 1
1350 a = open(fa).read()
1351 a = open(fa).read()
1351 if a != b:
1352 if a != b:
1352 ui.write(_(" patch test failed!\n"))
1353 ui.write(_(" patch test failed!\n"))
1353 patchproblems += 1
1354 patchproblems += 1
1354
1355
1355 if patchproblems:
1356 if patchproblems:
1356 if ui.config('ui', 'patch'):
1357 if ui.config('ui', 'patch'):
1357 ui.write(_(" (Current patch tool may be incompatible with patch,"
1358 ui.write(_(" (Current patch tool may be incompatible with patch,"
1358 " or misconfigured. Please check your configuration"
1359 " or misconfigured. Please check your configuration"
1359 " file)\n"))
1360 " file)\n"))
1360 else:
1361 else:
1361 ui.write(_(" Internal patcher failure, please report this error"
1362 ui.write(_(" Internal patcher failure, please report this error"
1362 " to http://mercurial.selenic.com/bts/\n"))
1363 " to http://mercurial.selenic.com/bts/\n"))
1363 problems += patchproblems
1364 problems += patchproblems
1364
1365
1365 os.unlink(fa)
1366 os.unlink(fa)
1366 os.unlink(fd)
1367 os.unlink(fd)
1367
1368
1368 # editor
1369 # editor
1369 ui.status(_("Checking commit editor...\n"))
1370 ui.status(_("Checking commit editor...\n"))
1370 editor = ui.geteditor()
1371 editor = ui.geteditor()
1371 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1372 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1372 if not cmdpath:
1373 if not cmdpath:
1373 if editor == 'vi':
1374 if editor == 'vi':
1374 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1375 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1375 ui.write(_(" (specify a commit editor in your configuration"
1376 ui.write(_(" (specify a commit editor in your configuration"
1376 " file)\n"))
1377 " file)\n"))
1377 else:
1378 else:
1378 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1379 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1379 ui.write(_(" (specify a commit editor in your configuration"
1380 ui.write(_(" (specify a commit editor in your configuration"
1380 " file)\n"))
1381 " file)\n"))
1381 problems += 1
1382 problems += 1
1382
1383
1383 # check username
1384 # check username
1384 ui.status(_("Checking username...\n"))
1385 ui.status(_("Checking username...\n"))
1385 try:
1386 try:
1386 ui.username()
1387 ui.username()
1387 except util.Abort, e:
1388 except util.Abort, e:
1388 ui.write(" %s\n" % e)
1389 ui.write(" %s\n" % e)
1389 ui.write(_(" (specify a username in your configuration file)\n"))
1390 ui.write(_(" (specify a username in your configuration file)\n"))
1390 problems += 1
1391 problems += 1
1391
1392
1392 if not problems:
1393 if not problems:
1393 ui.status(_("No problems detected\n"))
1394 ui.status(_("No problems detected\n"))
1394 else:
1395 else:
1395 ui.write(_("%s problems detected,"
1396 ui.write(_("%s problems detected,"
1396 " please check your install!\n") % problems)
1397 " please check your install!\n") % problems)
1397
1398
1398 return problems
1399 return problems
1399
1400
1400 def debugrename(ui, repo, file1, *pats, **opts):
1401 def debugrename(ui, repo, file1, *pats, **opts):
1401 """dump rename information"""
1402 """dump rename information"""
1402
1403
1403 ctx = repo[opts.get('rev')]
1404 ctx = repo[opts.get('rev')]
1404 m = cmdutil.match(repo, (file1,) + pats, opts)
1405 m = cmdutil.match(repo, (file1,) + pats, opts)
1405 for abs in ctx.walk(m):
1406 for abs in ctx.walk(m):
1406 fctx = ctx[abs]
1407 fctx = ctx[abs]
1407 o = fctx.filelog().renamed(fctx.filenode())
1408 o = fctx.filelog().renamed(fctx.filenode())
1408 rel = m.rel(abs)
1409 rel = m.rel(abs)
1409 if o:
1410 if o:
1410 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1411 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1411 else:
1412 else:
1412 ui.write(_("%s not renamed\n") % rel)
1413 ui.write(_("%s not renamed\n") % rel)
1413
1414
1414 def debugwalk(ui, repo, *pats, **opts):
1415 def debugwalk(ui, repo, *pats, **opts):
1415 """show how files match on given patterns"""
1416 """show how files match on given patterns"""
1416 m = cmdutil.match(repo, pats, opts)
1417 m = cmdutil.match(repo, pats, opts)
1417 items = list(repo.walk(m))
1418 items = list(repo.walk(m))
1418 if not items:
1419 if not items:
1419 return
1420 return
1420 fmt = 'f %%-%ds %%-%ds %%s' % (
1421 fmt = 'f %%-%ds %%-%ds %%s' % (
1421 max([len(abs) for abs in items]),
1422 max([len(abs) for abs in items]),
1422 max([len(m.rel(abs)) for abs in items]))
1423 max([len(m.rel(abs)) for abs in items]))
1423 for abs in items:
1424 for abs in items:
1424 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1425 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1425 ui.write("%s\n" % line.rstrip())
1426 ui.write("%s\n" % line.rstrip())
1426
1427
1427 def diff(ui, repo, *pats, **opts):
1428 def diff(ui, repo, *pats, **opts):
1428 """diff repository (or selected files)
1429 """diff repository (or selected files)
1429
1430
1430 Show differences between revisions for the specified files.
1431 Show differences between revisions for the specified files.
1431
1432
1432 Differences between files are shown using the unified diff format.
1433 Differences between files are shown using the unified diff format.
1433
1434
1434 NOTE: diff may generate unexpected results for merges, as it will
1435 NOTE: diff may generate unexpected results for merges, as it will
1435 default to comparing against the working directory's first parent
1436 default to comparing against the working directory's first parent
1436 changeset if no revisions are specified.
1437 changeset if no revisions are specified.
1437
1438
1438 When two revision arguments are given, then changes are shown
1439 When two revision arguments are given, then changes are shown
1439 between those revisions. If only one revision is specified then
1440 between those revisions. If only one revision is specified then
1440 that revision is compared to the working directory, and, when no
1441 that revision is compared to the working directory, and, when no
1441 revisions are specified, the working directory files are compared
1442 revisions are specified, the working directory files are compared
1442 to its parent.
1443 to its parent.
1443
1444
1444 Alternatively you can specify -c/--change with a revision to see
1445 Alternatively you can specify -c/--change with a revision to see
1445 the changes in that changeset relative to its first parent.
1446 the changes in that changeset relative to its first parent.
1446
1447
1447 Without the -a/--text option, diff will avoid generating diffs of
1448 Without the -a/--text option, diff will avoid generating diffs of
1448 files it detects as binary. With -a, diff will generate a diff
1449 files it detects as binary. With -a, diff will generate a diff
1449 anyway, probably with undesirable results.
1450 anyway, probably with undesirable results.
1450
1451
1451 Use the -g/--git option to generate diffs in the git extended diff
1452 Use the -g/--git option to generate diffs in the git extended diff
1452 format. For more information, read :hg:`help diffs`.
1453 format. For more information, read :hg:`help diffs`.
1453
1454
1454 Returns 0 on success.
1455 Returns 0 on success.
1455 """
1456 """
1456
1457
1457 revs = opts.get('rev')
1458 revs = opts.get('rev')
1458 change = opts.get('change')
1459 change = opts.get('change')
1459 stat = opts.get('stat')
1460 stat = opts.get('stat')
1460 reverse = opts.get('reverse')
1461 reverse = opts.get('reverse')
1461
1462
1462 if revs and change:
1463 if revs and change:
1463 msg = _('cannot specify --rev and --change at the same time')
1464 msg = _('cannot specify --rev and --change at the same time')
1464 raise util.Abort(msg)
1465 raise util.Abort(msg)
1465 elif change:
1466 elif change:
1466 node2 = repo.lookup(change)
1467 node2 = repo.lookup(change)
1467 node1 = repo[node2].parents()[0].node()
1468 node1 = repo[node2].parents()[0].node()
1468 else:
1469 else:
1469 node1, node2 = cmdutil.revpair(repo, revs)
1470 node1, node2 = cmdutil.revpair(repo, revs)
1470
1471
1471 if reverse:
1472 if reverse:
1472 node1, node2 = node2, node1
1473 node1, node2 = node2, node1
1473
1474
1474 diffopts = patch.diffopts(ui, opts)
1475 diffopts = patch.diffopts(ui, opts)
1475 m = cmdutil.match(repo, pats, opts)
1476 m = cmdutil.match(repo, pats, opts)
1476 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1477 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1477 listsubrepos=opts.get('subrepos'))
1478 listsubrepos=opts.get('subrepos'))
1478
1479
1479 def export(ui, repo, *changesets, **opts):
1480 def export(ui, repo, *changesets, **opts):
1480 """dump the header and diffs for one or more changesets
1481 """dump the header and diffs for one or more changesets
1481
1482
1482 Print the changeset header and diffs for one or more revisions.
1483 Print the changeset header and diffs for one or more revisions.
1483
1484
1484 The information shown in the changeset header is: author, date,
1485 The information shown in the changeset header is: author, date,
1485 branch name (if non-default), changeset hash, parent(s) and commit
1486 branch name (if non-default), changeset hash, parent(s) and commit
1486 comment.
1487 comment.
1487
1488
1488 NOTE: export may generate unexpected diff output for merge
1489 NOTE: export may generate unexpected diff output for merge
1489 changesets, as it will compare the merge changeset against its
1490 changesets, as it will compare the merge changeset against its
1490 first parent only.
1491 first parent only.
1491
1492
1492 Output may be to a file, in which case the name of the file is
1493 Output may be to a file, in which case the name of the file is
1493 given using a format string. The formatting rules are as follows:
1494 given using a format string. The formatting rules are as follows:
1494
1495
1495 :``%%``: literal "%" character
1496 :``%%``: literal "%" character
1496 :``%H``: changeset hash (40 hexadecimal digits)
1497 :``%H``: changeset hash (40 hexadecimal digits)
1497 :``%N``: number of patches being generated
1498 :``%N``: number of patches being generated
1498 :``%R``: changeset revision number
1499 :``%R``: changeset revision number
1499 :``%b``: basename of the exporting repository
1500 :``%b``: basename of the exporting repository
1500 :``%h``: short-form changeset hash (12 hexadecimal digits)
1501 :``%h``: short-form changeset hash (12 hexadecimal digits)
1501 :``%n``: zero-padded sequence number, starting at 1
1502 :``%n``: zero-padded sequence number, starting at 1
1502 :``%r``: zero-padded changeset revision number
1503 :``%r``: zero-padded changeset revision number
1503
1504
1504 Without the -a/--text option, export will avoid generating diffs
1505 Without the -a/--text option, export will avoid generating diffs
1505 of files it detects as binary. With -a, export will generate a
1506 of files it detects as binary. With -a, export will generate a
1506 diff anyway, probably with undesirable results.
1507 diff anyway, probably with undesirable results.
1507
1508
1508 Use the -g/--git option to generate diffs in the git extended diff
1509 Use the -g/--git option to generate diffs in the git extended diff
1509 format. See :hg:`help diffs` for more information.
1510 format. See :hg:`help diffs` for more information.
1510
1511
1511 With the --switch-parent option, the diff will be against the
1512 With the --switch-parent option, the diff will be against the
1512 second parent. It can be useful to review a merge.
1513 second parent. It can be useful to review a merge.
1513
1514
1514 Returns 0 on success.
1515 Returns 0 on success.
1515 """
1516 """
1516 changesets += tuple(opts.get('rev', []))
1517 changesets += tuple(opts.get('rev', []))
1517 if not changesets:
1518 if not changesets:
1518 raise util.Abort(_("export requires at least one changeset"))
1519 raise util.Abort(_("export requires at least one changeset"))
1519 revs = cmdutil.revrange(repo, changesets)
1520 revs = cmdutil.revrange(repo, changesets)
1520 if len(revs) > 1:
1521 if len(revs) > 1:
1521 ui.note(_('exporting patches:\n'))
1522 ui.note(_('exporting patches:\n'))
1522 else:
1523 else:
1523 ui.note(_('exporting patch:\n'))
1524 ui.note(_('exporting patch:\n'))
1524 cmdutil.export(repo, revs, template=opts.get('output'),
1525 cmdutil.export(repo, revs, template=opts.get('output'),
1525 switch_parent=opts.get('switch_parent'),
1526 switch_parent=opts.get('switch_parent'),
1526 opts=patch.diffopts(ui, opts))
1527 opts=patch.diffopts(ui, opts))
1527
1528
1528 def forget(ui, repo, *pats, **opts):
1529 def forget(ui, repo, *pats, **opts):
1529 """forget the specified files on the next commit
1530 """forget the specified files on the next commit
1530
1531
1531 Mark the specified files so they will no longer be tracked
1532 Mark the specified files so they will no longer be tracked
1532 after the next commit.
1533 after the next commit.
1533
1534
1534 This only removes files from the current branch, not from the
1535 This only removes files from the current branch, not from the
1535 entire project history, and it does not delete them from the
1536 entire project history, and it does not delete them from the
1536 working directory.
1537 working directory.
1537
1538
1538 To undo a forget before the next commit, see :hg:`add`.
1539 To undo a forget before the next commit, see :hg:`add`.
1539
1540
1540 Returns 0 on success.
1541 Returns 0 on success.
1541 """
1542 """
1542
1543
1543 if not pats:
1544 if not pats:
1544 raise util.Abort(_('no files specified'))
1545 raise util.Abort(_('no files specified'))
1545
1546
1546 m = cmdutil.match(repo, pats, opts)
1547 m = cmdutil.match(repo, pats, opts)
1547 s = repo.status(match=m, clean=True)
1548 s = repo.status(match=m, clean=True)
1548 forget = sorted(s[0] + s[1] + s[3] + s[6])
1549 forget = sorted(s[0] + s[1] + s[3] + s[6])
1549 errs = 0
1550 errs = 0
1550
1551
1551 for f in m.files():
1552 for f in m.files():
1552 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1553 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1553 ui.warn(_('not removing %s: file is already untracked\n')
1554 ui.warn(_('not removing %s: file is already untracked\n')
1554 % m.rel(f))
1555 % m.rel(f))
1555 errs = 1
1556 errs = 1
1556
1557
1557 for f in forget:
1558 for f in forget:
1558 if ui.verbose or not m.exact(f):
1559 if ui.verbose or not m.exact(f):
1559 ui.status(_('removing %s\n') % m.rel(f))
1560 ui.status(_('removing %s\n') % m.rel(f))
1560
1561
1561 repo[None].remove(forget, unlink=False)
1562 repo[None].remove(forget, unlink=False)
1562 return errs
1563 return errs
1563
1564
1564 def grep(ui, repo, pattern, *pats, **opts):
1565 def grep(ui, repo, pattern, *pats, **opts):
1565 """search for a pattern in specified files and revisions
1566 """search for a pattern in specified files and revisions
1566
1567
1567 Search revisions of files for a regular expression.
1568 Search revisions of files for a regular expression.
1568
1569
1569 This command behaves differently than Unix grep. It only accepts
1570 This command behaves differently than Unix grep. It only accepts
1570 Python/Perl regexps. It searches repository history, not the
1571 Python/Perl regexps. It searches repository history, not the
1571 working directory. It always prints the revision number in which a
1572 working directory. It always prints the revision number in which a
1572 match appears.
1573 match appears.
1573
1574
1574 By default, grep only prints output for the first revision of a
1575 By default, grep only prints output for the first revision of a
1575 file in which it finds a match. To get it to print every revision
1576 file in which it finds a match. To get it to print every revision
1576 that contains a change in match status ("-" for a match that
1577 that contains a change in match status ("-" for a match that
1577 becomes a non-match, or "+" for a non-match that becomes a match),
1578 becomes a non-match, or "+" for a non-match that becomes a match),
1578 use the --all flag.
1579 use the --all flag.
1579
1580
1580 Returns 0 if a match is found, 1 otherwise.
1581 Returns 0 if a match is found, 1 otherwise.
1581 """
1582 """
1582 reflags = 0
1583 reflags = 0
1583 if opts.get('ignore_case'):
1584 if opts.get('ignore_case'):
1584 reflags |= re.I
1585 reflags |= re.I
1585 try:
1586 try:
1586 regexp = re.compile(pattern, reflags)
1587 regexp = re.compile(pattern, reflags)
1587 except Exception, inst:
1588 except Exception, inst:
1588 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1589 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1589 return 1
1590 return 1
1590 sep, eol = ':', '\n'
1591 sep, eol = ':', '\n'
1591 if opts.get('print0'):
1592 if opts.get('print0'):
1592 sep = eol = '\0'
1593 sep = eol = '\0'
1593
1594
1594 getfile = util.lrucachefunc(repo.file)
1595 getfile = util.lrucachefunc(repo.file)
1595
1596
1596 def matchlines(body):
1597 def matchlines(body):
1597 begin = 0
1598 begin = 0
1598 linenum = 0
1599 linenum = 0
1599 while True:
1600 while True:
1600 match = regexp.search(body, begin)
1601 match = regexp.search(body, begin)
1601 if not match:
1602 if not match:
1602 break
1603 break
1603 mstart, mend = match.span()
1604 mstart, mend = match.span()
1604 linenum += body.count('\n', begin, mstart) + 1
1605 linenum += body.count('\n', begin, mstart) + 1
1605 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1606 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1606 begin = body.find('\n', mend) + 1 or len(body)
1607 begin = body.find('\n', mend) + 1 or len(body)
1607 lend = begin - 1
1608 lend = begin - 1
1608 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1609 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1609
1610
1610 class linestate(object):
1611 class linestate(object):
1611 def __init__(self, line, linenum, colstart, colend):
1612 def __init__(self, line, linenum, colstart, colend):
1612 self.line = line
1613 self.line = line
1613 self.linenum = linenum
1614 self.linenum = linenum
1614 self.colstart = colstart
1615 self.colstart = colstart
1615 self.colend = colend
1616 self.colend = colend
1616
1617
1617 def __hash__(self):
1618 def __hash__(self):
1618 return hash((self.linenum, self.line))
1619 return hash((self.linenum, self.line))
1619
1620
1620 def __eq__(self, other):
1621 def __eq__(self, other):
1621 return self.line == other.line
1622 return self.line == other.line
1622
1623
1623 matches = {}
1624 matches = {}
1624 copies = {}
1625 copies = {}
1625 def grepbody(fn, rev, body):
1626 def grepbody(fn, rev, body):
1626 matches[rev].setdefault(fn, [])
1627 matches[rev].setdefault(fn, [])
1627 m = matches[rev][fn]
1628 m = matches[rev][fn]
1628 for lnum, cstart, cend, line in matchlines(body):
1629 for lnum, cstart, cend, line in matchlines(body):
1629 s = linestate(line, lnum, cstart, cend)
1630 s = linestate(line, lnum, cstart, cend)
1630 m.append(s)
1631 m.append(s)
1631
1632
1632 def difflinestates(a, b):
1633 def difflinestates(a, b):
1633 sm = difflib.SequenceMatcher(None, a, b)
1634 sm = difflib.SequenceMatcher(None, a, b)
1634 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1635 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1635 if tag == 'insert':
1636 if tag == 'insert':
1636 for i in xrange(blo, bhi):
1637 for i in xrange(blo, bhi):
1637 yield ('+', b[i])
1638 yield ('+', b[i])
1638 elif tag == 'delete':
1639 elif tag == 'delete':
1639 for i in xrange(alo, ahi):
1640 for i in xrange(alo, ahi):
1640 yield ('-', a[i])
1641 yield ('-', a[i])
1641 elif tag == 'replace':
1642 elif tag == 'replace':
1642 for i in xrange(alo, ahi):
1643 for i in xrange(alo, ahi):
1643 yield ('-', a[i])
1644 yield ('-', a[i])
1644 for i in xrange(blo, bhi):
1645 for i in xrange(blo, bhi):
1645 yield ('+', b[i])
1646 yield ('+', b[i])
1646
1647
1647 def display(fn, ctx, pstates, states):
1648 def display(fn, ctx, pstates, states):
1648 rev = ctx.rev()
1649 rev = ctx.rev()
1649 datefunc = ui.quiet and util.shortdate or util.datestr
1650 datefunc = ui.quiet and util.shortdate or util.datestr
1650 found = False
1651 found = False
1651 filerevmatches = {}
1652 filerevmatches = {}
1652 if opts.get('all'):
1653 if opts.get('all'):
1653 iter = difflinestates(pstates, states)
1654 iter = difflinestates(pstates, states)
1654 else:
1655 else:
1655 iter = [('', l) for l in states]
1656 iter = [('', l) for l in states]
1656 for change, l in iter:
1657 for change, l in iter:
1657 cols = [fn, str(rev)]
1658 cols = [fn, str(rev)]
1658 before, match, after = None, None, None
1659 before, match, after = None, None, None
1659 if opts.get('line_number'):
1660 if opts.get('line_number'):
1660 cols.append(str(l.linenum))
1661 cols.append(str(l.linenum))
1661 if opts.get('all'):
1662 if opts.get('all'):
1662 cols.append(change)
1663 cols.append(change)
1663 if opts.get('user'):
1664 if opts.get('user'):
1664 cols.append(ui.shortuser(ctx.user()))
1665 cols.append(ui.shortuser(ctx.user()))
1665 if opts.get('date'):
1666 if opts.get('date'):
1666 cols.append(datefunc(ctx.date()))
1667 cols.append(datefunc(ctx.date()))
1667 if opts.get('files_with_matches'):
1668 if opts.get('files_with_matches'):
1668 c = (fn, rev)
1669 c = (fn, rev)
1669 if c in filerevmatches:
1670 if c in filerevmatches:
1670 continue
1671 continue
1671 filerevmatches[c] = 1
1672 filerevmatches[c] = 1
1672 else:
1673 else:
1673 before = l.line[:l.colstart]
1674 before = l.line[:l.colstart]
1674 match = l.line[l.colstart:l.colend]
1675 match = l.line[l.colstart:l.colend]
1675 after = l.line[l.colend:]
1676 after = l.line[l.colend:]
1676 ui.write(sep.join(cols))
1677 ui.write(sep.join(cols))
1677 if before is not None:
1678 if before is not None:
1678 ui.write(sep + before)
1679 ui.write(sep + before)
1679 ui.write(match, label='grep.match')
1680 ui.write(match, label='grep.match')
1680 ui.write(after)
1681 ui.write(after)
1681 ui.write(eol)
1682 ui.write(eol)
1682 found = True
1683 found = True
1683 return found
1684 return found
1684
1685
1685 skip = {}
1686 skip = {}
1686 revfiles = {}
1687 revfiles = {}
1687 matchfn = cmdutil.match(repo, pats, opts)
1688 matchfn = cmdutil.match(repo, pats, opts)
1688 found = False
1689 found = False
1689 follow = opts.get('follow')
1690 follow = opts.get('follow')
1690
1691
1691 def prep(ctx, fns):
1692 def prep(ctx, fns):
1692 rev = ctx.rev()
1693 rev = ctx.rev()
1693 pctx = ctx.parents()[0]
1694 pctx = ctx.parents()[0]
1694 parent = pctx.rev()
1695 parent = pctx.rev()
1695 matches.setdefault(rev, {})
1696 matches.setdefault(rev, {})
1696 matches.setdefault(parent, {})
1697 matches.setdefault(parent, {})
1697 files = revfiles.setdefault(rev, [])
1698 files = revfiles.setdefault(rev, [])
1698 for fn in fns:
1699 for fn in fns:
1699 flog = getfile(fn)
1700 flog = getfile(fn)
1700 try:
1701 try:
1701 fnode = ctx.filenode(fn)
1702 fnode = ctx.filenode(fn)
1702 except error.LookupError:
1703 except error.LookupError:
1703 continue
1704 continue
1704
1705
1705 copied = flog.renamed(fnode)
1706 copied = flog.renamed(fnode)
1706 copy = follow and copied and copied[0]
1707 copy = follow and copied and copied[0]
1707 if copy:
1708 if copy:
1708 copies.setdefault(rev, {})[fn] = copy
1709 copies.setdefault(rev, {})[fn] = copy
1709 if fn in skip:
1710 if fn in skip:
1710 if copy:
1711 if copy:
1711 skip[copy] = True
1712 skip[copy] = True
1712 continue
1713 continue
1713 files.append(fn)
1714 files.append(fn)
1714
1715
1715 if fn not in matches[rev]:
1716 if fn not in matches[rev]:
1716 grepbody(fn, rev, flog.read(fnode))
1717 grepbody(fn, rev, flog.read(fnode))
1717
1718
1718 pfn = copy or fn
1719 pfn = copy or fn
1719 if pfn not in matches[parent]:
1720 if pfn not in matches[parent]:
1720 try:
1721 try:
1721 fnode = pctx.filenode(pfn)
1722 fnode = pctx.filenode(pfn)
1722 grepbody(pfn, parent, flog.read(fnode))
1723 grepbody(pfn, parent, flog.read(fnode))
1723 except error.LookupError:
1724 except error.LookupError:
1724 pass
1725 pass
1725
1726
1726 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1727 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1727 rev = ctx.rev()
1728 rev = ctx.rev()
1728 parent = ctx.parents()[0].rev()
1729 parent = ctx.parents()[0].rev()
1729 for fn in sorted(revfiles.get(rev, [])):
1730 for fn in sorted(revfiles.get(rev, [])):
1730 states = matches[rev][fn]
1731 states = matches[rev][fn]
1731 copy = copies.get(rev, {}).get(fn)
1732 copy = copies.get(rev, {}).get(fn)
1732 if fn in skip:
1733 if fn in skip:
1733 if copy:
1734 if copy:
1734 skip[copy] = True
1735 skip[copy] = True
1735 continue
1736 continue
1736 pstates = matches.get(parent, {}).get(copy or fn, [])
1737 pstates = matches.get(parent, {}).get(copy or fn, [])
1737 if pstates or states:
1738 if pstates or states:
1738 r = display(fn, ctx, pstates, states)
1739 r = display(fn, ctx, pstates, states)
1739 found = found or r
1740 found = found or r
1740 if r and not opts.get('all'):
1741 if r and not opts.get('all'):
1741 skip[fn] = True
1742 skip[fn] = True
1742 if copy:
1743 if copy:
1743 skip[copy] = True
1744 skip[copy] = True
1744 del matches[rev]
1745 del matches[rev]
1745 del revfiles[rev]
1746 del revfiles[rev]
1746
1747
1747 return not found
1748 return not found
1748
1749
1749 def heads(ui, repo, *branchrevs, **opts):
1750 def heads(ui, repo, *branchrevs, **opts):
1750 """show current repository heads or show branch heads
1751 """show current repository heads or show branch heads
1751
1752
1752 With no arguments, show all repository branch heads.
1753 With no arguments, show all repository branch heads.
1753
1754
1754 Repository "heads" are changesets with no child changesets. They are
1755 Repository "heads" are changesets with no child changesets. They are
1755 where development generally takes place and are the usual targets
1756 where development generally takes place and are the usual targets
1756 for update and merge operations. Branch heads are changesets that have
1757 for update and merge operations. Branch heads are changesets that have
1757 no child changeset on the same branch.
1758 no child changeset on the same branch.
1758
1759
1759 If one or more REVs are given, only branch heads on the branches
1760 If one or more REVs are given, only branch heads on the branches
1760 associated with the specified changesets are shown.
1761 associated with the specified changesets are shown.
1761
1762
1762 If -c/--closed is specified, also show branch heads marked closed
1763 If -c/--closed is specified, also show branch heads marked closed
1763 (see :hg:`commit --close-branch`).
1764 (see :hg:`commit --close-branch`).
1764
1765
1765 If STARTREV is specified, only those heads that are descendants of
1766 If STARTREV is specified, only those heads that are descendants of
1766 STARTREV will be displayed.
1767 STARTREV will be displayed.
1767
1768
1768 If -t/--topo is specified, named branch mechanics will be ignored and only
1769 If -t/--topo is specified, named branch mechanics will be ignored and only
1769 changesets without children will be shown.
1770 changesets without children will be shown.
1770
1771
1771 Returns 0 if matching heads are found, 1 if not.
1772 Returns 0 if matching heads are found, 1 if not.
1772 """
1773 """
1773
1774
1774 if opts.get('rev'):
1775 if opts.get('rev'):
1775 start = repo.lookup(opts['rev'])
1776 start = repo.lookup(opts['rev'])
1776 else:
1777 else:
1777 start = None
1778 start = None
1778
1779
1779 if opts.get('topo'):
1780 if opts.get('topo'):
1780 heads = [repo[h] for h in repo.heads(start)]
1781 heads = [repo[h] for h in repo.heads(start)]
1781 else:
1782 else:
1782 heads = []
1783 heads = []
1783 for b, ls in repo.branchmap().iteritems():
1784 for b, ls in repo.branchmap().iteritems():
1784 if start is None:
1785 if start is None:
1785 heads += [repo[h] for h in ls]
1786 heads += [repo[h] for h in ls]
1786 continue
1787 continue
1787 startrev = repo.changelog.rev(start)
1788 startrev = repo.changelog.rev(start)
1788 descendants = set(repo.changelog.descendants(startrev))
1789 descendants = set(repo.changelog.descendants(startrev))
1789 descendants.add(startrev)
1790 descendants.add(startrev)
1790 rev = repo.changelog.rev
1791 rev = repo.changelog.rev
1791 heads += [repo[h] for h in ls if rev(h) in descendants]
1792 heads += [repo[h] for h in ls if rev(h) in descendants]
1792
1793
1793 if branchrevs:
1794 if branchrevs:
1794 decode, encode = encoding.fromlocal, encoding.tolocal
1795 decode, encode = encoding.fromlocal, encoding.tolocal
1795 branches = set(repo[decode(br)].branch() for br in branchrevs)
1796 branches = set(repo[decode(br)].branch() for br in branchrevs)
1796 heads = [h for h in heads if h.branch() in branches]
1797 heads = [h for h in heads if h.branch() in branches]
1797
1798
1798 if not opts.get('closed'):
1799 if not opts.get('closed'):
1799 heads = [h for h in heads if not h.extra().get('close')]
1800 heads = [h for h in heads if not h.extra().get('close')]
1800
1801
1801 if opts.get('active') and branchrevs:
1802 if opts.get('active') and branchrevs:
1802 dagheads = repo.heads(start)
1803 dagheads = repo.heads(start)
1803 heads = [h for h in heads if h.node() in dagheads]
1804 heads = [h for h in heads if h.node() in dagheads]
1804
1805
1805 if branchrevs:
1806 if branchrevs:
1806 haveheads = set(h.branch() for h in heads)
1807 haveheads = set(h.branch() for h in heads)
1807 if branches - haveheads:
1808 if branches - haveheads:
1808 headless = ', '.join(encode(b) for b in branches - haveheads)
1809 headless = ', '.join(encode(b) for b in branches - haveheads)
1809 msg = _('no open branch heads found on branches %s')
1810 msg = _('no open branch heads found on branches %s')
1810 if opts.get('rev'):
1811 if opts.get('rev'):
1811 msg += _(' (started at %s)' % opts['rev'])
1812 msg += _(' (started at %s)' % opts['rev'])
1812 ui.warn((msg + '\n') % headless)
1813 ui.warn((msg + '\n') % headless)
1813
1814
1814 if not heads:
1815 if not heads:
1815 return 1
1816 return 1
1816
1817
1817 heads = sorted(heads, key=lambda x: -x.rev())
1818 heads = sorted(heads, key=lambda x: -x.rev())
1818 displayer = cmdutil.show_changeset(ui, repo, opts)
1819 displayer = cmdutil.show_changeset(ui, repo, opts)
1819 for ctx in heads:
1820 for ctx in heads:
1820 displayer.show(ctx)
1821 displayer.show(ctx)
1821 displayer.close()
1822 displayer.close()
1822
1823
1823 def help_(ui, name=None, with_version=False, unknowncmd=False):
1824 def help_(ui, name=None, with_version=False, unknowncmd=False):
1824 """show help for a given topic or a help overview
1825 """show help for a given topic or a help overview
1825
1826
1826 With no arguments, print a list of commands with short help messages.
1827 With no arguments, print a list of commands with short help messages.
1827
1828
1828 Given a topic, extension, or command name, print help for that
1829 Given a topic, extension, or command name, print help for that
1829 topic.
1830 topic.
1830
1831
1831 Returns 0 if successful.
1832 Returns 0 if successful.
1832 """
1833 """
1833 option_lists = []
1834 option_lists = []
1834 textwidth = util.termwidth() - 2
1835 textwidth = util.termwidth() - 2
1835
1836
1836 def addglobalopts(aliases):
1837 def addglobalopts(aliases):
1837 if ui.verbose:
1838 if ui.verbose:
1838 option_lists.append((_("global options:"), globalopts))
1839 option_lists.append((_("global options:"), globalopts))
1839 if name == 'shortlist':
1840 if name == 'shortlist':
1840 option_lists.append((_('use "hg help" for the full list '
1841 option_lists.append((_('use "hg help" for the full list '
1841 'of commands'), ()))
1842 'of commands'), ()))
1842 else:
1843 else:
1843 if name == 'shortlist':
1844 if name == 'shortlist':
1844 msg = _('use "hg help" for the full list of commands '
1845 msg = _('use "hg help" for the full list of commands '
1845 'or "hg -v" for details')
1846 'or "hg -v" for details')
1846 elif aliases:
1847 elif aliases:
1847 msg = _('use "hg -v help%s" to show aliases and '
1848 msg = _('use "hg -v help%s" to show aliases and '
1848 'global options') % (name and " " + name or "")
1849 'global options') % (name and " " + name or "")
1849 else:
1850 else:
1850 msg = _('use "hg -v help %s" to show global options') % name
1851 msg = _('use "hg -v help %s" to show global options') % name
1851 option_lists.append((msg, ()))
1852 option_lists.append((msg, ()))
1852
1853
1853 def helpcmd(name):
1854 def helpcmd(name):
1854 if with_version:
1855 if with_version:
1855 version_(ui)
1856 version_(ui)
1856 ui.write('\n')
1857 ui.write('\n')
1857
1858
1858 try:
1859 try:
1859 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
1860 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
1860 except error.AmbiguousCommand, inst:
1861 except error.AmbiguousCommand, inst:
1861 # py3k fix: except vars can't be used outside the scope of the
1862 # py3k fix: except vars can't be used outside the scope of the
1862 # except block, nor can be used inside a lambda. python issue4617
1863 # except block, nor can be used inside a lambda. python issue4617
1863 prefix = inst.args[0]
1864 prefix = inst.args[0]
1864 select = lambda c: c.lstrip('^').startswith(prefix)
1865 select = lambda c: c.lstrip('^').startswith(prefix)
1865 helplist(_('list of commands:\n\n'), select)
1866 helplist(_('list of commands:\n\n'), select)
1866 return
1867 return
1867
1868
1868 # check if it's an invalid alias and display its error if it is
1869 # check if it's an invalid alias and display its error if it is
1869 if getattr(entry[0], 'badalias', False):
1870 if getattr(entry[0], 'badalias', False):
1870 if not unknowncmd:
1871 if not unknowncmd:
1871 entry[0](ui)
1872 entry[0](ui)
1872 return
1873 return
1873
1874
1874 # synopsis
1875 # synopsis
1875 if len(entry) > 2:
1876 if len(entry) > 2:
1876 if entry[2].startswith('hg'):
1877 if entry[2].startswith('hg'):
1877 ui.write("%s\n" % entry[2])
1878 ui.write("%s\n" % entry[2])
1878 else:
1879 else:
1879 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
1880 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
1880 else:
1881 else:
1881 ui.write('hg %s\n' % aliases[0])
1882 ui.write('hg %s\n' % aliases[0])
1882
1883
1883 # aliases
1884 # aliases
1884 if not ui.quiet and len(aliases) > 1:
1885 if not ui.quiet and len(aliases) > 1:
1885 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1886 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1886
1887
1887 # description
1888 # description
1888 doc = gettext(entry[0].__doc__)
1889 doc = gettext(entry[0].__doc__)
1889 if not doc:
1890 if not doc:
1890 doc = _("(no help text available)")
1891 doc = _("(no help text available)")
1891 if hasattr(entry[0], 'definition'): # aliased command
1892 if hasattr(entry[0], 'definition'): # aliased command
1892 if entry[0].definition.startswith('!'): # shell alias
1893 if entry[0].definition.startswith('!'): # shell alias
1893 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
1894 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
1894 else:
1895 else:
1895 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
1896 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
1896 if ui.quiet:
1897 if ui.quiet:
1897 doc = doc.splitlines()[0]
1898 doc = doc.splitlines()[0]
1898 keep = ui.verbose and ['verbose'] or []
1899 keep = ui.verbose and ['verbose'] or []
1899 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
1900 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
1900 ui.write("\n%s\n" % formatted)
1901 ui.write("\n%s\n" % formatted)
1901 if pruned:
1902 if pruned:
1902 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
1903 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
1903
1904
1904 if not ui.quiet:
1905 if not ui.quiet:
1905 # options
1906 # options
1906 if entry[1]:
1907 if entry[1]:
1907 option_lists.append((_("options:\n"), entry[1]))
1908 option_lists.append((_("options:\n"), entry[1]))
1908
1909
1909 addglobalopts(False)
1910 addglobalopts(False)
1910
1911
1911 def helplist(header, select=None):
1912 def helplist(header, select=None):
1912 h = {}
1913 h = {}
1913 cmds = {}
1914 cmds = {}
1914 for c, e in table.iteritems():
1915 for c, e in table.iteritems():
1915 f = c.split("|", 1)[0]
1916 f = c.split("|", 1)[0]
1916 if select and not select(f):
1917 if select and not select(f):
1917 continue
1918 continue
1918 if (not select and name != 'shortlist' and
1919 if (not select and name != 'shortlist' and
1919 e[0].__module__ != __name__):
1920 e[0].__module__ != __name__):
1920 continue
1921 continue
1921 if name == "shortlist" and not f.startswith("^"):
1922 if name == "shortlist" and not f.startswith("^"):
1922 continue
1923 continue
1923 f = f.lstrip("^")
1924 f = f.lstrip("^")
1924 if not ui.debugflag and f.startswith("debug"):
1925 if not ui.debugflag and f.startswith("debug"):
1925 continue
1926 continue
1926 doc = e[0].__doc__
1927 doc = e[0].__doc__
1927 if doc and 'DEPRECATED' in doc and not ui.verbose:
1928 if doc and 'DEPRECATED' in doc and not ui.verbose:
1928 continue
1929 continue
1929 doc = gettext(doc)
1930 doc = gettext(doc)
1930 if not doc:
1931 if not doc:
1931 doc = _("(no help text available)")
1932 doc = _("(no help text available)")
1932 h[f] = doc.splitlines()[0].rstrip()
1933 h[f] = doc.splitlines()[0].rstrip()
1933 cmds[f] = c.lstrip("^")
1934 cmds[f] = c.lstrip("^")
1934
1935
1935 if not h:
1936 if not h:
1936 ui.status(_('no commands defined\n'))
1937 ui.status(_('no commands defined\n'))
1937 return
1938 return
1938
1939
1939 ui.status(header)
1940 ui.status(header)
1940 fns = sorted(h)
1941 fns = sorted(h)
1941 m = max(map(len, fns))
1942 m = max(map(len, fns))
1942 for f in fns:
1943 for f in fns:
1943 if ui.verbose:
1944 if ui.verbose:
1944 commands = cmds[f].replace("|",", ")
1945 commands = cmds[f].replace("|",", ")
1945 ui.write(" %s:\n %s\n"%(commands, h[f]))
1946 ui.write(" %s:\n %s\n"%(commands, h[f]))
1946 else:
1947 else:
1947 ui.write('%s\n' % (util.wrap(h[f],
1948 ui.write('%s\n' % (util.wrap(h[f],
1948 initindent=' %-*s ' % (m, f),
1949 initindent=' %-*s ' % (m, f),
1949 hangindent=' ' * (m + 4))))
1950 hangindent=' ' * (m + 4))))
1950
1951
1951 if not ui.quiet:
1952 if not ui.quiet:
1952 addglobalopts(True)
1953 addglobalopts(True)
1953
1954
1954 def helptopic(name):
1955 def helptopic(name):
1955 for names, header, doc in help.helptable:
1956 for names, header, doc in help.helptable:
1956 if name in names:
1957 if name in names:
1957 break
1958 break
1958 else:
1959 else:
1959 raise error.UnknownCommand(name)
1960 raise error.UnknownCommand(name)
1960
1961
1961 # description
1962 # description
1962 if not doc:
1963 if not doc:
1963 doc = _("(no help text available)")
1964 doc = _("(no help text available)")
1964 if hasattr(doc, '__call__'):
1965 if hasattr(doc, '__call__'):
1965 doc = doc()
1966 doc = doc()
1966
1967
1967 ui.write("%s\n\n" % header)
1968 ui.write("%s\n\n" % header)
1968 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
1969 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
1969
1970
1970 def helpext(name):
1971 def helpext(name):
1971 try:
1972 try:
1972 mod = extensions.find(name)
1973 mod = extensions.find(name)
1973 doc = gettext(mod.__doc__) or _('no help text available')
1974 doc = gettext(mod.__doc__) or _('no help text available')
1974 except KeyError:
1975 except KeyError:
1975 mod = None
1976 mod = None
1976 doc = extensions.disabledext(name)
1977 doc = extensions.disabledext(name)
1977 if not doc:
1978 if not doc:
1978 raise error.UnknownCommand(name)
1979 raise error.UnknownCommand(name)
1979
1980
1980 if '\n' not in doc:
1981 if '\n' not in doc:
1981 head, tail = doc, ""
1982 head, tail = doc, ""
1982 else:
1983 else:
1983 head, tail = doc.split('\n', 1)
1984 head, tail = doc.split('\n', 1)
1984 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
1985 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
1985 if tail:
1986 if tail:
1986 ui.write(minirst.format(tail, textwidth))
1987 ui.write(minirst.format(tail, textwidth))
1987 ui.status('\n\n')
1988 ui.status('\n\n')
1988
1989
1989 if mod:
1990 if mod:
1990 try:
1991 try:
1991 ct = mod.cmdtable
1992 ct = mod.cmdtable
1992 except AttributeError:
1993 except AttributeError:
1993 ct = {}
1994 ct = {}
1994 modcmds = set([c.split('|', 1)[0] for c in ct])
1995 modcmds = set([c.split('|', 1)[0] for c in ct])
1995 helplist(_('list of commands:\n\n'), modcmds.__contains__)
1996 helplist(_('list of commands:\n\n'), modcmds.__contains__)
1996 else:
1997 else:
1997 ui.write(_('use "hg help extensions" for information on enabling '
1998 ui.write(_('use "hg help extensions" for information on enabling '
1998 'extensions\n'))
1999 'extensions\n'))
1999
2000
2000 def helpextcmd(name):
2001 def helpextcmd(name):
2001 cmd, ext, mod = extensions.disabledcmd(name, ui.config('ui', 'strict'))
2002 cmd, ext, mod = extensions.disabledcmd(name, ui.config('ui', 'strict'))
2002 doc = gettext(mod.__doc__).splitlines()[0]
2003 doc = gettext(mod.__doc__).splitlines()[0]
2003
2004
2004 msg = help.listexts(_("'%s' is provided by the following "
2005 msg = help.listexts(_("'%s' is provided by the following "
2005 "extension:") % cmd, {ext: doc}, len(ext),
2006 "extension:") % cmd, {ext: doc}, len(ext),
2006 indent=4)
2007 indent=4)
2007 ui.write(minirst.format(msg, textwidth))
2008 ui.write(minirst.format(msg, textwidth))
2008 ui.write('\n\n')
2009 ui.write('\n\n')
2009 ui.write(_('use "hg help extensions" for information on enabling '
2010 ui.write(_('use "hg help extensions" for information on enabling '
2010 'extensions\n'))
2011 'extensions\n'))
2011
2012
2012 if name and name != 'shortlist':
2013 if name and name != 'shortlist':
2013 i = None
2014 i = None
2014 if unknowncmd:
2015 if unknowncmd:
2015 queries = (helpextcmd,)
2016 queries = (helpextcmd,)
2016 else:
2017 else:
2017 queries = (helptopic, helpcmd, helpext, helpextcmd)
2018 queries = (helptopic, helpcmd, helpext, helpextcmd)
2018 for f in queries:
2019 for f in queries:
2019 try:
2020 try:
2020 f(name)
2021 f(name)
2021 i = None
2022 i = None
2022 break
2023 break
2023 except error.UnknownCommand, inst:
2024 except error.UnknownCommand, inst:
2024 i = inst
2025 i = inst
2025 if i:
2026 if i:
2026 raise i
2027 raise i
2027
2028
2028 else:
2029 else:
2029 # program name
2030 # program name
2030 if ui.verbose or with_version:
2031 if ui.verbose or with_version:
2031 version_(ui)
2032 version_(ui)
2032 else:
2033 else:
2033 ui.status(_("Mercurial Distributed SCM\n"))
2034 ui.status(_("Mercurial Distributed SCM\n"))
2034 ui.status('\n')
2035 ui.status('\n')
2035
2036
2036 # list of commands
2037 # list of commands
2037 if name == "shortlist":
2038 if name == "shortlist":
2038 header = _('basic commands:\n\n')
2039 header = _('basic commands:\n\n')
2039 else:
2040 else:
2040 header = _('list of commands:\n\n')
2041 header = _('list of commands:\n\n')
2041
2042
2042 helplist(header)
2043 helplist(header)
2043 if name != 'shortlist':
2044 if name != 'shortlist':
2044 exts, maxlength = extensions.enabled()
2045 exts, maxlength = extensions.enabled()
2045 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2046 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2046 if text:
2047 if text:
2047 ui.write("\n%s\n" % minirst.format(text, textwidth))
2048 ui.write("\n%s\n" % minirst.format(text, textwidth))
2048
2049
2049 # list all option lists
2050 # list all option lists
2050 opt_output = []
2051 opt_output = []
2051 multioccur = False
2052 multioccur = False
2052 for title, options in option_lists:
2053 for title, options in option_lists:
2053 opt_output.append(("\n%s" % title, None))
2054 opt_output.append(("\n%s" % title, None))
2054 for option in options:
2055 for option in options:
2055 if len(option) == 5:
2056 if len(option) == 5:
2056 shortopt, longopt, default, desc, optlabel = option
2057 shortopt, longopt, default, desc, optlabel = option
2057 else:
2058 else:
2058 shortopt, longopt, default, desc = option
2059 shortopt, longopt, default, desc = option
2059 optlabel = _("VALUE") # default label
2060 optlabel = _("VALUE") # default label
2060
2061
2061 if _("DEPRECATED") in desc and not ui.verbose:
2062 if _("DEPRECATED") in desc and not ui.verbose:
2062 continue
2063 continue
2063 if isinstance(default, list):
2064 if isinstance(default, list):
2064 numqualifier = " %s [+]" % optlabel
2065 numqualifier = " %s [+]" % optlabel
2065 multioccur = True
2066 multioccur = True
2066 elif (default is not None) and not isinstance(default, bool):
2067 elif (default is not None) and not isinstance(default, bool):
2067 numqualifier = " %s" % optlabel
2068 numqualifier = " %s" % optlabel
2068 else:
2069 else:
2069 numqualifier = ""
2070 numqualifier = ""
2070 opt_output.append(("%2s%s" %
2071 opt_output.append(("%2s%s" %
2071 (shortopt and "-%s" % shortopt,
2072 (shortopt and "-%s" % shortopt,
2072 longopt and " --%s%s" %
2073 longopt and " --%s%s" %
2073 (longopt, numqualifier)),
2074 (longopt, numqualifier)),
2074 "%s%s" % (desc,
2075 "%s%s" % (desc,
2075 default
2076 default
2076 and _(" (default: %s)") % default
2077 and _(" (default: %s)") % default
2077 or "")))
2078 or "")))
2078 if multioccur:
2079 if multioccur:
2079 msg = _("\n[+] marked option can be specified multiple times")
2080 msg = _("\n[+] marked option can be specified multiple times")
2080 if ui.verbose and name != 'shortlist':
2081 if ui.verbose and name != 'shortlist':
2081 opt_output.append((msg, None))
2082 opt_output.append((msg, None))
2082 else:
2083 else:
2083 opt_output.insert(-1, (msg, None))
2084 opt_output.insert(-1, (msg, None))
2084
2085
2085 if not name:
2086 if not name:
2086 ui.write(_("\nadditional help topics:\n\n"))
2087 ui.write(_("\nadditional help topics:\n\n"))
2087 topics = []
2088 topics = []
2088 for names, header, doc in help.helptable:
2089 for names, header, doc in help.helptable:
2089 topics.append((sorted(names, key=len, reverse=True)[0], header))
2090 topics.append((sorted(names, key=len, reverse=True)[0], header))
2090 topics_len = max([len(s[0]) for s in topics])
2091 topics_len = max([len(s[0]) for s in topics])
2091 for t, desc in topics:
2092 for t, desc in topics:
2092 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2093 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2093
2094
2094 if opt_output:
2095 if opt_output:
2095 colwidth = encoding.colwidth
2096 colwidth = encoding.colwidth
2096 # normalize: (opt or message, desc or None, width of opt)
2097 # normalize: (opt or message, desc or None, width of opt)
2097 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2098 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2098 for opt, desc in opt_output]
2099 for opt, desc in opt_output]
2099 hanging = max([e[2] for e in entries])
2100 hanging = max([e[2] for e in entries])
2100 for opt, desc, width in entries:
2101 for opt, desc, width in entries:
2101 if desc:
2102 if desc:
2102 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2103 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2103 hangindent = ' ' * (hanging + 3)
2104 hangindent = ' ' * (hanging + 3)
2104 ui.write('%s\n' % (util.wrap(desc,
2105 ui.write('%s\n' % (util.wrap(desc,
2105 initindent=initindent,
2106 initindent=initindent,
2106 hangindent=hangindent)))
2107 hangindent=hangindent)))
2107 else:
2108 else:
2108 ui.write("%s\n" % opt)
2109 ui.write("%s\n" % opt)
2109
2110
2110 def identify(ui, repo, source=None,
2111 def identify(ui, repo, source=None,
2111 rev=None, num=None, id=None, branch=None, tags=None):
2112 rev=None, num=None, id=None, branch=None, tags=None):
2112 """identify the working copy or specified revision
2113 """identify the working copy or specified revision
2113
2114
2114 With no revision, print a summary of the current state of the
2115 With no revision, print a summary of the current state of the
2115 repository.
2116 repository.
2116
2117
2117 Specifying a path to a repository root or Mercurial bundle will
2118 Specifying a path to a repository root or Mercurial bundle will
2118 cause lookup to operate on that repository/bundle.
2119 cause lookup to operate on that repository/bundle.
2119
2120
2120 This summary identifies the repository state using one or two
2121 This summary identifies the repository state using one or two
2121 parent hash identifiers, followed by a "+" if there are
2122 parent hash identifiers, followed by a "+" if there are
2122 uncommitted changes in the working directory, a list of tags for
2123 uncommitted changes in the working directory, a list of tags for
2123 this revision and a branch name for non-default branches.
2124 this revision and a branch name for non-default branches.
2124
2125
2125 Returns 0 if successful.
2126 Returns 0 if successful.
2126 """
2127 """
2127
2128
2128 if not repo and not source:
2129 if not repo and not source:
2129 raise util.Abort(_("there is no Mercurial repository here "
2130 raise util.Abort(_("there is no Mercurial repository here "
2130 "(.hg not found)"))
2131 "(.hg not found)"))
2131
2132
2132 hexfunc = ui.debugflag and hex or short
2133 hexfunc = ui.debugflag and hex or short
2133 default = not (num or id or branch or tags)
2134 default = not (num or id or branch or tags)
2134 output = []
2135 output = []
2135
2136
2136 revs = []
2137 revs = []
2137 if source:
2138 if source:
2138 source, branches = hg.parseurl(ui.expandpath(source))
2139 source, branches = hg.parseurl(ui.expandpath(source))
2139 repo = hg.repository(ui, source)
2140 repo = hg.repository(ui, source)
2140 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2141 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2141
2142
2142 if not repo.local():
2143 if not repo.local():
2143 if not rev and revs:
2144 if not rev and revs:
2144 rev = revs[0]
2145 rev = revs[0]
2145 if not rev:
2146 if not rev:
2146 rev = "tip"
2147 rev = "tip"
2147 if num or branch or tags:
2148 if num or branch or tags:
2148 raise util.Abort(
2149 raise util.Abort(
2149 "can't query remote revision number, branch, or tags")
2150 "can't query remote revision number, branch, or tags")
2150 output = [hexfunc(repo.lookup(rev))]
2151 output = [hexfunc(repo.lookup(rev))]
2151 elif not rev:
2152 elif not rev:
2152 ctx = repo[None]
2153 ctx = repo[None]
2153 parents = ctx.parents()
2154 parents = ctx.parents()
2154 changed = False
2155 changed = False
2155 if default or id or num:
2156 if default or id or num:
2156 changed = util.any(repo.status())
2157 changed = util.any(repo.status())
2157 if default or id:
2158 if default or id:
2158 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2159 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2159 (changed) and "+" or "")]
2160 (changed) and "+" or "")]
2160 if num:
2161 if num:
2161 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2162 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2162 (changed) and "+" or ""))
2163 (changed) and "+" or ""))
2163 else:
2164 else:
2164 ctx = repo[rev]
2165 ctx = repo[rev]
2165 if default or id:
2166 if default or id:
2166 output = [hexfunc(ctx.node())]
2167 output = [hexfunc(ctx.node())]
2167 if num:
2168 if num:
2168 output.append(str(ctx.rev()))
2169 output.append(str(ctx.rev()))
2169
2170
2170 if repo.local() and default and not ui.quiet:
2171 if repo.local() and default and not ui.quiet:
2171 b = encoding.tolocal(ctx.branch())
2172 b = encoding.tolocal(ctx.branch())
2172 if b != 'default':
2173 if b != 'default':
2173 output.append("(%s)" % b)
2174 output.append("(%s)" % b)
2174
2175
2175 # multiple tags for a single parent separated by '/'
2176 # multiple tags for a single parent separated by '/'
2176 t = "/".join(ctx.tags())
2177 t = "/".join(ctx.tags())
2177 if t:
2178 if t:
2178 output.append(t)
2179 output.append(t)
2179
2180
2180 if branch:
2181 if branch:
2181 output.append(encoding.tolocal(ctx.branch()))
2182 output.append(encoding.tolocal(ctx.branch()))
2182
2183
2183 if tags:
2184 if tags:
2184 output.extend(ctx.tags())
2185 output.extend(ctx.tags())
2185
2186
2186 ui.write("%s\n" % ' '.join(output))
2187 ui.write("%s\n" % ' '.join(output))
2187
2188
2188 def import_(ui, repo, patch1, *patches, **opts):
2189 def import_(ui, repo, patch1, *patches, **opts):
2189 """import an ordered set of patches
2190 """import an ordered set of patches
2190
2191
2191 Import a list of patches and commit them individually (unless
2192 Import a list of patches and commit them individually (unless
2192 --no-commit is specified).
2193 --no-commit is specified).
2193
2194
2194 If there are outstanding changes in the working directory, import
2195 If there are outstanding changes in the working directory, import
2195 will abort unless given the -f/--force flag.
2196 will abort unless given the -f/--force flag.
2196
2197
2197 You can import a patch straight from a mail message. Even patches
2198 You can import a patch straight from a mail message. Even patches
2198 as attachments work (to use the body part, it must have type
2199 as attachments work (to use the body part, it must have type
2199 text/plain or text/x-patch). From and Subject headers of email
2200 text/plain or text/x-patch). From and Subject headers of email
2200 message are used as default committer and commit message. All
2201 message are used as default committer and commit message. All
2201 text/plain body parts before first diff are added to commit
2202 text/plain body parts before first diff are added to commit
2202 message.
2203 message.
2203
2204
2204 If the imported patch was generated by :hg:`export`, user and
2205 If the imported patch was generated by :hg:`export`, user and
2205 description from patch override values from message headers and
2206 description from patch override values from message headers and
2206 body. Values given on command line with -m/--message and -u/--user
2207 body. Values given on command line with -m/--message and -u/--user
2207 override these.
2208 override these.
2208
2209
2209 If --exact is specified, import will set the working directory to
2210 If --exact is specified, import will set the working directory to
2210 the parent of each patch before applying it, and will abort if the
2211 the parent of each patch before applying it, and will abort if the
2211 resulting changeset has a different ID than the one recorded in
2212 resulting changeset has a different ID than the one recorded in
2212 the patch. This may happen due to character set problems or other
2213 the patch. This may happen due to character set problems or other
2213 deficiencies in the text patch format.
2214 deficiencies in the text patch format.
2214
2215
2215 With -s/--similarity, hg will attempt to discover renames and
2216 With -s/--similarity, hg will attempt to discover renames and
2216 copies in the patch in the same way as 'addremove'.
2217 copies in the patch in the same way as 'addremove'.
2217
2218
2218 To read a patch from standard input, use "-" as the patch name. If
2219 To read a patch from standard input, use "-" as the patch name. If
2219 a URL is specified, the patch will be downloaded from it.
2220 a URL is specified, the patch will be downloaded from it.
2220 See :hg:`help dates` for a list of formats valid for -d/--date.
2221 See :hg:`help dates` for a list of formats valid for -d/--date.
2221
2222
2222 Returns 0 on success.
2223 Returns 0 on success.
2223 """
2224 """
2224 patches = (patch1,) + patches
2225 patches = (patch1,) + patches
2225
2226
2226 date = opts.get('date')
2227 date = opts.get('date')
2227 if date:
2228 if date:
2228 opts['date'] = util.parsedate(date)
2229 opts['date'] = util.parsedate(date)
2229
2230
2230 try:
2231 try:
2231 sim = float(opts.get('similarity') or 0)
2232 sim = float(opts.get('similarity') or 0)
2232 except ValueError:
2233 except ValueError:
2233 raise util.Abort(_('similarity must be a number'))
2234 raise util.Abort(_('similarity must be a number'))
2234 if sim < 0 or sim > 100:
2235 if sim < 0 or sim > 100:
2235 raise util.Abort(_('similarity must be between 0 and 100'))
2236 raise util.Abort(_('similarity must be between 0 and 100'))
2236
2237
2237 if opts.get('exact') or not opts.get('force'):
2238 if opts.get('exact') or not opts.get('force'):
2238 cmdutil.bail_if_changed(repo)
2239 cmdutil.bail_if_changed(repo)
2239
2240
2240 d = opts["base"]
2241 d = opts["base"]
2241 strip = opts["strip"]
2242 strip = opts["strip"]
2242 wlock = lock = None
2243 wlock = lock = None
2243
2244
2244 def tryone(ui, hunk):
2245 def tryone(ui, hunk):
2245 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2246 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2246 patch.extract(ui, hunk)
2247 patch.extract(ui, hunk)
2247
2248
2248 if not tmpname:
2249 if not tmpname:
2249 return None
2250 return None
2250 commitid = _('to working directory')
2251 commitid = _('to working directory')
2251
2252
2252 try:
2253 try:
2253 cmdline_message = cmdutil.logmessage(opts)
2254 cmdline_message = cmdutil.logmessage(opts)
2254 if cmdline_message:
2255 if cmdline_message:
2255 # pickup the cmdline msg
2256 # pickup the cmdline msg
2256 message = cmdline_message
2257 message = cmdline_message
2257 elif message:
2258 elif message:
2258 # pickup the patch msg
2259 # pickup the patch msg
2259 message = message.strip()
2260 message = message.strip()
2260 else:
2261 else:
2261 # launch the editor
2262 # launch the editor
2262 message = None
2263 message = None
2263 ui.debug('message:\n%s\n' % message)
2264 ui.debug('message:\n%s\n' % message)
2264
2265
2265 wp = repo.parents()
2266 wp = repo.parents()
2266 if opts.get('exact'):
2267 if opts.get('exact'):
2267 if not nodeid or not p1:
2268 if not nodeid or not p1:
2268 raise util.Abort(_('not a Mercurial patch'))
2269 raise util.Abort(_('not a Mercurial patch'))
2269 p1 = repo.lookup(p1)
2270 p1 = repo.lookup(p1)
2270 p2 = repo.lookup(p2 or hex(nullid))
2271 p2 = repo.lookup(p2 or hex(nullid))
2271
2272
2272 if p1 != wp[0].node():
2273 if p1 != wp[0].node():
2273 hg.clean(repo, p1)
2274 hg.clean(repo, p1)
2274 repo.dirstate.setparents(p1, p2)
2275 repo.dirstate.setparents(p1, p2)
2275 elif p2:
2276 elif p2:
2276 try:
2277 try:
2277 p1 = repo.lookup(p1)
2278 p1 = repo.lookup(p1)
2278 p2 = repo.lookup(p2)
2279 p2 = repo.lookup(p2)
2279 if p1 == wp[0].node():
2280 if p1 == wp[0].node():
2280 repo.dirstate.setparents(p1, p2)
2281 repo.dirstate.setparents(p1, p2)
2281 except error.RepoError:
2282 except error.RepoError:
2282 pass
2283 pass
2283 if opts.get('exact') or opts.get('import_branch'):
2284 if opts.get('exact') or opts.get('import_branch'):
2284 repo.dirstate.setbranch(branch or 'default')
2285 repo.dirstate.setbranch(branch or 'default')
2285
2286
2286 files = {}
2287 files = {}
2287 try:
2288 try:
2288 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2289 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2289 files=files, eolmode=None)
2290 files=files, eolmode=None)
2290 finally:
2291 finally:
2291 files = cmdutil.updatedir(ui, repo, files,
2292 files = cmdutil.updatedir(ui, repo, files,
2292 similarity=sim / 100.0)
2293 similarity=sim / 100.0)
2293 if not opts.get('no_commit'):
2294 if not opts.get('no_commit'):
2294 if opts.get('exact'):
2295 if opts.get('exact'):
2295 m = None
2296 m = None
2296 else:
2297 else:
2297 m = cmdutil.matchfiles(repo, files or [])
2298 m = cmdutil.matchfiles(repo, files or [])
2298 n = repo.commit(message, opts.get('user') or user,
2299 n = repo.commit(message, opts.get('user') or user,
2299 opts.get('date') or date, match=m,
2300 opts.get('date') or date, match=m,
2300 editor=cmdutil.commiteditor)
2301 editor=cmdutil.commiteditor)
2301 if opts.get('exact'):
2302 if opts.get('exact'):
2302 if hex(n) != nodeid:
2303 if hex(n) != nodeid:
2303 repo.rollback()
2304 repo.rollback()
2304 raise util.Abort(_('patch is damaged'
2305 raise util.Abort(_('patch is damaged'
2305 ' or loses information'))
2306 ' or loses information'))
2306 # Force a dirstate write so that the next transaction
2307 # Force a dirstate write so that the next transaction
2307 # backups an up-do-date file.
2308 # backups an up-do-date file.
2308 repo.dirstate.write()
2309 repo.dirstate.write()
2309 if n:
2310 if n:
2310 commitid = short(n)
2311 commitid = short(n)
2311
2312
2312 return commitid
2313 return commitid
2313 finally:
2314 finally:
2314 os.unlink(tmpname)
2315 os.unlink(tmpname)
2315
2316
2316 try:
2317 try:
2317 wlock = repo.wlock()
2318 wlock = repo.wlock()
2318 lock = repo.lock()
2319 lock = repo.lock()
2319 lastcommit = None
2320 lastcommit = None
2320 for p in patches:
2321 for p in patches:
2321 pf = os.path.join(d, p)
2322 pf = os.path.join(d, p)
2322
2323
2323 if pf == '-':
2324 if pf == '-':
2324 ui.status(_("applying patch from stdin\n"))
2325 ui.status(_("applying patch from stdin\n"))
2325 pf = sys.stdin
2326 pf = sys.stdin
2326 else:
2327 else:
2327 ui.status(_("applying %s\n") % p)
2328 ui.status(_("applying %s\n") % p)
2328 pf = url.open(ui, pf)
2329 pf = url.open(ui, pf)
2329
2330
2330 haspatch = False
2331 haspatch = False
2331 for hunk in patch.split(pf):
2332 for hunk in patch.split(pf):
2332 commitid = tryone(ui, hunk)
2333 commitid = tryone(ui, hunk)
2333 if commitid:
2334 if commitid:
2334 haspatch = True
2335 haspatch = True
2335 if lastcommit:
2336 if lastcommit:
2336 ui.status(_('applied %s\n') % lastcommit)
2337 ui.status(_('applied %s\n') % lastcommit)
2337 lastcommit = commitid
2338 lastcommit = commitid
2338
2339
2339 if not haspatch:
2340 if not haspatch:
2340 raise util.Abort(_('no diffs found'))
2341 raise util.Abort(_('no diffs found'))
2341
2342
2342 finally:
2343 finally:
2343 release(lock, wlock)
2344 release(lock, wlock)
2344
2345
2345 def incoming(ui, repo, source="default", **opts):
2346 def incoming(ui, repo, source="default", **opts):
2346 """show new changesets found in source
2347 """show new changesets found in source
2347
2348
2348 Show new changesets found in the specified path/URL or the default
2349 Show new changesets found in the specified path/URL or the default
2349 pull location. These are the changesets that would have been pulled
2350 pull location. These are the changesets that would have been pulled
2350 if a pull at the time you issued this command.
2351 if a pull at the time you issued this command.
2351
2352
2352 For remote repository, using --bundle avoids downloading the
2353 For remote repository, using --bundle avoids downloading the
2353 changesets twice if the incoming is followed by a pull.
2354 changesets twice if the incoming is followed by a pull.
2354
2355
2355 See pull for valid source format details.
2356 See pull for valid source format details.
2356
2357
2357 Returns 0 if there are incoming changes, 1 otherwise.
2358 Returns 0 if there are incoming changes, 1 otherwise.
2358 """
2359 """
2359 limit = cmdutil.loglimit(opts)
2360 limit = cmdutil.loglimit(opts)
2360 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2361 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2361 other = hg.repository(hg.remoteui(repo, opts), source)
2362 other = hg.repository(hg.remoteui(repo, opts), source)
2362 ui.status(_('comparing with %s\n') % url.hidepassword(source))
2363 ui.status(_('comparing with %s\n') % url.hidepassword(source))
2363 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2364 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2364 if revs:
2365 if revs:
2365 revs = [other.lookup(rev) for rev in revs]
2366 revs = [other.lookup(rev) for rev in revs]
2366
2367
2367 tmp = discovery.findcommonincoming(repo, other, heads=revs,
2368 tmp = discovery.findcommonincoming(repo, other, heads=revs,
2368 force=opts.get('force'))
2369 force=opts.get('force'))
2369 common, incoming, rheads = tmp
2370 common, incoming, rheads = tmp
2370 if not incoming:
2371 if not incoming:
2371 try:
2372 try:
2372 os.unlink(opts["bundle"])
2373 os.unlink(opts["bundle"])
2373 except:
2374 except:
2374 pass
2375 pass
2375 ui.status(_("no changes found\n"))
2376 ui.status(_("no changes found\n"))
2376 return 1
2377 return 1
2377
2378
2378 cleanup = None
2379 cleanup = None
2379 try:
2380 try:
2380 fname = opts["bundle"]
2381 fname = opts["bundle"]
2381 if fname or not other.local():
2382 if fname or not other.local():
2382 # create a bundle (uncompressed if other repo is not local)
2383 # create a bundle (uncompressed if other repo is not local)
2383
2384
2384 if revs is None and other.capable('changegroupsubset'):
2385 if revs is None and other.capable('changegroupsubset'):
2385 revs = rheads
2386 revs = rheads
2386
2387
2387 if revs is None:
2388 if revs is None:
2388 cg = other.changegroup(incoming, "incoming")
2389 cg = other.changegroup(incoming, "incoming")
2389 else:
2390 else:
2390 cg = other.changegroupsubset(incoming, revs, 'incoming')
2391 cg = other.changegroupsubset(incoming, revs, 'incoming')
2391 bundletype = other.local() and "HG10BZ" or "HG10UN"
2392 bundletype = other.local() and "HG10BZ" or "HG10UN"
2392 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
2393 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
2393 # keep written bundle?
2394 # keep written bundle?
2394 if opts["bundle"]:
2395 if opts["bundle"]:
2395 cleanup = None
2396 cleanup = None
2396 if not other.local():
2397 if not other.local():
2397 # use the created uncompressed bundlerepo
2398 # use the created uncompressed bundlerepo
2398 other = bundlerepo.bundlerepository(ui, repo.root, fname)
2399 other = bundlerepo.bundlerepository(ui, repo.root, fname)
2399
2400
2400 o = other.changelog.nodesbetween(incoming, revs)[0]
2401 o = other.changelog.nodesbetween(incoming, revs)[0]
2401 if opts.get('newest_first'):
2402 if opts.get('newest_first'):
2402 o.reverse()
2403 o.reverse()
2403 displayer = cmdutil.show_changeset(ui, other, opts)
2404 displayer = cmdutil.show_changeset(ui, other, opts)
2404 count = 0
2405 count = 0
2405 for n in o:
2406 for n in o:
2406 if limit is not None and count >= limit:
2407 if limit is not None and count >= limit:
2407 break
2408 break
2408 parents = [p for p in other.changelog.parents(n) if p != nullid]
2409 parents = [p for p in other.changelog.parents(n) if p != nullid]
2409 if opts.get('no_merges') and len(parents) == 2:
2410 if opts.get('no_merges') and len(parents) == 2:
2410 continue
2411 continue
2411 count += 1
2412 count += 1
2412 displayer.show(other[n])
2413 displayer.show(other[n])
2413 displayer.close()
2414 displayer.close()
2414 finally:
2415 finally:
2415 if hasattr(other, 'close'):
2416 if hasattr(other, 'close'):
2416 other.close()
2417 other.close()
2417 if cleanup:
2418 if cleanup:
2418 os.unlink(cleanup)
2419 os.unlink(cleanup)
2419
2420
2420 def init(ui, dest=".", **opts):
2421 def init(ui, dest=".", **opts):
2421 """create a new repository in the given directory
2422 """create a new repository in the given directory
2422
2423
2423 Initialize a new repository in the given directory. If the given
2424 Initialize a new repository in the given directory. If the given
2424 directory does not exist, it will be created.
2425 directory does not exist, it will be created.
2425
2426
2426 If no directory is given, the current directory is used.
2427 If no directory is given, the current directory is used.
2427
2428
2428 It is possible to specify an ``ssh://`` URL as the destination.
2429 It is possible to specify an ``ssh://`` URL as the destination.
2429 See :hg:`help urls` for more information.
2430 See :hg:`help urls` for more information.
2430
2431
2431 Returns 0 on success.
2432 Returns 0 on success.
2432 """
2433 """
2433 hg.repository(hg.remoteui(ui, opts), dest, create=1)
2434 hg.repository(hg.remoteui(ui, opts), dest, create=1)
2434
2435
2435 def locate(ui, repo, *pats, **opts):
2436 def locate(ui, repo, *pats, **opts):
2436 """locate files matching specific patterns
2437 """locate files matching specific patterns
2437
2438
2438 Print files under Mercurial control in the working directory whose
2439 Print files under Mercurial control in the working directory whose
2439 names match the given patterns.
2440 names match the given patterns.
2440
2441
2441 By default, this command searches all directories in the working
2442 By default, this command searches all directories in the working
2442 directory. To search just the current directory and its
2443 directory. To search just the current directory and its
2443 subdirectories, use "--include .".
2444 subdirectories, use "--include .".
2444
2445
2445 If no patterns are given to match, this command prints the names
2446 If no patterns are given to match, this command prints the names
2446 of all files under Mercurial control in the working directory.
2447 of all files under Mercurial control in the working directory.
2447
2448
2448 If you want to feed the output of this command into the "xargs"
2449 If you want to feed the output of this command into the "xargs"
2449 command, use the -0 option to both this command and "xargs". This
2450 command, use the -0 option to both this command and "xargs". This
2450 will avoid the problem of "xargs" treating single filenames that
2451 will avoid the problem of "xargs" treating single filenames that
2451 contain whitespace as multiple filenames.
2452 contain whitespace as multiple filenames.
2452
2453
2453 Returns 0 if a match is found, 1 otherwise.
2454 Returns 0 if a match is found, 1 otherwise.
2454 """
2455 """
2455 end = opts.get('print0') and '\0' or '\n'
2456 end = opts.get('print0') and '\0' or '\n'
2456 rev = opts.get('rev') or None
2457 rev = opts.get('rev') or None
2457
2458
2458 ret = 1
2459 ret = 1
2459 m = cmdutil.match(repo, pats, opts, default='relglob')
2460 m = cmdutil.match(repo, pats, opts, default='relglob')
2460 m.bad = lambda x, y: False
2461 m.bad = lambda x, y: False
2461 for abs in repo[rev].walk(m):
2462 for abs in repo[rev].walk(m):
2462 if not rev and abs not in repo.dirstate:
2463 if not rev and abs not in repo.dirstate:
2463 continue
2464 continue
2464 if opts.get('fullpath'):
2465 if opts.get('fullpath'):
2465 ui.write(repo.wjoin(abs), end)
2466 ui.write(repo.wjoin(abs), end)
2466 else:
2467 else:
2467 ui.write(((pats and m.rel(abs)) or abs), end)
2468 ui.write(((pats and m.rel(abs)) or abs), end)
2468 ret = 0
2469 ret = 0
2469
2470
2470 return ret
2471 return ret
2471
2472
2472 def log(ui, repo, *pats, **opts):
2473 def log(ui, repo, *pats, **opts):
2473 """show revision history of entire repository or files
2474 """show revision history of entire repository or files
2474
2475
2475 Print the revision history of the specified files or the entire
2476 Print the revision history of the specified files or the entire
2476 project.
2477 project.
2477
2478
2478 File history is shown without following rename or copy history of
2479 File history is shown without following rename or copy history of
2479 files. Use -f/--follow with a filename to follow history across
2480 files. Use -f/--follow with a filename to follow history across
2480 renames and copies. --follow without a filename will only show
2481 renames and copies. --follow without a filename will only show
2481 ancestors or descendants of the starting revision. --follow-first
2482 ancestors or descendants of the starting revision. --follow-first
2482 only follows the first parent of merge revisions.
2483 only follows the first parent of merge revisions.
2483
2484
2484 If no revision range is specified, the default is tip:0 unless
2485 If no revision range is specified, the default is tip:0 unless
2485 --follow is set, in which case the working directory parent is
2486 --follow is set, in which case the working directory parent is
2486 used as the starting revision. You can specify a revision set for
2487 used as the starting revision. You can specify a revision set for
2487 log, see :hg:`help revsets` for more information.
2488 log, see :hg:`help revsets` for more information.
2488
2489
2489 See :hg:`help dates` for a list of formats valid for -d/--date.
2490 See :hg:`help dates` for a list of formats valid for -d/--date.
2490
2491
2491 By default this command prints revision number and changeset id,
2492 By default this command prints revision number and changeset id,
2492 tags, non-trivial parents, user, date and time, and a summary for
2493 tags, non-trivial parents, user, date and time, and a summary for
2493 each commit. When the -v/--verbose switch is used, the list of
2494 each commit. When the -v/--verbose switch is used, the list of
2494 changed files and full commit message are shown.
2495 changed files and full commit message are shown.
2495
2496
2496 NOTE: log -p/--patch may generate unexpected diff output for merge
2497 NOTE: log -p/--patch may generate unexpected diff output for merge
2497 changesets, as it will only compare the merge changeset against
2498 changesets, as it will only compare the merge changeset against
2498 its first parent. Also, only files different from BOTH parents
2499 its first parent. Also, only files different from BOTH parents
2499 will appear in files:.
2500 will appear in files:.
2500
2501
2501 Returns 0 on success.
2502 Returns 0 on success.
2502 """
2503 """
2503
2504
2504 matchfn = cmdutil.match(repo, pats, opts)
2505 matchfn = cmdutil.match(repo, pats, opts)
2505 limit = cmdutil.loglimit(opts)
2506 limit = cmdutil.loglimit(opts)
2506 count = 0
2507 count = 0
2507
2508
2508 endrev = None
2509 endrev = None
2509 if opts.get('copies') and opts.get('rev'):
2510 if opts.get('copies') and opts.get('rev'):
2510 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2511 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2511
2512
2512 df = False
2513 df = False
2513 if opts["date"]:
2514 if opts["date"]:
2514 df = util.matchdate(opts["date"])
2515 df = util.matchdate(opts["date"])
2515
2516
2516 branches = opts.get('branch', []) + opts.get('only_branch', [])
2517 branches = opts.get('branch', []) + opts.get('only_branch', [])
2517 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2518 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2518
2519
2519 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2520 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2520 def prep(ctx, fns):
2521 def prep(ctx, fns):
2521 rev = ctx.rev()
2522 rev = ctx.rev()
2522 parents = [p for p in repo.changelog.parentrevs(rev)
2523 parents = [p for p in repo.changelog.parentrevs(rev)
2523 if p != nullrev]
2524 if p != nullrev]
2524 if opts.get('no_merges') and len(parents) == 2:
2525 if opts.get('no_merges') and len(parents) == 2:
2525 return
2526 return
2526 if opts.get('only_merges') and len(parents) != 2:
2527 if opts.get('only_merges') and len(parents) != 2:
2527 return
2528 return
2528 if opts.get('branch') and ctx.branch() not in opts['branch']:
2529 if opts.get('branch') and ctx.branch() not in opts['branch']:
2529 return
2530 return
2530 if df and not df(ctx.date()[0]):
2531 if df and not df(ctx.date()[0]):
2531 return
2532 return
2532 if opts['user'] and not [k for k in opts['user'] if k in ctx.user()]:
2533 if opts['user'] and not [k for k in opts['user'] if k in ctx.user()]:
2533 return
2534 return
2534 if opts.get('keyword'):
2535 if opts.get('keyword'):
2535 for k in [kw.lower() for kw in opts['keyword']]:
2536 for k in [kw.lower() for kw in opts['keyword']]:
2536 if (k in ctx.user().lower() or
2537 if (k in ctx.user().lower() or
2537 k in ctx.description().lower() or
2538 k in ctx.description().lower() or
2538 k in " ".join(ctx.files()).lower()):
2539 k in " ".join(ctx.files()).lower()):
2539 break
2540 break
2540 else:
2541 else:
2541 return
2542 return
2542
2543
2543 copies = None
2544 copies = None
2544 if opts.get('copies') and rev:
2545 if opts.get('copies') and rev:
2545 copies = []
2546 copies = []
2546 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2547 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2547 for fn in ctx.files():
2548 for fn in ctx.files():
2548 rename = getrenamed(fn, rev)
2549 rename = getrenamed(fn, rev)
2549 if rename:
2550 if rename:
2550 copies.append((fn, rename[0]))
2551 copies.append((fn, rename[0]))
2551
2552
2552 revmatchfn = None
2553 revmatchfn = None
2553 if opts.get('patch') or opts.get('stat'):
2554 if opts.get('patch') or opts.get('stat'):
2554 revmatchfn = cmdutil.match(repo, fns, default='path')
2555 revmatchfn = cmdutil.match(repo, fns, default='path')
2555
2556
2556 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2557 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2557
2558
2558 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2559 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2559 if count == limit:
2560 if count == limit:
2560 break
2561 break
2561 if displayer.flush(ctx.rev()):
2562 if displayer.flush(ctx.rev()):
2562 count += 1
2563 count += 1
2563 displayer.close()
2564 displayer.close()
2564
2565
2565 def manifest(ui, repo, node=None, rev=None):
2566 def manifest(ui, repo, node=None, rev=None):
2566 """output the current or given revision of the project manifest
2567 """output the current or given revision of the project manifest
2567
2568
2568 Print a list of version controlled files for the given revision.
2569 Print a list of version controlled files for the given revision.
2569 If no revision is given, the first parent of the working directory
2570 If no revision is given, the first parent of the working directory
2570 is used, or the null revision if no revision is checked out.
2571 is used, or the null revision if no revision is checked out.
2571
2572
2572 With -v, print file permissions, symlink and executable bits.
2573 With -v, print file permissions, symlink and executable bits.
2573 With --debug, print file revision hashes.
2574 With --debug, print file revision hashes.
2574
2575
2575 Returns 0 on success.
2576 Returns 0 on success.
2576 """
2577 """
2577
2578
2578 if rev and node:
2579 if rev and node:
2579 raise util.Abort(_("please specify just one revision"))
2580 raise util.Abort(_("please specify just one revision"))
2580
2581
2581 if not node:
2582 if not node:
2582 node = rev
2583 node = rev
2583
2584
2584 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2585 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2585 ctx = repo[node]
2586 ctx = repo[node]
2586 for f in ctx:
2587 for f in ctx:
2587 if ui.debugflag:
2588 if ui.debugflag:
2588 ui.write("%40s " % hex(ctx.manifest()[f]))
2589 ui.write("%40s " % hex(ctx.manifest()[f]))
2589 if ui.verbose:
2590 if ui.verbose:
2590 ui.write(decor[ctx.flags(f)])
2591 ui.write(decor[ctx.flags(f)])
2591 ui.write("%s\n" % f)
2592 ui.write("%s\n" % f)
2592
2593
2593 def merge(ui, repo, node=None, **opts):
2594 def merge(ui, repo, node=None, **opts):
2594 """merge working directory with another revision
2595 """merge working directory with another revision
2595
2596
2596 The current working directory is updated with all changes made in
2597 The current working directory is updated with all changes made in
2597 the requested revision since the last common predecessor revision.
2598 the requested revision since the last common predecessor revision.
2598
2599
2599 Files that changed between either parent are marked as changed for
2600 Files that changed between either parent are marked as changed for
2600 the next commit and a commit must be performed before any further
2601 the next commit and a commit must be performed before any further
2601 updates to the repository are allowed. The next commit will have
2602 updates to the repository are allowed. The next commit will have
2602 two parents.
2603 two parents.
2603
2604
2604 If no revision is specified, the working directory's parent is a
2605 If no revision is specified, the working directory's parent is a
2605 head revision, and the current branch contains exactly one other
2606 head revision, and the current branch contains exactly one other
2606 head, the other head is merged with by default. Otherwise, an
2607 head, the other head is merged with by default. Otherwise, an
2607 explicit revision with which to merge with must be provided.
2608 explicit revision with which to merge with must be provided.
2608
2609
2609 To undo an uncommitted merge, use :hg:`update --clean .` which
2610 To undo an uncommitted merge, use :hg:`update --clean .` which
2610 will check out a clean copy of the original merge parent, losing
2611 will check out a clean copy of the original merge parent, losing
2611 all changes.
2612 all changes.
2612
2613
2613 Returns 0 on success, 1 if there are unresolved files.
2614 Returns 0 on success, 1 if there are unresolved files.
2614 """
2615 """
2615
2616
2616 if opts.get('rev') and node:
2617 if opts.get('rev') and node:
2617 raise util.Abort(_("please specify just one revision"))
2618 raise util.Abort(_("please specify just one revision"))
2618 if not node:
2619 if not node:
2619 node = opts.get('rev')
2620 node = opts.get('rev')
2620
2621
2621 if not node:
2622 if not node:
2622 branch = repo.changectx(None).branch()
2623 branch = repo.changectx(None).branch()
2623 bheads = repo.branchheads(branch)
2624 bheads = repo.branchheads(branch)
2624 if len(bheads) > 2:
2625 if len(bheads) > 2:
2625 raise util.Abort(_(
2626 raise util.Abort(_(
2626 'branch \'%s\' has %d heads - '
2627 'branch \'%s\' has %d heads - '
2627 'please merge with an explicit rev\n'
2628 'please merge with an explicit rev\n'
2628 '(run \'hg heads .\' to see heads)')
2629 '(run \'hg heads .\' to see heads)')
2629 % (branch, len(bheads)))
2630 % (branch, len(bheads)))
2630
2631
2631 parent = repo.dirstate.parents()[0]
2632 parent = repo.dirstate.parents()[0]
2632 if len(bheads) == 1:
2633 if len(bheads) == 1:
2633 if len(repo.heads()) > 1:
2634 if len(repo.heads()) > 1:
2634 raise util.Abort(_(
2635 raise util.Abort(_(
2635 'branch \'%s\' has one head - '
2636 'branch \'%s\' has one head - '
2636 'please merge with an explicit rev\n'
2637 'please merge with an explicit rev\n'
2637 '(run \'hg heads\' to see all heads)')
2638 '(run \'hg heads\' to see all heads)')
2638 % branch)
2639 % branch)
2639 msg = _('there is nothing to merge')
2640 msg = _('there is nothing to merge')
2640 if parent != repo.lookup(repo[None].branch()):
2641 if parent != repo.lookup(repo[None].branch()):
2641 msg = _('%s - use "hg update" instead') % msg
2642 msg = _('%s - use "hg update" instead') % msg
2642 raise util.Abort(msg)
2643 raise util.Abort(msg)
2643
2644
2644 if parent not in bheads:
2645 if parent not in bheads:
2645 raise util.Abort(_('working dir not at a head rev - '
2646 raise util.Abort(_('working dir not at a head rev - '
2646 'use "hg update" or merge with an explicit rev'))
2647 'use "hg update" or merge with an explicit rev'))
2647 node = parent == bheads[0] and bheads[-1] or bheads[0]
2648 node = parent == bheads[0] and bheads[-1] or bheads[0]
2648
2649
2649 if opts.get('preview'):
2650 if opts.get('preview'):
2650 # find nodes that are ancestors of p2 but not of p1
2651 # find nodes that are ancestors of p2 but not of p1
2651 p1 = repo.lookup('.')
2652 p1 = repo.lookup('.')
2652 p2 = repo.lookup(node)
2653 p2 = repo.lookup(node)
2653 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2654 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2654
2655
2655 displayer = cmdutil.show_changeset(ui, repo, opts)
2656 displayer = cmdutil.show_changeset(ui, repo, opts)
2656 for node in nodes:
2657 for node in nodes:
2657 displayer.show(repo[node])
2658 displayer.show(repo[node])
2658 displayer.close()
2659 displayer.close()
2659 return 0
2660 return 0
2660
2661
2661 return hg.merge(repo, node, force=opts.get('force'))
2662 return hg.merge(repo, node, force=opts.get('force'))
2662
2663
2663 def outgoing(ui, repo, dest=None, **opts):
2664 def outgoing(ui, repo, dest=None, **opts):
2664 """show changesets not found in the destination
2665 """show changesets not found in the destination
2665
2666
2666 Show changesets not found in the specified destination repository
2667 Show changesets not found in the specified destination repository
2667 or the default push location. These are the changesets that would
2668 or the default push location. These are the changesets that would
2668 be pushed if a push was requested.
2669 be pushed if a push was requested.
2669
2670
2670 See pull for details of valid destination formats.
2671 See pull for details of valid destination formats.
2671
2672
2672 Returns 0 if there are outgoing changes, 1 otherwise.
2673 Returns 0 if there are outgoing changes, 1 otherwise.
2673 """
2674 """
2674 limit = cmdutil.loglimit(opts)
2675 limit = cmdutil.loglimit(opts)
2675 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2676 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2676 dest, branches = hg.parseurl(dest, opts.get('branch'))
2677 dest, branches = hg.parseurl(dest, opts.get('branch'))
2677 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2678 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2678 if revs:
2679 if revs:
2679 revs = [repo.lookup(rev) for rev in revs]
2680 revs = [repo.lookup(rev) for rev in revs]
2680
2681
2681 other = hg.repository(hg.remoteui(repo, opts), dest)
2682 other = hg.repository(hg.remoteui(repo, opts), dest)
2682 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2683 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2683 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
2684 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
2684 if not o:
2685 if not o:
2685 ui.status(_("no changes found\n"))
2686 ui.status(_("no changes found\n"))
2686 return 1
2687 return 1
2687 o = repo.changelog.nodesbetween(o, revs)[0]
2688 o = repo.changelog.nodesbetween(o, revs)[0]
2688 if opts.get('newest_first'):
2689 if opts.get('newest_first'):
2689 o.reverse()
2690 o.reverse()
2690 displayer = cmdutil.show_changeset(ui, repo, opts)
2691 displayer = cmdutil.show_changeset(ui, repo, opts)
2691 count = 0
2692 count = 0
2692 for n in o:
2693 for n in o:
2693 if limit is not None and count >= limit:
2694 if limit is not None and count >= limit:
2694 break
2695 break
2695 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2696 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2696 if opts.get('no_merges') and len(parents) == 2:
2697 if opts.get('no_merges') and len(parents) == 2:
2697 continue
2698 continue
2698 count += 1
2699 count += 1
2699 displayer.show(repo[n])
2700 displayer.show(repo[n])
2700 displayer.close()
2701 displayer.close()
2701
2702
2702 def parents(ui, repo, file_=None, **opts):
2703 def parents(ui, repo, file_=None, **opts):
2703 """show the parents of the working directory or revision
2704 """show the parents of the working directory or revision
2704
2705
2705 Print the working directory's parent revisions. If a revision is
2706 Print the working directory's parent revisions. If a revision is
2706 given via -r/--rev, the parent of that revision will be printed.
2707 given via -r/--rev, the parent of that revision will be printed.
2707 If a file argument is given, the revision in which the file was
2708 If a file argument is given, the revision in which the file was
2708 last changed (before the working directory revision or the
2709 last changed (before the working directory revision or the
2709 argument to --rev if given) is printed.
2710 argument to --rev if given) is printed.
2710
2711
2711 Returns 0 on success.
2712 Returns 0 on success.
2712 """
2713 """
2713 rev = opts.get('rev')
2714 rev = opts.get('rev')
2714 if rev:
2715 if rev:
2715 ctx = repo[rev]
2716 ctx = repo[rev]
2716 else:
2717 else:
2717 ctx = repo[None]
2718 ctx = repo[None]
2718
2719
2719 if file_:
2720 if file_:
2720 m = cmdutil.match(repo, (file_,), opts)
2721 m = cmdutil.match(repo, (file_,), opts)
2721 if m.anypats() or len(m.files()) != 1:
2722 if m.anypats() or len(m.files()) != 1:
2722 raise util.Abort(_('can only specify an explicit filename'))
2723 raise util.Abort(_('can only specify an explicit filename'))
2723 file_ = m.files()[0]
2724 file_ = m.files()[0]
2724 filenodes = []
2725 filenodes = []
2725 for cp in ctx.parents():
2726 for cp in ctx.parents():
2726 if not cp:
2727 if not cp:
2727 continue
2728 continue
2728 try:
2729 try:
2729 filenodes.append(cp.filenode(file_))
2730 filenodes.append(cp.filenode(file_))
2730 except error.LookupError:
2731 except error.LookupError:
2731 pass
2732 pass
2732 if not filenodes:
2733 if not filenodes:
2733 raise util.Abort(_("'%s' not found in manifest!") % file_)
2734 raise util.Abort(_("'%s' not found in manifest!") % file_)
2734 fl = repo.file(file_)
2735 fl = repo.file(file_)
2735 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2736 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2736 else:
2737 else:
2737 p = [cp.node() for cp in ctx.parents()]
2738 p = [cp.node() for cp in ctx.parents()]
2738
2739
2739 displayer = cmdutil.show_changeset(ui, repo, opts)
2740 displayer = cmdutil.show_changeset(ui, repo, opts)
2740 for n in p:
2741 for n in p:
2741 if n != nullid:
2742 if n != nullid:
2742 displayer.show(repo[n])
2743 displayer.show(repo[n])
2743 displayer.close()
2744 displayer.close()
2744
2745
2745 def paths(ui, repo, search=None):
2746 def paths(ui, repo, search=None):
2746 """show aliases for remote repositories
2747 """show aliases for remote repositories
2747
2748
2748 Show definition of symbolic path name NAME. If no name is given,
2749 Show definition of symbolic path name NAME. If no name is given,
2749 show definition of all available names.
2750 show definition of all available names.
2750
2751
2751 Path names are defined in the [paths] section of your
2752 Path names are defined in the [paths] section of your
2752 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2753 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2753 repository, ``.hg/hgrc`` is used, too.
2754 repository, ``.hg/hgrc`` is used, too.
2754
2755
2755 The path names ``default`` and ``default-push`` have a special
2756 The path names ``default`` and ``default-push`` have a special
2756 meaning. When performing a push or pull operation, they are used
2757 meaning. When performing a push or pull operation, they are used
2757 as fallbacks if no location is specified on the command-line.
2758 as fallbacks if no location is specified on the command-line.
2758 When ``default-push`` is set, it will be used for push and
2759 When ``default-push`` is set, it will be used for push and
2759 ``default`` will be used for pull; otherwise ``default`` is used
2760 ``default`` will be used for pull; otherwise ``default`` is used
2760 as the fallback for both. When cloning a repository, the clone
2761 as the fallback for both. When cloning a repository, the clone
2761 source is written as ``default`` in ``.hg/hgrc``. Note that
2762 source is written as ``default`` in ``.hg/hgrc``. Note that
2762 ``default`` and ``default-push`` apply to all inbound (e.g.
2763 ``default`` and ``default-push`` apply to all inbound (e.g.
2763 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2764 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2764 :hg:`bundle`) operations.
2765 :hg:`bundle`) operations.
2765
2766
2766 See :hg:`help urls` for more information.
2767 See :hg:`help urls` for more information.
2767
2768
2768 Returns 0 on success.
2769 Returns 0 on success.
2769 """
2770 """
2770 if search:
2771 if search:
2771 for name, path in ui.configitems("paths"):
2772 for name, path in ui.configitems("paths"):
2772 if name == search:
2773 if name == search:
2773 ui.write("%s\n" % url.hidepassword(path))
2774 ui.write("%s\n" % url.hidepassword(path))
2774 return
2775 return
2775 ui.warn(_("not found!\n"))
2776 ui.warn(_("not found!\n"))
2776 return 1
2777 return 1
2777 else:
2778 else:
2778 for name, path in ui.configitems("paths"):
2779 for name, path in ui.configitems("paths"):
2779 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2780 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2780
2781
2781 def postincoming(ui, repo, modheads, optupdate, checkout):
2782 def postincoming(ui, repo, modheads, optupdate, checkout):
2782 if modheads == 0:
2783 if modheads == 0:
2783 return
2784 return
2784 if optupdate:
2785 if optupdate:
2785 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2786 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2786 return hg.update(repo, checkout)
2787 return hg.update(repo, checkout)
2787 else:
2788 else:
2788 ui.status(_("not updating, since new heads added\n"))
2789 ui.status(_("not updating, since new heads added\n"))
2789 if modheads > 1:
2790 if modheads > 1:
2790 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2791 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2791 else:
2792 else:
2792 ui.status(_("(run 'hg update' to get a working copy)\n"))
2793 ui.status(_("(run 'hg update' to get a working copy)\n"))
2793
2794
2794 def pull(ui, repo, source="default", **opts):
2795 def pull(ui, repo, source="default", **opts):
2795 """pull changes from the specified source
2796 """pull changes from the specified source
2796
2797
2797 Pull changes from a remote repository to a local one.
2798 Pull changes from a remote repository to a local one.
2798
2799
2799 This finds all changes from the repository at the specified path
2800 This finds all changes from the repository at the specified path
2800 or URL and adds them to a local repository (the current one unless
2801 or URL and adds them to a local repository (the current one unless
2801 -R is specified). By default, this does not update the copy of the
2802 -R is specified). By default, this does not update the copy of the
2802 project in the working directory.
2803 project in the working directory.
2803
2804
2804 Use :hg:`incoming` if you want to see what would have been added
2805 Use :hg:`incoming` if you want to see what would have been added
2805 by a pull at the time you issued this command. If you then decide
2806 by a pull at the time you issued this command. If you then decide
2806 to add those changes to the repository, you should use :hg:`pull
2807 to add those changes to the repository, you should use :hg:`pull
2807 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
2808 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
2808
2809
2809 If SOURCE is omitted, the 'default' path will be used.
2810 If SOURCE is omitted, the 'default' path will be used.
2810 See :hg:`help urls` for more information.
2811 See :hg:`help urls` for more information.
2811
2812
2812 Returns 0 on success, 1 if an update had unresolved files.
2813 Returns 0 on success, 1 if an update had unresolved files.
2813 """
2814 """
2814 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2815 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2815 other = hg.repository(hg.remoteui(repo, opts), source)
2816 other = hg.repository(hg.remoteui(repo, opts), source)
2816 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2817 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2817 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2818 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2818 if revs:
2819 if revs:
2819 try:
2820 try:
2820 revs = [other.lookup(rev) for rev in revs]
2821 revs = [other.lookup(rev) for rev in revs]
2821 except error.CapabilityError:
2822 except error.CapabilityError:
2822 err = _("other repository doesn't support revision lookup, "
2823 err = _("other repository doesn't support revision lookup, "
2823 "so a rev cannot be specified.")
2824 "so a rev cannot be specified.")
2824 raise util.Abort(err)
2825 raise util.Abort(err)
2825
2826
2826 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2827 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2827 if checkout:
2828 if checkout:
2828 checkout = str(repo.changelog.rev(other.lookup(checkout)))
2829 checkout = str(repo.changelog.rev(other.lookup(checkout)))
2829 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2830 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2830
2831
2831 def push(ui, repo, dest=None, **opts):
2832 def push(ui, repo, dest=None, **opts):
2832 """push changes to the specified destination
2833 """push changes to the specified destination
2833
2834
2834 Push changesets from the local repository to the specified
2835 Push changesets from the local repository to the specified
2835 destination.
2836 destination.
2836
2837
2837 This operation is symmetrical to pull: it is identical to a pull
2838 This operation is symmetrical to pull: it is identical to a pull
2838 in the destination repository from the current one.
2839 in the destination repository from the current one.
2839
2840
2840 By default, push will not allow creation of new heads at the
2841 By default, push will not allow creation of new heads at the
2841 destination, since multiple heads would make it unclear which head
2842 destination, since multiple heads would make it unclear which head
2842 to use. In this situation, it is recommended to pull and merge
2843 to use. In this situation, it is recommended to pull and merge
2843 before pushing.
2844 before pushing.
2844
2845
2845 Use --new-branch if you want to allow push to create a new named
2846 Use --new-branch if you want to allow push to create a new named
2846 branch that is not present at the destination. This allows you to
2847 branch that is not present at the destination. This allows you to
2847 only create a new branch without forcing other changes.
2848 only create a new branch without forcing other changes.
2848
2849
2849 Use -f/--force to override the default behavior and push all
2850 Use -f/--force to override the default behavior and push all
2850 changesets on all branches.
2851 changesets on all branches.
2851
2852
2852 If -r/--rev is used, the specified revision and all its ancestors
2853 If -r/--rev is used, the specified revision and all its ancestors
2853 will be pushed to the remote repository.
2854 will be pushed to the remote repository.
2854
2855
2855 Please see :hg:`help urls` for important details about ``ssh://``
2856 Please see :hg:`help urls` for important details about ``ssh://``
2856 URLs. If DESTINATION is omitted, a default path will be used.
2857 URLs. If DESTINATION is omitted, a default path will be used.
2857
2858
2858 Returns 0 if push was successful, 1 if nothing to push.
2859 Returns 0 if push was successful, 1 if nothing to push.
2859 """
2860 """
2860 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2861 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2861 dest, branches = hg.parseurl(dest, opts.get('branch'))
2862 dest, branches = hg.parseurl(dest, opts.get('branch'))
2862 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2863 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2863 other = hg.repository(hg.remoteui(repo, opts), dest)
2864 other = hg.repository(hg.remoteui(repo, opts), dest)
2864 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2865 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2865 if revs:
2866 if revs:
2866 revs = [repo.lookup(rev) for rev in revs]
2867 revs = [repo.lookup(rev) for rev in revs]
2867
2868
2868 # push subrepos depth-first for coherent ordering
2869 # push subrepos depth-first for coherent ordering
2869 c = repo['']
2870 c = repo['']
2870 subs = c.substate # only repos that are committed
2871 subs = c.substate # only repos that are committed
2871 for s in sorted(subs):
2872 for s in sorted(subs):
2872 if not c.sub(s).push(opts.get('force')):
2873 if not c.sub(s).push(opts.get('force')):
2873 return False
2874 return False
2874
2875
2875 r = repo.push(other, opts.get('force'), revs=revs,
2876 r = repo.push(other, opts.get('force'), revs=revs,
2876 newbranch=opts.get('new_branch'))
2877 newbranch=opts.get('new_branch'))
2877 return r == 0
2878 return r == 0
2878
2879
2879 def recover(ui, repo):
2880 def recover(ui, repo):
2880 """roll back an interrupted transaction
2881 """roll back an interrupted transaction
2881
2882
2882 Recover from an interrupted commit or pull.
2883 Recover from an interrupted commit or pull.
2883
2884
2884 This command tries to fix the repository status after an
2885 This command tries to fix the repository status after an
2885 interrupted operation. It should only be necessary when Mercurial
2886 interrupted operation. It should only be necessary when Mercurial
2886 suggests it.
2887 suggests it.
2887
2888
2888 Returns 0 if successful, 1 if nothing to recover or verify fails.
2889 Returns 0 if successful, 1 if nothing to recover or verify fails.
2889 """
2890 """
2890 if repo.recover():
2891 if repo.recover():
2891 return hg.verify(repo)
2892 return hg.verify(repo)
2892 return 1
2893 return 1
2893
2894
2894 def remove(ui, repo, *pats, **opts):
2895 def remove(ui, repo, *pats, **opts):
2895 """remove the specified files on the next commit
2896 """remove the specified files on the next commit
2896
2897
2897 Schedule the indicated files for removal from the repository.
2898 Schedule the indicated files for removal from the repository.
2898
2899
2899 This only removes files from the current branch, not from the
2900 This only removes files from the current branch, not from the
2900 entire project history. -A/--after can be used to remove only
2901 entire project history. -A/--after can be used to remove only
2901 files that have already been deleted, -f/--force can be used to
2902 files that have already been deleted, -f/--force can be used to
2902 force deletion, and -Af can be used to remove files from the next
2903 force deletion, and -Af can be used to remove files from the next
2903 revision without deleting them from the working directory.
2904 revision without deleting them from the working directory.
2904
2905
2905 The following table details the behavior of remove for different
2906 The following table details the behavior of remove for different
2906 file states (columns) and option combinations (rows). The file
2907 file states (columns) and option combinations (rows). The file
2907 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
2908 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
2908 reported by :hg:`status`). The actions are Warn, Remove (from
2909 reported by :hg:`status`). The actions are Warn, Remove (from
2909 branch) and Delete (from disk)::
2910 branch) and Delete (from disk)::
2910
2911
2911 A C M !
2912 A C M !
2912 none W RD W R
2913 none W RD W R
2913 -f R RD RD R
2914 -f R RD RD R
2914 -A W W W R
2915 -A W W W R
2915 -Af R R R R
2916 -Af R R R R
2916
2917
2917 This command schedules the files to be removed at the next commit.
2918 This command schedules the files to be removed at the next commit.
2918 To undo a remove before that, see :hg:`revert`.
2919 To undo a remove before that, see :hg:`revert`.
2919
2920
2920 Returns 0 on success, 1 if any warnings encountered.
2921 Returns 0 on success, 1 if any warnings encountered.
2921 """
2922 """
2922
2923
2923 ret = 0
2924 ret = 0
2924 after, force = opts.get('after'), opts.get('force')
2925 after, force = opts.get('after'), opts.get('force')
2925 if not pats and not after:
2926 if not pats and not after:
2926 raise util.Abort(_('no files specified'))
2927 raise util.Abort(_('no files specified'))
2927
2928
2928 m = cmdutil.match(repo, pats, opts)
2929 m = cmdutil.match(repo, pats, opts)
2929 s = repo.status(match=m, clean=True)
2930 s = repo.status(match=m, clean=True)
2930 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2931 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2931
2932
2932 for f in m.files():
2933 for f in m.files():
2933 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2934 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2934 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2935 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2935 ret = 1
2936 ret = 1
2936
2937
2937 if force:
2938 if force:
2938 remove, forget = modified + deleted + clean, added
2939 remove, forget = modified + deleted + clean, added
2939 elif after:
2940 elif after:
2940 remove, forget = deleted, []
2941 remove, forget = deleted, []
2941 for f in modified + added + clean:
2942 for f in modified + added + clean:
2942 ui.warn(_('not removing %s: file still exists (use -f'
2943 ui.warn(_('not removing %s: file still exists (use -f'
2943 ' to force removal)\n') % m.rel(f))
2944 ' to force removal)\n') % m.rel(f))
2944 ret = 1
2945 ret = 1
2945 else:
2946 else:
2946 remove, forget = deleted + clean, []
2947 remove, forget = deleted + clean, []
2947 for f in modified:
2948 for f in modified:
2948 ui.warn(_('not removing %s: file is modified (use -f'
2949 ui.warn(_('not removing %s: file is modified (use -f'
2949 ' to force removal)\n') % m.rel(f))
2950 ' to force removal)\n') % m.rel(f))
2950 ret = 1
2951 ret = 1
2951 for f in added:
2952 for f in added:
2952 ui.warn(_('not removing %s: file has been marked for add (use -f'
2953 ui.warn(_('not removing %s: file has been marked for add (use -f'
2953 ' to force removal)\n') % m.rel(f))
2954 ' to force removal)\n') % m.rel(f))
2954 ret = 1
2955 ret = 1
2955
2956
2956 for f in sorted(remove + forget):
2957 for f in sorted(remove + forget):
2957 if ui.verbose or not m.exact(f):
2958 if ui.verbose or not m.exact(f):
2958 ui.status(_('removing %s\n') % m.rel(f))
2959 ui.status(_('removing %s\n') % m.rel(f))
2959
2960
2960 repo[None].forget(forget)
2961 repo[None].forget(forget)
2961 repo[None].remove(remove, unlink=not after)
2962 repo[None].remove(remove, unlink=not after)
2962 return ret
2963 return ret
2963
2964
2964 def rename(ui, repo, *pats, **opts):
2965 def rename(ui, repo, *pats, **opts):
2965 """rename files; equivalent of copy + remove
2966 """rename files; equivalent of copy + remove
2966
2967
2967 Mark dest as copies of sources; mark sources for deletion. If dest
2968 Mark dest as copies of sources; mark sources for deletion. If dest
2968 is a directory, copies are put in that directory. If dest is a
2969 is a directory, copies are put in that directory. If dest is a
2969 file, there can only be one source.
2970 file, there can only be one source.
2970
2971
2971 By default, this command copies the contents of files as they
2972 By default, this command copies the contents of files as they
2972 exist in the working directory. If invoked with -A/--after, the
2973 exist in the working directory. If invoked with -A/--after, the
2973 operation is recorded, but no copying is performed.
2974 operation is recorded, but no copying is performed.
2974
2975
2975 This command takes effect at the next commit. To undo a rename
2976 This command takes effect at the next commit. To undo a rename
2976 before that, see :hg:`revert`.
2977 before that, see :hg:`revert`.
2977
2978
2978 Returns 0 on success, 1 if errors are encountered.
2979 Returns 0 on success, 1 if errors are encountered.
2979 """
2980 """
2980 wlock = repo.wlock(False)
2981 wlock = repo.wlock(False)
2981 try:
2982 try:
2982 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2983 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2983 finally:
2984 finally:
2984 wlock.release()
2985 wlock.release()
2985
2986
2986 def resolve(ui, repo, *pats, **opts):
2987 def resolve(ui, repo, *pats, **opts):
2987 """redo merges or set/view the merge status of files
2988 """redo merges or set/view the merge status of files
2988
2989
2989 Merges with unresolved conflicts are often the result of
2990 Merges with unresolved conflicts are often the result of
2990 non-interactive merging using the ``internal:merge`` configuration
2991 non-interactive merging using the ``internal:merge`` configuration
2991 setting, or a command-line merge tool like ``diff3``. The resolve
2992 setting, or a command-line merge tool like ``diff3``. The resolve
2992 command is used to manage the files involved in a merge, after
2993 command is used to manage the files involved in a merge, after
2993 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
2994 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
2994 working directory must have two parents).
2995 working directory must have two parents).
2995
2996
2996 The resolve command can be used in the following ways:
2997 The resolve command can be used in the following ways:
2997
2998
2998 - :hg:`resolve FILE...`: attempt to re-merge the specified files,
2999 - :hg:`resolve FILE...`: attempt to re-merge the specified files,
2999 discarding any previous merge attempts. Re-merging is not
3000 discarding any previous merge attempts. Re-merging is not
3000 performed for files already marked as resolved. Use ``--all/-a``
3001 performed for files already marked as resolved. Use ``--all/-a``
3001 to selects all unresolved files.
3002 to selects all unresolved files.
3002
3003
3003 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3004 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3004 (e.g. after having manually fixed-up the files). The default is
3005 (e.g. after having manually fixed-up the files). The default is
3005 to mark all unresolved files.
3006 to mark all unresolved files.
3006
3007
3007 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3008 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3008 default is to mark all resolved files.
3009 default is to mark all resolved files.
3009
3010
3010 - :hg:`resolve -l`: list files which had or still have conflicts.
3011 - :hg:`resolve -l`: list files which had or still have conflicts.
3011 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3012 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3012
3013
3013 Note that Mercurial will not let you commit files with unresolved
3014 Note that Mercurial will not let you commit files with unresolved
3014 merge conflicts. You must use :hg:`resolve -m ...` before you can
3015 merge conflicts. You must use :hg:`resolve -m ...` before you can
3015 commit after a conflicting merge.
3016 commit after a conflicting merge.
3016
3017
3017 Returns 0 on success, 1 if any files fail a resolve attempt.
3018 Returns 0 on success, 1 if any files fail a resolve attempt.
3018 """
3019 """
3019
3020
3020 all, mark, unmark, show, nostatus = \
3021 all, mark, unmark, show, nostatus = \
3021 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3022 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3022
3023
3023 if (show and (mark or unmark)) or (mark and unmark):
3024 if (show and (mark or unmark)) or (mark and unmark):
3024 raise util.Abort(_("too many options specified"))
3025 raise util.Abort(_("too many options specified"))
3025 if pats and all:
3026 if pats and all:
3026 raise util.Abort(_("can't specify --all and patterns"))
3027 raise util.Abort(_("can't specify --all and patterns"))
3027 if not (all or pats or show or mark or unmark):
3028 if not (all or pats or show or mark or unmark):
3028 raise util.Abort(_('no files or directories specified; '
3029 raise util.Abort(_('no files or directories specified; '
3029 'use --all to remerge all files'))
3030 'use --all to remerge all files'))
3030
3031
3031 ms = mergemod.mergestate(repo)
3032 ms = mergemod.mergestate(repo)
3032 m = cmdutil.match(repo, pats, opts)
3033 m = cmdutil.match(repo, pats, opts)
3033 ret = 0
3034 ret = 0
3034
3035
3035 for f in ms:
3036 for f in ms:
3036 if m(f):
3037 if m(f):
3037 if show:
3038 if show:
3038 if nostatus:
3039 if nostatus:
3039 ui.write("%s\n" % f)
3040 ui.write("%s\n" % f)
3040 else:
3041 else:
3041 ui.write("%s %s\n" % (ms[f].upper(), f),
3042 ui.write("%s %s\n" % (ms[f].upper(), f),
3042 label='resolve.' +
3043 label='resolve.' +
3043 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3044 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3044 elif mark:
3045 elif mark:
3045 ms.mark(f, "r")
3046 ms.mark(f, "r")
3046 elif unmark:
3047 elif unmark:
3047 ms.mark(f, "u")
3048 ms.mark(f, "u")
3048 else:
3049 else:
3049 wctx = repo[None]
3050 wctx = repo[None]
3050 mctx = wctx.parents()[-1]
3051 mctx = wctx.parents()[-1]
3051
3052
3052 # backup pre-resolve (merge uses .orig for its own purposes)
3053 # backup pre-resolve (merge uses .orig for its own purposes)
3053 a = repo.wjoin(f)
3054 a = repo.wjoin(f)
3054 util.copyfile(a, a + ".resolve")
3055 util.copyfile(a, a + ".resolve")
3055
3056
3056 # resolve file
3057 # resolve file
3057 if ms.resolve(f, wctx, mctx):
3058 if ms.resolve(f, wctx, mctx):
3058 ret = 1
3059 ret = 1
3059
3060
3060 # replace filemerge's .orig file with our resolve file
3061 # replace filemerge's .orig file with our resolve file
3061 util.rename(a + ".resolve", a + ".orig")
3062 util.rename(a + ".resolve", a + ".orig")
3062 return ret
3063 return ret
3063
3064
3064 def revert(ui, repo, *pats, **opts):
3065 def revert(ui, repo, *pats, **opts):
3065 """restore individual files or directories to an earlier state
3066 """restore individual files or directories to an earlier state
3066
3067
3067 NOTE: This command is most likely not what you are looking for. revert
3068 NOTE: This command is most likely not what you are looking for. revert
3068 will partially overwrite content in the working directory without changing
3069 will partially overwrite content in the working directory without changing
3069 the working directory parents. Use :hg:`update -r rev` to check out earlier
3070 the working directory parents. Use :hg:`update -r rev` to check out earlier
3070 revisions, or :hg:`update --clean .` to undo a merge which has added
3071 revisions, or :hg:`update --clean .` to undo a merge which has added
3071 another parent.
3072 another parent.
3072
3073
3073 With no revision specified, revert the named files or directories
3074 With no revision specified, revert the named files or directories
3074 to the contents they had in the parent of the working directory.
3075 to the contents they had in the parent of the working directory.
3075 This restores the contents of the affected files to an unmodified
3076 This restores the contents of the affected files to an unmodified
3076 state and unschedules adds, removes, copies, and renames. If the
3077 state and unschedules adds, removes, copies, and renames. If the
3077 working directory has two parents, you must explicitly specify a
3078 working directory has two parents, you must explicitly specify a
3078 revision.
3079 revision.
3079
3080
3080 Using the -r/--rev option, revert the given files or directories
3081 Using the -r/--rev option, revert the given files or directories
3081 to their contents as of a specific revision. This can be helpful
3082 to their contents as of a specific revision. This can be helpful
3082 to "roll back" some or all of an earlier change. See :hg:`help
3083 to "roll back" some or all of an earlier change. See :hg:`help
3083 dates` for a list of formats valid for -d/--date.
3084 dates` for a list of formats valid for -d/--date.
3084
3085
3085 Revert modifies the working directory. It does not commit any
3086 Revert modifies the working directory. It does not commit any
3086 changes, or change the parent of the working directory. If you
3087 changes, or change the parent of the working directory. If you
3087 revert to a revision other than the parent of the working
3088 revert to a revision other than the parent of the working
3088 directory, the reverted files will thus appear modified
3089 directory, the reverted files will thus appear modified
3089 afterwards.
3090 afterwards.
3090
3091
3091 If a file has been deleted, it is restored. If the executable mode
3092 If a file has been deleted, it is restored. If the executable mode
3092 of a file was changed, it is reset.
3093 of a file was changed, it is reset.
3093
3094
3094 If names are given, all files matching the names are reverted.
3095 If names are given, all files matching the names are reverted.
3095 If no arguments are given, no files are reverted.
3096 If no arguments are given, no files are reverted.
3096
3097
3097 Modified files are saved with a .orig suffix before reverting.
3098 Modified files are saved with a .orig suffix before reverting.
3098 To disable these backups, use --no-backup.
3099 To disable these backups, use --no-backup.
3099
3100
3100 Returns 0 on success.
3101 Returns 0 on success.
3101 """
3102 """
3102
3103
3103 if opts.get("date"):
3104 if opts.get("date"):
3104 if opts.get("rev"):
3105 if opts.get("rev"):
3105 raise util.Abort(_("you can't specify a revision and a date"))
3106 raise util.Abort(_("you can't specify a revision and a date"))
3106 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3107 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3107
3108
3108 if not pats and not opts.get('all'):
3109 if not pats and not opts.get('all'):
3109 raise util.Abort(_('no files or directories specified; '
3110 raise util.Abort(_('no files or directories specified; '
3110 'use --all to revert the whole repo'))
3111 'use --all to revert the whole repo'))
3111
3112
3112 parent, p2 = repo.dirstate.parents()
3113 parent, p2 = repo.dirstate.parents()
3113 if not opts.get('rev') and p2 != nullid:
3114 if not opts.get('rev') and p2 != nullid:
3114 raise util.Abort(_('uncommitted merge - please provide a '
3115 raise util.Abort(_('uncommitted merge - please provide a '
3115 'specific revision'))
3116 'specific revision'))
3116 ctx = repo[opts.get('rev')]
3117 ctx = repo[opts.get('rev')]
3117 node = ctx.node()
3118 node = ctx.node()
3118 mf = ctx.manifest()
3119 mf = ctx.manifest()
3119 if node == parent:
3120 if node == parent:
3120 pmf = mf
3121 pmf = mf
3121 else:
3122 else:
3122 pmf = None
3123 pmf = None
3123
3124
3124 # need all matching names in dirstate and manifest of target rev,
3125 # need all matching names in dirstate and manifest of target rev,
3125 # so have to walk both. do not print errors if files exist in one
3126 # so have to walk both. do not print errors if files exist in one
3126 # but not other.
3127 # but not other.
3127
3128
3128 names = {}
3129 names = {}
3129
3130
3130 wlock = repo.wlock()
3131 wlock = repo.wlock()
3131 try:
3132 try:
3132 # walk dirstate.
3133 # walk dirstate.
3133
3134
3134 m = cmdutil.match(repo, pats, opts)
3135 m = cmdutil.match(repo, pats, opts)
3135 m.bad = lambda x, y: False
3136 m.bad = lambda x, y: False
3136 for abs in repo.walk(m):
3137 for abs in repo.walk(m):
3137 names[abs] = m.rel(abs), m.exact(abs)
3138 names[abs] = m.rel(abs), m.exact(abs)
3138
3139
3139 # walk target manifest.
3140 # walk target manifest.
3140
3141
3141 def badfn(path, msg):
3142 def badfn(path, msg):
3142 if path in names:
3143 if path in names:
3143 return
3144 return
3144 path_ = path + '/'
3145 path_ = path + '/'
3145 for f in names:
3146 for f in names:
3146 if f.startswith(path_):
3147 if f.startswith(path_):
3147 return
3148 return
3148 ui.warn("%s: %s\n" % (m.rel(path), msg))
3149 ui.warn("%s: %s\n" % (m.rel(path), msg))
3149
3150
3150 m = cmdutil.match(repo, pats, opts)
3151 m = cmdutil.match(repo, pats, opts)
3151 m.bad = badfn
3152 m.bad = badfn
3152 for abs in repo[node].walk(m):
3153 for abs in repo[node].walk(m):
3153 if abs not in names:
3154 if abs not in names:
3154 names[abs] = m.rel(abs), m.exact(abs)
3155 names[abs] = m.rel(abs), m.exact(abs)
3155
3156
3156 m = cmdutil.matchfiles(repo, names)
3157 m = cmdutil.matchfiles(repo, names)
3157 changes = repo.status(match=m)[:4]
3158 changes = repo.status(match=m)[:4]
3158 modified, added, removed, deleted = map(set, changes)
3159 modified, added, removed, deleted = map(set, changes)
3159
3160
3160 # if f is a rename, also revert the source
3161 # if f is a rename, also revert the source
3161 cwd = repo.getcwd()
3162 cwd = repo.getcwd()
3162 for f in added:
3163 for f in added:
3163 src = repo.dirstate.copied(f)
3164 src = repo.dirstate.copied(f)
3164 if src and src not in names and repo.dirstate[src] == 'r':
3165 if src and src not in names and repo.dirstate[src] == 'r':
3165 removed.add(src)
3166 removed.add(src)
3166 names[src] = (repo.pathto(src, cwd), True)
3167 names[src] = (repo.pathto(src, cwd), True)
3167
3168
3168 def removeforget(abs):
3169 def removeforget(abs):
3169 if repo.dirstate[abs] == 'a':
3170 if repo.dirstate[abs] == 'a':
3170 return _('forgetting %s\n')
3171 return _('forgetting %s\n')
3171 return _('removing %s\n')
3172 return _('removing %s\n')
3172
3173
3173 revert = ([], _('reverting %s\n'))
3174 revert = ([], _('reverting %s\n'))
3174 add = ([], _('adding %s\n'))
3175 add = ([], _('adding %s\n'))
3175 remove = ([], removeforget)
3176 remove = ([], removeforget)
3176 undelete = ([], _('undeleting %s\n'))
3177 undelete = ([], _('undeleting %s\n'))
3177
3178
3178 disptable = (
3179 disptable = (
3179 # dispatch table:
3180 # dispatch table:
3180 # file state
3181 # file state
3181 # action if in target manifest
3182 # action if in target manifest
3182 # action if not in target manifest
3183 # action if not in target manifest
3183 # make backup if in target manifest
3184 # make backup if in target manifest
3184 # make backup if not in target manifest
3185 # make backup if not in target manifest
3185 (modified, revert, remove, True, True),
3186 (modified, revert, remove, True, True),
3186 (added, revert, remove, True, False),
3187 (added, revert, remove, True, False),
3187 (removed, undelete, None, False, False),
3188 (removed, undelete, None, False, False),
3188 (deleted, revert, remove, False, False),
3189 (deleted, revert, remove, False, False),
3189 )
3190 )
3190
3191
3191 for abs, (rel, exact) in sorted(names.items()):
3192 for abs, (rel, exact) in sorted(names.items()):
3192 mfentry = mf.get(abs)
3193 mfentry = mf.get(abs)
3193 target = repo.wjoin(abs)
3194 target = repo.wjoin(abs)
3194 def handle(xlist, dobackup):
3195 def handle(xlist, dobackup):
3195 xlist[0].append(abs)
3196 xlist[0].append(abs)
3196 if (dobackup and not opts.get('no_backup') and
3197 if (dobackup and not opts.get('no_backup') and
3197 os.path.lexists(target)):
3198 os.path.lexists(target)):
3198 bakname = "%s.orig" % rel
3199 bakname = "%s.orig" % rel
3199 ui.note(_('saving current version of %s as %s\n') %
3200 ui.note(_('saving current version of %s as %s\n') %
3200 (rel, bakname))
3201 (rel, bakname))
3201 if not opts.get('dry_run'):
3202 if not opts.get('dry_run'):
3202 util.rename(target, bakname)
3203 util.rename(target, bakname)
3203 if ui.verbose or not exact:
3204 if ui.verbose or not exact:
3204 msg = xlist[1]
3205 msg = xlist[1]
3205 if not isinstance(msg, basestring):
3206 if not isinstance(msg, basestring):
3206 msg = msg(abs)
3207 msg = msg(abs)
3207 ui.status(msg % rel)
3208 ui.status(msg % rel)
3208 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3209 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3209 if abs not in table:
3210 if abs not in table:
3210 continue
3211 continue
3211 # file has changed in dirstate
3212 # file has changed in dirstate
3212 if mfentry:
3213 if mfentry:
3213 handle(hitlist, backuphit)
3214 handle(hitlist, backuphit)
3214 elif misslist is not None:
3215 elif misslist is not None:
3215 handle(misslist, backupmiss)
3216 handle(misslist, backupmiss)
3216 break
3217 break
3217 else:
3218 else:
3218 if abs not in repo.dirstate:
3219 if abs not in repo.dirstate:
3219 if mfentry:
3220 if mfentry:
3220 handle(add, True)
3221 handle(add, True)
3221 elif exact:
3222 elif exact:
3222 ui.warn(_('file not managed: %s\n') % rel)
3223 ui.warn(_('file not managed: %s\n') % rel)
3223 continue
3224 continue
3224 # file has not changed in dirstate
3225 # file has not changed in dirstate
3225 if node == parent:
3226 if node == parent:
3226 if exact:
3227 if exact:
3227 ui.warn(_('no changes needed to %s\n') % rel)
3228 ui.warn(_('no changes needed to %s\n') % rel)
3228 continue
3229 continue
3229 if pmf is None:
3230 if pmf is None:
3230 # only need parent manifest in this unlikely case,
3231 # only need parent manifest in this unlikely case,
3231 # so do not read by default
3232 # so do not read by default
3232 pmf = repo[parent].manifest()
3233 pmf = repo[parent].manifest()
3233 if abs in pmf:
3234 if abs in pmf:
3234 if mfentry:
3235 if mfentry:
3235 # if version of file is same in parent and target
3236 # if version of file is same in parent and target
3236 # manifests, do nothing
3237 # manifests, do nothing
3237 if (pmf[abs] != mfentry or
3238 if (pmf[abs] != mfentry or
3238 pmf.flags(abs) != mf.flags(abs)):
3239 pmf.flags(abs) != mf.flags(abs)):
3239 handle(revert, False)
3240 handle(revert, False)
3240 else:
3241 else:
3241 handle(remove, False)
3242 handle(remove, False)
3242
3243
3243 if not opts.get('dry_run'):
3244 if not opts.get('dry_run'):
3244 def checkout(f):
3245 def checkout(f):
3245 fc = ctx[f]
3246 fc = ctx[f]
3246 repo.wwrite(f, fc.data(), fc.flags())
3247 repo.wwrite(f, fc.data(), fc.flags())
3247
3248
3248 audit_path = util.path_auditor(repo.root)
3249 audit_path = util.path_auditor(repo.root)
3249 for f in remove[0]:
3250 for f in remove[0]:
3250 if repo.dirstate[f] == 'a':
3251 if repo.dirstate[f] == 'a':
3251 repo.dirstate.forget(f)
3252 repo.dirstate.forget(f)
3252 continue
3253 continue
3253 audit_path(f)
3254 audit_path(f)
3254 try:
3255 try:
3255 util.unlink(repo.wjoin(f))
3256 util.unlink(repo.wjoin(f))
3256 except OSError:
3257 except OSError:
3257 pass
3258 pass
3258 repo.dirstate.remove(f)
3259 repo.dirstate.remove(f)
3259
3260
3260 normal = None
3261 normal = None
3261 if node == parent:
3262 if node == parent:
3262 # We're reverting to our parent. If possible, we'd like status
3263 # We're reverting to our parent. If possible, we'd like status
3263 # to report the file as clean. We have to use normallookup for
3264 # to report the file as clean. We have to use normallookup for
3264 # merges to avoid losing information about merged/dirty files.
3265 # merges to avoid losing information about merged/dirty files.
3265 if p2 != nullid:
3266 if p2 != nullid:
3266 normal = repo.dirstate.normallookup
3267 normal = repo.dirstate.normallookup
3267 else:
3268 else:
3268 normal = repo.dirstate.normal
3269 normal = repo.dirstate.normal
3269 for f in revert[0]:
3270 for f in revert[0]:
3270 checkout(f)
3271 checkout(f)
3271 if normal:
3272 if normal:
3272 normal(f)
3273 normal(f)
3273
3274
3274 for f in add[0]:
3275 for f in add[0]:
3275 checkout(f)
3276 checkout(f)
3276 repo.dirstate.add(f)
3277 repo.dirstate.add(f)
3277
3278
3278 normal = repo.dirstate.normallookup
3279 normal = repo.dirstate.normallookup
3279 if node == parent and p2 == nullid:
3280 if node == parent and p2 == nullid:
3280 normal = repo.dirstate.normal
3281 normal = repo.dirstate.normal
3281 for f in undelete[0]:
3282 for f in undelete[0]:
3282 checkout(f)
3283 checkout(f)
3283 normal(f)
3284 normal(f)
3284
3285
3285 finally:
3286 finally:
3286 wlock.release()
3287 wlock.release()
3287
3288
3288 def rollback(ui, repo, **opts):
3289 def rollback(ui, repo, **opts):
3289 """roll back the last transaction (dangerous)
3290 """roll back the last transaction (dangerous)
3290
3291
3291 This command should be used with care. There is only one level of
3292 This command should be used with care. There is only one level of
3292 rollback, and there is no way to undo a rollback. It will also
3293 rollback, and there is no way to undo a rollback. It will also
3293 restore the dirstate at the time of the last transaction, losing
3294 restore the dirstate at the time of the last transaction, losing
3294 any dirstate changes since that time. This command does not alter
3295 any dirstate changes since that time. This command does not alter
3295 the working directory.
3296 the working directory.
3296
3297
3297 Transactions are used to encapsulate the effects of all commands
3298 Transactions are used to encapsulate the effects of all commands
3298 that create new changesets or propagate existing changesets into a
3299 that create new changesets or propagate existing changesets into a
3299 repository. For example, the following commands are transactional,
3300 repository. For example, the following commands are transactional,
3300 and their effects can be rolled back:
3301 and their effects can be rolled back:
3301
3302
3302 - commit
3303 - commit
3303 - import
3304 - import
3304 - pull
3305 - pull
3305 - push (with this repository as the destination)
3306 - push (with this repository as the destination)
3306 - unbundle
3307 - unbundle
3307
3308
3308 This command is not intended for use on public repositories. Once
3309 This command is not intended for use on public repositories. Once
3309 changes are visible for pull by other users, rolling a transaction
3310 changes are visible for pull by other users, rolling a transaction
3310 back locally is ineffective (someone else may already have pulled
3311 back locally is ineffective (someone else may already have pulled
3311 the changes). Furthermore, a race is possible with readers of the
3312 the changes). Furthermore, a race is possible with readers of the
3312 repository; for example an in-progress pull from the repository
3313 repository; for example an in-progress pull from the repository
3313 may fail if a rollback is performed.
3314 may fail if a rollback is performed.
3314
3315
3315 Returns 0 on success, 1 if no rollback data is available.
3316 Returns 0 on success, 1 if no rollback data is available.
3316 """
3317 """
3317 return repo.rollback(opts.get('dry_run'))
3318 return repo.rollback(opts.get('dry_run'))
3318
3319
3319 def root(ui, repo):
3320 def root(ui, repo):
3320 """print the root (top) of the current working directory
3321 """print the root (top) of the current working directory
3321
3322
3322 Print the root directory of the current repository.
3323 Print the root directory of the current repository.
3323
3324
3324 Returns 0 on success.
3325 Returns 0 on success.
3325 """
3326 """
3326 ui.write(repo.root + "\n")
3327 ui.write(repo.root + "\n")
3327
3328
3328 def serve(ui, repo, **opts):
3329 def serve(ui, repo, **opts):
3329 """start stand-alone webserver
3330 """start stand-alone webserver
3330
3331
3331 Start a local HTTP repository browser and pull server. You can use
3332 Start a local HTTP repository browser and pull server. You can use
3332 this for ad-hoc sharing and browing of repositories. It is
3333 this for ad-hoc sharing and browing of repositories. It is
3333 recommended to use a real web server to serve a repository for
3334 recommended to use a real web server to serve a repository for
3334 longer periods of time.
3335 longer periods of time.
3335
3336
3336 Please note that the server does not implement access control.
3337 Please note that the server does not implement access control.
3337 This means that, by default, anybody can read from the server and
3338 This means that, by default, anybody can read from the server and
3338 nobody can write to it by default. Set the ``web.allow_push``
3339 nobody can write to it by default. Set the ``web.allow_push``
3339 option to ``*`` to allow everybody to push to the server. You
3340 option to ``*`` to allow everybody to push to the server. You
3340 should use a real web server if you need to authenticate users.
3341 should use a real web server if you need to authenticate users.
3341
3342
3342 By default, the server logs accesses to stdout and errors to
3343 By default, the server logs accesses to stdout and errors to
3343 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3344 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3344 files.
3345 files.
3345
3346
3346 To have the server choose a free port number to listen on, specify
3347 To have the server choose a free port number to listen on, specify
3347 a port number of 0; in this case, the server will print the port
3348 a port number of 0; in this case, the server will print the port
3348 number it uses.
3349 number it uses.
3349
3350
3350 Returns 0 on success.
3351 Returns 0 on success.
3351 """
3352 """
3352
3353
3353 if opts["stdio"]:
3354 if opts["stdio"]:
3354 if repo is None:
3355 if repo is None:
3355 raise error.RepoError(_("There is no Mercurial repository here"
3356 raise error.RepoError(_("There is no Mercurial repository here"
3356 " (.hg not found)"))
3357 " (.hg not found)"))
3357 s = sshserver.sshserver(ui, repo)
3358 s = sshserver.sshserver(ui, repo)
3358 s.serve_forever()
3359 s.serve_forever()
3359
3360
3360 # this way we can check if something was given in the command-line
3361 # this way we can check if something was given in the command-line
3361 if opts.get('port'):
3362 if opts.get('port'):
3362 opts['port'] = util.getport(opts.get('port'))
3363 opts['port'] = util.getport(opts.get('port'))
3363
3364
3364 baseui = repo and repo.baseui or ui
3365 baseui = repo and repo.baseui or ui
3365 optlist = ("name templates style address port prefix ipv6"
3366 optlist = ("name templates style address port prefix ipv6"
3366 " accesslog errorlog certificate encoding")
3367 " accesslog errorlog certificate encoding")
3367 for o in optlist.split():
3368 for o in optlist.split():
3368 val = opts.get(o, '')
3369 val = opts.get(o, '')
3369 if val in (None, ''): # should check against default options instead
3370 if val in (None, ''): # should check against default options instead
3370 continue
3371 continue
3371 baseui.setconfig("web", o, val)
3372 baseui.setconfig("web", o, val)
3372 if repo and repo.ui != baseui:
3373 if repo and repo.ui != baseui:
3373 repo.ui.setconfig("web", o, val)
3374 repo.ui.setconfig("web", o, val)
3374
3375
3375 o = opts.get('web_conf') or opts.get('webdir_conf')
3376 o = opts.get('web_conf') or opts.get('webdir_conf')
3376 if not o:
3377 if not o:
3377 if not repo:
3378 if not repo:
3378 raise error.RepoError(_("There is no Mercurial repository"
3379 raise error.RepoError(_("There is no Mercurial repository"
3379 " here (.hg not found)"))
3380 " here (.hg not found)"))
3380 o = repo.root
3381 o = repo.root
3381
3382
3382 app = hgweb.hgweb(o, baseui=ui)
3383 app = hgweb.hgweb(o, baseui=ui)
3383
3384
3384 class service(object):
3385 class service(object):
3385 def init(self):
3386 def init(self):
3386 util.set_signal_handler()
3387 util.set_signal_handler()
3387 self.httpd = hgweb.server.create_server(ui, app)
3388 self.httpd = hgweb.server.create_server(ui, app)
3388
3389
3389 if opts['port'] and not ui.verbose:
3390 if opts['port'] and not ui.verbose:
3390 return
3391 return
3391
3392
3392 if self.httpd.prefix:
3393 if self.httpd.prefix:
3393 prefix = self.httpd.prefix.strip('/') + '/'
3394 prefix = self.httpd.prefix.strip('/') + '/'
3394 else:
3395 else:
3395 prefix = ''
3396 prefix = ''
3396
3397
3397 port = ':%d' % self.httpd.port
3398 port = ':%d' % self.httpd.port
3398 if port == ':80':
3399 if port == ':80':
3399 port = ''
3400 port = ''
3400
3401
3401 bindaddr = self.httpd.addr
3402 bindaddr = self.httpd.addr
3402 if bindaddr == '0.0.0.0':
3403 if bindaddr == '0.0.0.0':
3403 bindaddr = '*'
3404 bindaddr = '*'
3404 elif ':' in bindaddr: # IPv6
3405 elif ':' in bindaddr: # IPv6
3405 bindaddr = '[%s]' % bindaddr
3406 bindaddr = '[%s]' % bindaddr
3406
3407
3407 fqaddr = self.httpd.fqaddr
3408 fqaddr = self.httpd.fqaddr
3408 if ':' in fqaddr:
3409 if ':' in fqaddr:
3409 fqaddr = '[%s]' % fqaddr
3410 fqaddr = '[%s]' % fqaddr
3410 if opts['port']:
3411 if opts['port']:
3411 write = ui.status
3412 write = ui.status
3412 else:
3413 else:
3413 write = ui.write
3414 write = ui.write
3414 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3415 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3415 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3416 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3416
3417
3417 def run(self):
3418 def run(self):
3418 self.httpd.serve_forever()
3419 self.httpd.serve_forever()
3419
3420
3420 service = service()
3421 service = service()
3421
3422
3422 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3423 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3423
3424
3424 def status(ui, repo, *pats, **opts):
3425 def status(ui, repo, *pats, **opts):
3425 """show changed files in the working directory
3426 """show changed files in the working directory
3426
3427
3427 Show status of files in the repository. If names are given, only
3428 Show status of files in the repository. If names are given, only
3428 files that match are shown. Files that are clean or ignored or
3429 files that match are shown. Files that are clean or ignored or
3429 the source of a copy/move operation, are not listed unless
3430 the source of a copy/move operation, are not listed unless
3430 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3431 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3431 Unless options described with "show only ..." are given, the
3432 Unless options described with "show only ..." are given, the
3432 options -mardu are used.
3433 options -mardu are used.
3433
3434
3434 Option -q/--quiet hides untracked (unknown and ignored) files
3435 Option -q/--quiet hides untracked (unknown and ignored) files
3435 unless explicitly requested with -u/--unknown or -i/--ignored.
3436 unless explicitly requested with -u/--unknown or -i/--ignored.
3436
3437
3437 NOTE: status may appear to disagree with diff if permissions have
3438 NOTE: status may appear to disagree with diff if permissions have
3438 changed or a merge has occurred. The standard diff format does not
3439 changed or a merge has occurred. The standard diff format does not
3439 report permission changes and diff only reports changes relative
3440 report permission changes and diff only reports changes relative
3440 to one merge parent.
3441 to one merge parent.
3441
3442
3442 If one revision is given, it is used as the base revision.
3443 If one revision is given, it is used as the base revision.
3443 If two revisions are given, the differences between them are
3444 If two revisions are given, the differences between them are
3444 shown. The --change option can also be used as a shortcut to list
3445 shown. The --change option can also be used as a shortcut to list
3445 the changed files of a revision from its first parent.
3446 the changed files of a revision from its first parent.
3446
3447
3447 The codes used to show the status of files are::
3448 The codes used to show the status of files are::
3448
3449
3449 M = modified
3450 M = modified
3450 A = added
3451 A = added
3451 R = removed
3452 R = removed
3452 C = clean
3453 C = clean
3453 ! = missing (deleted by non-hg command, but still tracked)
3454 ! = missing (deleted by non-hg command, but still tracked)
3454 ? = not tracked
3455 ? = not tracked
3455 I = ignored
3456 I = ignored
3456 = origin of the previous file listed as A (added)
3457 = origin of the previous file listed as A (added)
3457
3458
3458 Returns 0 on success.
3459 Returns 0 on success.
3459 """
3460 """
3460
3461
3461 revs = opts.get('rev')
3462 revs = opts.get('rev')
3462 change = opts.get('change')
3463 change = opts.get('change')
3463
3464
3464 if revs and change:
3465 if revs and change:
3465 msg = _('cannot specify --rev and --change at the same time')
3466 msg = _('cannot specify --rev and --change at the same time')
3466 raise util.Abort(msg)
3467 raise util.Abort(msg)
3467 elif change:
3468 elif change:
3468 node2 = repo.lookup(change)
3469 node2 = repo.lookup(change)
3469 node1 = repo[node2].parents()[0].node()
3470 node1 = repo[node2].parents()[0].node()
3470 else:
3471 else:
3471 node1, node2 = cmdutil.revpair(repo, revs)
3472 node1, node2 = cmdutil.revpair(repo, revs)
3472
3473
3473 cwd = (pats and repo.getcwd()) or ''
3474 cwd = (pats and repo.getcwd()) or ''
3474 end = opts.get('print0') and '\0' or '\n'
3475 end = opts.get('print0') and '\0' or '\n'
3475 copy = {}
3476 copy = {}
3476 states = 'modified added removed deleted unknown ignored clean'.split()
3477 states = 'modified added removed deleted unknown ignored clean'.split()
3477 show = [k for k in states if opts.get(k)]
3478 show = [k for k in states if opts.get(k)]
3478 if opts.get('all'):
3479 if opts.get('all'):
3479 show += ui.quiet and (states[:4] + ['clean']) or states
3480 show += ui.quiet and (states[:4] + ['clean']) or states
3480 if not show:
3481 if not show:
3481 show = ui.quiet and states[:4] or states[:5]
3482 show = ui.quiet and states[:4] or states[:5]
3482
3483
3483 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3484 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3484 'ignored' in show, 'clean' in show, 'unknown' in show,
3485 'ignored' in show, 'clean' in show, 'unknown' in show,
3485 opts.get('subrepos'))
3486 opts.get('subrepos'))
3486 changestates = zip(states, 'MAR!?IC', stat)
3487 changestates = zip(states, 'MAR!?IC', stat)
3487
3488
3488 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3489 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3489 ctxn = repo[nullid]
3490 ctxn = repo[nullid]
3490 ctx1 = repo[node1]
3491 ctx1 = repo[node1]
3491 ctx2 = repo[node2]
3492 ctx2 = repo[node2]
3492 added = stat[1]
3493 added = stat[1]
3493 if node2 is None:
3494 if node2 is None:
3494 added = stat[0] + stat[1] # merged?
3495 added = stat[0] + stat[1] # merged?
3495
3496
3496 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3497 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3497 if k in added:
3498 if k in added:
3498 copy[k] = v
3499 copy[k] = v
3499 elif v in added:
3500 elif v in added:
3500 copy[v] = k
3501 copy[v] = k
3501
3502
3502 for state, char, files in changestates:
3503 for state, char, files in changestates:
3503 if state in show:
3504 if state in show:
3504 format = "%s %%s%s" % (char, end)
3505 format = "%s %%s%s" % (char, end)
3505 if opts.get('no_status'):
3506 if opts.get('no_status'):
3506 format = "%%s%s" % end
3507 format = "%%s%s" % end
3507
3508
3508 for f in files:
3509 for f in files:
3509 ui.write(format % repo.pathto(f, cwd),
3510 ui.write(format % repo.pathto(f, cwd),
3510 label='status.' + state)
3511 label='status.' + state)
3511 if f in copy:
3512 if f in copy:
3512 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3513 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3513 label='status.copied')
3514 label='status.copied')
3514
3515
3515 def summary(ui, repo, **opts):
3516 def summary(ui, repo, **opts):
3516 """summarize working directory state
3517 """summarize working directory state
3517
3518
3518 This generates a brief summary of the working directory state,
3519 This generates a brief summary of the working directory state,
3519 including parents, branch, commit status, and available updates.
3520 including parents, branch, commit status, and available updates.
3520
3521
3521 With the --remote option, this will check the default paths for
3522 With the --remote option, this will check the default paths for
3522 incoming and outgoing changes. This can be time-consuming.
3523 incoming and outgoing changes. This can be time-consuming.
3523
3524
3524 Returns 0 on success.
3525 Returns 0 on success.
3525 """
3526 """
3526
3527
3527 ctx = repo[None]
3528 ctx = repo[None]
3528 parents = ctx.parents()
3529 parents = ctx.parents()
3529 pnode = parents[0].node()
3530 pnode = parents[0].node()
3530
3531
3531 for p in parents:
3532 for p in parents:
3532 # label with log.changeset (instead of log.parent) since this
3533 # label with log.changeset (instead of log.parent) since this
3533 # shows a working directory parent *changeset*:
3534 # shows a working directory parent *changeset*:
3534 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3535 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3535 label='log.changeset')
3536 label='log.changeset')
3536 ui.write(' '.join(p.tags()), label='log.tag')
3537 ui.write(' '.join(p.tags()), label='log.tag')
3537 if p.rev() == -1:
3538 if p.rev() == -1:
3538 if not len(repo):
3539 if not len(repo):
3539 ui.write(_(' (empty repository)'))
3540 ui.write(_(' (empty repository)'))
3540 else:
3541 else:
3541 ui.write(_(' (no revision checked out)'))
3542 ui.write(_(' (no revision checked out)'))
3542 ui.write('\n')
3543 ui.write('\n')
3543 if p.description():
3544 if p.description():
3544 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3545 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3545 label='log.summary')
3546 label='log.summary')
3546
3547
3547 branch = ctx.branch()
3548 branch = ctx.branch()
3548 bheads = repo.branchheads(branch)
3549 bheads = repo.branchheads(branch)
3549 m = _('branch: %s\n') % branch
3550 m = _('branch: %s\n') % branch
3550 if branch != 'default':
3551 if branch != 'default':
3551 ui.write(m, label='log.branch')
3552 ui.write(m, label='log.branch')
3552 else:
3553 else:
3553 ui.status(m, label='log.branch')
3554 ui.status(m, label='log.branch')
3554
3555
3555 st = list(repo.status(unknown=True))[:6]
3556 st = list(repo.status(unknown=True))[:6]
3556
3557
3557 c = repo.dirstate.copies()
3558 c = repo.dirstate.copies()
3558 copied, renamed = [], []
3559 copied, renamed = [], []
3559 for d, s in c.iteritems():
3560 for d, s in c.iteritems():
3560 if s in st[2]:
3561 if s in st[2]:
3561 st[2].remove(s)
3562 st[2].remove(s)
3562 renamed.append(d)
3563 renamed.append(d)
3563 else:
3564 else:
3564 copied.append(d)
3565 copied.append(d)
3565 if d in st[1]:
3566 if d in st[1]:
3566 st[1].remove(d)
3567 st[1].remove(d)
3567 st.insert(3, renamed)
3568 st.insert(3, renamed)
3568 st.insert(4, copied)
3569 st.insert(4, copied)
3569
3570
3570 ms = mergemod.mergestate(repo)
3571 ms = mergemod.mergestate(repo)
3571 st.append([f for f in ms if ms[f] == 'u'])
3572 st.append([f for f in ms if ms[f] == 'u'])
3572
3573
3573 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3574 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3574 st.append(subs)
3575 st.append(subs)
3575
3576
3576 labels = [ui.label(_('%d modified'), 'status.modified'),
3577 labels = [ui.label(_('%d modified'), 'status.modified'),
3577 ui.label(_('%d added'), 'status.added'),
3578 ui.label(_('%d added'), 'status.added'),
3578 ui.label(_('%d removed'), 'status.removed'),
3579 ui.label(_('%d removed'), 'status.removed'),
3579 ui.label(_('%d renamed'), 'status.copied'),
3580 ui.label(_('%d renamed'), 'status.copied'),
3580 ui.label(_('%d copied'), 'status.copied'),
3581 ui.label(_('%d copied'), 'status.copied'),
3581 ui.label(_('%d deleted'), 'status.deleted'),
3582 ui.label(_('%d deleted'), 'status.deleted'),
3582 ui.label(_('%d unknown'), 'status.unknown'),
3583 ui.label(_('%d unknown'), 'status.unknown'),
3583 ui.label(_('%d ignored'), 'status.ignored'),
3584 ui.label(_('%d ignored'), 'status.ignored'),
3584 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3585 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3585 ui.label(_('%d subrepos'), 'status.modified')]
3586 ui.label(_('%d subrepos'), 'status.modified')]
3586 t = []
3587 t = []
3587 for s, l in zip(st, labels):
3588 for s, l in zip(st, labels):
3588 if s:
3589 if s:
3589 t.append(l % len(s))
3590 t.append(l % len(s))
3590
3591
3591 t = ', '.join(t)
3592 t = ', '.join(t)
3592 cleanworkdir = False
3593 cleanworkdir = False
3593
3594
3594 if len(parents) > 1:
3595 if len(parents) > 1:
3595 t += _(' (merge)')
3596 t += _(' (merge)')
3596 elif branch != parents[0].branch():
3597 elif branch != parents[0].branch():
3597 t += _(' (new branch)')
3598 t += _(' (new branch)')
3598 elif (parents[0].extra().get('close') and
3599 elif (parents[0].extra().get('close') and
3599 pnode in repo.branchheads(branch, closed=True)):
3600 pnode in repo.branchheads(branch, closed=True)):
3600 t += _(' (head closed)')
3601 t += _(' (head closed)')
3601 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3602 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3602 t += _(' (clean)')
3603 t += _(' (clean)')
3603 cleanworkdir = True
3604 cleanworkdir = True
3604 elif pnode not in bheads:
3605 elif pnode not in bheads:
3605 t += _(' (new branch head)')
3606 t += _(' (new branch head)')
3606
3607
3607 if cleanworkdir:
3608 if cleanworkdir:
3608 ui.status(_('commit: %s\n') % t.strip())
3609 ui.status(_('commit: %s\n') % t.strip())
3609 else:
3610 else:
3610 ui.write(_('commit: %s\n') % t.strip())
3611 ui.write(_('commit: %s\n') % t.strip())
3611
3612
3612 # all ancestors of branch heads - all ancestors of parent = new csets
3613 # all ancestors of branch heads - all ancestors of parent = new csets
3613 new = [0] * len(repo)
3614 new = [0] * len(repo)
3614 cl = repo.changelog
3615 cl = repo.changelog
3615 for a in [cl.rev(n) for n in bheads]:
3616 for a in [cl.rev(n) for n in bheads]:
3616 new[a] = 1
3617 new[a] = 1
3617 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3618 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3618 new[a] = 1
3619 new[a] = 1
3619 for a in [p.rev() for p in parents]:
3620 for a in [p.rev() for p in parents]:
3620 if a >= 0:
3621 if a >= 0:
3621 new[a] = 0
3622 new[a] = 0
3622 for a in cl.ancestors(*[p.rev() for p in parents]):
3623 for a in cl.ancestors(*[p.rev() for p in parents]):
3623 new[a] = 0
3624 new[a] = 0
3624 new = sum(new)
3625 new = sum(new)
3625
3626
3626 if new == 0:
3627 if new == 0:
3627 ui.status(_('update: (current)\n'))
3628 ui.status(_('update: (current)\n'))
3628 elif pnode not in bheads:
3629 elif pnode not in bheads:
3629 ui.write(_('update: %d new changesets (update)\n') % new)
3630 ui.write(_('update: %d new changesets (update)\n') % new)
3630 else:
3631 else:
3631 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3632 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3632 (new, len(bheads)))
3633 (new, len(bheads)))
3633
3634
3634 if opts.get('remote'):
3635 if opts.get('remote'):
3635 t = []
3636 t = []
3636 source, branches = hg.parseurl(ui.expandpath('default'))
3637 source, branches = hg.parseurl(ui.expandpath('default'))
3637 other = hg.repository(hg.remoteui(repo, {}), source)
3638 other = hg.repository(hg.remoteui(repo, {}), source)
3638 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3639 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3639 ui.debug('comparing with %s\n' % url.hidepassword(source))
3640 ui.debug('comparing with %s\n' % url.hidepassword(source))
3640 repo.ui.pushbuffer()
3641 repo.ui.pushbuffer()
3641 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3642 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3642 repo.ui.popbuffer()
3643 repo.ui.popbuffer()
3643 if incoming:
3644 if incoming:
3644 t.append(_('1 or more incoming'))
3645 t.append(_('1 or more incoming'))
3645
3646
3646 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3647 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3647 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3648 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3648 other = hg.repository(hg.remoteui(repo, {}), dest)
3649 other = hg.repository(hg.remoteui(repo, {}), dest)
3649 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3650 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3650 repo.ui.pushbuffer()
3651 repo.ui.pushbuffer()
3651 o = discovery.findoutgoing(repo, other)
3652 o = discovery.findoutgoing(repo, other)
3652 repo.ui.popbuffer()
3653 repo.ui.popbuffer()
3653 o = repo.changelog.nodesbetween(o, None)[0]
3654 o = repo.changelog.nodesbetween(o, None)[0]
3654 if o:
3655 if o:
3655 t.append(_('%d outgoing') % len(o))
3656 t.append(_('%d outgoing') % len(o))
3656
3657
3657 if t:
3658 if t:
3658 ui.write(_('remote: %s\n') % (', '.join(t)))
3659 ui.write(_('remote: %s\n') % (', '.join(t)))
3659 else:
3660 else:
3660 ui.status(_('remote: (synced)\n'))
3661 ui.status(_('remote: (synced)\n'))
3661
3662
3662 def tag(ui, repo, name1, *names, **opts):
3663 def tag(ui, repo, name1, *names, **opts):
3663 """add one or more tags for the current or given revision
3664 """add one or more tags for the current or given revision
3664
3665
3665 Name a particular revision using <name>.
3666 Name a particular revision using <name>.
3666
3667
3667 Tags are used to name particular revisions of the repository and are
3668 Tags are used to name particular revisions of the repository and are
3668 very useful to compare different revisions, to go back to significant
3669 very useful to compare different revisions, to go back to significant
3669 earlier versions or to mark branch points as releases, etc.
3670 earlier versions or to mark branch points as releases, etc.
3670
3671
3671 If no revision is given, the parent of the working directory is
3672 If no revision is given, the parent of the working directory is
3672 used, or tip if no revision is checked out.
3673 used, or tip if no revision is checked out.
3673
3674
3674 To facilitate version control, distribution, and merging of tags,
3675 To facilitate version control, distribution, and merging of tags,
3675 they are stored as a file named ".hgtags" which is managed
3676 they are stored as a file named ".hgtags" which is managed
3676 similarly to other project files and can be hand-edited if
3677 similarly to other project files and can be hand-edited if
3677 necessary. The file '.hg/localtags' is used for local tags (not
3678 necessary. The file '.hg/localtags' is used for local tags (not
3678 shared among repositories).
3679 shared among repositories).
3679
3680
3680 See :hg:`help dates` for a list of formats valid for -d/--date.
3681 See :hg:`help dates` for a list of formats valid for -d/--date.
3681
3682
3682 Since tag names have priority over branch names during revision
3683 Since tag names have priority over branch names during revision
3683 lookup, using an existing branch name as a tag name is discouraged.
3684 lookup, using an existing branch name as a tag name is discouraged.
3684
3685
3685 Returns 0 on success.
3686 Returns 0 on success.
3686 """
3687 """
3687
3688
3688 rev_ = "."
3689 rev_ = "."
3689 names = [t.strip() for t in (name1,) + names]
3690 names = [t.strip() for t in (name1,) + names]
3690 if len(names) != len(set(names)):
3691 if len(names) != len(set(names)):
3691 raise util.Abort(_('tag names must be unique'))
3692 raise util.Abort(_('tag names must be unique'))
3692 for n in names:
3693 for n in names:
3693 if n in ['tip', '.', 'null']:
3694 if n in ['tip', '.', 'null']:
3694 raise util.Abort(_('the name \'%s\' is reserved') % n)
3695 raise util.Abort(_('the name \'%s\' is reserved') % n)
3695 if not n:
3696 if not n:
3696 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3697 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3697 if opts.get('rev') and opts.get('remove'):
3698 if opts.get('rev') and opts.get('remove'):
3698 raise util.Abort(_("--rev and --remove are incompatible"))
3699 raise util.Abort(_("--rev and --remove are incompatible"))
3699 if opts.get('rev'):
3700 if opts.get('rev'):
3700 rev_ = opts['rev']
3701 rev_ = opts['rev']
3701 message = opts.get('message')
3702 message = opts.get('message')
3702 if opts.get('remove'):
3703 if opts.get('remove'):
3703 expectedtype = opts.get('local') and 'local' or 'global'
3704 expectedtype = opts.get('local') and 'local' or 'global'
3704 for n in names:
3705 for n in names:
3705 if not repo.tagtype(n):
3706 if not repo.tagtype(n):
3706 raise util.Abort(_('tag \'%s\' does not exist') % n)
3707 raise util.Abort(_('tag \'%s\' does not exist') % n)
3707 if repo.tagtype(n) != expectedtype:
3708 if repo.tagtype(n) != expectedtype:
3708 if expectedtype == 'global':
3709 if expectedtype == 'global':
3709 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3710 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3710 else:
3711 else:
3711 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3712 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3712 rev_ = nullid
3713 rev_ = nullid
3713 if not message:
3714 if not message:
3714 # we don't translate commit messages
3715 # we don't translate commit messages
3715 message = 'Removed tag %s' % ', '.join(names)
3716 message = 'Removed tag %s' % ', '.join(names)
3716 elif not opts.get('force'):
3717 elif not opts.get('force'):
3717 for n in names:
3718 for n in names:
3718 if n in repo.tags():
3719 if n in repo.tags():
3719 raise util.Abort(_('tag \'%s\' already exists '
3720 raise util.Abort(_('tag \'%s\' already exists '
3720 '(use -f to force)') % n)
3721 '(use -f to force)') % n)
3721 if not rev_ and repo.dirstate.parents()[1] != nullid:
3722 if not rev_ and repo.dirstate.parents()[1] != nullid:
3722 raise util.Abort(_('uncommitted merge - please provide a '
3723 raise util.Abort(_('uncommitted merge - please provide a '
3723 'specific revision'))
3724 'specific revision'))
3724 r = repo[rev_].node()
3725 r = repo[rev_].node()
3725
3726
3726 if not message:
3727 if not message:
3727 # we don't translate commit messages
3728 # we don't translate commit messages
3728 message = ('Added tag %s for changeset %s' %
3729 message = ('Added tag %s for changeset %s' %
3729 (', '.join(names), short(r)))
3730 (', '.join(names), short(r)))
3730
3731
3731 date = opts.get('date')
3732 date = opts.get('date')
3732 if date:
3733 if date:
3733 date = util.parsedate(date)
3734 date = util.parsedate(date)
3734
3735
3735 if opts.get('edit'):
3736 if opts.get('edit'):
3736 message = ui.edit(message, ui.username())
3737 message = ui.edit(message, ui.username())
3737
3738
3738 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3739 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3739
3740
3740 def tags(ui, repo):
3741 def tags(ui, repo):
3741 """list repository tags
3742 """list repository tags
3742
3743
3743 This lists both regular and local tags. When the -v/--verbose
3744 This lists both regular and local tags. When the -v/--verbose
3744 switch is used, a third column "local" is printed for local tags.
3745 switch is used, a third column "local" is printed for local tags.
3745
3746
3746 Returns 0 on success.
3747 Returns 0 on success.
3747 """
3748 """
3748
3749
3749 hexfunc = ui.debugflag and hex or short
3750 hexfunc = ui.debugflag and hex or short
3750 tagtype = ""
3751 tagtype = ""
3751
3752
3752 for t, n in reversed(repo.tagslist()):
3753 for t, n in reversed(repo.tagslist()):
3753 if ui.quiet:
3754 if ui.quiet:
3754 ui.write("%s\n" % t)
3755 ui.write("%s\n" % t)
3755 continue
3756 continue
3756
3757
3757 try:
3758 try:
3758 hn = hexfunc(n)
3759 hn = hexfunc(n)
3759 r = "%5d:%s" % (repo.changelog.rev(n), hn)
3760 r = "%5d:%s" % (repo.changelog.rev(n), hn)
3760 except error.LookupError:
3761 except error.LookupError:
3761 r = " ?:%s" % hn
3762 r = " ?:%s" % hn
3762 else:
3763 else:
3763 spaces = " " * (30 - encoding.colwidth(t))
3764 spaces = " " * (30 - encoding.colwidth(t))
3764 if ui.verbose:
3765 if ui.verbose:
3765 if repo.tagtype(t) == 'local':
3766 if repo.tagtype(t) == 'local':
3766 tagtype = " local"
3767 tagtype = " local"
3767 else:
3768 else:
3768 tagtype = ""
3769 tagtype = ""
3769 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
3770 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
3770
3771
3771 def tip(ui, repo, **opts):
3772 def tip(ui, repo, **opts):
3772 """show the tip revision
3773 """show the tip revision
3773
3774
3774 The tip revision (usually just called the tip) is the changeset
3775 The tip revision (usually just called the tip) is the changeset
3775 most recently added to the repository (and therefore the most
3776 most recently added to the repository (and therefore the most
3776 recently changed head).
3777 recently changed head).
3777
3778
3778 If you have just made a commit, that commit will be the tip. If
3779 If you have just made a commit, that commit will be the tip. If
3779 you have just pulled changes from another repository, the tip of
3780 you have just pulled changes from another repository, the tip of
3780 that repository becomes the current tip. The "tip" tag is special
3781 that repository becomes the current tip. The "tip" tag is special
3781 and cannot be renamed or assigned to a different changeset.
3782 and cannot be renamed or assigned to a different changeset.
3782
3783
3783 Returns 0 on success.
3784 Returns 0 on success.
3784 """
3785 """
3785 displayer = cmdutil.show_changeset(ui, repo, opts)
3786 displayer = cmdutil.show_changeset(ui, repo, opts)
3786 displayer.show(repo[len(repo) - 1])
3787 displayer.show(repo[len(repo) - 1])
3787 displayer.close()
3788 displayer.close()
3788
3789
3789 def unbundle(ui, repo, fname1, *fnames, **opts):
3790 def unbundle(ui, repo, fname1, *fnames, **opts):
3790 """apply one or more changegroup files
3791 """apply one or more changegroup files
3791
3792
3792 Apply one or more compressed changegroup files generated by the
3793 Apply one or more compressed changegroup files generated by the
3793 bundle command.
3794 bundle command.
3794
3795
3795 Returns 0 on success, 1 if an update has unresolved files.
3796 Returns 0 on success, 1 if an update has unresolved files.
3796 """
3797 """
3797 fnames = (fname1,) + fnames
3798 fnames = (fname1,) + fnames
3798
3799
3799 lock = repo.lock()
3800 lock = repo.lock()
3800 try:
3801 try:
3801 for fname in fnames:
3802 for fname in fnames:
3802 f = url.open(ui, fname)
3803 f = url.open(ui, fname)
3803 gen = changegroup.readbundle(f, fname)
3804 gen = changegroup.readbundle(f, fname)
3804 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
3805 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
3805 lock=lock)
3806 lock=lock)
3806 finally:
3807 finally:
3807 lock.release()
3808 lock.release()
3808
3809
3809 return postincoming(ui, repo, modheads, opts.get('update'), None)
3810 return postincoming(ui, repo, modheads, opts.get('update'), None)
3810
3811
3811 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
3812 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
3812 """update working directory (or switch revisions)
3813 """update working directory (or switch revisions)
3813
3814
3814 Update the repository's working directory to the specified
3815 Update the repository's working directory to the specified
3815 changeset.
3816 changeset.
3816
3817
3817 If no changeset is specified, attempt to update to the tip of the
3818 If no changeset is specified, attempt to update to the tip of the
3818 current branch. If this changeset is a descendant of the working
3819 current branch. If this changeset is a descendant of the working
3819 directory's parent, update to it, otherwise abort.
3820 directory's parent, update to it, otherwise abort.
3820
3821
3821 The following rules apply when the working directory contains
3822 The following rules apply when the working directory contains
3822 uncommitted changes:
3823 uncommitted changes:
3823
3824
3824 1. If neither -c/--check nor -C/--clean is specified, and if
3825 1. If neither -c/--check nor -C/--clean is specified, and if
3825 the requested changeset is an ancestor or descendant of
3826 the requested changeset is an ancestor or descendant of
3826 the working directory's parent, the uncommitted changes
3827 the working directory's parent, the uncommitted changes
3827 are merged into the requested changeset and the merged
3828 are merged into the requested changeset and the merged
3828 result is left uncommitted. If the requested changeset is
3829 result is left uncommitted. If the requested changeset is
3829 not an ancestor or descendant (that is, it is on another
3830 not an ancestor or descendant (that is, it is on another
3830 branch), the update is aborted and the uncommitted changes
3831 branch), the update is aborted and the uncommitted changes
3831 are preserved.
3832 are preserved.
3832
3833
3833 2. With the -c/--check option, the update is aborted and the
3834 2. With the -c/--check option, the update is aborted and the
3834 uncommitted changes are preserved.
3835 uncommitted changes are preserved.
3835
3836
3836 3. With the -C/--clean option, uncommitted changes are discarded and
3837 3. With the -C/--clean option, uncommitted changes are discarded and
3837 the working directory is updated to the requested changeset.
3838 the working directory is updated to the requested changeset.
3838
3839
3839 Use null as the changeset to remove the working directory (like
3840 Use null as the changeset to remove the working directory (like
3840 :hg:`clone -U`).
3841 :hg:`clone -U`).
3841
3842
3842 If you want to update just one file to an older changeset, use :hg:`revert`.
3843 If you want to update just one file to an older changeset, use :hg:`revert`.
3843
3844
3844 See :hg:`help dates` for a list of formats valid for -d/--date.
3845 See :hg:`help dates` for a list of formats valid for -d/--date.
3845
3846
3846 Returns 0 on success, 1 if there are unresolved files.
3847 Returns 0 on success, 1 if there are unresolved files.
3847 """
3848 """
3848 if rev and node:
3849 if rev and node:
3849 raise util.Abort(_("please specify just one revision"))
3850 raise util.Abort(_("please specify just one revision"))
3850
3851
3851 if not rev:
3852 if not rev:
3852 rev = node
3853 rev = node
3853
3854
3854 if check and clean:
3855 if check and clean:
3855 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
3856 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
3856
3857
3857 if check:
3858 if check:
3858 # we could use dirty() but we can ignore merge and branch trivia
3859 # we could use dirty() but we can ignore merge and branch trivia
3859 c = repo[None]
3860 c = repo[None]
3860 if c.modified() or c.added() or c.removed():
3861 if c.modified() or c.added() or c.removed():
3861 raise util.Abort(_("uncommitted local changes"))
3862 raise util.Abort(_("uncommitted local changes"))
3862
3863
3863 if date:
3864 if date:
3864 if rev:
3865 if rev:
3865 raise util.Abort(_("you can't specify a revision and a date"))
3866 raise util.Abort(_("you can't specify a revision and a date"))
3866 rev = cmdutil.finddate(ui, repo, date)
3867 rev = cmdutil.finddate(ui, repo, date)
3867
3868
3868 if clean or check:
3869 if clean or check:
3869 return hg.clean(repo, rev)
3870 return hg.clean(repo, rev)
3870 else:
3871 else:
3871 return hg.update(repo, rev)
3872 return hg.update(repo, rev)
3872
3873
3873 def verify(ui, repo):
3874 def verify(ui, repo):
3874 """verify the integrity of the repository
3875 """verify the integrity of the repository
3875
3876
3876 Verify the integrity of the current repository.
3877 Verify the integrity of the current repository.
3877
3878
3878 This will perform an extensive check of the repository's
3879 This will perform an extensive check of the repository's
3879 integrity, validating the hashes and checksums of each entry in
3880 integrity, validating the hashes and checksums of each entry in
3880 the changelog, manifest, and tracked files, as well as the
3881 the changelog, manifest, and tracked files, as well as the
3881 integrity of their crosslinks and indices.
3882 integrity of their crosslinks and indices.
3882
3883
3883 Returns 0 on success, 1 if errors are encountered.
3884 Returns 0 on success, 1 if errors are encountered.
3884 """
3885 """
3885 return hg.verify(repo)
3886 return hg.verify(repo)
3886
3887
3887 def version_(ui):
3888 def version_(ui):
3888 """output version and copyright information"""
3889 """output version and copyright information"""
3889 ui.write(_("Mercurial Distributed SCM (version %s)\n")
3890 ui.write(_("Mercurial Distributed SCM (version %s)\n")
3890 % util.version())
3891 % util.version())
3891 ui.status(_(
3892 ui.status(_(
3892 "\nCopyright (C) 2005-2010 Matt Mackall <mpm@selenic.com> and others\n"
3893 "\nCopyright (C) 2005-2010 Matt Mackall <mpm@selenic.com> and others\n"
3893 "This is free software; see the source for copying conditions. "
3894 "This is free software; see the source for copying conditions. "
3894 "There is NO\nwarranty; "
3895 "There is NO\nwarranty; "
3895 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
3896 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
3896 ))
3897 ))
3897
3898
3898 # Command options and aliases are listed here, alphabetically
3899 # Command options and aliases are listed here, alphabetically
3899
3900
3900 globalopts = [
3901 globalopts = [
3901 ('R', 'repository', '',
3902 ('R', 'repository', '',
3902 _('repository root directory or name of overlay bundle file'),
3903 _('repository root directory or name of overlay bundle file'),
3903 _('REPO')),
3904 _('REPO')),
3904 ('', 'cwd', '',
3905 ('', 'cwd', '',
3905 _('change working directory'), _('DIR')),
3906 _('change working directory'), _('DIR')),
3906 ('y', 'noninteractive', None,
3907 ('y', 'noninteractive', None,
3907 _('do not prompt, assume \'yes\' for any required answers')),
3908 _('do not prompt, assume \'yes\' for any required answers')),
3908 ('q', 'quiet', None, _('suppress output')),
3909 ('q', 'quiet', None, _('suppress output')),
3909 ('v', 'verbose', None, _('enable additional output')),
3910 ('v', 'verbose', None, _('enable additional output')),
3910 ('', 'config', [],
3911 ('', 'config', [],
3911 _('set/override config option (use \'section.name=value\')'),
3912 _('set/override config option (use \'section.name=value\')'),
3912 _('CONFIG')),
3913 _('CONFIG')),
3913 ('', 'debug', None, _('enable debugging output')),
3914 ('', 'debug', None, _('enable debugging output')),
3914 ('', 'debugger', None, _('start debugger')),
3915 ('', 'debugger', None, _('start debugger')),
3915 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
3916 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
3916 _('ENCODE')),
3917 _('ENCODE')),
3917 ('', 'encodingmode', encoding.encodingmode,
3918 ('', 'encodingmode', encoding.encodingmode,
3918 _('set the charset encoding mode'), _('MODE')),
3919 _('set the charset encoding mode'), _('MODE')),
3919 ('', 'traceback', None, _('always print a traceback on exception')),
3920 ('', 'traceback', None, _('always print a traceback on exception')),
3920 ('', 'time', None, _('time how long the command takes')),
3921 ('', 'time', None, _('time how long the command takes')),
3921 ('', 'profile', None, _('print command execution profile')),
3922 ('', 'profile', None, _('print command execution profile')),
3922 ('', 'version', None, _('output version information and exit')),
3923 ('', 'version', None, _('output version information and exit')),
3923 ('h', 'help', None, _('display help and exit')),
3924 ('h', 'help', None, _('display help and exit')),
3924 ]
3925 ]
3925
3926
3926 dryrunopts = [('n', 'dry-run', None,
3927 dryrunopts = [('n', 'dry-run', None,
3927 _('do not perform actions, just print output'))]
3928 _('do not perform actions, just print output'))]
3928
3929
3929 remoteopts = [
3930 remoteopts = [
3930 ('e', 'ssh', '',
3931 ('e', 'ssh', '',
3931 _('specify ssh command to use'), _('CMD')),
3932 _('specify ssh command to use'), _('CMD')),
3932 ('', 'remotecmd', '',
3933 ('', 'remotecmd', '',
3933 _('specify hg command to run on the remote side'), _('CMD')),
3934 _('specify hg command to run on the remote side'), _('CMD')),
3934 ]
3935 ]
3935
3936
3936 walkopts = [
3937 walkopts = [
3937 ('I', 'include', [],
3938 ('I', 'include', [],
3938 _('include names matching the given patterns'), _('PATTERN')),
3939 _('include names matching the given patterns'), _('PATTERN')),
3939 ('X', 'exclude', [],
3940 ('X', 'exclude', [],
3940 _('exclude names matching the given patterns'), _('PATTERN')),
3941 _('exclude names matching the given patterns'), _('PATTERN')),
3941 ]
3942 ]
3942
3943
3943 commitopts = [
3944 commitopts = [
3944 ('m', 'message', '',
3945 ('m', 'message', '',
3945 _('use text as commit message'), _('TEXT')),
3946 _('use text as commit message'), _('TEXT')),
3946 ('l', 'logfile', '',
3947 ('l', 'logfile', '',
3947 _('read commit message from file'), _('FILE')),
3948 _('read commit message from file'), _('FILE')),
3948 ]
3949 ]
3949
3950
3950 commitopts2 = [
3951 commitopts2 = [
3951 ('d', 'date', '',
3952 ('d', 'date', '',
3952 _('record datecode as commit date'), _('DATE')),
3953 _('record datecode as commit date'), _('DATE')),
3953 ('u', 'user', '',
3954 ('u', 'user', '',
3954 _('record the specified user as committer'), _('USER')),
3955 _('record the specified user as committer'), _('USER')),
3955 ]
3956 ]
3956
3957
3957 templateopts = [
3958 templateopts = [
3958 ('', 'style', '',
3959 ('', 'style', '',
3959 _('display using template map file'), _('STYLE')),
3960 _('display using template map file'), _('STYLE')),
3960 ('', 'template', '',
3961 ('', 'template', '',
3961 _('display with template'), _('TEMPLATE')),
3962 _('display with template'), _('TEMPLATE')),
3962 ]
3963 ]
3963
3964
3964 logopts = [
3965 logopts = [
3965 ('p', 'patch', None, _('show patch')),
3966 ('p', 'patch', None, _('show patch')),
3966 ('g', 'git', None, _('use git extended diff format')),
3967 ('g', 'git', None, _('use git extended diff format')),
3967 ('l', 'limit', '',
3968 ('l', 'limit', '',
3968 _('limit number of changes displayed'), _('NUM')),
3969 _('limit number of changes displayed'), _('NUM')),
3969 ('M', 'no-merges', None, _('do not show merges')),
3970 ('M', 'no-merges', None, _('do not show merges')),
3970 ('', 'stat', None, _('output diffstat-style summary of changes')),
3971 ('', 'stat', None, _('output diffstat-style summary of changes')),
3971 ] + templateopts
3972 ] + templateopts
3972
3973
3973 diffopts = [
3974 diffopts = [
3974 ('a', 'text', None, _('treat all files as text')),
3975 ('a', 'text', None, _('treat all files as text')),
3975 ('g', 'git', None, _('use git extended diff format')),
3976 ('g', 'git', None, _('use git extended diff format')),
3976 ('', 'nodates', None, _('omit dates from diff headers'))
3977 ('', 'nodates', None, _('omit dates from diff headers'))
3977 ]
3978 ]
3978
3979
3979 diffopts2 = [
3980 diffopts2 = [
3980 ('p', 'show-function', None, _('show which function each change is in')),
3981 ('p', 'show-function', None, _('show which function each change is in')),
3981 ('', 'reverse', None, _('produce a diff that undoes the changes')),
3982 ('', 'reverse', None, _('produce a diff that undoes the changes')),
3982 ('w', 'ignore-all-space', None,
3983 ('w', 'ignore-all-space', None,
3983 _('ignore white space when comparing lines')),
3984 _('ignore white space when comparing lines')),
3984 ('b', 'ignore-space-change', None,
3985 ('b', 'ignore-space-change', None,
3985 _('ignore changes in the amount of white space')),
3986 _('ignore changes in the amount of white space')),
3986 ('B', 'ignore-blank-lines', None,
3987 ('B', 'ignore-blank-lines', None,
3987 _('ignore changes whose lines are all blank')),
3988 _('ignore changes whose lines are all blank')),
3988 ('U', 'unified', '',
3989 ('U', 'unified', '',
3989 _('number of lines of context to show'), _('NUM')),
3990 _('number of lines of context to show'), _('NUM')),
3990 ('', 'stat', None, _('output diffstat-style summary of changes')),
3991 ('', 'stat', None, _('output diffstat-style summary of changes')),
3991 ]
3992 ]
3992
3993
3993 similarityopts = [
3994 similarityopts = [
3994 ('s', 'similarity', '',
3995 ('s', 'similarity', '',
3995 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
3996 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
3996 ]
3997 ]
3997
3998
3998 subrepoopts = [
3999 subrepoopts = [
3999 ('S', 'subrepos', None,
4000 ('S', 'subrepos', None,
4000 _('recurse into subrepositories'))
4001 _('recurse into subrepositories'))
4001 ]
4002 ]
4002
4003
4003 table = {
4004 table = {
4004 "^add": (add, walkopts + dryrunopts, _('[OPTION]... [FILE]...')),
4005 "^add": (add, walkopts + subrepoopts + dryrunopts,
4006 _('[OPTION]... [FILE]...')),
4005 "addremove":
4007 "addremove":
4006 (addremove, similarityopts + walkopts + dryrunopts,
4008 (addremove, similarityopts + walkopts + dryrunopts,
4007 _('[OPTION]... [FILE]...')),
4009 _('[OPTION]... [FILE]...')),
4008 "^annotate|blame":
4010 "^annotate|blame":
4009 (annotate,
4011 (annotate,
4010 [('r', 'rev', '',
4012 [('r', 'rev', '',
4011 _('annotate the specified revision'), _('REV')),
4013 _('annotate the specified revision'), _('REV')),
4012 ('', 'follow', None,
4014 ('', 'follow', None,
4013 _('follow copies/renames and list the filename (DEPRECATED)')),
4015 _('follow copies/renames and list the filename (DEPRECATED)')),
4014 ('', 'no-follow', None, _("don't follow copies and renames")),
4016 ('', 'no-follow', None, _("don't follow copies and renames")),
4015 ('a', 'text', None, _('treat all files as text')),
4017 ('a', 'text', None, _('treat all files as text')),
4016 ('u', 'user', None, _('list the author (long with -v)')),
4018 ('u', 'user', None, _('list the author (long with -v)')),
4017 ('f', 'file', None, _('list the filename')),
4019 ('f', 'file', None, _('list the filename')),
4018 ('d', 'date', None, _('list the date (short with -q)')),
4020 ('d', 'date', None, _('list the date (short with -q)')),
4019 ('n', 'number', None, _('list the revision number (default)')),
4021 ('n', 'number', None, _('list the revision number (default)')),
4020 ('c', 'changeset', None, _('list the changeset')),
4022 ('c', 'changeset', None, _('list the changeset')),
4021 ('l', 'line-number', None,
4023 ('l', 'line-number', None,
4022 _('show line number at the first appearance'))
4024 _('show line number at the first appearance'))
4023 ] + walkopts,
4025 ] + walkopts,
4024 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4026 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4025 "archive":
4027 "archive":
4026 (archive,
4028 (archive,
4027 [('', 'no-decode', None, _('do not pass files through decoders')),
4029 [('', 'no-decode', None, _('do not pass files through decoders')),
4028 ('p', 'prefix', '',
4030 ('p', 'prefix', '',
4029 _('directory prefix for files in archive'), _('PREFIX')),
4031 _('directory prefix for files in archive'), _('PREFIX')),
4030 ('r', 'rev', '',
4032 ('r', 'rev', '',
4031 _('revision to distribute'), _('REV')),
4033 _('revision to distribute'), _('REV')),
4032 ('t', 'type', '',
4034 ('t', 'type', '',
4033 _('type of distribution to create'), _('TYPE')),
4035 _('type of distribution to create'), _('TYPE')),
4034 ] + walkopts,
4036 ] + walkopts,
4035 _('[OPTION]... DEST')),
4037 _('[OPTION]... DEST')),
4036 "backout":
4038 "backout":
4037 (backout,
4039 (backout,
4038 [('', 'merge', None,
4040 [('', 'merge', None,
4039 _('merge with old dirstate parent after backout')),
4041 _('merge with old dirstate parent after backout')),
4040 ('', 'parent', '',
4042 ('', 'parent', '',
4041 _('parent to choose when backing out merge'), _('REV')),
4043 _('parent to choose when backing out merge'), _('REV')),
4042 ('r', 'rev', '',
4044 ('r', 'rev', '',
4043 _('revision to backout'), _('REV')),
4045 _('revision to backout'), _('REV')),
4044 ] + walkopts + commitopts + commitopts2,
4046 ] + walkopts + commitopts + commitopts2,
4045 _('[OPTION]... [-r] REV')),
4047 _('[OPTION]... [-r] REV')),
4046 "bisect":
4048 "bisect":
4047 (bisect,
4049 (bisect,
4048 [('r', 'reset', False, _('reset bisect state')),
4050 [('r', 'reset', False, _('reset bisect state')),
4049 ('g', 'good', False, _('mark changeset good')),
4051 ('g', 'good', False, _('mark changeset good')),
4050 ('b', 'bad', False, _('mark changeset bad')),
4052 ('b', 'bad', False, _('mark changeset bad')),
4051 ('s', 'skip', False, _('skip testing changeset')),
4053 ('s', 'skip', False, _('skip testing changeset')),
4052 ('c', 'command', '',
4054 ('c', 'command', '',
4053 _('use command to check changeset state'), _('CMD')),
4055 _('use command to check changeset state'), _('CMD')),
4054 ('U', 'noupdate', False, _('do not update to target'))],
4056 ('U', 'noupdate', False, _('do not update to target'))],
4055 _("[-gbsr] [-U] [-c CMD] [REV]")),
4057 _("[-gbsr] [-U] [-c CMD] [REV]")),
4056 "branch":
4058 "branch":
4057 (branch,
4059 (branch,
4058 [('f', 'force', None,
4060 [('f', 'force', None,
4059 _('set branch name even if it shadows an existing branch')),
4061 _('set branch name even if it shadows an existing branch')),
4060 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4062 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4061 _('[-fC] [NAME]')),
4063 _('[-fC] [NAME]')),
4062 "branches":
4064 "branches":
4063 (branches,
4065 (branches,
4064 [('a', 'active', False,
4066 [('a', 'active', False,
4065 _('show only branches that have unmerged heads')),
4067 _('show only branches that have unmerged heads')),
4066 ('c', 'closed', False,
4068 ('c', 'closed', False,
4067 _('show normal and closed branches'))],
4069 _('show normal and closed branches'))],
4068 _('[-ac]')),
4070 _('[-ac]')),
4069 "bundle":
4071 "bundle":
4070 (bundle,
4072 (bundle,
4071 [('f', 'force', None,
4073 [('f', 'force', None,
4072 _('run even when the destination is unrelated')),
4074 _('run even when the destination is unrelated')),
4073 ('r', 'rev', [],
4075 ('r', 'rev', [],
4074 _('a changeset intended to be added to the destination'),
4076 _('a changeset intended to be added to the destination'),
4075 _('REV')),
4077 _('REV')),
4076 ('b', 'branch', [],
4078 ('b', 'branch', [],
4077 _('a specific branch you would like to bundle'),
4079 _('a specific branch you would like to bundle'),
4078 _('BRANCH')),
4080 _('BRANCH')),
4079 ('', 'base', [],
4081 ('', 'base', [],
4080 _('a base changeset assumed to be available at the destination'),
4082 _('a base changeset assumed to be available at the destination'),
4081 _('REV')),
4083 _('REV')),
4082 ('a', 'all', None, _('bundle all changesets in the repository')),
4084 ('a', 'all', None, _('bundle all changesets in the repository')),
4083 ('t', 'type', 'bzip2',
4085 ('t', 'type', 'bzip2',
4084 _('bundle compression type to use'), _('TYPE')),
4086 _('bundle compression type to use'), _('TYPE')),
4085 ] + remoteopts,
4087 ] + remoteopts,
4086 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4088 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4087 "cat":
4089 "cat":
4088 (cat,
4090 (cat,
4089 [('o', 'output', '',
4091 [('o', 'output', '',
4090 _('print output to file with formatted name'), _('FORMAT')),
4092 _('print output to file with formatted name'), _('FORMAT')),
4091 ('r', 'rev', '',
4093 ('r', 'rev', '',
4092 _('print the given revision'), _('REV')),
4094 _('print the given revision'), _('REV')),
4093 ('', 'decode', None, _('apply any matching decode filter')),
4095 ('', 'decode', None, _('apply any matching decode filter')),
4094 ] + walkopts,
4096 ] + walkopts,
4095 _('[OPTION]... FILE...')),
4097 _('[OPTION]... FILE...')),
4096 "^clone":
4098 "^clone":
4097 (clone,
4099 (clone,
4098 [('U', 'noupdate', None,
4100 [('U', 'noupdate', None,
4099 _('the clone will include an empty working copy (only a repository)')),
4101 _('the clone will include an empty working copy (only a repository)')),
4100 ('u', 'updaterev', '',
4102 ('u', 'updaterev', '',
4101 _('revision, tag or branch to check out'), _('REV')),
4103 _('revision, tag or branch to check out'), _('REV')),
4102 ('r', 'rev', [],
4104 ('r', 'rev', [],
4103 _('include the specified changeset'), _('REV')),
4105 _('include the specified changeset'), _('REV')),
4104 ('b', 'branch', [],
4106 ('b', 'branch', [],
4105 _('clone only the specified branch'), _('BRANCH')),
4107 _('clone only the specified branch'), _('BRANCH')),
4106 ('', 'pull', None, _('use pull protocol to copy metadata')),
4108 ('', 'pull', None, _('use pull protocol to copy metadata')),
4107 ('', 'uncompressed', None,
4109 ('', 'uncompressed', None,
4108 _('use uncompressed transfer (fast over LAN)')),
4110 _('use uncompressed transfer (fast over LAN)')),
4109 ] + remoteopts,
4111 ] + remoteopts,
4110 _('[OPTION]... SOURCE [DEST]')),
4112 _('[OPTION]... SOURCE [DEST]')),
4111 "^commit|ci":
4113 "^commit|ci":
4112 (commit,
4114 (commit,
4113 [('A', 'addremove', None,
4115 [('A', 'addremove', None,
4114 _('mark new/missing files as added/removed before committing')),
4116 _('mark new/missing files as added/removed before committing')),
4115 ('', 'close-branch', None,
4117 ('', 'close-branch', None,
4116 _('mark a branch as closed, hiding it from the branch list')),
4118 _('mark a branch as closed, hiding it from the branch list')),
4117 ] + walkopts + commitopts + commitopts2,
4119 ] + walkopts + commitopts + commitopts2,
4118 _('[OPTION]... [FILE]...')),
4120 _('[OPTION]... [FILE]...')),
4119 "copy|cp":
4121 "copy|cp":
4120 (copy,
4122 (copy,
4121 [('A', 'after', None, _('record a copy that has already occurred')),
4123 [('A', 'after', None, _('record a copy that has already occurred')),
4122 ('f', 'force', None,
4124 ('f', 'force', None,
4123 _('forcibly copy over an existing managed file')),
4125 _('forcibly copy over an existing managed file')),
4124 ] + walkopts + dryrunopts,
4126 ] + walkopts + dryrunopts,
4125 _('[OPTION]... [SOURCE]... DEST')),
4127 _('[OPTION]... [SOURCE]... DEST')),
4126 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4128 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4127 "debugbuilddag":
4129 "debugbuilddag":
4128 (debugbuilddag,
4130 (debugbuilddag,
4129 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4131 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4130 ('a', 'appended-file', None, _('add single file all revs append to')),
4132 ('a', 'appended-file', None, _('add single file all revs append to')),
4131 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4133 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4132 ('n', 'new-file', None, _('add new file at each rev')),
4134 ('n', 'new-file', None, _('add new file at each rev')),
4133 ],
4135 ],
4134 _('[OPTION]... TEXT')),
4136 _('[OPTION]... TEXT')),
4135 "debugcheckstate": (debugcheckstate, [], ''),
4137 "debugcheckstate": (debugcheckstate, [], ''),
4136 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4138 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4137 "debugcomplete":
4139 "debugcomplete":
4138 (debugcomplete,
4140 (debugcomplete,
4139 [('o', 'options', None, _('show the command options'))],
4141 [('o', 'options', None, _('show the command options'))],
4140 _('[-o] CMD')),
4142 _('[-o] CMD')),
4141 "debugdag":
4143 "debugdag":
4142 (debugdag,
4144 (debugdag,
4143 [('t', 'tags', None, _('use tags as labels')),
4145 [('t', 'tags', None, _('use tags as labels')),
4144 ('b', 'branches', None, _('annotate with branch names')),
4146 ('b', 'branches', None, _('annotate with branch names')),
4145 ('', 'dots', None, _('use dots for runs')),
4147 ('', 'dots', None, _('use dots for runs')),
4146 ('s', 'spaces', None, _('separate elements by spaces')),
4148 ('s', 'spaces', None, _('separate elements by spaces')),
4147 ],
4149 ],
4148 _('[OPTION]... [FILE [REV]...]')),
4150 _('[OPTION]... [FILE [REV]...]')),
4149 "debugdate":
4151 "debugdate":
4150 (debugdate,
4152 (debugdate,
4151 [('e', 'extended', None, _('try extended date formats'))],
4153 [('e', 'extended', None, _('try extended date formats'))],
4152 _('[-e] DATE [RANGE]')),
4154 _('[-e] DATE [RANGE]')),
4153 "debugdata": (debugdata, [], _('FILE REV')),
4155 "debugdata": (debugdata, [], _('FILE REV')),
4154 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4156 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4155 "debugindex": (debugindex, [], _('FILE')),
4157 "debugindex": (debugindex, [], _('FILE')),
4156 "debugindexdot": (debugindexdot, [], _('FILE')),
4158 "debugindexdot": (debugindexdot, [], _('FILE')),
4157 "debuginstall": (debuginstall, [], ''),
4159 "debuginstall": (debuginstall, [], ''),
4158 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4160 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4159 "debugrebuildstate":
4161 "debugrebuildstate":
4160 (debugrebuildstate,
4162 (debugrebuildstate,
4161 [('r', 'rev', '',
4163 [('r', 'rev', '',
4162 _('revision to rebuild to'), _('REV'))],
4164 _('revision to rebuild to'), _('REV'))],
4163 _('[-r REV] [REV]')),
4165 _('[-r REV] [REV]')),
4164 "debugrename":
4166 "debugrename":
4165 (debugrename,
4167 (debugrename,
4166 [('r', 'rev', '',
4168 [('r', 'rev', '',
4167 _('revision to debug'), _('REV'))],
4169 _('revision to debug'), _('REV'))],
4168 _('[-r REV] FILE')),
4170 _('[-r REV] FILE')),
4169 "debugrevspec":
4171 "debugrevspec":
4170 (debugrevspec, [], ('REVSPEC')),
4172 (debugrevspec, [], ('REVSPEC')),
4171 "debugsetparents":
4173 "debugsetparents":
4172 (debugsetparents, [], _('REV1 [REV2]')),
4174 (debugsetparents, [], _('REV1 [REV2]')),
4173 "debugstate":
4175 "debugstate":
4174 (debugstate,
4176 (debugstate,
4175 [('', 'nodates', None, _('do not display the saved mtime'))],
4177 [('', 'nodates', None, _('do not display the saved mtime'))],
4176 _('[OPTION]...')),
4178 _('[OPTION]...')),
4177 "debugsub":
4179 "debugsub":
4178 (debugsub,
4180 (debugsub,
4179 [('r', 'rev', '',
4181 [('r', 'rev', '',
4180 _('revision to check'), _('REV'))],
4182 _('revision to check'), _('REV'))],
4181 _('[-r REV] [REV]')),
4183 _('[-r REV] [REV]')),
4182 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4184 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4183 "^diff":
4185 "^diff":
4184 (diff,
4186 (diff,
4185 [('r', 'rev', [],
4187 [('r', 'rev', [],
4186 _('revision'), _('REV')),
4188 _('revision'), _('REV')),
4187 ('c', 'change', '',
4189 ('c', 'change', '',
4188 _('change made by revision'), _('REV'))
4190 _('change made by revision'), _('REV'))
4189 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4191 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4190 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4192 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4191 "^export":
4193 "^export":
4192 (export,
4194 (export,
4193 [('o', 'output', '',
4195 [('o', 'output', '',
4194 _('print output to file with formatted name'), _('FORMAT')),
4196 _('print output to file with formatted name'), _('FORMAT')),
4195 ('', 'switch-parent', None, _('diff against the second parent')),
4197 ('', 'switch-parent', None, _('diff against the second parent')),
4196 ('r', 'rev', [],
4198 ('r', 'rev', [],
4197 _('revisions to export'), _('REV')),
4199 _('revisions to export'), _('REV')),
4198 ] + diffopts,
4200 ] + diffopts,
4199 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4201 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4200 "^forget":
4202 "^forget":
4201 (forget,
4203 (forget,
4202 [] + walkopts,
4204 [] + walkopts,
4203 _('[OPTION]... FILE...')),
4205 _('[OPTION]... FILE...')),
4204 "grep":
4206 "grep":
4205 (grep,
4207 (grep,
4206 [('0', 'print0', None, _('end fields with NUL')),
4208 [('0', 'print0', None, _('end fields with NUL')),
4207 ('', 'all', None, _('print all revisions that match')),
4209 ('', 'all', None, _('print all revisions that match')),
4208 ('f', 'follow', None,
4210 ('f', 'follow', None,
4209 _('follow changeset history,'
4211 _('follow changeset history,'
4210 ' or file history across copies and renames')),
4212 ' or file history across copies and renames')),
4211 ('i', 'ignore-case', None, _('ignore case when matching')),
4213 ('i', 'ignore-case', None, _('ignore case when matching')),
4212 ('l', 'files-with-matches', None,
4214 ('l', 'files-with-matches', None,
4213 _('print only filenames and revisions that match')),
4215 _('print only filenames and revisions that match')),
4214 ('n', 'line-number', None, _('print matching line numbers')),
4216 ('n', 'line-number', None, _('print matching line numbers')),
4215 ('r', 'rev', [],
4217 ('r', 'rev', [],
4216 _('only search files changed within revision range'), _('REV')),
4218 _('only search files changed within revision range'), _('REV')),
4217 ('u', 'user', None, _('list the author (long with -v)')),
4219 ('u', 'user', None, _('list the author (long with -v)')),
4218 ('d', 'date', None, _('list the date (short with -q)')),
4220 ('d', 'date', None, _('list the date (short with -q)')),
4219 ] + walkopts,
4221 ] + walkopts,
4220 _('[OPTION]... PATTERN [FILE]...')),
4222 _('[OPTION]... PATTERN [FILE]...')),
4221 "heads":
4223 "heads":
4222 (heads,
4224 (heads,
4223 [('r', 'rev', '',
4225 [('r', 'rev', '',
4224 _('show only heads which are descendants of REV'), _('REV')),
4226 _('show only heads which are descendants of REV'), _('REV')),
4225 ('t', 'topo', False, _('show topological heads only')),
4227 ('t', 'topo', False, _('show topological heads only')),
4226 ('a', 'active', False,
4228 ('a', 'active', False,
4227 _('show active branchheads only (DEPRECATED)')),
4229 _('show active branchheads only (DEPRECATED)')),
4228 ('c', 'closed', False,
4230 ('c', 'closed', False,
4229 _('show normal and closed branch heads')),
4231 _('show normal and closed branch heads')),
4230 ] + templateopts,
4232 ] + templateopts,
4231 _('[-ac] [-r REV] [REV]...')),
4233 _('[-ac] [-r REV] [REV]...')),
4232 "help": (help_, [], _('[TOPIC]')),
4234 "help": (help_, [], _('[TOPIC]')),
4233 "identify|id":
4235 "identify|id":
4234 (identify,
4236 (identify,
4235 [('r', 'rev', '',
4237 [('r', 'rev', '',
4236 _('identify the specified revision'), _('REV')),
4238 _('identify the specified revision'), _('REV')),
4237 ('n', 'num', None, _('show local revision number')),
4239 ('n', 'num', None, _('show local revision number')),
4238 ('i', 'id', None, _('show global revision id')),
4240 ('i', 'id', None, _('show global revision id')),
4239 ('b', 'branch', None, _('show branch')),
4241 ('b', 'branch', None, _('show branch')),
4240 ('t', 'tags', None, _('show tags'))],
4242 ('t', 'tags', None, _('show tags'))],
4241 _('[-nibt] [-r REV] [SOURCE]')),
4243 _('[-nibt] [-r REV] [SOURCE]')),
4242 "import|patch":
4244 "import|patch":
4243 (import_,
4245 (import_,
4244 [('p', 'strip', 1,
4246 [('p', 'strip', 1,
4245 _('directory strip option for patch. This has the same '
4247 _('directory strip option for patch. This has the same '
4246 'meaning as the corresponding patch option'),
4248 'meaning as the corresponding patch option'),
4247 _('NUM')),
4249 _('NUM')),
4248 ('b', 'base', '',
4250 ('b', 'base', '',
4249 _('base path'), _('PATH')),
4251 _('base path'), _('PATH')),
4250 ('f', 'force', None,
4252 ('f', 'force', None,
4251 _('skip check for outstanding uncommitted changes')),
4253 _('skip check for outstanding uncommitted changes')),
4252 ('', 'no-commit', None,
4254 ('', 'no-commit', None,
4253 _("don't commit, just update the working directory")),
4255 _("don't commit, just update the working directory")),
4254 ('', 'exact', None,
4256 ('', 'exact', None,
4255 _('apply patch to the nodes from which it was generated')),
4257 _('apply patch to the nodes from which it was generated')),
4256 ('', 'import-branch', None,
4258 ('', 'import-branch', None,
4257 _('use any branch information in patch (implied by --exact)'))] +
4259 _('use any branch information in patch (implied by --exact)'))] +
4258 commitopts + commitopts2 + similarityopts,
4260 commitopts + commitopts2 + similarityopts,
4259 _('[OPTION]... PATCH...')),
4261 _('[OPTION]... PATCH...')),
4260 "incoming|in":
4262 "incoming|in":
4261 (incoming,
4263 (incoming,
4262 [('f', 'force', None,
4264 [('f', 'force', None,
4263 _('run even if remote repository is unrelated')),
4265 _('run even if remote repository is unrelated')),
4264 ('n', 'newest-first', None, _('show newest record first')),
4266 ('n', 'newest-first', None, _('show newest record first')),
4265 ('', 'bundle', '',
4267 ('', 'bundle', '',
4266 _('file to store the bundles into'), _('FILE')),
4268 _('file to store the bundles into'), _('FILE')),
4267 ('r', 'rev', [],
4269 ('r', 'rev', [],
4268 _('a remote changeset intended to be added'), _('REV')),
4270 _('a remote changeset intended to be added'), _('REV')),
4269 ('b', 'branch', [],
4271 ('b', 'branch', [],
4270 _('a specific branch you would like to pull'), _('BRANCH')),
4272 _('a specific branch you would like to pull'), _('BRANCH')),
4271 ] + logopts + remoteopts,
4273 ] + logopts + remoteopts,
4272 _('[-p] [-n] [-M] [-f] [-r REV]...'
4274 _('[-p] [-n] [-M] [-f] [-r REV]...'
4273 ' [--bundle FILENAME] [SOURCE]')),
4275 ' [--bundle FILENAME] [SOURCE]')),
4274 "^init":
4276 "^init":
4275 (init,
4277 (init,
4276 remoteopts,
4278 remoteopts,
4277 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4279 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4278 "locate":
4280 "locate":
4279 (locate,
4281 (locate,
4280 [('r', 'rev', '',
4282 [('r', 'rev', '',
4281 _('search the repository as it is in REV'), _('REV')),
4283 _('search the repository as it is in REV'), _('REV')),
4282 ('0', 'print0', None,
4284 ('0', 'print0', None,
4283 _('end filenames with NUL, for use with xargs')),
4285 _('end filenames with NUL, for use with xargs')),
4284 ('f', 'fullpath', None,
4286 ('f', 'fullpath', None,
4285 _('print complete paths from the filesystem root')),
4287 _('print complete paths from the filesystem root')),
4286 ] + walkopts,
4288 ] + walkopts,
4287 _('[OPTION]... [PATTERN]...')),
4289 _('[OPTION]... [PATTERN]...')),
4288 "^log|history":
4290 "^log|history":
4289 (log,
4291 (log,
4290 [('f', 'follow', None,
4292 [('f', 'follow', None,
4291 _('follow changeset history,'
4293 _('follow changeset history,'
4292 ' or file history across copies and renames')),
4294 ' or file history across copies and renames')),
4293 ('', 'follow-first', None,
4295 ('', 'follow-first', None,
4294 _('only follow the first parent of merge changesets')),
4296 _('only follow the first parent of merge changesets')),
4295 ('d', 'date', '',
4297 ('d', 'date', '',
4296 _('show revisions matching date spec'), _('DATE')),
4298 _('show revisions matching date spec'), _('DATE')),
4297 ('C', 'copies', None, _('show copied files')),
4299 ('C', 'copies', None, _('show copied files')),
4298 ('k', 'keyword', [],
4300 ('k', 'keyword', [],
4299 _('do case-insensitive search for a given text'), _('TEXT')),
4301 _('do case-insensitive search for a given text'), _('TEXT')),
4300 ('r', 'rev', [],
4302 ('r', 'rev', [],
4301 _('show the specified revision or range'), _('REV')),
4303 _('show the specified revision or range'), _('REV')),
4302 ('', 'removed', None, _('include revisions where files were removed')),
4304 ('', 'removed', None, _('include revisions where files were removed')),
4303 ('m', 'only-merges', None, _('show only merges')),
4305 ('m', 'only-merges', None, _('show only merges')),
4304 ('u', 'user', [],
4306 ('u', 'user', [],
4305 _('revisions committed by user'), _('USER')),
4307 _('revisions committed by user'), _('USER')),
4306 ('', 'only-branch', [],
4308 ('', 'only-branch', [],
4307 _('show only changesets within the given named branch (DEPRECATED)'),
4309 _('show only changesets within the given named branch (DEPRECATED)'),
4308 _('BRANCH')),
4310 _('BRANCH')),
4309 ('b', 'branch', [],
4311 ('b', 'branch', [],
4310 _('show changesets within the given named branch'), _('BRANCH')),
4312 _('show changesets within the given named branch'), _('BRANCH')),
4311 ('P', 'prune', [],
4313 ('P', 'prune', [],
4312 _('do not display revision or any of its ancestors'), _('REV')),
4314 _('do not display revision or any of its ancestors'), _('REV')),
4313 ] + logopts + walkopts,
4315 ] + logopts + walkopts,
4314 _('[OPTION]... [FILE]')),
4316 _('[OPTION]... [FILE]')),
4315 "manifest":
4317 "manifest":
4316 (manifest,
4318 (manifest,
4317 [('r', 'rev', '',
4319 [('r', 'rev', '',
4318 _('revision to display'), _('REV'))],
4320 _('revision to display'), _('REV'))],
4319 _('[-r REV]')),
4321 _('[-r REV]')),
4320 "^merge":
4322 "^merge":
4321 (merge,
4323 (merge,
4322 [('f', 'force', None, _('force a merge with outstanding changes')),
4324 [('f', 'force', None, _('force a merge with outstanding changes')),
4323 ('r', 'rev', '',
4325 ('r', 'rev', '',
4324 _('revision to merge'), _('REV')),
4326 _('revision to merge'), _('REV')),
4325 ('P', 'preview', None,
4327 ('P', 'preview', None,
4326 _('review revisions to merge (no merge is performed)'))],
4328 _('review revisions to merge (no merge is performed)'))],
4327 _('[-P] [-f] [[-r] REV]')),
4329 _('[-P] [-f] [[-r] REV]')),
4328 "outgoing|out":
4330 "outgoing|out":
4329 (outgoing,
4331 (outgoing,
4330 [('f', 'force', None,
4332 [('f', 'force', None,
4331 _('run even when the destination is unrelated')),
4333 _('run even when the destination is unrelated')),
4332 ('r', 'rev', [],
4334 ('r', 'rev', [],
4333 _('a changeset intended to be included in the destination'),
4335 _('a changeset intended to be included in the destination'),
4334 _('REV')),
4336 _('REV')),
4335 ('n', 'newest-first', None, _('show newest record first')),
4337 ('n', 'newest-first', None, _('show newest record first')),
4336 ('b', 'branch', [],
4338 ('b', 'branch', [],
4337 _('a specific branch you would like to push'), _('BRANCH')),
4339 _('a specific branch you would like to push'), _('BRANCH')),
4338 ] + logopts + remoteopts,
4340 ] + logopts + remoteopts,
4339 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4341 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4340 "parents":
4342 "parents":
4341 (parents,
4343 (parents,
4342 [('r', 'rev', '',
4344 [('r', 'rev', '',
4343 _('show parents of the specified revision'), _('REV')),
4345 _('show parents of the specified revision'), _('REV')),
4344 ] + templateopts,
4346 ] + templateopts,
4345 _('[-r REV] [FILE]')),
4347 _('[-r REV] [FILE]')),
4346 "paths": (paths, [], _('[NAME]')),
4348 "paths": (paths, [], _('[NAME]')),
4347 "^pull":
4349 "^pull":
4348 (pull,
4350 (pull,
4349 [('u', 'update', None,
4351 [('u', 'update', None,
4350 _('update to new branch head if changesets were pulled')),
4352 _('update to new branch head if changesets were pulled')),
4351 ('f', 'force', None,
4353 ('f', 'force', None,
4352 _('run even when remote repository is unrelated')),
4354 _('run even when remote repository is unrelated')),
4353 ('r', 'rev', [],
4355 ('r', 'rev', [],
4354 _('a remote changeset intended to be added'), _('REV')),
4356 _('a remote changeset intended to be added'), _('REV')),
4355 ('b', 'branch', [],
4357 ('b', 'branch', [],
4356 _('a specific branch you would like to pull'), _('BRANCH')),
4358 _('a specific branch you would like to pull'), _('BRANCH')),
4357 ] + remoteopts,
4359 ] + remoteopts,
4358 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4360 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4359 "^push":
4361 "^push":
4360 (push,
4362 (push,
4361 [('f', 'force', None, _('force push')),
4363 [('f', 'force', None, _('force push')),
4362 ('r', 'rev', [],
4364 ('r', 'rev', [],
4363 _('a changeset intended to be included in the destination'),
4365 _('a changeset intended to be included in the destination'),
4364 _('REV')),
4366 _('REV')),
4365 ('b', 'branch', [],
4367 ('b', 'branch', [],
4366 _('a specific branch you would like to push'), _('BRANCH')),
4368 _('a specific branch you would like to push'), _('BRANCH')),
4367 ('', 'new-branch', False, _('allow pushing a new branch')),
4369 ('', 'new-branch', False, _('allow pushing a new branch')),
4368 ] + remoteopts,
4370 ] + remoteopts,
4369 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4371 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4370 "recover": (recover, []),
4372 "recover": (recover, []),
4371 "^remove|rm":
4373 "^remove|rm":
4372 (remove,
4374 (remove,
4373 [('A', 'after', None, _('record delete for missing files')),
4375 [('A', 'after', None, _('record delete for missing files')),
4374 ('f', 'force', None,
4376 ('f', 'force', None,
4375 _('remove (and delete) file even if added or modified')),
4377 _('remove (and delete) file even if added or modified')),
4376 ] + walkopts,
4378 ] + walkopts,
4377 _('[OPTION]... FILE...')),
4379 _('[OPTION]... FILE...')),
4378 "rename|mv":
4380 "rename|mv":
4379 (rename,
4381 (rename,
4380 [('A', 'after', None, _('record a rename that has already occurred')),
4382 [('A', 'after', None, _('record a rename that has already occurred')),
4381 ('f', 'force', None,
4383 ('f', 'force', None,
4382 _('forcibly copy over an existing managed file')),
4384 _('forcibly copy over an existing managed file')),
4383 ] + walkopts + dryrunopts,
4385 ] + walkopts + dryrunopts,
4384 _('[OPTION]... SOURCE... DEST')),
4386 _('[OPTION]... SOURCE... DEST')),
4385 "resolve":
4387 "resolve":
4386 (resolve,
4388 (resolve,
4387 [('a', 'all', None, _('select all unresolved files')),
4389 [('a', 'all', None, _('select all unresolved files')),
4388 ('l', 'list', None, _('list state of files needing merge')),
4390 ('l', 'list', None, _('list state of files needing merge')),
4389 ('m', 'mark', None, _('mark files as resolved')),
4391 ('m', 'mark', None, _('mark files as resolved')),
4390 ('u', 'unmark', None, _('mark files as unresolved')),
4392 ('u', 'unmark', None, _('mark files as unresolved')),
4391 ('n', 'no-status', None, _('hide status prefix'))]
4393 ('n', 'no-status', None, _('hide status prefix'))]
4392 + walkopts,
4394 + walkopts,
4393 _('[OPTION]... [FILE]...')),
4395 _('[OPTION]... [FILE]...')),
4394 "revert":
4396 "revert":
4395 (revert,
4397 (revert,
4396 [('a', 'all', None, _('revert all changes when no arguments given')),
4398 [('a', 'all', None, _('revert all changes when no arguments given')),
4397 ('d', 'date', '',
4399 ('d', 'date', '',
4398 _('tipmost revision matching date'), _('DATE')),
4400 _('tipmost revision matching date'), _('DATE')),
4399 ('r', 'rev', '',
4401 ('r', 'rev', '',
4400 _('revert to the specified revision'), _('REV')),
4402 _('revert to the specified revision'), _('REV')),
4401 ('', 'no-backup', None, _('do not save backup copies of files')),
4403 ('', 'no-backup', None, _('do not save backup copies of files')),
4402 ] + walkopts + dryrunopts,
4404 ] + walkopts + dryrunopts,
4403 _('[OPTION]... [-r REV] [NAME]...')),
4405 _('[OPTION]... [-r REV] [NAME]...')),
4404 "rollback": (rollback, dryrunopts),
4406 "rollback": (rollback, dryrunopts),
4405 "root": (root, []),
4407 "root": (root, []),
4406 "^serve":
4408 "^serve":
4407 (serve,
4409 (serve,
4408 [('A', 'accesslog', '',
4410 [('A', 'accesslog', '',
4409 _('name of access log file to write to'), _('FILE')),
4411 _('name of access log file to write to'), _('FILE')),
4410 ('d', 'daemon', None, _('run server in background')),
4412 ('d', 'daemon', None, _('run server in background')),
4411 ('', 'daemon-pipefds', '',
4413 ('', 'daemon-pipefds', '',
4412 _('used internally by daemon mode'), _('NUM')),
4414 _('used internally by daemon mode'), _('NUM')),
4413 ('E', 'errorlog', '',
4415 ('E', 'errorlog', '',
4414 _('name of error log file to write to'), _('FILE')),
4416 _('name of error log file to write to'), _('FILE')),
4415 # use string type, then we can check if something was passed
4417 # use string type, then we can check if something was passed
4416 ('p', 'port', '',
4418 ('p', 'port', '',
4417 _('port to listen on (default: 8000)'), _('PORT')),
4419 _('port to listen on (default: 8000)'), _('PORT')),
4418 ('a', 'address', '',
4420 ('a', 'address', '',
4419 _('address to listen on (default: all interfaces)'), _('ADDR')),
4421 _('address to listen on (default: all interfaces)'), _('ADDR')),
4420 ('', 'prefix', '',
4422 ('', 'prefix', '',
4421 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4423 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4422 ('n', 'name', '',
4424 ('n', 'name', '',
4423 _('name to show in web pages (default: working directory)'),
4425 _('name to show in web pages (default: working directory)'),
4424 _('NAME')),
4426 _('NAME')),
4425 ('', 'web-conf', '',
4427 ('', 'web-conf', '',
4426 _('name of the hgweb config file (serve more than one repository)'),
4428 _('name of the hgweb config file (serve more than one repository)'),
4427 _('FILE')),
4429 _('FILE')),
4428 ('', 'webdir-conf', '',
4430 ('', 'webdir-conf', '',
4429 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4431 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4430 ('', 'pid-file', '',
4432 ('', 'pid-file', '',
4431 _('name of file to write process ID to'), _('FILE')),
4433 _('name of file to write process ID to'), _('FILE')),
4432 ('', 'stdio', None, _('for remote clients')),
4434 ('', 'stdio', None, _('for remote clients')),
4433 ('t', 'templates', '',
4435 ('t', 'templates', '',
4434 _('web templates to use'), _('TEMPLATE')),
4436 _('web templates to use'), _('TEMPLATE')),
4435 ('', 'style', '',
4437 ('', 'style', '',
4436 _('template style to use'), _('STYLE')),
4438 _('template style to use'), _('STYLE')),
4437 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4439 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4438 ('', 'certificate', '',
4440 ('', 'certificate', '',
4439 _('SSL certificate file'), _('FILE'))],
4441 _('SSL certificate file'), _('FILE'))],
4440 _('[OPTION]...')),
4442 _('[OPTION]...')),
4441 "showconfig|debugconfig":
4443 "showconfig|debugconfig":
4442 (showconfig,
4444 (showconfig,
4443 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4445 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4444 _('[-u] [NAME]...')),
4446 _('[-u] [NAME]...')),
4445 "^summary|sum":
4447 "^summary|sum":
4446 (summary,
4448 (summary,
4447 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4449 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4448 "^status|st":
4450 "^status|st":
4449 (status,
4451 (status,
4450 [('A', 'all', None, _('show status of all files')),
4452 [('A', 'all', None, _('show status of all files')),
4451 ('m', 'modified', None, _('show only modified files')),
4453 ('m', 'modified', None, _('show only modified files')),
4452 ('a', 'added', None, _('show only added files')),
4454 ('a', 'added', None, _('show only added files')),
4453 ('r', 'removed', None, _('show only removed files')),
4455 ('r', 'removed', None, _('show only removed files')),
4454 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4456 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4455 ('c', 'clean', None, _('show only files without changes')),
4457 ('c', 'clean', None, _('show only files without changes')),
4456 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4458 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4457 ('i', 'ignored', None, _('show only ignored files')),
4459 ('i', 'ignored', None, _('show only ignored files')),
4458 ('n', 'no-status', None, _('hide status prefix')),
4460 ('n', 'no-status', None, _('hide status prefix')),
4459 ('C', 'copies', None, _('show source of copied files')),
4461 ('C', 'copies', None, _('show source of copied files')),
4460 ('0', 'print0', None,
4462 ('0', 'print0', None,
4461 _('end filenames with NUL, for use with xargs')),
4463 _('end filenames with NUL, for use with xargs')),
4462 ('', 'rev', [],
4464 ('', 'rev', [],
4463 _('show difference from revision'), _('REV')),
4465 _('show difference from revision'), _('REV')),
4464 ('', 'change', '',
4466 ('', 'change', '',
4465 _('list the changed files of a revision'), _('REV')),
4467 _('list the changed files of a revision'), _('REV')),
4466 ] + walkopts + subrepoopts,
4468 ] + walkopts + subrepoopts,
4467 _('[OPTION]... [FILE]...')),
4469 _('[OPTION]... [FILE]...')),
4468 "tag":
4470 "tag":
4469 (tag,
4471 (tag,
4470 [('f', 'force', None, _('replace existing tag')),
4472 [('f', 'force', None, _('replace existing tag')),
4471 ('l', 'local', None, _('make the tag local')),
4473 ('l', 'local', None, _('make the tag local')),
4472 ('r', 'rev', '',
4474 ('r', 'rev', '',
4473 _('revision to tag'), _('REV')),
4475 _('revision to tag'), _('REV')),
4474 ('', 'remove', None, _('remove a tag')),
4476 ('', 'remove', None, _('remove a tag')),
4475 # -l/--local is already there, commitopts cannot be used
4477 # -l/--local is already there, commitopts cannot be used
4476 ('e', 'edit', None, _('edit commit message')),
4478 ('e', 'edit', None, _('edit commit message')),
4477 ('m', 'message', '',
4479 ('m', 'message', '',
4478 _('use <text> as commit message'), _('TEXT')),
4480 _('use <text> as commit message'), _('TEXT')),
4479 ] + commitopts2,
4481 ] + commitopts2,
4480 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4482 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4481 "tags": (tags, [], ''),
4483 "tags": (tags, [], ''),
4482 "tip":
4484 "tip":
4483 (tip,
4485 (tip,
4484 [('p', 'patch', None, _('show patch')),
4486 [('p', 'patch', None, _('show patch')),
4485 ('g', 'git', None, _('use git extended diff format')),
4487 ('g', 'git', None, _('use git extended diff format')),
4486 ] + templateopts,
4488 ] + templateopts,
4487 _('[-p] [-g]')),
4489 _('[-p] [-g]')),
4488 "unbundle":
4490 "unbundle":
4489 (unbundle,
4491 (unbundle,
4490 [('u', 'update', None,
4492 [('u', 'update', None,
4491 _('update to new branch head if changesets were unbundled'))],
4493 _('update to new branch head if changesets were unbundled'))],
4492 _('[-u] FILE...')),
4494 _('[-u] FILE...')),
4493 "^update|up|checkout|co":
4495 "^update|up|checkout|co":
4494 (update,
4496 (update,
4495 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4497 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4496 ('c', 'check', None, _('check for uncommitted changes')),
4498 ('c', 'check', None, _('check for uncommitted changes')),
4497 ('d', 'date', '',
4499 ('d', 'date', '',
4498 _('tipmost revision matching date'), _('DATE')),
4500 _('tipmost revision matching date'), _('DATE')),
4499 ('r', 'rev', '',
4501 ('r', 'rev', '',
4500 _('revision'), _('REV'))],
4502 _('revision'), _('REV'))],
4501 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4503 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4502 "verify": (verify, []),
4504 "verify": (verify, []),
4503 "version": (version_, []),
4505 "version": (version_, []),
4504 }
4506 }
4505
4507
4506 norepo = ("clone init version help debugcommands debugcomplete"
4508 norepo = ("clone init version help debugcommands debugcomplete"
4507 " debugdate debuginstall debugfsinfo debugpushkey")
4509 " debugdate debuginstall debugfsinfo debugpushkey")
4508 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4510 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4509 " debugdata debugindex debugindexdot")
4511 " debugdata debugindex debugindexdot")
@@ -1,1088 +1,1089 b''
1 # context.py - changeset and file context objects for mercurial
1 # context.py - changeset and file context objects for mercurial
2 #
2 #
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 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 nullid, nullrev, short, hex
8 from node import nullid, nullrev, short, hex
9 from i18n import _
9 from i18n import _
10 import ancestor, bdiff, error, util, subrepo, patch
10 import ancestor, bdiff, error, util, subrepo, patch
11 import os, errno, stat
11 import os, errno, stat
12
12
13 propertycache = util.propertycache
13 propertycache = util.propertycache
14
14
15 class changectx(object):
15 class changectx(object):
16 """A changecontext object makes access to data related to a particular
16 """A changecontext object makes access to data related to a particular
17 changeset convenient."""
17 changeset convenient."""
18 def __init__(self, repo, changeid=''):
18 def __init__(self, repo, changeid=''):
19 """changeid is a revision number, node, or tag"""
19 """changeid is a revision number, node, or tag"""
20 if changeid == '':
20 if changeid == '':
21 changeid = '.'
21 changeid = '.'
22 self._repo = repo
22 self._repo = repo
23 if isinstance(changeid, (long, int)):
23 if isinstance(changeid, (long, int)):
24 self._rev = changeid
24 self._rev = changeid
25 self._node = self._repo.changelog.node(changeid)
25 self._node = self._repo.changelog.node(changeid)
26 else:
26 else:
27 self._node = self._repo.lookup(changeid)
27 self._node = self._repo.lookup(changeid)
28 self._rev = self._repo.changelog.rev(self._node)
28 self._rev = self._repo.changelog.rev(self._node)
29
29
30 def __str__(self):
30 def __str__(self):
31 return short(self.node())
31 return short(self.node())
32
32
33 def __int__(self):
33 def __int__(self):
34 return self.rev()
34 return self.rev()
35
35
36 def __repr__(self):
36 def __repr__(self):
37 return "<changectx %s>" % str(self)
37 return "<changectx %s>" % str(self)
38
38
39 def __hash__(self):
39 def __hash__(self):
40 try:
40 try:
41 return hash(self._rev)
41 return hash(self._rev)
42 except AttributeError:
42 except AttributeError:
43 return id(self)
43 return id(self)
44
44
45 def __eq__(self, other):
45 def __eq__(self, other):
46 try:
46 try:
47 return self._rev == other._rev
47 return self._rev == other._rev
48 except AttributeError:
48 except AttributeError:
49 return False
49 return False
50
50
51 def __ne__(self, other):
51 def __ne__(self, other):
52 return not (self == other)
52 return not (self == other)
53
53
54 def __nonzero__(self):
54 def __nonzero__(self):
55 return self._rev != nullrev
55 return self._rev != nullrev
56
56
57 @propertycache
57 @propertycache
58 def _changeset(self):
58 def _changeset(self):
59 return self._repo.changelog.read(self.node())
59 return self._repo.changelog.read(self.node())
60
60
61 @propertycache
61 @propertycache
62 def _manifest(self):
62 def _manifest(self):
63 return self._repo.manifest.read(self._changeset[0])
63 return self._repo.manifest.read(self._changeset[0])
64
64
65 @propertycache
65 @propertycache
66 def _manifestdelta(self):
66 def _manifestdelta(self):
67 return self._repo.manifest.readdelta(self._changeset[0])
67 return self._repo.manifest.readdelta(self._changeset[0])
68
68
69 @propertycache
69 @propertycache
70 def _parents(self):
70 def _parents(self):
71 p = self._repo.changelog.parentrevs(self._rev)
71 p = self._repo.changelog.parentrevs(self._rev)
72 if p[1] == nullrev:
72 if p[1] == nullrev:
73 p = p[:-1]
73 p = p[:-1]
74 return [changectx(self._repo, x) for x in p]
74 return [changectx(self._repo, x) for x in p]
75
75
76 @propertycache
76 @propertycache
77 def substate(self):
77 def substate(self):
78 return subrepo.state(self, self._repo.ui)
78 return subrepo.state(self, self._repo.ui)
79
79
80 def __contains__(self, key):
80 def __contains__(self, key):
81 return key in self._manifest
81 return key in self._manifest
82
82
83 def __getitem__(self, key):
83 def __getitem__(self, key):
84 return self.filectx(key)
84 return self.filectx(key)
85
85
86 def __iter__(self):
86 def __iter__(self):
87 for f in sorted(self._manifest):
87 for f in sorted(self._manifest):
88 yield f
88 yield f
89
89
90 def changeset(self):
90 def changeset(self):
91 return self._changeset
91 return self._changeset
92 def manifest(self):
92 def manifest(self):
93 return self._manifest
93 return self._manifest
94 def manifestnode(self):
94 def manifestnode(self):
95 return self._changeset[0]
95 return self._changeset[0]
96
96
97 def rev(self):
97 def rev(self):
98 return self._rev
98 return self._rev
99 def node(self):
99 def node(self):
100 return self._node
100 return self._node
101 def hex(self):
101 def hex(self):
102 return hex(self._node)
102 return hex(self._node)
103 def user(self):
103 def user(self):
104 return self._changeset[1]
104 return self._changeset[1]
105 def date(self):
105 def date(self):
106 return self._changeset[2]
106 return self._changeset[2]
107 def files(self):
107 def files(self):
108 return self._changeset[3]
108 return self._changeset[3]
109 def description(self):
109 def description(self):
110 return self._changeset[4]
110 return self._changeset[4]
111 def branch(self):
111 def branch(self):
112 return self._changeset[5].get("branch")
112 return self._changeset[5].get("branch")
113 def extra(self):
113 def extra(self):
114 return self._changeset[5]
114 return self._changeset[5]
115 def tags(self):
115 def tags(self):
116 return self._repo.nodetags(self._node)
116 return self._repo.nodetags(self._node)
117
117
118 def parents(self):
118 def parents(self):
119 """return contexts for each parent changeset"""
119 """return contexts for each parent changeset"""
120 return self._parents
120 return self._parents
121
121
122 def p1(self):
122 def p1(self):
123 return self._parents[0]
123 return self._parents[0]
124
124
125 def p2(self):
125 def p2(self):
126 if len(self._parents) == 2:
126 if len(self._parents) == 2:
127 return self._parents[1]
127 return self._parents[1]
128 return changectx(self._repo, -1)
128 return changectx(self._repo, -1)
129
129
130 def children(self):
130 def children(self):
131 """return contexts for each child changeset"""
131 """return contexts for each child changeset"""
132 c = self._repo.changelog.children(self._node)
132 c = self._repo.changelog.children(self._node)
133 return [changectx(self._repo, x) for x in c]
133 return [changectx(self._repo, x) for x in c]
134
134
135 def ancestors(self):
135 def ancestors(self):
136 for a in self._repo.changelog.ancestors(self._rev):
136 for a in self._repo.changelog.ancestors(self._rev):
137 yield changectx(self._repo, a)
137 yield changectx(self._repo, a)
138
138
139 def descendants(self):
139 def descendants(self):
140 for d in self._repo.changelog.descendants(self._rev):
140 for d in self._repo.changelog.descendants(self._rev):
141 yield changectx(self._repo, d)
141 yield changectx(self._repo, d)
142
142
143 def _fileinfo(self, path):
143 def _fileinfo(self, path):
144 if '_manifest' in self.__dict__:
144 if '_manifest' in self.__dict__:
145 try:
145 try:
146 return self._manifest[path], self._manifest.flags(path)
146 return self._manifest[path], self._manifest.flags(path)
147 except KeyError:
147 except KeyError:
148 raise error.LookupError(self._node, path,
148 raise error.LookupError(self._node, path,
149 _('not found in manifest'))
149 _('not found in manifest'))
150 if '_manifestdelta' in self.__dict__ or path in self.files():
150 if '_manifestdelta' in self.__dict__ or path in self.files():
151 if path in self._manifestdelta:
151 if path in self._manifestdelta:
152 return self._manifestdelta[path], self._manifestdelta.flags(path)
152 return self._manifestdelta[path], self._manifestdelta.flags(path)
153 node, flag = self._repo.manifest.find(self._changeset[0], path)
153 node, flag = self._repo.manifest.find(self._changeset[0], path)
154 if not node:
154 if not node:
155 raise error.LookupError(self._node, path,
155 raise error.LookupError(self._node, path,
156 _('not found in manifest'))
156 _('not found in manifest'))
157
157
158 return node, flag
158 return node, flag
159
159
160 def filenode(self, path):
160 def filenode(self, path):
161 return self._fileinfo(path)[0]
161 return self._fileinfo(path)[0]
162
162
163 def flags(self, path):
163 def flags(self, path):
164 try:
164 try:
165 return self._fileinfo(path)[1]
165 return self._fileinfo(path)[1]
166 except error.LookupError:
166 except error.LookupError:
167 return ''
167 return ''
168
168
169 def filectx(self, path, fileid=None, filelog=None):
169 def filectx(self, path, fileid=None, filelog=None):
170 """get a file context from this changeset"""
170 """get a file context from this changeset"""
171 if fileid is None:
171 if fileid is None:
172 fileid = self.filenode(path)
172 fileid = self.filenode(path)
173 return filectx(self._repo, path, fileid=fileid,
173 return filectx(self._repo, path, fileid=fileid,
174 changectx=self, filelog=filelog)
174 changectx=self, filelog=filelog)
175
175
176 def ancestor(self, c2):
176 def ancestor(self, c2):
177 """
177 """
178 return the ancestor context of self and c2
178 return the ancestor context of self and c2
179 """
179 """
180 # deal with workingctxs
180 # deal with workingctxs
181 n2 = c2._node
181 n2 = c2._node
182 if n2 == None:
182 if n2 == None:
183 n2 = c2._parents[0]._node
183 n2 = c2._parents[0]._node
184 n = self._repo.changelog.ancestor(self._node, n2)
184 n = self._repo.changelog.ancestor(self._node, n2)
185 return changectx(self._repo, n)
185 return changectx(self._repo, n)
186
186
187 def walk(self, match):
187 def walk(self, match):
188 fset = set(match.files())
188 fset = set(match.files())
189 # for dirstate.walk, files=['.'] means "walk the whole tree".
189 # for dirstate.walk, files=['.'] means "walk the whole tree".
190 # follow that here, too
190 # follow that here, too
191 fset.discard('.')
191 fset.discard('.')
192 for fn in self:
192 for fn in self:
193 for ffn in fset:
193 for ffn in fset:
194 # match if the file is the exact name or a directory
194 # match if the file is the exact name or a directory
195 if ffn == fn or fn.startswith("%s/" % ffn):
195 if ffn == fn or fn.startswith("%s/" % ffn):
196 fset.remove(ffn)
196 fset.remove(ffn)
197 break
197 break
198 if match(fn):
198 if match(fn):
199 yield fn
199 yield fn
200 for fn in sorted(fset):
200 for fn in sorted(fset):
201 if match.bad(fn, _('no such file in rev %s') % self) and match(fn):
201 if match.bad(fn, _('no such file in rev %s') % self) and match(fn):
202 yield fn
202 yield fn
203
203
204 def sub(self, path):
204 def sub(self, path):
205 return subrepo.subrepo(self, path)
205 return subrepo.subrepo(self, path)
206
206
207 def diff(self, ctx2=None, match=None, **opts):
207 def diff(self, ctx2=None, match=None, **opts):
208 """Returns a diff generator for the given contexts and matcher"""
208 """Returns a diff generator for the given contexts and matcher"""
209 if ctx2 is None:
209 if ctx2 is None:
210 ctx2 = self.p1()
210 ctx2 = self.p1()
211 if ctx2 is not None and not isinstance(ctx2, changectx):
211 if ctx2 is not None and not isinstance(ctx2, changectx):
212 ctx2 = self._repo[ctx2]
212 ctx2 = self._repo[ctx2]
213 diffopts = patch.diffopts(self._repo.ui, opts)
213 diffopts = patch.diffopts(self._repo.ui, opts)
214 return patch.diff(self._repo, ctx2.node(), self.node(),
214 return patch.diff(self._repo, ctx2.node(), self.node(),
215 match=match, opts=diffopts)
215 match=match, opts=diffopts)
216
216
217 class filectx(object):
217 class filectx(object):
218 """A filecontext object makes access to data related to a particular
218 """A filecontext object makes access to data related to a particular
219 filerevision convenient."""
219 filerevision convenient."""
220 def __init__(self, repo, path, changeid=None, fileid=None,
220 def __init__(self, repo, path, changeid=None, fileid=None,
221 filelog=None, changectx=None):
221 filelog=None, changectx=None):
222 """changeid can be a changeset revision, node, or tag.
222 """changeid can be a changeset revision, node, or tag.
223 fileid can be a file revision or node."""
223 fileid can be a file revision or node."""
224 self._repo = repo
224 self._repo = repo
225 self._path = path
225 self._path = path
226
226
227 assert (changeid is not None
227 assert (changeid is not None
228 or fileid is not None
228 or fileid is not None
229 or changectx is not None), \
229 or changectx is not None), \
230 ("bad args: changeid=%r, fileid=%r, changectx=%r"
230 ("bad args: changeid=%r, fileid=%r, changectx=%r"
231 % (changeid, fileid, changectx))
231 % (changeid, fileid, changectx))
232
232
233 if filelog:
233 if filelog:
234 self._filelog = filelog
234 self._filelog = filelog
235
235
236 if changeid is not None:
236 if changeid is not None:
237 self._changeid = changeid
237 self._changeid = changeid
238 if changectx is not None:
238 if changectx is not None:
239 self._changectx = changectx
239 self._changectx = changectx
240 if fileid is not None:
240 if fileid is not None:
241 self._fileid = fileid
241 self._fileid = fileid
242
242
243 @propertycache
243 @propertycache
244 def _changectx(self):
244 def _changectx(self):
245 return changectx(self._repo, self._changeid)
245 return changectx(self._repo, self._changeid)
246
246
247 @propertycache
247 @propertycache
248 def _filelog(self):
248 def _filelog(self):
249 return self._repo.file(self._path)
249 return self._repo.file(self._path)
250
250
251 @propertycache
251 @propertycache
252 def _changeid(self):
252 def _changeid(self):
253 if '_changectx' in self.__dict__:
253 if '_changectx' in self.__dict__:
254 return self._changectx.rev()
254 return self._changectx.rev()
255 else:
255 else:
256 return self._filelog.linkrev(self._filerev)
256 return self._filelog.linkrev(self._filerev)
257
257
258 @propertycache
258 @propertycache
259 def _filenode(self):
259 def _filenode(self):
260 if '_fileid' in self.__dict__:
260 if '_fileid' in self.__dict__:
261 return self._filelog.lookup(self._fileid)
261 return self._filelog.lookup(self._fileid)
262 else:
262 else:
263 return self._changectx.filenode(self._path)
263 return self._changectx.filenode(self._path)
264
264
265 @propertycache
265 @propertycache
266 def _filerev(self):
266 def _filerev(self):
267 return self._filelog.rev(self._filenode)
267 return self._filelog.rev(self._filenode)
268
268
269 @propertycache
269 @propertycache
270 def _repopath(self):
270 def _repopath(self):
271 return self._path
271 return self._path
272
272
273 def __nonzero__(self):
273 def __nonzero__(self):
274 try:
274 try:
275 self._filenode
275 self._filenode
276 return True
276 return True
277 except error.LookupError:
277 except error.LookupError:
278 # file is missing
278 # file is missing
279 return False
279 return False
280
280
281 def __str__(self):
281 def __str__(self):
282 return "%s@%s" % (self.path(), short(self.node()))
282 return "%s@%s" % (self.path(), short(self.node()))
283
283
284 def __repr__(self):
284 def __repr__(self):
285 return "<filectx %s>" % str(self)
285 return "<filectx %s>" % str(self)
286
286
287 def __hash__(self):
287 def __hash__(self):
288 try:
288 try:
289 return hash((self._path, self._filenode))
289 return hash((self._path, self._filenode))
290 except AttributeError:
290 except AttributeError:
291 return id(self)
291 return id(self)
292
292
293 def __eq__(self, other):
293 def __eq__(self, other):
294 try:
294 try:
295 return (self._path == other._path
295 return (self._path == other._path
296 and self._filenode == other._filenode)
296 and self._filenode == other._filenode)
297 except AttributeError:
297 except AttributeError:
298 return False
298 return False
299
299
300 def __ne__(self, other):
300 def __ne__(self, other):
301 return not (self == other)
301 return not (self == other)
302
302
303 def filectx(self, fileid):
303 def filectx(self, fileid):
304 '''opens an arbitrary revision of the file without
304 '''opens an arbitrary revision of the file without
305 opening a new filelog'''
305 opening a new filelog'''
306 return filectx(self._repo, self._path, fileid=fileid,
306 return filectx(self._repo, self._path, fileid=fileid,
307 filelog=self._filelog)
307 filelog=self._filelog)
308
308
309 def filerev(self):
309 def filerev(self):
310 return self._filerev
310 return self._filerev
311 def filenode(self):
311 def filenode(self):
312 return self._filenode
312 return self._filenode
313 def flags(self):
313 def flags(self):
314 return self._changectx.flags(self._path)
314 return self._changectx.flags(self._path)
315 def filelog(self):
315 def filelog(self):
316 return self._filelog
316 return self._filelog
317
317
318 def rev(self):
318 def rev(self):
319 if '_changectx' in self.__dict__:
319 if '_changectx' in self.__dict__:
320 return self._changectx.rev()
320 return self._changectx.rev()
321 if '_changeid' in self.__dict__:
321 if '_changeid' in self.__dict__:
322 return self._changectx.rev()
322 return self._changectx.rev()
323 return self._filelog.linkrev(self._filerev)
323 return self._filelog.linkrev(self._filerev)
324
324
325 def linkrev(self):
325 def linkrev(self):
326 return self._filelog.linkrev(self._filerev)
326 return self._filelog.linkrev(self._filerev)
327 def node(self):
327 def node(self):
328 return self._changectx.node()
328 return self._changectx.node()
329 def hex(self):
329 def hex(self):
330 return hex(self.node())
330 return hex(self.node())
331 def user(self):
331 def user(self):
332 return self._changectx.user()
332 return self._changectx.user()
333 def date(self):
333 def date(self):
334 return self._changectx.date()
334 return self._changectx.date()
335 def files(self):
335 def files(self):
336 return self._changectx.files()
336 return self._changectx.files()
337 def description(self):
337 def description(self):
338 return self._changectx.description()
338 return self._changectx.description()
339 def branch(self):
339 def branch(self):
340 return self._changectx.branch()
340 return self._changectx.branch()
341 def extra(self):
341 def extra(self):
342 return self._changectx.extra()
342 return self._changectx.extra()
343 def manifest(self):
343 def manifest(self):
344 return self._changectx.manifest()
344 return self._changectx.manifest()
345 def changectx(self):
345 def changectx(self):
346 return self._changectx
346 return self._changectx
347
347
348 def data(self):
348 def data(self):
349 return self._filelog.read(self._filenode)
349 return self._filelog.read(self._filenode)
350 def path(self):
350 def path(self):
351 return self._path
351 return self._path
352 def size(self):
352 def size(self):
353 return self._filelog.size(self._filerev)
353 return self._filelog.size(self._filerev)
354
354
355 def cmp(self, fctx):
355 def cmp(self, fctx):
356 """compare with other file context
356 """compare with other file context
357
357
358 returns True if different than fctx.
358 returns True if different than fctx.
359 """
359 """
360 return self._filelog.cmp(self._filenode, fctx.data())
360 return self._filelog.cmp(self._filenode, fctx.data())
361
361
362 def renamed(self):
362 def renamed(self):
363 """check if file was actually renamed in this changeset revision
363 """check if file was actually renamed in this changeset revision
364
364
365 If rename logged in file revision, we report copy for changeset only
365 If rename logged in file revision, we report copy for changeset only
366 if file revisions linkrev points back to the changeset in question
366 if file revisions linkrev points back to the changeset in question
367 or both changeset parents contain different file revisions.
367 or both changeset parents contain different file revisions.
368 """
368 """
369
369
370 renamed = self._filelog.renamed(self._filenode)
370 renamed = self._filelog.renamed(self._filenode)
371 if not renamed:
371 if not renamed:
372 return renamed
372 return renamed
373
373
374 if self.rev() == self.linkrev():
374 if self.rev() == self.linkrev():
375 return renamed
375 return renamed
376
376
377 name = self.path()
377 name = self.path()
378 fnode = self._filenode
378 fnode = self._filenode
379 for p in self._changectx.parents():
379 for p in self._changectx.parents():
380 try:
380 try:
381 if fnode == p.filenode(name):
381 if fnode == p.filenode(name):
382 return None
382 return None
383 except error.LookupError:
383 except error.LookupError:
384 pass
384 pass
385 return renamed
385 return renamed
386
386
387 def parents(self):
387 def parents(self):
388 p = self._path
388 p = self._path
389 fl = self._filelog
389 fl = self._filelog
390 pl = [(p, n, fl) for n in self._filelog.parents(self._filenode)]
390 pl = [(p, n, fl) for n in self._filelog.parents(self._filenode)]
391
391
392 r = self._filelog.renamed(self._filenode)
392 r = self._filelog.renamed(self._filenode)
393 if r:
393 if r:
394 pl[0] = (r[0], r[1], None)
394 pl[0] = (r[0], r[1], None)
395
395
396 return [filectx(self._repo, p, fileid=n, filelog=l)
396 return [filectx(self._repo, p, fileid=n, filelog=l)
397 for p, n, l in pl if n != nullid]
397 for p, n, l in pl if n != nullid]
398
398
399 def children(self):
399 def children(self):
400 # hard for renames
400 # hard for renames
401 c = self._filelog.children(self._filenode)
401 c = self._filelog.children(self._filenode)
402 return [filectx(self._repo, self._path, fileid=x,
402 return [filectx(self._repo, self._path, fileid=x,
403 filelog=self._filelog) for x in c]
403 filelog=self._filelog) for x in c]
404
404
405 def annotate(self, follow=False, linenumber=None):
405 def annotate(self, follow=False, linenumber=None):
406 '''returns a list of tuples of (ctx, line) for each line
406 '''returns a list of tuples of (ctx, line) for each line
407 in the file, where ctx is the filectx of the node where
407 in the file, where ctx is the filectx of the node where
408 that line was last changed.
408 that line was last changed.
409 This returns tuples of ((ctx, linenumber), line) for each line,
409 This returns tuples of ((ctx, linenumber), line) for each line,
410 if "linenumber" parameter is NOT "None".
410 if "linenumber" parameter is NOT "None".
411 In such tuples, linenumber means one at the first appearance
411 In such tuples, linenumber means one at the first appearance
412 in the managed file.
412 in the managed file.
413 To reduce annotation cost,
413 To reduce annotation cost,
414 this returns fixed value(False is used) as linenumber,
414 this returns fixed value(False is used) as linenumber,
415 if "linenumber" parameter is "False".'''
415 if "linenumber" parameter is "False".'''
416
416
417 def decorate_compat(text, rev):
417 def decorate_compat(text, rev):
418 return ([rev] * len(text.splitlines()), text)
418 return ([rev] * len(text.splitlines()), text)
419
419
420 def without_linenumber(text, rev):
420 def without_linenumber(text, rev):
421 return ([(rev, False)] * len(text.splitlines()), text)
421 return ([(rev, False)] * len(text.splitlines()), text)
422
422
423 def with_linenumber(text, rev):
423 def with_linenumber(text, rev):
424 size = len(text.splitlines())
424 size = len(text.splitlines())
425 return ([(rev, i) for i in xrange(1, size + 1)], text)
425 return ([(rev, i) for i in xrange(1, size + 1)], text)
426
426
427 decorate = (((linenumber is None) and decorate_compat) or
427 decorate = (((linenumber is None) and decorate_compat) or
428 (linenumber and with_linenumber) or
428 (linenumber and with_linenumber) or
429 without_linenumber)
429 without_linenumber)
430
430
431 def pair(parent, child):
431 def pair(parent, child):
432 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
432 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
433 child[0][b1:b2] = parent[0][a1:a2]
433 child[0][b1:b2] = parent[0][a1:a2]
434 return child
434 return child
435
435
436 getlog = util.lrucachefunc(lambda x: self._repo.file(x))
436 getlog = util.lrucachefunc(lambda x: self._repo.file(x))
437 def getctx(path, fileid):
437 def getctx(path, fileid):
438 log = path == self._path and self._filelog or getlog(path)
438 log = path == self._path and self._filelog or getlog(path)
439 return filectx(self._repo, path, fileid=fileid, filelog=log)
439 return filectx(self._repo, path, fileid=fileid, filelog=log)
440 getctx = util.lrucachefunc(getctx)
440 getctx = util.lrucachefunc(getctx)
441
441
442 def parents(f):
442 def parents(f):
443 # we want to reuse filectx objects as much as possible
443 # we want to reuse filectx objects as much as possible
444 p = f._path
444 p = f._path
445 if f._filerev is None: # working dir
445 if f._filerev is None: # working dir
446 pl = [(n.path(), n.filerev()) for n in f.parents()]
446 pl = [(n.path(), n.filerev()) for n in f.parents()]
447 else:
447 else:
448 pl = [(p, n) for n in f._filelog.parentrevs(f._filerev)]
448 pl = [(p, n) for n in f._filelog.parentrevs(f._filerev)]
449
449
450 if follow:
450 if follow:
451 r = f.renamed()
451 r = f.renamed()
452 if r:
452 if r:
453 pl[0] = (r[0], getlog(r[0]).rev(r[1]))
453 pl[0] = (r[0], getlog(r[0]).rev(r[1]))
454
454
455 return [getctx(p, n) for p, n in pl if n != nullrev]
455 return [getctx(p, n) for p, n in pl if n != nullrev]
456
456
457 # use linkrev to find the first changeset where self appeared
457 # use linkrev to find the first changeset where self appeared
458 if self.rev() != self.linkrev():
458 if self.rev() != self.linkrev():
459 base = self.filectx(self.filerev())
459 base = self.filectx(self.filerev())
460 else:
460 else:
461 base = self
461 base = self
462
462
463 # find all ancestors
463 # find all ancestors
464 needed = {base: 1}
464 needed = {base: 1}
465 visit = [base]
465 visit = [base]
466 files = [base._path]
466 files = [base._path]
467 while visit:
467 while visit:
468 f = visit.pop(0)
468 f = visit.pop(0)
469 for p in parents(f):
469 for p in parents(f):
470 if p not in needed:
470 if p not in needed:
471 needed[p] = 1
471 needed[p] = 1
472 visit.append(p)
472 visit.append(p)
473 if p._path not in files:
473 if p._path not in files:
474 files.append(p._path)
474 files.append(p._path)
475 else:
475 else:
476 # count how many times we'll use this
476 # count how many times we'll use this
477 needed[p] += 1
477 needed[p] += 1
478
478
479 # sort by revision (per file) which is a topological order
479 # sort by revision (per file) which is a topological order
480 visit = []
480 visit = []
481 for f in files:
481 for f in files:
482 visit.extend(n for n in needed if n._path == f)
482 visit.extend(n for n in needed if n._path == f)
483
483
484 hist = {}
484 hist = {}
485 for f in sorted(visit, key=lambda x: x.rev()):
485 for f in sorted(visit, key=lambda x: x.rev()):
486 curr = decorate(f.data(), f)
486 curr = decorate(f.data(), f)
487 for p in parents(f):
487 for p in parents(f):
488 curr = pair(hist[p], curr)
488 curr = pair(hist[p], curr)
489 # trim the history of unneeded revs
489 # trim the history of unneeded revs
490 needed[p] -= 1
490 needed[p] -= 1
491 if not needed[p]:
491 if not needed[p]:
492 del hist[p]
492 del hist[p]
493 hist[f] = curr
493 hist[f] = curr
494
494
495 return zip(hist[f][0], hist[f][1].splitlines(True))
495 return zip(hist[f][0], hist[f][1].splitlines(True))
496
496
497 def ancestor(self, fc2, actx=None):
497 def ancestor(self, fc2, actx=None):
498 """
498 """
499 find the common ancestor file context, if any, of self, and fc2
499 find the common ancestor file context, if any, of self, and fc2
500
500
501 If actx is given, it must be the changectx of the common ancestor
501 If actx is given, it must be the changectx of the common ancestor
502 of self's and fc2's respective changesets.
502 of self's and fc2's respective changesets.
503 """
503 """
504
504
505 if actx is None:
505 if actx is None:
506 actx = self.changectx().ancestor(fc2.changectx())
506 actx = self.changectx().ancestor(fc2.changectx())
507
507
508 # the trivial case: changesets are unrelated, files must be too
508 # the trivial case: changesets are unrelated, files must be too
509 if not actx:
509 if not actx:
510 return None
510 return None
511
511
512 # the easy case: no (relevant) renames
512 # the easy case: no (relevant) renames
513 if fc2.path() == self.path() and self.path() in actx:
513 if fc2.path() == self.path() and self.path() in actx:
514 return actx[self.path()]
514 return actx[self.path()]
515 acache = {}
515 acache = {}
516
516
517 # prime the ancestor cache for the working directory
517 # prime the ancestor cache for the working directory
518 for c in (self, fc2):
518 for c in (self, fc2):
519 if c._filerev is None:
519 if c._filerev is None:
520 pl = [(n.path(), n.filenode()) for n in c.parents()]
520 pl = [(n.path(), n.filenode()) for n in c.parents()]
521 acache[(c._path, None)] = pl
521 acache[(c._path, None)] = pl
522
522
523 flcache = {self._repopath:self._filelog, fc2._repopath:fc2._filelog}
523 flcache = {self._repopath:self._filelog, fc2._repopath:fc2._filelog}
524 def parents(vertex):
524 def parents(vertex):
525 if vertex in acache:
525 if vertex in acache:
526 return acache[vertex]
526 return acache[vertex]
527 f, n = vertex
527 f, n = vertex
528 if f not in flcache:
528 if f not in flcache:
529 flcache[f] = self._repo.file(f)
529 flcache[f] = self._repo.file(f)
530 fl = flcache[f]
530 fl = flcache[f]
531 pl = [(f, p) for p in fl.parents(n) if p != nullid]
531 pl = [(f, p) for p in fl.parents(n) if p != nullid]
532 re = fl.renamed(n)
532 re = fl.renamed(n)
533 if re:
533 if re:
534 pl.append(re)
534 pl.append(re)
535 acache[vertex] = pl
535 acache[vertex] = pl
536 return pl
536 return pl
537
537
538 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
538 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
539 v = ancestor.ancestor(a, b, parents)
539 v = ancestor.ancestor(a, b, parents)
540 if v:
540 if v:
541 f, n = v
541 f, n = v
542 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
542 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
543
543
544 return None
544 return None
545
545
546 def ancestors(self):
546 def ancestors(self):
547 seen = set(str(self))
547 seen = set(str(self))
548 visit = [self]
548 visit = [self]
549 while visit:
549 while visit:
550 for parent in visit.pop(0).parents():
550 for parent in visit.pop(0).parents():
551 s = str(parent)
551 s = str(parent)
552 if s not in seen:
552 if s not in seen:
553 visit.append(parent)
553 visit.append(parent)
554 seen.add(s)
554 seen.add(s)
555 yield parent
555 yield parent
556
556
557 class workingctx(changectx):
557 class workingctx(changectx):
558 """A workingctx object makes access to data related to
558 """A workingctx object makes access to data related to
559 the current working directory convenient.
559 the current working directory convenient.
560 date - any valid date string or (unixtime, offset), or None.
560 date - any valid date string or (unixtime, offset), or None.
561 user - username string, or None.
561 user - username string, or None.
562 extra - a dictionary of extra values, or None.
562 extra - a dictionary of extra values, or None.
563 changes - a list of file lists as returned by localrepo.status()
563 changes - a list of file lists as returned by localrepo.status()
564 or None to use the repository status.
564 or None to use the repository status.
565 """
565 """
566 def __init__(self, repo, text="", user=None, date=None, extra=None,
566 def __init__(self, repo, text="", user=None, date=None, extra=None,
567 changes=None):
567 changes=None):
568 self._repo = repo
568 self._repo = repo
569 self._rev = None
569 self._rev = None
570 self._node = None
570 self._node = None
571 self._text = text
571 self._text = text
572 if date:
572 if date:
573 self._date = util.parsedate(date)
573 self._date = util.parsedate(date)
574 if user:
574 if user:
575 self._user = user
575 self._user = user
576 if changes:
576 if changes:
577 self._status = list(changes[:4])
577 self._status = list(changes[:4])
578 self._unknown = changes[4]
578 self._unknown = changes[4]
579 self._ignored = changes[5]
579 self._ignored = changes[5]
580 self._clean = changes[6]
580 self._clean = changes[6]
581 else:
581 else:
582 self._unknown = None
582 self._unknown = None
583 self._ignored = None
583 self._ignored = None
584 self._clean = None
584 self._clean = None
585
585
586 self._extra = {}
586 self._extra = {}
587 if extra:
587 if extra:
588 self._extra = extra.copy()
588 self._extra = extra.copy()
589 if 'branch' not in self._extra:
589 if 'branch' not in self._extra:
590 branch = self._repo.dirstate.branch()
590 branch = self._repo.dirstate.branch()
591 try:
591 try:
592 branch = branch.decode('UTF-8').encode('UTF-8')
592 branch = branch.decode('UTF-8').encode('UTF-8')
593 except UnicodeDecodeError:
593 except UnicodeDecodeError:
594 raise util.Abort(_('branch name not in UTF-8!'))
594 raise util.Abort(_('branch name not in UTF-8!'))
595 self._extra['branch'] = branch
595 self._extra['branch'] = branch
596 if self._extra['branch'] == '':
596 if self._extra['branch'] == '':
597 self._extra['branch'] = 'default'
597 self._extra['branch'] = 'default'
598
598
599 def __str__(self):
599 def __str__(self):
600 return str(self._parents[0]) + "+"
600 return str(self._parents[0]) + "+"
601
601
602 def __nonzero__(self):
602 def __nonzero__(self):
603 return True
603 return True
604
604
605 def __contains__(self, key):
605 def __contains__(self, key):
606 return self._repo.dirstate[key] not in "?r"
606 return self._repo.dirstate[key] not in "?r"
607
607
608 @propertycache
608 @propertycache
609 def _manifest(self):
609 def _manifest(self):
610 """generate a manifest corresponding to the working directory"""
610 """generate a manifest corresponding to the working directory"""
611
611
612 if self._unknown is None:
612 if self._unknown is None:
613 self.status(unknown=True)
613 self.status(unknown=True)
614
614
615 man = self._parents[0].manifest().copy()
615 man = self._parents[0].manifest().copy()
616 copied = self._repo.dirstate.copies()
616 copied = self._repo.dirstate.copies()
617 if len(self._parents) > 1:
617 if len(self._parents) > 1:
618 man2 = self.p2().manifest()
618 man2 = self.p2().manifest()
619 def getman(f):
619 def getman(f):
620 if f in man:
620 if f in man:
621 return man
621 return man
622 return man2
622 return man2
623 else:
623 else:
624 getman = lambda f: man
624 getman = lambda f: man
625 def cf(f):
625 def cf(f):
626 f = copied.get(f, f)
626 f = copied.get(f, f)
627 return getman(f).flags(f)
627 return getman(f).flags(f)
628 ff = self._repo.dirstate.flagfunc(cf)
628 ff = self._repo.dirstate.flagfunc(cf)
629 modified, added, removed, deleted = self._status
629 modified, added, removed, deleted = self._status
630 unknown = self._unknown
630 unknown = self._unknown
631 for i, l in (("a", added), ("m", modified), ("u", unknown)):
631 for i, l in (("a", added), ("m", modified), ("u", unknown)):
632 for f in l:
632 for f in l:
633 orig = copied.get(f, f)
633 orig = copied.get(f, f)
634 man[f] = getman(orig).get(orig, nullid) + i
634 man[f] = getman(orig).get(orig, nullid) + i
635 try:
635 try:
636 man.set(f, ff(f))
636 man.set(f, ff(f))
637 except OSError:
637 except OSError:
638 pass
638 pass
639
639
640 for f in deleted + removed:
640 for f in deleted + removed:
641 if f in man:
641 if f in man:
642 del man[f]
642 del man[f]
643
643
644 return man
644 return man
645
645
646 @propertycache
646 @propertycache
647 def _status(self):
647 def _status(self):
648 return self._repo.status()[:4]
648 return self._repo.status()[:4]
649
649
650 @propertycache
650 @propertycache
651 def _user(self):
651 def _user(self):
652 return self._repo.ui.username()
652 return self._repo.ui.username()
653
653
654 @propertycache
654 @propertycache
655 def _date(self):
655 def _date(self):
656 return util.makedate()
656 return util.makedate()
657
657
658 @propertycache
658 @propertycache
659 def _parents(self):
659 def _parents(self):
660 p = self._repo.dirstate.parents()
660 p = self._repo.dirstate.parents()
661 if p[1] == nullid:
661 if p[1] == nullid:
662 p = p[:-1]
662 p = p[:-1]
663 self._parents = [changectx(self._repo, x) for x in p]
663 self._parents = [changectx(self._repo, x) for x in p]
664 return self._parents
664 return self._parents
665
665
666 def status(self, ignored=False, clean=False, unknown=False):
666 def status(self, ignored=False, clean=False, unknown=False):
667 """Explicit status query
667 """Explicit status query
668 Unless this method is used to query the working copy status, the
668 Unless this method is used to query the working copy status, the
669 _status property will implicitly read the status using its default
669 _status property will implicitly read the status using its default
670 arguments."""
670 arguments."""
671 stat = self._repo.status(ignored=ignored, clean=clean, unknown=unknown)
671 stat = self._repo.status(ignored=ignored, clean=clean, unknown=unknown)
672 self._unknown = self._ignored = self._clean = None
672 self._unknown = self._ignored = self._clean = None
673 if unknown:
673 if unknown:
674 self._unknown = stat[4]
674 self._unknown = stat[4]
675 if ignored:
675 if ignored:
676 self._ignored = stat[5]
676 self._ignored = stat[5]
677 if clean:
677 if clean:
678 self._clean = stat[6]
678 self._clean = stat[6]
679 self._status = stat[:4]
679 self._status = stat[:4]
680 return stat
680 return stat
681
681
682 def manifest(self):
682 def manifest(self):
683 return self._manifest
683 return self._manifest
684 def user(self):
684 def user(self):
685 return self._user or self._repo.ui.username()
685 return self._user or self._repo.ui.username()
686 def date(self):
686 def date(self):
687 return self._date
687 return self._date
688 def description(self):
688 def description(self):
689 return self._text
689 return self._text
690 def files(self):
690 def files(self):
691 return sorted(self._status[0] + self._status[1] + self._status[2])
691 return sorted(self._status[0] + self._status[1] + self._status[2])
692
692
693 def modified(self):
693 def modified(self):
694 return self._status[0]
694 return self._status[0]
695 def added(self):
695 def added(self):
696 return self._status[1]
696 return self._status[1]
697 def removed(self):
697 def removed(self):
698 return self._status[2]
698 return self._status[2]
699 def deleted(self):
699 def deleted(self):
700 return self._status[3]
700 return self._status[3]
701 def unknown(self):
701 def unknown(self):
702 assert self._unknown is not None # must call status first
702 assert self._unknown is not None # must call status first
703 return self._unknown
703 return self._unknown
704 def ignored(self):
704 def ignored(self):
705 assert self._ignored is not None # must call status first
705 assert self._ignored is not None # must call status first
706 return self._ignored
706 return self._ignored
707 def clean(self):
707 def clean(self):
708 assert self._clean is not None # must call status first
708 assert self._clean is not None # must call status first
709 return self._clean
709 return self._clean
710 def branch(self):
710 def branch(self):
711 return self._extra['branch']
711 return self._extra['branch']
712 def extra(self):
712 def extra(self):
713 return self._extra
713 return self._extra
714
714
715 def tags(self):
715 def tags(self):
716 t = []
716 t = []
717 [t.extend(p.tags()) for p in self.parents()]
717 [t.extend(p.tags()) for p in self.parents()]
718 return t
718 return t
719
719
720 def children(self):
720 def children(self):
721 return []
721 return []
722
722
723 def flags(self, path):
723 def flags(self, path):
724 if '_manifest' in self.__dict__:
724 if '_manifest' in self.__dict__:
725 try:
725 try:
726 return self._manifest.flags(path)
726 return self._manifest.flags(path)
727 except KeyError:
727 except KeyError:
728 return ''
728 return ''
729
729
730 orig = self._repo.dirstate.copies().get(path, path)
730 orig = self._repo.dirstate.copies().get(path, path)
731
731
732 def findflag(ctx):
732 def findflag(ctx):
733 mnode = ctx.changeset()[0]
733 mnode = ctx.changeset()[0]
734 node, flag = self._repo.manifest.find(mnode, orig)
734 node, flag = self._repo.manifest.find(mnode, orig)
735 ff = self._repo.dirstate.flagfunc(lambda x: flag or '')
735 ff = self._repo.dirstate.flagfunc(lambda x: flag or '')
736 try:
736 try:
737 return ff(path)
737 return ff(path)
738 except OSError:
738 except OSError:
739 pass
739 pass
740
740
741 flag = findflag(self._parents[0])
741 flag = findflag(self._parents[0])
742 if flag is None and len(self.parents()) > 1:
742 if flag is None and len(self.parents()) > 1:
743 flag = findflag(self._parents[1])
743 flag = findflag(self._parents[1])
744 if flag is None or self._repo.dirstate[path] == 'r':
744 if flag is None or self._repo.dirstate[path] == 'r':
745 return ''
745 return ''
746 return flag
746 return flag
747
747
748 def filectx(self, path, filelog=None):
748 def filectx(self, path, filelog=None):
749 """get a file context from the working directory"""
749 """get a file context from the working directory"""
750 return workingfilectx(self._repo, path, workingctx=self,
750 return workingfilectx(self._repo, path, workingctx=self,
751 filelog=filelog)
751 filelog=filelog)
752
752
753 def ancestor(self, c2):
753 def ancestor(self, c2):
754 """return the ancestor context of self and c2"""
754 """return the ancestor context of self and c2"""
755 return self._parents[0].ancestor(c2) # punt on two parents for now
755 return self._parents[0].ancestor(c2) # punt on two parents for now
756
756
757 def walk(self, match):
757 def walk(self, match):
758 return sorted(self._repo.dirstate.walk(match, self.substate.keys(),
758 return sorted(self._repo.dirstate.walk(match, self.substate.keys(),
759 True, False))
759 True, False))
760
760
761 def dirty(self, missing=False):
761 def dirty(self, missing=False):
762 "check whether a working directory is modified"
762 "check whether a working directory is modified"
763 # check subrepos first
763 # check subrepos first
764 for s in self.substate:
764 for s in self.substate:
765 if self.sub(s).dirty():
765 if self.sub(s).dirty():
766 return True
766 return True
767 # check current working dir
767 # check current working dir
768 return (self.p2() or self.branch() != self.p1().branch() or
768 return (self.p2() or self.branch() != self.p1().branch() or
769 self.modified() or self.added() or self.removed() or
769 self.modified() or self.added() or self.removed() or
770 (missing and self.deleted()))
770 (missing and self.deleted()))
771
771
772 def add(self, list):
772 def add(self, list, prefix=""):
773 join = lambda f: os.path.join(prefix, f)
773 wlock = self._repo.wlock()
774 wlock = self._repo.wlock()
774 ui, ds = self._repo.ui, self._repo.dirstate
775 ui, ds = self._repo.ui, self._repo.dirstate
775 try:
776 try:
776 rejected = []
777 rejected = []
777 for f in list:
778 for f in list:
778 p = self._repo.wjoin(f)
779 p = self._repo.wjoin(f)
779 try:
780 try:
780 st = os.lstat(p)
781 st = os.lstat(p)
781 except:
782 except:
782 ui.warn(_("%s does not exist!\n") % f)
783 ui.warn(_("%s does not exist!\n") % join(f))
783 rejected.append(f)
784 rejected.append(f)
784 continue
785 continue
785 if st.st_size > 10000000:
786 if st.st_size > 10000000:
786 ui.warn(_("%s: up to %d MB of RAM may be required "
787 ui.warn(_("%s: up to %d MB of RAM may be required "
787 "to manage this file\n"
788 "to manage this file\n"
788 "(use 'hg revert %s' to cancel the "
789 "(use 'hg revert %s' to cancel the "
789 "pending addition)\n")
790 "pending addition)\n")
790 % (f, 3 * st.st_size // 1000000, f))
791 % (f, 3 * st.st_size // 1000000, join(f)))
791 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
792 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
792 ui.warn(_("%s not added: only files and symlinks "
793 ui.warn(_("%s not added: only files and symlinks "
793 "supported currently\n") % f)
794 "supported currently\n") % join(f))
794 rejected.append(p)
795 rejected.append(p)
795 elif ds[f] in 'amn':
796 elif ds[f] in 'amn':
796 ui.warn(_("%s already tracked!\n") % f)
797 ui.warn(_("%s already tracked!\n") % join(f))
797 elif ds[f] == 'r':
798 elif ds[f] == 'r':
798 ds.normallookup(f)
799 ds.normallookup(f)
799 else:
800 else:
800 ds.add(f)
801 ds.add(f)
801 return rejected
802 return rejected
802 finally:
803 finally:
803 wlock.release()
804 wlock.release()
804
805
805 def forget(self, list):
806 def forget(self, list):
806 wlock = self._repo.wlock()
807 wlock = self._repo.wlock()
807 try:
808 try:
808 for f in list:
809 for f in list:
809 if self._repo.dirstate[f] != 'a':
810 if self._repo.dirstate[f] != 'a':
810 self._repo.ui.warn(_("%s not added!\n") % f)
811 self._repo.ui.warn(_("%s not added!\n") % f)
811 else:
812 else:
812 self._repo.dirstate.forget(f)
813 self._repo.dirstate.forget(f)
813 finally:
814 finally:
814 wlock.release()
815 wlock.release()
815
816
816 def remove(self, list, unlink=False):
817 def remove(self, list, unlink=False):
817 if unlink:
818 if unlink:
818 for f in list:
819 for f in list:
819 try:
820 try:
820 util.unlink(self._repo.wjoin(f))
821 util.unlink(self._repo.wjoin(f))
821 except OSError, inst:
822 except OSError, inst:
822 if inst.errno != errno.ENOENT:
823 if inst.errno != errno.ENOENT:
823 raise
824 raise
824 wlock = self._repo.wlock()
825 wlock = self._repo.wlock()
825 try:
826 try:
826 for f in list:
827 for f in list:
827 if unlink and os.path.exists(self._repo.wjoin(f)):
828 if unlink and os.path.exists(self._repo.wjoin(f)):
828 self._repo.ui.warn(_("%s still exists!\n") % f)
829 self._repo.ui.warn(_("%s still exists!\n") % f)
829 elif self._repo.dirstate[f] == 'a':
830 elif self._repo.dirstate[f] == 'a':
830 self._repo.dirstate.forget(f)
831 self._repo.dirstate.forget(f)
831 elif f not in self._repo.dirstate:
832 elif f not in self._repo.dirstate:
832 self._repo.ui.warn(_("%s not tracked!\n") % f)
833 self._repo.ui.warn(_("%s not tracked!\n") % f)
833 else:
834 else:
834 self._repo.dirstate.remove(f)
835 self._repo.dirstate.remove(f)
835 finally:
836 finally:
836 wlock.release()
837 wlock.release()
837
838
838 def undelete(self, list):
839 def undelete(self, list):
839 pctxs = self.parents()
840 pctxs = self.parents()
840 wlock = self._repo.wlock()
841 wlock = self._repo.wlock()
841 try:
842 try:
842 for f in list:
843 for f in list:
843 if self._repo.dirstate[f] != 'r':
844 if self._repo.dirstate[f] != 'r':
844 self._repo.ui.warn(_("%s not removed!\n") % f)
845 self._repo.ui.warn(_("%s not removed!\n") % f)
845 else:
846 else:
846 fctx = f in pctxs[0] and pctxs[0] or pctxs[1]
847 fctx = f in pctxs[0] and pctxs[0] or pctxs[1]
847 t = fctx.data()
848 t = fctx.data()
848 self._repo.wwrite(f, t, fctx.flags())
849 self._repo.wwrite(f, t, fctx.flags())
849 self._repo.dirstate.normal(f)
850 self._repo.dirstate.normal(f)
850 finally:
851 finally:
851 wlock.release()
852 wlock.release()
852
853
853 def copy(self, source, dest):
854 def copy(self, source, dest):
854 p = self._repo.wjoin(dest)
855 p = self._repo.wjoin(dest)
855 if not (os.path.exists(p) or os.path.islink(p)):
856 if not (os.path.exists(p) or os.path.islink(p)):
856 self._repo.ui.warn(_("%s does not exist!\n") % dest)
857 self._repo.ui.warn(_("%s does not exist!\n") % dest)
857 elif not (os.path.isfile(p) or os.path.islink(p)):
858 elif not (os.path.isfile(p) or os.path.islink(p)):
858 self._repo.ui.warn(_("copy failed: %s is not a file or a "
859 self._repo.ui.warn(_("copy failed: %s is not a file or a "
859 "symbolic link\n") % dest)
860 "symbolic link\n") % dest)
860 else:
861 else:
861 wlock = self._repo.wlock()
862 wlock = self._repo.wlock()
862 try:
863 try:
863 if self._repo.dirstate[dest] in '?r':
864 if self._repo.dirstate[dest] in '?r':
864 self._repo.dirstate.add(dest)
865 self._repo.dirstate.add(dest)
865 self._repo.dirstate.copy(source, dest)
866 self._repo.dirstate.copy(source, dest)
866 finally:
867 finally:
867 wlock.release()
868 wlock.release()
868
869
869 class workingfilectx(filectx):
870 class workingfilectx(filectx):
870 """A workingfilectx object makes access to data related to a particular
871 """A workingfilectx object makes access to data related to a particular
871 file in the working directory convenient."""
872 file in the working directory convenient."""
872 def __init__(self, repo, path, filelog=None, workingctx=None):
873 def __init__(self, repo, path, filelog=None, workingctx=None):
873 """changeid can be a changeset revision, node, or tag.
874 """changeid can be a changeset revision, node, or tag.
874 fileid can be a file revision or node."""
875 fileid can be a file revision or node."""
875 self._repo = repo
876 self._repo = repo
876 self._path = path
877 self._path = path
877 self._changeid = None
878 self._changeid = None
878 self._filerev = self._filenode = None
879 self._filerev = self._filenode = None
879
880
880 if filelog:
881 if filelog:
881 self._filelog = filelog
882 self._filelog = filelog
882 if workingctx:
883 if workingctx:
883 self._changectx = workingctx
884 self._changectx = workingctx
884
885
885 @propertycache
886 @propertycache
886 def _changectx(self):
887 def _changectx(self):
887 return workingctx(self._repo)
888 return workingctx(self._repo)
888
889
889 def __nonzero__(self):
890 def __nonzero__(self):
890 return True
891 return True
891
892
892 def __str__(self):
893 def __str__(self):
893 return "%s@%s" % (self.path(), self._changectx)
894 return "%s@%s" % (self.path(), self._changectx)
894
895
895 def data(self):
896 def data(self):
896 return self._repo.wread(self._path)
897 return self._repo.wread(self._path)
897 def renamed(self):
898 def renamed(self):
898 rp = self._repo.dirstate.copied(self._path)
899 rp = self._repo.dirstate.copied(self._path)
899 if not rp:
900 if not rp:
900 return None
901 return None
901 return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
902 return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
902
903
903 def parents(self):
904 def parents(self):
904 '''return parent filectxs, following copies if necessary'''
905 '''return parent filectxs, following copies if necessary'''
905 def filenode(ctx, path):
906 def filenode(ctx, path):
906 return ctx._manifest.get(path, nullid)
907 return ctx._manifest.get(path, nullid)
907
908
908 path = self._path
909 path = self._path
909 fl = self._filelog
910 fl = self._filelog
910 pcl = self._changectx._parents
911 pcl = self._changectx._parents
911 renamed = self.renamed()
912 renamed = self.renamed()
912
913
913 if renamed:
914 if renamed:
914 pl = [renamed + (None,)]
915 pl = [renamed + (None,)]
915 else:
916 else:
916 pl = [(path, filenode(pcl[0], path), fl)]
917 pl = [(path, filenode(pcl[0], path), fl)]
917
918
918 for pc in pcl[1:]:
919 for pc in pcl[1:]:
919 pl.append((path, filenode(pc, path), fl))
920 pl.append((path, filenode(pc, path), fl))
920
921
921 return [filectx(self._repo, p, fileid=n, filelog=l)
922 return [filectx(self._repo, p, fileid=n, filelog=l)
922 for p, n, l in pl if n != nullid]
923 for p, n, l in pl if n != nullid]
923
924
924 def children(self):
925 def children(self):
925 return []
926 return []
926
927
927 def size(self):
928 def size(self):
928 return os.lstat(self._repo.wjoin(self._path)).st_size
929 return os.lstat(self._repo.wjoin(self._path)).st_size
929 def date(self):
930 def date(self):
930 t, tz = self._changectx.date()
931 t, tz = self._changectx.date()
931 try:
932 try:
932 return (int(os.lstat(self._repo.wjoin(self._path)).st_mtime), tz)
933 return (int(os.lstat(self._repo.wjoin(self._path)).st_mtime), tz)
933 except OSError, err:
934 except OSError, err:
934 if err.errno != errno.ENOENT:
935 if err.errno != errno.ENOENT:
935 raise
936 raise
936 return (t, tz)
937 return (t, tz)
937
938
938 def cmp(self, fctx):
939 def cmp(self, fctx):
939 """compare with other file context
940 """compare with other file context
940
941
941 returns True if different than fctx.
942 returns True if different than fctx.
942 """
943 """
943 # fctx should be a filectx (not a wfctx)
944 # fctx should be a filectx (not a wfctx)
944 # invert comparison to reuse the same code path
945 # invert comparison to reuse the same code path
945 return fctx.cmp(self)
946 return fctx.cmp(self)
946
947
947 class memctx(object):
948 class memctx(object):
948 """Use memctx to perform in-memory commits via localrepo.commitctx().
949 """Use memctx to perform in-memory commits via localrepo.commitctx().
949
950
950 Revision information is supplied at initialization time while
951 Revision information is supplied at initialization time while
951 related files data and is made available through a callback
952 related files data and is made available through a callback
952 mechanism. 'repo' is the current localrepo, 'parents' is a
953 mechanism. 'repo' is the current localrepo, 'parents' is a
953 sequence of two parent revisions identifiers (pass None for every
954 sequence of two parent revisions identifiers (pass None for every
954 missing parent), 'text' is the commit message and 'files' lists
955 missing parent), 'text' is the commit message and 'files' lists
955 names of files touched by the revision (normalized and relative to
956 names of files touched by the revision (normalized and relative to
956 repository root).
957 repository root).
957
958
958 filectxfn(repo, memctx, path) is a callable receiving the
959 filectxfn(repo, memctx, path) is a callable receiving the
959 repository, the current memctx object and the normalized path of
960 repository, the current memctx object and the normalized path of
960 requested file, relative to repository root. It is fired by the
961 requested file, relative to repository root. It is fired by the
961 commit function for every file in 'files', but calls order is
962 commit function for every file in 'files', but calls order is
962 undefined. If the file is available in the revision being
963 undefined. If the file is available in the revision being
963 committed (updated or added), filectxfn returns a memfilectx
964 committed (updated or added), filectxfn returns a memfilectx
964 object. If the file was removed, filectxfn raises an
965 object. If the file was removed, filectxfn raises an
965 IOError. Moved files are represented by marking the source file
966 IOError. Moved files are represented by marking the source file
966 removed and the new file added with copy information (see
967 removed and the new file added with copy information (see
967 memfilectx).
968 memfilectx).
968
969
969 user receives the committer name and defaults to current
970 user receives the committer name and defaults to current
970 repository username, date is the commit date in any format
971 repository username, date is the commit date in any format
971 supported by util.parsedate() and defaults to current date, extra
972 supported by util.parsedate() and defaults to current date, extra
972 is a dictionary of metadata or is left empty.
973 is a dictionary of metadata or is left empty.
973 """
974 """
974 def __init__(self, repo, parents, text, files, filectxfn, user=None,
975 def __init__(self, repo, parents, text, files, filectxfn, user=None,
975 date=None, extra=None):
976 date=None, extra=None):
976 self._repo = repo
977 self._repo = repo
977 self._rev = None
978 self._rev = None
978 self._node = None
979 self._node = None
979 self._text = text
980 self._text = text
980 self._date = date and util.parsedate(date) or util.makedate()
981 self._date = date and util.parsedate(date) or util.makedate()
981 self._user = user
982 self._user = user
982 parents = [(p or nullid) for p in parents]
983 parents = [(p or nullid) for p in parents]
983 p1, p2 = parents
984 p1, p2 = parents
984 self._parents = [changectx(self._repo, p) for p in (p1, p2)]
985 self._parents = [changectx(self._repo, p) for p in (p1, p2)]
985 files = sorted(set(files))
986 files = sorted(set(files))
986 self._status = [files, [], [], [], []]
987 self._status = [files, [], [], [], []]
987 self._filectxfn = filectxfn
988 self._filectxfn = filectxfn
988
989
989 self._extra = extra and extra.copy() or {}
990 self._extra = extra and extra.copy() or {}
990 if 'branch' not in self._extra:
991 if 'branch' not in self._extra:
991 self._extra['branch'] = 'default'
992 self._extra['branch'] = 'default'
992 elif self._extra.get('branch') == '':
993 elif self._extra.get('branch') == '':
993 self._extra['branch'] = 'default'
994 self._extra['branch'] = 'default'
994
995
995 def __str__(self):
996 def __str__(self):
996 return str(self._parents[0]) + "+"
997 return str(self._parents[0]) + "+"
997
998
998 def __int__(self):
999 def __int__(self):
999 return self._rev
1000 return self._rev
1000
1001
1001 def __nonzero__(self):
1002 def __nonzero__(self):
1002 return True
1003 return True
1003
1004
1004 def __getitem__(self, key):
1005 def __getitem__(self, key):
1005 return self.filectx(key)
1006 return self.filectx(key)
1006
1007
1007 def p1(self):
1008 def p1(self):
1008 return self._parents[0]
1009 return self._parents[0]
1009 def p2(self):
1010 def p2(self):
1010 return self._parents[1]
1011 return self._parents[1]
1011
1012
1012 def user(self):
1013 def user(self):
1013 return self._user or self._repo.ui.username()
1014 return self._user or self._repo.ui.username()
1014 def date(self):
1015 def date(self):
1015 return self._date
1016 return self._date
1016 def description(self):
1017 def description(self):
1017 return self._text
1018 return self._text
1018 def files(self):
1019 def files(self):
1019 return self.modified()
1020 return self.modified()
1020 def modified(self):
1021 def modified(self):
1021 return self._status[0]
1022 return self._status[0]
1022 def added(self):
1023 def added(self):
1023 return self._status[1]
1024 return self._status[1]
1024 def removed(self):
1025 def removed(self):
1025 return self._status[2]
1026 return self._status[2]
1026 def deleted(self):
1027 def deleted(self):
1027 return self._status[3]
1028 return self._status[3]
1028 def unknown(self):
1029 def unknown(self):
1029 return self._status[4]
1030 return self._status[4]
1030 def ignored(self):
1031 def ignored(self):
1031 return self._status[5]
1032 return self._status[5]
1032 def clean(self):
1033 def clean(self):
1033 return self._status[6]
1034 return self._status[6]
1034 def branch(self):
1035 def branch(self):
1035 return self._extra['branch']
1036 return self._extra['branch']
1036 def extra(self):
1037 def extra(self):
1037 return self._extra
1038 return self._extra
1038 def flags(self, f):
1039 def flags(self, f):
1039 return self[f].flags()
1040 return self[f].flags()
1040
1041
1041 def parents(self):
1042 def parents(self):
1042 """return contexts for each parent changeset"""
1043 """return contexts for each parent changeset"""
1043 return self._parents
1044 return self._parents
1044
1045
1045 def filectx(self, path, filelog=None):
1046 def filectx(self, path, filelog=None):
1046 """get a file context from the working directory"""
1047 """get a file context from the working directory"""
1047 return self._filectxfn(self._repo, self, path)
1048 return self._filectxfn(self._repo, self, path)
1048
1049
1049 def commit(self):
1050 def commit(self):
1050 """commit context to the repo"""
1051 """commit context to the repo"""
1051 return self._repo.commitctx(self)
1052 return self._repo.commitctx(self)
1052
1053
1053 class memfilectx(object):
1054 class memfilectx(object):
1054 """memfilectx represents an in-memory file to commit.
1055 """memfilectx represents an in-memory file to commit.
1055
1056
1056 See memctx for more details.
1057 See memctx for more details.
1057 """
1058 """
1058 def __init__(self, path, data, islink=False, isexec=False, copied=None):
1059 def __init__(self, path, data, islink=False, isexec=False, copied=None):
1059 """
1060 """
1060 path is the normalized file path relative to repository root.
1061 path is the normalized file path relative to repository root.
1061 data is the file content as a string.
1062 data is the file content as a string.
1062 islink is True if the file is a symbolic link.
1063 islink is True if the file is a symbolic link.
1063 isexec is True if the file is executable.
1064 isexec is True if the file is executable.
1064 copied is the source file path if current file was copied in the
1065 copied is the source file path if current file was copied in the
1065 revision being committed, or None."""
1066 revision being committed, or None."""
1066 self._path = path
1067 self._path = path
1067 self._data = data
1068 self._data = data
1068 self._flags = (islink and 'l' or '') + (isexec and 'x' or '')
1069 self._flags = (islink and 'l' or '') + (isexec and 'x' or '')
1069 self._copied = None
1070 self._copied = None
1070 if copied:
1071 if copied:
1071 self._copied = (copied, nullid)
1072 self._copied = (copied, nullid)
1072
1073
1073 def __nonzero__(self):
1074 def __nonzero__(self):
1074 return True
1075 return True
1075 def __str__(self):
1076 def __str__(self):
1076 return "%s@%s" % (self.path(), self._changectx)
1077 return "%s@%s" % (self.path(), self._changectx)
1077 def path(self):
1078 def path(self):
1078 return self._path
1079 return self._path
1079 def data(self):
1080 def data(self):
1080 return self._data
1081 return self._data
1081 def flags(self):
1082 def flags(self):
1082 return self._flags
1083 return self._flags
1083 def isexec(self):
1084 def isexec(self):
1084 return 'x' in self._flags
1085 return 'x' in self._flags
1085 def islink(self):
1086 def islink(self):
1086 return 'l' in self._flags
1087 return 'l' in self._flags
1087 def renamed(self):
1088 def renamed(self):
1088 return self._copied
1089 return self._copied
@@ -1,496 +1,502 b''
1 # subrepo.py - sub-repository handling for Mercurial
1 # subrepo.py - sub-repository handling for Mercurial
2 #
2 #
3 # Copyright 2009-2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2009-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 errno, os, re, xml.dom.minidom, shutil, urlparse, posixpath
8 import errno, os, re, xml.dom.minidom, shutil, urlparse, posixpath
9 from i18n import _
9 from i18n import _
10 import config, util, node, error, cmdutil
10 import config, util, node, error, cmdutil
11 hg = None
11 hg = None
12
12
13 nullstate = ('', '', 'empty')
13 nullstate = ('', '', 'empty')
14
14
15 def state(ctx, ui):
15 def state(ctx, ui):
16 """return a state dict, mapping subrepo paths configured in .hgsub
16 """return a state dict, mapping subrepo paths configured in .hgsub
17 to tuple: (source from .hgsub, revision from .hgsubstate, kind
17 to tuple: (source from .hgsub, revision from .hgsubstate, kind
18 (key in types dict))
18 (key in types dict))
19 """
19 """
20 p = config.config()
20 p = config.config()
21 def read(f, sections=None, remap=None):
21 def read(f, sections=None, remap=None):
22 if f in ctx:
22 if f in ctx:
23 p.parse(f, ctx[f].data(), sections, remap, read)
23 p.parse(f, ctx[f].data(), sections, remap, read)
24 else:
24 else:
25 raise util.Abort(_("subrepo spec file %s not found") % f)
25 raise util.Abort(_("subrepo spec file %s not found") % f)
26
26
27 if '.hgsub' in ctx:
27 if '.hgsub' in ctx:
28 read('.hgsub')
28 read('.hgsub')
29
29
30 for path, src in ui.configitems('subpaths'):
30 for path, src in ui.configitems('subpaths'):
31 p.set('subpaths', path, src, ui.configsource('subpaths', path))
31 p.set('subpaths', path, src, ui.configsource('subpaths', path))
32
32
33 rev = {}
33 rev = {}
34 if '.hgsubstate' in ctx:
34 if '.hgsubstate' in ctx:
35 try:
35 try:
36 for l in ctx['.hgsubstate'].data().splitlines():
36 for l in ctx['.hgsubstate'].data().splitlines():
37 revision, path = l.split(" ", 1)
37 revision, path = l.split(" ", 1)
38 rev[path] = revision
38 rev[path] = revision
39 except IOError, err:
39 except IOError, err:
40 if err.errno != errno.ENOENT:
40 if err.errno != errno.ENOENT:
41 raise
41 raise
42
42
43 state = {}
43 state = {}
44 for path, src in p[''].items():
44 for path, src in p[''].items():
45 kind = 'hg'
45 kind = 'hg'
46 if src.startswith('['):
46 if src.startswith('['):
47 if ']' not in src:
47 if ']' not in src:
48 raise util.Abort(_('missing ] in subrepo source'))
48 raise util.Abort(_('missing ] in subrepo source'))
49 kind, src = src.split(']', 1)
49 kind, src = src.split(']', 1)
50 kind = kind[1:]
50 kind = kind[1:]
51
51
52 for pattern, repl in p.items('subpaths'):
52 for pattern, repl in p.items('subpaths'):
53 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
53 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
54 # does a string decode.
54 # does a string decode.
55 repl = repl.encode('string-escape')
55 repl = repl.encode('string-escape')
56 # However, we still want to allow back references to go
56 # However, we still want to allow back references to go
57 # through unharmed, so we turn r'\\1' into r'\1'. Again,
57 # through unharmed, so we turn r'\\1' into r'\1'. Again,
58 # extra escapes are needed because re.sub string decodes.
58 # extra escapes are needed because re.sub string decodes.
59 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl)
59 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl)
60 try:
60 try:
61 src = re.sub(pattern, repl, src, 1)
61 src = re.sub(pattern, repl, src, 1)
62 except re.error, e:
62 except re.error, e:
63 raise util.Abort(_("bad subrepository pattern in %s: %s")
63 raise util.Abort(_("bad subrepository pattern in %s: %s")
64 % (p.source('subpaths', pattern), e))
64 % (p.source('subpaths', pattern), e))
65
65
66 state[path] = (src.strip(), rev.get(path, ''), kind)
66 state[path] = (src.strip(), rev.get(path, ''), kind)
67
67
68 return state
68 return state
69
69
70 def writestate(repo, state):
70 def writestate(repo, state):
71 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
71 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
72 repo.wwrite('.hgsubstate',
72 repo.wwrite('.hgsubstate',
73 ''.join(['%s %s\n' % (state[s][1], s)
73 ''.join(['%s %s\n' % (state[s][1], s)
74 for s in sorted(state)]), '')
74 for s in sorted(state)]), '')
75
75
76 def submerge(repo, wctx, mctx, actx):
76 def submerge(repo, wctx, mctx, actx):
77 """delegated from merge.applyupdates: merging of .hgsubstate file
77 """delegated from merge.applyupdates: merging of .hgsubstate file
78 in working context, merging context and ancestor context"""
78 in working context, merging context and ancestor context"""
79 if mctx == actx: # backwards?
79 if mctx == actx: # backwards?
80 actx = wctx.p1()
80 actx = wctx.p1()
81 s1 = wctx.substate
81 s1 = wctx.substate
82 s2 = mctx.substate
82 s2 = mctx.substate
83 sa = actx.substate
83 sa = actx.substate
84 sm = {}
84 sm = {}
85
85
86 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
86 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
87
87
88 def debug(s, msg, r=""):
88 def debug(s, msg, r=""):
89 if r:
89 if r:
90 r = "%s:%s:%s" % r
90 r = "%s:%s:%s" % r
91 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
91 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
92
92
93 for s, l in s1.items():
93 for s, l in s1.items():
94 a = sa.get(s, nullstate)
94 a = sa.get(s, nullstate)
95 ld = l # local state with possible dirty flag for compares
95 ld = l # local state with possible dirty flag for compares
96 if wctx.sub(s).dirty():
96 if wctx.sub(s).dirty():
97 ld = (l[0], l[1] + "+")
97 ld = (l[0], l[1] + "+")
98 if wctx == actx: # overwrite
98 if wctx == actx: # overwrite
99 a = ld
99 a = ld
100
100
101 if s in s2:
101 if s in s2:
102 r = s2[s]
102 r = s2[s]
103 if ld == r or r == a: # no change or local is newer
103 if ld == r or r == a: # no change or local is newer
104 sm[s] = l
104 sm[s] = l
105 continue
105 continue
106 elif ld == a: # other side changed
106 elif ld == a: # other side changed
107 debug(s, "other changed, get", r)
107 debug(s, "other changed, get", r)
108 wctx.sub(s).get(r)
108 wctx.sub(s).get(r)
109 sm[s] = r
109 sm[s] = r
110 elif ld[0] != r[0]: # sources differ
110 elif ld[0] != r[0]: # sources differ
111 if repo.ui.promptchoice(
111 if repo.ui.promptchoice(
112 _(' subrepository sources for %s differ\n'
112 _(' subrepository sources for %s differ\n'
113 'use (l)ocal source (%s) or (r)emote source (%s)?')
113 'use (l)ocal source (%s) or (r)emote source (%s)?')
114 % (s, l[0], r[0]),
114 % (s, l[0], r[0]),
115 (_('&Local'), _('&Remote')), 0):
115 (_('&Local'), _('&Remote')), 0):
116 debug(s, "prompt changed, get", r)
116 debug(s, "prompt changed, get", r)
117 wctx.sub(s).get(r)
117 wctx.sub(s).get(r)
118 sm[s] = r
118 sm[s] = r
119 elif ld[1] == a[1]: # local side is unchanged
119 elif ld[1] == a[1]: # local side is unchanged
120 debug(s, "other side changed, get", r)
120 debug(s, "other side changed, get", r)
121 wctx.sub(s).get(r)
121 wctx.sub(s).get(r)
122 sm[s] = r
122 sm[s] = r
123 else:
123 else:
124 debug(s, "both sides changed, merge with", r)
124 debug(s, "both sides changed, merge with", r)
125 wctx.sub(s).merge(r)
125 wctx.sub(s).merge(r)
126 sm[s] = l
126 sm[s] = l
127 elif ld == a: # remote removed, local unchanged
127 elif ld == a: # remote removed, local unchanged
128 debug(s, "remote removed, remove")
128 debug(s, "remote removed, remove")
129 wctx.sub(s).remove()
129 wctx.sub(s).remove()
130 else:
130 else:
131 if repo.ui.promptchoice(
131 if repo.ui.promptchoice(
132 _(' local changed subrepository %s which remote removed\n'
132 _(' local changed subrepository %s which remote removed\n'
133 'use (c)hanged version or (d)elete?') % s,
133 'use (c)hanged version or (d)elete?') % s,
134 (_('&Changed'), _('&Delete')), 0):
134 (_('&Changed'), _('&Delete')), 0):
135 debug(s, "prompt remove")
135 debug(s, "prompt remove")
136 wctx.sub(s).remove()
136 wctx.sub(s).remove()
137
137
138 for s, r in s2.items():
138 for s, r in s2.items():
139 if s in s1:
139 if s in s1:
140 continue
140 continue
141 elif s not in sa:
141 elif s not in sa:
142 debug(s, "remote added, get", r)
142 debug(s, "remote added, get", r)
143 mctx.sub(s).get(r)
143 mctx.sub(s).get(r)
144 sm[s] = r
144 sm[s] = r
145 elif r != sa[s]:
145 elif r != sa[s]:
146 if repo.ui.promptchoice(
146 if repo.ui.promptchoice(
147 _(' remote changed subrepository %s which local removed\n'
147 _(' remote changed subrepository %s which local removed\n'
148 'use (c)hanged version or (d)elete?') % s,
148 'use (c)hanged version or (d)elete?') % s,
149 (_('&Changed'), _('&Delete')), 0) == 0:
149 (_('&Changed'), _('&Delete')), 0) == 0:
150 debug(s, "prompt recreate", r)
150 debug(s, "prompt recreate", r)
151 wctx.sub(s).get(r)
151 wctx.sub(s).get(r)
152 sm[s] = r
152 sm[s] = r
153
153
154 # record merged .hgsubstate
154 # record merged .hgsubstate
155 writestate(repo, sm)
155 writestate(repo, sm)
156
156
157 def relpath(sub):
157 def relpath(sub):
158 """return path to this subrepo as seen from outermost repo"""
158 """return path to this subrepo as seen from outermost repo"""
159 if not hasattr(sub, '_repo'):
159 if not hasattr(sub, '_repo'):
160 return sub._path
160 return sub._path
161 parent = sub._repo
161 parent = sub._repo
162 while hasattr(parent, '_subparent'):
162 while hasattr(parent, '_subparent'):
163 parent = parent._subparent
163 parent = parent._subparent
164 return sub._repo.root[len(parent.root)+1:]
164 return sub._repo.root[len(parent.root)+1:]
165
165
166 def _abssource(repo, push=False):
166 def _abssource(repo, push=False):
167 """return pull/push path of repo - either based on parent repo
167 """return pull/push path of repo - either based on parent repo
168 .hgsub info or on the subrepos own config"""
168 .hgsub info or on the subrepos own config"""
169 if hasattr(repo, '_subparent'):
169 if hasattr(repo, '_subparent'):
170 source = repo._subsource
170 source = repo._subsource
171 if source.startswith('/') or '://' in source:
171 if source.startswith('/') or '://' in source:
172 return source
172 return source
173 parent = _abssource(repo._subparent, push)
173 parent = _abssource(repo._subparent, push)
174 if '://' in parent:
174 if '://' in parent:
175 if parent[-1] == '/':
175 if parent[-1] == '/':
176 parent = parent[:-1]
176 parent = parent[:-1]
177 r = urlparse.urlparse(parent + '/' + source)
177 r = urlparse.urlparse(parent + '/' + source)
178 r = urlparse.urlunparse((r[0], r[1],
178 r = urlparse.urlunparse((r[0], r[1],
179 posixpath.normpath(r[2]),
179 posixpath.normpath(r[2]),
180 r[3], r[4], r[5]))
180 r[3], r[4], r[5]))
181 return r
181 return r
182 return posixpath.normpath(os.path.join(parent, repo._subsource))
182 return posixpath.normpath(os.path.join(parent, repo._subsource))
183 if push and repo.ui.config('paths', 'default-push'):
183 if push and repo.ui.config('paths', 'default-push'):
184 return repo.ui.config('paths', 'default-push', repo.root)
184 return repo.ui.config('paths', 'default-push', repo.root)
185 return repo.ui.config('paths', 'default', repo.root)
185 return repo.ui.config('paths', 'default', repo.root)
186
186
187 def itersubrepos(ctx1, ctx2):
187 def itersubrepos(ctx1, ctx2):
188 """find subrepos in ctx1 or ctx2"""
188 """find subrepos in ctx1 or ctx2"""
189 # Create a (subpath, ctx) mapping where we prefer subpaths from
189 # Create a (subpath, ctx) mapping where we prefer subpaths from
190 # ctx1. The subpaths from ctx2 are important when the .hgsub file
190 # ctx1. The subpaths from ctx2 are important when the .hgsub file
191 # has been modified (in ctx2) but not yet committed (in ctx1).
191 # has been modified (in ctx2) but not yet committed (in ctx1).
192 subpaths = dict.fromkeys(ctx2.substate, ctx2)
192 subpaths = dict.fromkeys(ctx2.substate, ctx2)
193 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
193 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
194 for subpath, ctx in sorted(subpaths.iteritems()):
194 for subpath, ctx in sorted(subpaths.iteritems()):
195 yield subpath, ctx.sub(subpath)
195 yield subpath, ctx.sub(subpath)
196
196
197 def subrepo(ctx, path):
197 def subrepo(ctx, path):
198 """return instance of the right subrepo class for subrepo in path"""
198 """return instance of the right subrepo class for subrepo in path"""
199 # subrepo inherently violates our import layering rules
199 # subrepo inherently violates our import layering rules
200 # because it wants to make repo objects from deep inside the stack
200 # because it wants to make repo objects from deep inside the stack
201 # so we manually delay the circular imports to not break
201 # so we manually delay the circular imports to not break
202 # scripts that don't use our demand-loading
202 # scripts that don't use our demand-loading
203 global hg
203 global hg
204 import hg as h
204 import hg as h
205 hg = h
205 hg = h
206
206
207 util.path_auditor(ctx._repo.root)(path)
207 util.path_auditor(ctx._repo.root)(path)
208 state = ctx.substate.get(path, nullstate)
208 state = ctx.substate.get(path, nullstate)
209 if state[2] not in types:
209 if state[2] not in types:
210 raise util.Abort(_('unknown subrepo type %s') % state[2])
210 raise util.Abort(_('unknown subrepo type %s') % state[2])
211 return types[state[2]](ctx, path, state[:2])
211 return types[state[2]](ctx, path, state[:2])
212
212
213 # subrepo classes need to implement the following abstract class:
213 # subrepo classes need to implement the following abstract class:
214
214
215 class abstractsubrepo(object):
215 class abstractsubrepo(object):
216
216
217 def dirty(self):
217 def dirty(self):
218 """returns true if the dirstate of the subrepo does not match
218 """returns true if the dirstate of the subrepo does not match
219 current stored state
219 current stored state
220 """
220 """
221 raise NotImplementedError
221 raise NotImplementedError
222
222
223 def checknested(path):
223 def checknested(path):
224 """check if path is a subrepository within this repository"""
224 """check if path is a subrepository within this repository"""
225 return False
225 return False
226
226
227 def commit(self, text, user, date):
227 def commit(self, text, user, date):
228 """commit the current changes to the subrepo with the given
228 """commit the current changes to the subrepo with the given
229 log message. Use given user and date if possible. Return the
229 log message. Use given user and date if possible. Return the
230 new state of the subrepo.
230 new state of the subrepo.
231 """
231 """
232 raise NotImplementedError
232 raise NotImplementedError
233
233
234 def remove(self):
234 def remove(self):
235 """remove the subrepo
235 """remove the subrepo
236
236
237 (should verify the dirstate is not dirty first)
237 (should verify the dirstate is not dirty first)
238 """
238 """
239 raise NotImplementedError
239 raise NotImplementedError
240
240
241 def get(self, state):
241 def get(self, state):
242 """run whatever commands are needed to put the subrepo into
242 """run whatever commands are needed to put the subrepo into
243 this state
243 this state
244 """
244 """
245 raise NotImplementedError
245 raise NotImplementedError
246
246
247 def merge(self, state):
247 def merge(self, state):
248 """merge currently-saved state with the new state."""
248 """merge currently-saved state with the new state."""
249 raise NotImplementedError
249 raise NotImplementedError
250
250
251 def push(self, force):
251 def push(self, force):
252 """perform whatever action is analogous to 'hg push'
252 """perform whatever action is analogous to 'hg push'
253
253
254 This may be a no-op on some systems.
254 This may be a no-op on some systems.
255 """
255 """
256 raise NotImplementedError
256 raise NotImplementedError
257
257
258 def add(self, ui, match, dryrun, prefix):
259 return []
258
260
259 def status(self, rev2, **opts):
261 def status(self, rev2, **opts):
260 return [], [], [], [], [], [], []
262 return [], [], [], [], [], [], []
261
263
262 def diff(self, diffopts, node2, match, prefix, **opts):
264 def diff(self, diffopts, node2, match, prefix, **opts):
263 pass
265 pass
264
266
265 class hgsubrepo(abstractsubrepo):
267 class hgsubrepo(abstractsubrepo):
266 def __init__(self, ctx, path, state):
268 def __init__(self, ctx, path, state):
267 self._path = path
269 self._path = path
268 self._state = state
270 self._state = state
269 r = ctx._repo
271 r = ctx._repo
270 root = r.wjoin(path)
272 root = r.wjoin(path)
271 create = False
273 create = False
272 if not os.path.exists(os.path.join(root, '.hg')):
274 if not os.path.exists(os.path.join(root, '.hg')):
273 create = True
275 create = True
274 util.makedirs(root)
276 util.makedirs(root)
275 self._repo = hg.repository(r.ui, root, create=create)
277 self._repo = hg.repository(r.ui, root, create=create)
276 self._repo._subparent = r
278 self._repo._subparent = r
277 self._repo._subsource = state[0]
279 self._repo._subsource = state[0]
278
280
279 if create:
281 if create:
280 fp = self._repo.opener("hgrc", "w", text=True)
282 fp = self._repo.opener("hgrc", "w", text=True)
281 fp.write('[paths]\n')
283 fp.write('[paths]\n')
282
284
283 def addpathconfig(key, value):
285 def addpathconfig(key, value):
284 fp.write('%s = %s\n' % (key, value))
286 fp.write('%s = %s\n' % (key, value))
285 self._repo.ui.setconfig('paths', key, value)
287 self._repo.ui.setconfig('paths', key, value)
286
288
287 defpath = _abssource(self._repo)
289 defpath = _abssource(self._repo)
288 defpushpath = _abssource(self._repo, True)
290 defpushpath = _abssource(self._repo, True)
289 addpathconfig('default', defpath)
291 addpathconfig('default', defpath)
290 if defpath != defpushpath:
292 if defpath != defpushpath:
291 addpathconfig('default-push', defpushpath)
293 addpathconfig('default-push', defpushpath)
292 fp.close()
294 fp.close()
293
295
296 def add(self, ui, match, dryrun, prefix):
297 return cmdutil.add(ui, self._repo, match, dryrun, True,
298 os.path.join(prefix, self._path))
299
294 def status(self, rev2, **opts):
300 def status(self, rev2, **opts):
295 try:
301 try:
296 rev1 = self._state[1]
302 rev1 = self._state[1]
297 ctx1 = self._repo[rev1]
303 ctx1 = self._repo[rev1]
298 ctx2 = self._repo[rev2]
304 ctx2 = self._repo[rev2]
299 return self._repo.status(ctx1, ctx2, **opts)
305 return self._repo.status(ctx1, ctx2, **opts)
300 except error.RepoLookupError, inst:
306 except error.RepoLookupError, inst:
301 self._repo.ui.warn(_("warning: %s in %s\n")
307 self._repo.ui.warn(_("warning: %s in %s\n")
302 % (inst, relpath(self)))
308 % (inst, relpath(self)))
303 return [], [], [], [], [], [], []
309 return [], [], [], [], [], [], []
304
310
305 def diff(self, diffopts, node2, match, prefix, **opts):
311 def diff(self, diffopts, node2, match, prefix, **opts):
306 try:
312 try:
307 node1 = node.bin(self._state[1])
313 node1 = node.bin(self._state[1])
308 # We currently expect node2 to come from substate and be
314 # We currently expect node2 to come from substate and be
309 # in hex format
315 # in hex format
310 if node2 is not None:
316 if node2 is not None:
311 node2 = node.bin(node2)
317 node2 = node.bin(node2)
312 cmdutil.diffordiffstat(self._repo.ui, self._repo, diffopts,
318 cmdutil.diffordiffstat(self._repo.ui, self._repo, diffopts,
313 node1, node2, match,
319 node1, node2, match,
314 prefix=os.path.join(prefix, self._path),
320 prefix=os.path.join(prefix, self._path),
315 listsubrepos=True, **opts)
321 listsubrepos=True, **opts)
316 except error.RepoLookupError, inst:
322 except error.RepoLookupError, inst:
317 self._repo.ui.warn(_("warning: %s in %s\n")
323 self._repo.ui.warn(_("warning: %s in %s\n")
318 % (inst, relpath(self)))
324 % (inst, relpath(self)))
319
325
320 def dirty(self):
326 def dirty(self):
321 r = self._state[1]
327 r = self._state[1]
322 if r == '':
328 if r == '':
323 return True
329 return True
324 w = self._repo[None]
330 w = self._repo[None]
325 if w.p1() != self._repo[r]: # version checked out change
331 if w.p1() != self._repo[r]: # version checked out change
326 return True
332 return True
327 return w.dirty() # working directory changed
333 return w.dirty() # working directory changed
328
334
329 def checknested(self, path):
335 def checknested(self, path):
330 return self._repo._checknested(self._repo.wjoin(path))
336 return self._repo._checknested(self._repo.wjoin(path))
331
337
332 def commit(self, text, user, date):
338 def commit(self, text, user, date):
333 self._repo.ui.debug("committing subrepo %s\n" % relpath(self))
339 self._repo.ui.debug("committing subrepo %s\n" % relpath(self))
334 n = self._repo.commit(text, user, date)
340 n = self._repo.commit(text, user, date)
335 if not n:
341 if not n:
336 return self._repo['.'].hex() # different version checked out
342 return self._repo['.'].hex() # different version checked out
337 return node.hex(n)
343 return node.hex(n)
338
344
339 def remove(self):
345 def remove(self):
340 # we can't fully delete the repository as it may contain
346 # we can't fully delete the repository as it may contain
341 # local-only history
347 # local-only history
342 self._repo.ui.note(_('removing subrepo %s\n') % relpath(self))
348 self._repo.ui.note(_('removing subrepo %s\n') % relpath(self))
343 hg.clean(self._repo, node.nullid, False)
349 hg.clean(self._repo, node.nullid, False)
344
350
345 def _get(self, state):
351 def _get(self, state):
346 source, revision, kind = state
352 source, revision, kind = state
347 try:
353 try:
348 self._repo.lookup(revision)
354 self._repo.lookup(revision)
349 except error.RepoError:
355 except error.RepoError:
350 self._repo._subsource = source
356 self._repo._subsource = source
351 srcurl = _abssource(self._repo)
357 srcurl = _abssource(self._repo)
352 self._repo.ui.status(_('pulling subrepo %s from %s\n')
358 self._repo.ui.status(_('pulling subrepo %s from %s\n')
353 % (relpath(self), srcurl))
359 % (relpath(self), srcurl))
354 other = hg.repository(self._repo.ui, srcurl)
360 other = hg.repository(self._repo.ui, srcurl)
355 self._repo.pull(other)
361 self._repo.pull(other)
356
362
357 def get(self, state):
363 def get(self, state):
358 self._get(state)
364 self._get(state)
359 source, revision, kind = state
365 source, revision, kind = state
360 self._repo.ui.debug("getting subrepo %s\n" % self._path)
366 self._repo.ui.debug("getting subrepo %s\n" % self._path)
361 hg.clean(self._repo, revision, False)
367 hg.clean(self._repo, revision, False)
362
368
363 def merge(self, state):
369 def merge(self, state):
364 self._get(state)
370 self._get(state)
365 cur = self._repo['.']
371 cur = self._repo['.']
366 dst = self._repo[state[1]]
372 dst = self._repo[state[1]]
367 anc = dst.ancestor(cur)
373 anc = dst.ancestor(cur)
368 if anc == cur:
374 if anc == cur:
369 self._repo.ui.debug("updating subrepo %s\n" % relpath(self))
375 self._repo.ui.debug("updating subrepo %s\n" % relpath(self))
370 hg.update(self._repo, state[1])
376 hg.update(self._repo, state[1])
371 elif anc == dst:
377 elif anc == dst:
372 self._repo.ui.debug("skipping subrepo %s\n" % relpath(self))
378 self._repo.ui.debug("skipping subrepo %s\n" % relpath(self))
373 else:
379 else:
374 self._repo.ui.debug("merging subrepo %s\n" % relpath(self))
380 self._repo.ui.debug("merging subrepo %s\n" % relpath(self))
375 hg.merge(self._repo, state[1], remind=False)
381 hg.merge(self._repo, state[1], remind=False)
376
382
377 def push(self, force):
383 def push(self, force):
378 # push subrepos depth-first for coherent ordering
384 # push subrepos depth-first for coherent ordering
379 c = self._repo['']
385 c = self._repo['']
380 subs = c.substate # only repos that are committed
386 subs = c.substate # only repos that are committed
381 for s in sorted(subs):
387 for s in sorted(subs):
382 if not c.sub(s).push(force):
388 if not c.sub(s).push(force):
383 return False
389 return False
384
390
385 dsturl = _abssource(self._repo, True)
391 dsturl = _abssource(self._repo, True)
386 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
392 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
387 (relpath(self), dsturl))
393 (relpath(self), dsturl))
388 other = hg.repository(self._repo.ui, dsturl)
394 other = hg.repository(self._repo.ui, dsturl)
389 return self._repo.push(other, force)
395 return self._repo.push(other, force)
390
396
391 class svnsubrepo(abstractsubrepo):
397 class svnsubrepo(abstractsubrepo):
392 def __init__(self, ctx, path, state):
398 def __init__(self, ctx, path, state):
393 self._path = path
399 self._path = path
394 self._state = state
400 self._state = state
395 self._ctx = ctx
401 self._ctx = ctx
396 self._ui = ctx._repo.ui
402 self._ui = ctx._repo.ui
397
403
398 def _svncommand(self, commands, filename=''):
404 def _svncommand(self, commands, filename=''):
399 path = os.path.join(self._ctx._repo.origroot, self._path, filename)
405 path = os.path.join(self._ctx._repo.origroot, self._path, filename)
400 cmd = ['svn'] + commands + [path]
406 cmd = ['svn'] + commands + [path]
401 cmd = [util.shellquote(arg) for arg in cmd]
407 cmd = [util.shellquote(arg) for arg in cmd]
402 cmd = util.quotecommand(' '.join(cmd))
408 cmd = util.quotecommand(' '.join(cmd))
403 env = dict(os.environ)
409 env = dict(os.environ)
404 # Avoid localized output, preserve current locale for everything else.
410 # Avoid localized output, preserve current locale for everything else.
405 env['LC_MESSAGES'] = 'C'
411 env['LC_MESSAGES'] = 'C'
406 write, read, err = util.popen3(cmd, env=env, newlines=True)
412 write, read, err = util.popen3(cmd, env=env, newlines=True)
407 retdata = read.read()
413 retdata = read.read()
408 err = err.read().strip()
414 err = err.read().strip()
409 if err:
415 if err:
410 raise util.Abort(err)
416 raise util.Abort(err)
411 return retdata
417 return retdata
412
418
413 def _wcrev(self):
419 def _wcrev(self):
414 output = self._svncommand(['info', '--xml'])
420 output = self._svncommand(['info', '--xml'])
415 doc = xml.dom.minidom.parseString(output)
421 doc = xml.dom.minidom.parseString(output)
416 entries = doc.getElementsByTagName('entry')
422 entries = doc.getElementsByTagName('entry')
417 if not entries:
423 if not entries:
418 return 0
424 return 0
419 return int(entries[0].getAttribute('revision') or 0)
425 return int(entries[0].getAttribute('revision') or 0)
420
426
421 def _wcchanged(self):
427 def _wcchanged(self):
422 """Return (changes, extchanges) where changes is True
428 """Return (changes, extchanges) where changes is True
423 if the working directory was changed, and extchanges is
429 if the working directory was changed, and extchanges is
424 True if any of these changes concern an external entry.
430 True if any of these changes concern an external entry.
425 """
431 """
426 output = self._svncommand(['status', '--xml'])
432 output = self._svncommand(['status', '--xml'])
427 externals, changes = [], []
433 externals, changes = [], []
428 doc = xml.dom.minidom.parseString(output)
434 doc = xml.dom.minidom.parseString(output)
429 for e in doc.getElementsByTagName('entry'):
435 for e in doc.getElementsByTagName('entry'):
430 s = e.getElementsByTagName('wc-status')
436 s = e.getElementsByTagName('wc-status')
431 if not s:
437 if not s:
432 continue
438 continue
433 item = s[0].getAttribute('item')
439 item = s[0].getAttribute('item')
434 props = s[0].getAttribute('props')
440 props = s[0].getAttribute('props')
435 path = e.getAttribute('path')
441 path = e.getAttribute('path')
436 if item == 'external':
442 if item == 'external':
437 externals.append(path)
443 externals.append(path)
438 if (item not in ('', 'normal', 'unversioned', 'external')
444 if (item not in ('', 'normal', 'unversioned', 'external')
439 or props not in ('', 'none')):
445 or props not in ('', 'none')):
440 changes.append(path)
446 changes.append(path)
441 for path in changes:
447 for path in changes:
442 for ext in externals:
448 for ext in externals:
443 if path == ext or path.startswith(ext + os.sep):
449 if path == ext or path.startswith(ext + os.sep):
444 return True, True
450 return True, True
445 return bool(changes), False
451 return bool(changes), False
446
452
447 def dirty(self):
453 def dirty(self):
448 if self._wcrev() == self._state[1] and not self._wcchanged()[0]:
454 if self._wcrev() == self._state[1] and not self._wcchanged()[0]:
449 return False
455 return False
450 return True
456 return True
451
457
452 def commit(self, text, user, date):
458 def commit(self, text, user, date):
453 # user and date are out of our hands since svn is centralized
459 # user and date are out of our hands since svn is centralized
454 changed, extchanged = self._wcchanged()
460 changed, extchanged = self._wcchanged()
455 if not changed:
461 if not changed:
456 return self._wcrev()
462 return self._wcrev()
457 if extchanged:
463 if extchanged:
458 # Do not try to commit externals
464 # Do not try to commit externals
459 raise util.Abort(_('cannot commit svn externals'))
465 raise util.Abort(_('cannot commit svn externals'))
460 commitinfo = self._svncommand(['commit', '-m', text])
466 commitinfo = self._svncommand(['commit', '-m', text])
461 self._ui.status(commitinfo)
467 self._ui.status(commitinfo)
462 newrev = re.search('Committed revision ([0-9]+).', commitinfo)
468 newrev = re.search('Committed revision ([0-9]+).', commitinfo)
463 if not newrev:
469 if not newrev:
464 raise util.Abort(commitinfo.splitlines()[-1])
470 raise util.Abort(commitinfo.splitlines()[-1])
465 newrev = newrev.groups()[0]
471 newrev = newrev.groups()[0]
466 self._ui.status(self._svncommand(['update', '-r', newrev]))
472 self._ui.status(self._svncommand(['update', '-r', newrev]))
467 return newrev
473 return newrev
468
474
469 def remove(self):
475 def remove(self):
470 if self.dirty():
476 if self.dirty():
471 self._ui.warn(_('not removing repo %s because '
477 self._ui.warn(_('not removing repo %s because '
472 'it has changes.\n' % self._path))
478 'it has changes.\n' % self._path))
473 return
479 return
474 self._ui.note(_('removing subrepo %s\n') % self._path)
480 self._ui.note(_('removing subrepo %s\n') % self._path)
475 shutil.rmtree(self._ctx.repo.join(self._path))
481 shutil.rmtree(self._ctx.repo.join(self._path))
476
482
477 def get(self, state):
483 def get(self, state):
478 status = self._svncommand(['checkout', state[0], '--revision', state[1]])
484 status = self._svncommand(['checkout', state[0], '--revision', state[1]])
479 if not re.search('Checked out revision [0-9]+.', status):
485 if not re.search('Checked out revision [0-9]+.', status):
480 raise util.Abort(status.splitlines()[-1])
486 raise util.Abort(status.splitlines()[-1])
481 self._ui.status(status)
487 self._ui.status(status)
482
488
483 def merge(self, state):
489 def merge(self, state):
484 old = int(self._state[1])
490 old = int(self._state[1])
485 new = int(state[1])
491 new = int(state[1])
486 if new > old:
492 if new > old:
487 self.get(state)
493 self.get(state)
488
494
489 def push(self, force):
495 def push(self, force):
490 # push is a no-op for SVN
496 # push is a no-op for SVN
491 return True
497 return True
492
498
493 types = {
499 types = {
494 'hg': hgsubrepo,
500 'hg': hgsubrepo,
495 'svn': svnsubrepo,
501 'svn': svnsubrepo,
496 }
502 }
@@ -1,250 +1,250 b''
1 Show all commands except debug commands
1 Show all commands except debug commands
2 $ hg debugcomplete
2 $ hg debugcomplete
3 add
3 add
4 addremove
4 addremove
5 annotate
5 annotate
6 archive
6 archive
7 backout
7 backout
8 bisect
8 bisect
9 branch
9 branch
10 branches
10 branches
11 bundle
11 bundle
12 cat
12 cat
13 clone
13 clone
14 commit
14 commit
15 copy
15 copy
16 diff
16 diff
17 export
17 export
18 forget
18 forget
19 grep
19 grep
20 heads
20 heads
21 help
21 help
22 identify
22 identify
23 import
23 import
24 incoming
24 incoming
25 init
25 init
26 locate
26 locate
27 log
27 log
28 manifest
28 manifest
29 merge
29 merge
30 outgoing
30 outgoing
31 parents
31 parents
32 paths
32 paths
33 pull
33 pull
34 push
34 push
35 recover
35 recover
36 remove
36 remove
37 rename
37 rename
38 resolve
38 resolve
39 revert
39 revert
40 rollback
40 rollback
41 root
41 root
42 serve
42 serve
43 showconfig
43 showconfig
44 status
44 status
45 summary
45 summary
46 tag
46 tag
47 tags
47 tags
48 tip
48 tip
49 unbundle
49 unbundle
50 update
50 update
51 verify
51 verify
52 version
52 version
53
53
54 Show all commands that start with "a"
54 Show all commands that start with "a"
55 $ hg debugcomplete a
55 $ hg debugcomplete a
56 add
56 add
57 addremove
57 addremove
58 annotate
58 annotate
59 archive
59 archive
60
60
61 Do not show debug commands if there are other candidates
61 Do not show debug commands if there are other candidates
62 $ hg debugcomplete d
62 $ hg debugcomplete d
63 diff
63 diff
64
64
65 Show debug commands if there are no other candidates
65 Show debug commands if there are no other candidates
66 $ hg debugcomplete debug
66 $ hg debugcomplete debug
67 debugancestor
67 debugancestor
68 debugbuilddag
68 debugbuilddag
69 debugcheckstate
69 debugcheckstate
70 debugcommands
70 debugcommands
71 debugcomplete
71 debugcomplete
72 debugconfig
72 debugconfig
73 debugdag
73 debugdag
74 debugdata
74 debugdata
75 debugdate
75 debugdate
76 debugfsinfo
76 debugfsinfo
77 debugindex
77 debugindex
78 debugindexdot
78 debugindexdot
79 debuginstall
79 debuginstall
80 debugpushkey
80 debugpushkey
81 debugrebuildstate
81 debugrebuildstate
82 debugrename
82 debugrename
83 debugrevspec
83 debugrevspec
84 debugsetparents
84 debugsetparents
85 debugstate
85 debugstate
86 debugsub
86 debugsub
87 debugwalk
87 debugwalk
88
88
89 Do not show the alias of a debug command if there are other candidates
89 Do not show the alias of a debug command if there are other candidates
90 (this should hide rawcommit)
90 (this should hide rawcommit)
91 $ hg debugcomplete r
91 $ hg debugcomplete r
92 recover
92 recover
93 remove
93 remove
94 rename
94 rename
95 resolve
95 resolve
96 revert
96 revert
97 rollback
97 rollback
98 root
98 root
99 Show the alias of a debug command if there are no other candidates
99 Show the alias of a debug command if there are no other candidates
100 $ hg debugcomplete rawc
100 $ hg debugcomplete rawc
101
101
102
102
103 Show the global options
103 Show the global options
104 $ hg debugcomplete --options | sort
104 $ hg debugcomplete --options | sort
105 --config
105 --config
106 --cwd
106 --cwd
107 --debug
107 --debug
108 --debugger
108 --debugger
109 --encoding
109 --encoding
110 --encodingmode
110 --encodingmode
111 --help
111 --help
112 --noninteractive
112 --noninteractive
113 --profile
113 --profile
114 --quiet
114 --quiet
115 --repository
115 --repository
116 --time
116 --time
117 --traceback
117 --traceback
118 --verbose
118 --verbose
119 --version
119 --version
120 -R
120 -R
121 -h
121 -h
122 -q
122 -q
123 -v
123 -v
124 -y
124 -y
125
125
126 Show the options for the "serve" command
126 Show the options for the "serve" command
127 $ hg debugcomplete --options serve | sort
127 $ hg debugcomplete --options serve | sort
128 --accesslog
128 --accesslog
129 --address
129 --address
130 --certificate
130 --certificate
131 --config
131 --config
132 --cwd
132 --cwd
133 --daemon
133 --daemon
134 --daemon-pipefds
134 --daemon-pipefds
135 --debug
135 --debug
136 --debugger
136 --debugger
137 --encoding
137 --encoding
138 --encodingmode
138 --encodingmode
139 --errorlog
139 --errorlog
140 --help
140 --help
141 --ipv6
141 --ipv6
142 --name
142 --name
143 --noninteractive
143 --noninteractive
144 --pid-file
144 --pid-file
145 --port
145 --port
146 --prefix
146 --prefix
147 --profile
147 --profile
148 --quiet
148 --quiet
149 --repository
149 --repository
150 --stdio
150 --stdio
151 --style
151 --style
152 --templates
152 --templates
153 --time
153 --time
154 --traceback
154 --traceback
155 --verbose
155 --verbose
156 --version
156 --version
157 --web-conf
157 --web-conf
158 -6
158 -6
159 -A
159 -A
160 -E
160 -E
161 -R
161 -R
162 -a
162 -a
163 -d
163 -d
164 -h
164 -h
165 -n
165 -n
166 -p
166 -p
167 -q
167 -q
168 -t
168 -t
169 -v
169 -v
170 -y
170 -y
171
171
172 Show an error if we use --options with an ambiguous abbreviation
172 Show an error if we use --options with an ambiguous abbreviation
173 $ hg debugcomplete --options s
173 $ hg debugcomplete --options s
174 hg: command 's' is ambiguous:
174 hg: command 's' is ambiguous:
175 serve showconfig status summary
175 serve showconfig status summary
176
176
177 Show all commands + options
177 Show all commands + options
178 $ hg debugcommands
178 $ hg debugcommands
179 add: include, exclude, dry-run
179 add: include, exclude, subrepos, dry-run
180 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, include, exclude
180 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, include, exclude
181 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd
181 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd
182 commit: addremove, close-branch, include, exclude, message, logfile, date, user
182 commit: addremove, close-branch, include, exclude, message, logfile, date, user
183 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
183 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
184 export: output, switch-parent, rev, text, git, nodates
184 export: output, switch-parent, rev, text, git, nodates
185 forget: include, exclude
185 forget: include, exclude
186 init: ssh, remotecmd
186 init: ssh, remotecmd
187 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, style, template, include, exclude
187 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, style, template, include, exclude
188 merge: force, rev, preview
188 merge: force, rev, preview
189 pull: update, force, rev, branch, ssh, remotecmd
189 pull: update, force, rev, branch, ssh, remotecmd
190 push: force, rev, branch, new-branch, ssh, remotecmd
190 push: force, rev, branch, new-branch, ssh, remotecmd
191 remove: after, force, include, exclude
191 remove: after, force, include, exclude
192 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, templates, style, ipv6, certificate
192 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, templates, style, ipv6, certificate
193 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
193 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
194 summary: remote
194 summary: remote
195 update: clean, check, date, rev
195 update: clean, check, date, rev
196 addremove: similarity, include, exclude, dry-run
196 addremove: similarity, include, exclude, dry-run
197 archive: no-decode, prefix, rev, type, include, exclude
197 archive: no-decode, prefix, rev, type, include, exclude
198 backout: merge, parent, rev, include, exclude, message, logfile, date, user
198 backout: merge, parent, rev, include, exclude, message, logfile, date, user
199 bisect: reset, good, bad, skip, command, noupdate
199 bisect: reset, good, bad, skip, command, noupdate
200 branch: force, clean
200 branch: force, clean
201 branches: active, closed
201 branches: active, closed
202 bundle: force, rev, branch, base, all, type, ssh, remotecmd
202 bundle: force, rev, branch, base, all, type, ssh, remotecmd
203 cat: output, rev, decode, include, exclude
203 cat: output, rev, decode, include, exclude
204 copy: after, force, include, exclude, dry-run
204 copy: after, force, include, exclude, dry-run
205 debugancestor:
205 debugancestor:
206 debugbuilddag: mergeable-file, appended-file, overwritten-file, new-file
206 debugbuilddag: mergeable-file, appended-file, overwritten-file, new-file
207 debugcheckstate:
207 debugcheckstate:
208 debugcommands:
208 debugcommands:
209 debugcomplete: options
209 debugcomplete: options
210 debugdag: tags, branches, dots, spaces
210 debugdag: tags, branches, dots, spaces
211 debugdata:
211 debugdata:
212 debugdate: extended
212 debugdate: extended
213 debugfsinfo:
213 debugfsinfo:
214 debugindex:
214 debugindex:
215 debugindexdot:
215 debugindexdot:
216 debuginstall:
216 debuginstall:
217 debugpushkey:
217 debugpushkey:
218 debugrebuildstate: rev
218 debugrebuildstate: rev
219 debugrename: rev
219 debugrename: rev
220 debugrevspec:
220 debugrevspec:
221 debugsetparents:
221 debugsetparents:
222 debugstate: nodates
222 debugstate: nodates
223 debugsub: rev
223 debugsub: rev
224 debugwalk: include, exclude
224 debugwalk: include, exclude
225 grep: print0, all, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
225 grep: print0, all, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
226 heads: rev, topo, active, closed, style, template
226 heads: rev, topo, active, closed, style, template
227 help:
227 help:
228 identify: rev, num, id, branch, tags
228 identify: rev, num, id, branch, tags
229 import: strip, base, force, no-commit, exact, import-branch, message, logfile, date, user, similarity
229 import: strip, base, force, no-commit, exact, import-branch, message, logfile, date, user, similarity
230 incoming: force, newest-first, bundle, rev, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd
230 incoming: force, newest-first, bundle, rev, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd
231 locate: rev, print0, fullpath, include, exclude
231 locate: rev, print0, fullpath, include, exclude
232 manifest: rev
232 manifest: rev
233 outgoing: force, rev, newest-first, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd
233 outgoing: force, rev, newest-first, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd
234 parents: rev, style, template
234 parents: rev, style, template
235 paths:
235 paths:
236 recover:
236 recover:
237 rename: after, force, include, exclude, dry-run
237 rename: after, force, include, exclude, dry-run
238 resolve: all, list, mark, unmark, no-status, include, exclude
238 resolve: all, list, mark, unmark, no-status, include, exclude
239 revert: all, date, rev, no-backup, include, exclude, dry-run
239 revert: all, date, rev, no-backup, include, exclude, dry-run
240 rollback: dry-run
240 rollback: dry-run
241 root:
241 root:
242 showconfig: untrusted
242 showconfig: untrusted
243 tag: force, local, rev, remove, edit, message, date, user
243 tag: force, local, rev, remove, edit, message, date, user
244 tags:
244 tags:
245 tip: patch, git, style, template
245 tip: patch, git, style, template
246 unbundle: update
246 unbundle: update
247 verify:
247 verify:
248 version:
248 version:
249
249
250 $ exit 0
250 $ exit 0
@@ -1,746 +1,750 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 $ hg
3 $ hg
4 Mercurial Distributed SCM
4 Mercurial Distributed SCM
5
5
6 basic commands:
6 basic commands:
7
7
8 add add the specified files on the next commit
8 add add the specified files on the next commit
9 annotate show changeset information by line for each file
9 annotate show changeset information by line for each file
10 clone make a copy of an existing repository
10 clone make a copy of an existing repository
11 commit commit the specified files or all outstanding changes
11 commit commit the specified files or all outstanding changes
12 diff diff repository (or selected files)
12 diff diff repository (or selected files)
13 export dump the header and diffs for one or more changesets
13 export dump the header and diffs for one or more changesets
14 forget forget the specified files on the next commit
14 forget forget the specified files on the next commit
15 init create a new repository in the given directory
15 init create a new repository in the given directory
16 log show revision history of entire repository or files
16 log show revision history of entire repository or files
17 merge merge working directory with another revision
17 merge merge working directory with another revision
18 pull pull changes from the specified source
18 pull pull changes from the specified source
19 push push changes to the specified destination
19 push push changes to the specified destination
20 remove remove the specified files on the next commit
20 remove remove the specified files on the next commit
21 serve start stand-alone webserver
21 serve start stand-alone webserver
22 status show changed files in the working directory
22 status show changed files in the working directory
23 summary summarize working directory state
23 summary summarize working directory state
24 update update working directory (or switch revisions)
24 update update working directory (or switch revisions)
25
25
26 use "hg help" for the full list of commands or "hg -v" for details
26 use "hg help" for the full list of commands or "hg -v" for details
27
27
28 $ hg -q
28 $ hg -q
29 add add the specified files on the next commit
29 add add the specified files on the next commit
30 annotate show changeset information by line for each file
30 annotate show changeset information by line for each file
31 clone make a copy of an existing repository
31 clone make a copy of an existing repository
32 commit commit the specified files or all outstanding changes
32 commit commit the specified files or all outstanding changes
33 diff diff repository (or selected files)
33 diff diff repository (or selected files)
34 export dump the header and diffs for one or more changesets
34 export dump the header and diffs for one or more changesets
35 forget forget the specified files on the next commit
35 forget forget the specified files on the next commit
36 init create a new repository in the given directory
36 init create a new repository in the given directory
37 log show revision history of entire repository or files
37 log show revision history of entire repository or files
38 merge merge working directory with another revision
38 merge merge working directory with another revision
39 pull pull changes from the specified source
39 pull pull changes from the specified source
40 push push changes to the specified destination
40 push push changes to the specified destination
41 remove remove the specified files on the next commit
41 remove remove the specified files on the next commit
42 serve start stand-alone webserver
42 serve start stand-alone webserver
43 status show changed files in the working directory
43 status show changed files in the working directory
44 summary summarize working directory state
44 summary summarize working directory state
45 update update working directory (or switch revisions)
45 update update working directory (or switch revisions)
46
46
47 $ hg help
47 $ hg help
48 Mercurial Distributed SCM
48 Mercurial Distributed SCM
49
49
50 list of commands:
50 list of commands:
51
51
52 add add the specified files on the next commit
52 add add the specified files on the next commit
53 addremove add all new files, delete all missing files
53 addremove add all new files, delete all missing files
54 annotate show changeset information by line for each file
54 annotate show changeset information by line for each file
55 archive create an unversioned archive of a repository revision
55 archive create an unversioned archive of a repository revision
56 backout reverse effect of earlier changeset
56 backout reverse effect of earlier changeset
57 bisect subdivision search of changesets
57 bisect subdivision search of changesets
58 branch set or show the current branch name
58 branch set or show the current branch name
59 branches list repository named branches
59 branches list repository named branches
60 bundle create a changegroup file
60 bundle create a changegroup file
61 cat output the current or given revision of files
61 cat output the current or given revision of files
62 clone make a copy of an existing repository
62 clone make a copy of an existing repository
63 commit commit the specified files or all outstanding changes
63 commit commit the specified files or all outstanding changes
64 copy mark files as copied for the next commit
64 copy mark files as copied for the next commit
65 diff diff repository (or selected files)
65 diff diff repository (or selected files)
66 export dump the header and diffs for one or more changesets
66 export dump the header and diffs for one or more changesets
67 forget forget the specified files on the next commit
67 forget forget the specified files on the next commit
68 grep search for a pattern in specified files and revisions
68 grep search for a pattern in specified files and revisions
69 heads show current repository heads or show branch heads
69 heads show current repository heads or show branch heads
70 help show help for a given topic or a help overview
70 help show help for a given topic or a help overview
71 identify identify the working copy or specified revision
71 identify identify the working copy or specified revision
72 import import an ordered set of patches
72 import import an ordered set of patches
73 incoming show new changesets found in source
73 incoming show new changesets found in source
74 init create a new repository in the given directory
74 init create a new repository in the given directory
75 locate locate files matching specific patterns
75 locate locate files matching specific patterns
76 log show revision history of entire repository or files
76 log show revision history of entire repository or files
77 manifest output the current or given revision of the project manifest
77 manifest output the current or given revision of the project manifest
78 merge merge working directory with another revision
78 merge merge working directory with another revision
79 outgoing show changesets not found in the destination
79 outgoing show changesets not found in the destination
80 parents show the parents of the working directory or revision
80 parents show the parents of the working directory or revision
81 paths show aliases for remote repositories
81 paths show aliases for remote repositories
82 pull pull changes from the specified source
82 pull pull changes from the specified source
83 push push changes to the specified destination
83 push push changes to the specified destination
84 recover roll back an interrupted transaction
84 recover roll back an interrupted transaction
85 remove remove the specified files on the next commit
85 remove remove the specified files on the next commit
86 rename rename files; equivalent of copy + remove
86 rename rename files; equivalent of copy + remove
87 resolve redo merges or set/view the merge status of files
87 resolve redo merges or set/view the merge status of files
88 revert restore individual files or directories to an earlier state
88 revert restore individual files or directories to an earlier state
89 rollback roll back the last transaction (dangerous)
89 rollback roll back the last transaction (dangerous)
90 root print the root (top) of the current working directory
90 root print the root (top) of the current working directory
91 serve start stand-alone webserver
91 serve start stand-alone webserver
92 showconfig show combined config settings from all hgrc files
92 showconfig show combined config settings from all hgrc files
93 status show changed files in the working directory
93 status show changed files in the working directory
94 summary summarize working directory state
94 summary summarize working directory state
95 tag add one or more tags for the current or given revision
95 tag add one or more tags for the current or given revision
96 tags list repository tags
96 tags list repository tags
97 tip show the tip revision
97 tip show the tip revision
98 unbundle apply one or more changegroup files
98 unbundle apply one or more changegroup files
99 update update working directory (or switch revisions)
99 update update working directory (or switch revisions)
100 verify verify the integrity of the repository
100 verify verify the integrity of the repository
101 version output version and copyright information
101 version output version and copyright information
102
102
103 additional help topics:
103 additional help topics:
104
104
105 config Configuration Files
105 config Configuration Files
106 dates Date Formats
106 dates Date Formats
107 patterns File Name Patterns
107 patterns File Name Patterns
108 environment Environment Variables
108 environment Environment Variables
109 revisions Specifying Single Revisions
109 revisions Specifying Single Revisions
110 multirevs Specifying Multiple Revisions
110 multirevs Specifying Multiple Revisions
111 revsets Specifying Revision Sets
111 revsets Specifying Revision Sets
112 diffs Diff Formats
112 diffs Diff Formats
113 templating Template Usage
113 templating Template Usage
114 urls URL Paths
114 urls URL Paths
115 extensions Using additional features
115 extensions Using additional features
116 hgweb Configuring hgweb
116 hgweb Configuring hgweb
117 glossary Glossary
117 glossary Glossary
118
118
119 use "hg -v help" to show aliases and global options
119 use "hg -v help" to show aliases and global options
120
120
121 $ hg -q help
121 $ hg -q help
122 add add the specified files on the next commit
122 add add the specified files on the next commit
123 addremove add all new files, delete all missing files
123 addremove add all new files, delete all missing files
124 annotate show changeset information by line for each file
124 annotate show changeset information by line for each file
125 archive create an unversioned archive of a repository revision
125 archive create an unversioned archive of a repository revision
126 backout reverse effect of earlier changeset
126 backout reverse effect of earlier changeset
127 bisect subdivision search of changesets
127 bisect subdivision search of changesets
128 branch set or show the current branch name
128 branch set or show the current branch name
129 branches list repository named branches
129 branches list repository named branches
130 bundle create a changegroup file
130 bundle create a changegroup file
131 cat output the current or given revision of files
131 cat output the current or given revision of files
132 clone make a copy of an existing repository
132 clone make a copy of an existing repository
133 commit commit the specified files or all outstanding changes
133 commit commit the specified files or all outstanding changes
134 copy mark files as copied for the next commit
134 copy mark files as copied for the next commit
135 diff diff repository (or selected files)
135 diff diff repository (or selected files)
136 export dump the header and diffs for one or more changesets
136 export dump the header and diffs for one or more changesets
137 forget forget the specified files on the next commit
137 forget forget the specified files on the next commit
138 grep search for a pattern in specified files and revisions
138 grep search for a pattern in specified files and revisions
139 heads show current repository heads or show branch heads
139 heads show current repository heads or show branch heads
140 help show help for a given topic or a help overview
140 help show help for a given topic or a help overview
141 identify identify the working copy or specified revision
141 identify identify the working copy or specified revision
142 import import an ordered set of patches
142 import import an ordered set of patches
143 incoming show new changesets found in source
143 incoming show new changesets found in source
144 init create a new repository in the given directory
144 init create a new repository in the given directory
145 locate locate files matching specific patterns
145 locate locate files matching specific patterns
146 log show revision history of entire repository or files
146 log show revision history of entire repository or files
147 manifest output the current or given revision of the project manifest
147 manifest output the current or given revision of the project manifest
148 merge merge working directory with another revision
148 merge merge working directory with another revision
149 outgoing show changesets not found in the destination
149 outgoing show changesets not found in the destination
150 parents show the parents of the working directory or revision
150 parents show the parents of the working directory or revision
151 paths show aliases for remote repositories
151 paths show aliases for remote repositories
152 pull pull changes from the specified source
152 pull pull changes from the specified source
153 push push changes to the specified destination
153 push push changes to the specified destination
154 recover roll back an interrupted transaction
154 recover roll back an interrupted transaction
155 remove remove the specified files on the next commit
155 remove remove the specified files on the next commit
156 rename rename files; equivalent of copy + remove
156 rename rename files; equivalent of copy + remove
157 resolve redo merges or set/view the merge status of files
157 resolve redo merges or set/view the merge status of files
158 revert restore individual files or directories to an earlier state
158 revert restore individual files or directories to an earlier state
159 rollback roll back the last transaction (dangerous)
159 rollback roll back the last transaction (dangerous)
160 root print the root (top) of the current working directory
160 root print the root (top) of the current working directory
161 serve start stand-alone webserver
161 serve start stand-alone webserver
162 showconfig show combined config settings from all hgrc files
162 showconfig show combined config settings from all hgrc files
163 status show changed files in the working directory
163 status show changed files in the working directory
164 summary summarize working directory state
164 summary summarize working directory state
165 tag add one or more tags for the current or given revision
165 tag add one or more tags for the current or given revision
166 tags list repository tags
166 tags list repository tags
167 tip show the tip revision
167 tip show the tip revision
168 unbundle apply one or more changegroup files
168 unbundle apply one or more changegroup files
169 update update working directory (or switch revisions)
169 update update working directory (or switch revisions)
170 verify verify the integrity of the repository
170 verify verify the integrity of the repository
171 version output version and copyright information
171 version output version and copyright information
172
172
173 additional help topics:
173 additional help topics:
174
174
175 config Configuration Files
175 config Configuration Files
176 dates Date Formats
176 dates Date Formats
177 patterns File Name Patterns
177 patterns File Name Patterns
178 environment Environment Variables
178 environment Environment Variables
179 revisions Specifying Single Revisions
179 revisions Specifying Single Revisions
180 multirevs Specifying Multiple Revisions
180 multirevs Specifying Multiple Revisions
181 revsets Specifying Revision Sets
181 revsets Specifying Revision Sets
182 diffs Diff Formats
182 diffs Diff Formats
183 templating Template Usage
183 templating Template Usage
184 urls URL Paths
184 urls URL Paths
185 extensions Using additional features
185 extensions Using additional features
186 hgweb Configuring hgweb
186 hgweb Configuring hgweb
187 glossary Glossary
187 glossary Glossary
188
188
189 Test short command list with verbose option
189 Test short command list with verbose option
190
190
191 $ hg -v help shortlist
191 $ hg -v help shortlist
192 Mercurial Distributed SCM \(version .*?\)
192 Mercurial Distributed SCM \(version .*?\)
193
193
194 Copyright (C) 2005-2010 Matt Mackall <mpm@selenic.com> and others
194 Copyright (C) 2005-2010 Matt Mackall <mpm@selenic.com> and others
195 This is free software; see the source for copying conditions. There is NO
195 This is free software; see the source for copying conditions. There is NO
196 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
196 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
197
197
198 basic commands:
198 basic commands:
199
199
200 add:
200 add:
201 add the specified files on the next commit
201 add the specified files on the next commit
202 annotate, blame:
202 annotate, blame:
203 show changeset information by line for each file
203 show changeset information by line for each file
204 clone:
204 clone:
205 make a copy of an existing repository
205 make a copy of an existing repository
206 commit, ci:
206 commit, ci:
207 commit the specified files or all outstanding changes
207 commit the specified files or all outstanding changes
208 diff:
208 diff:
209 diff repository (or selected files)
209 diff repository (or selected files)
210 export:
210 export:
211 dump the header and diffs for one or more changesets
211 dump the header and diffs for one or more changesets
212 forget:
212 forget:
213 forget the specified files on the next commit
213 forget the specified files on the next commit
214 init:
214 init:
215 create a new repository in the given directory
215 create a new repository in the given directory
216 log, history:
216 log, history:
217 show revision history of entire repository or files
217 show revision history of entire repository or files
218 merge:
218 merge:
219 merge working directory with another revision
219 merge working directory with another revision
220 pull:
220 pull:
221 pull changes from the specified source
221 pull changes from the specified source
222 push:
222 push:
223 push changes to the specified destination
223 push changes to the specified destination
224 remove, rm:
224 remove, rm:
225 remove the specified files on the next commit
225 remove the specified files on the next commit
226 serve:
226 serve:
227 start stand-alone webserver
227 start stand-alone webserver
228 status, st:
228 status, st:
229 show changed files in the working directory
229 show changed files in the working directory
230 summary, sum:
230 summary, sum:
231 summarize working directory state
231 summarize working directory state
232 update, up, checkout, co:
232 update, up, checkout, co:
233 update working directory (or switch revisions)
233 update working directory (or switch revisions)
234
234
235 global options:
235 global options:
236 -R --repository REPO repository root directory or name of overlay bundle
236 -R --repository REPO repository root directory or name of overlay bundle
237 file
237 file
238 --cwd DIR change working directory
238 --cwd DIR change working directory
239 -y --noninteractive do not prompt, assume 'yes' for any required answers
239 -y --noninteractive do not prompt, assume 'yes' for any required answers
240 -q --quiet suppress output
240 -q --quiet suppress output
241 -v --verbose enable additional output
241 -v --verbose enable additional output
242 --config CONFIG [+] set/override config option (use 'section.name=value')
242 --config CONFIG [+] set/override config option (use 'section.name=value')
243 --debug enable debugging output
243 --debug enable debugging output
244 --debugger start debugger
244 --debugger start debugger
245 --encoding ENCODE set the charset encoding (default: ascii)
245 --encoding ENCODE set the charset encoding (default: ascii)
246 --encodingmode MODE set the charset encoding mode (default: strict)
246 --encodingmode MODE set the charset encoding mode (default: strict)
247 --traceback always print a traceback on exception
247 --traceback always print a traceback on exception
248 --time time how long the command takes
248 --time time how long the command takes
249 --profile print command execution profile
249 --profile print command execution profile
250 --version output version information and exit
250 --version output version information and exit
251 -h --help display help and exit
251 -h --help display help and exit
252
252
253 [+] marked option can be specified multiple times
253 [+] marked option can be specified multiple times
254
254
255 use "hg help" for the full list of commands
255 use "hg help" for the full list of commands
256
256
257 $ hg add -h
257 $ hg add -h
258 hg add [OPTION]... [FILE]...
258 hg add [OPTION]... [FILE]...
259
259
260 add the specified files on the next commit
260 add the specified files on the next commit
261
261
262 Schedule files to be version controlled and added to the repository.
262 Schedule files to be version controlled and added to the repository.
263
263
264 The files will be added to the repository at the next commit. To undo an
264 The files will be added to the repository at the next commit. To undo an
265 add before that, see "hg forget".
265 add before that, see "hg forget".
266
266
267 If no names are given, add all files to the repository.
267 If no names are given, add all files to the repository.
268
268
269 Returns 0 if all files are successfully added.
269 Returns 0 if all files are successfully added.
270
270
271 use "hg -v help add" to show verbose help
271 use "hg -v help add" to show verbose help
272
272
273 options:
273 options:
274
274
275 -I --include PATTERN [+] include names matching the given patterns
275 -I --include PATTERN [+] include names matching the given patterns
276 -X --exclude PATTERN [+] exclude names matching the given patterns
276 -X --exclude PATTERN [+] exclude names matching the given patterns
277 -S --subrepos recurse into subrepositories
277 -n --dry-run do not perform actions, just print output
278 -n --dry-run do not perform actions, just print output
278
279
279 [+] marked option can be specified multiple times
280 [+] marked option can be specified multiple times
280
281
281 use "hg -v help add" to show global options
282 use "hg -v help add" to show global options
282
283
283 Verbose help for add
284 Verbose help for add
284
285
285 $ hg add -hv
286 $ hg add -hv
286 hg add [OPTION]... [FILE]...
287 hg add [OPTION]... [FILE]...
287
288
288 add the specified files on the next commit
289 add the specified files on the next commit
289
290
290 Schedule files to be version controlled and added to the repository.
291 Schedule files to be version controlled and added to the repository.
291
292
292 The files will be added to the repository at the next commit. To undo an
293 The files will be added to the repository at the next commit. To undo an
293 add before that, see "hg forget".
294 add before that, see "hg forget".
294
295
295 If no names are given, add all files to the repository.
296 If no names are given, add all files to the repository.
296
297
297 An example showing how new (unknown) files are added automatically by "hg
298 An example showing how new (unknown) files are added automatically by "hg
298 add":
299 add":
299
300
300 $ ls
301 $ ls
301 foo.c
302 foo.c
302 $ hg status
303 $ hg status
303 ? foo.c
304 ? foo.c
304 $ hg add
305 $ hg add
305 adding foo.c
306 adding foo.c
306 $ hg status
307 $ hg status
307 A foo.c
308 A foo.c
308
309
309 Returns 0 if all files are successfully added.
310 Returns 0 if all files are successfully added.
310
311
311 options:
312 options:
312
313
313 -I --include PATTERN [+] include names matching the given patterns
314 -I --include PATTERN [+] include names matching the given patterns
314 -X --exclude PATTERN [+] exclude names matching the given patterns
315 -X --exclude PATTERN [+] exclude names matching the given patterns
316 -S --subrepos recurse into subrepositories
315 -n --dry-run do not perform actions, just print output
317 -n --dry-run do not perform actions, just print output
316
318
317 global options:
319 global options:
318 -R --repository REPO repository root directory or name of overlay bundle
320 -R --repository REPO repository root directory or name of overlay bundle
319 file
321 file
320 --cwd DIR change working directory
322 --cwd DIR change working directory
321 -y --noninteractive do not prompt, assume 'yes' for any required
323 -y --noninteractive do not prompt, assume 'yes' for any required
322 answers
324 answers
323 -q --quiet suppress output
325 -q --quiet suppress output
324 -v --verbose enable additional output
326 -v --verbose enable additional output
325 --config CONFIG [+] set/override config option (use
327 --config CONFIG [+] set/override config option (use
326 'section.name=value')
328 'section.name=value')
327 --debug enable debugging output
329 --debug enable debugging output
328 --debugger start debugger
330 --debugger start debugger
329 --encoding ENCODE set the charset encoding (default: ascii)
331 --encoding ENCODE set the charset encoding (default: ascii)
330 --encodingmode MODE set the charset encoding mode (default: strict)
332 --encodingmode MODE set the charset encoding mode (default: strict)
331 --traceback always print a traceback on exception
333 --traceback always print a traceback on exception
332 --time time how long the command takes
334 --time time how long the command takes
333 --profile print command execution profile
335 --profile print command execution profile
334 --version output version information and exit
336 --version output version information and exit
335 -h --help display help and exit
337 -h --help display help and exit
336
338
337 [+] marked option can be specified multiple times
339 [+] marked option can be specified multiple times
338
340
339 Test help option with version option
341 Test help option with version option
340
342
341 $ hg add -h --version
343 $ hg add -h --version
342 Mercurial Distributed SCM \(version .+?\)
344 Mercurial Distributed SCM \(version .+?\)
343
345
344 Copyright (C) 2005-2010 Matt Mackall <mpm@selenic.com> and others
346 Copyright (C) 2005-2010 Matt Mackall <mpm@selenic.com> and others
345 This is free software; see the source for copying conditions. There is NO
347 This is free software; see the source for copying conditions. There is NO
346 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
348 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
347
349
348 hg add [OPTION]... [FILE]...
350 hg add [OPTION]... [FILE]...
349
351
350 add the specified files on the next commit
352 add the specified files on the next commit
351
353
352 Schedule files to be version controlled and added to the repository.
354 Schedule files to be version controlled and added to the repository.
353
355
354 The files will be added to the repository at the next commit. To undo an
356 The files will be added to the repository at the next commit. To undo an
355 add before that, see "hg forget".
357 add before that, see "hg forget".
356
358
357 If no names are given, add all files to the repository.
359 If no names are given, add all files to the repository.
358
360
359 Returns 0 if all files are successfully added.
361 Returns 0 if all files are successfully added.
360
362
361 use "hg -v help add" to show verbose help
363 use "hg -v help add" to show verbose help
362
364
363 options:
365 options:
364
366
365 -I --include PATTERN [+] include names matching the given patterns
367 -I --include PATTERN [+] include names matching the given patterns
366 -X --exclude PATTERN [+] exclude names matching the given patterns
368 -X --exclude PATTERN [+] exclude names matching the given patterns
369 -S --subrepos recurse into subrepositories
367 -n --dry-run do not perform actions, just print output
370 -n --dry-run do not perform actions, just print output
368
371
369 [+] marked option can be specified multiple times
372 [+] marked option can be specified multiple times
370
373
371 use "hg -v help add" to show global options
374 use "hg -v help add" to show global options
372
375
373 $ hg add --skjdfks
376 $ hg add --skjdfks
374 hg add: option --skjdfks not recognized
377 hg add: option --skjdfks not recognized
375 hg add [OPTION]... [FILE]...
378 hg add [OPTION]... [FILE]...
376
379
377 add the specified files on the next commit
380 add the specified files on the next commit
378
381
379 Schedule files to be version controlled and added to the repository.
382 Schedule files to be version controlled and added to the repository.
380
383
381 The files will be added to the repository at the next commit. To undo an
384 The files will be added to the repository at the next commit. To undo an
382 add before that, see "hg forget".
385 add before that, see "hg forget".
383
386
384 If no names are given, add all files to the repository.
387 If no names are given, add all files to the repository.
385
388
386 Returns 0 if all files are successfully added.
389 Returns 0 if all files are successfully added.
387
390
388 use "hg -v help add" to show verbose help
391 use "hg -v help add" to show verbose help
389
392
390 options:
393 options:
391
394
392 -I --include PATTERN [+] include names matching the given patterns
395 -I --include PATTERN [+] include names matching the given patterns
393 -X --exclude PATTERN [+] exclude names matching the given patterns
396 -X --exclude PATTERN [+] exclude names matching the given patterns
397 -S --subrepos recurse into subrepositories
394 -n --dry-run do not perform actions, just print output
398 -n --dry-run do not perform actions, just print output
395
399
396 [+] marked option can be specified multiple times
400 [+] marked option can be specified multiple times
397
401
398 use "hg -v help add" to show global options
402 use "hg -v help add" to show global options
399
403
400 Test ambiguous command help
404 Test ambiguous command help
401
405
402 $ hg help ad
406 $ hg help ad
403 list of commands:
407 list of commands:
404
408
405 add add the specified files on the next commit
409 add add the specified files on the next commit
406 addremove add all new files, delete all missing files
410 addremove add all new files, delete all missing files
407
411
408 use "hg -v help ad" to show aliases and global options
412 use "hg -v help ad" to show aliases and global options
409
413
410 Test command without options
414 Test command without options
411
415
412 $ hg help verify
416 $ hg help verify
413 hg verify
417 hg verify
414
418
415 verify the integrity of the repository
419 verify the integrity of the repository
416
420
417 Verify the integrity of the current repository.
421 Verify the integrity of the current repository.
418
422
419 This will perform an extensive check of the repository's integrity,
423 This will perform an extensive check of the repository's integrity,
420 validating the hashes and checksums of each entry in the changelog,
424 validating the hashes and checksums of each entry in the changelog,
421 manifest, and tracked files, as well as the integrity of their crosslinks
425 manifest, and tracked files, as well as the integrity of their crosslinks
422 and indices.
426 and indices.
423
427
424 Returns 0 on success, 1 if errors are encountered.
428 Returns 0 on success, 1 if errors are encountered.
425
429
426 use "hg -v help verify" to show global options
430 use "hg -v help verify" to show global options
427
431
428 $ hg help diff
432 $ hg help diff
429 hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...
433 hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...
430
434
431 diff repository (or selected files)
435 diff repository (or selected files)
432
436
433 Show differences between revisions for the specified files.
437 Show differences between revisions for the specified files.
434
438
435 Differences between files are shown using the unified diff format.
439 Differences between files are shown using the unified diff format.
436
440
437 NOTE: diff may generate unexpected results for merges, as it will default
441 NOTE: diff may generate unexpected results for merges, as it will default
438 to comparing against the working directory's first parent changeset if no
442 to comparing against the working directory's first parent changeset if no
439 revisions are specified.
443 revisions are specified.
440
444
441 When two revision arguments are given, then changes are shown between
445 When two revision arguments are given, then changes are shown between
442 those revisions. If only one revision is specified then that revision is
446 those revisions. If only one revision is specified then that revision is
443 compared to the working directory, and, when no revisions are specified,
447 compared to the working directory, and, when no revisions are specified,
444 the working directory files are compared to its parent.
448 the working directory files are compared to its parent.
445
449
446 Alternatively you can specify -c/--change with a revision to see the
450 Alternatively you can specify -c/--change with a revision to see the
447 changes in that changeset relative to its first parent.
451 changes in that changeset relative to its first parent.
448
452
449 Without the -a/--text option, diff will avoid generating diffs of files it
453 Without the -a/--text option, diff will avoid generating diffs of files it
450 detects as binary. With -a, diff will generate a diff anyway, probably
454 detects as binary. With -a, diff will generate a diff anyway, probably
451 with undesirable results.
455 with undesirable results.
452
456
453 Use the -g/--git option to generate diffs in the git extended diff format.
457 Use the -g/--git option to generate diffs in the git extended diff format.
454 For more information, read "hg help diffs".
458 For more information, read "hg help diffs".
455
459
456 Returns 0 on success.
460 Returns 0 on success.
457
461
458 options:
462 options:
459
463
460 -r --rev REV [+] revision
464 -r --rev REV [+] revision
461 -c --change REV change made by revision
465 -c --change REV change made by revision
462 -a --text treat all files as text
466 -a --text treat all files as text
463 -g --git use git extended diff format
467 -g --git use git extended diff format
464 --nodates omit dates from diff headers
468 --nodates omit dates from diff headers
465 -p --show-function show which function each change is in
469 -p --show-function show which function each change is in
466 --reverse produce a diff that undoes the changes
470 --reverse produce a diff that undoes the changes
467 -w --ignore-all-space ignore white space when comparing lines
471 -w --ignore-all-space ignore white space when comparing lines
468 -b --ignore-space-change ignore changes in the amount of white space
472 -b --ignore-space-change ignore changes in the amount of white space
469 -B --ignore-blank-lines ignore changes whose lines are all blank
473 -B --ignore-blank-lines ignore changes whose lines are all blank
470 -U --unified NUM number of lines of context to show
474 -U --unified NUM number of lines of context to show
471 --stat output diffstat-style summary of changes
475 --stat output diffstat-style summary of changes
472 -I --include PATTERN [+] include names matching the given patterns
476 -I --include PATTERN [+] include names matching the given patterns
473 -X --exclude PATTERN [+] exclude names matching the given patterns
477 -X --exclude PATTERN [+] exclude names matching the given patterns
474 -S --subrepos recurse into subrepositories
478 -S --subrepos recurse into subrepositories
475
479
476 [+] marked option can be specified multiple times
480 [+] marked option can be specified multiple times
477
481
478 use "hg -v help diff" to show global options
482 use "hg -v help diff" to show global options
479
483
480 $ hg help status
484 $ hg help status
481 hg status [OPTION]... [FILE]...
485 hg status [OPTION]... [FILE]...
482
486
483 aliases: st
487 aliases: st
484
488
485 show changed files in the working directory
489 show changed files in the working directory
486
490
487 Show status of files in the repository. If names are given, only files
491 Show status of files in the repository. If names are given, only files
488 that match are shown. Files that are clean or ignored or the source of a
492 that match are shown. Files that are clean or ignored or the source of a
489 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
493 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
490 -C/--copies or -A/--all are given. Unless options described with "show
494 -C/--copies or -A/--all are given. Unless options described with "show
491 only ..." are given, the options -mardu are used.
495 only ..." are given, the options -mardu are used.
492
496
493 Option -q/--quiet hides untracked (unknown and ignored) files unless
497 Option -q/--quiet hides untracked (unknown and ignored) files unless
494 explicitly requested with -u/--unknown or -i/--ignored.
498 explicitly requested with -u/--unknown or -i/--ignored.
495
499
496 NOTE: status may appear to disagree with diff if permissions have changed
500 NOTE: status may appear to disagree with diff if permissions have changed
497 or a merge has occurred. The standard diff format does not report
501 or a merge has occurred. The standard diff format does not report
498 permission changes and diff only reports changes relative to one merge
502 permission changes and diff only reports changes relative to one merge
499 parent.
503 parent.
500
504
501 If one revision is given, it is used as the base revision. If two
505 If one revision is given, it is used as the base revision. If two
502 revisions are given, the differences between them are shown. The --change
506 revisions are given, the differences between them are shown. The --change
503 option can also be used as a shortcut to list the changed files of a
507 option can also be used as a shortcut to list the changed files of a
504 revision from its first parent.
508 revision from its first parent.
505
509
506 The codes used to show the status of files are:
510 The codes used to show the status of files are:
507
511
508 M = modified
512 M = modified
509 A = added
513 A = added
510 R = removed
514 R = removed
511 C = clean
515 C = clean
512 ! = missing (deleted by non-hg command, but still tracked)
516 ! = missing (deleted by non-hg command, but still tracked)
513 ? = not tracked
517 ? = not tracked
514 I = ignored
518 I = ignored
515 = origin of the previous file listed as A (added)
519 = origin of the previous file listed as A (added)
516
520
517 Returns 0 on success.
521 Returns 0 on success.
518
522
519 options:
523 options:
520
524
521 -A --all show status of all files
525 -A --all show status of all files
522 -m --modified show only modified files
526 -m --modified show only modified files
523 -a --added show only added files
527 -a --added show only added files
524 -r --removed show only removed files
528 -r --removed show only removed files
525 -d --deleted show only deleted (but tracked) files
529 -d --deleted show only deleted (but tracked) files
526 -c --clean show only files without changes
530 -c --clean show only files without changes
527 -u --unknown show only unknown (not tracked) files
531 -u --unknown show only unknown (not tracked) files
528 -i --ignored show only ignored files
532 -i --ignored show only ignored files
529 -n --no-status hide status prefix
533 -n --no-status hide status prefix
530 -C --copies show source of copied files
534 -C --copies show source of copied files
531 -0 --print0 end filenames with NUL, for use with xargs
535 -0 --print0 end filenames with NUL, for use with xargs
532 --rev REV [+] show difference from revision
536 --rev REV [+] show difference from revision
533 --change REV list the changed files of a revision
537 --change REV list the changed files of a revision
534 -I --include PATTERN [+] include names matching the given patterns
538 -I --include PATTERN [+] include names matching the given patterns
535 -X --exclude PATTERN [+] exclude names matching the given patterns
539 -X --exclude PATTERN [+] exclude names matching the given patterns
536 -S --subrepos recurse into subrepositories
540 -S --subrepos recurse into subrepositories
537
541
538 [+] marked option can be specified multiple times
542 [+] marked option can be specified multiple times
539
543
540 use "hg -v help status" to show global options
544 use "hg -v help status" to show global options
541
545
542 $ hg -q help status
546 $ hg -q help status
543 hg status [OPTION]... [FILE]...
547 hg status [OPTION]... [FILE]...
544
548
545 show changed files in the working directory
549 show changed files in the working directory
546
550
547 $ hg help foo
551 $ hg help foo
548 hg: unknown command 'foo'
552 hg: unknown command 'foo'
549 Mercurial Distributed SCM
553 Mercurial Distributed SCM
550
554
551 basic commands:
555 basic commands:
552
556
553 add add the specified files on the next commit
557 add add the specified files on the next commit
554 annotate show changeset information by line for each file
558 annotate show changeset information by line for each file
555 clone make a copy of an existing repository
559 clone make a copy of an existing repository
556 commit commit the specified files or all outstanding changes
560 commit commit the specified files or all outstanding changes
557 diff diff repository (or selected files)
561 diff diff repository (or selected files)
558 export dump the header and diffs for one or more changesets
562 export dump the header and diffs for one or more changesets
559 forget forget the specified files on the next commit
563 forget forget the specified files on the next commit
560 init create a new repository in the given directory
564 init create a new repository in the given directory
561 log show revision history of entire repository or files
565 log show revision history of entire repository or files
562 merge merge working directory with another revision
566 merge merge working directory with another revision
563 pull pull changes from the specified source
567 pull pull changes from the specified source
564 push push changes to the specified destination
568 push push changes to the specified destination
565 remove remove the specified files on the next commit
569 remove remove the specified files on the next commit
566 serve start stand-alone webserver
570 serve start stand-alone webserver
567 status show changed files in the working directory
571 status show changed files in the working directory
568 summary summarize working directory state
572 summary summarize working directory state
569 update update working directory (or switch revisions)
573 update update working directory (or switch revisions)
570
574
571 use "hg help" for the full list of commands or "hg -v" for details
575 use "hg help" for the full list of commands or "hg -v" for details
572
576
573 $ hg skjdfks
577 $ hg skjdfks
574 hg: unknown command 'skjdfks'
578 hg: unknown command 'skjdfks'
575 Mercurial Distributed SCM
579 Mercurial Distributed SCM
576
580
577 basic commands:
581 basic commands:
578
582
579 add add the specified files on the next commit
583 add add the specified files on the next commit
580 annotate show changeset information by line for each file
584 annotate show changeset information by line for each file
581 clone make a copy of an existing repository
585 clone make a copy of an existing repository
582 commit commit the specified files or all outstanding changes
586 commit commit the specified files or all outstanding changes
583 diff diff repository (or selected files)
587 diff diff repository (or selected files)
584 export dump the header and diffs for one or more changesets
588 export dump the header and diffs for one or more changesets
585 forget forget the specified files on the next commit
589 forget forget the specified files on the next commit
586 init create a new repository in the given directory
590 init create a new repository in the given directory
587 log show revision history of entire repository or files
591 log show revision history of entire repository or files
588 merge merge working directory with another revision
592 merge merge working directory with another revision
589 pull pull changes from the specified source
593 pull pull changes from the specified source
590 push push changes to the specified destination
594 push push changes to the specified destination
591 remove remove the specified files on the next commit
595 remove remove the specified files on the next commit
592 serve start stand-alone webserver
596 serve start stand-alone webserver
593 status show changed files in the working directory
597 status show changed files in the working directory
594 summary summarize working directory state
598 summary summarize working directory state
595 update update working directory (or switch revisions)
599 update update working directory (or switch revisions)
596
600
597 use "hg help" for the full list of commands or "hg -v" for details
601 use "hg help" for the full list of commands or "hg -v" for details
598
602
599 $ cat > helpext.py <<EOF
603 $ cat > helpext.py <<EOF
600 > import os
604 > import os
601 > from mercurial import commands
605 > from mercurial import commands
602 >
606 >
603 > def nohelp(ui, *args, **kwargs):
607 > def nohelp(ui, *args, **kwargs):
604 > pass
608 > pass
605 >
609 >
606 > cmdtable = {
610 > cmdtable = {
607 > "nohelp": (nohelp, [], "hg nohelp"),
611 > "nohelp": (nohelp, [], "hg nohelp"),
608 > }
612 > }
609 >
613 >
610 > commands.norepo += ' nohelp'
614 > commands.norepo += ' nohelp'
611 > EOF
615 > EOF
612 $ echo '[extensions]' >> $HGRCPATH
616 $ echo '[extensions]' >> $HGRCPATH
613 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
617 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
614
618
615 Test command with no help text
619 Test command with no help text
616
620
617 $ hg help nohelp
621 $ hg help nohelp
618 hg nohelp
622 hg nohelp
619
623
620 (no help text available)
624 (no help text available)
621
625
622 use "hg -v help nohelp" to show global options
626 use "hg -v help nohelp" to show global options
623
627
624 Test that default list of commands omits extension commands
628 Test that default list of commands omits extension commands
625
629
626 $ hg help
630 $ hg help
627 Mercurial Distributed SCM
631 Mercurial Distributed SCM
628
632
629 list of commands:
633 list of commands:
630
634
631 add add the specified files on the next commit
635 add add the specified files on the next commit
632 addremove add all new files, delete all missing files
636 addremove add all new files, delete all missing files
633 annotate show changeset information by line for each file
637 annotate show changeset information by line for each file
634 archive create an unversioned archive of a repository revision
638 archive create an unversioned archive of a repository revision
635 backout reverse effect of earlier changeset
639 backout reverse effect of earlier changeset
636 bisect subdivision search of changesets
640 bisect subdivision search of changesets
637 branch set or show the current branch name
641 branch set or show the current branch name
638 branches list repository named branches
642 branches list repository named branches
639 bundle create a changegroup file
643 bundle create a changegroup file
640 cat output the current or given revision of files
644 cat output the current or given revision of files
641 clone make a copy of an existing repository
645 clone make a copy of an existing repository
642 commit commit the specified files or all outstanding changes
646 commit commit the specified files or all outstanding changes
643 copy mark files as copied for the next commit
647 copy mark files as copied for the next commit
644 diff diff repository (or selected files)
648 diff diff repository (or selected files)
645 export dump the header and diffs for one or more changesets
649 export dump the header and diffs for one or more changesets
646 forget forget the specified files on the next commit
650 forget forget the specified files on the next commit
647 grep search for a pattern in specified files and revisions
651 grep search for a pattern in specified files and revisions
648 heads show current repository heads or show branch heads
652 heads show current repository heads or show branch heads
649 help show help for a given topic or a help overview
653 help show help for a given topic or a help overview
650 identify identify the working copy or specified revision
654 identify identify the working copy or specified revision
651 import import an ordered set of patches
655 import import an ordered set of patches
652 incoming show new changesets found in source
656 incoming show new changesets found in source
653 init create a new repository in the given directory
657 init create a new repository in the given directory
654 locate locate files matching specific patterns
658 locate locate files matching specific patterns
655 log show revision history of entire repository or files
659 log show revision history of entire repository or files
656 manifest output the current or given revision of the project manifest
660 manifest output the current or given revision of the project manifest
657 merge merge working directory with another revision
661 merge merge working directory with another revision
658 outgoing show changesets not found in the destination
662 outgoing show changesets not found in the destination
659 parents show the parents of the working directory or revision
663 parents show the parents of the working directory or revision
660 paths show aliases for remote repositories
664 paths show aliases for remote repositories
661 pull pull changes from the specified source
665 pull pull changes from the specified source
662 push push changes to the specified destination
666 push push changes to the specified destination
663 recover roll back an interrupted transaction
667 recover roll back an interrupted transaction
664 remove remove the specified files on the next commit
668 remove remove the specified files on the next commit
665 rename rename files; equivalent of copy + remove
669 rename rename files; equivalent of copy + remove
666 resolve redo merges or set/view the merge status of files
670 resolve redo merges or set/view the merge status of files
667 revert restore individual files or directories to an earlier state
671 revert restore individual files or directories to an earlier state
668 rollback roll back the last transaction (dangerous)
672 rollback roll back the last transaction (dangerous)
669 root print the root (top) of the current working directory
673 root print the root (top) of the current working directory
670 serve start stand-alone webserver
674 serve start stand-alone webserver
671 showconfig show combined config settings from all hgrc files
675 showconfig show combined config settings from all hgrc files
672 status show changed files in the working directory
676 status show changed files in the working directory
673 summary summarize working directory state
677 summary summarize working directory state
674 tag add one or more tags for the current or given revision
678 tag add one or more tags for the current or given revision
675 tags list repository tags
679 tags list repository tags
676 tip show the tip revision
680 tip show the tip revision
677 unbundle apply one or more changegroup files
681 unbundle apply one or more changegroup files
678 update update working directory (or switch revisions)
682 update update working directory (or switch revisions)
679 verify verify the integrity of the repository
683 verify verify the integrity of the repository
680 version output version and copyright information
684 version output version and copyright information
681
685
682 enabled extensions:
686 enabled extensions:
683
687
684 helpext (no help text available)
688 helpext (no help text available)
685
689
686 additional help topics:
690 additional help topics:
687
691
688 config Configuration Files
692 config Configuration Files
689 dates Date Formats
693 dates Date Formats
690 patterns File Name Patterns
694 patterns File Name Patterns
691 environment Environment Variables
695 environment Environment Variables
692 revisions Specifying Single Revisions
696 revisions Specifying Single Revisions
693 multirevs Specifying Multiple Revisions
697 multirevs Specifying Multiple Revisions
694 revsets Specifying Revision Sets
698 revsets Specifying Revision Sets
695 diffs Diff Formats
699 diffs Diff Formats
696 templating Template Usage
700 templating Template Usage
697 urls URL Paths
701 urls URL Paths
698 extensions Using additional features
702 extensions Using additional features
699 hgweb Configuring hgweb
703 hgweb Configuring hgweb
700 glossary Glossary
704 glossary Glossary
701
705
702 use "hg -v help" to show aliases and global options
706 use "hg -v help" to show aliases and global options
703
707
704 Test list of commands with command with no help text
708 Test list of commands with command with no help text
705
709
706 $ hg help helpext
710 $ hg help helpext
707 helpext extension - no help text available
711 helpext extension - no help text available
708
712
709 list of commands:
713 list of commands:
710
714
711 nohelp (no help text available)
715 nohelp (no help text available)
712
716
713 use "hg -v help helpext" to show aliases and global options
717 use "hg -v help helpext" to show aliases and global options
714
718
715 Test a help topic
719 Test a help topic
716
720
717 $ hg help revs
721 $ hg help revs
718 Specifying Single Revisions
722 Specifying Single Revisions
719
723
720 Mercurial supports several ways to specify individual revisions.
724 Mercurial supports several ways to specify individual revisions.
721
725
722 A plain integer is treated as a revision number. Negative integers are
726 A plain integer is treated as a revision number. Negative integers are
723 treated as sequential offsets from the tip, with -1 denoting the tip, -2
727 treated as sequential offsets from the tip, with -1 denoting the tip, -2
724 denoting the revision prior to the tip, and so forth.
728 denoting the revision prior to the tip, and so forth.
725
729
726 A 40-digit hexadecimal string is treated as a unique revision identifier.
730 A 40-digit hexadecimal string is treated as a unique revision identifier.
727
731
728 A hexadecimal string less than 40 characters long is treated as a unique
732 A hexadecimal string less than 40 characters long is treated as a unique
729 revision identifier and is referred to as a short-form identifier. A
733 revision identifier and is referred to as a short-form identifier. A
730 short-form identifier is only valid if it is the prefix of exactly one
734 short-form identifier is only valid if it is the prefix of exactly one
731 full-length identifier.
735 full-length identifier.
732
736
733 Any other string is treated as a tag or branch name. A tag name is a
737 Any other string is treated as a tag or branch name. A tag name is a
734 symbolic name associated with a revision identifier. A branch name denotes
738 symbolic name associated with a revision identifier. A branch name denotes
735 the tipmost revision of that branch. Tag and branch names must not contain
739 the tipmost revision of that branch. Tag and branch names must not contain
736 the ":" character.
740 the ":" character.
737
741
738 The reserved name "tip" is a special tag that always identifies the most
742 The reserved name "tip" is a special tag that always identifies the most
739 recent revision.
743 recent revision.
740
744
741 The reserved name "null" indicates the null revision. This is the revision
745 The reserved name "null" indicates the null revision. This is the revision
742 of an empty repository, and the parent of revision 0.
746 of an empty repository, and the parent of revision 0.
743
747
744 The reserved name "." indicates the working directory parent. If no
748 The reserved name "." indicates the working directory parent. If no
745 working directory is checked out, it is equivalent to null. If an
749 working directory is checked out, it is equivalent to null. If an
746 uncommitted merge is in progress, "." is the revision of the first parent.
750 uncommitted merge is in progress, "." is the revision of the first parent.
@@ -1,222 +1,227 b''
1 Make status look into subrepositories by default:
1 Make status look into subrepositories by default:
2
2
3 $ echo '[defaults]' >> $HGRCPATH
3 $ echo '[defaults]' >> $HGRCPATH
4 $ echo 'status = -S' >> $HGRCPATH
4 $ echo 'status = -S' >> $HGRCPATH
5 $ echo 'diff = --nodates -S' >> $HGRCPATH
5 $ echo 'diff = --nodates -S' >> $HGRCPATH
6
6
7 Create test repository:
7 Create test repository:
8
8
9 $ hg init
9 $ hg init
10 $ echo x1 > x.txt
10 $ echo x1 > x.txt
11 $ hg add x.txt
12
11
13 $ hg init foo
12 $ hg init foo
14 $ cd foo
13 $ cd foo
15 $ echo y1 > y.txt
14 $ echo y1 > y.txt
16 $ hg add y.txt
17
15
18 $ hg init bar
16 $ hg init bar
19 $ cd bar
17 $ cd bar
20 $ echo z1 > z.txt
18 $ echo z1 > z.txt
21 $ hg add z.txt
22
19
23 $ cd ..
20 $ cd ..
24 $ echo 'bar = bar' > .hgsub
21 $ echo 'bar = bar' > .hgsub
25 $ hg add .hgsub
26
22
27 $ cd ..
23 $ cd ..
28 $ echo 'foo = foo' > .hgsub
24 $ echo 'foo = foo' > .hgsub
29 $ hg add .hgsub
25
26 Add files --- .hgsub files must go first to trigger subrepos:
27
28 $ hg add -S .hgsub
29 $ hg add -S foo/.hgsub
30 $ hg add -S foo/bar
31 adding foo/bar/z.txt
32 $ hg add -S
33 adding x.txt
34 adding foo/y.txt
30
35
31 Test recursive status without committing anything:
36 Test recursive status without committing anything:
32
37
33 $ hg status
38 $ hg status
34 A .hgsub
39 A .hgsub
35 A foo/.hgsub
40 A foo/.hgsub
36 A foo/bar/z.txt
41 A foo/bar/z.txt
37 A foo/y.txt
42 A foo/y.txt
38 A x.txt
43 A x.txt
39
44
40 Test recursive diff without committing anything:
45 Test recursive diff without committing anything:
41
46
42 $ hg diff foo
47 $ hg diff foo
43 diff -r 000000000000 foo/.hgsub
48 diff -r 000000000000 foo/.hgsub
44 --- /dev/null
49 --- /dev/null
45 +++ b/foo/.hgsub
50 +++ b/foo/.hgsub
46 @@ -0,0 +1,1 @@
51 @@ -0,0 +1,1 @@
47 +bar = bar
52 +bar = bar
48 diff -r 000000000000 foo/y.txt
53 diff -r 000000000000 foo/y.txt
49 --- /dev/null
54 --- /dev/null
50 +++ b/foo/y.txt
55 +++ b/foo/y.txt
51 @@ -0,0 +1,1 @@
56 @@ -0,0 +1,1 @@
52 +y1
57 +y1
53 diff -r 000000000000 foo/bar/z.txt
58 diff -r 000000000000 foo/bar/z.txt
54 --- /dev/null
59 --- /dev/null
55 +++ b/foo/bar/z.txt
60 +++ b/foo/bar/z.txt
56 @@ -0,0 +1,1 @@
61 @@ -0,0 +1,1 @@
57 +z1
62 +z1
58
63
59 Commits:
64 Commits:
60
65
61 $ hg commit -m 0-0-0
66 $ hg commit -m 0-0-0
62 committing subrepository foo
67 committing subrepository foo
63 committing subrepository foo/bar
68 committing subrepository foo/bar
64
69
65 $ cd foo
70 $ cd foo
66 $ echo y2 >> y.txt
71 $ echo y2 >> y.txt
67 $ hg commit -m 0-1-0
72 $ hg commit -m 0-1-0
68
73
69 $ cd bar
74 $ cd bar
70 $ echo z2 >> z.txt
75 $ echo z2 >> z.txt
71 $ hg commit -m 0-1-1
76 $ hg commit -m 0-1-1
72
77
73 $ cd ..
78 $ cd ..
74 $ hg commit -m 0-2-1
79 $ hg commit -m 0-2-1
75 committing subrepository bar
80 committing subrepository bar
76
81
77 $ cd ..
82 $ cd ..
78 $ hg commit -m 1-2-1
83 $ hg commit -m 1-2-1
79 committing subrepository foo
84 committing subrepository foo
80
85
81 Change working directory:
86 Change working directory:
82
87
83 $ echo y3 >> foo/y.txt
88 $ echo y3 >> foo/y.txt
84 $ echo z3 >> foo/bar/z.txt
89 $ echo z3 >> foo/bar/z.txt
85 $ hg status
90 $ hg status
86 M foo/bar/z.txt
91 M foo/bar/z.txt
87 M foo/y.txt
92 M foo/y.txt
88 $ hg diff
93 $ hg diff
89 diff -r d254738c5f5e foo/y.txt
94 diff -r d254738c5f5e foo/y.txt
90 --- a/foo/y.txt
95 --- a/foo/y.txt
91 +++ b/foo/y.txt
96 +++ b/foo/y.txt
92 @@ -1,2 +1,3 @@
97 @@ -1,2 +1,3 @@
93 y1
98 y1
94 y2
99 y2
95 +y3
100 +y3
96 diff -r 9647f22de499 foo/bar/z.txt
101 diff -r 9647f22de499 foo/bar/z.txt
97 --- a/foo/bar/z.txt
102 --- a/foo/bar/z.txt
98 +++ b/foo/bar/z.txt
103 +++ b/foo/bar/z.txt
99 @@ -1,2 +1,3 @@
104 @@ -1,2 +1,3 @@
100 z1
105 z1
101 z2
106 z2
102 +z3
107 +z3
103
108
104 Status call crossing repository boundaries:
109 Status call crossing repository boundaries:
105
110
106 $ hg status foo/bar/z.txt
111 $ hg status foo/bar/z.txt
107 M foo/bar/z.txt
112 M foo/bar/z.txt
108 $ hg status -I 'foo/?.txt'
113 $ hg status -I 'foo/?.txt'
109 M foo/y.txt
114 M foo/y.txt
110 $ hg status -I '**/?.txt'
115 $ hg status -I '**/?.txt'
111 M foo/bar/z.txt
116 M foo/bar/z.txt
112 M foo/y.txt
117 M foo/y.txt
113 $ hg diff -I '**/?.txt'
118 $ hg diff -I '**/?.txt'
114 diff -r d254738c5f5e foo/y.txt
119 diff -r d254738c5f5e foo/y.txt
115 --- a/foo/y.txt
120 --- a/foo/y.txt
116 +++ b/foo/y.txt
121 +++ b/foo/y.txt
117 @@ -1,2 +1,3 @@
122 @@ -1,2 +1,3 @@
118 y1
123 y1
119 y2
124 y2
120 +y3
125 +y3
121 diff -r 9647f22de499 foo/bar/z.txt
126 diff -r 9647f22de499 foo/bar/z.txt
122 --- a/foo/bar/z.txt
127 --- a/foo/bar/z.txt
123 +++ b/foo/bar/z.txt
128 +++ b/foo/bar/z.txt
124 @@ -1,2 +1,3 @@
129 @@ -1,2 +1,3 @@
125 z1
130 z1
126 z2
131 z2
127 +z3
132 +z3
128
133
129 Status from within a subdirectory:
134 Status from within a subdirectory:
130
135
131 $ mkdir dir
136 $ mkdir dir
132 $ cd dir
137 $ cd dir
133 $ echo a1 > a.txt
138 $ echo a1 > a.txt
134 $ hg status
139 $ hg status
135 M foo/bar/z.txt
140 M foo/bar/z.txt
136 M foo/y.txt
141 M foo/y.txt
137 ? dir/a.txt
142 ? dir/a.txt
138 $ hg diff
143 $ hg diff
139 diff -r d254738c5f5e foo/y.txt
144 diff -r d254738c5f5e foo/y.txt
140 --- a/foo/y.txt
145 --- a/foo/y.txt
141 +++ b/foo/y.txt
146 +++ b/foo/y.txt
142 @@ -1,2 +1,3 @@
147 @@ -1,2 +1,3 @@
143 y1
148 y1
144 y2
149 y2
145 +y3
150 +y3
146 diff -r 9647f22de499 foo/bar/z.txt
151 diff -r 9647f22de499 foo/bar/z.txt
147 --- a/foo/bar/z.txt
152 --- a/foo/bar/z.txt
148 +++ b/foo/bar/z.txt
153 +++ b/foo/bar/z.txt
149 @@ -1,2 +1,3 @@
154 @@ -1,2 +1,3 @@
150 z1
155 z1
151 z2
156 z2
152 +z3
157 +z3
153
158
154 Status with relative path:
159 Status with relative path:
155
160
156 $ hg status ..
161 $ hg status ..
157 M ../foo/bar/z.txt
162 M ../foo/bar/z.txt
158 M ../foo/y.txt
163 M ../foo/y.txt
159 ? a.txt
164 ? a.txt
160 $ hg diff ..
165 $ hg diff ..
161 diff -r d254738c5f5e foo/y.txt
166 diff -r d254738c5f5e foo/y.txt
162 --- a/foo/y.txt
167 --- a/foo/y.txt
163 +++ b/foo/y.txt
168 +++ b/foo/y.txt
164 @@ -1,2 +1,3 @@
169 @@ -1,2 +1,3 @@
165 y1
170 y1
166 y2
171 y2
167 +y3
172 +y3
168 diff -r 9647f22de499 foo/bar/z.txt
173 diff -r 9647f22de499 foo/bar/z.txt
169 --- a/foo/bar/z.txt
174 --- a/foo/bar/z.txt
170 +++ b/foo/bar/z.txt
175 +++ b/foo/bar/z.txt
171 @@ -1,2 +1,3 @@
176 @@ -1,2 +1,3 @@
172 z1
177 z1
173 z2
178 z2
174 +z3
179 +z3
175 $ cd ..
180 $ cd ..
176
181
177 Cleanup and final commit:
182 Cleanup and final commit:
178
183
179 $ rm -r dir
184 $ rm -r dir
180 $ hg commit -m 2-3-2
185 $ hg commit -m 2-3-2
181 committing subrepository foo
186 committing subrepository foo
182 committing subrepository foo/bar
187 committing subrepository foo/bar
183
188
184 Log with the relationships between repo and its subrepo:
189 Log with the relationships between repo and its subrepo:
185
190
186 $ hg log --template '{rev}:{node|short} {desc}\n'
191 $ hg log --template '{rev}:{node|short} {desc}\n'
187 2:1326fa26d0c0 2-3-2
192 2:1326fa26d0c0 2-3-2
188 1:4b3c9ff4f66b 1-2-1
193 1:4b3c9ff4f66b 1-2-1
189 0:23376cbba0d8 0-0-0
194 0:23376cbba0d8 0-0-0
190
195
191 $ hg -R foo log --template '{rev}:{node|short} {desc}\n'
196 $ hg -R foo log --template '{rev}:{node|short} {desc}\n'
192 3:65903cebad86 2-3-2
197 3:65903cebad86 2-3-2
193 2:d254738c5f5e 0-2-1
198 2:d254738c5f5e 0-2-1
194 1:8629ce7dcc39 0-1-0
199 1:8629ce7dcc39 0-1-0
195 0:af048e97ade2 0-0-0
200 0:af048e97ade2 0-0-0
196
201
197 $ hg -R foo/bar log --template '{rev}:{node|short} {desc}\n'
202 $ hg -R foo/bar log --template '{rev}:{node|short} {desc}\n'
198 2:31ecbdafd357 2-3-2
203 2:31ecbdafd357 2-3-2
199 1:9647f22de499 0-1-1
204 1:9647f22de499 0-1-1
200 0:4904098473f9 0-0-0
205 0:4904098473f9 0-0-0
201
206
202 Status between revisions:
207 Status between revisions:
203
208
204 $ hg status
209 $ hg status
205 $ hg status --rev 0:1
210 $ hg status --rev 0:1
206 M .hgsubstate
211 M .hgsubstate
207 M foo/.hgsubstate
212 M foo/.hgsubstate
208 M foo/bar/z.txt
213 M foo/bar/z.txt
209 M foo/y.txt
214 M foo/y.txt
210 $ hg diff -I '**/?.txt' --rev 0:1
215 $ hg diff -I '**/?.txt' --rev 0:1
211 diff -r af048e97ade2 -r d254738c5f5e foo/y.txt
216 diff -r af048e97ade2 -r d254738c5f5e foo/y.txt
212 --- a/foo/y.txt
217 --- a/foo/y.txt
213 +++ b/foo/y.txt
218 +++ b/foo/y.txt
214 @@ -1,1 +1,2 @@
219 @@ -1,1 +1,2 @@
215 y1
220 y1
216 +y2
221 +y2
217 diff -r 4904098473f9 -r 9647f22de499 foo/bar/z.txt
222 diff -r 4904098473f9 -r 9647f22de499 foo/bar/z.txt
218 --- a/foo/bar/z.txt
223 --- a/foo/bar/z.txt
219 +++ b/foo/bar/z.txt
224 +++ b/foo/bar/z.txt
220 @@ -1,1 +1,2 @@
225 @@ -1,1 +1,2 @@
221 z1
226 z1
222 +z2
227 +z2
General Comments 0
You need to be logged in to leave comments. Login now