##// END OF EJS Templates
export: add %m to file format string (first line of the commit message)...
Andrzej Bieniek -
r14986:70e11de6 default
parent child Browse files
Show More
@@ -1,1244 +1,1247 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, tempfile
10 import os, sys, errno, re, tempfile
11 import util, scmutil, templater, patch, error, templatekw, revlog
11 import util, scmutil, templater, patch, error, templatekw, revlog
12 import match as matchmod
12 import match as matchmod
13 import subrepo
13 import subrepo
14
14
15 def parsealiases(cmd):
15 def parsealiases(cmd):
16 return cmd.lstrip("^").split("|")
16 return cmd.lstrip("^").split("|")
17
17
18 def findpossible(cmd, table, strict=False):
18 def findpossible(cmd, table, strict=False):
19 """
19 """
20 Return cmd -> (aliases, command table entry)
20 Return cmd -> (aliases, command table entry)
21 for each matching command.
21 for each matching command.
22 Return debug commands (or their aliases) only if no normal command matches.
22 Return debug commands (or their aliases) only if no normal command matches.
23 """
23 """
24 choice = {}
24 choice = {}
25 debugchoice = {}
25 debugchoice = {}
26 for e in table.keys():
26 for e in table.keys():
27 aliases = parsealiases(e)
27 aliases = parsealiases(e)
28 found = None
28 found = None
29 if cmd in aliases:
29 if cmd in aliases:
30 found = cmd
30 found = cmd
31 elif not strict:
31 elif not strict:
32 for a in aliases:
32 for a in aliases:
33 if a.startswith(cmd):
33 if a.startswith(cmd):
34 found = a
34 found = a
35 break
35 break
36 if found is not None:
36 if found is not None:
37 if aliases[0].startswith("debug") or found.startswith("debug"):
37 if aliases[0].startswith("debug") or found.startswith("debug"):
38 debugchoice[found] = (aliases, table[e])
38 debugchoice[found] = (aliases, table[e])
39 else:
39 else:
40 choice[found] = (aliases, table[e])
40 choice[found] = (aliases, table[e])
41
41
42 if not choice and debugchoice:
42 if not choice and debugchoice:
43 choice = debugchoice
43 choice = debugchoice
44
44
45 return choice
45 return choice
46
46
47 def findcmd(cmd, table, strict=True):
47 def findcmd(cmd, table, strict=True):
48 """Return (aliases, command table entry) for command string."""
48 """Return (aliases, command table entry) for command string."""
49 choice = findpossible(cmd, table, strict)
49 choice = findpossible(cmd, table, strict)
50
50
51 if cmd in choice:
51 if cmd in choice:
52 return choice[cmd]
52 return choice[cmd]
53
53
54 if len(choice) > 1:
54 if len(choice) > 1:
55 clist = choice.keys()
55 clist = choice.keys()
56 clist.sort()
56 clist.sort()
57 raise error.AmbiguousCommand(cmd, clist)
57 raise error.AmbiguousCommand(cmd, clist)
58
58
59 if choice:
59 if choice:
60 return choice.values()[0]
60 return choice.values()[0]
61
61
62 raise error.UnknownCommand(cmd)
62 raise error.UnknownCommand(cmd)
63
63
64 def findrepo(p):
64 def findrepo(p):
65 while not os.path.isdir(os.path.join(p, ".hg")):
65 while not os.path.isdir(os.path.join(p, ".hg")):
66 oldp, p = p, os.path.dirname(p)
66 oldp, p = p, os.path.dirname(p)
67 if p == oldp:
67 if p == oldp:
68 return None
68 return None
69
69
70 return p
70 return p
71
71
72 def bailifchanged(repo):
72 def bailifchanged(repo):
73 if repo.dirstate.p2() != nullid:
73 if repo.dirstate.p2() != nullid:
74 raise util.Abort(_('outstanding uncommitted merge'))
74 raise util.Abort(_('outstanding uncommitted merge'))
75 modified, added, removed, deleted = repo.status()[:4]
75 modified, added, removed, deleted = repo.status()[:4]
76 if modified or added or removed or deleted:
76 if modified or added or removed or deleted:
77 raise util.Abort(_("outstanding uncommitted changes"))
77 raise util.Abort(_("outstanding uncommitted changes"))
78
78
79 def logmessage(ui, opts):
79 def logmessage(ui, opts):
80 """ get the log message according to -m and -l option """
80 """ get the log message according to -m and -l option """
81 message = opts.get('message')
81 message = opts.get('message')
82 logfile = opts.get('logfile')
82 logfile = opts.get('logfile')
83
83
84 if message and logfile:
84 if message and logfile:
85 raise util.Abort(_('options --message and --logfile are mutually '
85 raise util.Abort(_('options --message and --logfile are mutually '
86 'exclusive'))
86 'exclusive'))
87 if not message and logfile:
87 if not message and logfile:
88 try:
88 try:
89 if logfile == '-':
89 if logfile == '-':
90 message = ui.fin.read()
90 message = ui.fin.read()
91 else:
91 else:
92 message = '\n'.join(util.readfile(logfile).splitlines())
92 message = '\n'.join(util.readfile(logfile).splitlines())
93 except IOError, inst:
93 except IOError, inst:
94 raise util.Abort(_("can't read commit message '%s': %s") %
94 raise util.Abort(_("can't read commit message '%s': %s") %
95 (logfile, inst.strerror))
95 (logfile, inst.strerror))
96 return message
96 return message
97
97
98 def loglimit(opts):
98 def loglimit(opts):
99 """get the log limit according to option -l/--limit"""
99 """get the log limit according to option -l/--limit"""
100 limit = opts.get('limit')
100 limit = opts.get('limit')
101 if limit:
101 if limit:
102 try:
102 try:
103 limit = int(limit)
103 limit = int(limit)
104 except ValueError:
104 except ValueError:
105 raise util.Abort(_('limit must be a positive integer'))
105 raise util.Abort(_('limit must be a positive integer'))
106 if limit <= 0:
106 if limit <= 0:
107 raise util.Abort(_('limit must be positive'))
107 raise util.Abort(_('limit must be positive'))
108 else:
108 else:
109 limit = None
109 limit = None
110 return limit
110 return limit
111
111
112 def makefilename(repo, pat, node,
112 def makefilename(repo, pat, node, desc=None,
113 total=None, seqno=None, revwidth=None, pathname=None):
113 total=None, seqno=None, revwidth=None, pathname=None):
114 node_expander = {
114 node_expander = {
115 'H': lambda: hex(node),
115 'H': lambda: hex(node),
116 'R': lambda: str(repo.changelog.rev(node)),
116 'R': lambda: str(repo.changelog.rev(node)),
117 'h': lambda: short(node),
117 'h': lambda: short(node),
118 'm': lambda: re.sub('[^\w]', '_', str(desc))
118 }
119 }
119 expander = {
120 expander = {
120 '%': lambda: '%',
121 '%': lambda: '%',
121 'b': lambda: os.path.basename(repo.root),
122 'b': lambda: os.path.basename(repo.root),
122 }
123 }
123
124
124 try:
125 try:
125 if node:
126 if node:
126 expander.update(node_expander)
127 expander.update(node_expander)
127 if node:
128 if node:
128 expander['r'] = (lambda:
129 expander['r'] = (lambda:
129 str(repo.changelog.rev(node)).zfill(revwidth or 0))
130 str(repo.changelog.rev(node)).zfill(revwidth or 0))
130 if total is not None:
131 if total is not None:
131 expander['N'] = lambda: str(total)
132 expander['N'] = lambda: str(total)
132 if seqno is not None:
133 if seqno is not None:
133 expander['n'] = lambda: str(seqno)
134 expander['n'] = lambda: str(seqno)
134 if total is not None and seqno is not None:
135 if total is not None and seqno is not None:
135 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
136 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
136 if pathname is not None:
137 if pathname is not None:
137 expander['s'] = lambda: os.path.basename(pathname)
138 expander['s'] = lambda: os.path.basename(pathname)
138 expander['d'] = lambda: os.path.dirname(pathname) or '.'
139 expander['d'] = lambda: os.path.dirname(pathname) or '.'
139 expander['p'] = lambda: pathname
140 expander['p'] = lambda: pathname
140
141
141 newname = []
142 newname = []
142 patlen = len(pat)
143 patlen = len(pat)
143 i = 0
144 i = 0
144 while i < patlen:
145 while i < patlen:
145 c = pat[i]
146 c = pat[i]
146 if c == '%':
147 if c == '%':
147 i += 1
148 i += 1
148 c = pat[i]
149 c = pat[i]
149 c = expander[c]()
150 c = expander[c]()
150 newname.append(c)
151 newname.append(c)
151 i += 1
152 i += 1
152 return ''.join(newname)
153 return ''.join(newname)
153 except KeyError, inst:
154 except KeyError, inst:
154 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
155 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
155 inst.args[0])
156 inst.args[0])
156
157
157 def makefileobj(repo, pat, node=None, total=None,
158 def makefileobj(repo, pat, node=None, desc=None, total=None,
158 seqno=None, revwidth=None, mode='wb', pathname=None):
159 seqno=None, revwidth=None, mode='wb', pathname=None):
159
160
160 writable = mode not in ('r', 'rb')
161 writable = mode not in ('r', 'rb')
161
162
162 if not pat or pat == '-':
163 if not pat or pat == '-':
163 fp = writable and repo.ui.fout or repo.ui.fin
164 fp = writable and repo.ui.fout or repo.ui.fin
164 if util.safehasattr(fp, 'fileno'):
165 if util.safehasattr(fp, 'fileno'):
165 return os.fdopen(os.dup(fp.fileno()), mode)
166 return os.fdopen(os.dup(fp.fileno()), mode)
166 else:
167 else:
167 # if this fp can't be duped properly, return
168 # if this fp can't be duped properly, return
168 # a dummy object that can be closed
169 # a dummy object that can be closed
169 class wrappedfileobj(object):
170 class wrappedfileobj(object):
170 noop = lambda x: None
171 noop = lambda x: None
171 def __init__(self, f):
172 def __init__(self, f):
172 self.f = f
173 self.f = f
173 def __getattr__(self, attr):
174 def __getattr__(self, attr):
174 if attr == 'close':
175 if attr == 'close':
175 return self.noop
176 return self.noop
176 else:
177 else:
177 return getattr(self.f, attr)
178 return getattr(self.f, attr)
178
179
179 return wrappedfileobj(fp)
180 return wrappedfileobj(fp)
180 if util.safehasattr(pat, 'write') and writable:
181 if util.safehasattr(pat, 'write') and writable:
181 return pat
182 return pat
182 if util.safehasattr(pat, 'read') and 'r' in mode:
183 if util.safehasattr(pat, 'read') and 'r' in mode:
183 return pat
184 return pat
184 return open(makefilename(repo, pat, node, total, seqno, revwidth,
185 return open(makefilename(repo, pat, node, desc, total, seqno, revwidth,
185 pathname),
186 pathname),
186 mode)
187 mode)
187
188
188 def openrevlog(repo, cmd, file_, opts):
189 def openrevlog(repo, cmd, file_, opts):
189 """opens the changelog, manifest, a filelog or a given revlog"""
190 """opens the changelog, manifest, a filelog or a given revlog"""
190 cl = opts['changelog']
191 cl = opts['changelog']
191 mf = opts['manifest']
192 mf = opts['manifest']
192 msg = None
193 msg = None
193 if cl and mf:
194 if cl and mf:
194 msg = _('cannot specify --changelog and --manifest at the same time')
195 msg = _('cannot specify --changelog and --manifest at the same time')
195 elif cl or mf:
196 elif cl or mf:
196 if file_:
197 if file_:
197 msg = _('cannot specify filename with --changelog or --manifest')
198 msg = _('cannot specify filename with --changelog or --manifest')
198 elif not repo:
199 elif not repo:
199 msg = _('cannot specify --changelog or --manifest '
200 msg = _('cannot specify --changelog or --manifest '
200 'without a repository')
201 'without a repository')
201 if msg:
202 if msg:
202 raise util.Abort(msg)
203 raise util.Abort(msg)
203
204
204 r = None
205 r = None
205 if repo:
206 if repo:
206 if cl:
207 if cl:
207 r = repo.changelog
208 r = repo.changelog
208 elif mf:
209 elif mf:
209 r = repo.manifest
210 r = repo.manifest
210 elif file_:
211 elif file_:
211 filelog = repo.file(file_)
212 filelog = repo.file(file_)
212 if len(filelog):
213 if len(filelog):
213 r = filelog
214 r = filelog
214 if not r:
215 if not r:
215 if not file_:
216 if not file_:
216 raise error.CommandError(cmd, _('invalid arguments'))
217 raise error.CommandError(cmd, _('invalid arguments'))
217 if not os.path.isfile(file_):
218 if not os.path.isfile(file_):
218 raise util.Abort(_("revlog '%s' not found") % file_)
219 raise util.Abort(_("revlog '%s' not found") % file_)
219 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
220 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
220 file_[:-2] + ".i")
221 file_[:-2] + ".i")
221 return r
222 return r
222
223
223 def copy(ui, repo, pats, opts, rename=False):
224 def copy(ui, repo, pats, opts, rename=False):
224 # called with the repo lock held
225 # called with the repo lock held
225 #
226 #
226 # hgsep => pathname that uses "/" to separate directories
227 # hgsep => pathname that uses "/" to separate directories
227 # ossep => pathname that uses os.sep to separate directories
228 # ossep => pathname that uses os.sep to separate directories
228 cwd = repo.getcwd()
229 cwd = repo.getcwd()
229 targets = {}
230 targets = {}
230 after = opts.get("after")
231 after = opts.get("after")
231 dryrun = opts.get("dry_run")
232 dryrun = opts.get("dry_run")
232 wctx = repo[None]
233 wctx = repo[None]
233
234
234 def walkpat(pat):
235 def walkpat(pat):
235 srcs = []
236 srcs = []
236 badstates = after and '?' or '?r'
237 badstates = after and '?' or '?r'
237 m = scmutil.match(repo[None], [pat], opts, globbed=True)
238 m = scmutil.match(repo[None], [pat], opts, globbed=True)
238 for abs in repo.walk(m):
239 for abs in repo.walk(m):
239 state = repo.dirstate[abs]
240 state = repo.dirstate[abs]
240 rel = m.rel(abs)
241 rel = m.rel(abs)
241 exact = m.exact(abs)
242 exact = m.exact(abs)
242 if state in badstates:
243 if state in badstates:
243 if exact and state == '?':
244 if exact and state == '?':
244 ui.warn(_('%s: not copying - file is not managed\n') % rel)
245 ui.warn(_('%s: not copying - file is not managed\n') % rel)
245 if exact and state == 'r':
246 if exact and state == 'r':
246 ui.warn(_('%s: not copying - file has been marked for'
247 ui.warn(_('%s: not copying - file has been marked for'
247 ' remove\n') % rel)
248 ' remove\n') % rel)
248 continue
249 continue
249 # abs: hgsep
250 # abs: hgsep
250 # rel: ossep
251 # rel: ossep
251 srcs.append((abs, rel, exact))
252 srcs.append((abs, rel, exact))
252 return srcs
253 return srcs
253
254
254 # abssrc: hgsep
255 # abssrc: hgsep
255 # relsrc: ossep
256 # relsrc: ossep
256 # otarget: ossep
257 # otarget: ossep
257 def copyfile(abssrc, relsrc, otarget, exact):
258 def copyfile(abssrc, relsrc, otarget, exact):
258 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
259 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
259 reltarget = repo.pathto(abstarget, cwd)
260 reltarget = repo.pathto(abstarget, cwd)
260 target = repo.wjoin(abstarget)
261 target = repo.wjoin(abstarget)
261 src = repo.wjoin(abssrc)
262 src = repo.wjoin(abssrc)
262 state = repo.dirstate[abstarget]
263 state = repo.dirstate[abstarget]
263
264
264 scmutil.checkportable(ui, abstarget)
265 scmutil.checkportable(ui, abstarget)
265
266
266 # check for collisions
267 # check for collisions
267 prevsrc = targets.get(abstarget)
268 prevsrc = targets.get(abstarget)
268 if prevsrc is not None:
269 if prevsrc is not None:
269 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
270 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
270 (reltarget, repo.pathto(abssrc, cwd),
271 (reltarget, repo.pathto(abssrc, cwd),
271 repo.pathto(prevsrc, cwd)))
272 repo.pathto(prevsrc, cwd)))
272 return
273 return
273
274
274 # check for overwrites
275 # check for overwrites
275 exists = os.path.lexists(target)
276 exists = os.path.lexists(target)
276 if not after and exists or after and state in 'mn':
277 if not after and exists or after and state in 'mn':
277 if not opts['force']:
278 if not opts['force']:
278 ui.warn(_('%s: not overwriting - file exists\n') %
279 ui.warn(_('%s: not overwriting - file exists\n') %
279 reltarget)
280 reltarget)
280 return
281 return
281
282
282 if after:
283 if after:
283 if not exists:
284 if not exists:
284 if rename:
285 if rename:
285 ui.warn(_('%s: not recording move - %s does not exist\n') %
286 ui.warn(_('%s: not recording move - %s does not exist\n') %
286 (relsrc, reltarget))
287 (relsrc, reltarget))
287 else:
288 else:
288 ui.warn(_('%s: not recording copy - %s does not exist\n') %
289 ui.warn(_('%s: not recording copy - %s does not exist\n') %
289 (relsrc, reltarget))
290 (relsrc, reltarget))
290 return
291 return
291 elif not dryrun:
292 elif not dryrun:
292 try:
293 try:
293 if exists:
294 if exists:
294 os.unlink(target)
295 os.unlink(target)
295 targetdir = os.path.dirname(target) or '.'
296 targetdir = os.path.dirname(target) or '.'
296 if not os.path.isdir(targetdir):
297 if not os.path.isdir(targetdir):
297 os.makedirs(targetdir)
298 os.makedirs(targetdir)
298 util.copyfile(src, target)
299 util.copyfile(src, target)
299 srcexists = True
300 srcexists = True
300 except IOError, inst:
301 except IOError, inst:
301 if inst.errno == errno.ENOENT:
302 if inst.errno == errno.ENOENT:
302 ui.warn(_('%s: deleted in working copy\n') % relsrc)
303 ui.warn(_('%s: deleted in working copy\n') % relsrc)
303 srcexists = False
304 srcexists = False
304 else:
305 else:
305 ui.warn(_('%s: cannot copy - %s\n') %
306 ui.warn(_('%s: cannot copy - %s\n') %
306 (relsrc, inst.strerror))
307 (relsrc, inst.strerror))
307 return True # report a failure
308 return True # report a failure
308
309
309 if ui.verbose or not exact:
310 if ui.verbose or not exact:
310 if rename:
311 if rename:
311 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
312 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
312 else:
313 else:
313 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
314 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
314
315
315 targets[abstarget] = abssrc
316 targets[abstarget] = abssrc
316
317
317 # fix up dirstate
318 # fix up dirstate
318 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
319 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
319 dryrun=dryrun, cwd=cwd)
320 dryrun=dryrun, cwd=cwd)
320 if rename and not dryrun:
321 if rename and not dryrun:
321 if not after and srcexists:
322 if not after and srcexists:
322 util.unlinkpath(repo.wjoin(abssrc))
323 util.unlinkpath(repo.wjoin(abssrc))
323 wctx.forget([abssrc])
324 wctx.forget([abssrc])
324
325
325 # pat: ossep
326 # pat: ossep
326 # dest ossep
327 # dest ossep
327 # srcs: list of (hgsep, hgsep, ossep, bool)
328 # srcs: list of (hgsep, hgsep, ossep, bool)
328 # return: function that takes hgsep and returns ossep
329 # return: function that takes hgsep and returns ossep
329 def targetpathfn(pat, dest, srcs):
330 def targetpathfn(pat, dest, srcs):
330 if os.path.isdir(pat):
331 if os.path.isdir(pat):
331 abspfx = scmutil.canonpath(repo.root, cwd, pat)
332 abspfx = scmutil.canonpath(repo.root, cwd, pat)
332 abspfx = util.localpath(abspfx)
333 abspfx = util.localpath(abspfx)
333 if destdirexists:
334 if destdirexists:
334 striplen = len(os.path.split(abspfx)[0])
335 striplen = len(os.path.split(abspfx)[0])
335 else:
336 else:
336 striplen = len(abspfx)
337 striplen = len(abspfx)
337 if striplen:
338 if striplen:
338 striplen += len(os.sep)
339 striplen += len(os.sep)
339 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
340 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
340 elif destdirexists:
341 elif destdirexists:
341 res = lambda p: os.path.join(dest,
342 res = lambda p: os.path.join(dest,
342 os.path.basename(util.localpath(p)))
343 os.path.basename(util.localpath(p)))
343 else:
344 else:
344 res = lambda p: dest
345 res = lambda p: dest
345 return res
346 return res
346
347
347 # pat: ossep
348 # pat: ossep
348 # dest ossep
349 # dest ossep
349 # srcs: list of (hgsep, hgsep, ossep, bool)
350 # srcs: list of (hgsep, hgsep, ossep, bool)
350 # return: function that takes hgsep and returns ossep
351 # return: function that takes hgsep and returns ossep
351 def targetpathafterfn(pat, dest, srcs):
352 def targetpathafterfn(pat, dest, srcs):
352 if matchmod.patkind(pat):
353 if matchmod.patkind(pat):
353 # a mercurial pattern
354 # a mercurial pattern
354 res = lambda p: os.path.join(dest,
355 res = lambda p: os.path.join(dest,
355 os.path.basename(util.localpath(p)))
356 os.path.basename(util.localpath(p)))
356 else:
357 else:
357 abspfx = scmutil.canonpath(repo.root, cwd, pat)
358 abspfx = scmutil.canonpath(repo.root, cwd, pat)
358 if len(abspfx) < len(srcs[0][0]):
359 if len(abspfx) < len(srcs[0][0]):
359 # A directory. Either the target path contains the last
360 # A directory. Either the target path contains the last
360 # component of the source path or it does not.
361 # component of the source path or it does not.
361 def evalpath(striplen):
362 def evalpath(striplen):
362 score = 0
363 score = 0
363 for s in srcs:
364 for s in srcs:
364 t = os.path.join(dest, util.localpath(s[0])[striplen:])
365 t = os.path.join(dest, util.localpath(s[0])[striplen:])
365 if os.path.lexists(t):
366 if os.path.lexists(t):
366 score += 1
367 score += 1
367 return score
368 return score
368
369
369 abspfx = util.localpath(abspfx)
370 abspfx = util.localpath(abspfx)
370 striplen = len(abspfx)
371 striplen = len(abspfx)
371 if striplen:
372 if striplen:
372 striplen += len(os.sep)
373 striplen += len(os.sep)
373 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
374 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
374 score = evalpath(striplen)
375 score = evalpath(striplen)
375 striplen1 = len(os.path.split(abspfx)[0])
376 striplen1 = len(os.path.split(abspfx)[0])
376 if striplen1:
377 if striplen1:
377 striplen1 += len(os.sep)
378 striplen1 += len(os.sep)
378 if evalpath(striplen1) > score:
379 if evalpath(striplen1) > score:
379 striplen = striplen1
380 striplen = striplen1
380 res = lambda p: os.path.join(dest,
381 res = lambda p: os.path.join(dest,
381 util.localpath(p)[striplen:])
382 util.localpath(p)[striplen:])
382 else:
383 else:
383 # a file
384 # a file
384 if destdirexists:
385 if destdirexists:
385 res = lambda p: os.path.join(dest,
386 res = lambda p: os.path.join(dest,
386 os.path.basename(util.localpath(p)))
387 os.path.basename(util.localpath(p)))
387 else:
388 else:
388 res = lambda p: dest
389 res = lambda p: dest
389 return res
390 return res
390
391
391
392
392 pats = scmutil.expandpats(pats)
393 pats = scmutil.expandpats(pats)
393 if not pats:
394 if not pats:
394 raise util.Abort(_('no source or destination specified'))
395 raise util.Abort(_('no source or destination specified'))
395 if len(pats) == 1:
396 if len(pats) == 1:
396 raise util.Abort(_('no destination specified'))
397 raise util.Abort(_('no destination specified'))
397 dest = pats.pop()
398 dest = pats.pop()
398 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
399 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
399 if not destdirexists:
400 if not destdirexists:
400 if len(pats) > 1 or matchmod.patkind(pats[0]):
401 if len(pats) > 1 or matchmod.patkind(pats[0]):
401 raise util.Abort(_('with multiple sources, destination must be an '
402 raise util.Abort(_('with multiple sources, destination must be an '
402 'existing directory'))
403 'existing directory'))
403 if util.endswithsep(dest):
404 if util.endswithsep(dest):
404 raise util.Abort(_('destination %s is not a directory') % dest)
405 raise util.Abort(_('destination %s is not a directory') % dest)
405
406
406 tfn = targetpathfn
407 tfn = targetpathfn
407 if after:
408 if after:
408 tfn = targetpathafterfn
409 tfn = targetpathafterfn
409 copylist = []
410 copylist = []
410 for pat in pats:
411 for pat in pats:
411 srcs = walkpat(pat)
412 srcs = walkpat(pat)
412 if not srcs:
413 if not srcs:
413 continue
414 continue
414 copylist.append((tfn(pat, dest, srcs), srcs))
415 copylist.append((tfn(pat, dest, srcs), srcs))
415 if not copylist:
416 if not copylist:
416 raise util.Abort(_('no files to copy'))
417 raise util.Abort(_('no files to copy'))
417
418
418 errors = 0
419 errors = 0
419 for targetpath, srcs in copylist:
420 for targetpath, srcs in copylist:
420 for abssrc, relsrc, exact in srcs:
421 for abssrc, relsrc, exact in srcs:
421 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
422 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
422 errors += 1
423 errors += 1
423
424
424 if errors:
425 if errors:
425 ui.warn(_('(consider using --after)\n'))
426 ui.warn(_('(consider using --after)\n'))
426
427
427 return errors != 0
428 return errors != 0
428
429
429 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
430 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
430 runargs=None, appendpid=False):
431 runargs=None, appendpid=False):
431 '''Run a command as a service.'''
432 '''Run a command as a service.'''
432
433
433 if opts['daemon'] and not opts['daemon_pipefds']:
434 if opts['daemon'] and not opts['daemon_pipefds']:
434 # Signal child process startup with file removal
435 # Signal child process startup with file removal
435 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
436 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
436 os.close(lockfd)
437 os.close(lockfd)
437 try:
438 try:
438 if not runargs:
439 if not runargs:
439 runargs = util.hgcmd() + sys.argv[1:]
440 runargs = util.hgcmd() + sys.argv[1:]
440 runargs.append('--daemon-pipefds=%s' % lockpath)
441 runargs.append('--daemon-pipefds=%s' % lockpath)
441 # Don't pass --cwd to the child process, because we've already
442 # Don't pass --cwd to the child process, because we've already
442 # changed directory.
443 # changed directory.
443 for i in xrange(1, len(runargs)):
444 for i in xrange(1, len(runargs)):
444 if runargs[i].startswith('--cwd='):
445 if runargs[i].startswith('--cwd='):
445 del runargs[i]
446 del runargs[i]
446 break
447 break
447 elif runargs[i].startswith('--cwd'):
448 elif runargs[i].startswith('--cwd'):
448 del runargs[i:i + 2]
449 del runargs[i:i + 2]
449 break
450 break
450 def condfn():
451 def condfn():
451 return not os.path.exists(lockpath)
452 return not os.path.exists(lockpath)
452 pid = util.rundetached(runargs, condfn)
453 pid = util.rundetached(runargs, condfn)
453 if pid < 0:
454 if pid < 0:
454 raise util.Abort(_('child process failed to start'))
455 raise util.Abort(_('child process failed to start'))
455 finally:
456 finally:
456 try:
457 try:
457 os.unlink(lockpath)
458 os.unlink(lockpath)
458 except OSError, e:
459 except OSError, e:
459 if e.errno != errno.ENOENT:
460 if e.errno != errno.ENOENT:
460 raise
461 raise
461 if parentfn:
462 if parentfn:
462 return parentfn(pid)
463 return parentfn(pid)
463 else:
464 else:
464 return
465 return
465
466
466 if initfn:
467 if initfn:
467 initfn()
468 initfn()
468
469
469 if opts['pid_file']:
470 if opts['pid_file']:
470 mode = appendpid and 'a' or 'w'
471 mode = appendpid and 'a' or 'w'
471 fp = open(opts['pid_file'], mode)
472 fp = open(opts['pid_file'], mode)
472 fp.write(str(os.getpid()) + '\n')
473 fp.write(str(os.getpid()) + '\n')
473 fp.close()
474 fp.close()
474
475
475 if opts['daemon_pipefds']:
476 if opts['daemon_pipefds']:
476 lockpath = opts['daemon_pipefds']
477 lockpath = opts['daemon_pipefds']
477 try:
478 try:
478 os.setsid()
479 os.setsid()
479 except AttributeError:
480 except AttributeError:
480 pass
481 pass
481 os.unlink(lockpath)
482 os.unlink(lockpath)
482 util.hidewindow()
483 util.hidewindow()
483 sys.stdout.flush()
484 sys.stdout.flush()
484 sys.stderr.flush()
485 sys.stderr.flush()
485
486
486 nullfd = os.open(util.nulldev, os.O_RDWR)
487 nullfd = os.open(util.nulldev, os.O_RDWR)
487 logfilefd = nullfd
488 logfilefd = nullfd
488 if logfile:
489 if logfile:
489 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
490 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
490 os.dup2(nullfd, 0)
491 os.dup2(nullfd, 0)
491 os.dup2(logfilefd, 1)
492 os.dup2(logfilefd, 1)
492 os.dup2(logfilefd, 2)
493 os.dup2(logfilefd, 2)
493 if nullfd not in (0, 1, 2):
494 if nullfd not in (0, 1, 2):
494 os.close(nullfd)
495 os.close(nullfd)
495 if logfile and logfilefd not in (0, 1, 2):
496 if logfile and logfilefd not in (0, 1, 2):
496 os.close(logfilefd)
497 os.close(logfilefd)
497
498
498 if runfn:
499 if runfn:
499 return runfn()
500 return runfn()
500
501
501 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
502 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
502 opts=None):
503 opts=None):
503 '''export changesets as hg patches.'''
504 '''export changesets as hg patches.'''
504
505
505 total = len(revs)
506 total = len(revs)
506 revwidth = max([len(str(rev)) for rev in revs])
507 revwidth = max([len(str(rev)) for rev in revs])
507
508
508 def single(rev, seqno, fp):
509 def single(rev, seqno, fp):
509 ctx = repo[rev]
510 ctx = repo[rev]
510 node = ctx.node()
511 node = ctx.node()
511 parents = [p.node() for p in ctx.parents() if p]
512 parents = [p.node() for p in ctx.parents() if p]
512 branch = ctx.branch()
513 branch = ctx.branch()
513 if switch_parent:
514 if switch_parent:
514 parents.reverse()
515 parents.reverse()
515 prev = (parents and parents[0]) or nullid
516 prev = (parents and parents[0]) or nullid
516
517
517 shouldclose = False
518 shouldclose = False
518 if not fp:
519 if not fp:
519 fp = makefileobj(repo, template, node, total=total, seqno=seqno,
520 desc_lines = ctx.description().rstrip().split('\n')
520 revwidth=revwidth, mode='ab')
521 desc = desc_lines[0] #Commit always has a first line.
522 fp = makefileobj(repo, template, node, desc=desc, total=total,
523 seqno=seqno, revwidth=revwidth, mode='ab')
521 if fp != template:
524 if fp != template:
522 shouldclose = True
525 shouldclose = True
523 if fp != sys.stdout and util.safehasattr(fp, 'name'):
526 if fp != sys.stdout and util.safehasattr(fp, 'name'):
524 repo.ui.note("%s\n" % fp.name)
527 repo.ui.note("%s\n" % fp.name)
525
528
526 fp.write("# HG changeset patch\n")
529 fp.write("# HG changeset patch\n")
527 fp.write("# User %s\n" % ctx.user())
530 fp.write("# User %s\n" % ctx.user())
528 fp.write("# Date %d %d\n" % ctx.date())
531 fp.write("# Date %d %d\n" % ctx.date())
529 if branch and branch != 'default':
532 if branch and branch != 'default':
530 fp.write("# Branch %s\n" % branch)
533 fp.write("# Branch %s\n" % branch)
531 fp.write("# Node ID %s\n" % hex(node))
534 fp.write("# Node ID %s\n" % hex(node))
532 fp.write("# Parent %s\n" % hex(prev))
535 fp.write("# Parent %s\n" % hex(prev))
533 if len(parents) > 1:
536 if len(parents) > 1:
534 fp.write("# Parent %s\n" % hex(parents[1]))
537 fp.write("# Parent %s\n" % hex(parents[1]))
535 fp.write(ctx.description().rstrip())
538 fp.write(ctx.description().rstrip())
536 fp.write("\n\n")
539 fp.write("\n\n")
537
540
538 for chunk in patch.diff(repo, prev, node, opts=opts):
541 for chunk in patch.diff(repo, prev, node, opts=opts):
539 fp.write(chunk)
542 fp.write(chunk)
540
543
541 if shouldclose:
544 if shouldclose:
542 fp.close()
545 fp.close()
543
546
544 for seqno, rev in enumerate(revs):
547 for seqno, rev in enumerate(revs):
545 single(rev, seqno + 1, fp)
548 single(rev, seqno + 1, fp)
546
549
547 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
550 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
548 changes=None, stat=False, fp=None, prefix='',
551 changes=None, stat=False, fp=None, prefix='',
549 listsubrepos=False):
552 listsubrepos=False):
550 '''show diff or diffstat.'''
553 '''show diff or diffstat.'''
551 if fp is None:
554 if fp is None:
552 write = ui.write
555 write = ui.write
553 else:
556 else:
554 def write(s, **kw):
557 def write(s, **kw):
555 fp.write(s)
558 fp.write(s)
556
559
557 if stat:
560 if stat:
558 diffopts = diffopts.copy(context=0)
561 diffopts = diffopts.copy(context=0)
559 width = 80
562 width = 80
560 if not ui.plain():
563 if not ui.plain():
561 width = ui.termwidth()
564 width = ui.termwidth()
562 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
565 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
563 prefix=prefix)
566 prefix=prefix)
564 for chunk, label in patch.diffstatui(util.iterlines(chunks),
567 for chunk, label in patch.diffstatui(util.iterlines(chunks),
565 width=width,
568 width=width,
566 git=diffopts.git):
569 git=diffopts.git):
567 write(chunk, label=label)
570 write(chunk, label=label)
568 else:
571 else:
569 for chunk, label in patch.diffui(repo, node1, node2, match,
572 for chunk, label in patch.diffui(repo, node1, node2, match,
570 changes, diffopts, prefix=prefix):
573 changes, diffopts, prefix=prefix):
571 write(chunk, label=label)
574 write(chunk, label=label)
572
575
573 if listsubrepos:
576 if listsubrepos:
574 ctx1 = repo[node1]
577 ctx1 = repo[node1]
575 ctx2 = repo[node2]
578 ctx2 = repo[node2]
576 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
579 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
577 if node2 is not None:
580 if node2 is not None:
578 node2 = ctx2.substate[subpath][1]
581 node2 = ctx2.substate[subpath][1]
579 submatch = matchmod.narrowmatcher(subpath, match)
582 submatch = matchmod.narrowmatcher(subpath, match)
580 sub.diff(diffopts, node2, submatch, changes=changes,
583 sub.diff(diffopts, node2, submatch, changes=changes,
581 stat=stat, fp=fp, prefix=prefix)
584 stat=stat, fp=fp, prefix=prefix)
582
585
583 class changeset_printer(object):
586 class changeset_printer(object):
584 '''show changeset information when templating not requested.'''
587 '''show changeset information when templating not requested.'''
585
588
586 def __init__(self, ui, repo, patch, diffopts, buffered):
589 def __init__(self, ui, repo, patch, diffopts, buffered):
587 self.ui = ui
590 self.ui = ui
588 self.repo = repo
591 self.repo = repo
589 self.buffered = buffered
592 self.buffered = buffered
590 self.patch = patch
593 self.patch = patch
591 self.diffopts = diffopts
594 self.diffopts = diffopts
592 self.header = {}
595 self.header = {}
593 self.hunk = {}
596 self.hunk = {}
594 self.lastheader = None
597 self.lastheader = None
595 self.footer = None
598 self.footer = None
596
599
597 def flush(self, rev):
600 def flush(self, rev):
598 if rev in self.header:
601 if rev in self.header:
599 h = self.header[rev]
602 h = self.header[rev]
600 if h != self.lastheader:
603 if h != self.lastheader:
601 self.lastheader = h
604 self.lastheader = h
602 self.ui.write(h)
605 self.ui.write(h)
603 del self.header[rev]
606 del self.header[rev]
604 if rev in self.hunk:
607 if rev in self.hunk:
605 self.ui.write(self.hunk[rev])
608 self.ui.write(self.hunk[rev])
606 del self.hunk[rev]
609 del self.hunk[rev]
607 return 1
610 return 1
608 return 0
611 return 0
609
612
610 def close(self):
613 def close(self):
611 if self.footer:
614 if self.footer:
612 self.ui.write(self.footer)
615 self.ui.write(self.footer)
613
616
614 def show(self, ctx, copies=None, matchfn=None, **props):
617 def show(self, ctx, copies=None, matchfn=None, **props):
615 if self.buffered:
618 if self.buffered:
616 self.ui.pushbuffer()
619 self.ui.pushbuffer()
617 self._show(ctx, copies, matchfn, props)
620 self._show(ctx, copies, matchfn, props)
618 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
621 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
619 else:
622 else:
620 self._show(ctx, copies, matchfn, props)
623 self._show(ctx, copies, matchfn, props)
621
624
622 def _show(self, ctx, copies, matchfn, props):
625 def _show(self, ctx, copies, matchfn, props):
623 '''show a single changeset or file revision'''
626 '''show a single changeset or file revision'''
624 changenode = ctx.node()
627 changenode = ctx.node()
625 rev = ctx.rev()
628 rev = ctx.rev()
626
629
627 if self.ui.quiet:
630 if self.ui.quiet:
628 self.ui.write("%d:%s\n" % (rev, short(changenode)),
631 self.ui.write("%d:%s\n" % (rev, short(changenode)),
629 label='log.node')
632 label='log.node')
630 return
633 return
631
634
632 log = self.repo.changelog
635 log = self.repo.changelog
633 date = util.datestr(ctx.date())
636 date = util.datestr(ctx.date())
634
637
635 hexfunc = self.ui.debugflag and hex or short
638 hexfunc = self.ui.debugflag and hex or short
636
639
637 parents = [(p, hexfunc(log.node(p)))
640 parents = [(p, hexfunc(log.node(p)))
638 for p in self._meaningful_parentrevs(log, rev)]
641 for p in self._meaningful_parentrevs(log, rev)]
639
642
640 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
643 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
641 label='log.changeset')
644 label='log.changeset')
642
645
643 branch = ctx.branch()
646 branch = ctx.branch()
644 # don't show the default branch name
647 # don't show the default branch name
645 if branch != 'default':
648 if branch != 'default':
646 self.ui.write(_("branch: %s\n") % branch,
649 self.ui.write(_("branch: %s\n") % branch,
647 label='log.branch')
650 label='log.branch')
648 for bookmark in self.repo.nodebookmarks(changenode):
651 for bookmark in self.repo.nodebookmarks(changenode):
649 self.ui.write(_("bookmark: %s\n") % bookmark,
652 self.ui.write(_("bookmark: %s\n") % bookmark,
650 label='log.bookmark')
653 label='log.bookmark')
651 for tag in self.repo.nodetags(changenode):
654 for tag in self.repo.nodetags(changenode):
652 self.ui.write(_("tag: %s\n") % tag,
655 self.ui.write(_("tag: %s\n") % tag,
653 label='log.tag')
656 label='log.tag')
654 for parent in parents:
657 for parent in parents:
655 self.ui.write(_("parent: %d:%s\n") % parent,
658 self.ui.write(_("parent: %d:%s\n") % parent,
656 label='log.parent')
659 label='log.parent')
657
660
658 if self.ui.debugflag:
661 if self.ui.debugflag:
659 mnode = ctx.manifestnode()
662 mnode = ctx.manifestnode()
660 self.ui.write(_("manifest: %d:%s\n") %
663 self.ui.write(_("manifest: %d:%s\n") %
661 (self.repo.manifest.rev(mnode), hex(mnode)),
664 (self.repo.manifest.rev(mnode), hex(mnode)),
662 label='ui.debug log.manifest')
665 label='ui.debug log.manifest')
663 self.ui.write(_("user: %s\n") % ctx.user(),
666 self.ui.write(_("user: %s\n") % ctx.user(),
664 label='log.user')
667 label='log.user')
665 self.ui.write(_("date: %s\n") % date,
668 self.ui.write(_("date: %s\n") % date,
666 label='log.date')
669 label='log.date')
667
670
668 if self.ui.debugflag:
671 if self.ui.debugflag:
669 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
672 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
670 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
673 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
671 files):
674 files):
672 if value:
675 if value:
673 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
676 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
674 label='ui.debug log.files')
677 label='ui.debug log.files')
675 elif ctx.files() and self.ui.verbose:
678 elif ctx.files() and self.ui.verbose:
676 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
679 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
677 label='ui.note log.files')
680 label='ui.note log.files')
678 if copies and self.ui.verbose:
681 if copies and self.ui.verbose:
679 copies = ['%s (%s)' % c for c in copies]
682 copies = ['%s (%s)' % c for c in copies]
680 self.ui.write(_("copies: %s\n") % ' '.join(copies),
683 self.ui.write(_("copies: %s\n") % ' '.join(copies),
681 label='ui.note log.copies')
684 label='ui.note log.copies')
682
685
683 extra = ctx.extra()
686 extra = ctx.extra()
684 if extra and self.ui.debugflag:
687 if extra and self.ui.debugflag:
685 for key, value in sorted(extra.items()):
688 for key, value in sorted(extra.items()):
686 self.ui.write(_("extra: %s=%s\n")
689 self.ui.write(_("extra: %s=%s\n")
687 % (key, value.encode('string_escape')),
690 % (key, value.encode('string_escape')),
688 label='ui.debug log.extra')
691 label='ui.debug log.extra')
689
692
690 description = ctx.description().strip()
693 description = ctx.description().strip()
691 if description:
694 if description:
692 if self.ui.verbose:
695 if self.ui.verbose:
693 self.ui.write(_("description:\n"),
696 self.ui.write(_("description:\n"),
694 label='ui.note log.description')
697 label='ui.note log.description')
695 self.ui.write(description,
698 self.ui.write(description,
696 label='ui.note log.description')
699 label='ui.note log.description')
697 self.ui.write("\n\n")
700 self.ui.write("\n\n")
698 else:
701 else:
699 self.ui.write(_("summary: %s\n") %
702 self.ui.write(_("summary: %s\n") %
700 description.splitlines()[0],
703 description.splitlines()[0],
701 label='log.summary')
704 label='log.summary')
702 self.ui.write("\n")
705 self.ui.write("\n")
703
706
704 self.showpatch(changenode, matchfn)
707 self.showpatch(changenode, matchfn)
705
708
706 def showpatch(self, node, matchfn):
709 def showpatch(self, node, matchfn):
707 if not matchfn:
710 if not matchfn:
708 matchfn = self.patch
711 matchfn = self.patch
709 if matchfn:
712 if matchfn:
710 stat = self.diffopts.get('stat')
713 stat = self.diffopts.get('stat')
711 diff = self.diffopts.get('patch')
714 diff = self.diffopts.get('patch')
712 diffopts = patch.diffopts(self.ui, self.diffopts)
715 diffopts = patch.diffopts(self.ui, self.diffopts)
713 prev = self.repo.changelog.parents(node)[0]
716 prev = self.repo.changelog.parents(node)[0]
714 if stat:
717 if stat:
715 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
718 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
716 match=matchfn, stat=True)
719 match=matchfn, stat=True)
717 if diff:
720 if diff:
718 if stat:
721 if stat:
719 self.ui.write("\n")
722 self.ui.write("\n")
720 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
723 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
721 match=matchfn, stat=False)
724 match=matchfn, stat=False)
722 self.ui.write("\n")
725 self.ui.write("\n")
723
726
724 def _meaningful_parentrevs(self, log, rev):
727 def _meaningful_parentrevs(self, log, rev):
725 """Return list of meaningful (or all if debug) parentrevs for rev.
728 """Return list of meaningful (or all if debug) parentrevs for rev.
726
729
727 For merges (two non-nullrev revisions) both parents are meaningful.
730 For merges (two non-nullrev revisions) both parents are meaningful.
728 Otherwise the first parent revision is considered meaningful if it
731 Otherwise the first parent revision is considered meaningful if it
729 is not the preceding revision.
732 is not the preceding revision.
730 """
733 """
731 parents = log.parentrevs(rev)
734 parents = log.parentrevs(rev)
732 if not self.ui.debugflag and parents[1] == nullrev:
735 if not self.ui.debugflag and parents[1] == nullrev:
733 if parents[0] >= rev - 1:
736 if parents[0] >= rev - 1:
734 parents = []
737 parents = []
735 else:
738 else:
736 parents = [parents[0]]
739 parents = [parents[0]]
737 return parents
740 return parents
738
741
739
742
740 class changeset_templater(changeset_printer):
743 class changeset_templater(changeset_printer):
741 '''format changeset information.'''
744 '''format changeset information.'''
742
745
743 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
746 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
744 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
747 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
745 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
748 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
746 defaulttempl = {
749 defaulttempl = {
747 'parent': '{rev}:{node|formatnode} ',
750 'parent': '{rev}:{node|formatnode} ',
748 'manifest': '{rev}:{node|formatnode}',
751 'manifest': '{rev}:{node|formatnode}',
749 'file_copy': '{name} ({source})',
752 'file_copy': '{name} ({source})',
750 'extra': '{key}={value|stringescape}'
753 'extra': '{key}={value|stringescape}'
751 }
754 }
752 # filecopy is preserved for compatibility reasons
755 # filecopy is preserved for compatibility reasons
753 defaulttempl['filecopy'] = defaulttempl['file_copy']
756 defaulttempl['filecopy'] = defaulttempl['file_copy']
754 self.t = templater.templater(mapfile, {'formatnode': formatnode},
757 self.t = templater.templater(mapfile, {'formatnode': formatnode},
755 cache=defaulttempl)
758 cache=defaulttempl)
756 self.cache = {}
759 self.cache = {}
757
760
758 def use_template(self, t):
761 def use_template(self, t):
759 '''set template string to use'''
762 '''set template string to use'''
760 self.t.cache['changeset'] = t
763 self.t.cache['changeset'] = t
761
764
762 def _meaningful_parentrevs(self, ctx):
765 def _meaningful_parentrevs(self, ctx):
763 """Return list of meaningful (or all if debug) parentrevs for rev.
766 """Return list of meaningful (or all if debug) parentrevs for rev.
764 """
767 """
765 parents = ctx.parents()
768 parents = ctx.parents()
766 if len(parents) > 1:
769 if len(parents) > 1:
767 return parents
770 return parents
768 if self.ui.debugflag:
771 if self.ui.debugflag:
769 return [parents[0], self.repo['null']]
772 return [parents[0], self.repo['null']]
770 if parents[0].rev() >= ctx.rev() - 1:
773 if parents[0].rev() >= ctx.rev() - 1:
771 return []
774 return []
772 return parents
775 return parents
773
776
774 def _show(self, ctx, copies, matchfn, props):
777 def _show(self, ctx, copies, matchfn, props):
775 '''show a single changeset or file revision'''
778 '''show a single changeset or file revision'''
776
779
777 showlist = templatekw.showlist
780 showlist = templatekw.showlist
778
781
779 # showparents() behaviour depends on ui trace level which
782 # showparents() behaviour depends on ui trace level which
780 # causes unexpected behaviours at templating level and makes
783 # causes unexpected behaviours at templating level and makes
781 # it harder to extract it in a standalone function. Its
784 # it harder to extract it in a standalone function. Its
782 # behaviour cannot be changed so leave it here for now.
785 # behaviour cannot be changed so leave it here for now.
783 def showparents(**args):
786 def showparents(**args):
784 ctx = args['ctx']
787 ctx = args['ctx']
785 parents = [[('rev', p.rev()), ('node', p.hex())]
788 parents = [[('rev', p.rev()), ('node', p.hex())]
786 for p in self._meaningful_parentrevs(ctx)]
789 for p in self._meaningful_parentrevs(ctx)]
787 return showlist('parent', parents, **args)
790 return showlist('parent', parents, **args)
788
791
789 props = props.copy()
792 props = props.copy()
790 props.update(templatekw.keywords)
793 props.update(templatekw.keywords)
791 props['parents'] = showparents
794 props['parents'] = showparents
792 props['templ'] = self.t
795 props['templ'] = self.t
793 props['ctx'] = ctx
796 props['ctx'] = ctx
794 props['repo'] = self.repo
797 props['repo'] = self.repo
795 props['revcache'] = {'copies': copies}
798 props['revcache'] = {'copies': copies}
796 props['cache'] = self.cache
799 props['cache'] = self.cache
797
800
798 # find correct templates for current mode
801 # find correct templates for current mode
799
802
800 tmplmodes = [
803 tmplmodes = [
801 (True, None),
804 (True, None),
802 (self.ui.verbose, 'verbose'),
805 (self.ui.verbose, 'verbose'),
803 (self.ui.quiet, 'quiet'),
806 (self.ui.quiet, 'quiet'),
804 (self.ui.debugflag, 'debug'),
807 (self.ui.debugflag, 'debug'),
805 ]
808 ]
806
809
807 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
810 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
808 for mode, postfix in tmplmodes:
811 for mode, postfix in tmplmodes:
809 for type in types:
812 for type in types:
810 cur = postfix and ('%s_%s' % (type, postfix)) or type
813 cur = postfix and ('%s_%s' % (type, postfix)) or type
811 if mode and cur in self.t:
814 if mode and cur in self.t:
812 types[type] = cur
815 types[type] = cur
813
816
814 try:
817 try:
815
818
816 # write header
819 # write header
817 if types['header']:
820 if types['header']:
818 h = templater.stringify(self.t(types['header'], **props))
821 h = templater.stringify(self.t(types['header'], **props))
819 if self.buffered:
822 if self.buffered:
820 self.header[ctx.rev()] = h
823 self.header[ctx.rev()] = h
821 else:
824 else:
822 if self.lastheader != h:
825 if self.lastheader != h:
823 self.lastheader = h
826 self.lastheader = h
824 self.ui.write(h)
827 self.ui.write(h)
825
828
826 # write changeset metadata, then patch if requested
829 # write changeset metadata, then patch if requested
827 key = types['changeset']
830 key = types['changeset']
828 self.ui.write(templater.stringify(self.t(key, **props)))
831 self.ui.write(templater.stringify(self.t(key, **props)))
829 self.showpatch(ctx.node(), matchfn)
832 self.showpatch(ctx.node(), matchfn)
830
833
831 if types['footer']:
834 if types['footer']:
832 if not self.footer:
835 if not self.footer:
833 self.footer = templater.stringify(self.t(types['footer'],
836 self.footer = templater.stringify(self.t(types['footer'],
834 **props))
837 **props))
835
838
836 except KeyError, inst:
839 except KeyError, inst:
837 msg = _("%s: no key named '%s'")
840 msg = _("%s: no key named '%s'")
838 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
841 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
839 except SyntaxError, inst:
842 except SyntaxError, inst:
840 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
843 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
841
844
842 def show_changeset(ui, repo, opts, buffered=False):
845 def show_changeset(ui, repo, opts, buffered=False):
843 """show one changeset using template or regular display.
846 """show one changeset using template or regular display.
844
847
845 Display format will be the first non-empty hit of:
848 Display format will be the first non-empty hit of:
846 1. option 'template'
849 1. option 'template'
847 2. option 'style'
850 2. option 'style'
848 3. [ui] setting 'logtemplate'
851 3. [ui] setting 'logtemplate'
849 4. [ui] setting 'style'
852 4. [ui] setting 'style'
850 If all of these values are either the unset or the empty string,
853 If all of these values are either the unset or the empty string,
851 regular display via changeset_printer() is done.
854 regular display via changeset_printer() is done.
852 """
855 """
853 # options
856 # options
854 patch = False
857 patch = False
855 if opts.get('patch') or opts.get('stat'):
858 if opts.get('patch') or opts.get('stat'):
856 patch = scmutil.matchall(repo)
859 patch = scmutil.matchall(repo)
857
860
858 tmpl = opts.get('template')
861 tmpl = opts.get('template')
859 style = None
862 style = None
860 if tmpl:
863 if tmpl:
861 tmpl = templater.parsestring(tmpl, quoted=False)
864 tmpl = templater.parsestring(tmpl, quoted=False)
862 else:
865 else:
863 style = opts.get('style')
866 style = opts.get('style')
864
867
865 # ui settings
868 # ui settings
866 if not (tmpl or style):
869 if not (tmpl or style):
867 tmpl = ui.config('ui', 'logtemplate')
870 tmpl = ui.config('ui', 'logtemplate')
868 if tmpl:
871 if tmpl:
869 tmpl = templater.parsestring(tmpl)
872 tmpl = templater.parsestring(tmpl)
870 else:
873 else:
871 style = util.expandpath(ui.config('ui', 'style', ''))
874 style = util.expandpath(ui.config('ui', 'style', ''))
872
875
873 if not (tmpl or style):
876 if not (tmpl or style):
874 return changeset_printer(ui, repo, patch, opts, buffered)
877 return changeset_printer(ui, repo, patch, opts, buffered)
875
878
876 mapfile = None
879 mapfile = None
877 if style and not tmpl:
880 if style and not tmpl:
878 mapfile = style
881 mapfile = style
879 if not os.path.split(mapfile)[0]:
882 if not os.path.split(mapfile)[0]:
880 mapname = (templater.templatepath('map-cmdline.' + mapfile)
883 mapname = (templater.templatepath('map-cmdline.' + mapfile)
881 or templater.templatepath(mapfile))
884 or templater.templatepath(mapfile))
882 if mapname:
885 if mapname:
883 mapfile = mapname
886 mapfile = mapname
884
887
885 try:
888 try:
886 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
889 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
887 except SyntaxError, inst:
890 except SyntaxError, inst:
888 raise util.Abort(inst.args[0])
891 raise util.Abort(inst.args[0])
889 if tmpl:
892 if tmpl:
890 t.use_template(tmpl)
893 t.use_template(tmpl)
891 return t
894 return t
892
895
893 def finddate(ui, repo, date):
896 def finddate(ui, repo, date):
894 """Find the tipmost changeset that matches the given date spec"""
897 """Find the tipmost changeset that matches the given date spec"""
895
898
896 df = util.matchdate(date)
899 df = util.matchdate(date)
897 m = scmutil.matchall(repo)
900 m = scmutil.matchall(repo)
898 results = {}
901 results = {}
899
902
900 def prep(ctx, fns):
903 def prep(ctx, fns):
901 d = ctx.date()
904 d = ctx.date()
902 if df(d[0]):
905 if df(d[0]):
903 results[ctx.rev()] = d
906 results[ctx.rev()] = d
904
907
905 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
908 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
906 rev = ctx.rev()
909 rev = ctx.rev()
907 if rev in results:
910 if rev in results:
908 ui.status(_("Found revision %s from %s\n") %
911 ui.status(_("Found revision %s from %s\n") %
909 (rev, util.datestr(results[rev])))
912 (rev, util.datestr(results[rev])))
910 return str(rev)
913 return str(rev)
911
914
912 raise util.Abort(_("revision matching date not found"))
915 raise util.Abort(_("revision matching date not found"))
913
916
914 def walkchangerevs(repo, match, opts, prepare):
917 def walkchangerevs(repo, match, opts, prepare):
915 '''Iterate over files and the revs in which they changed.
918 '''Iterate over files and the revs in which they changed.
916
919
917 Callers most commonly need to iterate backwards over the history
920 Callers most commonly need to iterate backwards over the history
918 in which they are interested. Doing so has awful (quadratic-looking)
921 in which they are interested. Doing so has awful (quadratic-looking)
919 performance, so we use iterators in a "windowed" way.
922 performance, so we use iterators in a "windowed" way.
920
923
921 We walk a window of revisions in the desired order. Within the
924 We walk a window of revisions in the desired order. Within the
922 window, we first walk forwards to gather data, then in the desired
925 window, we first walk forwards to gather data, then in the desired
923 order (usually backwards) to display it.
926 order (usually backwards) to display it.
924
927
925 This function returns an iterator yielding contexts. Before
928 This function returns an iterator yielding contexts. Before
926 yielding each context, the iterator will first call the prepare
929 yielding each context, the iterator will first call the prepare
927 function on each context in the window in forward order.'''
930 function on each context in the window in forward order.'''
928
931
929 def increasing_windows(start, end, windowsize=8, sizelimit=512):
932 def increasing_windows(start, end, windowsize=8, sizelimit=512):
930 if start < end:
933 if start < end:
931 while start < end:
934 while start < end:
932 yield start, min(windowsize, end - start)
935 yield start, min(windowsize, end - start)
933 start += windowsize
936 start += windowsize
934 if windowsize < sizelimit:
937 if windowsize < sizelimit:
935 windowsize *= 2
938 windowsize *= 2
936 else:
939 else:
937 while start > end:
940 while start > end:
938 yield start, min(windowsize, start - end - 1)
941 yield start, min(windowsize, start - end - 1)
939 start -= windowsize
942 start -= windowsize
940 if windowsize < sizelimit:
943 if windowsize < sizelimit:
941 windowsize *= 2
944 windowsize *= 2
942
945
943 follow = opts.get('follow') or opts.get('follow_first')
946 follow = opts.get('follow') or opts.get('follow_first')
944
947
945 if not len(repo):
948 if not len(repo):
946 return []
949 return []
947
950
948 if follow:
951 if follow:
949 defrange = '%s:0' % repo['.'].rev()
952 defrange = '%s:0' % repo['.'].rev()
950 else:
953 else:
951 defrange = '-1:0'
954 defrange = '-1:0'
952 revs = scmutil.revrange(repo, opts['rev'] or [defrange])
955 revs = scmutil.revrange(repo, opts['rev'] or [defrange])
953 if not revs:
956 if not revs:
954 return []
957 return []
955 wanted = set()
958 wanted = set()
956 slowpath = match.anypats() or (match.files() and opts.get('removed'))
959 slowpath = match.anypats() or (match.files() and opts.get('removed'))
957 fncache = {}
960 fncache = {}
958 change = util.cachefunc(repo.changectx)
961 change = util.cachefunc(repo.changectx)
959
962
960 # First step is to fill wanted, the set of revisions that we want to yield.
963 # First step is to fill wanted, the set of revisions that we want to yield.
961 # When it does not induce extra cost, we also fill fncache for revisions in
964 # When it does not induce extra cost, we also fill fncache for revisions in
962 # wanted: a cache of filenames that were changed (ctx.files()) and that
965 # wanted: a cache of filenames that were changed (ctx.files()) and that
963 # match the file filtering conditions.
966 # match the file filtering conditions.
964
967
965 if not slowpath and not match.files():
968 if not slowpath and not match.files():
966 # No files, no patterns. Display all revs.
969 # No files, no patterns. Display all revs.
967 wanted = set(revs)
970 wanted = set(revs)
968 copies = []
971 copies = []
969
972
970 if not slowpath:
973 if not slowpath:
971 # We only have to read through the filelog to find wanted revisions
974 # We only have to read through the filelog to find wanted revisions
972
975
973 minrev, maxrev = min(revs), max(revs)
976 minrev, maxrev = min(revs), max(revs)
974 def filerevgen(filelog, last):
977 def filerevgen(filelog, last):
975 """
978 """
976 Only files, no patterns. Check the history of each file.
979 Only files, no patterns. Check the history of each file.
977
980
978 Examines filelog entries within minrev, maxrev linkrev range
981 Examines filelog entries within minrev, maxrev linkrev range
979 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
982 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
980 tuples in backwards order
983 tuples in backwards order
981 """
984 """
982 cl_count = len(repo)
985 cl_count = len(repo)
983 revs = []
986 revs = []
984 for j in xrange(0, last + 1):
987 for j in xrange(0, last + 1):
985 linkrev = filelog.linkrev(j)
988 linkrev = filelog.linkrev(j)
986 if linkrev < minrev:
989 if linkrev < minrev:
987 continue
990 continue
988 # only yield rev for which we have the changelog, it can
991 # only yield rev for which we have the changelog, it can
989 # happen while doing "hg log" during a pull or commit
992 # happen while doing "hg log" during a pull or commit
990 if linkrev >= cl_count:
993 if linkrev >= cl_count:
991 break
994 break
992
995
993 parentlinkrevs = []
996 parentlinkrevs = []
994 for p in filelog.parentrevs(j):
997 for p in filelog.parentrevs(j):
995 if p != nullrev:
998 if p != nullrev:
996 parentlinkrevs.append(filelog.linkrev(p))
999 parentlinkrevs.append(filelog.linkrev(p))
997 n = filelog.node(j)
1000 n = filelog.node(j)
998 revs.append((linkrev, parentlinkrevs,
1001 revs.append((linkrev, parentlinkrevs,
999 follow and filelog.renamed(n)))
1002 follow and filelog.renamed(n)))
1000
1003
1001 return reversed(revs)
1004 return reversed(revs)
1002 def iterfiles():
1005 def iterfiles():
1003 for filename in match.files():
1006 for filename in match.files():
1004 yield filename, None
1007 yield filename, None
1005 for filename_node in copies:
1008 for filename_node in copies:
1006 yield filename_node
1009 yield filename_node
1007 for file_, node in iterfiles():
1010 for file_, node in iterfiles():
1008 filelog = repo.file(file_)
1011 filelog = repo.file(file_)
1009 if not len(filelog):
1012 if not len(filelog):
1010 if node is None:
1013 if node is None:
1011 # A zero count may be a directory or deleted file, so
1014 # A zero count may be a directory or deleted file, so
1012 # try to find matching entries on the slow path.
1015 # try to find matching entries on the slow path.
1013 if follow:
1016 if follow:
1014 raise util.Abort(
1017 raise util.Abort(
1015 _('cannot follow nonexistent file: "%s"') % file_)
1018 _('cannot follow nonexistent file: "%s"') % file_)
1016 slowpath = True
1019 slowpath = True
1017 break
1020 break
1018 else:
1021 else:
1019 continue
1022 continue
1020
1023
1021 if node is None:
1024 if node is None:
1022 last = len(filelog) - 1
1025 last = len(filelog) - 1
1023 else:
1026 else:
1024 last = filelog.rev(node)
1027 last = filelog.rev(node)
1025
1028
1026
1029
1027 # keep track of all ancestors of the file
1030 # keep track of all ancestors of the file
1028 ancestors = set([filelog.linkrev(last)])
1031 ancestors = set([filelog.linkrev(last)])
1029
1032
1030 # iterate from latest to oldest revision
1033 # iterate from latest to oldest revision
1031 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1034 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1032 if not follow:
1035 if not follow:
1033 if rev > maxrev:
1036 if rev > maxrev:
1034 continue
1037 continue
1035 else:
1038 else:
1036 # Note that last might not be the first interesting
1039 # Note that last might not be the first interesting
1037 # rev to us:
1040 # rev to us:
1038 # if the file has been changed after maxrev, we'll
1041 # if the file has been changed after maxrev, we'll
1039 # have linkrev(last) > maxrev, and we still need
1042 # have linkrev(last) > maxrev, and we still need
1040 # to explore the file graph
1043 # to explore the file graph
1041 if rev not in ancestors:
1044 if rev not in ancestors:
1042 continue
1045 continue
1043 # XXX insert 1327 fix here
1046 # XXX insert 1327 fix here
1044 if flparentlinkrevs:
1047 if flparentlinkrevs:
1045 ancestors.update(flparentlinkrevs)
1048 ancestors.update(flparentlinkrevs)
1046
1049
1047 fncache.setdefault(rev, []).append(file_)
1050 fncache.setdefault(rev, []).append(file_)
1048 wanted.add(rev)
1051 wanted.add(rev)
1049 if copied:
1052 if copied:
1050 copies.append(copied)
1053 copies.append(copied)
1051 if slowpath:
1054 if slowpath:
1052 # We have to read the changelog to match filenames against
1055 # We have to read the changelog to match filenames against
1053 # changed files
1056 # changed files
1054
1057
1055 if follow:
1058 if follow:
1056 raise util.Abort(_('can only follow copies/renames for explicit '
1059 raise util.Abort(_('can only follow copies/renames for explicit '
1057 'filenames'))
1060 'filenames'))
1058
1061
1059 # The slow path checks files modified in every changeset.
1062 # The slow path checks files modified in every changeset.
1060 for i in sorted(revs):
1063 for i in sorted(revs):
1061 ctx = change(i)
1064 ctx = change(i)
1062 matches = filter(match, ctx.files())
1065 matches = filter(match, ctx.files())
1063 if matches:
1066 if matches:
1064 fncache[i] = matches
1067 fncache[i] = matches
1065 wanted.add(i)
1068 wanted.add(i)
1066
1069
1067 class followfilter(object):
1070 class followfilter(object):
1068 def __init__(self, onlyfirst=False):
1071 def __init__(self, onlyfirst=False):
1069 self.startrev = nullrev
1072 self.startrev = nullrev
1070 self.roots = set()
1073 self.roots = set()
1071 self.onlyfirst = onlyfirst
1074 self.onlyfirst = onlyfirst
1072
1075
1073 def match(self, rev):
1076 def match(self, rev):
1074 def realparents(rev):
1077 def realparents(rev):
1075 if self.onlyfirst:
1078 if self.onlyfirst:
1076 return repo.changelog.parentrevs(rev)[0:1]
1079 return repo.changelog.parentrevs(rev)[0:1]
1077 else:
1080 else:
1078 return filter(lambda x: x != nullrev,
1081 return filter(lambda x: x != nullrev,
1079 repo.changelog.parentrevs(rev))
1082 repo.changelog.parentrevs(rev))
1080
1083
1081 if self.startrev == nullrev:
1084 if self.startrev == nullrev:
1082 self.startrev = rev
1085 self.startrev = rev
1083 return True
1086 return True
1084
1087
1085 if rev > self.startrev:
1088 if rev > self.startrev:
1086 # forward: all descendants
1089 # forward: all descendants
1087 if not self.roots:
1090 if not self.roots:
1088 self.roots.add(self.startrev)
1091 self.roots.add(self.startrev)
1089 for parent in realparents(rev):
1092 for parent in realparents(rev):
1090 if parent in self.roots:
1093 if parent in self.roots:
1091 self.roots.add(rev)
1094 self.roots.add(rev)
1092 return True
1095 return True
1093 else:
1096 else:
1094 # backwards: all parents
1097 # backwards: all parents
1095 if not self.roots:
1098 if not self.roots:
1096 self.roots.update(realparents(self.startrev))
1099 self.roots.update(realparents(self.startrev))
1097 if rev in self.roots:
1100 if rev in self.roots:
1098 self.roots.remove(rev)
1101 self.roots.remove(rev)
1099 self.roots.update(realparents(rev))
1102 self.roots.update(realparents(rev))
1100 return True
1103 return True
1101
1104
1102 return False
1105 return False
1103
1106
1104 # it might be worthwhile to do this in the iterator if the rev range
1107 # it might be worthwhile to do this in the iterator if the rev range
1105 # is descending and the prune args are all within that range
1108 # is descending and the prune args are all within that range
1106 for rev in opts.get('prune', ()):
1109 for rev in opts.get('prune', ()):
1107 rev = repo.changelog.rev(repo.lookup(rev))
1110 rev = repo.changelog.rev(repo.lookup(rev))
1108 ff = followfilter()
1111 ff = followfilter()
1109 stop = min(revs[0], revs[-1])
1112 stop = min(revs[0], revs[-1])
1110 for x in xrange(rev, stop - 1, -1):
1113 for x in xrange(rev, stop - 1, -1):
1111 if ff.match(x):
1114 if ff.match(x):
1112 wanted.discard(x)
1115 wanted.discard(x)
1113
1116
1114 # Now that wanted is correctly initialized, we can iterate over the
1117 # Now that wanted is correctly initialized, we can iterate over the
1115 # revision range, yielding only revisions in wanted.
1118 # revision range, yielding only revisions in wanted.
1116 def iterate():
1119 def iterate():
1117 if follow and not match.files():
1120 if follow and not match.files():
1118 ff = followfilter(onlyfirst=opts.get('follow_first'))
1121 ff = followfilter(onlyfirst=opts.get('follow_first'))
1119 def want(rev):
1122 def want(rev):
1120 return ff.match(rev) and rev in wanted
1123 return ff.match(rev) and rev in wanted
1121 else:
1124 else:
1122 def want(rev):
1125 def want(rev):
1123 return rev in wanted
1126 return rev in wanted
1124
1127
1125 for i, window in increasing_windows(0, len(revs)):
1128 for i, window in increasing_windows(0, len(revs)):
1126 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1129 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1127 for rev in sorted(nrevs):
1130 for rev in sorted(nrevs):
1128 fns = fncache.get(rev)
1131 fns = fncache.get(rev)
1129 ctx = change(rev)
1132 ctx = change(rev)
1130 if not fns:
1133 if not fns:
1131 def fns_generator():
1134 def fns_generator():
1132 for f in ctx.files():
1135 for f in ctx.files():
1133 if match(f):
1136 if match(f):
1134 yield f
1137 yield f
1135 fns = fns_generator()
1138 fns = fns_generator()
1136 prepare(ctx, fns)
1139 prepare(ctx, fns)
1137 for rev in nrevs:
1140 for rev in nrevs:
1138 yield change(rev)
1141 yield change(rev)
1139 return iterate()
1142 return iterate()
1140
1143
1141 def add(ui, repo, match, dryrun, listsubrepos, prefix):
1144 def add(ui, repo, match, dryrun, listsubrepos, prefix):
1142 join = lambda f: os.path.join(prefix, f)
1145 join = lambda f: os.path.join(prefix, f)
1143 bad = []
1146 bad = []
1144 oldbad = match.bad
1147 oldbad = match.bad
1145 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1148 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1146 names = []
1149 names = []
1147 wctx = repo[None]
1150 wctx = repo[None]
1148 cca = None
1151 cca = None
1149 abort, warn = scmutil.checkportabilityalert(ui)
1152 abort, warn = scmutil.checkportabilityalert(ui)
1150 if abort or warn:
1153 if abort or warn:
1151 cca = scmutil.casecollisionauditor(ui, abort, wctx)
1154 cca = scmutil.casecollisionauditor(ui, abort, wctx)
1152 for f in repo.walk(match):
1155 for f in repo.walk(match):
1153 exact = match.exact(f)
1156 exact = match.exact(f)
1154 if exact or f not in repo.dirstate:
1157 if exact or f not in repo.dirstate:
1155 if cca:
1158 if cca:
1156 cca(f)
1159 cca(f)
1157 names.append(f)
1160 names.append(f)
1158 if ui.verbose or not exact:
1161 if ui.verbose or not exact:
1159 ui.status(_('adding %s\n') % match.rel(join(f)))
1162 ui.status(_('adding %s\n') % match.rel(join(f)))
1160
1163
1161 if listsubrepos:
1164 if listsubrepos:
1162 for subpath in wctx.substate:
1165 for subpath in wctx.substate:
1163 sub = wctx.sub(subpath)
1166 sub = wctx.sub(subpath)
1164 try:
1167 try:
1165 submatch = matchmod.narrowmatcher(subpath, match)
1168 submatch = matchmod.narrowmatcher(subpath, match)
1166 bad.extend(sub.add(ui, submatch, dryrun, prefix))
1169 bad.extend(sub.add(ui, submatch, dryrun, prefix))
1167 except error.LookupError:
1170 except error.LookupError:
1168 ui.status(_("skipping missing subrepository: %s\n")
1171 ui.status(_("skipping missing subrepository: %s\n")
1169 % join(subpath))
1172 % join(subpath))
1170
1173
1171 if not dryrun:
1174 if not dryrun:
1172 rejected = wctx.add(names, prefix)
1175 rejected = wctx.add(names, prefix)
1173 bad.extend(f for f in rejected if f in match.files())
1176 bad.extend(f for f in rejected if f in match.files())
1174 return bad
1177 return bad
1175
1178
1176 def commit(ui, repo, commitfunc, pats, opts):
1179 def commit(ui, repo, commitfunc, pats, opts):
1177 '''commit the specified files or all outstanding changes'''
1180 '''commit the specified files or all outstanding changes'''
1178 date = opts.get('date')
1181 date = opts.get('date')
1179 if date:
1182 if date:
1180 opts['date'] = util.parsedate(date)
1183 opts['date'] = util.parsedate(date)
1181 message = logmessage(ui, opts)
1184 message = logmessage(ui, opts)
1182
1185
1183 # extract addremove carefully -- this function can be called from a command
1186 # extract addremove carefully -- this function can be called from a command
1184 # that doesn't support addremove
1187 # that doesn't support addremove
1185 if opts.get('addremove'):
1188 if opts.get('addremove'):
1186 scmutil.addremove(repo, pats, opts)
1189 scmutil.addremove(repo, pats, opts)
1187
1190
1188 return commitfunc(ui, repo, message,
1191 return commitfunc(ui, repo, message,
1189 scmutil.match(repo[None], pats, opts), opts)
1192 scmutil.match(repo[None], pats, opts), opts)
1190
1193
1191 def commiteditor(repo, ctx, subs):
1194 def commiteditor(repo, ctx, subs):
1192 if ctx.description():
1195 if ctx.description():
1193 return ctx.description()
1196 return ctx.description()
1194 return commitforceeditor(repo, ctx, subs)
1197 return commitforceeditor(repo, ctx, subs)
1195
1198
1196 def commitforceeditor(repo, ctx, subs):
1199 def commitforceeditor(repo, ctx, subs):
1197 edittext = []
1200 edittext = []
1198 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1201 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1199 if ctx.description():
1202 if ctx.description():
1200 edittext.append(ctx.description())
1203 edittext.append(ctx.description())
1201 edittext.append("")
1204 edittext.append("")
1202 edittext.append("") # Empty line between message and comments.
1205 edittext.append("") # Empty line between message and comments.
1203 edittext.append(_("HG: Enter commit message."
1206 edittext.append(_("HG: Enter commit message."
1204 " Lines beginning with 'HG:' are removed."))
1207 " Lines beginning with 'HG:' are removed."))
1205 edittext.append(_("HG: Leave message empty to abort commit."))
1208 edittext.append(_("HG: Leave message empty to abort commit."))
1206 edittext.append("HG: --")
1209 edittext.append("HG: --")
1207 edittext.append(_("HG: user: %s") % ctx.user())
1210 edittext.append(_("HG: user: %s") % ctx.user())
1208 if ctx.p2():
1211 if ctx.p2():
1209 edittext.append(_("HG: branch merge"))
1212 edittext.append(_("HG: branch merge"))
1210 if ctx.branch():
1213 if ctx.branch():
1211 edittext.append(_("HG: branch '%s'") % ctx.branch())
1214 edittext.append(_("HG: branch '%s'") % ctx.branch())
1212 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1215 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1213 edittext.extend([_("HG: added %s") % f for f in added])
1216 edittext.extend([_("HG: added %s") % f for f in added])
1214 edittext.extend([_("HG: changed %s") % f for f in modified])
1217 edittext.extend([_("HG: changed %s") % f for f in modified])
1215 edittext.extend([_("HG: removed %s") % f for f in removed])
1218 edittext.extend([_("HG: removed %s") % f for f in removed])
1216 if not added and not modified and not removed:
1219 if not added and not modified and not removed:
1217 edittext.append(_("HG: no files changed"))
1220 edittext.append(_("HG: no files changed"))
1218 edittext.append("")
1221 edittext.append("")
1219 # run editor in the repository root
1222 # run editor in the repository root
1220 olddir = os.getcwd()
1223 olddir = os.getcwd()
1221 os.chdir(repo.root)
1224 os.chdir(repo.root)
1222 text = repo.ui.edit("\n".join(edittext), ctx.user())
1225 text = repo.ui.edit("\n".join(edittext), ctx.user())
1223 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1226 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1224 os.chdir(olddir)
1227 os.chdir(olddir)
1225
1228
1226 if not text.strip():
1229 if not text.strip():
1227 raise util.Abort(_("empty commit message"))
1230 raise util.Abort(_("empty commit message"))
1228
1231
1229 return text
1232 return text
1230
1233
1231 def command(table):
1234 def command(table):
1232 '''returns a function object bound to table which can be used as
1235 '''returns a function object bound to table which can be used as
1233 a decorator for populating table as a command table'''
1236 a decorator for populating table as a command table'''
1234
1237
1235 def cmd(name, options, synopsis=None):
1238 def cmd(name, options, synopsis=None):
1236 def decorator(func):
1239 def decorator(func):
1237 if synopsis:
1240 if synopsis:
1238 table[name] = func, options[:], synopsis
1241 table[name] = func, options[:], synopsis
1239 else:
1242 else:
1240 table[name] = func, options[:]
1243 table[name] = func, options[:]
1241 return func
1244 return func
1242 return decorator
1245 return decorator
1243
1246
1244 return cmd
1247 return cmd
@@ -1,5188 +1,5189 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, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge
18 import dagparser, context, simplemerge
19 import random, setdiscovery, treediscovery, dagutil
19 import random, setdiscovery, treediscovery, dagutil
20
20
21 table = {}
21 table = {}
22
22
23 command = cmdutil.command(table)
23 command = cmdutil.command(table)
24
24
25 # common command options
25 # common command options
26
26
27 globalopts = [
27 globalopts = [
28 ('R', 'repository', '',
28 ('R', 'repository', '',
29 _('repository root directory or name of overlay bundle file'),
29 _('repository root directory or name of overlay bundle file'),
30 _('REPO')),
30 _('REPO')),
31 ('', 'cwd', '',
31 ('', 'cwd', '',
32 _('change working directory'), _('DIR')),
32 _('change working directory'), _('DIR')),
33 ('y', 'noninteractive', None,
33 ('y', 'noninteractive', None,
34 _('do not prompt, automatically pick the first choice for all prompts')),
34 _('do not prompt, automatically pick the first choice for all prompts')),
35 ('q', 'quiet', None, _('suppress output')),
35 ('q', 'quiet', None, _('suppress output')),
36 ('v', 'verbose', None, _('enable additional output')),
36 ('v', 'verbose', None, _('enable additional output')),
37 ('', 'config', [],
37 ('', 'config', [],
38 _('set/override config option (use \'section.name=value\')'),
38 _('set/override config option (use \'section.name=value\')'),
39 _('CONFIG')),
39 _('CONFIG')),
40 ('', 'debug', None, _('enable debugging output')),
40 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debugger', None, _('start debugger')),
41 ('', 'debugger', None, _('start debugger')),
42 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
42 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 _('ENCODE')),
43 _('ENCODE')),
44 ('', 'encodingmode', encoding.encodingmode,
44 ('', 'encodingmode', encoding.encodingmode,
45 _('set the charset encoding mode'), _('MODE')),
45 _('set the charset encoding mode'), _('MODE')),
46 ('', 'traceback', None, _('always print a traceback on exception')),
46 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'time', None, _('time how long the command takes')),
47 ('', 'time', None, _('time how long the command takes')),
48 ('', 'profile', None, _('print command execution profile')),
48 ('', 'profile', None, _('print command execution profile')),
49 ('', 'version', None, _('output version information and exit')),
49 ('', 'version', None, _('output version information and exit')),
50 ('h', 'help', None, _('display help and exit')),
50 ('h', 'help', None, _('display help and exit')),
51 ]
51 ]
52
52
53 dryrunopts = [('n', 'dry-run', None,
53 dryrunopts = [('n', 'dry-run', None,
54 _('do not perform actions, just print output'))]
54 _('do not perform actions, just print output'))]
55
55
56 remoteopts = [
56 remoteopts = [
57 ('e', 'ssh', '',
57 ('e', 'ssh', '',
58 _('specify ssh command to use'), _('CMD')),
58 _('specify ssh command to use'), _('CMD')),
59 ('', 'remotecmd', '',
59 ('', 'remotecmd', '',
60 _('specify hg command to run on the remote side'), _('CMD')),
60 _('specify hg command to run on the remote side'), _('CMD')),
61 ('', 'insecure', None,
61 ('', 'insecure', None,
62 _('do not verify server certificate (ignoring web.cacerts config)')),
62 _('do not verify server certificate (ignoring web.cacerts config)')),
63 ]
63 ]
64
64
65 walkopts = [
65 walkopts = [
66 ('I', 'include', [],
66 ('I', 'include', [],
67 _('include names matching the given patterns'), _('PATTERN')),
67 _('include names matching the given patterns'), _('PATTERN')),
68 ('X', 'exclude', [],
68 ('X', 'exclude', [],
69 _('exclude names matching the given patterns'), _('PATTERN')),
69 _('exclude names matching the given patterns'), _('PATTERN')),
70 ]
70 ]
71
71
72 commitopts = [
72 commitopts = [
73 ('m', 'message', '',
73 ('m', 'message', '',
74 _('use text as commit message'), _('TEXT')),
74 _('use text as commit message'), _('TEXT')),
75 ('l', 'logfile', '',
75 ('l', 'logfile', '',
76 _('read commit message from file'), _('FILE')),
76 _('read commit message from file'), _('FILE')),
77 ]
77 ]
78
78
79 commitopts2 = [
79 commitopts2 = [
80 ('d', 'date', '',
80 ('d', 'date', '',
81 _('record the specified date as commit date'), _('DATE')),
81 _('record the specified date as commit date'), _('DATE')),
82 ('u', 'user', '',
82 ('u', 'user', '',
83 _('record the specified user as committer'), _('USER')),
83 _('record the specified user as committer'), _('USER')),
84 ]
84 ]
85
85
86 templateopts = [
86 templateopts = [
87 ('', 'style', '',
87 ('', 'style', '',
88 _('display using template map file'), _('STYLE')),
88 _('display using template map file'), _('STYLE')),
89 ('', 'template', '',
89 ('', 'template', '',
90 _('display with template'), _('TEMPLATE')),
90 _('display with template'), _('TEMPLATE')),
91 ]
91 ]
92
92
93 logopts = [
93 logopts = [
94 ('p', 'patch', None, _('show patch')),
94 ('p', 'patch', None, _('show patch')),
95 ('g', 'git', None, _('use git extended diff format')),
95 ('g', 'git', None, _('use git extended diff format')),
96 ('l', 'limit', '',
96 ('l', 'limit', '',
97 _('limit number of changes displayed'), _('NUM')),
97 _('limit number of changes displayed'), _('NUM')),
98 ('M', 'no-merges', None, _('do not show merges')),
98 ('M', 'no-merges', None, _('do not show merges')),
99 ('', 'stat', None, _('output diffstat-style summary of changes')),
99 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ] + templateopts
100 ] + templateopts
101
101
102 diffopts = [
102 diffopts = [
103 ('a', 'text', None, _('treat all files as text')),
103 ('a', 'text', None, _('treat all files as text')),
104 ('g', 'git', None, _('use git extended diff format')),
104 ('g', 'git', None, _('use git extended diff format')),
105 ('', 'nodates', None, _('omit dates from diff headers'))
105 ('', 'nodates', None, _('omit dates from diff headers'))
106 ]
106 ]
107
107
108 diffopts2 = [
108 diffopts2 = [
109 ('p', 'show-function', None, _('show which function each change is in')),
109 ('p', 'show-function', None, _('show which function each change is in')),
110 ('', 'reverse', None, _('produce a diff that undoes the changes')),
110 ('', 'reverse', None, _('produce a diff that undoes the changes')),
111 ('w', 'ignore-all-space', None,
111 ('w', 'ignore-all-space', None,
112 _('ignore white space when comparing lines')),
112 _('ignore white space when comparing lines')),
113 ('b', 'ignore-space-change', None,
113 ('b', 'ignore-space-change', None,
114 _('ignore changes in the amount of white space')),
114 _('ignore changes in the amount of white space')),
115 ('B', 'ignore-blank-lines', None,
115 ('B', 'ignore-blank-lines', None,
116 _('ignore changes whose lines are all blank')),
116 _('ignore changes whose lines are all blank')),
117 ('U', 'unified', '',
117 ('U', 'unified', '',
118 _('number of lines of context to show'), _('NUM')),
118 _('number of lines of context to show'), _('NUM')),
119 ('', 'stat', None, _('output diffstat-style summary of changes')),
119 ('', 'stat', None, _('output diffstat-style summary of changes')),
120 ]
120 ]
121
121
122 mergetoolopts = [
122 mergetoolopts = [
123 ('t', 'tool', '', _('specify merge tool')),
123 ('t', 'tool', '', _('specify merge tool')),
124 ]
124 ]
125
125
126 similarityopts = [
126 similarityopts = [
127 ('s', 'similarity', '',
127 ('s', 'similarity', '',
128 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
128 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
129 ]
129 ]
130
130
131 subrepoopts = [
131 subrepoopts = [
132 ('S', 'subrepos', None,
132 ('S', 'subrepos', None,
133 _('recurse into subrepositories'))
133 _('recurse into subrepositories'))
134 ]
134 ]
135
135
136 # Commands start here, listed alphabetically
136 # Commands start here, listed alphabetically
137
137
138 @command('^add',
138 @command('^add',
139 walkopts + subrepoopts + dryrunopts,
139 walkopts + subrepoopts + dryrunopts,
140 _('[OPTION]... [FILE]...'))
140 _('[OPTION]... [FILE]...'))
141 def add(ui, repo, *pats, **opts):
141 def add(ui, repo, *pats, **opts):
142 """add the specified files on the next commit
142 """add the specified files on the next commit
143
143
144 Schedule files to be version controlled and added to the
144 Schedule files to be version controlled and added to the
145 repository.
145 repository.
146
146
147 The files will be added to the repository at the next commit. To
147 The files will be added to the repository at the next commit. To
148 undo an add before that, see :hg:`forget`.
148 undo an add before that, see :hg:`forget`.
149
149
150 If no names are given, add all files to the repository.
150 If no names are given, add all files to the repository.
151
151
152 .. container:: verbose
152 .. container:: verbose
153
153
154 An example showing how new (unknown) files are added
154 An example showing how new (unknown) files are added
155 automatically by :hg:`add`::
155 automatically by :hg:`add`::
156
156
157 $ ls
157 $ ls
158 foo.c
158 foo.c
159 $ hg status
159 $ hg status
160 ? foo.c
160 ? foo.c
161 $ hg add
161 $ hg add
162 adding foo.c
162 adding foo.c
163 $ hg status
163 $ hg status
164 A foo.c
164 A foo.c
165
165
166 Returns 0 if all files are successfully added.
166 Returns 0 if all files are successfully added.
167 """
167 """
168
168
169 m = scmutil.match(repo[None], pats, opts)
169 m = scmutil.match(repo[None], pats, opts)
170 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
170 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
171 opts.get('subrepos'), prefix="")
171 opts.get('subrepos'), prefix="")
172 return rejected and 1 or 0
172 return rejected and 1 or 0
173
173
174 @command('addremove',
174 @command('addremove',
175 similarityopts + walkopts + dryrunopts,
175 similarityopts + walkopts + dryrunopts,
176 _('[OPTION]... [FILE]...'))
176 _('[OPTION]... [FILE]...'))
177 def addremove(ui, repo, *pats, **opts):
177 def addremove(ui, repo, *pats, **opts):
178 """add all new files, delete all missing files
178 """add all new files, delete all missing files
179
179
180 Add all new files and remove all missing files from the
180 Add all new files and remove all missing files from the
181 repository.
181 repository.
182
182
183 New files are ignored if they match any of the patterns in
183 New files are ignored if they match any of the patterns in
184 ``.hgignore``. As with add, these changes take effect at the next
184 ``.hgignore``. As with add, these changes take effect at the next
185 commit.
185 commit.
186
186
187 Use the -s/--similarity option to detect renamed files. With a
187 Use the -s/--similarity option to detect renamed files. With a
188 parameter greater than 0, this compares every removed file with
188 parameter greater than 0, this compares every removed file with
189 every added file and records those similar enough as renames. This
189 every added file and records those similar enough as renames. This
190 option takes a percentage between 0 (disabled) and 100 (files must
190 option takes a percentage between 0 (disabled) and 100 (files must
191 be identical) as its parameter. Detecting renamed files this way
191 be identical) as its parameter. Detecting renamed files this way
192 can be expensive. After using this option, :hg:`status -C` can be
192 can be expensive. After using this option, :hg:`status -C` can be
193 used to check which files were identified as moved or renamed.
193 used to check which files were identified as moved or renamed.
194
194
195 Returns 0 if all files are successfully added.
195 Returns 0 if all files are successfully added.
196 """
196 """
197 try:
197 try:
198 sim = float(opts.get('similarity') or 100)
198 sim = float(opts.get('similarity') or 100)
199 except ValueError:
199 except ValueError:
200 raise util.Abort(_('similarity must be a number'))
200 raise util.Abort(_('similarity must be a number'))
201 if sim < 0 or sim > 100:
201 if sim < 0 or sim > 100:
202 raise util.Abort(_('similarity must be between 0 and 100'))
202 raise util.Abort(_('similarity must be between 0 and 100'))
203 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
203 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
204
204
205 @command('^annotate|blame',
205 @command('^annotate|blame',
206 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
206 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
207 ('', 'follow', None,
207 ('', 'follow', None,
208 _('follow copies/renames and list the filename (DEPRECATED)')),
208 _('follow copies/renames and list the filename (DEPRECATED)')),
209 ('', 'no-follow', None, _("don't follow copies and renames")),
209 ('', 'no-follow', None, _("don't follow copies and renames")),
210 ('a', 'text', None, _('treat all files as text')),
210 ('a', 'text', None, _('treat all files as text')),
211 ('u', 'user', None, _('list the author (long with -v)')),
211 ('u', 'user', None, _('list the author (long with -v)')),
212 ('f', 'file', None, _('list the filename')),
212 ('f', 'file', None, _('list the filename')),
213 ('d', 'date', None, _('list the date (short with -q)')),
213 ('d', 'date', None, _('list the date (short with -q)')),
214 ('n', 'number', None, _('list the revision number (default)')),
214 ('n', 'number', None, _('list the revision number (default)')),
215 ('c', 'changeset', None, _('list the changeset')),
215 ('c', 'changeset', None, _('list the changeset')),
216 ('l', 'line-number', None, _('show line number at the first appearance'))
216 ('l', 'line-number', None, _('show line number at the first appearance'))
217 ] + walkopts,
217 ] + walkopts,
218 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
218 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
219 def annotate(ui, repo, *pats, **opts):
219 def annotate(ui, repo, *pats, **opts):
220 """show changeset information by line for each file
220 """show changeset information by line for each file
221
221
222 List changes in files, showing the revision id responsible for
222 List changes in files, showing the revision id responsible for
223 each line
223 each line
224
224
225 This command is useful for discovering when a change was made and
225 This command is useful for discovering when a change was made and
226 by whom.
226 by whom.
227
227
228 Without the -a/--text option, annotate will avoid processing files
228 Without the -a/--text option, annotate will avoid processing files
229 it detects as binary. With -a, annotate will annotate the file
229 it detects as binary. With -a, annotate will annotate the file
230 anyway, although the results will probably be neither useful
230 anyway, although the results will probably be neither useful
231 nor desirable.
231 nor desirable.
232
232
233 Returns 0 on success.
233 Returns 0 on success.
234 """
234 """
235 if opts.get('follow'):
235 if opts.get('follow'):
236 # --follow is deprecated and now just an alias for -f/--file
236 # --follow is deprecated and now just an alias for -f/--file
237 # to mimic the behavior of Mercurial before version 1.5
237 # to mimic the behavior of Mercurial before version 1.5
238 opts['file'] = True
238 opts['file'] = True
239
239
240 datefunc = ui.quiet and util.shortdate or util.datestr
240 datefunc = ui.quiet and util.shortdate or util.datestr
241 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
241 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
242
242
243 if not pats:
243 if not pats:
244 raise util.Abort(_('at least one filename or pattern is required'))
244 raise util.Abort(_('at least one filename or pattern is required'))
245
245
246 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
246 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
247 ('number', ' ', lambda x: str(x[0].rev())),
247 ('number', ' ', lambda x: str(x[0].rev())),
248 ('changeset', ' ', lambda x: short(x[0].node())),
248 ('changeset', ' ', lambda x: short(x[0].node())),
249 ('date', ' ', getdate),
249 ('date', ' ', getdate),
250 ('file', ' ', lambda x: x[0].path()),
250 ('file', ' ', lambda x: x[0].path()),
251 ('line_number', ':', lambda x: str(x[1])),
251 ('line_number', ':', lambda x: str(x[1])),
252 ]
252 ]
253
253
254 if (not opts.get('user') and not opts.get('changeset')
254 if (not opts.get('user') and not opts.get('changeset')
255 and not opts.get('date') and not opts.get('file')):
255 and not opts.get('date') and not opts.get('file')):
256 opts['number'] = True
256 opts['number'] = True
257
257
258 linenumber = opts.get('line_number') is not None
258 linenumber = opts.get('line_number') is not None
259 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
259 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
260 raise util.Abort(_('at least one of -n/-c is required for -l'))
260 raise util.Abort(_('at least one of -n/-c is required for -l'))
261
261
262 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
262 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
263 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
263 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
264
264
265 def bad(x, y):
265 def bad(x, y):
266 raise util.Abort("%s: %s" % (x, y))
266 raise util.Abort("%s: %s" % (x, y))
267
267
268 ctx = scmutil.revsingle(repo, opts.get('rev'))
268 ctx = scmutil.revsingle(repo, opts.get('rev'))
269 m = scmutil.match(ctx, pats, opts)
269 m = scmutil.match(ctx, pats, opts)
270 m.bad = bad
270 m.bad = bad
271 follow = not opts.get('no_follow')
271 follow = not opts.get('no_follow')
272 for abs in ctx.walk(m):
272 for abs in ctx.walk(m):
273 fctx = ctx[abs]
273 fctx = ctx[abs]
274 if not opts.get('text') and util.binary(fctx.data()):
274 if not opts.get('text') and util.binary(fctx.data()):
275 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
275 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
276 continue
276 continue
277
277
278 lines = fctx.annotate(follow=follow, linenumber=linenumber)
278 lines = fctx.annotate(follow=follow, linenumber=linenumber)
279 pieces = []
279 pieces = []
280
280
281 for f, sep in funcmap:
281 for f, sep in funcmap:
282 l = [f(n) for n, dummy in lines]
282 l = [f(n) for n, dummy in lines]
283 if l:
283 if l:
284 sized = [(x, encoding.colwidth(x)) for x in l]
284 sized = [(x, encoding.colwidth(x)) for x in l]
285 ml = max([w for x, w in sized])
285 ml = max([w for x, w in sized])
286 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
286 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
287 for x, w in sized])
287 for x, w in sized])
288
288
289 if pieces:
289 if pieces:
290 for p, l in zip(zip(*pieces), lines):
290 for p, l in zip(zip(*pieces), lines):
291 ui.write("%s: %s" % ("".join(p), l[1]))
291 ui.write("%s: %s" % ("".join(p), l[1]))
292
292
293 @command('archive',
293 @command('archive',
294 [('', 'no-decode', None, _('do not pass files through decoders')),
294 [('', 'no-decode', None, _('do not pass files through decoders')),
295 ('p', 'prefix', '', _('directory prefix for files in archive'),
295 ('p', 'prefix', '', _('directory prefix for files in archive'),
296 _('PREFIX')),
296 _('PREFIX')),
297 ('r', 'rev', '', _('revision to distribute'), _('REV')),
297 ('r', 'rev', '', _('revision to distribute'), _('REV')),
298 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
298 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
299 ] + subrepoopts + walkopts,
299 ] + subrepoopts + walkopts,
300 _('[OPTION]... DEST'))
300 _('[OPTION]... DEST'))
301 def archive(ui, repo, dest, **opts):
301 def archive(ui, repo, dest, **opts):
302 '''create an unversioned archive of a repository revision
302 '''create an unversioned archive of a repository revision
303
303
304 By default, the revision used is the parent of the working
304 By default, the revision used is the parent of the working
305 directory; use -r/--rev to specify a different revision.
305 directory; use -r/--rev to specify a different revision.
306
306
307 The archive type is automatically detected based on file
307 The archive type is automatically detected based on file
308 extension (or override using -t/--type).
308 extension (or override using -t/--type).
309
309
310 Valid types are:
310 Valid types are:
311
311
312 :``files``: a directory full of files (default)
312 :``files``: a directory full of files (default)
313 :``tar``: tar archive, uncompressed
313 :``tar``: tar archive, uncompressed
314 :``tbz2``: tar archive, compressed using bzip2
314 :``tbz2``: tar archive, compressed using bzip2
315 :``tgz``: tar archive, compressed using gzip
315 :``tgz``: tar archive, compressed using gzip
316 :``uzip``: zip archive, uncompressed
316 :``uzip``: zip archive, uncompressed
317 :``zip``: zip archive, compressed using deflate
317 :``zip``: zip archive, compressed using deflate
318
318
319 The exact name of the destination archive or directory is given
319 The exact name of the destination archive or directory is given
320 using a format string; see :hg:`help export` for details.
320 using a format string; see :hg:`help export` for details.
321
321
322 Each member added to an archive file has a directory prefix
322 Each member added to an archive file has a directory prefix
323 prepended. Use -p/--prefix to specify a format string for the
323 prepended. Use -p/--prefix to specify a format string for the
324 prefix. The default is the basename of the archive, with suffixes
324 prefix. The default is the basename of the archive, with suffixes
325 removed.
325 removed.
326
326
327 Returns 0 on success.
327 Returns 0 on success.
328 '''
328 '''
329
329
330 ctx = scmutil.revsingle(repo, opts.get('rev'))
330 ctx = scmutil.revsingle(repo, opts.get('rev'))
331 if not ctx:
331 if not ctx:
332 raise util.Abort(_('no working directory: please specify a revision'))
332 raise util.Abort(_('no working directory: please specify a revision'))
333 node = ctx.node()
333 node = ctx.node()
334 dest = cmdutil.makefilename(repo, dest, node)
334 dest = cmdutil.makefilename(repo, dest, node)
335 if os.path.realpath(dest) == repo.root:
335 if os.path.realpath(dest) == repo.root:
336 raise util.Abort(_('repository root cannot be destination'))
336 raise util.Abort(_('repository root cannot be destination'))
337
337
338 kind = opts.get('type') or archival.guesskind(dest) or 'files'
338 kind = opts.get('type') or archival.guesskind(dest) or 'files'
339 prefix = opts.get('prefix')
339 prefix = opts.get('prefix')
340
340
341 if dest == '-':
341 if dest == '-':
342 if kind == 'files':
342 if kind == 'files':
343 raise util.Abort(_('cannot archive plain files to stdout'))
343 raise util.Abort(_('cannot archive plain files to stdout'))
344 dest = cmdutil.makefileobj(repo, dest)
344 dest = cmdutil.makefileobj(repo, dest)
345 if not prefix:
345 if not prefix:
346 prefix = os.path.basename(repo.root) + '-%h'
346 prefix = os.path.basename(repo.root) + '-%h'
347
347
348 prefix = cmdutil.makefilename(repo, prefix, node)
348 prefix = cmdutil.makefilename(repo, prefix, node)
349 matchfn = scmutil.match(ctx, [], opts)
349 matchfn = scmutil.match(ctx, [], opts)
350 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
350 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
351 matchfn, prefix, subrepos=opts.get('subrepos'))
351 matchfn, prefix, subrepos=opts.get('subrepos'))
352
352
353 @command('backout',
353 @command('backout',
354 [('', 'merge', None, _('merge with old dirstate parent after backout')),
354 [('', 'merge', None, _('merge with old dirstate parent after backout')),
355 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
355 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
356 ('r', 'rev', '', _('revision to backout'), _('REV')),
356 ('r', 'rev', '', _('revision to backout'), _('REV')),
357 ] + mergetoolopts + walkopts + commitopts + commitopts2,
357 ] + mergetoolopts + walkopts + commitopts + commitopts2,
358 _('[OPTION]... [-r] REV'))
358 _('[OPTION]... [-r] REV'))
359 def backout(ui, repo, node=None, rev=None, **opts):
359 def backout(ui, repo, node=None, rev=None, **opts):
360 '''reverse effect of earlier changeset
360 '''reverse effect of earlier changeset
361
361
362 Prepare a new changeset with the effect of REV undone in the
362 Prepare a new changeset with the effect of REV undone in the
363 current working directory.
363 current working directory.
364
364
365 If REV is the parent of the working directory, then this new changeset
365 If REV is the parent of the working directory, then this new changeset
366 is committed automatically. Otherwise, hg needs to merge the
366 is committed automatically. Otherwise, hg needs to merge the
367 changes and the merged result is left uncommitted.
367 changes and the merged result is left uncommitted.
368
368
369 By default, the pending changeset will have one parent,
369 By default, the pending changeset will have one parent,
370 maintaining a linear history. With --merge, the pending changeset
370 maintaining a linear history. With --merge, the pending changeset
371 will instead have two parents: the old parent of the working
371 will instead have two parents: the old parent of the working
372 directory and a new child of REV that simply undoes REV.
372 directory and a new child of REV that simply undoes REV.
373
373
374 Before version 1.7, the behavior without --merge was equivalent to
374 Before version 1.7, the behavior without --merge was equivalent to
375 specifying --merge followed by :hg:`update --clean .` to cancel
375 specifying --merge followed by :hg:`update --clean .` to cancel
376 the merge and leave the child of REV as a head to be merged
376 the merge and leave the child of REV as a head to be merged
377 separately.
377 separately.
378
378
379 See :hg:`help dates` for a list of formats valid for -d/--date.
379 See :hg:`help dates` for a list of formats valid for -d/--date.
380
380
381 Returns 0 on success.
381 Returns 0 on success.
382 '''
382 '''
383 if rev and node:
383 if rev and node:
384 raise util.Abort(_("please specify just one revision"))
384 raise util.Abort(_("please specify just one revision"))
385
385
386 if not rev:
386 if not rev:
387 rev = node
387 rev = node
388
388
389 if not rev:
389 if not rev:
390 raise util.Abort(_("please specify a revision to backout"))
390 raise util.Abort(_("please specify a revision to backout"))
391
391
392 date = opts.get('date')
392 date = opts.get('date')
393 if date:
393 if date:
394 opts['date'] = util.parsedate(date)
394 opts['date'] = util.parsedate(date)
395
395
396 cmdutil.bailifchanged(repo)
396 cmdutil.bailifchanged(repo)
397 node = scmutil.revsingle(repo, rev).node()
397 node = scmutil.revsingle(repo, rev).node()
398
398
399 op1, op2 = repo.dirstate.parents()
399 op1, op2 = repo.dirstate.parents()
400 a = repo.changelog.ancestor(op1, node)
400 a = repo.changelog.ancestor(op1, node)
401 if a != node:
401 if a != node:
402 raise util.Abort(_('cannot backout change on a different branch'))
402 raise util.Abort(_('cannot backout change on a different branch'))
403
403
404 p1, p2 = repo.changelog.parents(node)
404 p1, p2 = repo.changelog.parents(node)
405 if p1 == nullid:
405 if p1 == nullid:
406 raise util.Abort(_('cannot backout a change with no parents'))
406 raise util.Abort(_('cannot backout a change with no parents'))
407 if p2 != nullid:
407 if p2 != nullid:
408 if not opts.get('parent'):
408 if not opts.get('parent'):
409 raise util.Abort(_('cannot backout a merge changeset without '
409 raise util.Abort(_('cannot backout a merge changeset without '
410 '--parent'))
410 '--parent'))
411 p = repo.lookup(opts['parent'])
411 p = repo.lookup(opts['parent'])
412 if p not in (p1, p2):
412 if p not in (p1, p2):
413 raise util.Abort(_('%s is not a parent of %s') %
413 raise util.Abort(_('%s is not a parent of %s') %
414 (short(p), short(node)))
414 (short(p), short(node)))
415 parent = p
415 parent = p
416 else:
416 else:
417 if opts.get('parent'):
417 if opts.get('parent'):
418 raise util.Abort(_('cannot use --parent on non-merge changeset'))
418 raise util.Abort(_('cannot use --parent on non-merge changeset'))
419 parent = p1
419 parent = p1
420
420
421 # the backout should appear on the same branch
421 # the backout should appear on the same branch
422 branch = repo.dirstate.branch()
422 branch = repo.dirstate.branch()
423 hg.clean(repo, node, show_stats=False)
423 hg.clean(repo, node, show_stats=False)
424 repo.dirstate.setbranch(branch)
424 repo.dirstate.setbranch(branch)
425 revert_opts = opts.copy()
425 revert_opts = opts.copy()
426 revert_opts['date'] = None
426 revert_opts['date'] = None
427 revert_opts['all'] = True
427 revert_opts['all'] = True
428 revert_opts['rev'] = hex(parent)
428 revert_opts['rev'] = hex(parent)
429 revert_opts['no_backup'] = None
429 revert_opts['no_backup'] = None
430 revert(ui, repo, **revert_opts)
430 revert(ui, repo, **revert_opts)
431 if not opts.get('merge') and op1 != node:
431 if not opts.get('merge') and op1 != node:
432 try:
432 try:
433 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
433 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
434 return hg.update(repo, op1)
434 return hg.update(repo, op1)
435 finally:
435 finally:
436 ui.setconfig('ui', 'forcemerge', '')
436 ui.setconfig('ui', 'forcemerge', '')
437
437
438 commit_opts = opts.copy()
438 commit_opts = opts.copy()
439 commit_opts['addremove'] = False
439 commit_opts['addremove'] = False
440 if not commit_opts['message'] and not commit_opts['logfile']:
440 if not commit_opts['message'] and not commit_opts['logfile']:
441 # we don't translate commit messages
441 # we don't translate commit messages
442 commit_opts['message'] = "Backed out changeset %s" % short(node)
442 commit_opts['message'] = "Backed out changeset %s" % short(node)
443 commit_opts['force_editor'] = True
443 commit_opts['force_editor'] = True
444 commit(ui, repo, **commit_opts)
444 commit(ui, repo, **commit_opts)
445 def nice(node):
445 def nice(node):
446 return '%d:%s' % (repo.changelog.rev(node), short(node))
446 return '%d:%s' % (repo.changelog.rev(node), short(node))
447 ui.status(_('changeset %s backs out changeset %s\n') %
447 ui.status(_('changeset %s backs out changeset %s\n') %
448 (nice(repo.changelog.tip()), nice(node)))
448 (nice(repo.changelog.tip()), nice(node)))
449 if opts.get('merge') and op1 != node:
449 if opts.get('merge') and op1 != node:
450 hg.clean(repo, op1, show_stats=False)
450 hg.clean(repo, op1, show_stats=False)
451 ui.status(_('merging with changeset %s\n')
451 ui.status(_('merging with changeset %s\n')
452 % nice(repo.changelog.tip()))
452 % nice(repo.changelog.tip()))
453 try:
453 try:
454 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
454 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
455 return hg.merge(repo, hex(repo.changelog.tip()))
455 return hg.merge(repo, hex(repo.changelog.tip()))
456 finally:
456 finally:
457 ui.setconfig('ui', 'forcemerge', '')
457 ui.setconfig('ui', 'forcemerge', '')
458 return 0
458 return 0
459
459
460 @command('bisect',
460 @command('bisect',
461 [('r', 'reset', False, _('reset bisect state')),
461 [('r', 'reset', False, _('reset bisect state')),
462 ('g', 'good', False, _('mark changeset good')),
462 ('g', 'good', False, _('mark changeset good')),
463 ('b', 'bad', False, _('mark changeset bad')),
463 ('b', 'bad', False, _('mark changeset bad')),
464 ('s', 'skip', False, _('skip testing changeset')),
464 ('s', 'skip', False, _('skip testing changeset')),
465 ('e', 'extend', False, _('extend the bisect range')),
465 ('e', 'extend', False, _('extend the bisect range')),
466 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
466 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
467 ('U', 'noupdate', False, _('do not update to target'))],
467 ('U', 'noupdate', False, _('do not update to target'))],
468 _("[-gbsr] [-U] [-c CMD] [REV]"))
468 _("[-gbsr] [-U] [-c CMD] [REV]"))
469 def bisect(ui, repo, rev=None, extra=None, command=None,
469 def bisect(ui, repo, rev=None, extra=None, command=None,
470 reset=None, good=None, bad=None, skip=None, extend=None,
470 reset=None, good=None, bad=None, skip=None, extend=None,
471 noupdate=None):
471 noupdate=None):
472 """subdivision search of changesets
472 """subdivision search of changesets
473
473
474 This command helps to find changesets which introduce problems. To
474 This command helps to find changesets which introduce problems. To
475 use, mark the earliest changeset you know exhibits the problem as
475 use, mark the earliest changeset you know exhibits the problem as
476 bad, then mark the latest changeset which is free from the problem
476 bad, then mark the latest changeset which is free from the problem
477 as good. Bisect will update your working directory to a revision
477 as good. Bisect will update your working directory to a revision
478 for testing (unless the -U/--noupdate option is specified). Once
478 for testing (unless the -U/--noupdate option is specified). Once
479 you have performed tests, mark the working directory as good or
479 you have performed tests, mark the working directory as good or
480 bad, and bisect will either update to another candidate changeset
480 bad, and bisect will either update to another candidate changeset
481 or announce that it has found the bad revision.
481 or announce that it has found the bad revision.
482
482
483 As a shortcut, you can also use the revision argument to mark a
483 As a shortcut, you can also use the revision argument to mark a
484 revision as good or bad without checking it out first.
484 revision as good or bad without checking it out first.
485
485
486 If you supply a command, it will be used for automatic bisection.
486 If you supply a command, it will be used for automatic bisection.
487 Its exit status will be used to mark revisions as good or bad:
487 Its exit status will be used to mark revisions as good or bad:
488 status 0 means good, 125 means to skip the revision, 127
488 status 0 means good, 125 means to skip the revision, 127
489 (command not found) will abort the bisection, and any other
489 (command not found) will abort the bisection, and any other
490 non-zero exit status means the revision is bad.
490 non-zero exit status means the revision is bad.
491
491
492 Returns 0 on success.
492 Returns 0 on success.
493 """
493 """
494 def extendbisectrange(nodes, good):
494 def extendbisectrange(nodes, good):
495 # bisect is incomplete when it ends on a merge node and
495 # bisect is incomplete when it ends on a merge node and
496 # one of the parent was not checked.
496 # one of the parent was not checked.
497 parents = repo[nodes[0]].parents()
497 parents = repo[nodes[0]].parents()
498 if len(parents) > 1:
498 if len(parents) > 1:
499 side = good and state['bad'] or state['good']
499 side = good and state['bad'] or state['good']
500 num = len(set(i.node() for i in parents) & set(side))
500 num = len(set(i.node() for i in parents) & set(side))
501 if num == 1:
501 if num == 1:
502 return parents[0].ancestor(parents[1])
502 return parents[0].ancestor(parents[1])
503 return None
503 return None
504
504
505 def print_result(nodes, good):
505 def print_result(nodes, good):
506 displayer = cmdutil.show_changeset(ui, repo, {})
506 displayer = cmdutil.show_changeset(ui, repo, {})
507 if len(nodes) == 1:
507 if len(nodes) == 1:
508 # narrowed it down to a single revision
508 # narrowed it down to a single revision
509 if good:
509 if good:
510 ui.write(_("The first good revision is:\n"))
510 ui.write(_("The first good revision is:\n"))
511 else:
511 else:
512 ui.write(_("The first bad revision is:\n"))
512 ui.write(_("The first bad revision is:\n"))
513 displayer.show(repo[nodes[0]])
513 displayer.show(repo[nodes[0]])
514 extendnode = extendbisectrange(nodes, good)
514 extendnode = extendbisectrange(nodes, good)
515 if extendnode is not None:
515 if extendnode is not None:
516 ui.write(_('Not all ancestors of this changeset have been'
516 ui.write(_('Not all ancestors of this changeset have been'
517 ' checked.\nUse bisect --extend to continue the '
517 ' checked.\nUse bisect --extend to continue the '
518 'bisection from\nthe common ancestor, %s.\n')
518 'bisection from\nthe common ancestor, %s.\n')
519 % extendnode)
519 % extendnode)
520 else:
520 else:
521 # multiple possible revisions
521 # multiple possible revisions
522 if good:
522 if good:
523 ui.write(_("Due to skipped revisions, the first "
523 ui.write(_("Due to skipped revisions, the first "
524 "good revision could be any of:\n"))
524 "good revision could be any of:\n"))
525 else:
525 else:
526 ui.write(_("Due to skipped revisions, the first "
526 ui.write(_("Due to skipped revisions, the first "
527 "bad revision could be any of:\n"))
527 "bad revision could be any of:\n"))
528 for n in nodes:
528 for n in nodes:
529 displayer.show(repo[n])
529 displayer.show(repo[n])
530 displayer.close()
530 displayer.close()
531
531
532 def check_state(state, interactive=True):
532 def check_state(state, interactive=True):
533 if not state['good'] or not state['bad']:
533 if not state['good'] or not state['bad']:
534 if (good or bad or skip or reset) and interactive:
534 if (good or bad or skip or reset) and interactive:
535 return
535 return
536 if not state['good']:
536 if not state['good']:
537 raise util.Abort(_('cannot bisect (no known good revisions)'))
537 raise util.Abort(_('cannot bisect (no known good revisions)'))
538 else:
538 else:
539 raise util.Abort(_('cannot bisect (no known bad revisions)'))
539 raise util.Abort(_('cannot bisect (no known bad revisions)'))
540 return True
540 return True
541
541
542 # backward compatibility
542 # backward compatibility
543 if rev in "good bad reset init".split():
543 if rev in "good bad reset init".split():
544 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
544 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
545 cmd, rev, extra = rev, extra, None
545 cmd, rev, extra = rev, extra, None
546 if cmd == "good":
546 if cmd == "good":
547 good = True
547 good = True
548 elif cmd == "bad":
548 elif cmd == "bad":
549 bad = True
549 bad = True
550 else:
550 else:
551 reset = True
551 reset = True
552 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
552 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
553 raise util.Abort(_('incompatible arguments'))
553 raise util.Abort(_('incompatible arguments'))
554
554
555 if reset:
555 if reset:
556 p = repo.join("bisect.state")
556 p = repo.join("bisect.state")
557 if os.path.exists(p):
557 if os.path.exists(p):
558 os.unlink(p)
558 os.unlink(p)
559 return
559 return
560
560
561 state = hbisect.load_state(repo)
561 state = hbisect.load_state(repo)
562
562
563 if command:
563 if command:
564 changesets = 1
564 changesets = 1
565 try:
565 try:
566 while changesets:
566 while changesets:
567 # update state
567 # update state
568 status = util.system(command, out=ui.fout)
568 status = util.system(command, out=ui.fout)
569 if status == 125:
569 if status == 125:
570 transition = "skip"
570 transition = "skip"
571 elif status == 0:
571 elif status == 0:
572 transition = "good"
572 transition = "good"
573 # status < 0 means process was killed
573 # status < 0 means process was killed
574 elif status == 127:
574 elif status == 127:
575 raise util.Abort(_("failed to execute %s") % command)
575 raise util.Abort(_("failed to execute %s") % command)
576 elif status < 0:
576 elif status < 0:
577 raise util.Abort(_("%s killed") % command)
577 raise util.Abort(_("%s killed") % command)
578 else:
578 else:
579 transition = "bad"
579 transition = "bad"
580 ctx = scmutil.revsingle(repo, rev)
580 ctx = scmutil.revsingle(repo, rev)
581 rev = None # clear for future iterations
581 rev = None # clear for future iterations
582 state[transition].append(ctx.node())
582 state[transition].append(ctx.node())
583 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
583 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
584 check_state(state, interactive=False)
584 check_state(state, interactive=False)
585 # bisect
585 # bisect
586 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
586 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
587 # update to next check
587 # update to next check
588 cmdutil.bailifchanged(repo)
588 cmdutil.bailifchanged(repo)
589 hg.clean(repo, nodes[0], show_stats=False)
589 hg.clean(repo, nodes[0], show_stats=False)
590 finally:
590 finally:
591 hbisect.save_state(repo, state)
591 hbisect.save_state(repo, state)
592 print_result(nodes, good)
592 print_result(nodes, good)
593 return
593 return
594
594
595 # update state
595 # update state
596
596
597 if rev:
597 if rev:
598 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
598 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
599 else:
599 else:
600 nodes = [repo.lookup('.')]
600 nodes = [repo.lookup('.')]
601
601
602 if good or bad or skip:
602 if good or bad or skip:
603 if good:
603 if good:
604 state['good'] += nodes
604 state['good'] += nodes
605 elif bad:
605 elif bad:
606 state['bad'] += nodes
606 state['bad'] += nodes
607 elif skip:
607 elif skip:
608 state['skip'] += nodes
608 state['skip'] += nodes
609 hbisect.save_state(repo, state)
609 hbisect.save_state(repo, state)
610
610
611 if not check_state(state):
611 if not check_state(state):
612 return
612 return
613
613
614 # actually bisect
614 # actually bisect
615 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
615 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
616 if extend:
616 if extend:
617 if not changesets:
617 if not changesets:
618 extendnode = extendbisectrange(nodes, good)
618 extendnode = extendbisectrange(nodes, good)
619 if extendnode is not None:
619 if extendnode is not None:
620 ui.write(_("Extending search to changeset %d:%s\n"
620 ui.write(_("Extending search to changeset %d:%s\n"
621 % (extendnode.rev(), extendnode)))
621 % (extendnode.rev(), extendnode)))
622 if noupdate:
622 if noupdate:
623 return
623 return
624 cmdutil.bailifchanged(repo)
624 cmdutil.bailifchanged(repo)
625 return hg.clean(repo, extendnode.node())
625 return hg.clean(repo, extendnode.node())
626 raise util.Abort(_("nothing to extend"))
626 raise util.Abort(_("nothing to extend"))
627
627
628 if changesets == 0:
628 if changesets == 0:
629 print_result(nodes, good)
629 print_result(nodes, good)
630 else:
630 else:
631 assert len(nodes) == 1 # only a single node can be tested next
631 assert len(nodes) == 1 # only a single node can be tested next
632 node = nodes[0]
632 node = nodes[0]
633 # compute the approximate number of remaining tests
633 # compute the approximate number of remaining tests
634 tests, size = 0, 2
634 tests, size = 0, 2
635 while size <= changesets:
635 while size <= changesets:
636 tests, size = tests + 1, size * 2
636 tests, size = tests + 1, size * 2
637 rev = repo.changelog.rev(node)
637 rev = repo.changelog.rev(node)
638 ui.write(_("Testing changeset %d:%s "
638 ui.write(_("Testing changeset %d:%s "
639 "(%d changesets remaining, ~%d tests)\n")
639 "(%d changesets remaining, ~%d tests)\n")
640 % (rev, short(node), changesets, tests))
640 % (rev, short(node), changesets, tests))
641 if not noupdate:
641 if not noupdate:
642 cmdutil.bailifchanged(repo)
642 cmdutil.bailifchanged(repo)
643 return hg.clean(repo, node)
643 return hg.clean(repo, node)
644
644
645 @command('bookmarks',
645 @command('bookmarks',
646 [('f', 'force', False, _('force')),
646 [('f', 'force', False, _('force')),
647 ('r', 'rev', '', _('revision'), _('REV')),
647 ('r', 'rev', '', _('revision'), _('REV')),
648 ('d', 'delete', False, _('delete a given bookmark')),
648 ('d', 'delete', False, _('delete a given bookmark')),
649 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
649 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
650 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
650 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
651 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
651 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
652 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
652 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
653 rename=None, inactive=False):
653 rename=None, inactive=False):
654 '''track a line of development with movable markers
654 '''track a line of development with movable markers
655
655
656 Bookmarks are pointers to certain commits that move when
656 Bookmarks are pointers to certain commits that move when
657 committing. Bookmarks are local. They can be renamed, copied and
657 committing. Bookmarks are local. They can be renamed, copied and
658 deleted. It is possible to use bookmark names in :hg:`merge` and
658 deleted. It is possible to use bookmark names in :hg:`merge` and
659 :hg:`update` to merge and update respectively to a given bookmark.
659 :hg:`update` to merge and update respectively to a given bookmark.
660
660
661 You can use :hg:`bookmark NAME` to set a bookmark on the working
661 You can use :hg:`bookmark NAME` to set a bookmark on the working
662 directory's parent revision with the given name. If you specify
662 directory's parent revision with the given name. If you specify
663 a revision using -r REV (where REV may be an existing bookmark),
663 a revision using -r REV (where REV may be an existing bookmark),
664 the bookmark is assigned to that revision.
664 the bookmark is assigned to that revision.
665
665
666 Bookmarks can be pushed and pulled between repositories (see :hg:`help
666 Bookmarks can be pushed and pulled between repositories (see :hg:`help
667 push` and :hg:`help pull`). This requires both the local and remote
667 push` and :hg:`help pull`). This requires both the local and remote
668 repositories to support bookmarks. For versions prior to 1.8, this means
668 repositories to support bookmarks. For versions prior to 1.8, this means
669 the bookmarks extension must be enabled.
669 the bookmarks extension must be enabled.
670 '''
670 '''
671 hexfn = ui.debugflag and hex or short
671 hexfn = ui.debugflag and hex or short
672 marks = repo._bookmarks
672 marks = repo._bookmarks
673 cur = repo.changectx('.').node()
673 cur = repo.changectx('.').node()
674
674
675 if rename:
675 if rename:
676 if rename not in marks:
676 if rename not in marks:
677 raise util.Abort(_("bookmark '%s' does not exist") % rename)
677 raise util.Abort(_("bookmark '%s' does not exist") % rename)
678 if mark in marks and not force:
678 if mark in marks and not force:
679 raise util.Abort(_("bookmark '%s' already exists "
679 raise util.Abort(_("bookmark '%s' already exists "
680 "(use -f to force)") % mark)
680 "(use -f to force)") % mark)
681 if mark is None:
681 if mark is None:
682 raise util.Abort(_("new bookmark name required"))
682 raise util.Abort(_("new bookmark name required"))
683 marks[mark] = marks[rename]
683 marks[mark] = marks[rename]
684 if repo._bookmarkcurrent == rename and not inactive:
684 if repo._bookmarkcurrent == rename and not inactive:
685 bookmarks.setcurrent(repo, mark)
685 bookmarks.setcurrent(repo, mark)
686 del marks[rename]
686 del marks[rename]
687 bookmarks.write(repo)
687 bookmarks.write(repo)
688 return
688 return
689
689
690 if delete:
690 if delete:
691 if mark is None:
691 if mark is None:
692 raise util.Abort(_("bookmark name required"))
692 raise util.Abort(_("bookmark name required"))
693 if mark not in marks:
693 if mark not in marks:
694 raise util.Abort(_("bookmark '%s' does not exist") % mark)
694 raise util.Abort(_("bookmark '%s' does not exist") % mark)
695 if mark == repo._bookmarkcurrent:
695 if mark == repo._bookmarkcurrent:
696 bookmarks.setcurrent(repo, None)
696 bookmarks.setcurrent(repo, None)
697 del marks[mark]
697 del marks[mark]
698 bookmarks.write(repo)
698 bookmarks.write(repo)
699 return
699 return
700
700
701 if mark is not None:
701 if mark is not None:
702 if "\n" in mark:
702 if "\n" in mark:
703 raise util.Abort(_("bookmark name cannot contain newlines"))
703 raise util.Abort(_("bookmark name cannot contain newlines"))
704 mark = mark.strip()
704 mark = mark.strip()
705 if not mark:
705 if not mark:
706 raise util.Abort(_("bookmark names cannot consist entirely of "
706 raise util.Abort(_("bookmark names cannot consist entirely of "
707 "whitespace"))
707 "whitespace"))
708 if inactive and mark == repo._bookmarkcurrent:
708 if inactive and mark == repo._bookmarkcurrent:
709 bookmarks.setcurrent(repo, None)
709 bookmarks.setcurrent(repo, None)
710 return
710 return
711 if mark in marks and not force:
711 if mark in marks and not force:
712 raise util.Abort(_("bookmark '%s' already exists "
712 raise util.Abort(_("bookmark '%s' already exists "
713 "(use -f to force)") % mark)
713 "(use -f to force)") % mark)
714 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
714 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
715 and not force):
715 and not force):
716 raise util.Abort(
716 raise util.Abort(
717 _("a bookmark cannot have the name of an existing branch"))
717 _("a bookmark cannot have the name of an existing branch"))
718 if rev:
718 if rev:
719 marks[mark] = repo.lookup(rev)
719 marks[mark] = repo.lookup(rev)
720 else:
720 else:
721 marks[mark] = repo.changectx('.').node()
721 marks[mark] = repo.changectx('.').node()
722 if not inactive and repo.changectx('.').node() == marks[mark]:
722 if not inactive and repo.changectx('.').node() == marks[mark]:
723 bookmarks.setcurrent(repo, mark)
723 bookmarks.setcurrent(repo, mark)
724 bookmarks.write(repo)
724 bookmarks.write(repo)
725 return
725 return
726
726
727 if mark is None:
727 if mark is None:
728 if rev:
728 if rev:
729 raise util.Abort(_("bookmark name required"))
729 raise util.Abort(_("bookmark name required"))
730 if len(marks) == 0:
730 if len(marks) == 0:
731 ui.status(_("no bookmarks set\n"))
731 ui.status(_("no bookmarks set\n"))
732 else:
732 else:
733 for bmark, n in sorted(marks.iteritems()):
733 for bmark, n in sorted(marks.iteritems()):
734 current = repo._bookmarkcurrent
734 current = repo._bookmarkcurrent
735 if bmark == current and n == cur:
735 if bmark == current and n == cur:
736 prefix, label = '*', 'bookmarks.current'
736 prefix, label = '*', 'bookmarks.current'
737 else:
737 else:
738 prefix, label = ' ', ''
738 prefix, label = ' ', ''
739
739
740 if ui.quiet:
740 if ui.quiet:
741 ui.write("%s\n" % bmark, label=label)
741 ui.write("%s\n" % bmark, label=label)
742 else:
742 else:
743 ui.write(" %s %-25s %d:%s\n" % (
743 ui.write(" %s %-25s %d:%s\n" % (
744 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
744 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
745 label=label)
745 label=label)
746 return
746 return
747
747
748 @command('branch',
748 @command('branch',
749 [('f', 'force', None,
749 [('f', 'force', None,
750 _('set branch name even if it shadows an existing branch')),
750 _('set branch name even if it shadows an existing branch')),
751 ('C', 'clean', None, _('reset branch name to parent branch name'))],
751 ('C', 'clean', None, _('reset branch name to parent branch name'))],
752 _('[-fC] [NAME]'))
752 _('[-fC] [NAME]'))
753 def branch(ui, repo, label=None, **opts):
753 def branch(ui, repo, label=None, **opts):
754 """set or show the current branch name
754 """set or show the current branch name
755
755
756 With no argument, show the current branch name. With one argument,
756 With no argument, show the current branch name. With one argument,
757 set the working directory branch name (the branch will not exist
757 set the working directory branch name (the branch will not exist
758 in the repository until the next commit). Standard practice
758 in the repository until the next commit). Standard practice
759 recommends that primary development take place on the 'default'
759 recommends that primary development take place on the 'default'
760 branch.
760 branch.
761
761
762 Unless -f/--force is specified, branch will not let you set a
762 Unless -f/--force is specified, branch will not let you set a
763 branch name that already exists, even if it's inactive.
763 branch name that already exists, even if it's inactive.
764
764
765 Use -C/--clean to reset the working directory branch to that of
765 Use -C/--clean to reset the working directory branch to that of
766 the parent of the working directory, negating a previous branch
766 the parent of the working directory, negating a previous branch
767 change.
767 change.
768
768
769 Use the command :hg:`update` to switch to an existing branch. Use
769 Use the command :hg:`update` to switch to an existing branch. Use
770 :hg:`commit --close-branch` to mark this branch as closed.
770 :hg:`commit --close-branch` to mark this branch as closed.
771
771
772 .. note::
772 .. note::
773
773
774 Branch names are permanent. Use :hg:`bookmark` to create a
774 Branch names are permanent. Use :hg:`bookmark` to create a
775 light-weight bookmark instead. See :hg:`help glossary` for more
775 light-weight bookmark instead. See :hg:`help glossary` for more
776 information about named branches and bookmarks.
776 information about named branches and bookmarks.
777
777
778 Returns 0 on success.
778 Returns 0 on success.
779 """
779 """
780
780
781 if opts.get('clean'):
781 if opts.get('clean'):
782 label = repo[None].p1().branch()
782 label = repo[None].p1().branch()
783 repo.dirstate.setbranch(label)
783 repo.dirstate.setbranch(label)
784 ui.status(_('reset working directory to branch %s\n') % label)
784 ui.status(_('reset working directory to branch %s\n') % label)
785 elif label:
785 elif label:
786 if not opts.get('force') and label in repo.branchtags():
786 if not opts.get('force') and label in repo.branchtags():
787 if label not in [p.branch() for p in repo.parents()]:
787 if label not in [p.branch() for p in repo.parents()]:
788 raise util.Abort(_('a branch of the same name already exists'),
788 raise util.Abort(_('a branch of the same name already exists'),
789 # i18n: "it" refers to an existing branch
789 # i18n: "it" refers to an existing branch
790 hint=_("use 'hg update' to switch to it"))
790 hint=_("use 'hg update' to switch to it"))
791 repo.dirstate.setbranch(label)
791 repo.dirstate.setbranch(label)
792 ui.status(_('marked working directory as branch %s\n') % label)
792 ui.status(_('marked working directory as branch %s\n') % label)
793 else:
793 else:
794 ui.write("%s\n" % repo.dirstate.branch())
794 ui.write("%s\n" % repo.dirstate.branch())
795
795
796 @command('branches',
796 @command('branches',
797 [('a', 'active', False, _('show only branches that have unmerged heads')),
797 [('a', 'active', False, _('show only branches that have unmerged heads')),
798 ('c', 'closed', False, _('show normal and closed branches'))],
798 ('c', 'closed', False, _('show normal and closed branches'))],
799 _('[-ac]'))
799 _('[-ac]'))
800 def branches(ui, repo, active=False, closed=False):
800 def branches(ui, repo, active=False, closed=False):
801 """list repository named branches
801 """list repository named branches
802
802
803 List the repository's named branches, indicating which ones are
803 List the repository's named branches, indicating which ones are
804 inactive. If -c/--closed is specified, also list branches which have
804 inactive. If -c/--closed is specified, also list branches which have
805 been marked closed (see :hg:`commit --close-branch`).
805 been marked closed (see :hg:`commit --close-branch`).
806
806
807 If -a/--active is specified, only show active branches. A branch
807 If -a/--active is specified, only show active branches. A branch
808 is considered active if it contains repository heads.
808 is considered active if it contains repository heads.
809
809
810 Use the command :hg:`update` to switch to an existing branch.
810 Use the command :hg:`update` to switch to an existing branch.
811
811
812 Returns 0.
812 Returns 0.
813 """
813 """
814
814
815 hexfunc = ui.debugflag and hex or short
815 hexfunc = ui.debugflag and hex or short
816 activebranches = [repo[n].branch() for n in repo.heads()]
816 activebranches = [repo[n].branch() for n in repo.heads()]
817 def testactive(tag, node):
817 def testactive(tag, node):
818 realhead = tag in activebranches
818 realhead = tag in activebranches
819 open = node in repo.branchheads(tag, closed=False)
819 open = node in repo.branchheads(tag, closed=False)
820 return realhead and open
820 return realhead and open
821 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
821 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
822 for tag, node in repo.branchtags().items()],
822 for tag, node in repo.branchtags().items()],
823 reverse=True)
823 reverse=True)
824
824
825 for isactive, node, tag in branches:
825 for isactive, node, tag in branches:
826 if (not active) or isactive:
826 if (not active) or isactive:
827 if ui.quiet:
827 if ui.quiet:
828 ui.write("%s\n" % tag)
828 ui.write("%s\n" % tag)
829 else:
829 else:
830 hn = repo.lookup(node)
830 hn = repo.lookup(node)
831 if isactive:
831 if isactive:
832 label = 'branches.active'
832 label = 'branches.active'
833 notice = ''
833 notice = ''
834 elif hn not in repo.branchheads(tag, closed=False):
834 elif hn not in repo.branchheads(tag, closed=False):
835 if not closed:
835 if not closed:
836 continue
836 continue
837 label = 'branches.closed'
837 label = 'branches.closed'
838 notice = _(' (closed)')
838 notice = _(' (closed)')
839 else:
839 else:
840 label = 'branches.inactive'
840 label = 'branches.inactive'
841 notice = _(' (inactive)')
841 notice = _(' (inactive)')
842 if tag == repo.dirstate.branch():
842 if tag == repo.dirstate.branch():
843 label = 'branches.current'
843 label = 'branches.current'
844 rev = str(node).rjust(31 - encoding.colwidth(tag))
844 rev = str(node).rjust(31 - encoding.colwidth(tag))
845 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
845 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
846 tag = ui.label(tag, label)
846 tag = ui.label(tag, label)
847 ui.write("%s %s%s\n" % (tag, rev, notice))
847 ui.write("%s %s%s\n" % (tag, rev, notice))
848
848
849 @command('bundle',
849 @command('bundle',
850 [('f', 'force', None, _('run even when the destination is unrelated')),
850 [('f', 'force', None, _('run even when the destination is unrelated')),
851 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
851 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
852 _('REV')),
852 _('REV')),
853 ('b', 'branch', [], _('a specific branch you would like to bundle'),
853 ('b', 'branch', [], _('a specific branch you would like to bundle'),
854 _('BRANCH')),
854 _('BRANCH')),
855 ('', 'base', [],
855 ('', 'base', [],
856 _('a base changeset assumed to be available at the destination'),
856 _('a base changeset assumed to be available at the destination'),
857 _('REV')),
857 _('REV')),
858 ('a', 'all', None, _('bundle all changesets in the repository')),
858 ('a', 'all', None, _('bundle all changesets in the repository')),
859 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
859 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
860 ] + remoteopts,
860 ] + remoteopts,
861 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
861 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
862 def bundle(ui, repo, fname, dest=None, **opts):
862 def bundle(ui, repo, fname, dest=None, **opts):
863 """create a changegroup file
863 """create a changegroup file
864
864
865 Generate a compressed changegroup file collecting changesets not
865 Generate a compressed changegroup file collecting changesets not
866 known to be in another repository.
866 known to be in another repository.
867
867
868 If you omit the destination repository, then hg assumes the
868 If you omit the destination repository, then hg assumes the
869 destination will have all the nodes you specify with --base
869 destination will have all the nodes you specify with --base
870 parameters. To create a bundle containing all changesets, use
870 parameters. To create a bundle containing all changesets, use
871 -a/--all (or --base null).
871 -a/--all (or --base null).
872
872
873 You can change compression method with the -t/--type option.
873 You can change compression method with the -t/--type option.
874 The available compression methods are: none, bzip2, and
874 The available compression methods are: none, bzip2, and
875 gzip (by default, bundles are compressed using bzip2).
875 gzip (by default, bundles are compressed using bzip2).
876
876
877 The bundle file can then be transferred using conventional means
877 The bundle file can then be transferred using conventional means
878 and applied to another repository with the unbundle or pull
878 and applied to another repository with the unbundle or pull
879 command. This is useful when direct push and pull are not
879 command. This is useful when direct push and pull are not
880 available or when exporting an entire repository is undesirable.
880 available or when exporting an entire repository is undesirable.
881
881
882 Applying bundles preserves all changeset contents including
882 Applying bundles preserves all changeset contents including
883 permissions, copy/rename information, and revision history.
883 permissions, copy/rename information, and revision history.
884
884
885 Returns 0 on success, 1 if no changes found.
885 Returns 0 on success, 1 if no changes found.
886 """
886 """
887 revs = None
887 revs = None
888 if 'rev' in opts:
888 if 'rev' in opts:
889 revs = scmutil.revrange(repo, opts['rev'])
889 revs = scmutil.revrange(repo, opts['rev'])
890
890
891 if opts.get('all'):
891 if opts.get('all'):
892 base = ['null']
892 base = ['null']
893 else:
893 else:
894 base = scmutil.revrange(repo, opts.get('base'))
894 base = scmutil.revrange(repo, opts.get('base'))
895 if base:
895 if base:
896 if dest:
896 if dest:
897 raise util.Abort(_("--base is incompatible with specifying "
897 raise util.Abort(_("--base is incompatible with specifying "
898 "a destination"))
898 "a destination"))
899 common = [repo.lookup(rev) for rev in base]
899 common = [repo.lookup(rev) for rev in base]
900 heads = revs and map(repo.lookup, revs) or revs
900 heads = revs and map(repo.lookup, revs) or revs
901 else:
901 else:
902 dest = ui.expandpath(dest or 'default-push', dest or 'default')
902 dest = ui.expandpath(dest or 'default-push', dest or 'default')
903 dest, branches = hg.parseurl(dest, opts.get('branch'))
903 dest, branches = hg.parseurl(dest, opts.get('branch'))
904 other = hg.peer(repo, opts, dest)
904 other = hg.peer(repo, opts, dest)
905 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
905 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
906 heads = revs and map(repo.lookup, revs) or revs
906 heads = revs and map(repo.lookup, revs) or revs
907 common, outheads = discovery.findcommonoutgoing(repo, other,
907 common, outheads = discovery.findcommonoutgoing(repo, other,
908 onlyheads=heads,
908 onlyheads=heads,
909 force=opts.get('force'))
909 force=opts.get('force'))
910
910
911 cg = repo.getbundle('bundle', common=common, heads=heads)
911 cg = repo.getbundle('bundle', common=common, heads=heads)
912 if not cg:
912 if not cg:
913 ui.status(_("no changes found\n"))
913 ui.status(_("no changes found\n"))
914 return 1
914 return 1
915
915
916 bundletype = opts.get('type', 'bzip2').lower()
916 bundletype = opts.get('type', 'bzip2').lower()
917 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
917 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
918 bundletype = btypes.get(bundletype)
918 bundletype = btypes.get(bundletype)
919 if bundletype not in changegroup.bundletypes:
919 if bundletype not in changegroup.bundletypes:
920 raise util.Abort(_('unknown bundle type specified with --type'))
920 raise util.Abort(_('unknown bundle type specified with --type'))
921
921
922 changegroup.writebundle(cg, fname, bundletype)
922 changegroup.writebundle(cg, fname, bundletype)
923
923
924 @command('cat',
924 @command('cat',
925 [('o', 'output', '',
925 [('o', 'output', '',
926 _('print output to file with formatted name'), _('FORMAT')),
926 _('print output to file with formatted name'), _('FORMAT')),
927 ('r', 'rev', '', _('print the given revision'), _('REV')),
927 ('r', 'rev', '', _('print the given revision'), _('REV')),
928 ('', 'decode', None, _('apply any matching decode filter')),
928 ('', 'decode', None, _('apply any matching decode filter')),
929 ] + walkopts,
929 ] + walkopts,
930 _('[OPTION]... FILE...'))
930 _('[OPTION]... FILE...'))
931 def cat(ui, repo, file1, *pats, **opts):
931 def cat(ui, repo, file1, *pats, **opts):
932 """output the current or given revision of files
932 """output the current or given revision of files
933
933
934 Print the specified files as they were at the given revision. If
934 Print the specified files as they were at the given revision. If
935 no revision is given, the parent of the working directory is used,
935 no revision is given, the parent of the working directory is used,
936 or tip if no revision is checked out.
936 or tip if no revision is checked out.
937
937
938 Output may be to a file, in which case the name of the file is
938 Output may be to a file, in which case the name of the file is
939 given using a format string. The formatting rules are the same as
939 given using a format string. The formatting rules are the same as
940 for the export command, with the following additions:
940 for the export command, with the following additions:
941
941
942 :``%s``: basename of file being printed
942 :``%s``: basename of file being printed
943 :``%d``: dirname of file being printed, or '.' if in repository root
943 :``%d``: dirname of file being printed, or '.' if in repository root
944 :``%p``: root-relative path name of file being printed
944 :``%p``: root-relative path name of file being printed
945
945
946 Returns 0 on success.
946 Returns 0 on success.
947 """
947 """
948 ctx = scmutil.revsingle(repo, opts.get('rev'))
948 ctx = scmutil.revsingle(repo, opts.get('rev'))
949 err = 1
949 err = 1
950 m = scmutil.match(ctx, (file1,) + pats, opts)
950 m = scmutil.match(ctx, (file1,) + pats, opts)
951 for abs in ctx.walk(m):
951 for abs in ctx.walk(m):
952 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
952 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
953 pathname=abs)
953 pathname=abs)
954 data = ctx[abs].data()
954 data = ctx[abs].data()
955 if opts.get('decode'):
955 if opts.get('decode'):
956 data = repo.wwritedata(abs, data)
956 data = repo.wwritedata(abs, data)
957 fp.write(data)
957 fp.write(data)
958 fp.close()
958 fp.close()
959 err = 0
959 err = 0
960 return err
960 return err
961
961
962 @command('^clone',
962 @command('^clone',
963 [('U', 'noupdate', None,
963 [('U', 'noupdate', None,
964 _('the clone will include an empty working copy (only a repository)')),
964 _('the clone will include an empty working copy (only a repository)')),
965 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
965 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
966 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
966 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
967 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
967 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
968 ('', 'pull', None, _('use pull protocol to copy metadata')),
968 ('', 'pull', None, _('use pull protocol to copy metadata')),
969 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
969 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
970 ] + remoteopts,
970 ] + remoteopts,
971 _('[OPTION]... SOURCE [DEST]'))
971 _('[OPTION]... SOURCE [DEST]'))
972 def clone(ui, source, dest=None, **opts):
972 def clone(ui, source, dest=None, **opts):
973 """make a copy of an existing repository
973 """make a copy of an existing repository
974
974
975 Create a copy of an existing repository in a new directory.
975 Create a copy of an existing repository in a new directory.
976
976
977 If no destination directory name is specified, it defaults to the
977 If no destination directory name is specified, it defaults to the
978 basename of the source.
978 basename of the source.
979
979
980 The location of the source is added to the new repository's
980 The location of the source is added to the new repository's
981 ``.hg/hgrc`` file, as the default to be used for future pulls.
981 ``.hg/hgrc`` file, as the default to be used for future pulls.
982
982
983 See :hg:`help urls` for valid source format details.
983 See :hg:`help urls` for valid source format details.
984
984
985 It is possible to specify an ``ssh://`` URL as the destination, but no
985 It is possible to specify an ``ssh://`` URL as the destination, but no
986 ``.hg/hgrc`` and working directory will be created on the remote side.
986 ``.hg/hgrc`` and working directory will be created on the remote side.
987 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
987 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
988
988
989 A set of changesets (tags, or branch names) to pull may be specified
989 A set of changesets (tags, or branch names) to pull may be specified
990 by listing each changeset (tag, or branch name) with -r/--rev.
990 by listing each changeset (tag, or branch name) with -r/--rev.
991 If -r/--rev is used, the cloned repository will contain only a subset
991 If -r/--rev is used, the cloned repository will contain only a subset
992 of the changesets of the source repository. Only the set of changesets
992 of the changesets of the source repository. Only the set of changesets
993 defined by all -r/--rev options (including all their ancestors)
993 defined by all -r/--rev options (including all their ancestors)
994 will be pulled into the destination repository.
994 will be pulled into the destination repository.
995 No subsequent changesets (including subsequent tags) will be present
995 No subsequent changesets (including subsequent tags) will be present
996 in the destination.
996 in the destination.
997
997
998 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
998 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
999 local source repositories.
999 local source repositories.
1000
1000
1001 For efficiency, hardlinks are used for cloning whenever the source
1001 For efficiency, hardlinks are used for cloning whenever the source
1002 and destination are on the same filesystem (note this applies only
1002 and destination are on the same filesystem (note this applies only
1003 to the repository data, not to the working directory). Some
1003 to the repository data, not to the working directory). Some
1004 filesystems, such as AFS, implement hardlinking incorrectly, but
1004 filesystems, such as AFS, implement hardlinking incorrectly, but
1005 do not report errors. In these cases, use the --pull option to
1005 do not report errors. In these cases, use the --pull option to
1006 avoid hardlinking.
1006 avoid hardlinking.
1007
1007
1008 In some cases, you can clone repositories and the working directory
1008 In some cases, you can clone repositories and the working directory
1009 using full hardlinks with ::
1009 using full hardlinks with ::
1010
1010
1011 $ cp -al REPO REPOCLONE
1011 $ cp -al REPO REPOCLONE
1012
1012
1013 This is the fastest way to clone, but it is not always safe. The
1013 This is the fastest way to clone, but it is not always safe. The
1014 operation is not atomic (making sure REPO is not modified during
1014 operation is not atomic (making sure REPO is not modified during
1015 the operation is up to you) and you have to make sure your editor
1015 the operation is up to you) and you have to make sure your editor
1016 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
1016 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
1017 this is not compatible with certain extensions that place their
1017 this is not compatible with certain extensions that place their
1018 metadata under the .hg directory, such as mq.
1018 metadata under the .hg directory, such as mq.
1019
1019
1020 Mercurial will update the working directory to the first applicable
1020 Mercurial will update the working directory to the first applicable
1021 revision from this list:
1021 revision from this list:
1022
1022
1023 a) null if -U or the source repository has no changesets
1023 a) null if -U or the source repository has no changesets
1024 b) if -u . and the source repository is local, the first parent of
1024 b) if -u . and the source repository is local, the first parent of
1025 the source repository's working directory
1025 the source repository's working directory
1026 c) the changeset specified with -u (if a branch name, this means the
1026 c) the changeset specified with -u (if a branch name, this means the
1027 latest head of that branch)
1027 latest head of that branch)
1028 d) the changeset specified with -r
1028 d) the changeset specified with -r
1029 e) the tipmost head specified with -b
1029 e) the tipmost head specified with -b
1030 f) the tipmost head specified with the url#branch source syntax
1030 f) the tipmost head specified with the url#branch source syntax
1031 g) the tipmost head of the default branch
1031 g) the tipmost head of the default branch
1032 h) tip
1032 h) tip
1033
1033
1034 Returns 0 on success.
1034 Returns 0 on success.
1035 """
1035 """
1036 if opts.get('noupdate') and opts.get('updaterev'):
1036 if opts.get('noupdate') and opts.get('updaterev'):
1037 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1037 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1038
1038
1039 r = hg.clone(ui, opts, source, dest,
1039 r = hg.clone(ui, opts, source, dest,
1040 pull=opts.get('pull'),
1040 pull=opts.get('pull'),
1041 stream=opts.get('uncompressed'),
1041 stream=opts.get('uncompressed'),
1042 rev=opts.get('rev'),
1042 rev=opts.get('rev'),
1043 update=opts.get('updaterev') or not opts.get('noupdate'),
1043 update=opts.get('updaterev') or not opts.get('noupdate'),
1044 branch=opts.get('branch'))
1044 branch=opts.get('branch'))
1045
1045
1046 return r is None
1046 return r is None
1047
1047
1048 @command('^commit|ci',
1048 @command('^commit|ci',
1049 [('A', 'addremove', None,
1049 [('A', 'addremove', None,
1050 _('mark new/missing files as added/removed before committing')),
1050 _('mark new/missing files as added/removed before committing')),
1051 ('', 'close-branch', None,
1051 ('', 'close-branch', None,
1052 _('mark a branch as closed, hiding it from the branch list')),
1052 _('mark a branch as closed, hiding it from the branch list')),
1053 ] + walkopts + commitopts + commitopts2,
1053 ] + walkopts + commitopts + commitopts2,
1054 _('[OPTION]... [FILE]...'))
1054 _('[OPTION]... [FILE]...'))
1055 def commit(ui, repo, *pats, **opts):
1055 def commit(ui, repo, *pats, **opts):
1056 """commit the specified files or all outstanding changes
1056 """commit the specified files or all outstanding changes
1057
1057
1058 Commit changes to the given files into the repository. Unlike a
1058 Commit changes to the given files into the repository. Unlike a
1059 centralized SCM, this operation is a local operation. See
1059 centralized SCM, this operation is a local operation. See
1060 :hg:`push` for a way to actively distribute your changes.
1060 :hg:`push` for a way to actively distribute your changes.
1061
1061
1062 If a list of files is omitted, all changes reported by :hg:`status`
1062 If a list of files is omitted, all changes reported by :hg:`status`
1063 will be committed.
1063 will be committed.
1064
1064
1065 If you are committing the result of a merge, do not provide any
1065 If you are committing the result of a merge, do not provide any
1066 filenames or -I/-X filters.
1066 filenames or -I/-X filters.
1067
1067
1068 If no commit message is specified, Mercurial starts your
1068 If no commit message is specified, Mercurial starts your
1069 configured editor where you can enter a message. In case your
1069 configured editor where you can enter a message. In case your
1070 commit fails, you will find a backup of your message in
1070 commit fails, you will find a backup of your message in
1071 ``.hg/last-message.txt``.
1071 ``.hg/last-message.txt``.
1072
1072
1073 See :hg:`help dates` for a list of formats valid for -d/--date.
1073 See :hg:`help dates` for a list of formats valid for -d/--date.
1074
1074
1075 Returns 0 on success, 1 if nothing changed.
1075 Returns 0 on success, 1 if nothing changed.
1076 """
1076 """
1077 extra = {}
1077 extra = {}
1078 if opts.get('close_branch'):
1078 if opts.get('close_branch'):
1079 if repo['.'].node() not in repo.branchheads():
1079 if repo['.'].node() not in repo.branchheads():
1080 # The topo heads set is included in the branch heads set of the
1080 # The topo heads set is included in the branch heads set of the
1081 # current branch, so it's sufficient to test branchheads
1081 # current branch, so it's sufficient to test branchheads
1082 raise util.Abort(_('can only close branch heads'))
1082 raise util.Abort(_('can only close branch heads'))
1083 extra['close'] = 1
1083 extra['close'] = 1
1084 e = cmdutil.commiteditor
1084 e = cmdutil.commiteditor
1085 if opts.get('force_editor'):
1085 if opts.get('force_editor'):
1086 e = cmdutil.commitforceeditor
1086 e = cmdutil.commitforceeditor
1087
1087
1088 def commitfunc(ui, repo, message, match, opts):
1088 def commitfunc(ui, repo, message, match, opts):
1089 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1089 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1090 editor=e, extra=extra)
1090 editor=e, extra=extra)
1091
1091
1092 branch = repo[None].branch()
1092 branch = repo[None].branch()
1093 bheads = repo.branchheads(branch)
1093 bheads = repo.branchheads(branch)
1094
1094
1095 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1095 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1096 if not node:
1096 if not node:
1097 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1097 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1098 if stat[3]:
1098 if stat[3]:
1099 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1099 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1100 % len(stat[3]))
1100 % len(stat[3]))
1101 else:
1101 else:
1102 ui.status(_("nothing changed\n"))
1102 ui.status(_("nothing changed\n"))
1103 return 1
1103 return 1
1104
1104
1105 ctx = repo[node]
1105 ctx = repo[node]
1106 parents = ctx.parents()
1106 parents = ctx.parents()
1107
1107
1108 if (bheads and node not in bheads and not
1108 if (bheads and node not in bheads and not
1109 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1109 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1110 ui.status(_('created new head\n'))
1110 ui.status(_('created new head\n'))
1111 # The message is not printed for initial roots. For the other
1111 # The message is not printed for initial roots. For the other
1112 # changesets, it is printed in the following situations:
1112 # changesets, it is printed in the following situations:
1113 #
1113 #
1114 # Par column: for the 2 parents with ...
1114 # Par column: for the 2 parents with ...
1115 # N: null or no parent
1115 # N: null or no parent
1116 # B: parent is on another named branch
1116 # B: parent is on another named branch
1117 # C: parent is a regular non head changeset
1117 # C: parent is a regular non head changeset
1118 # H: parent was a branch head of the current branch
1118 # H: parent was a branch head of the current branch
1119 # Msg column: whether we print "created new head" message
1119 # Msg column: whether we print "created new head" message
1120 # In the following, it is assumed that there already exists some
1120 # In the following, it is assumed that there already exists some
1121 # initial branch heads of the current branch, otherwise nothing is
1121 # initial branch heads of the current branch, otherwise nothing is
1122 # printed anyway.
1122 # printed anyway.
1123 #
1123 #
1124 # Par Msg Comment
1124 # Par Msg Comment
1125 # NN y additional topo root
1125 # NN y additional topo root
1126 #
1126 #
1127 # BN y additional branch root
1127 # BN y additional branch root
1128 # CN y additional topo head
1128 # CN y additional topo head
1129 # HN n usual case
1129 # HN n usual case
1130 #
1130 #
1131 # BB y weird additional branch root
1131 # BB y weird additional branch root
1132 # CB y branch merge
1132 # CB y branch merge
1133 # HB n merge with named branch
1133 # HB n merge with named branch
1134 #
1134 #
1135 # CC y additional head from merge
1135 # CC y additional head from merge
1136 # CH n merge with a head
1136 # CH n merge with a head
1137 #
1137 #
1138 # HH n head merge: head count decreases
1138 # HH n head merge: head count decreases
1139
1139
1140 if not opts.get('close_branch'):
1140 if not opts.get('close_branch'):
1141 for r in parents:
1141 for r in parents:
1142 if r.extra().get('close') and r.branch() == branch:
1142 if r.extra().get('close') and r.branch() == branch:
1143 ui.status(_('reopening closed branch head %d\n') % r)
1143 ui.status(_('reopening closed branch head %d\n') % r)
1144
1144
1145 if ui.debugflag:
1145 if ui.debugflag:
1146 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1146 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1147 elif ui.verbose:
1147 elif ui.verbose:
1148 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1148 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1149
1149
1150 @command('copy|cp',
1150 @command('copy|cp',
1151 [('A', 'after', None, _('record a copy that has already occurred')),
1151 [('A', 'after', None, _('record a copy that has already occurred')),
1152 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1152 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1153 ] + walkopts + dryrunopts,
1153 ] + walkopts + dryrunopts,
1154 _('[OPTION]... [SOURCE]... DEST'))
1154 _('[OPTION]... [SOURCE]... DEST'))
1155 def copy(ui, repo, *pats, **opts):
1155 def copy(ui, repo, *pats, **opts):
1156 """mark files as copied for the next commit
1156 """mark files as copied for the next commit
1157
1157
1158 Mark dest as having copies of source files. If dest is a
1158 Mark dest as having copies of source files. If dest is a
1159 directory, copies are put in that directory. If dest is a file,
1159 directory, copies are put in that directory. If dest is a file,
1160 the source must be a single file.
1160 the source must be a single file.
1161
1161
1162 By default, this command copies the contents of files as they
1162 By default, this command copies the contents of files as they
1163 exist in the working directory. If invoked with -A/--after, the
1163 exist in the working directory. If invoked with -A/--after, the
1164 operation is recorded, but no copying is performed.
1164 operation is recorded, but no copying is performed.
1165
1165
1166 This command takes effect with the next commit. To undo a copy
1166 This command takes effect with the next commit. To undo a copy
1167 before that, see :hg:`revert`.
1167 before that, see :hg:`revert`.
1168
1168
1169 Returns 0 on success, 1 if errors are encountered.
1169 Returns 0 on success, 1 if errors are encountered.
1170 """
1170 """
1171 wlock = repo.wlock(False)
1171 wlock = repo.wlock(False)
1172 try:
1172 try:
1173 return cmdutil.copy(ui, repo, pats, opts)
1173 return cmdutil.copy(ui, repo, pats, opts)
1174 finally:
1174 finally:
1175 wlock.release()
1175 wlock.release()
1176
1176
1177 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1177 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1178 def debugancestor(ui, repo, *args):
1178 def debugancestor(ui, repo, *args):
1179 """find the ancestor revision of two revisions in a given index"""
1179 """find the ancestor revision of two revisions in a given index"""
1180 if len(args) == 3:
1180 if len(args) == 3:
1181 index, rev1, rev2 = args
1181 index, rev1, rev2 = args
1182 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1182 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1183 lookup = r.lookup
1183 lookup = r.lookup
1184 elif len(args) == 2:
1184 elif len(args) == 2:
1185 if not repo:
1185 if not repo:
1186 raise util.Abort(_("there is no Mercurial repository here "
1186 raise util.Abort(_("there is no Mercurial repository here "
1187 "(.hg not found)"))
1187 "(.hg not found)"))
1188 rev1, rev2 = args
1188 rev1, rev2 = args
1189 r = repo.changelog
1189 r = repo.changelog
1190 lookup = repo.lookup
1190 lookup = repo.lookup
1191 else:
1191 else:
1192 raise util.Abort(_('either two or three arguments required'))
1192 raise util.Abort(_('either two or three arguments required'))
1193 a = r.ancestor(lookup(rev1), lookup(rev2))
1193 a = r.ancestor(lookup(rev1), lookup(rev2))
1194 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1194 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1195
1195
1196 @command('debugbuilddag',
1196 @command('debugbuilddag',
1197 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1197 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1198 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1198 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1199 ('n', 'new-file', None, _('add new file at each rev'))],
1199 ('n', 'new-file', None, _('add new file at each rev'))],
1200 _('[OPTION]... [TEXT]'))
1200 _('[OPTION]... [TEXT]'))
1201 def debugbuilddag(ui, repo, text=None,
1201 def debugbuilddag(ui, repo, text=None,
1202 mergeable_file=False,
1202 mergeable_file=False,
1203 overwritten_file=False,
1203 overwritten_file=False,
1204 new_file=False):
1204 new_file=False):
1205 """builds a repo with a given DAG from scratch in the current empty repo
1205 """builds a repo with a given DAG from scratch in the current empty repo
1206
1206
1207 The description of the DAG is read from stdin if not given on the
1207 The description of the DAG is read from stdin if not given on the
1208 command line.
1208 command line.
1209
1209
1210 Elements:
1210 Elements:
1211
1211
1212 - "+n" is a linear run of n nodes based on the current default parent
1212 - "+n" is a linear run of n nodes based on the current default parent
1213 - "." is a single node based on the current default parent
1213 - "." is a single node based on the current default parent
1214 - "$" resets the default parent to null (implied at the start);
1214 - "$" resets the default parent to null (implied at the start);
1215 otherwise the default parent is always the last node created
1215 otherwise the default parent is always the last node created
1216 - "<p" sets the default parent to the backref p
1216 - "<p" sets the default parent to the backref p
1217 - "*p" is a fork at parent p, which is a backref
1217 - "*p" is a fork at parent p, which is a backref
1218 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1218 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1219 - "/p2" is a merge of the preceding node and p2
1219 - "/p2" is a merge of the preceding node and p2
1220 - ":tag" defines a local tag for the preceding node
1220 - ":tag" defines a local tag for the preceding node
1221 - "@branch" sets the named branch for subsequent nodes
1221 - "@branch" sets the named branch for subsequent nodes
1222 - "#...\\n" is a comment up to the end of the line
1222 - "#...\\n" is a comment up to the end of the line
1223
1223
1224 Whitespace between the above elements is ignored.
1224 Whitespace between the above elements is ignored.
1225
1225
1226 A backref is either
1226 A backref is either
1227
1227
1228 - a number n, which references the node curr-n, where curr is the current
1228 - a number n, which references the node curr-n, where curr is the current
1229 node, or
1229 node, or
1230 - the name of a local tag you placed earlier using ":tag", or
1230 - the name of a local tag you placed earlier using ":tag", or
1231 - empty to denote the default parent.
1231 - empty to denote the default parent.
1232
1232
1233 All string valued-elements are either strictly alphanumeric, or must
1233 All string valued-elements are either strictly alphanumeric, or must
1234 be enclosed in double quotes ("..."), with "\\" as escape character.
1234 be enclosed in double quotes ("..."), with "\\" as escape character.
1235 """
1235 """
1236
1236
1237 if text is None:
1237 if text is None:
1238 ui.status(_("reading DAG from stdin\n"))
1238 ui.status(_("reading DAG from stdin\n"))
1239 text = ui.fin.read()
1239 text = ui.fin.read()
1240
1240
1241 cl = repo.changelog
1241 cl = repo.changelog
1242 if len(cl) > 0:
1242 if len(cl) > 0:
1243 raise util.Abort(_('repository is not empty'))
1243 raise util.Abort(_('repository is not empty'))
1244
1244
1245 # determine number of revs in DAG
1245 # determine number of revs in DAG
1246 total = 0
1246 total = 0
1247 for type, data in dagparser.parsedag(text):
1247 for type, data in dagparser.parsedag(text):
1248 if type == 'n':
1248 if type == 'n':
1249 total += 1
1249 total += 1
1250
1250
1251 if mergeable_file:
1251 if mergeable_file:
1252 linesperrev = 2
1252 linesperrev = 2
1253 # make a file with k lines per rev
1253 # make a file with k lines per rev
1254 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1254 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1255 initialmergedlines.append("")
1255 initialmergedlines.append("")
1256
1256
1257 tags = []
1257 tags = []
1258
1258
1259 tr = repo.transaction("builddag")
1259 tr = repo.transaction("builddag")
1260 try:
1260 try:
1261
1261
1262 at = -1
1262 at = -1
1263 atbranch = 'default'
1263 atbranch = 'default'
1264 nodeids = []
1264 nodeids = []
1265 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1265 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1266 for type, data in dagparser.parsedag(text):
1266 for type, data in dagparser.parsedag(text):
1267 if type == 'n':
1267 if type == 'n':
1268 ui.note('node %s\n' % str(data))
1268 ui.note('node %s\n' % str(data))
1269 id, ps = data
1269 id, ps = data
1270
1270
1271 files = []
1271 files = []
1272 fctxs = {}
1272 fctxs = {}
1273
1273
1274 p2 = None
1274 p2 = None
1275 if mergeable_file:
1275 if mergeable_file:
1276 fn = "mf"
1276 fn = "mf"
1277 p1 = repo[ps[0]]
1277 p1 = repo[ps[0]]
1278 if len(ps) > 1:
1278 if len(ps) > 1:
1279 p2 = repo[ps[1]]
1279 p2 = repo[ps[1]]
1280 pa = p1.ancestor(p2)
1280 pa = p1.ancestor(p2)
1281 base, local, other = [x[fn].data() for x in pa, p1, p2]
1281 base, local, other = [x[fn].data() for x in pa, p1, p2]
1282 m3 = simplemerge.Merge3Text(base, local, other)
1282 m3 = simplemerge.Merge3Text(base, local, other)
1283 ml = [l.strip() for l in m3.merge_lines()]
1283 ml = [l.strip() for l in m3.merge_lines()]
1284 ml.append("")
1284 ml.append("")
1285 elif at > 0:
1285 elif at > 0:
1286 ml = p1[fn].data().split("\n")
1286 ml = p1[fn].data().split("\n")
1287 else:
1287 else:
1288 ml = initialmergedlines
1288 ml = initialmergedlines
1289 ml[id * linesperrev] += " r%i" % id
1289 ml[id * linesperrev] += " r%i" % id
1290 mergedtext = "\n".join(ml)
1290 mergedtext = "\n".join(ml)
1291 files.append(fn)
1291 files.append(fn)
1292 fctxs[fn] = context.memfilectx(fn, mergedtext)
1292 fctxs[fn] = context.memfilectx(fn, mergedtext)
1293
1293
1294 if overwritten_file:
1294 if overwritten_file:
1295 fn = "of"
1295 fn = "of"
1296 files.append(fn)
1296 files.append(fn)
1297 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1297 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1298
1298
1299 if new_file:
1299 if new_file:
1300 fn = "nf%i" % id
1300 fn = "nf%i" % id
1301 files.append(fn)
1301 files.append(fn)
1302 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1302 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1303 if len(ps) > 1:
1303 if len(ps) > 1:
1304 if not p2:
1304 if not p2:
1305 p2 = repo[ps[1]]
1305 p2 = repo[ps[1]]
1306 for fn in p2:
1306 for fn in p2:
1307 if fn.startswith("nf"):
1307 if fn.startswith("nf"):
1308 files.append(fn)
1308 files.append(fn)
1309 fctxs[fn] = p2[fn]
1309 fctxs[fn] = p2[fn]
1310
1310
1311 def fctxfn(repo, cx, path):
1311 def fctxfn(repo, cx, path):
1312 return fctxs.get(path)
1312 return fctxs.get(path)
1313
1313
1314 if len(ps) == 0 or ps[0] < 0:
1314 if len(ps) == 0 or ps[0] < 0:
1315 pars = [None, None]
1315 pars = [None, None]
1316 elif len(ps) == 1:
1316 elif len(ps) == 1:
1317 pars = [nodeids[ps[0]], None]
1317 pars = [nodeids[ps[0]], None]
1318 else:
1318 else:
1319 pars = [nodeids[p] for p in ps]
1319 pars = [nodeids[p] for p in ps]
1320 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1320 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1321 date=(id, 0),
1321 date=(id, 0),
1322 user="debugbuilddag",
1322 user="debugbuilddag",
1323 extra={'branch': atbranch})
1323 extra={'branch': atbranch})
1324 nodeid = repo.commitctx(cx)
1324 nodeid = repo.commitctx(cx)
1325 nodeids.append(nodeid)
1325 nodeids.append(nodeid)
1326 at = id
1326 at = id
1327 elif type == 'l':
1327 elif type == 'l':
1328 id, name = data
1328 id, name = data
1329 ui.note('tag %s\n' % name)
1329 ui.note('tag %s\n' % name)
1330 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1330 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1331 elif type == 'a':
1331 elif type == 'a':
1332 ui.note('branch %s\n' % data)
1332 ui.note('branch %s\n' % data)
1333 atbranch = data
1333 atbranch = data
1334 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1334 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1335 tr.close()
1335 tr.close()
1336 finally:
1336 finally:
1337 ui.progress(_('building'), None)
1337 ui.progress(_('building'), None)
1338 tr.release()
1338 tr.release()
1339
1339
1340 if tags:
1340 if tags:
1341 repo.opener.write("localtags", "".join(tags))
1341 repo.opener.write("localtags", "".join(tags))
1342
1342
1343 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1343 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1344 def debugbundle(ui, bundlepath, all=None, **opts):
1344 def debugbundle(ui, bundlepath, all=None, **opts):
1345 """lists the contents of a bundle"""
1345 """lists the contents of a bundle"""
1346 f = url.open(ui, bundlepath)
1346 f = url.open(ui, bundlepath)
1347 try:
1347 try:
1348 gen = changegroup.readbundle(f, bundlepath)
1348 gen = changegroup.readbundle(f, bundlepath)
1349 if all:
1349 if all:
1350 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1350 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1351
1351
1352 def showchunks(named):
1352 def showchunks(named):
1353 ui.write("\n%s\n" % named)
1353 ui.write("\n%s\n" % named)
1354 chain = None
1354 chain = None
1355 while True:
1355 while True:
1356 chunkdata = gen.deltachunk(chain)
1356 chunkdata = gen.deltachunk(chain)
1357 if not chunkdata:
1357 if not chunkdata:
1358 break
1358 break
1359 node = chunkdata['node']
1359 node = chunkdata['node']
1360 p1 = chunkdata['p1']
1360 p1 = chunkdata['p1']
1361 p2 = chunkdata['p2']
1361 p2 = chunkdata['p2']
1362 cs = chunkdata['cs']
1362 cs = chunkdata['cs']
1363 deltabase = chunkdata['deltabase']
1363 deltabase = chunkdata['deltabase']
1364 delta = chunkdata['delta']
1364 delta = chunkdata['delta']
1365 ui.write("%s %s %s %s %s %s\n" %
1365 ui.write("%s %s %s %s %s %s\n" %
1366 (hex(node), hex(p1), hex(p2),
1366 (hex(node), hex(p1), hex(p2),
1367 hex(cs), hex(deltabase), len(delta)))
1367 hex(cs), hex(deltabase), len(delta)))
1368 chain = node
1368 chain = node
1369
1369
1370 chunkdata = gen.changelogheader()
1370 chunkdata = gen.changelogheader()
1371 showchunks("changelog")
1371 showchunks("changelog")
1372 chunkdata = gen.manifestheader()
1372 chunkdata = gen.manifestheader()
1373 showchunks("manifest")
1373 showchunks("manifest")
1374 while True:
1374 while True:
1375 chunkdata = gen.filelogheader()
1375 chunkdata = gen.filelogheader()
1376 if not chunkdata:
1376 if not chunkdata:
1377 break
1377 break
1378 fname = chunkdata['filename']
1378 fname = chunkdata['filename']
1379 showchunks(fname)
1379 showchunks(fname)
1380 else:
1380 else:
1381 chunkdata = gen.changelogheader()
1381 chunkdata = gen.changelogheader()
1382 chain = None
1382 chain = None
1383 while True:
1383 while True:
1384 chunkdata = gen.deltachunk(chain)
1384 chunkdata = gen.deltachunk(chain)
1385 if not chunkdata:
1385 if not chunkdata:
1386 break
1386 break
1387 node = chunkdata['node']
1387 node = chunkdata['node']
1388 ui.write("%s\n" % hex(node))
1388 ui.write("%s\n" % hex(node))
1389 chain = node
1389 chain = node
1390 finally:
1390 finally:
1391 f.close()
1391 f.close()
1392
1392
1393 @command('debugcheckstate', [], '')
1393 @command('debugcheckstate', [], '')
1394 def debugcheckstate(ui, repo):
1394 def debugcheckstate(ui, repo):
1395 """validate the correctness of the current dirstate"""
1395 """validate the correctness of the current dirstate"""
1396 parent1, parent2 = repo.dirstate.parents()
1396 parent1, parent2 = repo.dirstate.parents()
1397 m1 = repo[parent1].manifest()
1397 m1 = repo[parent1].manifest()
1398 m2 = repo[parent2].manifest()
1398 m2 = repo[parent2].manifest()
1399 errors = 0
1399 errors = 0
1400 for f in repo.dirstate:
1400 for f in repo.dirstate:
1401 state = repo.dirstate[f]
1401 state = repo.dirstate[f]
1402 if state in "nr" and f not in m1:
1402 if state in "nr" and f not in m1:
1403 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1403 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1404 errors += 1
1404 errors += 1
1405 if state in "a" and f in m1:
1405 if state in "a" and f in m1:
1406 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1406 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1407 errors += 1
1407 errors += 1
1408 if state in "m" and f not in m1 and f not in m2:
1408 if state in "m" and f not in m1 and f not in m2:
1409 ui.warn(_("%s in state %s, but not in either manifest\n") %
1409 ui.warn(_("%s in state %s, but not in either manifest\n") %
1410 (f, state))
1410 (f, state))
1411 errors += 1
1411 errors += 1
1412 for f in m1:
1412 for f in m1:
1413 state = repo.dirstate[f]
1413 state = repo.dirstate[f]
1414 if state not in "nrm":
1414 if state not in "nrm":
1415 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1415 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1416 errors += 1
1416 errors += 1
1417 if errors:
1417 if errors:
1418 error = _(".hg/dirstate inconsistent with current parent's manifest")
1418 error = _(".hg/dirstate inconsistent with current parent's manifest")
1419 raise util.Abort(error)
1419 raise util.Abort(error)
1420
1420
1421 @command('debugcommands', [], _('[COMMAND]'))
1421 @command('debugcommands', [], _('[COMMAND]'))
1422 def debugcommands(ui, cmd='', *args):
1422 def debugcommands(ui, cmd='', *args):
1423 """list all available commands and options"""
1423 """list all available commands and options"""
1424 for cmd, vals in sorted(table.iteritems()):
1424 for cmd, vals in sorted(table.iteritems()):
1425 cmd = cmd.split('|')[0].strip('^')
1425 cmd = cmd.split('|')[0].strip('^')
1426 opts = ', '.join([i[1] for i in vals[1]])
1426 opts = ', '.join([i[1] for i in vals[1]])
1427 ui.write('%s: %s\n' % (cmd, opts))
1427 ui.write('%s: %s\n' % (cmd, opts))
1428
1428
1429 @command('debugcomplete',
1429 @command('debugcomplete',
1430 [('o', 'options', None, _('show the command options'))],
1430 [('o', 'options', None, _('show the command options'))],
1431 _('[-o] CMD'))
1431 _('[-o] CMD'))
1432 def debugcomplete(ui, cmd='', **opts):
1432 def debugcomplete(ui, cmd='', **opts):
1433 """returns the completion list associated with the given command"""
1433 """returns the completion list associated with the given command"""
1434
1434
1435 if opts.get('options'):
1435 if opts.get('options'):
1436 options = []
1436 options = []
1437 otables = [globalopts]
1437 otables = [globalopts]
1438 if cmd:
1438 if cmd:
1439 aliases, entry = cmdutil.findcmd(cmd, table, False)
1439 aliases, entry = cmdutil.findcmd(cmd, table, False)
1440 otables.append(entry[1])
1440 otables.append(entry[1])
1441 for t in otables:
1441 for t in otables:
1442 for o in t:
1442 for o in t:
1443 if "(DEPRECATED)" in o[3]:
1443 if "(DEPRECATED)" in o[3]:
1444 continue
1444 continue
1445 if o[0]:
1445 if o[0]:
1446 options.append('-%s' % o[0])
1446 options.append('-%s' % o[0])
1447 options.append('--%s' % o[1])
1447 options.append('--%s' % o[1])
1448 ui.write("%s\n" % "\n".join(options))
1448 ui.write("%s\n" % "\n".join(options))
1449 return
1449 return
1450
1450
1451 cmdlist = cmdutil.findpossible(cmd, table)
1451 cmdlist = cmdutil.findpossible(cmd, table)
1452 if ui.verbose:
1452 if ui.verbose:
1453 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1453 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1454 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1454 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1455
1455
1456 @command('debugdag',
1456 @command('debugdag',
1457 [('t', 'tags', None, _('use tags as labels')),
1457 [('t', 'tags', None, _('use tags as labels')),
1458 ('b', 'branches', None, _('annotate with branch names')),
1458 ('b', 'branches', None, _('annotate with branch names')),
1459 ('', 'dots', None, _('use dots for runs')),
1459 ('', 'dots', None, _('use dots for runs')),
1460 ('s', 'spaces', None, _('separate elements by spaces'))],
1460 ('s', 'spaces', None, _('separate elements by spaces'))],
1461 _('[OPTION]... [FILE [REV]...]'))
1461 _('[OPTION]... [FILE [REV]...]'))
1462 def debugdag(ui, repo, file_=None, *revs, **opts):
1462 def debugdag(ui, repo, file_=None, *revs, **opts):
1463 """format the changelog or an index DAG as a concise textual description
1463 """format the changelog or an index DAG as a concise textual description
1464
1464
1465 If you pass a revlog index, the revlog's DAG is emitted. If you list
1465 If you pass a revlog index, the revlog's DAG is emitted. If you list
1466 revision numbers, they get labelled in the output as rN.
1466 revision numbers, they get labelled in the output as rN.
1467
1467
1468 Otherwise, the changelog DAG of the current repo is emitted.
1468 Otherwise, the changelog DAG of the current repo is emitted.
1469 """
1469 """
1470 spaces = opts.get('spaces')
1470 spaces = opts.get('spaces')
1471 dots = opts.get('dots')
1471 dots = opts.get('dots')
1472 if file_:
1472 if file_:
1473 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1473 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1474 revs = set((int(r) for r in revs))
1474 revs = set((int(r) for r in revs))
1475 def events():
1475 def events():
1476 for r in rlog:
1476 for r in rlog:
1477 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1477 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1478 if r in revs:
1478 if r in revs:
1479 yield 'l', (r, "r%i" % r)
1479 yield 'l', (r, "r%i" % r)
1480 elif repo:
1480 elif repo:
1481 cl = repo.changelog
1481 cl = repo.changelog
1482 tags = opts.get('tags')
1482 tags = opts.get('tags')
1483 branches = opts.get('branches')
1483 branches = opts.get('branches')
1484 if tags:
1484 if tags:
1485 labels = {}
1485 labels = {}
1486 for l, n in repo.tags().items():
1486 for l, n in repo.tags().items():
1487 labels.setdefault(cl.rev(n), []).append(l)
1487 labels.setdefault(cl.rev(n), []).append(l)
1488 def events():
1488 def events():
1489 b = "default"
1489 b = "default"
1490 for r in cl:
1490 for r in cl:
1491 if branches:
1491 if branches:
1492 newb = cl.read(cl.node(r))[5]['branch']
1492 newb = cl.read(cl.node(r))[5]['branch']
1493 if newb != b:
1493 if newb != b:
1494 yield 'a', newb
1494 yield 'a', newb
1495 b = newb
1495 b = newb
1496 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1496 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1497 if tags:
1497 if tags:
1498 ls = labels.get(r)
1498 ls = labels.get(r)
1499 if ls:
1499 if ls:
1500 for l in ls:
1500 for l in ls:
1501 yield 'l', (r, l)
1501 yield 'l', (r, l)
1502 else:
1502 else:
1503 raise util.Abort(_('need repo for changelog dag'))
1503 raise util.Abort(_('need repo for changelog dag'))
1504
1504
1505 for line in dagparser.dagtextlines(events(),
1505 for line in dagparser.dagtextlines(events(),
1506 addspaces=spaces,
1506 addspaces=spaces,
1507 wraplabels=True,
1507 wraplabels=True,
1508 wrapannotations=True,
1508 wrapannotations=True,
1509 wrapnonlinear=dots,
1509 wrapnonlinear=dots,
1510 usedots=dots,
1510 usedots=dots,
1511 maxlinewidth=70):
1511 maxlinewidth=70):
1512 ui.write(line)
1512 ui.write(line)
1513 ui.write("\n")
1513 ui.write("\n")
1514
1514
1515 @command('debugdata',
1515 @command('debugdata',
1516 [('c', 'changelog', False, _('open changelog')),
1516 [('c', 'changelog', False, _('open changelog')),
1517 ('m', 'manifest', False, _('open manifest'))],
1517 ('m', 'manifest', False, _('open manifest'))],
1518 _('-c|-m|FILE REV'))
1518 _('-c|-m|FILE REV'))
1519 def debugdata(ui, repo, file_, rev = None, **opts):
1519 def debugdata(ui, repo, file_, rev = None, **opts):
1520 """dump the contents of a data file revision"""
1520 """dump the contents of a data file revision"""
1521 if opts.get('changelog') or opts.get('manifest'):
1521 if opts.get('changelog') or opts.get('manifest'):
1522 file_, rev = None, file_
1522 file_, rev = None, file_
1523 elif rev is None:
1523 elif rev is None:
1524 raise error.CommandError('debugdata', _('invalid arguments'))
1524 raise error.CommandError('debugdata', _('invalid arguments'))
1525 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1525 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1526 try:
1526 try:
1527 ui.write(r.revision(r.lookup(rev)))
1527 ui.write(r.revision(r.lookup(rev)))
1528 except KeyError:
1528 except KeyError:
1529 raise util.Abort(_('invalid revision identifier %s') % rev)
1529 raise util.Abort(_('invalid revision identifier %s') % rev)
1530
1530
1531 @command('debugdate',
1531 @command('debugdate',
1532 [('e', 'extended', None, _('try extended date formats'))],
1532 [('e', 'extended', None, _('try extended date formats'))],
1533 _('[-e] DATE [RANGE]'))
1533 _('[-e] DATE [RANGE]'))
1534 def debugdate(ui, date, range=None, **opts):
1534 def debugdate(ui, date, range=None, **opts):
1535 """parse and display a date"""
1535 """parse and display a date"""
1536 if opts["extended"]:
1536 if opts["extended"]:
1537 d = util.parsedate(date, util.extendeddateformats)
1537 d = util.parsedate(date, util.extendeddateformats)
1538 else:
1538 else:
1539 d = util.parsedate(date)
1539 d = util.parsedate(date)
1540 ui.write("internal: %s %s\n" % d)
1540 ui.write("internal: %s %s\n" % d)
1541 ui.write("standard: %s\n" % util.datestr(d))
1541 ui.write("standard: %s\n" % util.datestr(d))
1542 if range:
1542 if range:
1543 m = util.matchdate(range)
1543 m = util.matchdate(range)
1544 ui.write("match: %s\n" % m(d[0]))
1544 ui.write("match: %s\n" % m(d[0]))
1545
1545
1546 @command('debugdiscovery',
1546 @command('debugdiscovery',
1547 [('', 'old', None, _('use old-style discovery')),
1547 [('', 'old', None, _('use old-style discovery')),
1548 ('', 'nonheads', None,
1548 ('', 'nonheads', None,
1549 _('use old-style discovery with non-heads included')),
1549 _('use old-style discovery with non-heads included')),
1550 ] + remoteopts,
1550 ] + remoteopts,
1551 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1551 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1552 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1552 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1553 """runs the changeset discovery protocol in isolation"""
1553 """runs the changeset discovery protocol in isolation"""
1554 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1554 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1555 remote = hg.peer(repo, opts, remoteurl)
1555 remote = hg.peer(repo, opts, remoteurl)
1556 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1556 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1557
1557
1558 # make sure tests are repeatable
1558 # make sure tests are repeatable
1559 random.seed(12323)
1559 random.seed(12323)
1560
1560
1561 def doit(localheads, remoteheads):
1561 def doit(localheads, remoteheads):
1562 if opts.get('old'):
1562 if opts.get('old'):
1563 if localheads:
1563 if localheads:
1564 raise util.Abort('cannot use localheads with old style discovery')
1564 raise util.Abort('cannot use localheads with old style discovery')
1565 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1565 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1566 force=True)
1566 force=True)
1567 common = set(common)
1567 common = set(common)
1568 if not opts.get('nonheads'):
1568 if not opts.get('nonheads'):
1569 ui.write("unpruned common: %s\n" % " ".join([short(n)
1569 ui.write("unpruned common: %s\n" % " ".join([short(n)
1570 for n in common]))
1570 for n in common]))
1571 dag = dagutil.revlogdag(repo.changelog)
1571 dag = dagutil.revlogdag(repo.changelog)
1572 all = dag.ancestorset(dag.internalizeall(common))
1572 all = dag.ancestorset(dag.internalizeall(common))
1573 common = dag.externalizeall(dag.headsetofconnecteds(all))
1573 common = dag.externalizeall(dag.headsetofconnecteds(all))
1574 else:
1574 else:
1575 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1575 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1576 common = set(common)
1576 common = set(common)
1577 rheads = set(hds)
1577 rheads = set(hds)
1578 lheads = set(repo.heads())
1578 lheads = set(repo.heads())
1579 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1579 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1580 if lheads <= common:
1580 if lheads <= common:
1581 ui.write("local is subset\n")
1581 ui.write("local is subset\n")
1582 elif rheads <= common:
1582 elif rheads <= common:
1583 ui.write("remote is subset\n")
1583 ui.write("remote is subset\n")
1584
1584
1585 serverlogs = opts.get('serverlog')
1585 serverlogs = opts.get('serverlog')
1586 if serverlogs:
1586 if serverlogs:
1587 for filename in serverlogs:
1587 for filename in serverlogs:
1588 logfile = open(filename, 'r')
1588 logfile = open(filename, 'r')
1589 try:
1589 try:
1590 line = logfile.readline()
1590 line = logfile.readline()
1591 while line:
1591 while line:
1592 parts = line.strip().split(';')
1592 parts = line.strip().split(';')
1593 op = parts[1]
1593 op = parts[1]
1594 if op == 'cg':
1594 if op == 'cg':
1595 pass
1595 pass
1596 elif op == 'cgss':
1596 elif op == 'cgss':
1597 doit(parts[2].split(' '), parts[3].split(' '))
1597 doit(parts[2].split(' '), parts[3].split(' '))
1598 elif op == 'unb':
1598 elif op == 'unb':
1599 doit(parts[3].split(' '), parts[2].split(' '))
1599 doit(parts[3].split(' '), parts[2].split(' '))
1600 line = logfile.readline()
1600 line = logfile.readline()
1601 finally:
1601 finally:
1602 logfile.close()
1602 logfile.close()
1603
1603
1604 else:
1604 else:
1605 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1605 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1606 opts.get('remote_head'))
1606 opts.get('remote_head'))
1607 localrevs = opts.get('local_head')
1607 localrevs = opts.get('local_head')
1608 doit(localrevs, remoterevs)
1608 doit(localrevs, remoterevs)
1609
1609
1610 @command('debugfileset', [], ('REVSPEC'))
1610 @command('debugfileset', [], ('REVSPEC'))
1611 def debugfileset(ui, repo, expr):
1611 def debugfileset(ui, repo, expr):
1612 '''parse and apply a fileset specification'''
1612 '''parse and apply a fileset specification'''
1613 if ui.verbose:
1613 if ui.verbose:
1614 tree = fileset.parse(expr)[0]
1614 tree = fileset.parse(expr)[0]
1615 ui.note(tree, "\n")
1615 ui.note(tree, "\n")
1616
1616
1617 for f in fileset.getfileset(repo[None], expr):
1617 for f in fileset.getfileset(repo[None], expr):
1618 ui.write("%s\n" % f)
1618 ui.write("%s\n" % f)
1619
1619
1620 @command('debugfsinfo', [], _('[PATH]'))
1620 @command('debugfsinfo', [], _('[PATH]'))
1621 def debugfsinfo(ui, path = "."):
1621 def debugfsinfo(ui, path = "."):
1622 """show information detected about current filesystem"""
1622 """show information detected about current filesystem"""
1623 util.writefile('.debugfsinfo', '')
1623 util.writefile('.debugfsinfo', '')
1624 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1624 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1625 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1625 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1626 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1626 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1627 and 'yes' or 'no'))
1627 and 'yes' or 'no'))
1628 os.unlink('.debugfsinfo')
1628 os.unlink('.debugfsinfo')
1629
1629
1630 @command('debuggetbundle',
1630 @command('debuggetbundle',
1631 [('H', 'head', [], _('id of head node'), _('ID')),
1631 [('H', 'head', [], _('id of head node'), _('ID')),
1632 ('C', 'common', [], _('id of common node'), _('ID')),
1632 ('C', 'common', [], _('id of common node'), _('ID')),
1633 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1633 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1634 _('REPO FILE [-H|-C ID]...'))
1634 _('REPO FILE [-H|-C ID]...'))
1635 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1635 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1636 """retrieves a bundle from a repo
1636 """retrieves a bundle from a repo
1637
1637
1638 Every ID must be a full-length hex node id string. Saves the bundle to the
1638 Every ID must be a full-length hex node id string. Saves the bundle to the
1639 given file.
1639 given file.
1640 """
1640 """
1641 repo = hg.peer(ui, opts, repopath)
1641 repo = hg.peer(ui, opts, repopath)
1642 if not repo.capable('getbundle'):
1642 if not repo.capable('getbundle'):
1643 raise util.Abort("getbundle() not supported by target repository")
1643 raise util.Abort("getbundle() not supported by target repository")
1644 args = {}
1644 args = {}
1645 if common:
1645 if common:
1646 args['common'] = [bin(s) for s in common]
1646 args['common'] = [bin(s) for s in common]
1647 if head:
1647 if head:
1648 args['heads'] = [bin(s) for s in head]
1648 args['heads'] = [bin(s) for s in head]
1649 bundle = repo.getbundle('debug', **args)
1649 bundle = repo.getbundle('debug', **args)
1650
1650
1651 bundletype = opts.get('type', 'bzip2').lower()
1651 bundletype = opts.get('type', 'bzip2').lower()
1652 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1652 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1653 bundletype = btypes.get(bundletype)
1653 bundletype = btypes.get(bundletype)
1654 if bundletype not in changegroup.bundletypes:
1654 if bundletype not in changegroup.bundletypes:
1655 raise util.Abort(_('unknown bundle type specified with --type'))
1655 raise util.Abort(_('unknown bundle type specified with --type'))
1656 changegroup.writebundle(bundle, bundlepath, bundletype)
1656 changegroup.writebundle(bundle, bundlepath, bundletype)
1657
1657
1658 @command('debugignore', [], '')
1658 @command('debugignore', [], '')
1659 def debugignore(ui, repo, *values, **opts):
1659 def debugignore(ui, repo, *values, **opts):
1660 """display the combined ignore pattern"""
1660 """display the combined ignore pattern"""
1661 ignore = repo.dirstate._ignore
1661 ignore = repo.dirstate._ignore
1662 includepat = getattr(ignore, 'includepat', None)
1662 includepat = getattr(ignore, 'includepat', None)
1663 if includepat is not None:
1663 if includepat is not None:
1664 ui.write("%s\n" % includepat)
1664 ui.write("%s\n" % includepat)
1665 else:
1665 else:
1666 raise util.Abort(_("no ignore patterns found"))
1666 raise util.Abort(_("no ignore patterns found"))
1667
1667
1668 @command('debugindex',
1668 @command('debugindex',
1669 [('c', 'changelog', False, _('open changelog')),
1669 [('c', 'changelog', False, _('open changelog')),
1670 ('m', 'manifest', False, _('open manifest')),
1670 ('m', 'manifest', False, _('open manifest')),
1671 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1671 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1672 _('[-f FORMAT] -c|-m|FILE'))
1672 _('[-f FORMAT] -c|-m|FILE'))
1673 def debugindex(ui, repo, file_ = None, **opts):
1673 def debugindex(ui, repo, file_ = None, **opts):
1674 """dump the contents of an index file"""
1674 """dump the contents of an index file"""
1675 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1675 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1676 format = opts.get('format', 0)
1676 format = opts.get('format', 0)
1677 if format not in (0, 1):
1677 if format not in (0, 1):
1678 raise util.Abort(_("unknown format %d") % format)
1678 raise util.Abort(_("unknown format %d") % format)
1679
1679
1680 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1680 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1681 if generaldelta:
1681 if generaldelta:
1682 basehdr = ' delta'
1682 basehdr = ' delta'
1683 else:
1683 else:
1684 basehdr = ' base'
1684 basehdr = ' base'
1685
1685
1686 if format == 0:
1686 if format == 0:
1687 ui.write(" rev offset length " + basehdr + " linkrev"
1687 ui.write(" rev offset length " + basehdr + " linkrev"
1688 " nodeid p1 p2\n")
1688 " nodeid p1 p2\n")
1689 elif format == 1:
1689 elif format == 1:
1690 ui.write(" rev flag offset length"
1690 ui.write(" rev flag offset length"
1691 " size " + basehdr + " link p1 p2 nodeid\n")
1691 " size " + basehdr + " link p1 p2 nodeid\n")
1692
1692
1693 for i in r:
1693 for i in r:
1694 node = r.node(i)
1694 node = r.node(i)
1695 if generaldelta:
1695 if generaldelta:
1696 base = r.deltaparent(i)
1696 base = r.deltaparent(i)
1697 else:
1697 else:
1698 base = r.chainbase(i)
1698 base = r.chainbase(i)
1699 if format == 0:
1699 if format == 0:
1700 try:
1700 try:
1701 pp = r.parents(node)
1701 pp = r.parents(node)
1702 except:
1702 except:
1703 pp = [nullid, nullid]
1703 pp = [nullid, nullid]
1704 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1704 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1705 i, r.start(i), r.length(i), base, r.linkrev(i),
1705 i, r.start(i), r.length(i), base, r.linkrev(i),
1706 short(node), short(pp[0]), short(pp[1])))
1706 short(node), short(pp[0]), short(pp[1])))
1707 elif format == 1:
1707 elif format == 1:
1708 pr = r.parentrevs(i)
1708 pr = r.parentrevs(i)
1709 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1709 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1710 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1710 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1711 base, r.linkrev(i), pr[0], pr[1], short(node)))
1711 base, r.linkrev(i), pr[0], pr[1], short(node)))
1712
1712
1713 @command('debugindexdot', [], _('FILE'))
1713 @command('debugindexdot', [], _('FILE'))
1714 def debugindexdot(ui, repo, file_):
1714 def debugindexdot(ui, repo, file_):
1715 """dump an index DAG as a graphviz dot file"""
1715 """dump an index DAG as a graphviz dot file"""
1716 r = None
1716 r = None
1717 if repo:
1717 if repo:
1718 filelog = repo.file(file_)
1718 filelog = repo.file(file_)
1719 if len(filelog):
1719 if len(filelog):
1720 r = filelog
1720 r = filelog
1721 if not r:
1721 if not r:
1722 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1722 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1723 ui.write("digraph G {\n")
1723 ui.write("digraph G {\n")
1724 for i in r:
1724 for i in r:
1725 node = r.node(i)
1725 node = r.node(i)
1726 pp = r.parents(node)
1726 pp = r.parents(node)
1727 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1727 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1728 if pp[1] != nullid:
1728 if pp[1] != nullid:
1729 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1729 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1730 ui.write("}\n")
1730 ui.write("}\n")
1731
1731
1732 @command('debuginstall', [], '')
1732 @command('debuginstall', [], '')
1733 def debuginstall(ui):
1733 def debuginstall(ui):
1734 '''test Mercurial installation
1734 '''test Mercurial installation
1735
1735
1736 Returns 0 on success.
1736 Returns 0 on success.
1737 '''
1737 '''
1738
1738
1739 def writetemp(contents):
1739 def writetemp(contents):
1740 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1740 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1741 f = os.fdopen(fd, "wb")
1741 f = os.fdopen(fd, "wb")
1742 f.write(contents)
1742 f.write(contents)
1743 f.close()
1743 f.close()
1744 return name
1744 return name
1745
1745
1746 problems = 0
1746 problems = 0
1747
1747
1748 # encoding
1748 # encoding
1749 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1749 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1750 try:
1750 try:
1751 encoding.fromlocal("test")
1751 encoding.fromlocal("test")
1752 except util.Abort, inst:
1752 except util.Abort, inst:
1753 ui.write(" %s\n" % inst)
1753 ui.write(" %s\n" % inst)
1754 ui.write(_(" (check that your locale is properly set)\n"))
1754 ui.write(_(" (check that your locale is properly set)\n"))
1755 problems += 1
1755 problems += 1
1756
1756
1757 # compiled modules
1757 # compiled modules
1758 ui.status(_("Checking installed modules (%s)...\n")
1758 ui.status(_("Checking installed modules (%s)...\n")
1759 % os.path.dirname(__file__))
1759 % os.path.dirname(__file__))
1760 try:
1760 try:
1761 import bdiff, mpatch, base85, osutil
1761 import bdiff, mpatch, base85, osutil
1762 except Exception, inst:
1762 except Exception, inst:
1763 ui.write(" %s\n" % inst)
1763 ui.write(" %s\n" % inst)
1764 ui.write(_(" One or more extensions could not be found"))
1764 ui.write(_(" One or more extensions could not be found"))
1765 ui.write(_(" (check that you compiled the extensions)\n"))
1765 ui.write(_(" (check that you compiled the extensions)\n"))
1766 problems += 1
1766 problems += 1
1767
1767
1768 # templates
1768 # templates
1769 ui.status(_("Checking templates...\n"))
1769 ui.status(_("Checking templates...\n"))
1770 try:
1770 try:
1771 import templater
1771 import templater
1772 templater.templater(templater.templatepath("map-cmdline.default"))
1772 templater.templater(templater.templatepath("map-cmdline.default"))
1773 except Exception, inst:
1773 except Exception, inst:
1774 ui.write(" %s\n" % inst)
1774 ui.write(" %s\n" % inst)
1775 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1775 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1776 problems += 1
1776 problems += 1
1777
1777
1778 # editor
1778 # editor
1779 ui.status(_("Checking commit editor...\n"))
1779 ui.status(_("Checking commit editor...\n"))
1780 editor = ui.geteditor()
1780 editor = ui.geteditor()
1781 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1781 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1782 if not cmdpath:
1782 if not cmdpath:
1783 if editor == 'vi':
1783 if editor == 'vi':
1784 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1784 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1785 ui.write(_(" (specify a commit editor in your configuration"
1785 ui.write(_(" (specify a commit editor in your configuration"
1786 " file)\n"))
1786 " file)\n"))
1787 else:
1787 else:
1788 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1788 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1789 ui.write(_(" (specify a commit editor in your configuration"
1789 ui.write(_(" (specify a commit editor in your configuration"
1790 " file)\n"))
1790 " file)\n"))
1791 problems += 1
1791 problems += 1
1792
1792
1793 # check username
1793 # check username
1794 ui.status(_("Checking username...\n"))
1794 ui.status(_("Checking username...\n"))
1795 try:
1795 try:
1796 ui.username()
1796 ui.username()
1797 except util.Abort, e:
1797 except util.Abort, e:
1798 ui.write(" %s\n" % e)
1798 ui.write(" %s\n" % e)
1799 ui.write(_(" (specify a username in your configuration file)\n"))
1799 ui.write(_(" (specify a username in your configuration file)\n"))
1800 problems += 1
1800 problems += 1
1801
1801
1802 if not problems:
1802 if not problems:
1803 ui.status(_("No problems detected\n"))
1803 ui.status(_("No problems detected\n"))
1804 else:
1804 else:
1805 ui.write(_("%s problems detected,"
1805 ui.write(_("%s problems detected,"
1806 " please check your install!\n") % problems)
1806 " please check your install!\n") % problems)
1807
1807
1808 return problems
1808 return problems
1809
1809
1810 @command('debugknown', [], _('REPO ID...'))
1810 @command('debugknown', [], _('REPO ID...'))
1811 def debugknown(ui, repopath, *ids, **opts):
1811 def debugknown(ui, repopath, *ids, **opts):
1812 """test whether node ids are known to a repo
1812 """test whether node ids are known to a repo
1813
1813
1814 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1814 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1815 indicating unknown/known.
1815 indicating unknown/known.
1816 """
1816 """
1817 repo = hg.peer(ui, opts, repopath)
1817 repo = hg.peer(ui, opts, repopath)
1818 if not repo.capable('known'):
1818 if not repo.capable('known'):
1819 raise util.Abort("known() not supported by target repository")
1819 raise util.Abort("known() not supported by target repository")
1820 flags = repo.known([bin(s) for s in ids])
1820 flags = repo.known([bin(s) for s in ids])
1821 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1821 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1822
1822
1823 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1823 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1824 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1824 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1825 '''access the pushkey key/value protocol
1825 '''access the pushkey key/value protocol
1826
1826
1827 With two args, list the keys in the given namespace.
1827 With two args, list the keys in the given namespace.
1828
1828
1829 With five args, set a key to new if it currently is set to old.
1829 With five args, set a key to new if it currently is set to old.
1830 Reports success or failure.
1830 Reports success or failure.
1831 '''
1831 '''
1832
1832
1833 target = hg.peer(ui, {}, repopath)
1833 target = hg.peer(ui, {}, repopath)
1834 if keyinfo:
1834 if keyinfo:
1835 key, old, new = keyinfo
1835 key, old, new = keyinfo
1836 r = target.pushkey(namespace, key, old, new)
1836 r = target.pushkey(namespace, key, old, new)
1837 ui.status(str(r) + '\n')
1837 ui.status(str(r) + '\n')
1838 return not r
1838 return not r
1839 else:
1839 else:
1840 for k, v in target.listkeys(namespace).iteritems():
1840 for k, v in target.listkeys(namespace).iteritems():
1841 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1841 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1842 v.encode('string-escape')))
1842 v.encode('string-escape')))
1843
1843
1844 @command('debugrebuildstate',
1844 @command('debugrebuildstate',
1845 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1845 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1846 _('[-r REV] [REV]'))
1846 _('[-r REV] [REV]'))
1847 def debugrebuildstate(ui, repo, rev="tip"):
1847 def debugrebuildstate(ui, repo, rev="tip"):
1848 """rebuild the dirstate as it would look like for the given revision"""
1848 """rebuild the dirstate as it would look like for the given revision"""
1849 ctx = scmutil.revsingle(repo, rev)
1849 ctx = scmutil.revsingle(repo, rev)
1850 wlock = repo.wlock()
1850 wlock = repo.wlock()
1851 try:
1851 try:
1852 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1852 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1853 finally:
1853 finally:
1854 wlock.release()
1854 wlock.release()
1855
1855
1856 @command('debugrename',
1856 @command('debugrename',
1857 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1857 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1858 _('[-r REV] FILE'))
1858 _('[-r REV] FILE'))
1859 def debugrename(ui, repo, file1, *pats, **opts):
1859 def debugrename(ui, repo, file1, *pats, **opts):
1860 """dump rename information"""
1860 """dump rename information"""
1861
1861
1862 ctx = scmutil.revsingle(repo, opts.get('rev'))
1862 ctx = scmutil.revsingle(repo, opts.get('rev'))
1863 m = scmutil.match(ctx, (file1,) + pats, opts)
1863 m = scmutil.match(ctx, (file1,) + pats, opts)
1864 for abs in ctx.walk(m):
1864 for abs in ctx.walk(m):
1865 fctx = ctx[abs]
1865 fctx = ctx[abs]
1866 o = fctx.filelog().renamed(fctx.filenode())
1866 o = fctx.filelog().renamed(fctx.filenode())
1867 rel = m.rel(abs)
1867 rel = m.rel(abs)
1868 if o:
1868 if o:
1869 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1869 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1870 else:
1870 else:
1871 ui.write(_("%s not renamed\n") % rel)
1871 ui.write(_("%s not renamed\n") % rel)
1872
1872
1873 @command('debugrevlog',
1873 @command('debugrevlog',
1874 [('c', 'changelog', False, _('open changelog')),
1874 [('c', 'changelog', False, _('open changelog')),
1875 ('m', 'manifest', False, _('open manifest')),
1875 ('m', 'manifest', False, _('open manifest')),
1876 ('d', 'dump', False, _('dump index data'))],
1876 ('d', 'dump', False, _('dump index data'))],
1877 _('-c|-m|FILE'))
1877 _('-c|-m|FILE'))
1878 def debugrevlog(ui, repo, file_ = None, **opts):
1878 def debugrevlog(ui, repo, file_ = None, **opts):
1879 """show data and statistics about a revlog"""
1879 """show data and statistics about a revlog"""
1880 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1880 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1881
1881
1882 if opts.get("dump"):
1882 if opts.get("dump"):
1883 numrevs = len(r)
1883 numrevs = len(r)
1884 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1884 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1885 " rawsize totalsize compression heads\n")
1885 " rawsize totalsize compression heads\n")
1886 ts = 0
1886 ts = 0
1887 heads = set()
1887 heads = set()
1888 for rev in xrange(numrevs):
1888 for rev in xrange(numrevs):
1889 dbase = r.deltaparent(rev)
1889 dbase = r.deltaparent(rev)
1890 if dbase == -1:
1890 if dbase == -1:
1891 dbase = rev
1891 dbase = rev
1892 cbase = r.chainbase(rev)
1892 cbase = r.chainbase(rev)
1893 p1, p2 = r.parentrevs(rev)
1893 p1, p2 = r.parentrevs(rev)
1894 rs = r.rawsize(rev)
1894 rs = r.rawsize(rev)
1895 ts = ts + rs
1895 ts = ts + rs
1896 heads -= set(r.parentrevs(rev))
1896 heads -= set(r.parentrevs(rev))
1897 heads.add(rev)
1897 heads.add(rev)
1898 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1898 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1899 (rev, p1, p2, r.start(rev), r.end(rev),
1899 (rev, p1, p2, r.start(rev), r.end(rev),
1900 r.start(dbase), r.start(cbase),
1900 r.start(dbase), r.start(cbase),
1901 r.start(p1), r.start(p2),
1901 r.start(p1), r.start(p2),
1902 rs, ts, ts / r.end(rev), len(heads)))
1902 rs, ts, ts / r.end(rev), len(heads)))
1903 return 0
1903 return 0
1904
1904
1905 v = r.version
1905 v = r.version
1906 format = v & 0xFFFF
1906 format = v & 0xFFFF
1907 flags = []
1907 flags = []
1908 gdelta = False
1908 gdelta = False
1909 if v & revlog.REVLOGNGINLINEDATA:
1909 if v & revlog.REVLOGNGINLINEDATA:
1910 flags.append('inline')
1910 flags.append('inline')
1911 if v & revlog.REVLOGGENERALDELTA:
1911 if v & revlog.REVLOGGENERALDELTA:
1912 gdelta = True
1912 gdelta = True
1913 flags.append('generaldelta')
1913 flags.append('generaldelta')
1914 if not flags:
1914 if not flags:
1915 flags = ['(none)']
1915 flags = ['(none)']
1916
1916
1917 nummerges = 0
1917 nummerges = 0
1918 numfull = 0
1918 numfull = 0
1919 numprev = 0
1919 numprev = 0
1920 nump1 = 0
1920 nump1 = 0
1921 nump2 = 0
1921 nump2 = 0
1922 numother = 0
1922 numother = 0
1923 nump1prev = 0
1923 nump1prev = 0
1924 nump2prev = 0
1924 nump2prev = 0
1925 chainlengths = []
1925 chainlengths = []
1926
1926
1927 datasize = [None, 0, 0L]
1927 datasize = [None, 0, 0L]
1928 fullsize = [None, 0, 0L]
1928 fullsize = [None, 0, 0L]
1929 deltasize = [None, 0, 0L]
1929 deltasize = [None, 0, 0L]
1930
1930
1931 def addsize(size, l):
1931 def addsize(size, l):
1932 if l[0] is None or size < l[0]:
1932 if l[0] is None or size < l[0]:
1933 l[0] = size
1933 l[0] = size
1934 if size > l[1]:
1934 if size > l[1]:
1935 l[1] = size
1935 l[1] = size
1936 l[2] += size
1936 l[2] += size
1937
1937
1938 numrevs = len(r)
1938 numrevs = len(r)
1939 for rev in xrange(numrevs):
1939 for rev in xrange(numrevs):
1940 p1, p2 = r.parentrevs(rev)
1940 p1, p2 = r.parentrevs(rev)
1941 delta = r.deltaparent(rev)
1941 delta = r.deltaparent(rev)
1942 if format > 0:
1942 if format > 0:
1943 addsize(r.rawsize(rev), datasize)
1943 addsize(r.rawsize(rev), datasize)
1944 if p2 != nullrev:
1944 if p2 != nullrev:
1945 nummerges += 1
1945 nummerges += 1
1946 size = r.length(rev)
1946 size = r.length(rev)
1947 if delta == nullrev:
1947 if delta == nullrev:
1948 chainlengths.append(0)
1948 chainlengths.append(0)
1949 numfull += 1
1949 numfull += 1
1950 addsize(size, fullsize)
1950 addsize(size, fullsize)
1951 else:
1951 else:
1952 chainlengths.append(chainlengths[delta] + 1)
1952 chainlengths.append(chainlengths[delta] + 1)
1953 addsize(size, deltasize)
1953 addsize(size, deltasize)
1954 if delta == rev - 1:
1954 if delta == rev - 1:
1955 numprev += 1
1955 numprev += 1
1956 if delta == p1:
1956 if delta == p1:
1957 nump1prev += 1
1957 nump1prev += 1
1958 elif delta == p2:
1958 elif delta == p2:
1959 nump2prev += 1
1959 nump2prev += 1
1960 elif delta == p1:
1960 elif delta == p1:
1961 nump1 += 1
1961 nump1 += 1
1962 elif delta == p2:
1962 elif delta == p2:
1963 nump2 += 1
1963 nump2 += 1
1964 elif delta != nullrev:
1964 elif delta != nullrev:
1965 numother += 1
1965 numother += 1
1966
1966
1967 numdeltas = numrevs - numfull
1967 numdeltas = numrevs - numfull
1968 numoprev = numprev - nump1prev - nump2prev
1968 numoprev = numprev - nump1prev - nump2prev
1969 totalrawsize = datasize[2]
1969 totalrawsize = datasize[2]
1970 datasize[2] /= numrevs
1970 datasize[2] /= numrevs
1971 fulltotal = fullsize[2]
1971 fulltotal = fullsize[2]
1972 fullsize[2] /= numfull
1972 fullsize[2] /= numfull
1973 deltatotal = deltasize[2]
1973 deltatotal = deltasize[2]
1974 deltasize[2] /= numrevs - numfull
1974 deltasize[2] /= numrevs - numfull
1975 totalsize = fulltotal + deltatotal
1975 totalsize = fulltotal + deltatotal
1976 avgchainlen = sum(chainlengths) / numrevs
1976 avgchainlen = sum(chainlengths) / numrevs
1977 compratio = totalrawsize / totalsize
1977 compratio = totalrawsize / totalsize
1978
1978
1979 basedfmtstr = '%%%dd\n'
1979 basedfmtstr = '%%%dd\n'
1980 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1980 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1981
1981
1982 def dfmtstr(max):
1982 def dfmtstr(max):
1983 return basedfmtstr % len(str(max))
1983 return basedfmtstr % len(str(max))
1984 def pcfmtstr(max, padding=0):
1984 def pcfmtstr(max, padding=0):
1985 return basepcfmtstr % (len(str(max)), ' ' * padding)
1985 return basepcfmtstr % (len(str(max)), ' ' * padding)
1986
1986
1987 def pcfmt(value, total):
1987 def pcfmt(value, total):
1988 return (value, 100 * float(value) / total)
1988 return (value, 100 * float(value) / total)
1989
1989
1990 ui.write('format : %d\n' % format)
1990 ui.write('format : %d\n' % format)
1991 ui.write('flags : %s\n' % ', '.join(flags))
1991 ui.write('flags : %s\n' % ', '.join(flags))
1992
1992
1993 ui.write('\n')
1993 ui.write('\n')
1994 fmt = pcfmtstr(totalsize)
1994 fmt = pcfmtstr(totalsize)
1995 fmt2 = dfmtstr(totalsize)
1995 fmt2 = dfmtstr(totalsize)
1996 ui.write('revisions : ' + fmt2 % numrevs)
1996 ui.write('revisions : ' + fmt2 % numrevs)
1997 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
1997 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
1998 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
1998 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
1999 ui.write('revisions : ' + fmt2 % numrevs)
1999 ui.write('revisions : ' + fmt2 % numrevs)
2000 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2000 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2001 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2001 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2002 ui.write('revision size : ' + fmt2 % totalsize)
2002 ui.write('revision size : ' + fmt2 % totalsize)
2003 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2003 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2004 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2004 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2005
2005
2006 ui.write('\n')
2006 ui.write('\n')
2007 fmt = dfmtstr(max(avgchainlen, compratio))
2007 fmt = dfmtstr(max(avgchainlen, compratio))
2008 ui.write('avg chain length : ' + fmt % avgchainlen)
2008 ui.write('avg chain length : ' + fmt % avgchainlen)
2009 ui.write('compression ratio : ' + fmt % compratio)
2009 ui.write('compression ratio : ' + fmt % compratio)
2010
2010
2011 if format > 0:
2011 if format > 0:
2012 ui.write('\n')
2012 ui.write('\n')
2013 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2013 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2014 % tuple(datasize))
2014 % tuple(datasize))
2015 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2015 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2016 % tuple(fullsize))
2016 % tuple(fullsize))
2017 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2017 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2018 % tuple(deltasize))
2018 % tuple(deltasize))
2019
2019
2020 if numdeltas > 0:
2020 if numdeltas > 0:
2021 ui.write('\n')
2021 ui.write('\n')
2022 fmt = pcfmtstr(numdeltas)
2022 fmt = pcfmtstr(numdeltas)
2023 fmt2 = pcfmtstr(numdeltas, 4)
2023 fmt2 = pcfmtstr(numdeltas, 4)
2024 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2024 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2025 if numprev > 0:
2025 if numprev > 0:
2026 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2026 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2027 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2027 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2028 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2028 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2029 if gdelta:
2029 if gdelta:
2030 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2030 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2031 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2031 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2032 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2032 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2033
2033
2034 @command('debugrevspec', [], ('REVSPEC'))
2034 @command('debugrevspec', [], ('REVSPEC'))
2035 def debugrevspec(ui, repo, expr):
2035 def debugrevspec(ui, repo, expr):
2036 '''parse and apply a revision specification'''
2036 '''parse and apply a revision specification'''
2037 if ui.verbose:
2037 if ui.verbose:
2038 tree = revset.parse(expr)[0]
2038 tree = revset.parse(expr)[0]
2039 ui.note(tree, "\n")
2039 ui.note(tree, "\n")
2040 newtree = revset.findaliases(ui, tree)
2040 newtree = revset.findaliases(ui, tree)
2041 if newtree != tree:
2041 if newtree != tree:
2042 ui.note(newtree, "\n")
2042 ui.note(newtree, "\n")
2043 func = revset.match(ui, expr)
2043 func = revset.match(ui, expr)
2044 for c in func(repo, range(len(repo))):
2044 for c in func(repo, range(len(repo))):
2045 ui.write("%s\n" % c)
2045 ui.write("%s\n" % c)
2046
2046
2047 @command('debugsetparents', [], _('REV1 [REV2]'))
2047 @command('debugsetparents', [], _('REV1 [REV2]'))
2048 def debugsetparents(ui, repo, rev1, rev2=None):
2048 def debugsetparents(ui, repo, rev1, rev2=None):
2049 """manually set the parents of the current working directory
2049 """manually set the parents of the current working directory
2050
2050
2051 This is useful for writing repository conversion tools, but should
2051 This is useful for writing repository conversion tools, but should
2052 be used with care.
2052 be used with care.
2053
2053
2054 Returns 0 on success.
2054 Returns 0 on success.
2055 """
2055 """
2056
2056
2057 r1 = scmutil.revsingle(repo, rev1).node()
2057 r1 = scmutil.revsingle(repo, rev1).node()
2058 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2058 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2059
2059
2060 wlock = repo.wlock()
2060 wlock = repo.wlock()
2061 try:
2061 try:
2062 repo.dirstate.setparents(r1, r2)
2062 repo.dirstate.setparents(r1, r2)
2063 finally:
2063 finally:
2064 wlock.release()
2064 wlock.release()
2065
2065
2066 @command('debugstate',
2066 @command('debugstate',
2067 [('', 'nodates', None, _('do not display the saved mtime')),
2067 [('', 'nodates', None, _('do not display the saved mtime')),
2068 ('', 'datesort', None, _('sort by saved mtime'))],
2068 ('', 'datesort', None, _('sort by saved mtime'))],
2069 _('[OPTION]...'))
2069 _('[OPTION]...'))
2070 def debugstate(ui, repo, nodates=None, datesort=None):
2070 def debugstate(ui, repo, nodates=None, datesort=None):
2071 """show the contents of the current dirstate"""
2071 """show the contents of the current dirstate"""
2072 timestr = ""
2072 timestr = ""
2073 showdate = not nodates
2073 showdate = not nodates
2074 if datesort:
2074 if datesort:
2075 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2075 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2076 else:
2076 else:
2077 keyfunc = None # sort by filename
2077 keyfunc = None # sort by filename
2078 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2078 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2079 if showdate:
2079 if showdate:
2080 if ent[3] == -1:
2080 if ent[3] == -1:
2081 # Pad or slice to locale representation
2081 # Pad or slice to locale representation
2082 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2082 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2083 time.localtime(0)))
2083 time.localtime(0)))
2084 timestr = 'unset'
2084 timestr = 'unset'
2085 timestr = (timestr[:locale_len] +
2085 timestr = (timestr[:locale_len] +
2086 ' ' * (locale_len - len(timestr)))
2086 ' ' * (locale_len - len(timestr)))
2087 else:
2087 else:
2088 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2088 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2089 time.localtime(ent[3]))
2089 time.localtime(ent[3]))
2090 if ent[1] & 020000:
2090 if ent[1] & 020000:
2091 mode = 'lnk'
2091 mode = 'lnk'
2092 else:
2092 else:
2093 mode = '%3o' % (ent[1] & 0777)
2093 mode = '%3o' % (ent[1] & 0777)
2094 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2094 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2095 for f in repo.dirstate.copies():
2095 for f in repo.dirstate.copies():
2096 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2096 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2097
2097
2098 @command('debugsub',
2098 @command('debugsub',
2099 [('r', 'rev', '',
2099 [('r', 'rev', '',
2100 _('revision to check'), _('REV'))],
2100 _('revision to check'), _('REV'))],
2101 _('[-r REV] [REV]'))
2101 _('[-r REV] [REV]'))
2102 def debugsub(ui, repo, rev=None):
2102 def debugsub(ui, repo, rev=None):
2103 ctx = scmutil.revsingle(repo, rev, None)
2103 ctx = scmutil.revsingle(repo, rev, None)
2104 for k, v in sorted(ctx.substate.items()):
2104 for k, v in sorted(ctx.substate.items()):
2105 ui.write('path %s\n' % k)
2105 ui.write('path %s\n' % k)
2106 ui.write(' source %s\n' % v[0])
2106 ui.write(' source %s\n' % v[0])
2107 ui.write(' revision %s\n' % v[1])
2107 ui.write(' revision %s\n' % v[1])
2108
2108
2109 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2109 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2110 def debugwalk(ui, repo, *pats, **opts):
2110 def debugwalk(ui, repo, *pats, **opts):
2111 """show how files match on given patterns"""
2111 """show how files match on given patterns"""
2112 m = scmutil.match(repo[None], pats, opts)
2112 m = scmutil.match(repo[None], pats, opts)
2113 items = list(repo.walk(m))
2113 items = list(repo.walk(m))
2114 if not items:
2114 if not items:
2115 return
2115 return
2116 fmt = 'f %%-%ds %%-%ds %%s' % (
2116 fmt = 'f %%-%ds %%-%ds %%s' % (
2117 max([len(abs) for abs in items]),
2117 max([len(abs) for abs in items]),
2118 max([len(m.rel(abs)) for abs in items]))
2118 max([len(m.rel(abs)) for abs in items]))
2119 for abs in items:
2119 for abs in items:
2120 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2120 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2121 ui.write("%s\n" % line.rstrip())
2121 ui.write("%s\n" % line.rstrip())
2122
2122
2123 @command('debugwireargs',
2123 @command('debugwireargs',
2124 [('', 'three', '', 'three'),
2124 [('', 'three', '', 'three'),
2125 ('', 'four', '', 'four'),
2125 ('', 'four', '', 'four'),
2126 ('', 'five', '', 'five'),
2126 ('', 'five', '', 'five'),
2127 ] + remoteopts,
2127 ] + remoteopts,
2128 _('REPO [OPTIONS]... [ONE [TWO]]'))
2128 _('REPO [OPTIONS]... [ONE [TWO]]'))
2129 def debugwireargs(ui, repopath, *vals, **opts):
2129 def debugwireargs(ui, repopath, *vals, **opts):
2130 repo = hg.peer(ui, opts, repopath)
2130 repo = hg.peer(ui, opts, repopath)
2131 for opt in remoteopts:
2131 for opt in remoteopts:
2132 del opts[opt[1]]
2132 del opts[opt[1]]
2133 args = {}
2133 args = {}
2134 for k, v in opts.iteritems():
2134 for k, v in opts.iteritems():
2135 if v:
2135 if v:
2136 args[k] = v
2136 args[k] = v
2137 # run twice to check that we don't mess up the stream for the next command
2137 # run twice to check that we don't mess up the stream for the next command
2138 res1 = repo.debugwireargs(*vals, **args)
2138 res1 = repo.debugwireargs(*vals, **args)
2139 res2 = repo.debugwireargs(*vals, **args)
2139 res2 = repo.debugwireargs(*vals, **args)
2140 ui.write("%s\n" % res1)
2140 ui.write("%s\n" % res1)
2141 if res1 != res2:
2141 if res1 != res2:
2142 ui.warn("%s\n" % res2)
2142 ui.warn("%s\n" % res2)
2143
2143
2144 @command('^diff',
2144 @command('^diff',
2145 [('r', 'rev', [], _('revision'), _('REV')),
2145 [('r', 'rev', [], _('revision'), _('REV')),
2146 ('c', 'change', '', _('change made by revision'), _('REV'))
2146 ('c', 'change', '', _('change made by revision'), _('REV'))
2147 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2147 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2148 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2148 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2149 def diff(ui, repo, *pats, **opts):
2149 def diff(ui, repo, *pats, **opts):
2150 """diff repository (or selected files)
2150 """diff repository (or selected files)
2151
2151
2152 Show differences between revisions for the specified files.
2152 Show differences between revisions for the specified files.
2153
2153
2154 Differences between files are shown using the unified diff format.
2154 Differences between files are shown using the unified diff format.
2155
2155
2156 .. note::
2156 .. note::
2157 diff may generate unexpected results for merges, as it will
2157 diff may generate unexpected results for merges, as it will
2158 default to comparing against the working directory's first
2158 default to comparing against the working directory's first
2159 parent changeset if no revisions are specified.
2159 parent changeset if no revisions are specified.
2160
2160
2161 When two revision arguments are given, then changes are shown
2161 When two revision arguments are given, then changes are shown
2162 between those revisions. If only one revision is specified then
2162 between those revisions. If only one revision is specified then
2163 that revision is compared to the working directory, and, when no
2163 that revision is compared to the working directory, and, when no
2164 revisions are specified, the working directory files are compared
2164 revisions are specified, the working directory files are compared
2165 to its parent.
2165 to its parent.
2166
2166
2167 Alternatively you can specify -c/--change with a revision to see
2167 Alternatively you can specify -c/--change with a revision to see
2168 the changes in that changeset relative to its first parent.
2168 the changes in that changeset relative to its first parent.
2169
2169
2170 Without the -a/--text option, diff will avoid generating diffs of
2170 Without the -a/--text option, diff will avoid generating diffs of
2171 files it detects as binary. With -a, diff will generate a diff
2171 files it detects as binary. With -a, diff will generate a diff
2172 anyway, probably with undesirable results.
2172 anyway, probably with undesirable results.
2173
2173
2174 Use the -g/--git option to generate diffs in the git extended diff
2174 Use the -g/--git option to generate diffs in the git extended diff
2175 format. For more information, read :hg:`help diffs`.
2175 format. For more information, read :hg:`help diffs`.
2176
2176
2177 Returns 0 on success.
2177 Returns 0 on success.
2178 """
2178 """
2179
2179
2180 revs = opts.get('rev')
2180 revs = opts.get('rev')
2181 change = opts.get('change')
2181 change = opts.get('change')
2182 stat = opts.get('stat')
2182 stat = opts.get('stat')
2183 reverse = opts.get('reverse')
2183 reverse = opts.get('reverse')
2184
2184
2185 if revs and change:
2185 if revs and change:
2186 msg = _('cannot specify --rev and --change at the same time')
2186 msg = _('cannot specify --rev and --change at the same time')
2187 raise util.Abort(msg)
2187 raise util.Abort(msg)
2188 elif change:
2188 elif change:
2189 node2 = scmutil.revsingle(repo, change, None).node()
2189 node2 = scmutil.revsingle(repo, change, None).node()
2190 node1 = repo[node2].p1().node()
2190 node1 = repo[node2].p1().node()
2191 else:
2191 else:
2192 node1, node2 = scmutil.revpair(repo, revs)
2192 node1, node2 = scmutil.revpair(repo, revs)
2193
2193
2194 if reverse:
2194 if reverse:
2195 node1, node2 = node2, node1
2195 node1, node2 = node2, node1
2196
2196
2197 diffopts = patch.diffopts(ui, opts)
2197 diffopts = patch.diffopts(ui, opts)
2198 m = scmutil.match(repo[node2], pats, opts)
2198 m = scmutil.match(repo[node2], pats, opts)
2199 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2199 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2200 listsubrepos=opts.get('subrepos'))
2200 listsubrepos=opts.get('subrepos'))
2201
2201
2202 @command('^export',
2202 @command('^export',
2203 [('o', 'output', '',
2203 [('o', 'output', '',
2204 _('print output to file with formatted name'), _('FORMAT')),
2204 _('print output to file with formatted name'), _('FORMAT')),
2205 ('', 'switch-parent', None, _('diff against the second parent')),
2205 ('', 'switch-parent', None, _('diff against the second parent')),
2206 ('r', 'rev', [], _('revisions to export'), _('REV')),
2206 ('r', 'rev', [], _('revisions to export'), _('REV')),
2207 ] + diffopts,
2207 ] + diffopts,
2208 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2208 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2209 def export(ui, repo, *changesets, **opts):
2209 def export(ui, repo, *changesets, **opts):
2210 """dump the header and diffs for one or more changesets
2210 """dump the header and diffs for one or more changesets
2211
2211
2212 Print the changeset header and diffs for one or more revisions.
2212 Print the changeset header and diffs for one or more revisions.
2213
2213
2214 The information shown in the changeset header is: author, date,
2214 The information shown in the changeset header is: author, date,
2215 branch name (if non-default), changeset hash, parent(s) and commit
2215 branch name (if non-default), changeset hash, parent(s) and commit
2216 comment.
2216 comment.
2217
2217
2218 .. note::
2218 .. note::
2219 export may generate unexpected diff output for merge
2219 export may generate unexpected diff output for merge
2220 changesets, as it will compare the merge changeset against its
2220 changesets, as it will compare the merge changeset against its
2221 first parent only.
2221 first parent only.
2222
2222
2223 Output may be to a file, in which case the name of the file is
2223 Output may be to a file, in which case the name of the file is
2224 given using a format string. The formatting rules are as follows:
2224 given using a format string. The formatting rules are as follows:
2225
2225
2226 :``%%``: literal "%" character
2226 :``%%``: literal "%" character
2227 :``%H``: changeset hash (40 hexadecimal digits)
2227 :``%H``: changeset hash (40 hexadecimal digits)
2228 :``%N``: number of patches being generated
2228 :``%N``: number of patches being generated
2229 :``%R``: changeset revision number
2229 :``%R``: changeset revision number
2230 :``%b``: basename of the exporting repository
2230 :``%b``: basename of the exporting repository
2231 :``%h``: short-form changeset hash (12 hexadecimal digits)
2231 :``%h``: short-form changeset hash (12 hexadecimal digits)
2232 :``%m``: first line of the commit message (only alphanumeric characters)
2232 :``%n``: zero-padded sequence number, starting at 1
2233 :``%n``: zero-padded sequence number, starting at 1
2233 :``%r``: zero-padded changeset revision number
2234 :``%r``: zero-padded changeset revision number
2234
2235
2235 Without the -a/--text option, export will avoid generating diffs
2236 Without the -a/--text option, export will avoid generating diffs
2236 of files it detects as binary. With -a, export will generate a
2237 of files it detects as binary. With -a, export will generate a
2237 diff anyway, probably with undesirable results.
2238 diff anyway, probably with undesirable results.
2238
2239
2239 Use the -g/--git option to generate diffs in the git extended diff
2240 Use the -g/--git option to generate diffs in the git extended diff
2240 format. See :hg:`help diffs` for more information.
2241 format. See :hg:`help diffs` for more information.
2241
2242
2242 With the --switch-parent option, the diff will be against the
2243 With the --switch-parent option, the diff will be against the
2243 second parent. It can be useful to review a merge.
2244 second parent. It can be useful to review a merge.
2244
2245
2245 Returns 0 on success.
2246 Returns 0 on success.
2246 """
2247 """
2247 changesets += tuple(opts.get('rev', []))
2248 changesets += tuple(opts.get('rev', []))
2248 if not changesets:
2249 if not changesets:
2249 raise util.Abort(_("export requires at least one changeset"))
2250 raise util.Abort(_("export requires at least one changeset"))
2250 revs = scmutil.revrange(repo, changesets)
2251 revs = scmutil.revrange(repo, changesets)
2251 if len(revs) > 1:
2252 if len(revs) > 1:
2252 ui.note(_('exporting patches:\n'))
2253 ui.note(_('exporting patches:\n'))
2253 else:
2254 else:
2254 ui.note(_('exporting patch:\n'))
2255 ui.note(_('exporting patch:\n'))
2255 cmdutil.export(repo, revs, template=opts.get('output'),
2256 cmdutil.export(repo, revs, template=opts.get('output'),
2256 switch_parent=opts.get('switch_parent'),
2257 switch_parent=opts.get('switch_parent'),
2257 opts=patch.diffopts(ui, opts))
2258 opts=patch.diffopts(ui, opts))
2258
2259
2259 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2260 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2260 def forget(ui, repo, *pats, **opts):
2261 def forget(ui, repo, *pats, **opts):
2261 """forget the specified files on the next commit
2262 """forget the specified files on the next commit
2262
2263
2263 Mark the specified files so they will no longer be tracked
2264 Mark the specified files so they will no longer be tracked
2264 after the next commit.
2265 after the next commit.
2265
2266
2266 This only removes files from the current branch, not from the
2267 This only removes files from the current branch, not from the
2267 entire project history, and it does not delete them from the
2268 entire project history, and it does not delete them from the
2268 working directory.
2269 working directory.
2269
2270
2270 To undo a forget before the next commit, see :hg:`add`.
2271 To undo a forget before the next commit, see :hg:`add`.
2271
2272
2272 Returns 0 on success.
2273 Returns 0 on success.
2273 """
2274 """
2274
2275
2275 if not pats:
2276 if not pats:
2276 raise util.Abort(_('no files specified'))
2277 raise util.Abort(_('no files specified'))
2277
2278
2278 m = scmutil.match(repo[None], pats, opts)
2279 m = scmutil.match(repo[None], pats, opts)
2279 s = repo.status(match=m, clean=True)
2280 s = repo.status(match=m, clean=True)
2280 forget = sorted(s[0] + s[1] + s[3] + s[6])
2281 forget = sorted(s[0] + s[1] + s[3] + s[6])
2281 errs = 0
2282 errs = 0
2282
2283
2283 for f in m.files():
2284 for f in m.files():
2284 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2285 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2285 if os.path.exists(m.rel(f)):
2286 if os.path.exists(m.rel(f)):
2286 ui.warn(_('not removing %s: file is already untracked\n')
2287 ui.warn(_('not removing %s: file is already untracked\n')
2287 % m.rel(f))
2288 % m.rel(f))
2288 errs = 1
2289 errs = 1
2289
2290
2290 for f in forget:
2291 for f in forget:
2291 if ui.verbose or not m.exact(f):
2292 if ui.verbose or not m.exact(f):
2292 ui.status(_('removing %s\n') % m.rel(f))
2293 ui.status(_('removing %s\n') % m.rel(f))
2293
2294
2294 repo[None].forget(forget)
2295 repo[None].forget(forget)
2295 return errs
2296 return errs
2296
2297
2297 @command('grep',
2298 @command('grep',
2298 [('0', 'print0', None, _('end fields with NUL')),
2299 [('0', 'print0', None, _('end fields with NUL')),
2299 ('', 'all', None, _('print all revisions that match')),
2300 ('', 'all', None, _('print all revisions that match')),
2300 ('a', 'text', None, _('treat all files as text')),
2301 ('a', 'text', None, _('treat all files as text')),
2301 ('f', 'follow', None,
2302 ('f', 'follow', None,
2302 _('follow changeset history,'
2303 _('follow changeset history,'
2303 ' or file history across copies and renames')),
2304 ' or file history across copies and renames')),
2304 ('i', 'ignore-case', None, _('ignore case when matching')),
2305 ('i', 'ignore-case', None, _('ignore case when matching')),
2305 ('l', 'files-with-matches', None,
2306 ('l', 'files-with-matches', None,
2306 _('print only filenames and revisions that match')),
2307 _('print only filenames and revisions that match')),
2307 ('n', 'line-number', None, _('print matching line numbers')),
2308 ('n', 'line-number', None, _('print matching line numbers')),
2308 ('r', 'rev', [],
2309 ('r', 'rev', [],
2309 _('only search files changed within revision range'), _('REV')),
2310 _('only search files changed within revision range'), _('REV')),
2310 ('u', 'user', None, _('list the author (long with -v)')),
2311 ('u', 'user', None, _('list the author (long with -v)')),
2311 ('d', 'date', None, _('list the date (short with -q)')),
2312 ('d', 'date', None, _('list the date (short with -q)')),
2312 ] + walkopts,
2313 ] + walkopts,
2313 _('[OPTION]... PATTERN [FILE]...'))
2314 _('[OPTION]... PATTERN [FILE]...'))
2314 def grep(ui, repo, pattern, *pats, **opts):
2315 def grep(ui, repo, pattern, *pats, **opts):
2315 """search for a pattern in specified files and revisions
2316 """search for a pattern in specified files and revisions
2316
2317
2317 Search revisions of files for a regular expression.
2318 Search revisions of files for a regular expression.
2318
2319
2319 This command behaves differently than Unix grep. It only accepts
2320 This command behaves differently than Unix grep. It only accepts
2320 Python/Perl regexps. It searches repository history, not the
2321 Python/Perl regexps. It searches repository history, not the
2321 working directory. It always prints the revision number in which a
2322 working directory. It always prints the revision number in which a
2322 match appears.
2323 match appears.
2323
2324
2324 By default, grep only prints output for the first revision of a
2325 By default, grep only prints output for the first revision of a
2325 file in which it finds a match. To get it to print every revision
2326 file in which it finds a match. To get it to print every revision
2326 that contains a change in match status ("-" for a match that
2327 that contains a change in match status ("-" for a match that
2327 becomes a non-match, or "+" for a non-match that becomes a match),
2328 becomes a non-match, or "+" for a non-match that becomes a match),
2328 use the --all flag.
2329 use the --all flag.
2329
2330
2330 Returns 0 if a match is found, 1 otherwise.
2331 Returns 0 if a match is found, 1 otherwise.
2331 """
2332 """
2332 reflags = 0
2333 reflags = 0
2333 if opts.get('ignore_case'):
2334 if opts.get('ignore_case'):
2334 reflags |= re.I
2335 reflags |= re.I
2335 try:
2336 try:
2336 regexp = re.compile(pattern, reflags)
2337 regexp = re.compile(pattern, reflags)
2337 except re.error, inst:
2338 except re.error, inst:
2338 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2339 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2339 return 1
2340 return 1
2340 sep, eol = ':', '\n'
2341 sep, eol = ':', '\n'
2341 if opts.get('print0'):
2342 if opts.get('print0'):
2342 sep = eol = '\0'
2343 sep = eol = '\0'
2343
2344
2344 getfile = util.lrucachefunc(repo.file)
2345 getfile = util.lrucachefunc(repo.file)
2345
2346
2346 def matchlines(body):
2347 def matchlines(body):
2347 begin = 0
2348 begin = 0
2348 linenum = 0
2349 linenum = 0
2349 while True:
2350 while True:
2350 match = regexp.search(body, begin)
2351 match = regexp.search(body, begin)
2351 if not match:
2352 if not match:
2352 break
2353 break
2353 mstart, mend = match.span()
2354 mstart, mend = match.span()
2354 linenum += body.count('\n', begin, mstart) + 1
2355 linenum += body.count('\n', begin, mstart) + 1
2355 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2356 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2356 begin = body.find('\n', mend) + 1 or len(body)
2357 begin = body.find('\n', mend) + 1 or len(body)
2357 lend = begin - 1
2358 lend = begin - 1
2358 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2359 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2359
2360
2360 class linestate(object):
2361 class linestate(object):
2361 def __init__(self, line, linenum, colstart, colend):
2362 def __init__(self, line, linenum, colstart, colend):
2362 self.line = line
2363 self.line = line
2363 self.linenum = linenum
2364 self.linenum = linenum
2364 self.colstart = colstart
2365 self.colstart = colstart
2365 self.colend = colend
2366 self.colend = colend
2366
2367
2367 def __hash__(self):
2368 def __hash__(self):
2368 return hash((self.linenum, self.line))
2369 return hash((self.linenum, self.line))
2369
2370
2370 def __eq__(self, other):
2371 def __eq__(self, other):
2371 return self.line == other.line
2372 return self.line == other.line
2372
2373
2373 matches = {}
2374 matches = {}
2374 copies = {}
2375 copies = {}
2375 def grepbody(fn, rev, body):
2376 def grepbody(fn, rev, body):
2376 matches[rev].setdefault(fn, [])
2377 matches[rev].setdefault(fn, [])
2377 m = matches[rev][fn]
2378 m = matches[rev][fn]
2378 for lnum, cstart, cend, line in matchlines(body):
2379 for lnum, cstart, cend, line in matchlines(body):
2379 s = linestate(line, lnum, cstart, cend)
2380 s = linestate(line, lnum, cstart, cend)
2380 m.append(s)
2381 m.append(s)
2381
2382
2382 def difflinestates(a, b):
2383 def difflinestates(a, b):
2383 sm = difflib.SequenceMatcher(None, a, b)
2384 sm = difflib.SequenceMatcher(None, a, b)
2384 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2385 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2385 if tag == 'insert':
2386 if tag == 'insert':
2386 for i in xrange(blo, bhi):
2387 for i in xrange(blo, bhi):
2387 yield ('+', b[i])
2388 yield ('+', b[i])
2388 elif tag == 'delete':
2389 elif tag == 'delete':
2389 for i in xrange(alo, ahi):
2390 for i in xrange(alo, ahi):
2390 yield ('-', a[i])
2391 yield ('-', a[i])
2391 elif tag == 'replace':
2392 elif tag == 'replace':
2392 for i in xrange(alo, ahi):
2393 for i in xrange(alo, ahi):
2393 yield ('-', a[i])
2394 yield ('-', a[i])
2394 for i in xrange(blo, bhi):
2395 for i in xrange(blo, bhi):
2395 yield ('+', b[i])
2396 yield ('+', b[i])
2396
2397
2397 def display(fn, ctx, pstates, states):
2398 def display(fn, ctx, pstates, states):
2398 rev = ctx.rev()
2399 rev = ctx.rev()
2399 datefunc = ui.quiet and util.shortdate or util.datestr
2400 datefunc = ui.quiet and util.shortdate or util.datestr
2400 found = False
2401 found = False
2401 filerevmatches = {}
2402 filerevmatches = {}
2402 def binary():
2403 def binary():
2403 flog = getfile(fn)
2404 flog = getfile(fn)
2404 return util.binary(flog.read(ctx.filenode(fn)))
2405 return util.binary(flog.read(ctx.filenode(fn)))
2405
2406
2406 if opts.get('all'):
2407 if opts.get('all'):
2407 iter = difflinestates(pstates, states)
2408 iter = difflinestates(pstates, states)
2408 else:
2409 else:
2409 iter = [('', l) for l in states]
2410 iter = [('', l) for l in states]
2410 for change, l in iter:
2411 for change, l in iter:
2411 cols = [fn, str(rev)]
2412 cols = [fn, str(rev)]
2412 before, match, after = None, None, None
2413 before, match, after = None, None, None
2413 if opts.get('line_number'):
2414 if opts.get('line_number'):
2414 cols.append(str(l.linenum))
2415 cols.append(str(l.linenum))
2415 if opts.get('all'):
2416 if opts.get('all'):
2416 cols.append(change)
2417 cols.append(change)
2417 if opts.get('user'):
2418 if opts.get('user'):
2418 cols.append(ui.shortuser(ctx.user()))
2419 cols.append(ui.shortuser(ctx.user()))
2419 if opts.get('date'):
2420 if opts.get('date'):
2420 cols.append(datefunc(ctx.date()))
2421 cols.append(datefunc(ctx.date()))
2421 if opts.get('files_with_matches'):
2422 if opts.get('files_with_matches'):
2422 c = (fn, rev)
2423 c = (fn, rev)
2423 if c in filerevmatches:
2424 if c in filerevmatches:
2424 continue
2425 continue
2425 filerevmatches[c] = 1
2426 filerevmatches[c] = 1
2426 else:
2427 else:
2427 before = l.line[:l.colstart]
2428 before = l.line[:l.colstart]
2428 match = l.line[l.colstart:l.colend]
2429 match = l.line[l.colstart:l.colend]
2429 after = l.line[l.colend:]
2430 after = l.line[l.colend:]
2430 ui.write(sep.join(cols))
2431 ui.write(sep.join(cols))
2431 if before is not None:
2432 if before is not None:
2432 if not opts.get('text') and binary():
2433 if not opts.get('text') and binary():
2433 ui.write(sep + " Binary file matches")
2434 ui.write(sep + " Binary file matches")
2434 else:
2435 else:
2435 ui.write(sep + before)
2436 ui.write(sep + before)
2436 ui.write(match, label='grep.match')
2437 ui.write(match, label='grep.match')
2437 ui.write(after)
2438 ui.write(after)
2438 ui.write(eol)
2439 ui.write(eol)
2439 found = True
2440 found = True
2440 return found
2441 return found
2441
2442
2442 skip = {}
2443 skip = {}
2443 revfiles = {}
2444 revfiles = {}
2444 matchfn = scmutil.match(repo[None], pats, opts)
2445 matchfn = scmutil.match(repo[None], pats, opts)
2445 found = False
2446 found = False
2446 follow = opts.get('follow')
2447 follow = opts.get('follow')
2447
2448
2448 def prep(ctx, fns):
2449 def prep(ctx, fns):
2449 rev = ctx.rev()
2450 rev = ctx.rev()
2450 pctx = ctx.p1()
2451 pctx = ctx.p1()
2451 parent = pctx.rev()
2452 parent = pctx.rev()
2452 matches.setdefault(rev, {})
2453 matches.setdefault(rev, {})
2453 matches.setdefault(parent, {})
2454 matches.setdefault(parent, {})
2454 files = revfiles.setdefault(rev, [])
2455 files = revfiles.setdefault(rev, [])
2455 for fn in fns:
2456 for fn in fns:
2456 flog = getfile(fn)
2457 flog = getfile(fn)
2457 try:
2458 try:
2458 fnode = ctx.filenode(fn)
2459 fnode = ctx.filenode(fn)
2459 except error.LookupError:
2460 except error.LookupError:
2460 continue
2461 continue
2461
2462
2462 copied = flog.renamed(fnode)
2463 copied = flog.renamed(fnode)
2463 copy = follow and copied and copied[0]
2464 copy = follow and copied and copied[0]
2464 if copy:
2465 if copy:
2465 copies.setdefault(rev, {})[fn] = copy
2466 copies.setdefault(rev, {})[fn] = copy
2466 if fn in skip:
2467 if fn in skip:
2467 if copy:
2468 if copy:
2468 skip[copy] = True
2469 skip[copy] = True
2469 continue
2470 continue
2470 files.append(fn)
2471 files.append(fn)
2471
2472
2472 if fn not in matches[rev]:
2473 if fn not in matches[rev]:
2473 grepbody(fn, rev, flog.read(fnode))
2474 grepbody(fn, rev, flog.read(fnode))
2474
2475
2475 pfn = copy or fn
2476 pfn = copy or fn
2476 if pfn not in matches[parent]:
2477 if pfn not in matches[parent]:
2477 try:
2478 try:
2478 fnode = pctx.filenode(pfn)
2479 fnode = pctx.filenode(pfn)
2479 grepbody(pfn, parent, flog.read(fnode))
2480 grepbody(pfn, parent, flog.read(fnode))
2480 except error.LookupError:
2481 except error.LookupError:
2481 pass
2482 pass
2482
2483
2483 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2484 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2484 rev = ctx.rev()
2485 rev = ctx.rev()
2485 parent = ctx.p1().rev()
2486 parent = ctx.p1().rev()
2486 for fn in sorted(revfiles.get(rev, [])):
2487 for fn in sorted(revfiles.get(rev, [])):
2487 states = matches[rev][fn]
2488 states = matches[rev][fn]
2488 copy = copies.get(rev, {}).get(fn)
2489 copy = copies.get(rev, {}).get(fn)
2489 if fn in skip:
2490 if fn in skip:
2490 if copy:
2491 if copy:
2491 skip[copy] = True
2492 skip[copy] = True
2492 continue
2493 continue
2493 pstates = matches.get(parent, {}).get(copy or fn, [])
2494 pstates = matches.get(parent, {}).get(copy or fn, [])
2494 if pstates or states:
2495 if pstates or states:
2495 r = display(fn, ctx, pstates, states)
2496 r = display(fn, ctx, pstates, states)
2496 found = found or r
2497 found = found or r
2497 if r and not opts.get('all'):
2498 if r and not opts.get('all'):
2498 skip[fn] = True
2499 skip[fn] = True
2499 if copy:
2500 if copy:
2500 skip[copy] = True
2501 skip[copy] = True
2501 del matches[rev]
2502 del matches[rev]
2502 del revfiles[rev]
2503 del revfiles[rev]
2503
2504
2504 return not found
2505 return not found
2505
2506
2506 @command('heads',
2507 @command('heads',
2507 [('r', 'rev', '',
2508 [('r', 'rev', '',
2508 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2509 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2509 ('t', 'topo', False, _('show topological heads only')),
2510 ('t', 'topo', False, _('show topological heads only')),
2510 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2511 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2511 ('c', 'closed', False, _('show normal and closed branch heads')),
2512 ('c', 'closed', False, _('show normal and closed branch heads')),
2512 ] + templateopts,
2513 ] + templateopts,
2513 _('[-ac] [-r STARTREV] [REV]...'))
2514 _('[-ac] [-r STARTREV] [REV]...'))
2514 def heads(ui, repo, *branchrevs, **opts):
2515 def heads(ui, repo, *branchrevs, **opts):
2515 """show current repository heads or show branch heads
2516 """show current repository heads or show branch heads
2516
2517
2517 With no arguments, show all repository branch heads.
2518 With no arguments, show all repository branch heads.
2518
2519
2519 Repository "heads" are changesets with no child changesets. They are
2520 Repository "heads" are changesets with no child changesets. They are
2520 where development generally takes place and are the usual targets
2521 where development generally takes place and are the usual targets
2521 for update and merge operations. Branch heads are changesets that have
2522 for update and merge operations. Branch heads are changesets that have
2522 no child changeset on the same branch.
2523 no child changeset on the same branch.
2523
2524
2524 If one or more REVs are given, only branch heads on the branches
2525 If one or more REVs are given, only branch heads on the branches
2525 associated with the specified changesets are shown.
2526 associated with the specified changesets are shown.
2526
2527
2527 If -c/--closed is specified, also show branch heads marked closed
2528 If -c/--closed is specified, also show branch heads marked closed
2528 (see :hg:`commit --close-branch`).
2529 (see :hg:`commit --close-branch`).
2529
2530
2530 If STARTREV is specified, only those heads that are descendants of
2531 If STARTREV is specified, only those heads that are descendants of
2531 STARTREV will be displayed.
2532 STARTREV will be displayed.
2532
2533
2533 If -t/--topo is specified, named branch mechanics will be ignored and only
2534 If -t/--topo is specified, named branch mechanics will be ignored and only
2534 changesets without children will be shown.
2535 changesets without children will be shown.
2535
2536
2536 Returns 0 if matching heads are found, 1 if not.
2537 Returns 0 if matching heads are found, 1 if not.
2537 """
2538 """
2538
2539
2539 start = None
2540 start = None
2540 if 'rev' in opts:
2541 if 'rev' in opts:
2541 start = scmutil.revsingle(repo, opts['rev'], None).node()
2542 start = scmutil.revsingle(repo, opts['rev'], None).node()
2542
2543
2543 if opts.get('topo'):
2544 if opts.get('topo'):
2544 heads = [repo[h] for h in repo.heads(start)]
2545 heads = [repo[h] for h in repo.heads(start)]
2545 else:
2546 else:
2546 heads = []
2547 heads = []
2547 for branch in repo.branchmap():
2548 for branch in repo.branchmap():
2548 heads += repo.branchheads(branch, start, opts.get('closed'))
2549 heads += repo.branchheads(branch, start, opts.get('closed'))
2549 heads = [repo[h] for h in heads]
2550 heads = [repo[h] for h in heads]
2550
2551
2551 if branchrevs:
2552 if branchrevs:
2552 branches = set(repo[br].branch() for br in branchrevs)
2553 branches = set(repo[br].branch() for br in branchrevs)
2553 heads = [h for h in heads if h.branch() in branches]
2554 heads = [h for h in heads if h.branch() in branches]
2554
2555
2555 if opts.get('active') and branchrevs:
2556 if opts.get('active') and branchrevs:
2556 dagheads = repo.heads(start)
2557 dagheads = repo.heads(start)
2557 heads = [h for h in heads if h.node() in dagheads]
2558 heads = [h for h in heads if h.node() in dagheads]
2558
2559
2559 if branchrevs:
2560 if branchrevs:
2560 haveheads = set(h.branch() for h in heads)
2561 haveheads = set(h.branch() for h in heads)
2561 if branches - haveheads:
2562 if branches - haveheads:
2562 headless = ', '.join(b for b in branches - haveheads)
2563 headless = ', '.join(b for b in branches - haveheads)
2563 msg = _('no open branch heads found on branches %s')
2564 msg = _('no open branch heads found on branches %s')
2564 if opts.get('rev'):
2565 if opts.get('rev'):
2565 msg += _(' (started at %s)' % opts['rev'])
2566 msg += _(' (started at %s)' % opts['rev'])
2566 ui.warn((msg + '\n') % headless)
2567 ui.warn((msg + '\n') % headless)
2567
2568
2568 if not heads:
2569 if not heads:
2569 return 1
2570 return 1
2570
2571
2571 heads = sorted(heads, key=lambda x: -x.rev())
2572 heads = sorted(heads, key=lambda x: -x.rev())
2572 displayer = cmdutil.show_changeset(ui, repo, opts)
2573 displayer = cmdutil.show_changeset(ui, repo, opts)
2573 for ctx in heads:
2574 for ctx in heads:
2574 displayer.show(ctx)
2575 displayer.show(ctx)
2575 displayer.close()
2576 displayer.close()
2576
2577
2577 @command('help',
2578 @command('help',
2578 [('e', 'extension', None, _('show only help for extensions')),
2579 [('e', 'extension', None, _('show only help for extensions')),
2579 ('c', 'command', None, _('show only help for commands'))],
2580 ('c', 'command', None, _('show only help for commands'))],
2580 _('[-ec] [TOPIC]'))
2581 _('[-ec] [TOPIC]'))
2581 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True, **opts):
2582 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True, **opts):
2582 """show help for a given topic or a help overview
2583 """show help for a given topic or a help overview
2583
2584
2584 With no arguments, print a list of commands with short help messages.
2585 With no arguments, print a list of commands with short help messages.
2585
2586
2586 Given a topic, extension, or command name, print help for that
2587 Given a topic, extension, or command name, print help for that
2587 topic.
2588 topic.
2588
2589
2589 Returns 0 if successful.
2590 Returns 0 if successful.
2590 """
2591 """
2591 option_lists = []
2592 option_lists = []
2592 textwidth = min(ui.termwidth(), 80) - 2
2593 textwidth = min(ui.termwidth(), 80) - 2
2593
2594
2594 def addglobalopts(aliases):
2595 def addglobalopts(aliases):
2595 if ui.verbose:
2596 if ui.verbose:
2596 option_lists.append((_("global options:"), globalopts))
2597 option_lists.append((_("global options:"), globalopts))
2597 if name == 'shortlist':
2598 if name == 'shortlist':
2598 option_lists.append((_('use "hg help" for the full list '
2599 option_lists.append((_('use "hg help" for the full list '
2599 'of commands'), ()))
2600 'of commands'), ()))
2600 else:
2601 else:
2601 if name == 'shortlist':
2602 if name == 'shortlist':
2602 msg = _('use "hg help" for the full list of commands '
2603 msg = _('use "hg help" for the full list of commands '
2603 'or "hg -v" for details')
2604 'or "hg -v" for details')
2604 elif name and not full:
2605 elif name and not full:
2605 msg = _('use "hg help %s" to show the full help text' % name)
2606 msg = _('use "hg help %s" to show the full help text' % name)
2606 elif aliases:
2607 elif aliases:
2607 msg = _('use "hg -v help%s" to show builtin aliases and '
2608 msg = _('use "hg -v help%s" to show builtin aliases and '
2608 'global options') % (name and " " + name or "")
2609 'global options') % (name and " " + name or "")
2609 else:
2610 else:
2610 msg = _('use "hg -v help %s" to show global options') % name
2611 msg = _('use "hg -v help %s" to show global options') % name
2611 option_lists.append((msg, ()))
2612 option_lists.append((msg, ()))
2612
2613
2613 def helpcmd(name):
2614 def helpcmd(name):
2614 if with_version:
2615 if with_version:
2615 version_(ui)
2616 version_(ui)
2616 ui.write('\n')
2617 ui.write('\n')
2617
2618
2618 try:
2619 try:
2619 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2620 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2620 except error.AmbiguousCommand, inst:
2621 except error.AmbiguousCommand, inst:
2621 # py3k fix: except vars can't be used outside the scope of the
2622 # py3k fix: except vars can't be used outside the scope of the
2622 # except block, nor can be used inside a lambda. python issue4617
2623 # except block, nor can be used inside a lambda. python issue4617
2623 prefix = inst.args[0]
2624 prefix = inst.args[0]
2624 select = lambda c: c.lstrip('^').startswith(prefix)
2625 select = lambda c: c.lstrip('^').startswith(prefix)
2625 helplist(_('list of commands:\n\n'), select)
2626 helplist(_('list of commands:\n\n'), select)
2626 return
2627 return
2627
2628
2628 # check if it's an invalid alias and display its error if it is
2629 # check if it's an invalid alias and display its error if it is
2629 if getattr(entry[0], 'badalias', False):
2630 if getattr(entry[0], 'badalias', False):
2630 if not unknowncmd:
2631 if not unknowncmd:
2631 entry[0](ui)
2632 entry[0](ui)
2632 return
2633 return
2633
2634
2634 # synopsis
2635 # synopsis
2635 if len(entry) > 2:
2636 if len(entry) > 2:
2636 if entry[2].startswith('hg'):
2637 if entry[2].startswith('hg'):
2637 ui.write("%s\n" % entry[2])
2638 ui.write("%s\n" % entry[2])
2638 else:
2639 else:
2639 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2640 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2640 else:
2641 else:
2641 ui.write('hg %s\n' % aliases[0])
2642 ui.write('hg %s\n' % aliases[0])
2642
2643
2643 # aliases
2644 # aliases
2644 if full and not ui.quiet and len(aliases) > 1:
2645 if full and not ui.quiet and len(aliases) > 1:
2645 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2646 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2646
2647
2647 # description
2648 # description
2648 doc = gettext(entry[0].__doc__)
2649 doc = gettext(entry[0].__doc__)
2649 if not doc:
2650 if not doc:
2650 doc = _("(no help text available)")
2651 doc = _("(no help text available)")
2651 if util.safehasattr(entry[0], 'definition'): # aliased command
2652 if util.safehasattr(entry[0], 'definition'): # aliased command
2652 if entry[0].definition.startswith('!'): # shell alias
2653 if entry[0].definition.startswith('!'): # shell alias
2653 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2654 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2654 else:
2655 else:
2655 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2656 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2656 if ui.quiet or not full:
2657 if ui.quiet or not full:
2657 doc = doc.splitlines()[0]
2658 doc = doc.splitlines()[0]
2658 keep = ui.verbose and ['verbose'] or []
2659 keep = ui.verbose and ['verbose'] or []
2659 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2660 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2660 ui.write("\n%s\n" % formatted)
2661 ui.write("\n%s\n" % formatted)
2661 if pruned:
2662 if pruned:
2662 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2663 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2663
2664
2664 if not ui.quiet:
2665 if not ui.quiet:
2665 # options
2666 # options
2666 if entry[1]:
2667 if entry[1]:
2667 option_lists.append((_("options:\n"), entry[1]))
2668 option_lists.append((_("options:\n"), entry[1]))
2668
2669
2669 addglobalopts(False)
2670 addglobalopts(False)
2670
2671
2671 # check if this command shadows a non-trivial (multi-line)
2672 # check if this command shadows a non-trivial (multi-line)
2672 # extension help text
2673 # extension help text
2673 try:
2674 try:
2674 mod = extensions.find(name)
2675 mod = extensions.find(name)
2675 doc = gettext(mod.__doc__) or ''
2676 doc = gettext(mod.__doc__) or ''
2676 if '\n' in doc.strip():
2677 if '\n' in doc.strip():
2677 msg = _('use "hg help -e %s" to show help for '
2678 msg = _('use "hg help -e %s" to show help for '
2678 'the %s extension') % (name, name)
2679 'the %s extension') % (name, name)
2679 ui.write('\n%s\n' % msg)
2680 ui.write('\n%s\n' % msg)
2680 except KeyError:
2681 except KeyError:
2681 pass
2682 pass
2682
2683
2683 def helplist(header, select=None):
2684 def helplist(header, select=None):
2684 h = {}
2685 h = {}
2685 cmds = {}
2686 cmds = {}
2686 for c, e in table.iteritems():
2687 for c, e in table.iteritems():
2687 f = c.split("|", 1)[0]
2688 f = c.split("|", 1)[0]
2688 if select and not select(f):
2689 if select and not select(f):
2689 continue
2690 continue
2690 if (not select and name != 'shortlist' and
2691 if (not select and name != 'shortlist' and
2691 e[0].__module__ != __name__):
2692 e[0].__module__ != __name__):
2692 continue
2693 continue
2693 if name == "shortlist" and not f.startswith("^"):
2694 if name == "shortlist" and not f.startswith("^"):
2694 continue
2695 continue
2695 f = f.lstrip("^")
2696 f = f.lstrip("^")
2696 if not ui.debugflag and f.startswith("debug"):
2697 if not ui.debugflag and f.startswith("debug"):
2697 continue
2698 continue
2698 doc = e[0].__doc__
2699 doc = e[0].__doc__
2699 if doc and 'DEPRECATED' in doc and not ui.verbose:
2700 if doc and 'DEPRECATED' in doc and not ui.verbose:
2700 continue
2701 continue
2701 doc = gettext(doc)
2702 doc = gettext(doc)
2702 if not doc:
2703 if not doc:
2703 doc = _("(no help text available)")
2704 doc = _("(no help text available)")
2704 h[f] = doc.splitlines()[0].rstrip()
2705 h[f] = doc.splitlines()[0].rstrip()
2705 cmds[f] = c.lstrip("^")
2706 cmds[f] = c.lstrip("^")
2706
2707
2707 if not h:
2708 if not h:
2708 ui.status(_('no commands defined\n'))
2709 ui.status(_('no commands defined\n'))
2709 return
2710 return
2710
2711
2711 ui.status(header)
2712 ui.status(header)
2712 fns = sorted(h)
2713 fns = sorted(h)
2713 m = max(map(len, fns))
2714 m = max(map(len, fns))
2714 for f in fns:
2715 for f in fns:
2715 if ui.verbose:
2716 if ui.verbose:
2716 commands = cmds[f].replace("|",", ")
2717 commands = cmds[f].replace("|",", ")
2717 ui.write(" %s:\n %s\n"%(commands, h[f]))
2718 ui.write(" %s:\n %s\n"%(commands, h[f]))
2718 else:
2719 else:
2719 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2720 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2720 initindent=' %-*s ' % (m, f),
2721 initindent=' %-*s ' % (m, f),
2721 hangindent=' ' * (m + 4))))
2722 hangindent=' ' * (m + 4))))
2722
2723
2723 if not ui.quiet:
2724 if not ui.quiet:
2724 addglobalopts(True)
2725 addglobalopts(True)
2725
2726
2726 def helptopic(name):
2727 def helptopic(name):
2727 for names, header, doc in help.helptable:
2728 for names, header, doc in help.helptable:
2728 if name in names:
2729 if name in names:
2729 break
2730 break
2730 else:
2731 else:
2731 raise error.UnknownCommand(name)
2732 raise error.UnknownCommand(name)
2732
2733
2733 # description
2734 # description
2734 if not doc:
2735 if not doc:
2735 doc = _("(no help text available)")
2736 doc = _("(no help text available)")
2736 if util.safehasattr(doc, '__call__'):
2737 if util.safehasattr(doc, '__call__'):
2737 doc = doc()
2738 doc = doc()
2738
2739
2739 ui.write("%s\n\n" % header)
2740 ui.write("%s\n\n" % header)
2740 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2741 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2741 try:
2742 try:
2742 cmdutil.findcmd(name, table)
2743 cmdutil.findcmd(name, table)
2743 ui.write(_('\nuse "hg help -c %s" to see help for '
2744 ui.write(_('\nuse "hg help -c %s" to see help for '
2744 'the %s command\n') % (name, name))
2745 'the %s command\n') % (name, name))
2745 except error.UnknownCommand:
2746 except error.UnknownCommand:
2746 pass
2747 pass
2747
2748
2748 def helpext(name):
2749 def helpext(name):
2749 try:
2750 try:
2750 mod = extensions.find(name)
2751 mod = extensions.find(name)
2751 doc = gettext(mod.__doc__) or _('no help text available')
2752 doc = gettext(mod.__doc__) or _('no help text available')
2752 except KeyError:
2753 except KeyError:
2753 mod = None
2754 mod = None
2754 doc = extensions.disabledext(name)
2755 doc = extensions.disabledext(name)
2755 if not doc:
2756 if not doc:
2756 raise error.UnknownCommand(name)
2757 raise error.UnknownCommand(name)
2757
2758
2758 if '\n' not in doc:
2759 if '\n' not in doc:
2759 head, tail = doc, ""
2760 head, tail = doc, ""
2760 else:
2761 else:
2761 head, tail = doc.split('\n', 1)
2762 head, tail = doc.split('\n', 1)
2762 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2763 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2763 if tail:
2764 if tail:
2764 ui.write(minirst.format(tail, textwidth))
2765 ui.write(minirst.format(tail, textwidth))
2765 ui.status('\n\n')
2766 ui.status('\n\n')
2766
2767
2767 if mod:
2768 if mod:
2768 try:
2769 try:
2769 ct = mod.cmdtable
2770 ct = mod.cmdtable
2770 except AttributeError:
2771 except AttributeError:
2771 ct = {}
2772 ct = {}
2772 modcmds = set([c.split('|', 1)[0] for c in ct])
2773 modcmds = set([c.split('|', 1)[0] for c in ct])
2773 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2774 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2774 else:
2775 else:
2775 ui.write(_('use "hg help extensions" for information on enabling '
2776 ui.write(_('use "hg help extensions" for information on enabling '
2776 'extensions\n'))
2777 'extensions\n'))
2777
2778
2778 def helpextcmd(name):
2779 def helpextcmd(name):
2779 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2780 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2780 doc = gettext(mod.__doc__).splitlines()[0]
2781 doc = gettext(mod.__doc__).splitlines()[0]
2781
2782
2782 msg = help.listexts(_("'%s' is provided by the following "
2783 msg = help.listexts(_("'%s' is provided by the following "
2783 "extension:") % cmd, {ext: doc}, indent=4)
2784 "extension:") % cmd, {ext: doc}, indent=4)
2784 ui.write(minirst.format(msg, textwidth))
2785 ui.write(minirst.format(msg, textwidth))
2785 ui.write('\n\n')
2786 ui.write('\n\n')
2786 ui.write(_('use "hg help extensions" for information on enabling '
2787 ui.write(_('use "hg help extensions" for information on enabling '
2787 'extensions\n'))
2788 'extensions\n'))
2788
2789
2789 if name and name != 'shortlist':
2790 if name and name != 'shortlist':
2790 i = None
2791 i = None
2791 if unknowncmd:
2792 if unknowncmd:
2792 queries = (helpextcmd,)
2793 queries = (helpextcmd,)
2793 elif opts.get('extension'):
2794 elif opts.get('extension'):
2794 queries = (helpext,)
2795 queries = (helpext,)
2795 elif opts.get('command'):
2796 elif opts.get('command'):
2796 queries = (helpcmd,)
2797 queries = (helpcmd,)
2797 else:
2798 else:
2798 queries = (helptopic, helpcmd, helpext, helpextcmd)
2799 queries = (helptopic, helpcmd, helpext, helpextcmd)
2799 for f in queries:
2800 for f in queries:
2800 try:
2801 try:
2801 f(name)
2802 f(name)
2802 i = None
2803 i = None
2803 break
2804 break
2804 except error.UnknownCommand, inst:
2805 except error.UnknownCommand, inst:
2805 i = inst
2806 i = inst
2806 if i:
2807 if i:
2807 raise i
2808 raise i
2808
2809
2809 else:
2810 else:
2810 # program name
2811 # program name
2811 if ui.verbose or with_version:
2812 if ui.verbose or with_version:
2812 version_(ui)
2813 version_(ui)
2813 else:
2814 else:
2814 ui.status(_("Mercurial Distributed SCM\n"))
2815 ui.status(_("Mercurial Distributed SCM\n"))
2815 ui.status('\n')
2816 ui.status('\n')
2816
2817
2817 # list of commands
2818 # list of commands
2818 if name == "shortlist":
2819 if name == "shortlist":
2819 header = _('basic commands:\n\n')
2820 header = _('basic commands:\n\n')
2820 else:
2821 else:
2821 header = _('list of commands:\n\n')
2822 header = _('list of commands:\n\n')
2822
2823
2823 helplist(header)
2824 helplist(header)
2824 if name != 'shortlist':
2825 if name != 'shortlist':
2825 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2826 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2826 if text:
2827 if text:
2827 ui.write("\n%s\n" % minirst.format(text, textwidth))
2828 ui.write("\n%s\n" % minirst.format(text, textwidth))
2828
2829
2829 # list all option lists
2830 # list all option lists
2830 opt_output = []
2831 opt_output = []
2831 multioccur = False
2832 multioccur = False
2832 for title, options in option_lists:
2833 for title, options in option_lists:
2833 opt_output.append(("\n%s" % title, None))
2834 opt_output.append(("\n%s" % title, None))
2834 for option in options:
2835 for option in options:
2835 if len(option) == 5:
2836 if len(option) == 5:
2836 shortopt, longopt, default, desc, optlabel = option
2837 shortopt, longopt, default, desc, optlabel = option
2837 else:
2838 else:
2838 shortopt, longopt, default, desc = option
2839 shortopt, longopt, default, desc = option
2839 optlabel = _("VALUE") # default label
2840 optlabel = _("VALUE") # default label
2840
2841
2841 if _("DEPRECATED") in desc and not ui.verbose:
2842 if _("DEPRECATED") in desc and not ui.verbose:
2842 continue
2843 continue
2843 if isinstance(default, list):
2844 if isinstance(default, list):
2844 numqualifier = " %s [+]" % optlabel
2845 numqualifier = " %s [+]" % optlabel
2845 multioccur = True
2846 multioccur = True
2846 elif (default is not None) and not isinstance(default, bool):
2847 elif (default is not None) and not isinstance(default, bool):
2847 numqualifier = " %s" % optlabel
2848 numqualifier = " %s" % optlabel
2848 else:
2849 else:
2849 numqualifier = ""
2850 numqualifier = ""
2850 opt_output.append(("%2s%s" %
2851 opt_output.append(("%2s%s" %
2851 (shortopt and "-%s" % shortopt,
2852 (shortopt and "-%s" % shortopt,
2852 longopt and " --%s%s" %
2853 longopt and " --%s%s" %
2853 (longopt, numqualifier)),
2854 (longopt, numqualifier)),
2854 "%s%s" % (desc,
2855 "%s%s" % (desc,
2855 default
2856 default
2856 and _(" (default: %s)") % default
2857 and _(" (default: %s)") % default
2857 or "")))
2858 or "")))
2858 if multioccur:
2859 if multioccur:
2859 msg = _("\n[+] marked option can be specified multiple times")
2860 msg = _("\n[+] marked option can be specified multiple times")
2860 if ui.verbose and name != 'shortlist':
2861 if ui.verbose and name != 'shortlist':
2861 opt_output.append((msg, None))
2862 opt_output.append((msg, None))
2862 else:
2863 else:
2863 opt_output.insert(-1, (msg, None))
2864 opt_output.insert(-1, (msg, None))
2864
2865
2865 if not name:
2866 if not name:
2866 ui.write(_("\nadditional help topics:\n\n"))
2867 ui.write(_("\nadditional help topics:\n\n"))
2867 topics = []
2868 topics = []
2868 for names, header, doc in help.helptable:
2869 for names, header, doc in help.helptable:
2869 topics.append((sorted(names, key=len, reverse=True)[0], header))
2870 topics.append((sorted(names, key=len, reverse=True)[0], header))
2870 topics_len = max([len(s[0]) for s in topics])
2871 topics_len = max([len(s[0]) for s in topics])
2871 for t, desc in topics:
2872 for t, desc in topics:
2872 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2873 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2873
2874
2874 if opt_output:
2875 if opt_output:
2875 colwidth = encoding.colwidth
2876 colwidth = encoding.colwidth
2876 # normalize: (opt or message, desc or None, width of opt)
2877 # normalize: (opt or message, desc or None, width of opt)
2877 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2878 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2878 for opt, desc in opt_output]
2879 for opt, desc in opt_output]
2879 hanging = max([e[2] for e in entries])
2880 hanging = max([e[2] for e in entries])
2880 for opt, desc, width in entries:
2881 for opt, desc, width in entries:
2881 if desc:
2882 if desc:
2882 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2883 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2883 hangindent = ' ' * (hanging + 3)
2884 hangindent = ' ' * (hanging + 3)
2884 ui.write('%s\n' % (util.wrap(desc, textwidth,
2885 ui.write('%s\n' % (util.wrap(desc, textwidth,
2885 initindent=initindent,
2886 initindent=initindent,
2886 hangindent=hangindent)))
2887 hangindent=hangindent)))
2887 else:
2888 else:
2888 ui.write("%s\n" % opt)
2889 ui.write("%s\n" % opt)
2889
2890
2890 @command('identify|id',
2891 @command('identify|id',
2891 [('r', 'rev', '',
2892 [('r', 'rev', '',
2892 _('identify the specified revision'), _('REV')),
2893 _('identify the specified revision'), _('REV')),
2893 ('n', 'num', None, _('show local revision number')),
2894 ('n', 'num', None, _('show local revision number')),
2894 ('i', 'id', None, _('show global revision id')),
2895 ('i', 'id', None, _('show global revision id')),
2895 ('b', 'branch', None, _('show branch')),
2896 ('b', 'branch', None, _('show branch')),
2896 ('t', 'tags', None, _('show tags')),
2897 ('t', 'tags', None, _('show tags')),
2897 ('B', 'bookmarks', None, _('show bookmarks'))],
2898 ('B', 'bookmarks', None, _('show bookmarks'))],
2898 _('[-nibtB] [-r REV] [SOURCE]'))
2899 _('[-nibtB] [-r REV] [SOURCE]'))
2899 def identify(ui, repo, source=None, rev=None,
2900 def identify(ui, repo, source=None, rev=None,
2900 num=None, id=None, branch=None, tags=None, bookmarks=None):
2901 num=None, id=None, branch=None, tags=None, bookmarks=None):
2901 """identify the working copy or specified revision
2902 """identify the working copy or specified revision
2902
2903
2903 Print a summary identifying the repository state at REV using one or
2904 Print a summary identifying the repository state at REV using one or
2904 two parent hash identifiers, followed by a "+" if the working
2905 two parent hash identifiers, followed by a "+" if the working
2905 directory has uncommitted changes, the branch name (if not default),
2906 directory has uncommitted changes, the branch name (if not default),
2906 a list of tags, and a list of bookmarks.
2907 a list of tags, and a list of bookmarks.
2907
2908
2908 When REV is not given, print a summary of the current state of the
2909 When REV is not given, print a summary of the current state of the
2909 repository.
2910 repository.
2910
2911
2911 Specifying a path to a repository root or Mercurial bundle will
2912 Specifying a path to a repository root or Mercurial bundle will
2912 cause lookup to operate on that repository/bundle.
2913 cause lookup to operate on that repository/bundle.
2913
2914
2914 Returns 0 if successful.
2915 Returns 0 if successful.
2915 """
2916 """
2916
2917
2917 if not repo and not source:
2918 if not repo and not source:
2918 raise util.Abort(_("there is no Mercurial repository here "
2919 raise util.Abort(_("there is no Mercurial repository here "
2919 "(.hg not found)"))
2920 "(.hg not found)"))
2920
2921
2921 hexfunc = ui.debugflag and hex or short
2922 hexfunc = ui.debugflag and hex or short
2922 default = not (num or id or branch or tags or bookmarks)
2923 default = not (num or id or branch or tags or bookmarks)
2923 output = []
2924 output = []
2924 revs = []
2925 revs = []
2925
2926
2926 if source:
2927 if source:
2927 source, branches = hg.parseurl(ui.expandpath(source))
2928 source, branches = hg.parseurl(ui.expandpath(source))
2928 repo = hg.peer(ui, {}, source)
2929 repo = hg.peer(ui, {}, source)
2929 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2930 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2930
2931
2931 if not repo.local():
2932 if not repo.local():
2932 if num or branch or tags:
2933 if num or branch or tags:
2933 raise util.Abort(
2934 raise util.Abort(
2934 _("can't query remote revision number, branch, or tags"))
2935 _("can't query remote revision number, branch, or tags"))
2935 if not rev and revs:
2936 if not rev and revs:
2936 rev = revs[0]
2937 rev = revs[0]
2937 if not rev:
2938 if not rev:
2938 rev = "tip"
2939 rev = "tip"
2939
2940
2940 remoterev = repo.lookup(rev)
2941 remoterev = repo.lookup(rev)
2941 if default or id:
2942 if default or id:
2942 output = [hexfunc(remoterev)]
2943 output = [hexfunc(remoterev)]
2943
2944
2944 def getbms():
2945 def getbms():
2945 bms = []
2946 bms = []
2946
2947
2947 if 'bookmarks' in repo.listkeys('namespaces'):
2948 if 'bookmarks' in repo.listkeys('namespaces'):
2948 hexremoterev = hex(remoterev)
2949 hexremoterev = hex(remoterev)
2949 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2950 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2950 if bmr == hexremoterev]
2951 if bmr == hexremoterev]
2951
2952
2952 return bms
2953 return bms
2953
2954
2954 if bookmarks:
2955 if bookmarks:
2955 output.extend(getbms())
2956 output.extend(getbms())
2956 elif default and not ui.quiet:
2957 elif default and not ui.quiet:
2957 # multiple bookmarks for a single parent separated by '/'
2958 # multiple bookmarks for a single parent separated by '/'
2958 bm = '/'.join(getbms())
2959 bm = '/'.join(getbms())
2959 if bm:
2960 if bm:
2960 output.append(bm)
2961 output.append(bm)
2961 else:
2962 else:
2962 if not rev:
2963 if not rev:
2963 ctx = repo[None]
2964 ctx = repo[None]
2964 parents = ctx.parents()
2965 parents = ctx.parents()
2965 changed = ""
2966 changed = ""
2966 if default or id or num:
2967 if default or id or num:
2967 changed = util.any(repo.status()) and "+" or ""
2968 changed = util.any(repo.status()) and "+" or ""
2968 if default or id:
2969 if default or id:
2969 output = ["%s%s" %
2970 output = ["%s%s" %
2970 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2971 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2971 if num:
2972 if num:
2972 output.append("%s%s" %
2973 output.append("%s%s" %
2973 ('+'.join([str(p.rev()) for p in parents]), changed))
2974 ('+'.join([str(p.rev()) for p in parents]), changed))
2974 else:
2975 else:
2975 ctx = scmutil.revsingle(repo, rev)
2976 ctx = scmutil.revsingle(repo, rev)
2976 if default or id:
2977 if default or id:
2977 output = [hexfunc(ctx.node())]
2978 output = [hexfunc(ctx.node())]
2978 if num:
2979 if num:
2979 output.append(str(ctx.rev()))
2980 output.append(str(ctx.rev()))
2980
2981
2981 if default and not ui.quiet:
2982 if default and not ui.quiet:
2982 b = ctx.branch()
2983 b = ctx.branch()
2983 if b != 'default':
2984 if b != 'default':
2984 output.append("(%s)" % b)
2985 output.append("(%s)" % b)
2985
2986
2986 # multiple tags for a single parent separated by '/'
2987 # multiple tags for a single parent separated by '/'
2987 t = '/'.join(ctx.tags())
2988 t = '/'.join(ctx.tags())
2988 if t:
2989 if t:
2989 output.append(t)
2990 output.append(t)
2990
2991
2991 # multiple bookmarks for a single parent separated by '/'
2992 # multiple bookmarks for a single parent separated by '/'
2992 bm = '/'.join(ctx.bookmarks())
2993 bm = '/'.join(ctx.bookmarks())
2993 if bm:
2994 if bm:
2994 output.append(bm)
2995 output.append(bm)
2995 else:
2996 else:
2996 if branch:
2997 if branch:
2997 output.append(ctx.branch())
2998 output.append(ctx.branch())
2998
2999
2999 if tags:
3000 if tags:
3000 output.extend(ctx.tags())
3001 output.extend(ctx.tags())
3001
3002
3002 if bookmarks:
3003 if bookmarks:
3003 output.extend(ctx.bookmarks())
3004 output.extend(ctx.bookmarks())
3004
3005
3005 ui.write("%s\n" % ' '.join(output))
3006 ui.write("%s\n" % ' '.join(output))
3006
3007
3007 @command('import|patch',
3008 @command('import|patch',
3008 [('p', 'strip', 1,
3009 [('p', 'strip', 1,
3009 _('directory strip option for patch. This has the same '
3010 _('directory strip option for patch. This has the same '
3010 'meaning as the corresponding patch option'), _('NUM')),
3011 'meaning as the corresponding patch option'), _('NUM')),
3011 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3012 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3012 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3013 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3013 ('', 'no-commit', None,
3014 ('', 'no-commit', None,
3014 _("don't commit, just update the working directory")),
3015 _("don't commit, just update the working directory")),
3015 ('', 'bypass', None,
3016 ('', 'bypass', None,
3016 _("apply patch without touching the working directory")),
3017 _("apply patch without touching the working directory")),
3017 ('', 'exact', None,
3018 ('', 'exact', None,
3018 _('apply patch to the nodes from which it was generated')),
3019 _('apply patch to the nodes from which it was generated')),
3019 ('', 'import-branch', None,
3020 ('', 'import-branch', None,
3020 _('use any branch information in patch (implied by --exact)'))] +
3021 _('use any branch information in patch (implied by --exact)'))] +
3021 commitopts + commitopts2 + similarityopts,
3022 commitopts + commitopts2 + similarityopts,
3022 _('[OPTION]... PATCH...'))
3023 _('[OPTION]... PATCH...'))
3023 def import_(ui, repo, patch1, *patches, **opts):
3024 def import_(ui, repo, patch1, *patches, **opts):
3024 """import an ordered set of patches
3025 """import an ordered set of patches
3025
3026
3026 Import a list of patches and commit them individually (unless
3027 Import a list of patches and commit them individually (unless
3027 --no-commit is specified).
3028 --no-commit is specified).
3028
3029
3029 If there are outstanding changes in the working directory, import
3030 If there are outstanding changes in the working directory, import
3030 will abort unless given the -f/--force flag.
3031 will abort unless given the -f/--force flag.
3031
3032
3032 You can import a patch straight from a mail message. Even patches
3033 You can import a patch straight from a mail message. Even patches
3033 as attachments work (to use the body part, it must have type
3034 as attachments work (to use the body part, it must have type
3034 text/plain or text/x-patch). From and Subject headers of email
3035 text/plain or text/x-patch). From and Subject headers of email
3035 message are used as default committer and commit message. All
3036 message are used as default committer and commit message. All
3036 text/plain body parts before first diff are added to commit
3037 text/plain body parts before first diff are added to commit
3037 message.
3038 message.
3038
3039
3039 If the imported patch was generated by :hg:`export`, user and
3040 If the imported patch was generated by :hg:`export`, user and
3040 description from patch override values from message headers and
3041 description from patch override values from message headers and
3041 body. Values given on command line with -m/--message and -u/--user
3042 body. Values given on command line with -m/--message and -u/--user
3042 override these.
3043 override these.
3043
3044
3044 If --exact is specified, import will set the working directory to
3045 If --exact is specified, import will set the working directory to
3045 the parent of each patch before applying it, and will abort if the
3046 the parent of each patch before applying it, and will abort if the
3046 resulting changeset has a different ID than the one recorded in
3047 resulting changeset has a different ID than the one recorded in
3047 the patch. This may happen due to character set problems or other
3048 the patch. This may happen due to character set problems or other
3048 deficiencies in the text patch format.
3049 deficiencies in the text patch format.
3049
3050
3050 Use --bypass to apply and commit patches directly to the
3051 Use --bypass to apply and commit patches directly to the
3051 repository, not touching the working directory. Without --exact,
3052 repository, not touching the working directory. Without --exact,
3052 patches will be applied on top of the working directory parent
3053 patches will be applied on top of the working directory parent
3053 revision.
3054 revision.
3054
3055
3055 With -s/--similarity, hg will attempt to discover renames and
3056 With -s/--similarity, hg will attempt to discover renames and
3056 copies in the patch in the same way as 'addremove'.
3057 copies in the patch in the same way as 'addremove'.
3057
3058
3058 To read a patch from standard input, use "-" as the patch name. If
3059 To read a patch from standard input, use "-" as the patch name. If
3059 a URL is specified, the patch will be downloaded from it.
3060 a URL is specified, the patch will be downloaded from it.
3060 See :hg:`help dates` for a list of formats valid for -d/--date.
3061 See :hg:`help dates` for a list of formats valid for -d/--date.
3061
3062
3062 Returns 0 on success.
3063 Returns 0 on success.
3063 """
3064 """
3064 patches = (patch1,) + patches
3065 patches = (patch1,) + patches
3065
3066
3066 date = opts.get('date')
3067 date = opts.get('date')
3067 if date:
3068 if date:
3068 opts['date'] = util.parsedate(date)
3069 opts['date'] = util.parsedate(date)
3069
3070
3070 update = not opts.get('bypass')
3071 update = not opts.get('bypass')
3071 if not update and opts.get('no_commit'):
3072 if not update and opts.get('no_commit'):
3072 raise util.Abort(_('cannot use --no-commit with --bypass'))
3073 raise util.Abort(_('cannot use --no-commit with --bypass'))
3073 try:
3074 try:
3074 sim = float(opts.get('similarity') or 0)
3075 sim = float(opts.get('similarity') or 0)
3075 except ValueError:
3076 except ValueError:
3076 raise util.Abort(_('similarity must be a number'))
3077 raise util.Abort(_('similarity must be a number'))
3077 if sim < 0 or sim > 100:
3078 if sim < 0 or sim > 100:
3078 raise util.Abort(_('similarity must be between 0 and 100'))
3079 raise util.Abort(_('similarity must be between 0 and 100'))
3079 if sim and not update:
3080 if sim and not update:
3080 raise util.Abort(_('cannot use --similarity with --bypass'))
3081 raise util.Abort(_('cannot use --similarity with --bypass'))
3081
3082
3082 if (opts.get('exact') or not opts.get('force')) and update:
3083 if (opts.get('exact') or not opts.get('force')) and update:
3083 cmdutil.bailifchanged(repo)
3084 cmdutil.bailifchanged(repo)
3084
3085
3085 d = opts["base"]
3086 d = opts["base"]
3086 strip = opts["strip"]
3087 strip = opts["strip"]
3087 wlock = lock = None
3088 wlock = lock = None
3088 msgs = []
3089 msgs = []
3089
3090
3090 def checkexact(repo, n, nodeid):
3091 def checkexact(repo, n, nodeid):
3091 if opts.get('exact') and hex(n) != nodeid:
3092 if opts.get('exact') and hex(n) != nodeid:
3092 repo.rollback()
3093 repo.rollback()
3093 raise util.Abort(_('patch is damaged or loses information'))
3094 raise util.Abort(_('patch is damaged or loses information'))
3094
3095
3095 def tryone(ui, hunk, parents):
3096 def tryone(ui, hunk, parents):
3096 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3097 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3097 patch.extract(ui, hunk)
3098 patch.extract(ui, hunk)
3098
3099
3099 if not tmpname:
3100 if not tmpname:
3100 return None
3101 return None
3101 commitid = _('to working directory')
3102 commitid = _('to working directory')
3102
3103
3103 try:
3104 try:
3104 cmdline_message = cmdutil.logmessage(ui, opts)
3105 cmdline_message = cmdutil.logmessage(ui, opts)
3105 if cmdline_message:
3106 if cmdline_message:
3106 # pickup the cmdline msg
3107 # pickup the cmdline msg
3107 message = cmdline_message
3108 message = cmdline_message
3108 elif message:
3109 elif message:
3109 # pickup the patch msg
3110 # pickup the patch msg
3110 message = message.strip()
3111 message = message.strip()
3111 else:
3112 else:
3112 # launch the editor
3113 # launch the editor
3113 message = None
3114 message = None
3114 ui.debug('message:\n%s\n' % message)
3115 ui.debug('message:\n%s\n' % message)
3115
3116
3116 if len(parents) == 1:
3117 if len(parents) == 1:
3117 parents.append(repo[nullid])
3118 parents.append(repo[nullid])
3118 if opts.get('exact'):
3119 if opts.get('exact'):
3119 if not nodeid or not p1:
3120 if not nodeid or not p1:
3120 raise util.Abort(_('not a Mercurial patch'))
3121 raise util.Abort(_('not a Mercurial patch'))
3121 p1 = repo[p1]
3122 p1 = repo[p1]
3122 p2 = repo[p2 or nullid]
3123 p2 = repo[p2 or nullid]
3123 elif p2:
3124 elif p2:
3124 try:
3125 try:
3125 p1 = repo[p1]
3126 p1 = repo[p1]
3126 p2 = repo[p2]
3127 p2 = repo[p2]
3127 except error.RepoError:
3128 except error.RepoError:
3128 p1, p2 = parents
3129 p1, p2 = parents
3129 else:
3130 else:
3130 p1, p2 = parents
3131 p1, p2 = parents
3131
3132
3132 n = None
3133 n = None
3133 if update:
3134 if update:
3134 if opts.get('exact') and p1 != parents[0]:
3135 if opts.get('exact') and p1 != parents[0]:
3135 hg.clean(repo, p1.node())
3136 hg.clean(repo, p1.node())
3136 if p1 != parents[0] and p2 != parents[1]:
3137 if p1 != parents[0] and p2 != parents[1]:
3137 repo.dirstate.setparents(p1.node(), p2.node())
3138 repo.dirstate.setparents(p1.node(), p2.node())
3138
3139
3139 if opts.get('exact') or opts.get('import_branch'):
3140 if opts.get('exact') or opts.get('import_branch'):
3140 repo.dirstate.setbranch(branch or 'default')
3141 repo.dirstate.setbranch(branch or 'default')
3141
3142
3142 files = set()
3143 files = set()
3143 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3144 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3144 eolmode=None, similarity=sim / 100.0)
3145 eolmode=None, similarity=sim / 100.0)
3145 files = list(files)
3146 files = list(files)
3146 if opts.get('no_commit'):
3147 if opts.get('no_commit'):
3147 if message:
3148 if message:
3148 msgs.append(message)
3149 msgs.append(message)
3149 else:
3150 else:
3150 if opts.get('exact'):
3151 if opts.get('exact'):
3151 m = None
3152 m = None
3152 else:
3153 else:
3153 m = scmutil.matchfiles(repo, files or [])
3154 m = scmutil.matchfiles(repo, files or [])
3154 n = repo.commit(message, opts.get('user') or user,
3155 n = repo.commit(message, opts.get('user') or user,
3155 opts.get('date') or date, match=m,
3156 opts.get('date') or date, match=m,
3156 editor=cmdutil.commiteditor)
3157 editor=cmdutil.commiteditor)
3157 checkexact(repo, n, nodeid)
3158 checkexact(repo, n, nodeid)
3158 # Force a dirstate write so that the next transaction
3159 # Force a dirstate write so that the next transaction
3159 # backups an up-to-date file.
3160 # backups an up-to-date file.
3160 repo.dirstate.write()
3161 repo.dirstate.write()
3161 else:
3162 else:
3162 if opts.get('exact') or opts.get('import_branch'):
3163 if opts.get('exact') or opts.get('import_branch'):
3163 branch = branch or 'default'
3164 branch = branch or 'default'
3164 else:
3165 else:
3165 branch = p1.branch()
3166 branch = p1.branch()
3166 store = patch.filestore()
3167 store = patch.filestore()
3167 try:
3168 try:
3168 files = set()
3169 files = set()
3169 try:
3170 try:
3170 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3171 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3171 files, eolmode=None)
3172 files, eolmode=None)
3172 except patch.PatchError, e:
3173 except patch.PatchError, e:
3173 raise util.Abort(str(e))
3174 raise util.Abort(str(e))
3174 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3175 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3175 message,
3176 message,
3176 opts.get('user') or user,
3177 opts.get('user') or user,
3177 opts.get('date') or date,
3178 opts.get('date') or date,
3178 branch, files, store,
3179 branch, files, store,
3179 editor=cmdutil.commiteditor)
3180 editor=cmdutil.commiteditor)
3180 repo.savecommitmessage(memctx.description())
3181 repo.savecommitmessage(memctx.description())
3181 n = memctx.commit()
3182 n = memctx.commit()
3182 checkexact(repo, n, nodeid)
3183 checkexact(repo, n, nodeid)
3183 finally:
3184 finally:
3184 store.close()
3185 store.close()
3185 if n:
3186 if n:
3186 commitid = short(n)
3187 commitid = short(n)
3187 return commitid
3188 return commitid
3188 finally:
3189 finally:
3189 os.unlink(tmpname)
3190 os.unlink(tmpname)
3190
3191
3191 try:
3192 try:
3192 wlock = repo.wlock()
3193 wlock = repo.wlock()
3193 lock = repo.lock()
3194 lock = repo.lock()
3194 parents = repo.parents()
3195 parents = repo.parents()
3195 lastcommit = None
3196 lastcommit = None
3196 for p in patches:
3197 for p in patches:
3197 pf = os.path.join(d, p)
3198 pf = os.path.join(d, p)
3198
3199
3199 if pf == '-':
3200 if pf == '-':
3200 ui.status(_("applying patch from stdin\n"))
3201 ui.status(_("applying patch from stdin\n"))
3201 pf = ui.fin
3202 pf = ui.fin
3202 else:
3203 else:
3203 ui.status(_("applying %s\n") % p)
3204 ui.status(_("applying %s\n") % p)
3204 pf = url.open(ui, pf)
3205 pf = url.open(ui, pf)
3205
3206
3206 haspatch = False
3207 haspatch = False
3207 for hunk in patch.split(pf):
3208 for hunk in patch.split(pf):
3208 commitid = tryone(ui, hunk, parents)
3209 commitid = tryone(ui, hunk, parents)
3209 if commitid:
3210 if commitid:
3210 haspatch = True
3211 haspatch = True
3211 if lastcommit:
3212 if lastcommit:
3212 ui.status(_('applied %s\n') % lastcommit)
3213 ui.status(_('applied %s\n') % lastcommit)
3213 lastcommit = commitid
3214 lastcommit = commitid
3214 if update or opts.get('exact'):
3215 if update or opts.get('exact'):
3215 parents = repo.parents()
3216 parents = repo.parents()
3216 else:
3217 else:
3217 parents = [repo[commitid]]
3218 parents = [repo[commitid]]
3218
3219
3219 if not haspatch:
3220 if not haspatch:
3220 raise util.Abort(_('no diffs found'))
3221 raise util.Abort(_('no diffs found'))
3221
3222
3222 if msgs:
3223 if msgs:
3223 repo.savecommitmessage('\n* * *\n'.join(msgs))
3224 repo.savecommitmessage('\n* * *\n'.join(msgs))
3224 finally:
3225 finally:
3225 release(lock, wlock)
3226 release(lock, wlock)
3226
3227
3227 @command('incoming|in',
3228 @command('incoming|in',
3228 [('f', 'force', None,
3229 [('f', 'force', None,
3229 _('run even if remote repository is unrelated')),
3230 _('run even if remote repository is unrelated')),
3230 ('n', 'newest-first', None, _('show newest record first')),
3231 ('n', 'newest-first', None, _('show newest record first')),
3231 ('', 'bundle', '',
3232 ('', 'bundle', '',
3232 _('file to store the bundles into'), _('FILE')),
3233 _('file to store the bundles into'), _('FILE')),
3233 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3234 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3234 ('B', 'bookmarks', False, _("compare bookmarks")),
3235 ('B', 'bookmarks', False, _("compare bookmarks")),
3235 ('b', 'branch', [],
3236 ('b', 'branch', [],
3236 _('a specific branch you would like to pull'), _('BRANCH')),
3237 _('a specific branch you would like to pull'), _('BRANCH')),
3237 ] + logopts + remoteopts + subrepoopts,
3238 ] + logopts + remoteopts + subrepoopts,
3238 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3239 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3239 def incoming(ui, repo, source="default", **opts):
3240 def incoming(ui, repo, source="default", **opts):
3240 """show new changesets found in source
3241 """show new changesets found in source
3241
3242
3242 Show new changesets found in the specified path/URL or the default
3243 Show new changesets found in the specified path/URL or the default
3243 pull location. These are the changesets that would have been pulled
3244 pull location. These are the changesets that would have been pulled
3244 if a pull at the time you issued this command.
3245 if a pull at the time you issued this command.
3245
3246
3246 For remote repository, using --bundle avoids downloading the
3247 For remote repository, using --bundle avoids downloading the
3247 changesets twice if the incoming is followed by a pull.
3248 changesets twice if the incoming is followed by a pull.
3248
3249
3249 See pull for valid source format details.
3250 See pull for valid source format details.
3250
3251
3251 Returns 0 if there are incoming changes, 1 otherwise.
3252 Returns 0 if there are incoming changes, 1 otherwise.
3252 """
3253 """
3253 if opts.get('bundle') and opts.get('subrepos'):
3254 if opts.get('bundle') and opts.get('subrepos'):
3254 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3255 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3255
3256
3256 if opts.get('bookmarks'):
3257 if opts.get('bookmarks'):
3257 source, branches = hg.parseurl(ui.expandpath(source),
3258 source, branches = hg.parseurl(ui.expandpath(source),
3258 opts.get('branch'))
3259 opts.get('branch'))
3259 other = hg.peer(repo, opts, source)
3260 other = hg.peer(repo, opts, source)
3260 if 'bookmarks' not in other.listkeys('namespaces'):
3261 if 'bookmarks' not in other.listkeys('namespaces'):
3261 ui.warn(_("remote doesn't support bookmarks\n"))
3262 ui.warn(_("remote doesn't support bookmarks\n"))
3262 return 0
3263 return 0
3263 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3264 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3264 return bookmarks.diff(ui, repo, other)
3265 return bookmarks.diff(ui, repo, other)
3265
3266
3266 repo._subtoppath = ui.expandpath(source)
3267 repo._subtoppath = ui.expandpath(source)
3267 try:
3268 try:
3268 return hg.incoming(ui, repo, source, opts)
3269 return hg.incoming(ui, repo, source, opts)
3269 finally:
3270 finally:
3270 del repo._subtoppath
3271 del repo._subtoppath
3271
3272
3272
3273
3273 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3274 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3274 def init(ui, dest=".", **opts):
3275 def init(ui, dest=".", **opts):
3275 """create a new repository in the given directory
3276 """create a new repository in the given directory
3276
3277
3277 Initialize a new repository in the given directory. If the given
3278 Initialize a new repository in the given directory. If the given
3278 directory does not exist, it will be created.
3279 directory does not exist, it will be created.
3279
3280
3280 If no directory is given, the current directory is used.
3281 If no directory is given, the current directory is used.
3281
3282
3282 It is possible to specify an ``ssh://`` URL as the destination.
3283 It is possible to specify an ``ssh://`` URL as the destination.
3283 See :hg:`help urls` for more information.
3284 See :hg:`help urls` for more information.
3284
3285
3285 Returns 0 on success.
3286 Returns 0 on success.
3286 """
3287 """
3287 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3288 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3288
3289
3289 @command('locate',
3290 @command('locate',
3290 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3291 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3291 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3292 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3292 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3293 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3293 ] + walkopts,
3294 ] + walkopts,
3294 _('[OPTION]... [PATTERN]...'))
3295 _('[OPTION]... [PATTERN]...'))
3295 def locate(ui, repo, *pats, **opts):
3296 def locate(ui, repo, *pats, **opts):
3296 """locate files matching specific patterns
3297 """locate files matching specific patterns
3297
3298
3298 Print files under Mercurial control in the working directory whose
3299 Print files under Mercurial control in the working directory whose
3299 names match the given patterns.
3300 names match the given patterns.
3300
3301
3301 By default, this command searches all directories in the working
3302 By default, this command searches all directories in the working
3302 directory. To search just the current directory and its
3303 directory. To search just the current directory and its
3303 subdirectories, use "--include .".
3304 subdirectories, use "--include .".
3304
3305
3305 If no patterns are given to match, this command prints the names
3306 If no patterns are given to match, this command prints the names
3306 of all files under Mercurial control in the working directory.
3307 of all files under Mercurial control in the working directory.
3307
3308
3308 If you want to feed the output of this command into the "xargs"
3309 If you want to feed the output of this command into the "xargs"
3309 command, use the -0 option to both this command and "xargs". This
3310 command, use the -0 option to both this command and "xargs". This
3310 will avoid the problem of "xargs" treating single filenames that
3311 will avoid the problem of "xargs" treating single filenames that
3311 contain whitespace as multiple filenames.
3312 contain whitespace as multiple filenames.
3312
3313
3313 Returns 0 if a match is found, 1 otherwise.
3314 Returns 0 if a match is found, 1 otherwise.
3314 """
3315 """
3315 end = opts.get('print0') and '\0' or '\n'
3316 end = opts.get('print0') and '\0' or '\n'
3316 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3317 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3317
3318
3318 ret = 1
3319 ret = 1
3319 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3320 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3320 m.bad = lambda x, y: False
3321 m.bad = lambda x, y: False
3321 for abs in repo[rev].walk(m):
3322 for abs in repo[rev].walk(m):
3322 if not rev and abs not in repo.dirstate:
3323 if not rev and abs not in repo.dirstate:
3323 continue
3324 continue
3324 if opts.get('fullpath'):
3325 if opts.get('fullpath'):
3325 ui.write(repo.wjoin(abs), end)
3326 ui.write(repo.wjoin(abs), end)
3326 else:
3327 else:
3327 ui.write(((pats and m.rel(abs)) or abs), end)
3328 ui.write(((pats and m.rel(abs)) or abs), end)
3328 ret = 0
3329 ret = 0
3329
3330
3330 return ret
3331 return ret
3331
3332
3332 @command('^log|history',
3333 @command('^log|history',
3333 [('f', 'follow', None,
3334 [('f', 'follow', None,
3334 _('follow changeset history, or file history across copies and renames')),
3335 _('follow changeset history, or file history across copies and renames')),
3335 ('', 'follow-first', None,
3336 ('', 'follow-first', None,
3336 _('only follow the first parent of merge changesets')),
3337 _('only follow the first parent of merge changesets')),
3337 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3338 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3338 ('C', 'copies', None, _('show copied files')),
3339 ('C', 'copies', None, _('show copied files')),
3339 ('k', 'keyword', [],
3340 ('k', 'keyword', [],
3340 _('do case-insensitive search for a given text'), _('TEXT')),
3341 _('do case-insensitive search for a given text'), _('TEXT')),
3341 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3342 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3342 ('', 'removed', None, _('include revisions where files were removed')),
3343 ('', 'removed', None, _('include revisions where files were removed')),
3343 ('m', 'only-merges', None, _('show only merges')),
3344 ('m', 'only-merges', None, _('show only merges')),
3344 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3345 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3345 ('', 'only-branch', [],
3346 ('', 'only-branch', [],
3346 _('show only changesets within the given named branch (DEPRECATED)'),
3347 _('show only changesets within the given named branch (DEPRECATED)'),
3347 _('BRANCH')),
3348 _('BRANCH')),
3348 ('b', 'branch', [],
3349 ('b', 'branch', [],
3349 _('show changesets within the given named branch'), _('BRANCH')),
3350 _('show changesets within the given named branch'), _('BRANCH')),
3350 ('P', 'prune', [],
3351 ('P', 'prune', [],
3351 _('do not display revision or any of its ancestors'), _('REV')),
3352 _('do not display revision or any of its ancestors'), _('REV')),
3352 ('h', 'hidden', False, _('show hidden changesets')),
3353 ('h', 'hidden', False, _('show hidden changesets')),
3353 ] + logopts + walkopts,
3354 ] + logopts + walkopts,
3354 _('[OPTION]... [FILE]'))
3355 _('[OPTION]... [FILE]'))
3355 def log(ui, repo, *pats, **opts):
3356 def log(ui, repo, *pats, **opts):
3356 """show revision history of entire repository or files
3357 """show revision history of entire repository or files
3357
3358
3358 Print the revision history of the specified files or the entire
3359 Print the revision history of the specified files or the entire
3359 project.
3360 project.
3360
3361
3361 File history is shown without following rename or copy history of
3362 File history is shown without following rename or copy history of
3362 files. Use -f/--follow with a filename to follow history across
3363 files. Use -f/--follow with a filename to follow history across
3363 renames and copies. --follow without a filename will only show
3364 renames and copies. --follow without a filename will only show
3364 ancestors or descendants of the starting revision. --follow-first
3365 ancestors or descendants of the starting revision. --follow-first
3365 only follows the first parent of merge revisions.
3366 only follows the first parent of merge revisions.
3366
3367
3367 If no revision range is specified, the default is ``tip:0`` unless
3368 If no revision range is specified, the default is ``tip:0`` unless
3368 --follow is set, in which case the working directory parent is
3369 --follow is set, in which case the working directory parent is
3369 used as the starting revision. You can specify a revision set for
3370 used as the starting revision. You can specify a revision set for
3370 log, see :hg:`help revsets` for more information.
3371 log, see :hg:`help revsets` for more information.
3371
3372
3372 See :hg:`help dates` for a list of formats valid for -d/--date.
3373 See :hg:`help dates` for a list of formats valid for -d/--date.
3373
3374
3374 By default this command prints revision number and changeset id,
3375 By default this command prints revision number and changeset id,
3375 tags, non-trivial parents, user, date and time, and a summary for
3376 tags, non-trivial parents, user, date and time, and a summary for
3376 each commit. When the -v/--verbose switch is used, the list of
3377 each commit. When the -v/--verbose switch is used, the list of
3377 changed files and full commit message are shown.
3378 changed files and full commit message are shown.
3378
3379
3379 .. note::
3380 .. note::
3380 log -p/--patch may generate unexpected diff output for merge
3381 log -p/--patch may generate unexpected diff output for merge
3381 changesets, as it will only compare the merge changeset against
3382 changesets, as it will only compare the merge changeset against
3382 its first parent. Also, only files different from BOTH parents
3383 its first parent. Also, only files different from BOTH parents
3383 will appear in files:.
3384 will appear in files:.
3384
3385
3385 Returns 0 on success.
3386 Returns 0 on success.
3386 """
3387 """
3387
3388
3388 matchfn = scmutil.match(repo[None], pats, opts)
3389 matchfn = scmutil.match(repo[None], pats, opts)
3389 limit = cmdutil.loglimit(opts)
3390 limit = cmdutil.loglimit(opts)
3390 count = 0
3391 count = 0
3391
3392
3392 endrev = None
3393 endrev = None
3393 if opts.get('copies') and opts.get('rev'):
3394 if opts.get('copies') and opts.get('rev'):
3394 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3395 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3395
3396
3396 df = False
3397 df = False
3397 if opts["date"]:
3398 if opts["date"]:
3398 df = util.matchdate(opts["date"])
3399 df = util.matchdate(opts["date"])
3399
3400
3400 branches = opts.get('branch', []) + opts.get('only_branch', [])
3401 branches = opts.get('branch', []) + opts.get('only_branch', [])
3401 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3402 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3402
3403
3403 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3404 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3404 def prep(ctx, fns):
3405 def prep(ctx, fns):
3405 rev = ctx.rev()
3406 rev = ctx.rev()
3406 parents = [p for p in repo.changelog.parentrevs(rev)
3407 parents = [p for p in repo.changelog.parentrevs(rev)
3407 if p != nullrev]
3408 if p != nullrev]
3408 if opts.get('no_merges') and len(parents) == 2:
3409 if opts.get('no_merges') and len(parents) == 2:
3409 return
3410 return
3410 if opts.get('only_merges') and len(parents) != 2:
3411 if opts.get('only_merges') and len(parents) != 2:
3411 return
3412 return
3412 if opts.get('branch') and ctx.branch() not in opts['branch']:
3413 if opts.get('branch') and ctx.branch() not in opts['branch']:
3413 return
3414 return
3414 if not opts.get('hidden') and ctx.hidden():
3415 if not opts.get('hidden') and ctx.hidden():
3415 return
3416 return
3416 if df and not df(ctx.date()[0]):
3417 if df and not df(ctx.date()[0]):
3417 return
3418 return
3418 if opts['user'] and not [k for k in opts['user']
3419 if opts['user'] and not [k for k in opts['user']
3419 if k.lower() in ctx.user().lower()]:
3420 if k.lower() in ctx.user().lower()]:
3420 return
3421 return
3421 if opts.get('keyword'):
3422 if opts.get('keyword'):
3422 for k in [kw.lower() for kw in opts['keyword']]:
3423 for k in [kw.lower() for kw in opts['keyword']]:
3423 if (k in ctx.user().lower() or
3424 if (k in ctx.user().lower() or
3424 k in ctx.description().lower() or
3425 k in ctx.description().lower() or
3425 k in " ".join(ctx.files()).lower()):
3426 k in " ".join(ctx.files()).lower()):
3426 break
3427 break
3427 else:
3428 else:
3428 return
3429 return
3429
3430
3430 copies = None
3431 copies = None
3431 if opts.get('copies') and rev:
3432 if opts.get('copies') and rev:
3432 copies = []
3433 copies = []
3433 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3434 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3434 for fn in ctx.files():
3435 for fn in ctx.files():
3435 rename = getrenamed(fn, rev)
3436 rename = getrenamed(fn, rev)
3436 if rename:
3437 if rename:
3437 copies.append((fn, rename[0]))
3438 copies.append((fn, rename[0]))
3438
3439
3439 revmatchfn = None
3440 revmatchfn = None
3440 if opts.get('patch') or opts.get('stat'):
3441 if opts.get('patch') or opts.get('stat'):
3441 if opts.get('follow') or opts.get('follow_first'):
3442 if opts.get('follow') or opts.get('follow_first'):
3442 # note: this might be wrong when following through merges
3443 # note: this might be wrong when following through merges
3443 revmatchfn = scmutil.match(repo[None], fns, default='path')
3444 revmatchfn = scmutil.match(repo[None], fns, default='path')
3444 else:
3445 else:
3445 revmatchfn = matchfn
3446 revmatchfn = matchfn
3446
3447
3447 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3448 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3448
3449
3449 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3450 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3450 if count == limit:
3451 if count == limit:
3451 break
3452 break
3452 if displayer.flush(ctx.rev()):
3453 if displayer.flush(ctx.rev()):
3453 count += 1
3454 count += 1
3454 displayer.close()
3455 displayer.close()
3455
3456
3456 @command('manifest',
3457 @command('manifest',
3457 [('r', 'rev', '', _('revision to display'), _('REV')),
3458 [('r', 'rev', '', _('revision to display'), _('REV')),
3458 ('', 'all', False, _("list files from all revisions"))],
3459 ('', 'all', False, _("list files from all revisions"))],
3459 _('[-r REV]'))
3460 _('[-r REV]'))
3460 def manifest(ui, repo, node=None, rev=None, **opts):
3461 def manifest(ui, repo, node=None, rev=None, **opts):
3461 """output the current or given revision of the project manifest
3462 """output the current or given revision of the project manifest
3462
3463
3463 Print a list of version controlled files for the given revision.
3464 Print a list of version controlled files for the given revision.
3464 If no revision is given, the first parent of the working directory
3465 If no revision is given, the first parent of the working directory
3465 is used, or the null revision if no revision is checked out.
3466 is used, or the null revision if no revision is checked out.
3466
3467
3467 With -v, print file permissions, symlink and executable bits.
3468 With -v, print file permissions, symlink and executable bits.
3468 With --debug, print file revision hashes.
3469 With --debug, print file revision hashes.
3469
3470
3470 If option --all is specified, the list of all files from all revisions
3471 If option --all is specified, the list of all files from all revisions
3471 is printed. This includes deleted and renamed files.
3472 is printed. This includes deleted and renamed files.
3472
3473
3473 Returns 0 on success.
3474 Returns 0 on success.
3474 """
3475 """
3475 if opts.get('all'):
3476 if opts.get('all'):
3476 if rev or node:
3477 if rev or node:
3477 raise util.Abort(_("can't specify a revision with --all"))
3478 raise util.Abort(_("can't specify a revision with --all"))
3478
3479
3479 res = []
3480 res = []
3480 prefix = "data/"
3481 prefix = "data/"
3481 suffix = ".i"
3482 suffix = ".i"
3482 plen = len(prefix)
3483 plen = len(prefix)
3483 slen = len(suffix)
3484 slen = len(suffix)
3484 lock = repo.lock()
3485 lock = repo.lock()
3485 try:
3486 try:
3486 for fn, b, size in repo.store.datafiles():
3487 for fn, b, size in repo.store.datafiles():
3487 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3488 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3488 res.append(fn[plen:-slen])
3489 res.append(fn[plen:-slen])
3489 finally:
3490 finally:
3490 lock.release()
3491 lock.release()
3491 for f in sorted(res):
3492 for f in sorted(res):
3492 ui.write("%s\n" % f)
3493 ui.write("%s\n" % f)
3493 return
3494 return
3494
3495
3495 if rev and node:
3496 if rev and node:
3496 raise util.Abort(_("please specify just one revision"))
3497 raise util.Abort(_("please specify just one revision"))
3497
3498
3498 if not node:
3499 if not node:
3499 node = rev
3500 node = rev
3500
3501
3501 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3502 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3502 ctx = scmutil.revsingle(repo, node)
3503 ctx = scmutil.revsingle(repo, node)
3503 for f in ctx:
3504 for f in ctx:
3504 if ui.debugflag:
3505 if ui.debugflag:
3505 ui.write("%40s " % hex(ctx.manifest()[f]))
3506 ui.write("%40s " % hex(ctx.manifest()[f]))
3506 if ui.verbose:
3507 if ui.verbose:
3507 ui.write(decor[ctx.flags(f)])
3508 ui.write(decor[ctx.flags(f)])
3508 ui.write("%s\n" % f)
3509 ui.write("%s\n" % f)
3509
3510
3510 @command('^merge',
3511 @command('^merge',
3511 [('f', 'force', None, _('force a merge with outstanding changes')),
3512 [('f', 'force', None, _('force a merge with outstanding changes')),
3512 ('r', 'rev', '', _('revision to merge'), _('REV')),
3513 ('r', 'rev', '', _('revision to merge'), _('REV')),
3513 ('P', 'preview', None,
3514 ('P', 'preview', None,
3514 _('review revisions to merge (no merge is performed)'))
3515 _('review revisions to merge (no merge is performed)'))
3515 ] + mergetoolopts,
3516 ] + mergetoolopts,
3516 _('[-P] [-f] [[-r] REV]'))
3517 _('[-P] [-f] [[-r] REV]'))
3517 def merge(ui, repo, node=None, **opts):
3518 def merge(ui, repo, node=None, **opts):
3518 """merge working directory with another revision
3519 """merge working directory with another revision
3519
3520
3520 The current working directory is updated with all changes made in
3521 The current working directory is updated with all changes made in
3521 the requested revision since the last common predecessor revision.
3522 the requested revision since the last common predecessor revision.
3522
3523
3523 Files that changed between either parent are marked as changed for
3524 Files that changed between either parent are marked as changed for
3524 the next commit and a commit must be performed before any further
3525 the next commit and a commit must be performed before any further
3525 updates to the repository are allowed. The next commit will have
3526 updates to the repository are allowed. The next commit will have
3526 two parents.
3527 two parents.
3527
3528
3528 ``--tool`` can be used to specify the merge tool used for file
3529 ``--tool`` can be used to specify the merge tool used for file
3529 merges. It overrides the HGMERGE environment variable and your
3530 merges. It overrides the HGMERGE environment variable and your
3530 configuration files. See :hg:`help merge-tools` for options.
3531 configuration files. See :hg:`help merge-tools` for options.
3531
3532
3532 If no revision is specified, the working directory's parent is a
3533 If no revision is specified, the working directory's parent is a
3533 head revision, and the current branch contains exactly one other
3534 head revision, and the current branch contains exactly one other
3534 head, the other head is merged with by default. Otherwise, an
3535 head, the other head is merged with by default. Otherwise, an
3535 explicit revision with which to merge with must be provided.
3536 explicit revision with which to merge with must be provided.
3536
3537
3537 :hg:`resolve` must be used to resolve unresolved files.
3538 :hg:`resolve` must be used to resolve unresolved files.
3538
3539
3539 To undo an uncommitted merge, use :hg:`update --clean .` which
3540 To undo an uncommitted merge, use :hg:`update --clean .` which
3540 will check out a clean copy of the original merge parent, losing
3541 will check out a clean copy of the original merge parent, losing
3541 all changes.
3542 all changes.
3542
3543
3543 Returns 0 on success, 1 if there are unresolved files.
3544 Returns 0 on success, 1 if there are unresolved files.
3544 """
3545 """
3545
3546
3546 if opts.get('rev') and node:
3547 if opts.get('rev') and node:
3547 raise util.Abort(_("please specify just one revision"))
3548 raise util.Abort(_("please specify just one revision"))
3548 if not node:
3549 if not node:
3549 node = opts.get('rev')
3550 node = opts.get('rev')
3550
3551
3551 if not node:
3552 if not node:
3552 branch = repo[None].branch()
3553 branch = repo[None].branch()
3553 bheads = repo.branchheads(branch)
3554 bheads = repo.branchheads(branch)
3554 if len(bheads) > 2:
3555 if len(bheads) > 2:
3555 raise util.Abort(_("branch '%s' has %d heads - "
3556 raise util.Abort(_("branch '%s' has %d heads - "
3556 "please merge with an explicit rev")
3557 "please merge with an explicit rev")
3557 % (branch, len(bheads)),
3558 % (branch, len(bheads)),
3558 hint=_("run 'hg heads .' to see heads"))
3559 hint=_("run 'hg heads .' to see heads"))
3559
3560
3560 parent = repo.dirstate.p1()
3561 parent = repo.dirstate.p1()
3561 if len(bheads) == 1:
3562 if len(bheads) == 1:
3562 if len(repo.heads()) > 1:
3563 if len(repo.heads()) > 1:
3563 raise util.Abort(_("branch '%s' has one head - "
3564 raise util.Abort(_("branch '%s' has one head - "
3564 "please merge with an explicit rev")
3565 "please merge with an explicit rev")
3565 % branch,
3566 % branch,
3566 hint=_("run 'hg heads' to see all heads"))
3567 hint=_("run 'hg heads' to see all heads"))
3567 msg = _('there is nothing to merge')
3568 msg = _('there is nothing to merge')
3568 if parent != repo.lookup(repo[None].branch()):
3569 if parent != repo.lookup(repo[None].branch()):
3569 msg = _('%s - use "hg update" instead') % msg
3570 msg = _('%s - use "hg update" instead') % msg
3570 raise util.Abort(msg)
3571 raise util.Abort(msg)
3571
3572
3572 if parent not in bheads:
3573 if parent not in bheads:
3573 raise util.Abort(_('working directory not at a head revision'),
3574 raise util.Abort(_('working directory not at a head revision'),
3574 hint=_("use 'hg update' or merge with an "
3575 hint=_("use 'hg update' or merge with an "
3575 "explicit revision"))
3576 "explicit revision"))
3576 node = parent == bheads[0] and bheads[-1] or bheads[0]
3577 node = parent == bheads[0] and bheads[-1] or bheads[0]
3577 else:
3578 else:
3578 node = scmutil.revsingle(repo, node).node()
3579 node = scmutil.revsingle(repo, node).node()
3579
3580
3580 if opts.get('preview'):
3581 if opts.get('preview'):
3581 # find nodes that are ancestors of p2 but not of p1
3582 # find nodes that are ancestors of p2 but not of p1
3582 p1 = repo.lookup('.')
3583 p1 = repo.lookup('.')
3583 p2 = repo.lookup(node)
3584 p2 = repo.lookup(node)
3584 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3585 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3585
3586
3586 displayer = cmdutil.show_changeset(ui, repo, opts)
3587 displayer = cmdutil.show_changeset(ui, repo, opts)
3587 for node in nodes:
3588 for node in nodes:
3588 displayer.show(repo[node])
3589 displayer.show(repo[node])
3589 displayer.close()
3590 displayer.close()
3590 return 0
3591 return 0
3591
3592
3592 try:
3593 try:
3593 # ui.forcemerge is an internal variable, do not document
3594 # ui.forcemerge is an internal variable, do not document
3594 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3595 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3595 return hg.merge(repo, node, force=opts.get('force'))
3596 return hg.merge(repo, node, force=opts.get('force'))
3596 finally:
3597 finally:
3597 ui.setconfig('ui', 'forcemerge', '')
3598 ui.setconfig('ui', 'forcemerge', '')
3598
3599
3599 @command('outgoing|out',
3600 @command('outgoing|out',
3600 [('f', 'force', None, _('run even when the destination is unrelated')),
3601 [('f', 'force', None, _('run even when the destination is unrelated')),
3601 ('r', 'rev', [],
3602 ('r', 'rev', [],
3602 _('a changeset intended to be included in the destination'), _('REV')),
3603 _('a changeset intended to be included in the destination'), _('REV')),
3603 ('n', 'newest-first', None, _('show newest record first')),
3604 ('n', 'newest-first', None, _('show newest record first')),
3604 ('B', 'bookmarks', False, _('compare bookmarks')),
3605 ('B', 'bookmarks', False, _('compare bookmarks')),
3605 ('b', 'branch', [], _('a specific branch you would like to push'),
3606 ('b', 'branch', [], _('a specific branch you would like to push'),
3606 _('BRANCH')),
3607 _('BRANCH')),
3607 ] + logopts + remoteopts + subrepoopts,
3608 ] + logopts + remoteopts + subrepoopts,
3608 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3609 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3609 def outgoing(ui, repo, dest=None, **opts):
3610 def outgoing(ui, repo, dest=None, **opts):
3610 """show changesets not found in the destination
3611 """show changesets not found in the destination
3611
3612
3612 Show changesets not found in the specified destination repository
3613 Show changesets not found in the specified destination repository
3613 or the default push location. These are the changesets that would
3614 or the default push location. These are the changesets that would
3614 be pushed if a push was requested.
3615 be pushed if a push was requested.
3615
3616
3616 See pull for details of valid destination formats.
3617 See pull for details of valid destination formats.
3617
3618
3618 Returns 0 if there are outgoing changes, 1 otherwise.
3619 Returns 0 if there are outgoing changes, 1 otherwise.
3619 """
3620 """
3620
3621
3621 if opts.get('bookmarks'):
3622 if opts.get('bookmarks'):
3622 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3623 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3623 dest, branches = hg.parseurl(dest, opts.get('branch'))
3624 dest, branches = hg.parseurl(dest, opts.get('branch'))
3624 other = hg.peer(repo, opts, dest)
3625 other = hg.peer(repo, opts, dest)
3625 if 'bookmarks' not in other.listkeys('namespaces'):
3626 if 'bookmarks' not in other.listkeys('namespaces'):
3626 ui.warn(_("remote doesn't support bookmarks\n"))
3627 ui.warn(_("remote doesn't support bookmarks\n"))
3627 return 0
3628 return 0
3628 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3629 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3629 return bookmarks.diff(ui, other, repo)
3630 return bookmarks.diff(ui, other, repo)
3630
3631
3631 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3632 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3632 try:
3633 try:
3633 return hg.outgoing(ui, repo, dest, opts)
3634 return hg.outgoing(ui, repo, dest, opts)
3634 finally:
3635 finally:
3635 del repo._subtoppath
3636 del repo._subtoppath
3636
3637
3637 @command('parents',
3638 @command('parents',
3638 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3639 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3639 ] + templateopts,
3640 ] + templateopts,
3640 _('[-r REV] [FILE]'))
3641 _('[-r REV] [FILE]'))
3641 def parents(ui, repo, file_=None, **opts):
3642 def parents(ui, repo, file_=None, **opts):
3642 """show the parents of the working directory or revision
3643 """show the parents of the working directory or revision
3643
3644
3644 Print the working directory's parent revisions. If a revision is
3645 Print the working directory's parent revisions. If a revision is
3645 given via -r/--rev, the parent of that revision will be printed.
3646 given via -r/--rev, the parent of that revision will be printed.
3646 If a file argument is given, the revision in which the file was
3647 If a file argument is given, the revision in which the file was
3647 last changed (before the working directory revision or the
3648 last changed (before the working directory revision or the
3648 argument to --rev if given) is printed.
3649 argument to --rev if given) is printed.
3649
3650
3650 Returns 0 on success.
3651 Returns 0 on success.
3651 """
3652 """
3652
3653
3653 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3654 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3654
3655
3655 if file_:
3656 if file_:
3656 m = scmutil.match(ctx, (file_,), opts)
3657 m = scmutil.match(ctx, (file_,), opts)
3657 if m.anypats() or len(m.files()) != 1:
3658 if m.anypats() or len(m.files()) != 1:
3658 raise util.Abort(_('can only specify an explicit filename'))
3659 raise util.Abort(_('can only specify an explicit filename'))
3659 file_ = m.files()[0]
3660 file_ = m.files()[0]
3660 filenodes = []
3661 filenodes = []
3661 for cp in ctx.parents():
3662 for cp in ctx.parents():
3662 if not cp:
3663 if not cp:
3663 continue
3664 continue
3664 try:
3665 try:
3665 filenodes.append(cp.filenode(file_))
3666 filenodes.append(cp.filenode(file_))
3666 except error.LookupError:
3667 except error.LookupError:
3667 pass
3668 pass
3668 if not filenodes:
3669 if not filenodes:
3669 raise util.Abort(_("'%s' not found in manifest!") % file_)
3670 raise util.Abort(_("'%s' not found in manifest!") % file_)
3670 fl = repo.file(file_)
3671 fl = repo.file(file_)
3671 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3672 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3672 else:
3673 else:
3673 p = [cp.node() for cp in ctx.parents()]
3674 p = [cp.node() for cp in ctx.parents()]
3674
3675
3675 displayer = cmdutil.show_changeset(ui, repo, opts)
3676 displayer = cmdutil.show_changeset(ui, repo, opts)
3676 for n in p:
3677 for n in p:
3677 if n != nullid:
3678 if n != nullid:
3678 displayer.show(repo[n])
3679 displayer.show(repo[n])
3679 displayer.close()
3680 displayer.close()
3680
3681
3681 @command('paths', [], _('[NAME]'))
3682 @command('paths', [], _('[NAME]'))
3682 def paths(ui, repo, search=None):
3683 def paths(ui, repo, search=None):
3683 """show aliases for remote repositories
3684 """show aliases for remote repositories
3684
3685
3685 Show definition of symbolic path name NAME. If no name is given,
3686 Show definition of symbolic path name NAME. If no name is given,
3686 show definition of all available names.
3687 show definition of all available names.
3687
3688
3688 Option -q/--quiet suppresses all output when searching for NAME
3689 Option -q/--quiet suppresses all output when searching for NAME
3689 and shows only the path names when listing all definitions.
3690 and shows only the path names when listing all definitions.
3690
3691
3691 Path names are defined in the [paths] section of your
3692 Path names are defined in the [paths] section of your
3692 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3693 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3693 repository, ``.hg/hgrc`` is used, too.
3694 repository, ``.hg/hgrc`` is used, too.
3694
3695
3695 The path names ``default`` and ``default-push`` have a special
3696 The path names ``default`` and ``default-push`` have a special
3696 meaning. When performing a push or pull operation, they are used
3697 meaning. When performing a push or pull operation, they are used
3697 as fallbacks if no location is specified on the command-line.
3698 as fallbacks if no location is specified on the command-line.
3698 When ``default-push`` is set, it will be used for push and
3699 When ``default-push`` is set, it will be used for push and
3699 ``default`` will be used for pull; otherwise ``default`` is used
3700 ``default`` will be used for pull; otherwise ``default`` is used
3700 as the fallback for both. When cloning a repository, the clone
3701 as the fallback for both. When cloning a repository, the clone
3701 source is written as ``default`` in ``.hg/hgrc``. Note that
3702 source is written as ``default`` in ``.hg/hgrc``. Note that
3702 ``default`` and ``default-push`` apply to all inbound (e.g.
3703 ``default`` and ``default-push`` apply to all inbound (e.g.
3703 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3704 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3704 :hg:`bundle`) operations.
3705 :hg:`bundle`) operations.
3705
3706
3706 See :hg:`help urls` for more information.
3707 See :hg:`help urls` for more information.
3707
3708
3708 Returns 0 on success.
3709 Returns 0 on success.
3709 """
3710 """
3710 if search:
3711 if search:
3711 for name, path in ui.configitems("paths"):
3712 for name, path in ui.configitems("paths"):
3712 if name == search:
3713 if name == search:
3713 ui.status("%s\n" % util.hidepassword(path))
3714 ui.status("%s\n" % util.hidepassword(path))
3714 return
3715 return
3715 if not ui.quiet:
3716 if not ui.quiet:
3716 ui.warn(_("not found!\n"))
3717 ui.warn(_("not found!\n"))
3717 return 1
3718 return 1
3718 else:
3719 else:
3719 for name, path in ui.configitems("paths"):
3720 for name, path in ui.configitems("paths"):
3720 if ui.quiet:
3721 if ui.quiet:
3721 ui.write("%s\n" % name)
3722 ui.write("%s\n" % name)
3722 else:
3723 else:
3723 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3724 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3724
3725
3725 def postincoming(ui, repo, modheads, optupdate, checkout):
3726 def postincoming(ui, repo, modheads, optupdate, checkout):
3726 if modheads == 0:
3727 if modheads == 0:
3727 return
3728 return
3728 if optupdate:
3729 if optupdate:
3729 try:
3730 try:
3730 return hg.update(repo, checkout)
3731 return hg.update(repo, checkout)
3731 except util.Abort, inst:
3732 except util.Abort, inst:
3732 ui.warn(_("not updating: %s\n" % str(inst)))
3733 ui.warn(_("not updating: %s\n" % str(inst)))
3733 return 0
3734 return 0
3734 if modheads > 1:
3735 if modheads > 1:
3735 currentbranchheads = len(repo.branchheads())
3736 currentbranchheads = len(repo.branchheads())
3736 if currentbranchheads == modheads:
3737 if currentbranchheads == modheads:
3737 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3738 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3738 elif currentbranchheads > 1:
3739 elif currentbranchheads > 1:
3739 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3740 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3740 else:
3741 else:
3741 ui.status(_("(run 'hg heads' to see heads)\n"))
3742 ui.status(_("(run 'hg heads' to see heads)\n"))
3742 else:
3743 else:
3743 ui.status(_("(run 'hg update' to get a working copy)\n"))
3744 ui.status(_("(run 'hg update' to get a working copy)\n"))
3744
3745
3745 @command('^pull',
3746 @command('^pull',
3746 [('u', 'update', None,
3747 [('u', 'update', None,
3747 _('update to new branch head if changesets were pulled')),
3748 _('update to new branch head if changesets were pulled')),
3748 ('f', 'force', None, _('run even when remote repository is unrelated')),
3749 ('f', 'force', None, _('run even when remote repository is unrelated')),
3749 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3750 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3750 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3751 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3751 ('b', 'branch', [], _('a specific branch you would like to pull'),
3752 ('b', 'branch', [], _('a specific branch you would like to pull'),
3752 _('BRANCH')),
3753 _('BRANCH')),
3753 ] + remoteopts,
3754 ] + remoteopts,
3754 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3755 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3755 def pull(ui, repo, source="default", **opts):
3756 def pull(ui, repo, source="default", **opts):
3756 """pull changes from the specified source
3757 """pull changes from the specified source
3757
3758
3758 Pull changes from a remote repository to a local one.
3759 Pull changes from a remote repository to a local one.
3759
3760
3760 This finds all changes from the repository at the specified path
3761 This finds all changes from the repository at the specified path
3761 or URL and adds them to a local repository (the current one unless
3762 or URL and adds them to a local repository (the current one unless
3762 -R is specified). By default, this does not update the copy of the
3763 -R is specified). By default, this does not update the copy of the
3763 project in the working directory.
3764 project in the working directory.
3764
3765
3765 Use :hg:`incoming` if you want to see what would have been added
3766 Use :hg:`incoming` if you want to see what would have been added
3766 by a pull at the time you issued this command. If you then decide
3767 by a pull at the time you issued this command. If you then decide
3767 to add those changes to the repository, you should use :hg:`pull
3768 to add those changes to the repository, you should use :hg:`pull
3768 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3769 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3769
3770
3770 If SOURCE is omitted, the 'default' path will be used.
3771 If SOURCE is omitted, the 'default' path will be used.
3771 See :hg:`help urls` for more information.
3772 See :hg:`help urls` for more information.
3772
3773
3773 Returns 0 on success, 1 if an update had unresolved files.
3774 Returns 0 on success, 1 if an update had unresolved files.
3774 """
3775 """
3775 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3776 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3776 other = hg.peer(repo, opts, source)
3777 other = hg.peer(repo, opts, source)
3777 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3778 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3778 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3779 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3779
3780
3780 if opts.get('bookmark'):
3781 if opts.get('bookmark'):
3781 if not revs:
3782 if not revs:
3782 revs = []
3783 revs = []
3783 rb = other.listkeys('bookmarks')
3784 rb = other.listkeys('bookmarks')
3784 for b in opts['bookmark']:
3785 for b in opts['bookmark']:
3785 if b not in rb:
3786 if b not in rb:
3786 raise util.Abort(_('remote bookmark %s not found!') % b)
3787 raise util.Abort(_('remote bookmark %s not found!') % b)
3787 revs.append(rb[b])
3788 revs.append(rb[b])
3788
3789
3789 if revs:
3790 if revs:
3790 try:
3791 try:
3791 revs = [other.lookup(rev) for rev in revs]
3792 revs = [other.lookup(rev) for rev in revs]
3792 except error.CapabilityError:
3793 except error.CapabilityError:
3793 err = _("other repository doesn't support revision lookup, "
3794 err = _("other repository doesn't support revision lookup, "
3794 "so a rev cannot be specified.")
3795 "so a rev cannot be specified.")
3795 raise util.Abort(err)
3796 raise util.Abort(err)
3796
3797
3797 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3798 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3798 bookmarks.updatefromremote(ui, repo, other)
3799 bookmarks.updatefromremote(ui, repo, other)
3799 if checkout:
3800 if checkout:
3800 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3801 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3801 repo._subtoppath = source
3802 repo._subtoppath = source
3802 try:
3803 try:
3803 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3804 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3804
3805
3805 finally:
3806 finally:
3806 del repo._subtoppath
3807 del repo._subtoppath
3807
3808
3808 # update specified bookmarks
3809 # update specified bookmarks
3809 if opts.get('bookmark'):
3810 if opts.get('bookmark'):
3810 for b in opts['bookmark']:
3811 for b in opts['bookmark']:
3811 # explicit pull overrides local bookmark if any
3812 # explicit pull overrides local bookmark if any
3812 ui.status(_("importing bookmark %s\n") % b)
3813 ui.status(_("importing bookmark %s\n") % b)
3813 repo._bookmarks[b] = repo[rb[b]].node()
3814 repo._bookmarks[b] = repo[rb[b]].node()
3814 bookmarks.write(repo)
3815 bookmarks.write(repo)
3815
3816
3816 return ret
3817 return ret
3817
3818
3818 @command('^push',
3819 @command('^push',
3819 [('f', 'force', None, _('force push')),
3820 [('f', 'force', None, _('force push')),
3820 ('r', 'rev', [],
3821 ('r', 'rev', [],
3821 _('a changeset intended to be included in the destination'),
3822 _('a changeset intended to be included in the destination'),
3822 _('REV')),
3823 _('REV')),
3823 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3824 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3824 ('b', 'branch', [],
3825 ('b', 'branch', [],
3825 _('a specific branch you would like to push'), _('BRANCH')),
3826 _('a specific branch you would like to push'), _('BRANCH')),
3826 ('', 'new-branch', False, _('allow pushing a new branch')),
3827 ('', 'new-branch', False, _('allow pushing a new branch')),
3827 ] + remoteopts,
3828 ] + remoteopts,
3828 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3829 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3829 def push(ui, repo, dest=None, **opts):
3830 def push(ui, repo, dest=None, **opts):
3830 """push changes to the specified destination
3831 """push changes to the specified destination
3831
3832
3832 Push changesets from the local repository to the specified
3833 Push changesets from the local repository to the specified
3833 destination.
3834 destination.
3834
3835
3835 This operation is symmetrical to pull: it is identical to a pull
3836 This operation is symmetrical to pull: it is identical to a pull
3836 in the destination repository from the current one.
3837 in the destination repository from the current one.
3837
3838
3838 By default, push will not allow creation of new heads at the
3839 By default, push will not allow creation of new heads at the
3839 destination, since multiple heads would make it unclear which head
3840 destination, since multiple heads would make it unclear which head
3840 to use. In this situation, it is recommended to pull and merge
3841 to use. In this situation, it is recommended to pull and merge
3841 before pushing.
3842 before pushing.
3842
3843
3843 Use --new-branch if you want to allow push to create a new named
3844 Use --new-branch if you want to allow push to create a new named
3844 branch that is not present at the destination. This allows you to
3845 branch that is not present at the destination. This allows you to
3845 only create a new branch without forcing other changes.
3846 only create a new branch without forcing other changes.
3846
3847
3847 Use -f/--force to override the default behavior and push all
3848 Use -f/--force to override the default behavior and push all
3848 changesets on all branches.
3849 changesets on all branches.
3849
3850
3850 If -r/--rev is used, the specified revision and all its ancestors
3851 If -r/--rev is used, the specified revision and all its ancestors
3851 will be pushed to the remote repository.
3852 will be pushed to the remote repository.
3852
3853
3853 Please see :hg:`help urls` for important details about ``ssh://``
3854 Please see :hg:`help urls` for important details about ``ssh://``
3854 URLs. If DESTINATION is omitted, a default path will be used.
3855 URLs. If DESTINATION is omitted, a default path will be used.
3855
3856
3856 Returns 0 if push was successful, 1 if nothing to push.
3857 Returns 0 if push was successful, 1 if nothing to push.
3857 """
3858 """
3858
3859
3859 if opts.get('bookmark'):
3860 if opts.get('bookmark'):
3860 for b in opts['bookmark']:
3861 for b in opts['bookmark']:
3861 # translate -B options to -r so changesets get pushed
3862 # translate -B options to -r so changesets get pushed
3862 if b in repo._bookmarks:
3863 if b in repo._bookmarks:
3863 opts.setdefault('rev', []).append(b)
3864 opts.setdefault('rev', []).append(b)
3864 else:
3865 else:
3865 # if we try to push a deleted bookmark, translate it to null
3866 # if we try to push a deleted bookmark, translate it to null
3866 # this lets simultaneous -r, -b options continue working
3867 # this lets simultaneous -r, -b options continue working
3867 opts.setdefault('rev', []).append("null")
3868 opts.setdefault('rev', []).append("null")
3868
3869
3869 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3870 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3870 dest, branches = hg.parseurl(dest, opts.get('branch'))
3871 dest, branches = hg.parseurl(dest, opts.get('branch'))
3871 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3872 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3872 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3873 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3873 other = hg.peer(repo, opts, dest)
3874 other = hg.peer(repo, opts, dest)
3874 if revs:
3875 if revs:
3875 revs = [repo.lookup(rev) for rev in revs]
3876 revs = [repo.lookup(rev) for rev in revs]
3876
3877
3877 repo._subtoppath = dest
3878 repo._subtoppath = dest
3878 try:
3879 try:
3879 # push subrepos depth-first for coherent ordering
3880 # push subrepos depth-first for coherent ordering
3880 c = repo['']
3881 c = repo['']
3881 subs = c.substate # only repos that are committed
3882 subs = c.substate # only repos that are committed
3882 for s in sorted(subs):
3883 for s in sorted(subs):
3883 if not c.sub(s).push(opts.get('force')):
3884 if not c.sub(s).push(opts.get('force')):
3884 return False
3885 return False
3885 finally:
3886 finally:
3886 del repo._subtoppath
3887 del repo._subtoppath
3887 result = repo.push(other, opts.get('force'), revs=revs,
3888 result = repo.push(other, opts.get('force'), revs=revs,
3888 newbranch=opts.get('new_branch'))
3889 newbranch=opts.get('new_branch'))
3889
3890
3890 result = (result == 0)
3891 result = (result == 0)
3891
3892
3892 if opts.get('bookmark'):
3893 if opts.get('bookmark'):
3893 rb = other.listkeys('bookmarks')
3894 rb = other.listkeys('bookmarks')
3894 for b in opts['bookmark']:
3895 for b in opts['bookmark']:
3895 # explicit push overrides remote bookmark if any
3896 # explicit push overrides remote bookmark if any
3896 if b in repo._bookmarks:
3897 if b in repo._bookmarks:
3897 ui.status(_("exporting bookmark %s\n") % b)
3898 ui.status(_("exporting bookmark %s\n") % b)
3898 new = repo[b].hex()
3899 new = repo[b].hex()
3899 elif b in rb:
3900 elif b in rb:
3900 ui.status(_("deleting remote bookmark %s\n") % b)
3901 ui.status(_("deleting remote bookmark %s\n") % b)
3901 new = '' # delete
3902 new = '' # delete
3902 else:
3903 else:
3903 ui.warn(_('bookmark %s does not exist on the local '
3904 ui.warn(_('bookmark %s does not exist on the local '
3904 'or remote repository!\n') % b)
3905 'or remote repository!\n') % b)
3905 return 2
3906 return 2
3906 old = rb.get(b, '')
3907 old = rb.get(b, '')
3907 r = other.pushkey('bookmarks', b, old, new)
3908 r = other.pushkey('bookmarks', b, old, new)
3908 if not r:
3909 if not r:
3909 ui.warn(_('updating bookmark %s failed!\n') % b)
3910 ui.warn(_('updating bookmark %s failed!\n') % b)
3910 if not result:
3911 if not result:
3911 result = 2
3912 result = 2
3912
3913
3913 return result
3914 return result
3914
3915
3915 @command('recover', [])
3916 @command('recover', [])
3916 def recover(ui, repo):
3917 def recover(ui, repo):
3917 """roll back an interrupted transaction
3918 """roll back an interrupted transaction
3918
3919
3919 Recover from an interrupted commit or pull.
3920 Recover from an interrupted commit or pull.
3920
3921
3921 This command tries to fix the repository status after an
3922 This command tries to fix the repository status after an
3922 interrupted operation. It should only be necessary when Mercurial
3923 interrupted operation. It should only be necessary when Mercurial
3923 suggests it.
3924 suggests it.
3924
3925
3925 Returns 0 if successful, 1 if nothing to recover or verify fails.
3926 Returns 0 if successful, 1 if nothing to recover or verify fails.
3926 """
3927 """
3927 if repo.recover():
3928 if repo.recover():
3928 return hg.verify(repo)
3929 return hg.verify(repo)
3929 return 1
3930 return 1
3930
3931
3931 @command('^remove|rm',
3932 @command('^remove|rm',
3932 [('A', 'after', None, _('record delete for missing files')),
3933 [('A', 'after', None, _('record delete for missing files')),
3933 ('f', 'force', None,
3934 ('f', 'force', None,
3934 _('remove (and delete) file even if added or modified')),
3935 _('remove (and delete) file even if added or modified')),
3935 ] + walkopts,
3936 ] + walkopts,
3936 _('[OPTION]... FILE...'))
3937 _('[OPTION]... FILE...'))
3937 def remove(ui, repo, *pats, **opts):
3938 def remove(ui, repo, *pats, **opts):
3938 """remove the specified files on the next commit
3939 """remove the specified files on the next commit
3939
3940
3940 Schedule the indicated files for removal from the repository.
3941 Schedule the indicated files for removal from the repository.
3941
3942
3942 This only removes files from the current branch, not from the
3943 This only removes files from the current branch, not from the
3943 entire project history. -A/--after can be used to remove only
3944 entire project history. -A/--after can be used to remove only
3944 files that have already been deleted, -f/--force can be used to
3945 files that have already been deleted, -f/--force can be used to
3945 force deletion, and -Af can be used to remove files from the next
3946 force deletion, and -Af can be used to remove files from the next
3946 revision without deleting them from the working directory.
3947 revision without deleting them from the working directory.
3947
3948
3948 The following table details the behavior of remove for different
3949 The following table details the behavior of remove for different
3949 file states (columns) and option combinations (rows). The file
3950 file states (columns) and option combinations (rows). The file
3950 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3951 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3951 reported by :hg:`status`). The actions are Warn, Remove (from
3952 reported by :hg:`status`). The actions are Warn, Remove (from
3952 branch) and Delete (from disk)::
3953 branch) and Delete (from disk)::
3953
3954
3954 A C M !
3955 A C M !
3955 none W RD W R
3956 none W RD W R
3956 -f R RD RD R
3957 -f R RD RD R
3957 -A W W W R
3958 -A W W W R
3958 -Af R R R R
3959 -Af R R R R
3959
3960
3960 Note that remove never deletes files in Added [A] state from the
3961 Note that remove never deletes files in Added [A] state from the
3961 working directory, not even if option --force is specified.
3962 working directory, not even if option --force is specified.
3962
3963
3963 This command schedules the files to be removed at the next commit.
3964 This command schedules the files to be removed at the next commit.
3964 To undo a remove before that, see :hg:`revert`.
3965 To undo a remove before that, see :hg:`revert`.
3965
3966
3966 Returns 0 on success, 1 if any warnings encountered.
3967 Returns 0 on success, 1 if any warnings encountered.
3967 """
3968 """
3968
3969
3969 ret = 0
3970 ret = 0
3970 after, force = opts.get('after'), opts.get('force')
3971 after, force = opts.get('after'), opts.get('force')
3971 if not pats and not after:
3972 if not pats and not after:
3972 raise util.Abort(_('no files specified'))
3973 raise util.Abort(_('no files specified'))
3973
3974
3974 m = scmutil.match(repo[None], pats, opts)
3975 m = scmutil.match(repo[None], pats, opts)
3975 s = repo.status(match=m, clean=True)
3976 s = repo.status(match=m, clean=True)
3976 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3977 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3977
3978
3978 for f in m.files():
3979 for f in m.files():
3979 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3980 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3980 if os.path.exists(m.rel(f)):
3981 if os.path.exists(m.rel(f)):
3981 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3982 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3982 ret = 1
3983 ret = 1
3983
3984
3984 if force:
3985 if force:
3985 list = modified + deleted + clean + added
3986 list = modified + deleted + clean + added
3986 elif after:
3987 elif after:
3987 list = deleted
3988 list = deleted
3988 for f in modified + added + clean:
3989 for f in modified + added + clean:
3989 ui.warn(_('not removing %s: file still exists (use -f'
3990 ui.warn(_('not removing %s: file still exists (use -f'
3990 ' to force removal)\n') % m.rel(f))
3991 ' to force removal)\n') % m.rel(f))
3991 ret = 1
3992 ret = 1
3992 else:
3993 else:
3993 list = deleted + clean
3994 list = deleted + clean
3994 for f in modified:
3995 for f in modified:
3995 ui.warn(_('not removing %s: file is modified (use -f'
3996 ui.warn(_('not removing %s: file is modified (use -f'
3996 ' to force removal)\n') % m.rel(f))
3997 ' to force removal)\n') % m.rel(f))
3997 ret = 1
3998 ret = 1
3998 for f in added:
3999 for f in added:
3999 ui.warn(_('not removing %s: file has been marked for add (use -f'
4000 ui.warn(_('not removing %s: file has been marked for add (use -f'
4000 ' to force removal)\n') % m.rel(f))
4001 ' to force removal)\n') % m.rel(f))
4001 ret = 1
4002 ret = 1
4002
4003
4003 for f in sorted(list):
4004 for f in sorted(list):
4004 if ui.verbose or not m.exact(f):
4005 if ui.verbose or not m.exact(f):
4005 ui.status(_('removing %s\n') % m.rel(f))
4006 ui.status(_('removing %s\n') % m.rel(f))
4006
4007
4007 wlock = repo.wlock()
4008 wlock = repo.wlock()
4008 try:
4009 try:
4009 if not after:
4010 if not after:
4010 for f in list:
4011 for f in list:
4011 if f in added:
4012 if f in added:
4012 continue # we never unlink added files on remove
4013 continue # we never unlink added files on remove
4013 try:
4014 try:
4014 util.unlinkpath(repo.wjoin(f))
4015 util.unlinkpath(repo.wjoin(f))
4015 except OSError, inst:
4016 except OSError, inst:
4016 if inst.errno != errno.ENOENT:
4017 if inst.errno != errno.ENOENT:
4017 raise
4018 raise
4018 repo[None].forget(list)
4019 repo[None].forget(list)
4019 finally:
4020 finally:
4020 wlock.release()
4021 wlock.release()
4021
4022
4022 return ret
4023 return ret
4023
4024
4024 @command('rename|move|mv',
4025 @command('rename|move|mv',
4025 [('A', 'after', None, _('record a rename that has already occurred')),
4026 [('A', 'after', None, _('record a rename that has already occurred')),
4026 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4027 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4027 ] + walkopts + dryrunopts,
4028 ] + walkopts + dryrunopts,
4028 _('[OPTION]... SOURCE... DEST'))
4029 _('[OPTION]... SOURCE... DEST'))
4029 def rename(ui, repo, *pats, **opts):
4030 def rename(ui, repo, *pats, **opts):
4030 """rename files; equivalent of copy + remove
4031 """rename files; equivalent of copy + remove
4031
4032
4032 Mark dest as copies of sources; mark sources for deletion. If dest
4033 Mark dest as copies of sources; mark sources for deletion. If dest
4033 is a directory, copies are put in that directory. If dest is a
4034 is a directory, copies are put in that directory. If dest is a
4034 file, there can only be one source.
4035 file, there can only be one source.
4035
4036
4036 By default, this command copies the contents of files as they
4037 By default, this command copies the contents of files as they
4037 exist in the working directory. If invoked with -A/--after, the
4038 exist in the working directory. If invoked with -A/--after, the
4038 operation is recorded, but no copying is performed.
4039 operation is recorded, but no copying is performed.
4039
4040
4040 This command takes effect at the next commit. To undo a rename
4041 This command takes effect at the next commit. To undo a rename
4041 before that, see :hg:`revert`.
4042 before that, see :hg:`revert`.
4042
4043
4043 Returns 0 on success, 1 if errors are encountered.
4044 Returns 0 on success, 1 if errors are encountered.
4044 """
4045 """
4045 wlock = repo.wlock(False)
4046 wlock = repo.wlock(False)
4046 try:
4047 try:
4047 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4048 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4048 finally:
4049 finally:
4049 wlock.release()
4050 wlock.release()
4050
4051
4051 @command('resolve',
4052 @command('resolve',
4052 [('a', 'all', None, _('select all unresolved files')),
4053 [('a', 'all', None, _('select all unresolved files')),
4053 ('l', 'list', None, _('list state of files needing merge')),
4054 ('l', 'list', None, _('list state of files needing merge')),
4054 ('m', 'mark', None, _('mark files as resolved')),
4055 ('m', 'mark', None, _('mark files as resolved')),
4055 ('u', 'unmark', None, _('mark files as unresolved')),
4056 ('u', 'unmark', None, _('mark files as unresolved')),
4056 ('n', 'no-status', None, _('hide status prefix'))]
4057 ('n', 'no-status', None, _('hide status prefix'))]
4057 + mergetoolopts + walkopts,
4058 + mergetoolopts + walkopts,
4058 _('[OPTION]... [FILE]...'))
4059 _('[OPTION]... [FILE]...'))
4059 def resolve(ui, repo, *pats, **opts):
4060 def resolve(ui, repo, *pats, **opts):
4060 """redo merges or set/view the merge status of files
4061 """redo merges or set/view the merge status of files
4061
4062
4062 Merges with unresolved conflicts are often the result of
4063 Merges with unresolved conflicts are often the result of
4063 non-interactive merging using the ``internal:merge`` configuration
4064 non-interactive merging using the ``internal:merge`` configuration
4064 setting, or a command-line merge tool like ``diff3``. The resolve
4065 setting, or a command-line merge tool like ``diff3``. The resolve
4065 command is used to manage the files involved in a merge, after
4066 command is used to manage the files involved in a merge, after
4066 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4067 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4067 working directory must have two parents).
4068 working directory must have two parents).
4068
4069
4069 The resolve command can be used in the following ways:
4070 The resolve command can be used in the following ways:
4070
4071
4071 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4072 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4072 files, discarding any previous merge attempts. Re-merging is not
4073 files, discarding any previous merge attempts. Re-merging is not
4073 performed for files already marked as resolved. Use ``--all/-a``
4074 performed for files already marked as resolved. Use ``--all/-a``
4074 to selects all unresolved files. ``--tool`` can be used to specify
4075 to selects all unresolved files. ``--tool`` can be used to specify
4075 the merge tool used for the given files. It overrides the HGMERGE
4076 the merge tool used for the given files. It overrides the HGMERGE
4076 environment variable and your configuration files.
4077 environment variable and your configuration files.
4077
4078
4078 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4079 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4079 (e.g. after having manually fixed-up the files). The default is
4080 (e.g. after having manually fixed-up the files). The default is
4080 to mark all unresolved files.
4081 to mark all unresolved files.
4081
4082
4082 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4083 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4083 default is to mark all resolved files.
4084 default is to mark all resolved files.
4084
4085
4085 - :hg:`resolve -l`: list files which had or still have conflicts.
4086 - :hg:`resolve -l`: list files which had or still have conflicts.
4086 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4087 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4087
4088
4088 Note that Mercurial will not let you commit files with unresolved
4089 Note that Mercurial will not let you commit files with unresolved
4089 merge conflicts. You must use :hg:`resolve -m ...` before you can
4090 merge conflicts. You must use :hg:`resolve -m ...` before you can
4090 commit after a conflicting merge.
4091 commit after a conflicting merge.
4091
4092
4092 Returns 0 on success, 1 if any files fail a resolve attempt.
4093 Returns 0 on success, 1 if any files fail a resolve attempt.
4093 """
4094 """
4094
4095
4095 all, mark, unmark, show, nostatus = \
4096 all, mark, unmark, show, nostatus = \
4096 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4097 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4097
4098
4098 if (show and (mark or unmark)) or (mark and unmark):
4099 if (show and (mark or unmark)) or (mark and unmark):
4099 raise util.Abort(_("too many options specified"))
4100 raise util.Abort(_("too many options specified"))
4100 if pats and all:
4101 if pats and all:
4101 raise util.Abort(_("can't specify --all and patterns"))
4102 raise util.Abort(_("can't specify --all and patterns"))
4102 if not (all or pats or show or mark or unmark):
4103 if not (all or pats or show or mark or unmark):
4103 raise util.Abort(_('no files or directories specified; '
4104 raise util.Abort(_('no files or directories specified; '
4104 'use --all to remerge all files'))
4105 'use --all to remerge all files'))
4105
4106
4106 ms = mergemod.mergestate(repo)
4107 ms = mergemod.mergestate(repo)
4107 m = scmutil.match(repo[None], pats, opts)
4108 m = scmutil.match(repo[None], pats, opts)
4108 ret = 0
4109 ret = 0
4109
4110
4110 for f in ms:
4111 for f in ms:
4111 if m(f):
4112 if m(f):
4112 if show:
4113 if show:
4113 if nostatus:
4114 if nostatus:
4114 ui.write("%s\n" % f)
4115 ui.write("%s\n" % f)
4115 else:
4116 else:
4116 ui.write("%s %s\n" % (ms[f].upper(), f),
4117 ui.write("%s %s\n" % (ms[f].upper(), f),
4117 label='resolve.' +
4118 label='resolve.' +
4118 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4119 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4119 elif mark:
4120 elif mark:
4120 ms.mark(f, "r")
4121 ms.mark(f, "r")
4121 elif unmark:
4122 elif unmark:
4122 ms.mark(f, "u")
4123 ms.mark(f, "u")
4123 else:
4124 else:
4124 wctx = repo[None]
4125 wctx = repo[None]
4125 mctx = wctx.parents()[-1]
4126 mctx = wctx.parents()[-1]
4126
4127
4127 # backup pre-resolve (merge uses .orig for its own purposes)
4128 # backup pre-resolve (merge uses .orig for its own purposes)
4128 a = repo.wjoin(f)
4129 a = repo.wjoin(f)
4129 util.copyfile(a, a + ".resolve")
4130 util.copyfile(a, a + ".resolve")
4130
4131
4131 try:
4132 try:
4132 # resolve file
4133 # resolve file
4133 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4134 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4134 if ms.resolve(f, wctx, mctx):
4135 if ms.resolve(f, wctx, mctx):
4135 ret = 1
4136 ret = 1
4136 finally:
4137 finally:
4137 ui.setconfig('ui', 'forcemerge', '')
4138 ui.setconfig('ui', 'forcemerge', '')
4138
4139
4139 # replace filemerge's .orig file with our resolve file
4140 # replace filemerge's .orig file with our resolve file
4140 util.rename(a + ".resolve", a + ".orig")
4141 util.rename(a + ".resolve", a + ".orig")
4141
4142
4142 ms.commit()
4143 ms.commit()
4143 return ret
4144 return ret
4144
4145
4145 @command('revert',
4146 @command('revert',
4146 [('a', 'all', None, _('revert all changes when no arguments given')),
4147 [('a', 'all', None, _('revert all changes when no arguments given')),
4147 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4148 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4148 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4149 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4149 ('', 'no-backup', None, _('do not save backup copies of files')),
4150 ('', 'no-backup', None, _('do not save backup copies of files')),
4150 ] + walkopts + dryrunopts,
4151 ] + walkopts + dryrunopts,
4151 _('[OPTION]... [-r REV] [NAME]...'))
4152 _('[OPTION]... [-r REV] [NAME]...'))
4152 def revert(ui, repo, *pats, **opts):
4153 def revert(ui, repo, *pats, **opts):
4153 """restore files to their checkout state
4154 """restore files to their checkout state
4154
4155
4155 .. note::
4156 .. note::
4156 To check out earlier revisions, you should use :hg:`update REV`.
4157 To check out earlier revisions, you should use :hg:`update REV`.
4157 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4158 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4158
4159
4159 With no revision specified, revert the specified files or directories
4160 With no revision specified, revert the specified files or directories
4160 to the contents they had in the parent of the working directory.
4161 to the contents they had in the parent of the working directory.
4161 This restores the contents of files to an unmodified
4162 This restores the contents of files to an unmodified
4162 state and unschedules adds, removes, copies, and renames. If the
4163 state and unschedules adds, removes, copies, and renames. If the
4163 working directory has two parents, you must explicitly specify a
4164 working directory has two parents, you must explicitly specify a
4164 revision.
4165 revision.
4165
4166
4166 Using the -r/--rev or -d/--date options, revert the given files or
4167 Using the -r/--rev or -d/--date options, revert the given files or
4167 directories to their states as of a specific revision. Because
4168 directories to their states as of a specific revision. Because
4168 revert does not change the working directory parents, this will
4169 revert does not change the working directory parents, this will
4169 cause these files to appear modified. This can be helpful to "back
4170 cause these files to appear modified. This can be helpful to "back
4170 out" some or all of an earlier change. See :hg:`backout` for a
4171 out" some or all of an earlier change. See :hg:`backout` for a
4171 related method.
4172 related method.
4172
4173
4173 Modified files are saved with a .orig suffix before reverting.
4174 Modified files are saved with a .orig suffix before reverting.
4174 To disable these backups, use --no-backup.
4175 To disable these backups, use --no-backup.
4175
4176
4176 See :hg:`help dates` for a list of formats valid for -d/--date.
4177 See :hg:`help dates` for a list of formats valid for -d/--date.
4177
4178
4178 Returns 0 on success.
4179 Returns 0 on success.
4179 """
4180 """
4180
4181
4181 if opts.get("date"):
4182 if opts.get("date"):
4182 if opts.get("rev"):
4183 if opts.get("rev"):
4183 raise util.Abort(_("you can't specify a revision and a date"))
4184 raise util.Abort(_("you can't specify a revision and a date"))
4184 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4185 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4185
4186
4186 parent, p2 = repo.dirstate.parents()
4187 parent, p2 = repo.dirstate.parents()
4187 if not opts.get('rev') and p2 != nullid:
4188 if not opts.get('rev') and p2 != nullid:
4188 # revert after merge is a trap for new users (issue2915)
4189 # revert after merge is a trap for new users (issue2915)
4189 raise util.Abort(_('uncommitted merge with no revision specified'),
4190 raise util.Abort(_('uncommitted merge with no revision specified'),
4190 hint=_('use "hg update" or see "hg help revert"'))
4191 hint=_('use "hg update" or see "hg help revert"'))
4191
4192
4192 ctx = scmutil.revsingle(repo, opts.get('rev'))
4193 ctx = scmutil.revsingle(repo, opts.get('rev'))
4193 node = ctx.node()
4194 node = ctx.node()
4194
4195
4195 if not pats and not opts.get('all'):
4196 if not pats and not opts.get('all'):
4196 msg = _("no files or directories specified")
4197 msg = _("no files or directories specified")
4197 if p2 != nullid:
4198 if p2 != nullid:
4198 hint = _("uncommitted merge, use --all to discard all changes,"
4199 hint = _("uncommitted merge, use --all to discard all changes,"
4199 " or 'hg update -C .' to abort the merge")
4200 " or 'hg update -C .' to abort the merge")
4200 raise util.Abort(msg, hint=hint)
4201 raise util.Abort(msg, hint=hint)
4201 dirty = util.any(repo.status())
4202 dirty = util.any(repo.status())
4202 if node != parent:
4203 if node != parent:
4203 if dirty:
4204 if dirty:
4204 hint = _("uncommitted changes, use --all to discard all"
4205 hint = _("uncommitted changes, use --all to discard all"
4205 " changes, or 'hg update %s' to update") % ctx.rev()
4206 " changes, or 'hg update %s' to update") % ctx.rev()
4206 else:
4207 else:
4207 hint = _("use --all to revert all files,"
4208 hint = _("use --all to revert all files,"
4208 " or 'hg update %s' to update") % ctx.rev()
4209 " or 'hg update %s' to update") % ctx.rev()
4209 elif dirty:
4210 elif dirty:
4210 hint = _("uncommitted changes, use --all to discard all changes")
4211 hint = _("uncommitted changes, use --all to discard all changes")
4211 else:
4212 else:
4212 hint = _("use --all to revert all files")
4213 hint = _("use --all to revert all files")
4213 raise util.Abort(msg, hint=hint)
4214 raise util.Abort(msg, hint=hint)
4214
4215
4215 mf = ctx.manifest()
4216 mf = ctx.manifest()
4216 if node == parent:
4217 if node == parent:
4217 pmf = mf
4218 pmf = mf
4218 else:
4219 else:
4219 pmf = None
4220 pmf = None
4220
4221
4221 # need all matching names in dirstate and manifest of target rev,
4222 # need all matching names in dirstate and manifest of target rev,
4222 # so have to walk both. do not print errors if files exist in one
4223 # so have to walk both. do not print errors if files exist in one
4223 # but not other.
4224 # but not other.
4224
4225
4225 names = {}
4226 names = {}
4226
4227
4227 wlock = repo.wlock()
4228 wlock = repo.wlock()
4228 try:
4229 try:
4229 # walk dirstate.
4230 # walk dirstate.
4230
4231
4231 m = scmutil.match(repo[None], pats, opts)
4232 m = scmutil.match(repo[None], pats, opts)
4232 m.bad = lambda x, y: False
4233 m.bad = lambda x, y: False
4233 for abs in repo.walk(m):
4234 for abs in repo.walk(m):
4234 names[abs] = m.rel(abs), m.exact(abs)
4235 names[abs] = m.rel(abs), m.exact(abs)
4235
4236
4236 # walk target manifest.
4237 # walk target manifest.
4237
4238
4238 def badfn(path, msg):
4239 def badfn(path, msg):
4239 if path in names:
4240 if path in names:
4240 return
4241 return
4241 path_ = path + '/'
4242 path_ = path + '/'
4242 for f in names:
4243 for f in names:
4243 if f.startswith(path_):
4244 if f.startswith(path_):
4244 return
4245 return
4245 ui.warn("%s: %s\n" % (m.rel(path), msg))
4246 ui.warn("%s: %s\n" % (m.rel(path), msg))
4246
4247
4247 m = scmutil.match(repo[node], pats, opts)
4248 m = scmutil.match(repo[node], pats, opts)
4248 m.bad = badfn
4249 m.bad = badfn
4249 for abs in repo[node].walk(m):
4250 for abs in repo[node].walk(m):
4250 if abs not in names:
4251 if abs not in names:
4251 names[abs] = m.rel(abs), m.exact(abs)
4252 names[abs] = m.rel(abs), m.exact(abs)
4252
4253
4253 m = scmutil.matchfiles(repo, names)
4254 m = scmutil.matchfiles(repo, names)
4254 changes = repo.status(match=m)[:4]
4255 changes = repo.status(match=m)[:4]
4255 modified, added, removed, deleted = map(set, changes)
4256 modified, added, removed, deleted = map(set, changes)
4256
4257
4257 # if f is a rename, also revert the source
4258 # if f is a rename, also revert the source
4258 cwd = repo.getcwd()
4259 cwd = repo.getcwd()
4259 for f in added:
4260 for f in added:
4260 src = repo.dirstate.copied(f)
4261 src = repo.dirstate.copied(f)
4261 if src and src not in names and repo.dirstate[src] == 'r':
4262 if src and src not in names and repo.dirstate[src] == 'r':
4262 removed.add(src)
4263 removed.add(src)
4263 names[src] = (repo.pathto(src, cwd), True)
4264 names[src] = (repo.pathto(src, cwd), True)
4264
4265
4265 def removeforget(abs):
4266 def removeforget(abs):
4266 if repo.dirstate[abs] == 'a':
4267 if repo.dirstate[abs] == 'a':
4267 return _('forgetting %s\n')
4268 return _('forgetting %s\n')
4268 return _('removing %s\n')
4269 return _('removing %s\n')
4269
4270
4270 revert = ([], _('reverting %s\n'))
4271 revert = ([], _('reverting %s\n'))
4271 add = ([], _('adding %s\n'))
4272 add = ([], _('adding %s\n'))
4272 remove = ([], removeforget)
4273 remove = ([], removeforget)
4273 undelete = ([], _('undeleting %s\n'))
4274 undelete = ([], _('undeleting %s\n'))
4274
4275
4275 disptable = (
4276 disptable = (
4276 # dispatch table:
4277 # dispatch table:
4277 # file state
4278 # file state
4278 # action if in target manifest
4279 # action if in target manifest
4279 # action if not in target manifest
4280 # action if not in target manifest
4280 # make backup if in target manifest
4281 # make backup if in target manifest
4281 # make backup if not in target manifest
4282 # make backup if not in target manifest
4282 (modified, revert, remove, True, True),
4283 (modified, revert, remove, True, True),
4283 (added, revert, remove, True, False),
4284 (added, revert, remove, True, False),
4284 (removed, undelete, None, False, False),
4285 (removed, undelete, None, False, False),
4285 (deleted, revert, remove, False, False),
4286 (deleted, revert, remove, False, False),
4286 )
4287 )
4287
4288
4288 for abs, (rel, exact) in sorted(names.items()):
4289 for abs, (rel, exact) in sorted(names.items()):
4289 mfentry = mf.get(abs)
4290 mfentry = mf.get(abs)
4290 target = repo.wjoin(abs)
4291 target = repo.wjoin(abs)
4291 def handle(xlist, dobackup):
4292 def handle(xlist, dobackup):
4292 xlist[0].append(abs)
4293 xlist[0].append(abs)
4293 if (dobackup and not opts.get('no_backup') and
4294 if (dobackup and not opts.get('no_backup') and
4294 os.path.lexists(target)):
4295 os.path.lexists(target)):
4295 bakname = "%s.orig" % rel
4296 bakname = "%s.orig" % rel
4296 ui.note(_('saving current version of %s as %s\n') %
4297 ui.note(_('saving current version of %s as %s\n') %
4297 (rel, bakname))
4298 (rel, bakname))
4298 if not opts.get('dry_run'):
4299 if not opts.get('dry_run'):
4299 util.rename(target, bakname)
4300 util.rename(target, bakname)
4300 if ui.verbose or not exact:
4301 if ui.verbose or not exact:
4301 msg = xlist[1]
4302 msg = xlist[1]
4302 if not isinstance(msg, basestring):
4303 if not isinstance(msg, basestring):
4303 msg = msg(abs)
4304 msg = msg(abs)
4304 ui.status(msg % rel)
4305 ui.status(msg % rel)
4305 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4306 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4306 if abs not in table:
4307 if abs not in table:
4307 continue
4308 continue
4308 # file has changed in dirstate
4309 # file has changed in dirstate
4309 if mfentry:
4310 if mfentry:
4310 handle(hitlist, backuphit)
4311 handle(hitlist, backuphit)
4311 elif misslist is not None:
4312 elif misslist is not None:
4312 handle(misslist, backupmiss)
4313 handle(misslist, backupmiss)
4313 break
4314 break
4314 else:
4315 else:
4315 if abs not in repo.dirstate:
4316 if abs not in repo.dirstate:
4316 if mfentry:
4317 if mfentry:
4317 handle(add, True)
4318 handle(add, True)
4318 elif exact:
4319 elif exact:
4319 ui.warn(_('file not managed: %s\n') % rel)
4320 ui.warn(_('file not managed: %s\n') % rel)
4320 continue
4321 continue
4321 # file has not changed in dirstate
4322 # file has not changed in dirstate
4322 if node == parent:
4323 if node == parent:
4323 if exact:
4324 if exact:
4324 ui.warn(_('no changes needed to %s\n') % rel)
4325 ui.warn(_('no changes needed to %s\n') % rel)
4325 continue
4326 continue
4326 if pmf is None:
4327 if pmf is None:
4327 # only need parent manifest in this unlikely case,
4328 # only need parent manifest in this unlikely case,
4328 # so do not read by default
4329 # so do not read by default
4329 pmf = repo[parent].manifest()
4330 pmf = repo[parent].manifest()
4330 if abs in pmf:
4331 if abs in pmf:
4331 if mfentry:
4332 if mfentry:
4332 # if version of file is same in parent and target
4333 # if version of file is same in parent and target
4333 # manifests, do nothing
4334 # manifests, do nothing
4334 if (pmf[abs] != mfentry or
4335 if (pmf[abs] != mfentry or
4335 pmf.flags(abs) != mf.flags(abs)):
4336 pmf.flags(abs) != mf.flags(abs)):
4336 handle(revert, False)
4337 handle(revert, False)
4337 else:
4338 else:
4338 handle(remove, False)
4339 handle(remove, False)
4339
4340
4340 if not opts.get('dry_run'):
4341 if not opts.get('dry_run'):
4341 def checkout(f):
4342 def checkout(f):
4342 fc = ctx[f]
4343 fc = ctx[f]
4343 repo.wwrite(f, fc.data(), fc.flags())
4344 repo.wwrite(f, fc.data(), fc.flags())
4344
4345
4345 audit_path = scmutil.pathauditor(repo.root)
4346 audit_path = scmutil.pathauditor(repo.root)
4346 for f in remove[0]:
4347 for f in remove[0]:
4347 if repo.dirstate[f] == 'a':
4348 if repo.dirstate[f] == 'a':
4348 repo.dirstate.drop(f)
4349 repo.dirstate.drop(f)
4349 continue
4350 continue
4350 audit_path(f)
4351 audit_path(f)
4351 try:
4352 try:
4352 util.unlinkpath(repo.wjoin(f))
4353 util.unlinkpath(repo.wjoin(f))
4353 except OSError:
4354 except OSError:
4354 pass
4355 pass
4355 repo.dirstate.remove(f)
4356 repo.dirstate.remove(f)
4356
4357
4357 normal = None
4358 normal = None
4358 if node == parent:
4359 if node == parent:
4359 # We're reverting to our parent. If possible, we'd like status
4360 # We're reverting to our parent. If possible, we'd like status
4360 # to report the file as clean. We have to use normallookup for
4361 # to report the file as clean. We have to use normallookup for
4361 # merges to avoid losing information about merged/dirty files.
4362 # merges to avoid losing information about merged/dirty files.
4362 if p2 != nullid:
4363 if p2 != nullid:
4363 normal = repo.dirstate.normallookup
4364 normal = repo.dirstate.normallookup
4364 else:
4365 else:
4365 normal = repo.dirstate.normal
4366 normal = repo.dirstate.normal
4366 for f in revert[0]:
4367 for f in revert[0]:
4367 checkout(f)
4368 checkout(f)
4368 if normal:
4369 if normal:
4369 normal(f)
4370 normal(f)
4370
4371
4371 for f in add[0]:
4372 for f in add[0]:
4372 checkout(f)
4373 checkout(f)
4373 repo.dirstate.add(f)
4374 repo.dirstate.add(f)
4374
4375
4375 normal = repo.dirstate.normallookup
4376 normal = repo.dirstate.normallookup
4376 if node == parent and p2 == nullid:
4377 if node == parent and p2 == nullid:
4377 normal = repo.dirstate.normal
4378 normal = repo.dirstate.normal
4378 for f in undelete[0]:
4379 for f in undelete[0]:
4379 checkout(f)
4380 checkout(f)
4380 normal(f)
4381 normal(f)
4381
4382
4382 finally:
4383 finally:
4383 wlock.release()
4384 wlock.release()
4384
4385
4385 @command('rollback', dryrunopts)
4386 @command('rollback', dryrunopts)
4386 def rollback(ui, repo, **opts):
4387 def rollback(ui, repo, **opts):
4387 """roll back the last transaction (dangerous)
4388 """roll back the last transaction (dangerous)
4388
4389
4389 This command should be used with care. There is only one level of
4390 This command should be used with care. There is only one level of
4390 rollback, and there is no way to undo a rollback. It will also
4391 rollback, and there is no way to undo a rollback. It will also
4391 restore the dirstate at the time of the last transaction, losing
4392 restore the dirstate at the time of the last transaction, losing
4392 any dirstate changes since that time. This command does not alter
4393 any dirstate changes since that time. This command does not alter
4393 the working directory.
4394 the working directory.
4394
4395
4395 Transactions are used to encapsulate the effects of all commands
4396 Transactions are used to encapsulate the effects of all commands
4396 that create new changesets or propagate existing changesets into a
4397 that create new changesets or propagate existing changesets into a
4397 repository. For example, the following commands are transactional,
4398 repository. For example, the following commands are transactional,
4398 and their effects can be rolled back:
4399 and their effects can be rolled back:
4399
4400
4400 - commit
4401 - commit
4401 - import
4402 - import
4402 - pull
4403 - pull
4403 - push (with this repository as the destination)
4404 - push (with this repository as the destination)
4404 - unbundle
4405 - unbundle
4405
4406
4406 This command is not intended for use on public repositories. Once
4407 This command is not intended for use on public repositories. Once
4407 changes are visible for pull by other users, rolling a transaction
4408 changes are visible for pull by other users, rolling a transaction
4408 back locally is ineffective (someone else may already have pulled
4409 back locally is ineffective (someone else may already have pulled
4409 the changes). Furthermore, a race is possible with readers of the
4410 the changes). Furthermore, a race is possible with readers of the
4410 repository; for example an in-progress pull from the repository
4411 repository; for example an in-progress pull from the repository
4411 may fail if a rollback is performed.
4412 may fail if a rollback is performed.
4412
4413
4413 Returns 0 on success, 1 if no rollback data is available.
4414 Returns 0 on success, 1 if no rollback data is available.
4414 """
4415 """
4415 return repo.rollback(opts.get('dry_run'))
4416 return repo.rollback(opts.get('dry_run'))
4416
4417
4417 @command('root', [])
4418 @command('root', [])
4418 def root(ui, repo):
4419 def root(ui, repo):
4419 """print the root (top) of the current working directory
4420 """print the root (top) of the current working directory
4420
4421
4421 Print the root directory of the current repository.
4422 Print the root directory of the current repository.
4422
4423
4423 Returns 0 on success.
4424 Returns 0 on success.
4424 """
4425 """
4425 ui.write(repo.root + "\n")
4426 ui.write(repo.root + "\n")
4426
4427
4427 @command('^serve',
4428 @command('^serve',
4428 [('A', 'accesslog', '', _('name of access log file to write to'),
4429 [('A', 'accesslog', '', _('name of access log file to write to'),
4429 _('FILE')),
4430 _('FILE')),
4430 ('d', 'daemon', None, _('run server in background')),
4431 ('d', 'daemon', None, _('run server in background')),
4431 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4432 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4432 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4433 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4433 # use string type, then we can check if something was passed
4434 # use string type, then we can check if something was passed
4434 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4435 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4435 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4436 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4436 _('ADDR')),
4437 _('ADDR')),
4437 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4438 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4438 _('PREFIX')),
4439 _('PREFIX')),
4439 ('n', 'name', '',
4440 ('n', 'name', '',
4440 _('name to show in web pages (default: working directory)'), _('NAME')),
4441 _('name to show in web pages (default: working directory)'), _('NAME')),
4441 ('', 'web-conf', '',
4442 ('', 'web-conf', '',
4442 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4443 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4443 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4444 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4444 _('FILE')),
4445 _('FILE')),
4445 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4446 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4446 ('', 'stdio', None, _('for remote clients')),
4447 ('', 'stdio', None, _('for remote clients')),
4447 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4448 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4448 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4449 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4449 ('', 'style', '', _('template style to use'), _('STYLE')),
4450 ('', 'style', '', _('template style to use'), _('STYLE')),
4450 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4451 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4451 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4452 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4452 _('[OPTION]...'))
4453 _('[OPTION]...'))
4453 def serve(ui, repo, **opts):
4454 def serve(ui, repo, **opts):
4454 """start stand-alone webserver
4455 """start stand-alone webserver
4455
4456
4456 Start a local HTTP repository browser and pull server. You can use
4457 Start a local HTTP repository browser and pull server. You can use
4457 this for ad-hoc sharing and browsing of repositories. It is
4458 this for ad-hoc sharing and browsing of repositories. It is
4458 recommended to use a real web server to serve a repository for
4459 recommended to use a real web server to serve a repository for
4459 longer periods of time.
4460 longer periods of time.
4460
4461
4461 Please note that the server does not implement access control.
4462 Please note that the server does not implement access control.
4462 This means that, by default, anybody can read from the server and
4463 This means that, by default, anybody can read from the server and
4463 nobody can write to it by default. Set the ``web.allow_push``
4464 nobody can write to it by default. Set the ``web.allow_push``
4464 option to ``*`` to allow everybody to push to the server. You
4465 option to ``*`` to allow everybody to push to the server. You
4465 should use a real web server if you need to authenticate users.
4466 should use a real web server if you need to authenticate users.
4466
4467
4467 By default, the server logs accesses to stdout and errors to
4468 By default, the server logs accesses to stdout and errors to
4468 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4469 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4469 files.
4470 files.
4470
4471
4471 To have the server choose a free port number to listen on, specify
4472 To have the server choose a free port number to listen on, specify
4472 a port number of 0; in this case, the server will print the port
4473 a port number of 0; in this case, the server will print the port
4473 number it uses.
4474 number it uses.
4474
4475
4475 Returns 0 on success.
4476 Returns 0 on success.
4476 """
4477 """
4477
4478
4478 if opts["stdio"] and opts["cmdserver"]:
4479 if opts["stdio"] and opts["cmdserver"]:
4479 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4480 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4480
4481
4481 def checkrepo():
4482 def checkrepo():
4482 if repo is None:
4483 if repo is None:
4483 raise error.RepoError(_("There is no Mercurial repository here"
4484 raise error.RepoError(_("There is no Mercurial repository here"
4484 " (.hg not found)"))
4485 " (.hg not found)"))
4485
4486
4486 if opts["stdio"]:
4487 if opts["stdio"]:
4487 checkrepo()
4488 checkrepo()
4488 s = sshserver.sshserver(ui, repo)
4489 s = sshserver.sshserver(ui, repo)
4489 s.serve_forever()
4490 s.serve_forever()
4490
4491
4491 if opts["cmdserver"]:
4492 if opts["cmdserver"]:
4492 checkrepo()
4493 checkrepo()
4493 s = commandserver.server(ui, repo, opts["cmdserver"])
4494 s = commandserver.server(ui, repo, opts["cmdserver"])
4494 return s.serve()
4495 return s.serve()
4495
4496
4496 # this way we can check if something was given in the command-line
4497 # this way we can check if something was given in the command-line
4497 if opts.get('port'):
4498 if opts.get('port'):
4498 opts['port'] = util.getport(opts.get('port'))
4499 opts['port'] = util.getport(opts.get('port'))
4499
4500
4500 baseui = repo and repo.baseui or ui
4501 baseui = repo and repo.baseui or ui
4501 optlist = ("name templates style address port prefix ipv6"
4502 optlist = ("name templates style address port prefix ipv6"
4502 " accesslog errorlog certificate encoding")
4503 " accesslog errorlog certificate encoding")
4503 for o in optlist.split():
4504 for o in optlist.split():
4504 val = opts.get(o, '')
4505 val = opts.get(o, '')
4505 if val in (None, ''): # should check against default options instead
4506 if val in (None, ''): # should check against default options instead
4506 continue
4507 continue
4507 baseui.setconfig("web", o, val)
4508 baseui.setconfig("web", o, val)
4508 if repo and repo.ui != baseui:
4509 if repo and repo.ui != baseui:
4509 repo.ui.setconfig("web", o, val)
4510 repo.ui.setconfig("web", o, val)
4510
4511
4511 o = opts.get('web_conf') or opts.get('webdir_conf')
4512 o = opts.get('web_conf') or opts.get('webdir_conf')
4512 if not o:
4513 if not o:
4513 if not repo:
4514 if not repo:
4514 raise error.RepoError(_("There is no Mercurial repository"
4515 raise error.RepoError(_("There is no Mercurial repository"
4515 " here (.hg not found)"))
4516 " here (.hg not found)"))
4516 o = repo.root
4517 o = repo.root
4517
4518
4518 app = hgweb.hgweb(o, baseui=ui)
4519 app = hgweb.hgweb(o, baseui=ui)
4519
4520
4520 class service(object):
4521 class service(object):
4521 def init(self):
4522 def init(self):
4522 util.setsignalhandler()
4523 util.setsignalhandler()
4523 self.httpd = hgweb.server.create_server(ui, app)
4524 self.httpd = hgweb.server.create_server(ui, app)
4524
4525
4525 if opts['port'] and not ui.verbose:
4526 if opts['port'] and not ui.verbose:
4526 return
4527 return
4527
4528
4528 if self.httpd.prefix:
4529 if self.httpd.prefix:
4529 prefix = self.httpd.prefix.strip('/') + '/'
4530 prefix = self.httpd.prefix.strip('/') + '/'
4530 else:
4531 else:
4531 prefix = ''
4532 prefix = ''
4532
4533
4533 port = ':%d' % self.httpd.port
4534 port = ':%d' % self.httpd.port
4534 if port == ':80':
4535 if port == ':80':
4535 port = ''
4536 port = ''
4536
4537
4537 bindaddr = self.httpd.addr
4538 bindaddr = self.httpd.addr
4538 if bindaddr == '0.0.0.0':
4539 if bindaddr == '0.0.0.0':
4539 bindaddr = '*'
4540 bindaddr = '*'
4540 elif ':' in bindaddr: # IPv6
4541 elif ':' in bindaddr: # IPv6
4541 bindaddr = '[%s]' % bindaddr
4542 bindaddr = '[%s]' % bindaddr
4542
4543
4543 fqaddr = self.httpd.fqaddr
4544 fqaddr = self.httpd.fqaddr
4544 if ':' in fqaddr:
4545 if ':' in fqaddr:
4545 fqaddr = '[%s]' % fqaddr
4546 fqaddr = '[%s]' % fqaddr
4546 if opts['port']:
4547 if opts['port']:
4547 write = ui.status
4548 write = ui.status
4548 else:
4549 else:
4549 write = ui.write
4550 write = ui.write
4550 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4551 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4551 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4552 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4552
4553
4553 def run(self):
4554 def run(self):
4554 self.httpd.serve_forever()
4555 self.httpd.serve_forever()
4555
4556
4556 service = service()
4557 service = service()
4557
4558
4558 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4559 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4559
4560
4560 @command('showconfig|debugconfig',
4561 @command('showconfig|debugconfig',
4561 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4562 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4562 _('[-u] [NAME]...'))
4563 _('[-u] [NAME]...'))
4563 def showconfig(ui, repo, *values, **opts):
4564 def showconfig(ui, repo, *values, **opts):
4564 """show combined config settings from all hgrc files
4565 """show combined config settings from all hgrc files
4565
4566
4566 With no arguments, print names and values of all config items.
4567 With no arguments, print names and values of all config items.
4567
4568
4568 With one argument of the form section.name, print just the value
4569 With one argument of the form section.name, print just the value
4569 of that config item.
4570 of that config item.
4570
4571
4571 With multiple arguments, print names and values of all config
4572 With multiple arguments, print names and values of all config
4572 items with matching section names.
4573 items with matching section names.
4573
4574
4574 With --debug, the source (filename and line number) is printed
4575 With --debug, the source (filename and line number) is printed
4575 for each config item.
4576 for each config item.
4576
4577
4577 Returns 0 on success.
4578 Returns 0 on success.
4578 """
4579 """
4579
4580
4580 for f in scmutil.rcpath():
4581 for f in scmutil.rcpath():
4581 ui.debug('read config from: %s\n' % f)
4582 ui.debug('read config from: %s\n' % f)
4582 untrusted = bool(opts.get('untrusted'))
4583 untrusted = bool(opts.get('untrusted'))
4583 if values:
4584 if values:
4584 sections = [v for v in values if '.' not in v]
4585 sections = [v for v in values if '.' not in v]
4585 items = [v for v in values if '.' in v]
4586 items = [v for v in values if '.' in v]
4586 if len(items) > 1 or items and sections:
4587 if len(items) > 1 or items and sections:
4587 raise util.Abort(_('only one config item permitted'))
4588 raise util.Abort(_('only one config item permitted'))
4588 for section, name, value in ui.walkconfig(untrusted=untrusted):
4589 for section, name, value in ui.walkconfig(untrusted=untrusted):
4589 value = str(value).replace('\n', '\\n')
4590 value = str(value).replace('\n', '\\n')
4590 sectname = section + '.' + name
4591 sectname = section + '.' + name
4591 if values:
4592 if values:
4592 for v in values:
4593 for v in values:
4593 if v == section:
4594 if v == section:
4594 ui.debug('%s: ' %
4595 ui.debug('%s: ' %
4595 ui.configsource(section, name, untrusted))
4596 ui.configsource(section, name, untrusted))
4596 ui.write('%s=%s\n' % (sectname, value))
4597 ui.write('%s=%s\n' % (sectname, value))
4597 elif v == sectname:
4598 elif v == sectname:
4598 ui.debug('%s: ' %
4599 ui.debug('%s: ' %
4599 ui.configsource(section, name, untrusted))
4600 ui.configsource(section, name, untrusted))
4600 ui.write(value, '\n')
4601 ui.write(value, '\n')
4601 else:
4602 else:
4602 ui.debug('%s: ' %
4603 ui.debug('%s: ' %
4603 ui.configsource(section, name, untrusted))
4604 ui.configsource(section, name, untrusted))
4604 ui.write('%s=%s\n' % (sectname, value))
4605 ui.write('%s=%s\n' % (sectname, value))
4605
4606
4606 @command('^status|st',
4607 @command('^status|st',
4607 [('A', 'all', None, _('show status of all files')),
4608 [('A', 'all', None, _('show status of all files')),
4608 ('m', 'modified', None, _('show only modified files')),
4609 ('m', 'modified', None, _('show only modified files')),
4609 ('a', 'added', None, _('show only added files')),
4610 ('a', 'added', None, _('show only added files')),
4610 ('r', 'removed', None, _('show only removed files')),
4611 ('r', 'removed', None, _('show only removed files')),
4611 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4612 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4612 ('c', 'clean', None, _('show only files without changes')),
4613 ('c', 'clean', None, _('show only files without changes')),
4613 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4614 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4614 ('i', 'ignored', None, _('show only ignored files')),
4615 ('i', 'ignored', None, _('show only ignored files')),
4615 ('n', 'no-status', None, _('hide status prefix')),
4616 ('n', 'no-status', None, _('hide status prefix')),
4616 ('C', 'copies', None, _('show source of copied files')),
4617 ('C', 'copies', None, _('show source of copied files')),
4617 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4618 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4618 ('', 'rev', [], _('show difference from revision'), _('REV')),
4619 ('', 'rev', [], _('show difference from revision'), _('REV')),
4619 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4620 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4620 ] + walkopts + subrepoopts,
4621 ] + walkopts + subrepoopts,
4621 _('[OPTION]... [FILE]...'))
4622 _('[OPTION]... [FILE]...'))
4622 def status(ui, repo, *pats, **opts):
4623 def status(ui, repo, *pats, **opts):
4623 """show changed files in the working directory
4624 """show changed files in the working directory
4624
4625
4625 Show status of files in the repository. If names are given, only
4626 Show status of files in the repository. If names are given, only
4626 files that match are shown. Files that are clean or ignored or
4627 files that match are shown. Files that are clean or ignored or
4627 the source of a copy/move operation, are not listed unless
4628 the source of a copy/move operation, are not listed unless
4628 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4629 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4629 Unless options described with "show only ..." are given, the
4630 Unless options described with "show only ..." are given, the
4630 options -mardu are used.
4631 options -mardu are used.
4631
4632
4632 Option -q/--quiet hides untracked (unknown and ignored) files
4633 Option -q/--quiet hides untracked (unknown and ignored) files
4633 unless explicitly requested with -u/--unknown or -i/--ignored.
4634 unless explicitly requested with -u/--unknown or -i/--ignored.
4634
4635
4635 .. note::
4636 .. note::
4636 status may appear to disagree with diff if permissions have
4637 status may appear to disagree with diff if permissions have
4637 changed or a merge has occurred. The standard diff format does
4638 changed or a merge has occurred. The standard diff format does
4638 not report permission changes and diff only reports changes
4639 not report permission changes and diff only reports changes
4639 relative to one merge parent.
4640 relative to one merge parent.
4640
4641
4641 If one revision is given, it is used as the base revision.
4642 If one revision is given, it is used as the base revision.
4642 If two revisions are given, the differences between them are
4643 If two revisions are given, the differences between them are
4643 shown. The --change option can also be used as a shortcut to list
4644 shown. The --change option can also be used as a shortcut to list
4644 the changed files of a revision from its first parent.
4645 the changed files of a revision from its first parent.
4645
4646
4646 The codes used to show the status of files are::
4647 The codes used to show the status of files are::
4647
4648
4648 M = modified
4649 M = modified
4649 A = added
4650 A = added
4650 R = removed
4651 R = removed
4651 C = clean
4652 C = clean
4652 ! = missing (deleted by non-hg command, but still tracked)
4653 ! = missing (deleted by non-hg command, but still tracked)
4653 ? = not tracked
4654 ? = not tracked
4654 I = ignored
4655 I = ignored
4655 = origin of the previous file listed as A (added)
4656 = origin of the previous file listed as A (added)
4656
4657
4657 Returns 0 on success.
4658 Returns 0 on success.
4658 """
4659 """
4659
4660
4660 revs = opts.get('rev')
4661 revs = opts.get('rev')
4661 change = opts.get('change')
4662 change = opts.get('change')
4662
4663
4663 if revs and change:
4664 if revs and change:
4664 msg = _('cannot specify --rev and --change at the same time')
4665 msg = _('cannot specify --rev and --change at the same time')
4665 raise util.Abort(msg)
4666 raise util.Abort(msg)
4666 elif change:
4667 elif change:
4667 node2 = repo.lookup(change)
4668 node2 = repo.lookup(change)
4668 node1 = repo[node2].p1().node()
4669 node1 = repo[node2].p1().node()
4669 else:
4670 else:
4670 node1, node2 = scmutil.revpair(repo, revs)
4671 node1, node2 = scmutil.revpair(repo, revs)
4671
4672
4672 cwd = (pats and repo.getcwd()) or ''
4673 cwd = (pats and repo.getcwd()) or ''
4673 end = opts.get('print0') and '\0' or '\n'
4674 end = opts.get('print0') and '\0' or '\n'
4674 copy = {}
4675 copy = {}
4675 states = 'modified added removed deleted unknown ignored clean'.split()
4676 states = 'modified added removed deleted unknown ignored clean'.split()
4676 show = [k for k in states if opts.get(k)]
4677 show = [k for k in states if opts.get(k)]
4677 if opts.get('all'):
4678 if opts.get('all'):
4678 show += ui.quiet and (states[:4] + ['clean']) or states
4679 show += ui.quiet and (states[:4] + ['clean']) or states
4679 if not show:
4680 if not show:
4680 show = ui.quiet and states[:4] or states[:5]
4681 show = ui.quiet and states[:4] or states[:5]
4681
4682
4682 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
4683 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
4683 'ignored' in show, 'clean' in show, 'unknown' in show,
4684 'ignored' in show, 'clean' in show, 'unknown' in show,
4684 opts.get('subrepos'))
4685 opts.get('subrepos'))
4685 changestates = zip(states, 'MAR!?IC', stat)
4686 changestates = zip(states, 'MAR!?IC', stat)
4686
4687
4687 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4688 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4688 ctxn = repo[nullid]
4689 ctxn = repo[nullid]
4689 ctx1 = repo[node1]
4690 ctx1 = repo[node1]
4690 ctx2 = repo[node2]
4691 ctx2 = repo[node2]
4691 added = stat[1]
4692 added = stat[1]
4692 if node2 is None:
4693 if node2 is None:
4693 added = stat[0] + stat[1] # merged?
4694 added = stat[0] + stat[1] # merged?
4694
4695
4695 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4696 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4696 if k in added:
4697 if k in added:
4697 copy[k] = v
4698 copy[k] = v
4698 elif v in added:
4699 elif v in added:
4699 copy[v] = k
4700 copy[v] = k
4700
4701
4701 for state, char, files in changestates:
4702 for state, char, files in changestates:
4702 if state in show:
4703 if state in show:
4703 format = "%s %%s%s" % (char, end)
4704 format = "%s %%s%s" % (char, end)
4704 if opts.get('no_status'):
4705 if opts.get('no_status'):
4705 format = "%%s%s" % end
4706 format = "%%s%s" % end
4706
4707
4707 for f in files:
4708 for f in files:
4708 ui.write(format % repo.pathto(f, cwd),
4709 ui.write(format % repo.pathto(f, cwd),
4709 label='status.' + state)
4710 label='status.' + state)
4710 if f in copy:
4711 if f in copy:
4711 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4712 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4712 label='status.copied')
4713 label='status.copied')
4713
4714
4714 @command('^summary|sum',
4715 @command('^summary|sum',
4715 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4716 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4716 def summary(ui, repo, **opts):
4717 def summary(ui, repo, **opts):
4717 """summarize working directory state
4718 """summarize working directory state
4718
4719
4719 This generates a brief summary of the working directory state,
4720 This generates a brief summary of the working directory state,
4720 including parents, branch, commit status, and available updates.
4721 including parents, branch, commit status, and available updates.
4721
4722
4722 With the --remote option, this will check the default paths for
4723 With the --remote option, this will check the default paths for
4723 incoming and outgoing changes. This can be time-consuming.
4724 incoming and outgoing changes. This can be time-consuming.
4724
4725
4725 Returns 0 on success.
4726 Returns 0 on success.
4726 """
4727 """
4727
4728
4728 ctx = repo[None]
4729 ctx = repo[None]
4729 parents = ctx.parents()
4730 parents = ctx.parents()
4730 pnode = parents[0].node()
4731 pnode = parents[0].node()
4731 marks = []
4732 marks = []
4732
4733
4733 for p in parents:
4734 for p in parents:
4734 # label with log.changeset (instead of log.parent) since this
4735 # label with log.changeset (instead of log.parent) since this
4735 # shows a working directory parent *changeset*:
4736 # shows a working directory parent *changeset*:
4736 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4737 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4737 label='log.changeset')
4738 label='log.changeset')
4738 ui.write(' '.join(p.tags()), label='log.tag')
4739 ui.write(' '.join(p.tags()), label='log.tag')
4739 if p.bookmarks():
4740 if p.bookmarks():
4740 marks.extend(p.bookmarks())
4741 marks.extend(p.bookmarks())
4741 if p.rev() == -1:
4742 if p.rev() == -1:
4742 if not len(repo):
4743 if not len(repo):
4743 ui.write(_(' (empty repository)'))
4744 ui.write(_(' (empty repository)'))
4744 else:
4745 else:
4745 ui.write(_(' (no revision checked out)'))
4746 ui.write(_(' (no revision checked out)'))
4746 ui.write('\n')
4747 ui.write('\n')
4747 if p.description():
4748 if p.description():
4748 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4749 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4749 label='log.summary')
4750 label='log.summary')
4750
4751
4751 branch = ctx.branch()
4752 branch = ctx.branch()
4752 bheads = repo.branchheads(branch)
4753 bheads = repo.branchheads(branch)
4753 m = _('branch: %s\n') % branch
4754 m = _('branch: %s\n') % branch
4754 if branch != 'default':
4755 if branch != 'default':
4755 ui.write(m, label='log.branch')
4756 ui.write(m, label='log.branch')
4756 else:
4757 else:
4757 ui.status(m, label='log.branch')
4758 ui.status(m, label='log.branch')
4758
4759
4759 if marks:
4760 if marks:
4760 current = repo._bookmarkcurrent
4761 current = repo._bookmarkcurrent
4761 ui.write(_('bookmarks:'), label='log.bookmark')
4762 ui.write(_('bookmarks:'), label='log.bookmark')
4762 if current is not None:
4763 if current is not None:
4763 try:
4764 try:
4764 marks.remove(current)
4765 marks.remove(current)
4765 ui.write(' *' + current, label='bookmarks.current')
4766 ui.write(' *' + current, label='bookmarks.current')
4766 except ValueError:
4767 except ValueError:
4767 # current bookmark not in parent ctx marks
4768 # current bookmark not in parent ctx marks
4768 pass
4769 pass
4769 for m in marks:
4770 for m in marks:
4770 ui.write(' ' + m, label='log.bookmark')
4771 ui.write(' ' + m, label='log.bookmark')
4771 ui.write('\n', label='log.bookmark')
4772 ui.write('\n', label='log.bookmark')
4772
4773
4773 st = list(repo.status(unknown=True))[:6]
4774 st = list(repo.status(unknown=True))[:6]
4774
4775
4775 c = repo.dirstate.copies()
4776 c = repo.dirstate.copies()
4776 copied, renamed = [], []
4777 copied, renamed = [], []
4777 for d, s in c.iteritems():
4778 for d, s in c.iteritems():
4778 if s in st[2]:
4779 if s in st[2]:
4779 st[2].remove(s)
4780 st[2].remove(s)
4780 renamed.append(d)
4781 renamed.append(d)
4781 else:
4782 else:
4782 copied.append(d)
4783 copied.append(d)
4783 if d in st[1]:
4784 if d in st[1]:
4784 st[1].remove(d)
4785 st[1].remove(d)
4785 st.insert(3, renamed)
4786 st.insert(3, renamed)
4786 st.insert(4, copied)
4787 st.insert(4, copied)
4787
4788
4788 ms = mergemod.mergestate(repo)
4789 ms = mergemod.mergestate(repo)
4789 st.append([f for f in ms if ms[f] == 'u'])
4790 st.append([f for f in ms if ms[f] == 'u'])
4790
4791
4791 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4792 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4792 st.append(subs)
4793 st.append(subs)
4793
4794
4794 labels = [ui.label(_('%d modified'), 'status.modified'),
4795 labels = [ui.label(_('%d modified'), 'status.modified'),
4795 ui.label(_('%d added'), 'status.added'),
4796 ui.label(_('%d added'), 'status.added'),
4796 ui.label(_('%d removed'), 'status.removed'),
4797 ui.label(_('%d removed'), 'status.removed'),
4797 ui.label(_('%d renamed'), 'status.copied'),
4798 ui.label(_('%d renamed'), 'status.copied'),
4798 ui.label(_('%d copied'), 'status.copied'),
4799 ui.label(_('%d copied'), 'status.copied'),
4799 ui.label(_('%d deleted'), 'status.deleted'),
4800 ui.label(_('%d deleted'), 'status.deleted'),
4800 ui.label(_('%d unknown'), 'status.unknown'),
4801 ui.label(_('%d unknown'), 'status.unknown'),
4801 ui.label(_('%d ignored'), 'status.ignored'),
4802 ui.label(_('%d ignored'), 'status.ignored'),
4802 ui.label(_('%d unresolved'), 'resolve.unresolved'),
4803 ui.label(_('%d unresolved'), 'resolve.unresolved'),
4803 ui.label(_('%d subrepos'), 'status.modified')]
4804 ui.label(_('%d subrepos'), 'status.modified')]
4804 t = []
4805 t = []
4805 for s, l in zip(st, labels):
4806 for s, l in zip(st, labels):
4806 if s:
4807 if s:
4807 t.append(l % len(s))
4808 t.append(l % len(s))
4808
4809
4809 t = ', '.join(t)
4810 t = ', '.join(t)
4810 cleanworkdir = False
4811 cleanworkdir = False
4811
4812
4812 if len(parents) > 1:
4813 if len(parents) > 1:
4813 t += _(' (merge)')
4814 t += _(' (merge)')
4814 elif branch != parents[0].branch():
4815 elif branch != parents[0].branch():
4815 t += _(' (new branch)')
4816 t += _(' (new branch)')
4816 elif (parents[0].extra().get('close') and
4817 elif (parents[0].extra().get('close') and
4817 pnode in repo.branchheads(branch, closed=True)):
4818 pnode in repo.branchheads(branch, closed=True)):
4818 t += _(' (head closed)')
4819 t += _(' (head closed)')
4819 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4820 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4820 t += _(' (clean)')
4821 t += _(' (clean)')
4821 cleanworkdir = True
4822 cleanworkdir = True
4822 elif pnode not in bheads:
4823 elif pnode not in bheads:
4823 t += _(' (new branch head)')
4824 t += _(' (new branch head)')
4824
4825
4825 if cleanworkdir:
4826 if cleanworkdir:
4826 ui.status(_('commit: %s\n') % t.strip())
4827 ui.status(_('commit: %s\n') % t.strip())
4827 else:
4828 else:
4828 ui.write(_('commit: %s\n') % t.strip())
4829 ui.write(_('commit: %s\n') % t.strip())
4829
4830
4830 # all ancestors of branch heads - all ancestors of parent = new csets
4831 # all ancestors of branch heads - all ancestors of parent = new csets
4831 new = [0] * len(repo)
4832 new = [0] * len(repo)
4832 cl = repo.changelog
4833 cl = repo.changelog
4833 for a in [cl.rev(n) for n in bheads]:
4834 for a in [cl.rev(n) for n in bheads]:
4834 new[a] = 1
4835 new[a] = 1
4835 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
4836 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
4836 new[a] = 1
4837 new[a] = 1
4837 for a in [p.rev() for p in parents]:
4838 for a in [p.rev() for p in parents]:
4838 if a >= 0:
4839 if a >= 0:
4839 new[a] = 0
4840 new[a] = 0
4840 for a in cl.ancestors(*[p.rev() for p in parents]):
4841 for a in cl.ancestors(*[p.rev() for p in parents]):
4841 new[a] = 0
4842 new[a] = 0
4842 new = sum(new)
4843 new = sum(new)
4843
4844
4844 if new == 0:
4845 if new == 0:
4845 ui.status(_('update: (current)\n'))
4846 ui.status(_('update: (current)\n'))
4846 elif pnode not in bheads:
4847 elif pnode not in bheads:
4847 ui.write(_('update: %d new changesets (update)\n') % new)
4848 ui.write(_('update: %d new changesets (update)\n') % new)
4848 else:
4849 else:
4849 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4850 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4850 (new, len(bheads)))
4851 (new, len(bheads)))
4851
4852
4852 if opts.get('remote'):
4853 if opts.get('remote'):
4853 t = []
4854 t = []
4854 source, branches = hg.parseurl(ui.expandpath('default'))
4855 source, branches = hg.parseurl(ui.expandpath('default'))
4855 other = hg.peer(repo, {}, source)
4856 other = hg.peer(repo, {}, source)
4856 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4857 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4857 ui.debug('comparing with %s\n' % util.hidepassword(source))
4858 ui.debug('comparing with %s\n' % util.hidepassword(source))
4858 repo.ui.pushbuffer()
4859 repo.ui.pushbuffer()
4859 commoninc = discovery.findcommonincoming(repo, other)
4860 commoninc = discovery.findcommonincoming(repo, other)
4860 _common, incoming, _rheads = commoninc
4861 _common, incoming, _rheads = commoninc
4861 repo.ui.popbuffer()
4862 repo.ui.popbuffer()
4862 if incoming:
4863 if incoming:
4863 t.append(_('1 or more incoming'))
4864 t.append(_('1 or more incoming'))
4864
4865
4865 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4866 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4866 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4867 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4867 if source != dest:
4868 if source != dest:
4868 other = hg.peer(repo, {}, dest)
4869 other = hg.peer(repo, {}, dest)
4869 commoninc = None
4870 commoninc = None
4870 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4871 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4871 repo.ui.pushbuffer()
4872 repo.ui.pushbuffer()
4872 common, outheads = discovery.findcommonoutgoing(repo, other,
4873 common, outheads = discovery.findcommonoutgoing(repo, other,
4873 commoninc=commoninc)
4874 commoninc=commoninc)
4874 repo.ui.popbuffer()
4875 repo.ui.popbuffer()
4875 o = repo.changelog.findmissing(common=common, heads=outheads)
4876 o = repo.changelog.findmissing(common=common, heads=outheads)
4876 if o:
4877 if o:
4877 t.append(_('%d outgoing') % len(o))
4878 t.append(_('%d outgoing') % len(o))
4878 if 'bookmarks' in other.listkeys('namespaces'):
4879 if 'bookmarks' in other.listkeys('namespaces'):
4879 lmarks = repo.listkeys('bookmarks')
4880 lmarks = repo.listkeys('bookmarks')
4880 rmarks = other.listkeys('bookmarks')
4881 rmarks = other.listkeys('bookmarks')
4881 diff = set(rmarks) - set(lmarks)
4882 diff = set(rmarks) - set(lmarks)
4882 if len(diff) > 0:
4883 if len(diff) > 0:
4883 t.append(_('%d incoming bookmarks') % len(diff))
4884 t.append(_('%d incoming bookmarks') % len(diff))
4884 diff = set(lmarks) - set(rmarks)
4885 diff = set(lmarks) - set(rmarks)
4885 if len(diff) > 0:
4886 if len(diff) > 0:
4886 t.append(_('%d outgoing bookmarks') % len(diff))
4887 t.append(_('%d outgoing bookmarks') % len(diff))
4887
4888
4888 if t:
4889 if t:
4889 ui.write(_('remote: %s\n') % (', '.join(t)))
4890 ui.write(_('remote: %s\n') % (', '.join(t)))
4890 else:
4891 else:
4891 ui.status(_('remote: (synced)\n'))
4892 ui.status(_('remote: (synced)\n'))
4892
4893
4893 @command('tag',
4894 @command('tag',
4894 [('f', 'force', None, _('force tag')),
4895 [('f', 'force', None, _('force tag')),
4895 ('l', 'local', None, _('make the tag local')),
4896 ('l', 'local', None, _('make the tag local')),
4896 ('r', 'rev', '', _('revision to tag'), _('REV')),
4897 ('r', 'rev', '', _('revision to tag'), _('REV')),
4897 ('', 'remove', None, _('remove a tag')),
4898 ('', 'remove', None, _('remove a tag')),
4898 # -l/--local is already there, commitopts cannot be used
4899 # -l/--local is already there, commitopts cannot be used
4899 ('e', 'edit', None, _('edit commit message')),
4900 ('e', 'edit', None, _('edit commit message')),
4900 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
4901 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
4901 ] + commitopts2,
4902 ] + commitopts2,
4902 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
4903 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
4903 def tag(ui, repo, name1, *names, **opts):
4904 def tag(ui, repo, name1, *names, **opts):
4904 """add one or more tags for the current or given revision
4905 """add one or more tags for the current or given revision
4905
4906
4906 Name a particular revision using <name>.
4907 Name a particular revision using <name>.
4907
4908
4908 Tags are used to name particular revisions of the repository and are
4909 Tags are used to name particular revisions of the repository and are
4909 very useful to compare different revisions, to go back to significant
4910 very useful to compare different revisions, to go back to significant
4910 earlier versions or to mark branch points as releases, etc. Changing
4911 earlier versions or to mark branch points as releases, etc. Changing
4911 an existing tag is normally disallowed; use -f/--force to override.
4912 an existing tag is normally disallowed; use -f/--force to override.
4912
4913
4913 If no revision is given, the parent of the working directory is
4914 If no revision is given, the parent of the working directory is
4914 used, or tip if no revision is checked out.
4915 used, or tip if no revision is checked out.
4915
4916
4916 To facilitate version control, distribution, and merging of tags,
4917 To facilitate version control, distribution, and merging of tags,
4917 they are stored as a file named ".hgtags" which is managed similarly
4918 they are stored as a file named ".hgtags" which is managed similarly
4918 to other project files and can be hand-edited if necessary. This
4919 to other project files and can be hand-edited if necessary. This
4919 also means that tagging creates a new commit. The file
4920 also means that tagging creates a new commit. The file
4920 ".hg/localtags" is used for local tags (not shared among
4921 ".hg/localtags" is used for local tags (not shared among
4921 repositories).
4922 repositories).
4922
4923
4923 Tag commits are usually made at the head of a branch. If the parent
4924 Tag commits are usually made at the head of a branch. If the parent
4924 of the working directory is not a branch head, :hg:`tag` aborts; use
4925 of the working directory is not a branch head, :hg:`tag` aborts; use
4925 -f/--force to force the tag commit to be based on a non-head
4926 -f/--force to force the tag commit to be based on a non-head
4926 changeset.
4927 changeset.
4927
4928
4928 See :hg:`help dates` for a list of formats valid for -d/--date.
4929 See :hg:`help dates` for a list of formats valid for -d/--date.
4929
4930
4930 Since tag names have priority over branch names during revision
4931 Since tag names have priority over branch names during revision
4931 lookup, using an existing branch name as a tag name is discouraged.
4932 lookup, using an existing branch name as a tag name is discouraged.
4932
4933
4933 Returns 0 on success.
4934 Returns 0 on success.
4934 """
4935 """
4935
4936
4936 rev_ = "."
4937 rev_ = "."
4937 names = [t.strip() for t in (name1,) + names]
4938 names = [t.strip() for t in (name1,) + names]
4938 if len(names) != len(set(names)):
4939 if len(names) != len(set(names)):
4939 raise util.Abort(_('tag names must be unique'))
4940 raise util.Abort(_('tag names must be unique'))
4940 for n in names:
4941 for n in names:
4941 if n in ['tip', '.', 'null']:
4942 if n in ['tip', '.', 'null']:
4942 raise util.Abort(_("the name '%s' is reserved") % n)
4943 raise util.Abort(_("the name '%s' is reserved") % n)
4943 if not n:
4944 if not n:
4944 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4945 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4945 if opts.get('rev') and opts.get('remove'):
4946 if opts.get('rev') and opts.get('remove'):
4946 raise util.Abort(_("--rev and --remove are incompatible"))
4947 raise util.Abort(_("--rev and --remove are incompatible"))
4947 if opts.get('rev'):
4948 if opts.get('rev'):
4948 rev_ = opts['rev']
4949 rev_ = opts['rev']
4949 message = opts.get('message')
4950 message = opts.get('message')
4950 if opts.get('remove'):
4951 if opts.get('remove'):
4951 expectedtype = opts.get('local') and 'local' or 'global'
4952 expectedtype = opts.get('local') and 'local' or 'global'
4952 for n in names:
4953 for n in names:
4953 if not repo.tagtype(n):
4954 if not repo.tagtype(n):
4954 raise util.Abort(_("tag '%s' does not exist") % n)
4955 raise util.Abort(_("tag '%s' does not exist") % n)
4955 if repo.tagtype(n) != expectedtype:
4956 if repo.tagtype(n) != expectedtype:
4956 if expectedtype == 'global':
4957 if expectedtype == 'global':
4957 raise util.Abort(_("tag '%s' is not a global tag") % n)
4958 raise util.Abort(_("tag '%s' is not a global tag") % n)
4958 else:
4959 else:
4959 raise util.Abort(_("tag '%s' is not a local tag") % n)
4960 raise util.Abort(_("tag '%s' is not a local tag") % n)
4960 rev_ = nullid
4961 rev_ = nullid
4961 if not message:
4962 if not message:
4962 # we don't translate commit messages
4963 # we don't translate commit messages
4963 message = 'Removed tag %s' % ', '.join(names)
4964 message = 'Removed tag %s' % ', '.join(names)
4964 elif not opts.get('force'):
4965 elif not opts.get('force'):
4965 for n in names:
4966 for n in names:
4966 if n in repo.tags():
4967 if n in repo.tags():
4967 raise util.Abort(_("tag '%s' already exists "
4968 raise util.Abort(_("tag '%s' already exists "
4968 "(use -f to force)") % n)
4969 "(use -f to force)") % n)
4969 if not opts.get('local'):
4970 if not opts.get('local'):
4970 p1, p2 = repo.dirstate.parents()
4971 p1, p2 = repo.dirstate.parents()
4971 if p2 != nullid:
4972 if p2 != nullid:
4972 raise util.Abort(_('uncommitted merge'))
4973 raise util.Abort(_('uncommitted merge'))
4973 bheads = repo.branchheads()
4974 bheads = repo.branchheads()
4974 if not opts.get('force') and bheads and p1 not in bheads:
4975 if not opts.get('force') and bheads and p1 not in bheads:
4975 raise util.Abort(_('not at a branch head (use -f to force)'))
4976 raise util.Abort(_('not at a branch head (use -f to force)'))
4976 r = scmutil.revsingle(repo, rev_).node()
4977 r = scmutil.revsingle(repo, rev_).node()
4977
4978
4978 if not message:
4979 if not message:
4979 # we don't translate commit messages
4980 # we don't translate commit messages
4980 message = ('Added tag %s for changeset %s' %
4981 message = ('Added tag %s for changeset %s' %
4981 (', '.join(names), short(r)))
4982 (', '.join(names), short(r)))
4982
4983
4983 date = opts.get('date')
4984 date = opts.get('date')
4984 if date:
4985 if date:
4985 date = util.parsedate(date)
4986 date = util.parsedate(date)
4986
4987
4987 if opts.get('edit'):
4988 if opts.get('edit'):
4988 message = ui.edit(message, ui.username())
4989 message = ui.edit(message, ui.username())
4989
4990
4990 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4991 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4991
4992
4992 @command('tags', [], '')
4993 @command('tags', [], '')
4993 def tags(ui, repo):
4994 def tags(ui, repo):
4994 """list repository tags
4995 """list repository tags
4995
4996
4996 This lists both regular and local tags. When the -v/--verbose
4997 This lists both regular and local tags. When the -v/--verbose
4997 switch is used, a third column "local" is printed for local tags.
4998 switch is used, a third column "local" is printed for local tags.
4998
4999
4999 Returns 0 on success.
5000 Returns 0 on success.
5000 """
5001 """
5001
5002
5002 hexfunc = ui.debugflag and hex or short
5003 hexfunc = ui.debugflag and hex or short
5003 tagtype = ""
5004 tagtype = ""
5004
5005
5005 for t, n in reversed(repo.tagslist()):
5006 for t, n in reversed(repo.tagslist()):
5006 if ui.quiet:
5007 if ui.quiet:
5007 ui.write("%s\n" % t)
5008 ui.write("%s\n" % t)
5008 continue
5009 continue
5009
5010
5010 hn = hexfunc(n)
5011 hn = hexfunc(n)
5011 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5012 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5012 spaces = " " * (30 - encoding.colwidth(t))
5013 spaces = " " * (30 - encoding.colwidth(t))
5013
5014
5014 if ui.verbose:
5015 if ui.verbose:
5015 if repo.tagtype(t) == 'local':
5016 if repo.tagtype(t) == 'local':
5016 tagtype = " local"
5017 tagtype = " local"
5017 else:
5018 else:
5018 tagtype = ""
5019 tagtype = ""
5019 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
5020 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
5020
5021
5021 @command('tip',
5022 @command('tip',
5022 [('p', 'patch', None, _('show patch')),
5023 [('p', 'patch', None, _('show patch')),
5023 ('g', 'git', None, _('use git extended diff format')),
5024 ('g', 'git', None, _('use git extended diff format')),
5024 ] + templateopts,
5025 ] + templateopts,
5025 _('[-p] [-g]'))
5026 _('[-p] [-g]'))
5026 def tip(ui, repo, **opts):
5027 def tip(ui, repo, **opts):
5027 """show the tip revision
5028 """show the tip revision
5028
5029
5029 The tip revision (usually just called the tip) is the changeset
5030 The tip revision (usually just called the tip) is the changeset
5030 most recently added to the repository (and therefore the most
5031 most recently added to the repository (and therefore the most
5031 recently changed head).
5032 recently changed head).
5032
5033
5033 If you have just made a commit, that commit will be the tip. If
5034 If you have just made a commit, that commit will be the tip. If
5034 you have just pulled changes from another repository, the tip of
5035 you have just pulled changes from another repository, the tip of
5035 that repository becomes the current tip. The "tip" tag is special
5036 that repository becomes the current tip. The "tip" tag is special
5036 and cannot be renamed or assigned to a different changeset.
5037 and cannot be renamed or assigned to a different changeset.
5037
5038
5038 Returns 0 on success.
5039 Returns 0 on success.
5039 """
5040 """
5040 displayer = cmdutil.show_changeset(ui, repo, opts)
5041 displayer = cmdutil.show_changeset(ui, repo, opts)
5041 displayer.show(repo[len(repo) - 1])
5042 displayer.show(repo[len(repo) - 1])
5042 displayer.close()
5043 displayer.close()
5043
5044
5044 @command('unbundle',
5045 @command('unbundle',
5045 [('u', 'update', None,
5046 [('u', 'update', None,
5046 _('update to new branch head if changesets were unbundled'))],
5047 _('update to new branch head if changesets were unbundled'))],
5047 _('[-u] FILE...'))
5048 _('[-u] FILE...'))
5048 def unbundle(ui, repo, fname1, *fnames, **opts):
5049 def unbundle(ui, repo, fname1, *fnames, **opts):
5049 """apply one or more changegroup files
5050 """apply one or more changegroup files
5050
5051
5051 Apply one or more compressed changegroup files generated by the
5052 Apply one or more compressed changegroup files generated by the
5052 bundle command.
5053 bundle command.
5053
5054
5054 Returns 0 on success, 1 if an update has unresolved files.
5055 Returns 0 on success, 1 if an update has unresolved files.
5055 """
5056 """
5056 fnames = (fname1,) + fnames
5057 fnames = (fname1,) + fnames
5057
5058
5058 lock = repo.lock()
5059 lock = repo.lock()
5059 wc = repo['.']
5060 wc = repo['.']
5060 try:
5061 try:
5061 for fname in fnames:
5062 for fname in fnames:
5062 f = url.open(ui, fname)
5063 f = url.open(ui, fname)
5063 gen = changegroup.readbundle(f, fname)
5064 gen = changegroup.readbundle(f, fname)
5064 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5065 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5065 lock=lock)
5066 lock=lock)
5066 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5067 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5067 finally:
5068 finally:
5068 lock.release()
5069 lock.release()
5069 return postincoming(ui, repo, modheads, opts.get('update'), None)
5070 return postincoming(ui, repo, modheads, opts.get('update'), None)
5070
5071
5071 @command('^update|up|checkout|co',
5072 @command('^update|up|checkout|co',
5072 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5073 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5073 ('c', 'check', None,
5074 ('c', 'check', None,
5074 _('update across branches if no uncommitted changes')),
5075 _('update across branches if no uncommitted changes')),
5075 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5076 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5076 ('r', 'rev', '', _('revision'), _('REV'))],
5077 ('r', 'rev', '', _('revision'), _('REV'))],
5077 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5078 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5078 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5079 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5079 """update working directory (or switch revisions)
5080 """update working directory (or switch revisions)
5080
5081
5081 Update the repository's working directory to the specified
5082 Update the repository's working directory to the specified
5082 changeset. If no changeset is specified, update to the tip of the
5083 changeset. If no changeset is specified, update to the tip of the
5083 current named branch.
5084 current named branch.
5084
5085
5085 If the changeset is not a descendant of the working directory's
5086 If the changeset is not a descendant of the working directory's
5086 parent, the update is aborted. With the -c/--check option, the
5087 parent, the update is aborted. With the -c/--check option, the
5087 working directory is checked for uncommitted changes; if none are
5088 working directory is checked for uncommitted changes; if none are
5088 found, the working directory is updated to the specified
5089 found, the working directory is updated to the specified
5089 changeset.
5090 changeset.
5090
5091
5091 Update sets the working directory's parent revison to the specified
5092 Update sets the working directory's parent revison to the specified
5092 changeset (see :hg:`help parents`).
5093 changeset (see :hg:`help parents`).
5093
5094
5094 The following rules apply when the working directory contains
5095 The following rules apply when the working directory contains
5095 uncommitted changes:
5096 uncommitted changes:
5096
5097
5097 1. If neither -c/--check nor -C/--clean is specified, and if
5098 1. If neither -c/--check nor -C/--clean is specified, and if
5098 the requested changeset is an ancestor or descendant of
5099 the requested changeset is an ancestor or descendant of
5099 the working directory's parent, the uncommitted changes
5100 the working directory's parent, the uncommitted changes
5100 are merged into the requested changeset and the merged
5101 are merged into the requested changeset and the merged
5101 result is left uncommitted. If the requested changeset is
5102 result is left uncommitted. If the requested changeset is
5102 not an ancestor or descendant (that is, it is on another
5103 not an ancestor or descendant (that is, it is on another
5103 branch), the update is aborted and the uncommitted changes
5104 branch), the update is aborted and the uncommitted changes
5104 are preserved.
5105 are preserved.
5105
5106
5106 2. With the -c/--check option, the update is aborted and the
5107 2. With the -c/--check option, the update is aborted and the
5107 uncommitted changes are preserved.
5108 uncommitted changes are preserved.
5108
5109
5109 3. With the -C/--clean option, uncommitted changes are discarded and
5110 3. With the -C/--clean option, uncommitted changes are discarded and
5110 the working directory is updated to the requested changeset.
5111 the working directory is updated to the requested changeset.
5111
5112
5112 Use null as the changeset to remove the working directory (like
5113 Use null as the changeset to remove the working directory (like
5113 :hg:`clone -U`).
5114 :hg:`clone -U`).
5114
5115
5115 If you want to revert just one file to an older revision, use
5116 If you want to revert just one file to an older revision, use
5116 :hg:`revert [-r REV] NAME`.
5117 :hg:`revert [-r REV] NAME`.
5117
5118
5118 See :hg:`help dates` for a list of formats valid for -d/--date.
5119 See :hg:`help dates` for a list of formats valid for -d/--date.
5119
5120
5120 Returns 0 on success, 1 if there are unresolved files.
5121 Returns 0 on success, 1 if there are unresolved files.
5121 """
5122 """
5122 if rev and node:
5123 if rev and node:
5123 raise util.Abort(_("please specify just one revision"))
5124 raise util.Abort(_("please specify just one revision"))
5124
5125
5125 if rev is None or rev == '':
5126 if rev is None or rev == '':
5126 rev = node
5127 rev = node
5127
5128
5128 # if we defined a bookmark, we have to remember the original bookmark name
5129 # if we defined a bookmark, we have to remember the original bookmark name
5129 brev = rev
5130 brev = rev
5130 rev = scmutil.revsingle(repo, rev, rev).rev()
5131 rev = scmutil.revsingle(repo, rev, rev).rev()
5131
5132
5132 if check and clean:
5133 if check and clean:
5133 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5134 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5134
5135
5135 if check:
5136 if check:
5136 # we could use dirty() but we can ignore merge and branch trivia
5137 # we could use dirty() but we can ignore merge and branch trivia
5137 c = repo[None]
5138 c = repo[None]
5138 if c.modified() or c.added() or c.removed():
5139 if c.modified() or c.added() or c.removed():
5139 raise util.Abort(_("uncommitted local changes"))
5140 raise util.Abort(_("uncommitted local changes"))
5140
5141
5141 if date:
5142 if date:
5142 if rev is not None:
5143 if rev is not None:
5143 raise util.Abort(_("you can't specify a revision and a date"))
5144 raise util.Abort(_("you can't specify a revision and a date"))
5144 rev = cmdutil.finddate(ui, repo, date)
5145 rev = cmdutil.finddate(ui, repo, date)
5145
5146
5146 if clean or check:
5147 if clean or check:
5147 ret = hg.clean(repo, rev)
5148 ret = hg.clean(repo, rev)
5148 else:
5149 else:
5149 ret = hg.update(repo, rev)
5150 ret = hg.update(repo, rev)
5150
5151
5151 if brev in repo._bookmarks:
5152 if brev in repo._bookmarks:
5152 bookmarks.setcurrent(repo, brev)
5153 bookmarks.setcurrent(repo, brev)
5153
5154
5154 return ret
5155 return ret
5155
5156
5156 @command('verify', [])
5157 @command('verify', [])
5157 def verify(ui, repo):
5158 def verify(ui, repo):
5158 """verify the integrity of the repository
5159 """verify the integrity of the repository
5159
5160
5160 Verify the integrity of the current repository.
5161 Verify the integrity of the current repository.
5161
5162
5162 This will perform an extensive check of the repository's
5163 This will perform an extensive check of the repository's
5163 integrity, validating the hashes and checksums of each entry in
5164 integrity, validating the hashes and checksums of each entry in
5164 the changelog, manifest, and tracked files, as well as the
5165 the changelog, manifest, and tracked files, as well as the
5165 integrity of their crosslinks and indices.
5166 integrity of their crosslinks and indices.
5166
5167
5167 Returns 0 on success, 1 if errors are encountered.
5168 Returns 0 on success, 1 if errors are encountered.
5168 """
5169 """
5169 return hg.verify(repo)
5170 return hg.verify(repo)
5170
5171
5171 @command('version', [])
5172 @command('version', [])
5172 def version_(ui):
5173 def version_(ui):
5173 """output version and copyright information"""
5174 """output version and copyright information"""
5174 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5175 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5175 % util.version())
5176 % util.version())
5176 ui.status(_(
5177 ui.status(_(
5177 "(see http://mercurial.selenic.com for more information)\n"
5178 "(see http://mercurial.selenic.com for more information)\n"
5178 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5179 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5179 "This is free software; see the source for copying conditions. "
5180 "This is free software; see the source for copying conditions. "
5180 "There is NO\nwarranty; "
5181 "There is NO\nwarranty; "
5181 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5182 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5182 ))
5183 ))
5183
5184
5184 norepo = ("clone init version help debugcommands debugcomplete"
5185 norepo = ("clone init version help debugcommands debugcomplete"
5185 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5186 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5186 " debugknown debuggetbundle debugbundle")
5187 " debugknown debuggetbundle debugbundle")
5187 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5188 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5188 " debugdata debugindex debugindexdot debugrevlog")
5189 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,110 +1,131 b''
1 $ hg init repo
1 $ hg init repo
2 $ cd repo
2 $ cd repo
3 $ touch foo
3 $ touch foo
4 $ hg add foo
4 $ hg add foo
5 $ for i in 0 1 2 3 4 5 6 7 8 9 10 11; do
5 $ for i in 0 1 2 3 4 5 6 7 8 9 10 11; do
6 > echo "foo-$i" >> foo
6 > echo "foo-$i" >> foo
7 > hg ci -m "foo-$i"
7 > hg ci -m "foo-$i"
8 > done
8 > done
9
9
10 $ for out in "%nof%N" "%%%H" "%b-%R" "%h" "%r"; do
10 $ for out in "%nof%N" "%%%H" "%b-%R" "%h" "%r" "%m"; do
11 > echo
11 > echo
12 > echo "# foo-$out.patch"
12 > echo "# foo-$out.patch"
13 > hg export -v -o "foo-$out.patch" 2:tip
13 > hg export -v -o "foo-$out.patch" 2:tip
14 > done
14 > done
15
15
16 # foo-%nof%N.patch
16 # foo-%nof%N.patch
17 exporting patches:
17 exporting patches:
18 foo-01of10.patch
18 foo-01of10.patch
19 foo-02of10.patch
19 foo-02of10.patch
20 foo-03of10.patch
20 foo-03of10.patch
21 foo-04of10.patch
21 foo-04of10.patch
22 foo-05of10.patch
22 foo-05of10.patch
23 foo-06of10.patch
23 foo-06of10.patch
24 foo-07of10.patch
24 foo-07of10.patch
25 foo-08of10.patch
25 foo-08of10.patch
26 foo-09of10.patch
26 foo-09of10.patch
27 foo-10of10.patch
27 foo-10of10.patch
28
28
29 # foo-%%%H.patch
29 # foo-%%%H.patch
30 exporting patches:
30 exporting patches:
31 foo-%617188a1c80f869a7b66c85134da88a6fb145f67.patch
31 foo-%617188a1c80f869a7b66c85134da88a6fb145f67.patch
32 foo-%dd41a5ff707a5225204105611ba49cc5c229d55f.patch
32 foo-%dd41a5ff707a5225204105611ba49cc5c229d55f.patch
33 foo-%f95a5410f8664b6e1490a4af654e4b7d41a7b321.patch
33 foo-%f95a5410f8664b6e1490a4af654e4b7d41a7b321.patch
34 foo-%4346bcfde53b4d9042489078bcfa9c3e28201db2.patch
34 foo-%4346bcfde53b4d9042489078bcfa9c3e28201db2.patch
35 foo-%afda8c3a009cc99449a05ad8aa4655648c4ecd34.patch
35 foo-%afda8c3a009cc99449a05ad8aa4655648c4ecd34.patch
36 foo-%35284ce2b6b99c9d2ac66268fe99e68e1974e1aa.patch
36 foo-%35284ce2b6b99c9d2ac66268fe99e68e1974e1aa.patch
37 foo-%9688c41894e6931305fa7165a37f6568050b4e9b.patch
37 foo-%9688c41894e6931305fa7165a37f6568050b4e9b.patch
38 foo-%747d3c68f8ec44bb35816bfcd59aeb50b9654c2f.patch
38 foo-%747d3c68f8ec44bb35816bfcd59aeb50b9654c2f.patch
39 foo-%5f17a83f5fbd9414006a5e563eab4c8a00729efd.patch
39 foo-%5f17a83f5fbd9414006a5e563eab4c8a00729efd.patch
40 foo-%f3acbafac161ec68f1598af38f794f28847ca5d3.patch
40 foo-%f3acbafac161ec68f1598af38f794f28847ca5d3.patch
41
41
42 # foo-%b-%R.patch
42 # foo-%b-%R.patch
43 exporting patches:
43 exporting patches:
44 foo-repo-2.patch
44 foo-repo-2.patch
45 foo-repo-3.patch
45 foo-repo-3.patch
46 foo-repo-4.patch
46 foo-repo-4.patch
47 foo-repo-5.patch
47 foo-repo-5.patch
48 foo-repo-6.patch
48 foo-repo-6.patch
49 foo-repo-7.patch
49 foo-repo-7.patch
50 foo-repo-8.patch
50 foo-repo-8.patch
51 foo-repo-9.patch
51 foo-repo-9.patch
52 foo-repo-10.patch
52 foo-repo-10.patch
53 foo-repo-11.patch
53 foo-repo-11.patch
54
54
55 # foo-%h.patch
55 # foo-%h.patch
56 exporting patches:
56 exporting patches:
57 foo-617188a1c80f.patch
57 foo-617188a1c80f.patch
58 foo-dd41a5ff707a.patch
58 foo-dd41a5ff707a.patch
59 foo-f95a5410f866.patch
59 foo-f95a5410f866.patch
60 foo-4346bcfde53b.patch
60 foo-4346bcfde53b.patch
61 foo-afda8c3a009c.patch
61 foo-afda8c3a009c.patch
62 foo-35284ce2b6b9.patch
62 foo-35284ce2b6b9.patch
63 foo-9688c41894e6.patch
63 foo-9688c41894e6.patch
64 foo-747d3c68f8ec.patch
64 foo-747d3c68f8ec.patch
65 foo-5f17a83f5fbd.patch
65 foo-5f17a83f5fbd.patch
66 foo-f3acbafac161.patch
66 foo-f3acbafac161.patch
67
67
68 # foo-%r.patch
68 # foo-%r.patch
69 exporting patches:
69 exporting patches:
70 foo-02.patch
70 foo-02.patch
71 foo-03.patch
71 foo-03.patch
72 foo-04.patch
72 foo-04.patch
73 foo-05.patch
73 foo-05.patch
74 foo-06.patch
74 foo-06.patch
75 foo-07.patch
75 foo-07.patch
76 foo-08.patch
76 foo-08.patch
77 foo-09.patch
77 foo-09.patch
78 foo-10.patch
78 foo-10.patch
79 foo-11.patch
79 foo-11.patch
80
81 # foo-%m.patch
82 exporting patches:
83 foo-foo_2.patch
84 foo-foo_3.patch
85 foo-foo_4.patch
86 foo-foo_5.patch
87 foo-foo_6.patch
88 foo-foo_7.patch
89 foo-foo_8.patch
90 foo-foo_9.patch
91 foo-foo_10.patch
92 foo-foo_11.patch
80
93
81 Exporting 4 changesets to a file:
94 Exporting 4 changesets to a file:
82
95
83 $ hg export -o export_internal 1 2 3 4
96 $ hg export -o export_internal 1 2 3 4
84 $ grep HG export_internal | wc -l
97 $ grep HG export_internal | wc -l
85 \s*4 (re)
98 \s*4 (re)
86
99
87 Exporting 4 changesets to a file:
100 Exporting 4 changesets to a file:
88
101
89 $ hg export 1 2 3 4 | grep HG | wc -l
102 $ hg export 1 2 3 4 | grep HG | wc -l
90 \s*4 (re)
103 \s*4 (re)
91
104
92 Exporting revision -2 to a file:
105 Exporting revision -2 to a file:
93
106
94 $ hg export -- -2
107 $ hg export -- -2
95 # HG changeset patch
108 # HG changeset patch
96 # User test
109 # User test
97 # Date 0 0
110 # Date 0 0
98 # Node ID 5f17a83f5fbd9414006a5e563eab4c8a00729efd
111 # Node ID 5f17a83f5fbd9414006a5e563eab4c8a00729efd
99 # Parent 747d3c68f8ec44bb35816bfcd59aeb50b9654c2f
112 # Parent 747d3c68f8ec44bb35816bfcd59aeb50b9654c2f
100 foo-10
113 foo-10
101
114
102 diff -r 747d3c68f8ec -r 5f17a83f5fbd foo
115 diff -r 747d3c68f8ec -r 5f17a83f5fbd foo
103 --- a/foo Thu Jan 01 00:00:00 1970 +0000
116 --- a/foo Thu Jan 01 00:00:00 1970 +0000
104 +++ b/foo Thu Jan 01 00:00:00 1970 +0000
117 +++ b/foo Thu Jan 01 00:00:00 1970 +0000
105 @@ -8,3 +8,4 @@
118 @@ -8,3 +8,4 @@
106 foo-7
119 foo-7
107 foo-8
120 foo-8
108 foo-9
121 foo-9
109 +foo-10
122 +foo-10
110
123
124 Checking if only alphanumeric characters are used in the file name (%m option):
125
126 $ echo "line" >> foo
127 $ hg commit -m " !\"#$%&(,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\`abcdefghijklmnopqrstuvwxyz{|}~"
128 $ hg export -v -o %m.patch tip
129 exporting patch:
130 ____________0123456789_______ABCDEFGHIJKLMNOPQRSTUVWXYZ______abcdefghijklmnopqrstuvwxyz____.patch
131
General Comments 0
You need to be logged in to leave comments. Login now