##// END OF EJS Templates
debugindex etc.: add --changelog and --manifest options...
Sune Foldager -
r14323:a79fea6b default
parent child Browse files
Show More
@@ -1,1189 +1,1224 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
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(opts):
79 def logmessage(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 = sys.stdin.read()
90 message = sys.stdin.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,
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 }
118 }
119 expander = {
119 expander = {
120 '%': lambda: '%',
120 '%': lambda: '%',
121 'b': lambda: os.path.basename(repo.root),
121 'b': lambda: os.path.basename(repo.root),
122 }
122 }
123
123
124 try:
124 try:
125 if node:
125 if node:
126 expander.update(node_expander)
126 expander.update(node_expander)
127 if node:
127 if node:
128 expander['r'] = (lambda:
128 expander['r'] = (lambda:
129 str(repo.changelog.rev(node)).zfill(revwidth or 0))
129 str(repo.changelog.rev(node)).zfill(revwidth or 0))
130 if total is not None:
130 if total is not None:
131 expander['N'] = lambda: str(total)
131 expander['N'] = lambda: str(total)
132 if seqno is not None:
132 if seqno is not None:
133 expander['n'] = lambda: str(seqno)
133 expander['n'] = lambda: str(seqno)
134 if total is not None and seqno is not None:
134 if total is not None and seqno is not None:
135 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
135 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
136 if pathname is not None:
136 if pathname is not None:
137 expander['s'] = lambda: os.path.basename(pathname)
137 expander['s'] = lambda: os.path.basename(pathname)
138 expander['d'] = lambda: os.path.dirname(pathname) or '.'
138 expander['d'] = lambda: os.path.dirname(pathname) or '.'
139 expander['p'] = lambda: pathname
139 expander['p'] = lambda: pathname
140
140
141 newname = []
141 newname = []
142 patlen = len(pat)
142 patlen = len(pat)
143 i = 0
143 i = 0
144 while i < patlen:
144 while i < patlen:
145 c = pat[i]
145 c = pat[i]
146 if c == '%':
146 if c == '%':
147 i += 1
147 i += 1
148 c = pat[i]
148 c = pat[i]
149 c = expander[c]()
149 c = expander[c]()
150 newname.append(c)
150 newname.append(c)
151 i += 1
151 i += 1
152 return ''.join(newname)
152 return ''.join(newname)
153 except KeyError, inst:
153 except KeyError, inst:
154 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
154 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
155 inst.args[0])
155 inst.args[0])
156
156
157 def makefileobj(repo, pat, node=None, total=None,
157 def makefileobj(repo, pat, node=None, total=None,
158 seqno=None, revwidth=None, mode='wb', pathname=None):
158 seqno=None, revwidth=None, mode='wb', pathname=None):
159
159
160 writable = mode not in ('r', 'rb')
160 writable = mode not in ('r', 'rb')
161
161
162 if not pat or pat == '-':
162 if not pat or pat == '-':
163 fp = writable and sys.stdout or sys.stdin
163 fp = writable and sys.stdout or sys.stdin
164 return os.fdopen(os.dup(fp.fileno()), mode)
164 return os.fdopen(os.dup(fp.fileno()), mode)
165 if hasattr(pat, 'write') and writable:
165 if hasattr(pat, 'write') and writable:
166 return pat
166 return pat
167 if hasattr(pat, 'read') and 'r' in mode:
167 if hasattr(pat, 'read') and 'r' in mode:
168 return pat
168 return pat
169 return open(makefilename(repo, pat, node, total, seqno, revwidth,
169 return open(makefilename(repo, pat, node, total, seqno, revwidth,
170 pathname),
170 pathname),
171 mode)
171 mode)
172
172
173 def openrevlog(repo, cmd, file_, opts):
174 """opens the changelog, manifest, a filelog or a given revlog"""
175 cl = opts['changelog']
176 mf = opts['manifest']
177 msg = None
178 if cl and mf:
179 msg = _('cannot specify --changelog and --manifest at the same time')
180 elif cl or mf:
181 if file_:
182 msg = _('cannot specify filename with --changelog or --manifest')
183 elif not repo:
184 msg = _('cannot specify --changelog or --manifest '
185 'without a repository')
186 if msg:
187 raise util.Abort(msg)
188
189 r = None
190 if repo:
191 if cl:
192 r = repo.changelog
193 elif mf:
194 r = repo.manifest
195 elif file_:
196 filelog = repo.file(file_)
197 if len(filelog):
198 r = filelog
199 if not r:
200 if not file_:
201 raise error.CommandError(cmd, _('invalid arguments'))
202 if not os.path.isfile(file_):
203 raise util.Abort(_("revlog '%s' not found") % file_)
204 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
205 file_[:-2] + ".i")
206 return r
207
173 def copy(ui, repo, pats, opts, rename=False):
208 def copy(ui, repo, pats, opts, rename=False):
174 # called with the repo lock held
209 # called with the repo lock held
175 #
210 #
176 # hgsep => pathname that uses "/" to separate directories
211 # hgsep => pathname that uses "/" to separate directories
177 # ossep => pathname that uses os.sep to separate directories
212 # ossep => pathname that uses os.sep to separate directories
178 cwd = repo.getcwd()
213 cwd = repo.getcwd()
179 targets = {}
214 targets = {}
180 after = opts.get("after")
215 after = opts.get("after")
181 dryrun = opts.get("dry_run")
216 dryrun = opts.get("dry_run")
182 wctx = repo[None]
217 wctx = repo[None]
183
218
184 def walkpat(pat):
219 def walkpat(pat):
185 srcs = []
220 srcs = []
186 badstates = after and '?' or '?r'
221 badstates = after and '?' or '?r'
187 m = scmutil.match(repo, [pat], opts, globbed=True)
222 m = scmutil.match(repo, [pat], opts, globbed=True)
188 for abs in repo.walk(m):
223 for abs in repo.walk(m):
189 state = repo.dirstate[abs]
224 state = repo.dirstate[abs]
190 rel = m.rel(abs)
225 rel = m.rel(abs)
191 exact = m.exact(abs)
226 exact = m.exact(abs)
192 if state in badstates:
227 if state in badstates:
193 if exact and state == '?':
228 if exact and state == '?':
194 ui.warn(_('%s: not copying - file is not managed\n') % rel)
229 ui.warn(_('%s: not copying - file is not managed\n') % rel)
195 if exact and state == 'r':
230 if exact and state == 'r':
196 ui.warn(_('%s: not copying - file has been marked for'
231 ui.warn(_('%s: not copying - file has been marked for'
197 ' remove\n') % rel)
232 ' remove\n') % rel)
198 continue
233 continue
199 # abs: hgsep
234 # abs: hgsep
200 # rel: ossep
235 # rel: ossep
201 srcs.append((abs, rel, exact))
236 srcs.append((abs, rel, exact))
202 return srcs
237 return srcs
203
238
204 # abssrc: hgsep
239 # abssrc: hgsep
205 # relsrc: ossep
240 # relsrc: ossep
206 # otarget: ossep
241 # otarget: ossep
207 def copyfile(abssrc, relsrc, otarget, exact):
242 def copyfile(abssrc, relsrc, otarget, exact):
208 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
243 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
209 reltarget = repo.pathto(abstarget, cwd)
244 reltarget = repo.pathto(abstarget, cwd)
210 target = repo.wjoin(abstarget)
245 target = repo.wjoin(abstarget)
211 src = repo.wjoin(abssrc)
246 src = repo.wjoin(abssrc)
212 state = repo.dirstate[abstarget]
247 state = repo.dirstate[abstarget]
213
248
214 scmutil.checkportable(ui, abstarget)
249 scmutil.checkportable(ui, abstarget)
215
250
216 # check for collisions
251 # check for collisions
217 prevsrc = targets.get(abstarget)
252 prevsrc = targets.get(abstarget)
218 if prevsrc is not None:
253 if prevsrc is not None:
219 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
254 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
220 (reltarget, repo.pathto(abssrc, cwd),
255 (reltarget, repo.pathto(abssrc, cwd),
221 repo.pathto(prevsrc, cwd)))
256 repo.pathto(prevsrc, cwd)))
222 return
257 return
223
258
224 # check for overwrites
259 # check for overwrites
225 exists = os.path.lexists(target)
260 exists = os.path.lexists(target)
226 if not after and exists or after and state in 'mn':
261 if not after and exists or after and state in 'mn':
227 if not opts['force']:
262 if not opts['force']:
228 ui.warn(_('%s: not overwriting - file exists\n') %
263 ui.warn(_('%s: not overwriting - file exists\n') %
229 reltarget)
264 reltarget)
230 return
265 return
231
266
232 if after:
267 if after:
233 if not exists:
268 if not exists:
234 if rename:
269 if rename:
235 ui.warn(_('%s: not recording move - %s does not exist\n') %
270 ui.warn(_('%s: not recording move - %s does not exist\n') %
236 (relsrc, reltarget))
271 (relsrc, reltarget))
237 else:
272 else:
238 ui.warn(_('%s: not recording copy - %s does not exist\n') %
273 ui.warn(_('%s: not recording copy - %s does not exist\n') %
239 (relsrc, reltarget))
274 (relsrc, reltarget))
240 return
275 return
241 elif not dryrun:
276 elif not dryrun:
242 try:
277 try:
243 if exists:
278 if exists:
244 os.unlink(target)
279 os.unlink(target)
245 targetdir = os.path.dirname(target) or '.'
280 targetdir = os.path.dirname(target) or '.'
246 if not os.path.isdir(targetdir):
281 if not os.path.isdir(targetdir):
247 os.makedirs(targetdir)
282 os.makedirs(targetdir)
248 util.copyfile(src, target)
283 util.copyfile(src, target)
249 except IOError, inst:
284 except IOError, inst:
250 if inst.errno == errno.ENOENT:
285 if inst.errno == errno.ENOENT:
251 ui.warn(_('%s: deleted in working copy\n') % relsrc)
286 ui.warn(_('%s: deleted in working copy\n') % relsrc)
252 else:
287 else:
253 ui.warn(_('%s: cannot copy - %s\n') %
288 ui.warn(_('%s: cannot copy - %s\n') %
254 (relsrc, inst.strerror))
289 (relsrc, inst.strerror))
255 return True # report a failure
290 return True # report a failure
256
291
257 if ui.verbose or not exact:
292 if ui.verbose or not exact:
258 if rename:
293 if rename:
259 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
294 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
260 else:
295 else:
261 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
296 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
262
297
263 targets[abstarget] = abssrc
298 targets[abstarget] = abssrc
264
299
265 # fix up dirstate
300 # fix up dirstate
266 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
301 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
267 dryrun=dryrun, cwd=cwd)
302 dryrun=dryrun, cwd=cwd)
268 if rename and not dryrun:
303 if rename and not dryrun:
269 wctx.remove([abssrc], not after)
304 wctx.remove([abssrc], not after)
270
305
271 # pat: ossep
306 # pat: ossep
272 # dest ossep
307 # dest ossep
273 # srcs: list of (hgsep, hgsep, ossep, bool)
308 # srcs: list of (hgsep, hgsep, ossep, bool)
274 # return: function that takes hgsep and returns ossep
309 # return: function that takes hgsep and returns ossep
275 def targetpathfn(pat, dest, srcs):
310 def targetpathfn(pat, dest, srcs):
276 if os.path.isdir(pat):
311 if os.path.isdir(pat):
277 abspfx = scmutil.canonpath(repo.root, cwd, pat)
312 abspfx = scmutil.canonpath(repo.root, cwd, pat)
278 abspfx = util.localpath(abspfx)
313 abspfx = util.localpath(abspfx)
279 if destdirexists:
314 if destdirexists:
280 striplen = len(os.path.split(abspfx)[0])
315 striplen = len(os.path.split(abspfx)[0])
281 else:
316 else:
282 striplen = len(abspfx)
317 striplen = len(abspfx)
283 if striplen:
318 if striplen:
284 striplen += len(os.sep)
319 striplen += len(os.sep)
285 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
320 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
286 elif destdirexists:
321 elif destdirexists:
287 res = lambda p: os.path.join(dest,
322 res = lambda p: os.path.join(dest,
288 os.path.basename(util.localpath(p)))
323 os.path.basename(util.localpath(p)))
289 else:
324 else:
290 res = lambda p: dest
325 res = lambda p: dest
291 return res
326 return res
292
327
293 # pat: ossep
328 # pat: ossep
294 # dest ossep
329 # dest ossep
295 # srcs: list of (hgsep, hgsep, ossep, bool)
330 # srcs: list of (hgsep, hgsep, ossep, bool)
296 # return: function that takes hgsep and returns ossep
331 # return: function that takes hgsep and returns ossep
297 def targetpathafterfn(pat, dest, srcs):
332 def targetpathafterfn(pat, dest, srcs):
298 if matchmod.patkind(pat):
333 if matchmod.patkind(pat):
299 # a mercurial pattern
334 # a mercurial pattern
300 res = lambda p: os.path.join(dest,
335 res = lambda p: os.path.join(dest,
301 os.path.basename(util.localpath(p)))
336 os.path.basename(util.localpath(p)))
302 else:
337 else:
303 abspfx = scmutil.canonpath(repo.root, cwd, pat)
338 abspfx = scmutil.canonpath(repo.root, cwd, pat)
304 if len(abspfx) < len(srcs[0][0]):
339 if len(abspfx) < len(srcs[0][0]):
305 # A directory. Either the target path contains the last
340 # A directory. Either the target path contains the last
306 # component of the source path or it does not.
341 # component of the source path or it does not.
307 def evalpath(striplen):
342 def evalpath(striplen):
308 score = 0
343 score = 0
309 for s in srcs:
344 for s in srcs:
310 t = os.path.join(dest, util.localpath(s[0])[striplen:])
345 t = os.path.join(dest, util.localpath(s[0])[striplen:])
311 if os.path.lexists(t):
346 if os.path.lexists(t):
312 score += 1
347 score += 1
313 return score
348 return score
314
349
315 abspfx = util.localpath(abspfx)
350 abspfx = util.localpath(abspfx)
316 striplen = len(abspfx)
351 striplen = len(abspfx)
317 if striplen:
352 if striplen:
318 striplen += len(os.sep)
353 striplen += len(os.sep)
319 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
354 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
320 score = evalpath(striplen)
355 score = evalpath(striplen)
321 striplen1 = len(os.path.split(abspfx)[0])
356 striplen1 = len(os.path.split(abspfx)[0])
322 if striplen1:
357 if striplen1:
323 striplen1 += len(os.sep)
358 striplen1 += len(os.sep)
324 if evalpath(striplen1) > score:
359 if evalpath(striplen1) > score:
325 striplen = striplen1
360 striplen = striplen1
326 res = lambda p: os.path.join(dest,
361 res = lambda p: os.path.join(dest,
327 util.localpath(p)[striplen:])
362 util.localpath(p)[striplen:])
328 else:
363 else:
329 # a file
364 # a file
330 if destdirexists:
365 if destdirexists:
331 res = lambda p: os.path.join(dest,
366 res = lambda p: os.path.join(dest,
332 os.path.basename(util.localpath(p)))
367 os.path.basename(util.localpath(p)))
333 else:
368 else:
334 res = lambda p: dest
369 res = lambda p: dest
335 return res
370 return res
336
371
337
372
338 pats = scmutil.expandpats(pats)
373 pats = scmutil.expandpats(pats)
339 if not pats:
374 if not pats:
340 raise util.Abort(_('no source or destination specified'))
375 raise util.Abort(_('no source or destination specified'))
341 if len(pats) == 1:
376 if len(pats) == 1:
342 raise util.Abort(_('no destination specified'))
377 raise util.Abort(_('no destination specified'))
343 dest = pats.pop()
378 dest = pats.pop()
344 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
379 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
345 if not destdirexists:
380 if not destdirexists:
346 if len(pats) > 1 or matchmod.patkind(pats[0]):
381 if len(pats) > 1 or matchmod.patkind(pats[0]):
347 raise util.Abort(_('with multiple sources, destination must be an '
382 raise util.Abort(_('with multiple sources, destination must be an '
348 'existing directory'))
383 'existing directory'))
349 if util.endswithsep(dest):
384 if util.endswithsep(dest):
350 raise util.Abort(_('destination %s is not a directory') % dest)
385 raise util.Abort(_('destination %s is not a directory') % dest)
351
386
352 tfn = targetpathfn
387 tfn = targetpathfn
353 if after:
388 if after:
354 tfn = targetpathafterfn
389 tfn = targetpathafterfn
355 copylist = []
390 copylist = []
356 for pat in pats:
391 for pat in pats:
357 srcs = walkpat(pat)
392 srcs = walkpat(pat)
358 if not srcs:
393 if not srcs:
359 continue
394 continue
360 copylist.append((tfn(pat, dest, srcs), srcs))
395 copylist.append((tfn(pat, dest, srcs), srcs))
361 if not copylist:
396 if not copylist:
362 raise util.Abort(_('no files to copy'))
397 raise util.Abort(_('no files to copy'))
363
398
364 errors = 0
399 errors = 0
365 for targetpath, srcs in copylist:
400 for targetpath, srcs in copylist:
366 for abssrc, relsrc, exact in srcs:
401 for abssrc, relsrc, exact in srcs:
367 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
402 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
368 errors += 1
403 errors += 1
369
404
370 if errors:
405 if errors:
371 ui.warn(_('(consider using --after)\n'))
406 ui.warn(_('(consider using --after)\n'))
372
407
373 return errors != 0
408 return errors != 0
374
409
375 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
410 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
376 runargs=None, appendpid=False):
411 runargs=None, appendpid=False):
377 '''Run a command as a service.'''
412 '''Run a command as a service.'''
378
413
379 if opts['daemon'] and not opts['daemon_pipefds']:
414 if opts['daemon'] and not opts['daemon_pipefds']:
380 # Signal child process startup with file removal
415 # Signal child process startup with file removal
381 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
416 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
382 os.close(lockfd)
417 os.close(lockfd)
383 try:
418 try:
384 if not runargs:
419 if not runargs:
385 runargs = util.hgcmd() + sys.argv[1:]
420 runargs = util.hgcmd() + sys.argv[1:]
386 runargs.append('--daemon-pipefds=%s' % lockpath)
421 runargs.append('--daemon-pipefds=%s' % lockpath)
387 # Don't pass --cwd to the child process, because we've already
422 # Don't pass --cwd to the child process, because we've already
388 # changed directory.
423 # changed directory.
389 for i in xrange(1, len(runargs)):
424 for i in xrange(1, len(runargs)):
390 if runargs[i].startswith('--cwd='):
425 if runargs[i].startswith('--cwd='):
391 del runargs[i]
426 del runargs[i]
392 break
427 break
393 elif runargs[i].startswith('--cwd'):
428 elif runargs[i].startswith('--cwd'):
394 del runargs[i:i + 2]
429 del runargs[i:i + 2]
395 break
430 break
396 def condfn():
431 def condfn():
397 return not os.path.exists(lockpath)
432 return not os.path.exists(lockpath)
398 pid = util.rundetached(runargs, condfn)
433 pid = util.rundetached(runargs, condfn)
399 if pid < 0:
434 if pid < 0:
400 raise util.Abort(_('child process failed to start'))
435 raise util.Abort(_('child process failed to start'))
401 finally:
436 finally:
402 try:
437 try:
403 os.unlink(lockpath)
438 os.unlink(lockpath)
404 except OSError, e:
439 except OSError, e:
405 if e.errno != errno.ENOENT:
440 if e.errno != errno.ENOENT:
406 raise
441 raise
407 if parentfn:
442 if parentfn:
408 return parentfn(pid)
443 return parentfn(pid)
409 else:
444 else:
410 return
445 return
411
446
412 if initfn:
447 if initfn:
413 initfn()
448 initfn()
414
449
415 if opts['pid_file']:
450 if opts['pid_file']:
416 mode = appendpid and 'a' or 'w'
451 mode = appendpid and 'a' or 'w'
417 fp = open(opts['pid_file'], mode)
452 fp = open(opts['pid_file'], mode)
418 fp.write(str(os.getpid()) + '\n')
453 fp.write(str(os.getpid()) + '\n')
419 fp.close()
454 fp.close()
420
455
421 if opts['daemon_pipefds']:
456 if opts['daemon_pipefds']:
422 lockpath = opts['daemon_pipefds']
457 lockpath = opts['daemon_pipefds']
423 try:
458 try:
424 os.setsid()
459 os.setsid()
425 except AttributeError:
460 except AttributeError:
426 pass
461 pass
427 os.unlink(lockpath)
462 os.unlink(lockpath)
428 util.hidewindow()
463 util.hidewindow()
429 sys.stdout.flush()
464 sys.stdout.flush()
430 sys.stderr.flush()
465 sys.stderr.flush()
431
466
432 nullfd = os.open(util.nulldev, os.O_RDWR)
467 nullfd = os.open(util.nulldev, os.O_RDWR)
433 logfilefd = nullfd
468 logfilefd = nullfd
434 if logfile:
469 if logfile:
435 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
470 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
436 os.dup2(nullfd, 0)
471 os.dup2(nullfd, 0)
437 os.dup2(logfilefd, 1)
472 os.dup2(logfilefd, 1)
438 os.dup2(logfilefd, 2)
473 os.dup2(logfilefd, 2)
439 if nullfd not in (0, 1, 2):
474 if nullfd not in (0, 1, 2):
440 os.close(nullfd)
475 os.close(nullfd)
441 if logfile and logfilefd not in (0, 1, 2):
476 if logfile and logfilefd not in (0, 1, 2):
442 os.close(logfilefd)
477 os.close(logfilefd)
443
478
444 if runfn:
479 if runfn:
445 return runfn()
480 return runfn()
446
481
447 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
482 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
448 opts=None):
483 opts=None):
449 '''export changesets as hg patches.'''
484 '''export changesets as hg patches.'''
450
485
451 total = len(revs)
486 total = len(revs)
452 revwidth = max([len(str(rev)) for rev in revs])
487 revwidth = max([len(str(rev)) for rev in revs])
453
488
454 def single(rev, seqno, fp):
489 def single(rev, seqno, fp):
455 ctx = repo[rev]
490 ctx = repo[rev]
456 node = ctx.node()
491 node = ctx.node()
457 parents = [p.node() for p in ctx.parents() if p]
492 parents = [p.node() for p in ctx.parents() if p]
458 branch = ctx.branch()
493 branch = ctx.branch()
459 if switch_parent:
494 if switch_parent:
460 parents.reverse()
495 parents.reverse()
461 prev = (parents and parents[0]) or nullid
496 prev = (parents and parents[0]) or nullid
462
497
463 shouldclose = False
498 shouldclose = False
464 if not fp:
499 if not fp:
465 fp = makefileobj(repo, template, node, total=total, seqno=seqno,
500 fp = makefileobj(repo, template, node, total=total, seqno=seqno,
466 revwidth=revwidth, mode='ab')
501 revwidth=revwidth, mode='ab')
467 if fp != template:
502 if fp != template:
468 shouldclose = True
503 shouldclose = True
469 if fp != sys.stdout and hasattr(fp, 'name'):
504 if fp != sys.stdout and hasattr(fp, 'name'):
470 repo.ui.note("%s\n" % fp.name)
505 repo.ui.note("%s\n" % fp.name)
471
506
472 fp.write("# HG changeset patch\n")
507 fp.write("# HG changeset patch\n")
473 fp.write("# User %s\n" % ctx.user())
508 fp.write("# User %s\n" % ctx.user())
474 fp.write("# Date %d %d\n" % ctx.date())
509 fp.write("# Date %d %d\n" % ctx.date())
475 if branch and branch != 'default':
510 if branch and branch != 'default':
476 fp.write("# Branch %s\n" % branch)
511 fp.write("# Branch %s\n" % branch)
477 fp.write("# Node ID %s\n" % hex(node))
512 fp.write("# Node ID %s\n" % hex(node))
478 fp.write("# Parent %s\n" % hex(prev))
513 fp.write("# Parent %s\n" % hex(prev))
479 if len(parents) > 1:
514 if len(parents) > 1:
480 fp.write("# Parent %s\n" % hex(parents[1]))
515 fp.write("# Parent %s\n" % hex(parents[1]))
481 fp.write(ctx.description().rstrip())
516 fp.write(ctx.description().rstrip())
482 fp.write("\n\n")
517 fp.write("\n\n")
483
518
484 for chunk in patch.diff(repo, prev, node, opts=opts):
519 for chunk in patch.diff(repo, prev, node, opts=opts):
485 fp.write(chunk)
520 fp.write(chunk)
486
521
487 if shouldclose:
522 if shouldclose:
488 fp.close()
523 fp.close()
489
524
490 for seqno, rev in enumerate(revs):
525 for seqno, rev in enumerate(revs):
491 single(rev, seqno + 1, fp)
526 single(rev, seqno + 1, fp)
492
527
493 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
528 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
494 changes=None, stat=False, fp=None, prefix='',
529 changes=None, stat=False, fp=None, prefix='',
495 listsubrepos=False):
530 listsubrepos=False):
496 '''show diff or diffstat.'''
531 '''show diff or diffstat.'''
497 if fp is None:
532 if fp is None:
498 write = ui.write
533 write = ui.write
499 else:
534 else:
500 def write(s, **kw):
535 def write(s, **kw):
501 fp.write(s)
536 fp.write(s)
502
537
503 if stat:
538 if stat:
504 diffopts = diffopts.copy(context=0)
539 diffopts = diffopts.copy(context=0)
505 width = 80
540 width = 80
506 if not ui.plain():
541 if not ui.plain():
507 width = ui.termwidth()
542 width = ui.termwidth()
508 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
543 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
509 prefix=prefix)
544 prefix=prefix)
510 for chunk, label in patch.diffstatui(util.iterlines(chunks),
545 for chunk, label in patch.diffstatui(util.iterlines(chunks),
511 width=width,
546 width=width,
512 git=diffopts.git):
547 git=diffopts.git):
513 write(chunk, label=label)
548 write(chunk, label=label)
514 else:
549 else:
515 for chunk, label in patch.diffui(repo, node1, node2, match,
550 for chunk, label in patch.diffui(repo, node1, node2, match,
516 changes, diffopts, prefix=prefix):
551 changes, diffopts, prefix=prefix):
517 write(chunk, label=label)
552 write(chunk, label=label)
518
553
519 if listsubrepos:
554 if listsubrepos:
520 ctx1 = repo[node1]
555 ctx1 = repo[node1]
521 ctx2 = repo[node2]
556 ctx2 = repo[node2]
522 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
557 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
523 if node2 is not None:
558 if node2 is not None:
524 node2 = ctx2.substate[subpath][1]
559 node2 = ctx2.substate[subpath][1]
525 submatch = matchmod.narrowmatcher(subpath, match)
560 submatch = matchmod.narrowmatcher(subpath, match)
526 sub.diff(diffopts, node2, submatch, changes=changes,
561 sub.diff(diffopts, node2, submatch, changes=changes,
527 stat=stat, fp=fp, prefix=prefix)
562 stat=stat, fp=fp, prefix=prefix)
528
563
529 class changeset_printer(object):
564 class changeset_printer(object):
530 '''show changeset information when templating not requested.'''
565 '''show changeset information when templating not requested.'''
531
566
532 def __init__(self, ui, repo, patch, diffopts, buffered):
567 def __init__(self, ui, repo, patch, diffopts, buffered):
533 self.ui = ui
568 self.ui = ui
534 self.repo = repo
569 self.repo = repo
535 self.buffered = buffered
570 self.buffered = buffered
536 self.patch = patch
571 self.patch = patch
537 self.diffopts = diffopts
572 self.diffopts = diffopts
538 self.header = {}
573 self.header = {}
539 self.hunk = {}
574 self.hunk = {}
540 self.lastheader = None
575 self.lastheader = None
541 self.footer = None
576 self.footer = None
542
577
543 def flush(self, rev):
578 def flush(self, rev):
544 if rev in self.header:
579 if rev in self.header:
545 h = self.header[rev]
580 h = self.header[rev]
546 if h != self.lastheader:
581 if h != self.lastheader:
547 self.lastheader = h
582 self.lastheader = h
548 self.ui.write(h)
583 self.ui.write(h)
549 del self.header[rev]
584 del self.header[rev]
550 if rev in self.hunk:
585 if rev in self.hunk:
551 self.ui.write(self.hunk[rev])
586 self.ui.write(self.hunk[rev])
552 del self.hunk[rev]
587 del self.hunk[rev]
553 return 1
588 return 1
554 return 0
589 return 0
555
590
556 def close(self):
591 def close(self):
557 if self.footer:
592 if self.footer:
558 self.ui.write(self.footer)
593 self.ui.write(self.footer)
559
594
560 def show(self, ctx, copies=None, matchfn=None, **props):
595 def show(self, ctx, copies=None, matchfn=None, **props):
561 if self.buffered:
596 if self.buffered:
562 self.ui.pushbuffer()
597 self.ui.pushbuffer()
563 self._show(ctx, copies, matchfn, props)
598 self._show(ctx, copies, matchfn, props)
564 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
599 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
565 else:
600 else:
566 self._show(ctx, copies, matchfn, props)
601 self._show(ctx, copies, matchfn, props)
567
602
568 def _show(self, ctx, copies, matchfn, props):
603 def _show(self, ctx, copies, matchfn, props):
569 '''show a single changeset or file revision'''
604 '''show a single changeset or file revision'''
570 changenode = ctx.node()
605 changenode = ctx.node()
571 rev = ctx.rev()
606 rev = ctx.rev()
572
607
573 if self.ui.quiet:
608 if self.ui.quiet:
574 self.ui.write("%d:%s\n" % (rev, short(changenode)),
609 self.ui.write("%d:%s\n" % (rev, short(changenode)),
575 label='log.node')
610 label='log.node')
576 return
611 return
577
612
578 log = self.repo.changelog
613 log = self.repo.changelog
579 date = util.datestr(ctx.date())
614 date = util.datestr(ctx.date())
580
615
581 hexfunc = self.ui.debugflag and hex or short
616 hexfunc = self.ui.debugflag and hex or short
582
617
583 parents = [(p, hexfunc(log.node(p)))
618 parents = [(p, hexfunc(log.node(p)))
584 for p in self._meaningful_parentrevs(log, rev)]
619 for p in self._meaningful_parentrevs(log, rev)]
585
620
586 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
621 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
587 label='log.changeset')
622 label='log.changeset')
588
623
589 branch = ctx.branch()
624 branch = ctx.branch()
590 # don't show the default branch name
625 # don't show the default branch name
591 if branch != 'default':
626 if branch != 'default':
592 self.ui.write(_("branch: %s\n") % branch,
627 self.ui.write(_("branch: %s\n") % branch,
593 label='log.branch')
628 label='log.branch')
594 for bookmark in self.repo.nodebookmarks(changenode):
629 for bookmark in self.repo.nodebookmarks(changenode):
595 self.ui.write(_("bookmark: %s\n") % bookmark,
630 self.ui.write(_("bookmark: %s\n") % bookmark,
596 label='log.bookmark')
631 label='log.bookmark')
597 for tag in self.repo.nodetags(changenode):
632 for tag in self.repo.nodetags(changenode):
598 self.ui.write(_("tag: %s\n") % tag,
633 self.ui.write(_("tag: %s\n") % tag,
599 label='log.tag')
634 label='log.tag')
600 for parent in parents:
635 for parent in parents:
601 self.ui.write(_("parent: %d:%s\n") % parent,
636 self.ui.write(_("parent: %d:%s\n") % parent,
602 label='log.parent')
637 label='log.parent')
603
638
604 if self.ui.debugflag:
639 if self.ui.debugflag:
605 mnode = ctx.manifestnode()
640 mnode = ctx.manifestnode()
606 self.ui.write(_("manifest: %d:%s\n") %
641 self.ui.write(_("manifest: %d:%s\n") %
607 (self.repo.manifest.rev(mnode), hex(mnode)),
642 (self.repo.manifest.rev(mnode), hex(mnode)),
608 label='ui.debug log.manifest')
643 label='ui.debug log.manifest')
609 self.ui.write(_("user: %s\n") % ctx.user(),
644 self.ui.write(_("user: %s\n") % ctx.user(),
610 label='log.user')
645 label='log.user')
611 self.ui.write(_("date: %s\n") % date,
646 self.ui.write(_("date: %s\n") % date,
612 label='log.date')
647 label='log.date')
613
648
614 if self.ui.debugflag:
649 if self.ui.debugflag:
615 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
650 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
616 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
651 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
617 files):
652 files):
618 if value:
653 if value:
619 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
654 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
620 label='ui.debug log.files')
655 label='ui.debug log.files')
621 elif ctx.files() and self.ui.verbose:
656 elif ctx.files() and self.ui.verbose:
622 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
657 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
623 label='ui.note log.files')
658 label='ui.note log.files')
624 if copies and self.ui.verbose:
659 if copies and self.ui.verbose:
625 copies = ['%s (%s)' % c for c in copies]
660 copies = ['%s (%s)' % c for c in copies]
626 self.ui.write(_("copies: %s\n") % ' '.join(copies),
661 self.ui.write(_("copies: %s\n") % ' '.join(copies),
627 label='ui.note log.copies')
662 label='ui.note log.copies')
628
663
629 extra = ctx.extra()
664 extra = ctx.extra()
630 if extra and self.ui.debugflag:
665 if extra and self.ui.debugflag:
631 for key, value in sorted(extra.items()):
666 for key, value in sorted(extra.items()):
632 self.ui.write(_("extra: %s=%s\n")
667 self.ui.write(_("extra: %s=%s\n")
633 % (key, value.encode('string_escape')),
668 % (key, value.encode('string_escape')),
634 label='ui.debug log.extra')
669 label='ui.debug log.extra')
635
670
636 description = ctx.description().strip()
671 description = ctx.description().strip()
637 if description:
672 if description:
638 if self.ui.verbose:
673 if self.ui.verbose:
639 self.ui.write(_("description:\n"),
674 self.ui.write(_("description:\n"),
640 label='ui.note log.description')
675 label='ui.note log.description')
641 self.ui.write(description,
676 self.ui.write(description,
642 label='ui.note log.description')
677 label='ui.note log.description')
643 self.ui.write("\n\n")
678 self.ui.write("\n\n")
644 else:
679 else:
645 self.ui.write(_("summary: %s\n") %
680 self.ui.write(_("summary: %s\n") %
646 description.splitlines()[0],
681 description.splitlines()[0],
647 label='log.summary')
682 label='log.summary')
648 self.ui.write("\n")
683 self.ui.write("\n")
649
684
650 self.showpatch(changenode, matchfn)
685 self.showpatch(changenode, matchfn)
651
686
652 def showpatch(self, node, matchfn):
687 def showpatch(self, node, matchfn):
653 if not matchfn:
688 if not matchfn:
654 matchfn = self.patch
689 matchfn = self.patch
655 if matchfn:
690 if matchfn:
656 stat = self.diffopts.get('stat')
691 stat = self.diffopts.get('stat')
657 diff = self.diffopts.get('patch')
692 diff = self.diffopts.get('patch')
658 diffopts = patch.diffopts(self.ui, self.diffopts)
693 diffopts = patch.diffopts(self.ui, self.diffopts)
659 prev = self.repo.changelog.parents(node)[0]
694 prev = self.repo.changelog.parents(node)[0]
660 if stat:
695 if stat:
661 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
696 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
662 match=matchfn, stat=True)
697 match=matchfn, stat=True)
663 if diff:
698 if diff:
664 if stat:
699 if stat:
665 self.ui.write("\n")
700 self.ui.write("\n")
666 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
701 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
667 match=matchfn, stat=False)
702 match=matchfn, stat=False)
668 self.ui.write("\n")
703 self.ui.write("\n")
669
704
670 def _meaningful_parentrevs(self, log, rev):
705 def _meaningful_parentrevs(self, log, rev):
671 """Return list of meaningful (or all if debug) parentrevs for rev.
706 """Return list of meaningful (or all if debug) parentrevs for rev.
672
707
673 For merges (two non-nullrev revisions) both parents are meaningful.
708 For merges (two non-nullrev revisions) both parents are meaningful.
674 Otherwise the first parent revision is considered meaningful if it
709 Otherwise the first parent revision is considered meaningful if it
675 is not the preceding revision.
710 is not the preceding revision.
676 """
711 """
677 parents = log.parentrevs(rev)
712 parents = log.parentrevs(rev)
678 if not self.ui.debugflag and parents[1] == nullrev:
713 if not self.ui.debugflag and parents[1] == nullrev:
679 if parents[0] >= rev - 1:
714 if parents[0] >= rev - 1:
680 parents = []
715 parents = []
681 else:
716 else:
682 parents = [parents[0]]
717 parents = [parents[0]]
683 return parents
718 return parents
684
719
685
720
686 class changeset_templater(changeset_printer):
721 class changeset_templater(changeset_printer):
687 '''format changeset information.'''
722 '''format changeset information.'''
688
723
689 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
724 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
690 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
725 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
691 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
726 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
692 defaulttempl = {
727 defaulttempl = {
693 'parent': '{rev}:{node|formatnode} ',
728 'parent': '{rev}:{node|formatnode} ',
694 'manifest': '{rev}:{node|formatnode}',
729 'manifest': '{rev}:{node|formatnode}',
695 'file_copy': '{name} ({source})',
730 'file_copy': '{name} ({source})',
696 'extra': '{key}={value|stringescape}'
731 'extra': '{key}={value|stringescape}'
697 }
732 }
698 # filecopy is preserved for compatibility reasons
733 # filecopy is preserved for compatibility reasons
699 defaulttempl['filecopy'] = defaulttempl['file_copy']
734 defaulttempl['filecopy'] = defaulttempl['file_copy']
700 self.t = templater.templater(mapfile, {'formatnode': formatnode},
735 self.t = templater.templater(mapfile, {'formatnode': formatnode},
701 cache=defaulttempl)
736 cache=defaulttempl)
702 self.cache = {}
737 self.cache = {}
703
738
704 def use_template(self, t):
739 def use_template(self, t):
705 '''set template string to use'''
740 '''set template string to use'''
706 self.t.cache['changeset'] = t
741 self.t.cache['changeset'] = t
707
742
708 def _meaningful_parentrevs(self, ctx):
743 def _meaningful_parentrevs(self, ctx):
709 """Return list of meaningful (or all if debug) parentrevs for rev.
744 """Return list of meaningful (or all if debug) parentrevs for rev.
710 """
745 """
711 parents = ctx.parents()
746 parents = ctx.parents()
712 if len(parents) > 1:
747 if len(parents) > 1:
713 return parents
748 return parents
714 if self.ui.debugflag:
749 if self.ui.debugflag:
715 return [parents[0], self.repo['null']]
750 return [parents[0], self.repo['null']]
716 if parents[0].rev() >= ctx.rev() - 1:
751 if parents[0].rev() >= ctx.rev() - 1:
717 return []
752 return []
718 return parents
753 return parents
719
754
720 def _show(self, ctx, copies, matchfn, props):
755 def _show(self, ctx, copies, matchfn, props):
721 '''show a single changeset or file revision'''
756 '''show a single changeset or file revision'''
722
757
723 showlist = templatekw.showlist
758 showlist = templatekw.showlist
724
759
725 # showparents() behaviour depends on ui trace level which
760 # showparents() behaviour depends on ui trace level which
726 # causes unexpected behaviours at templating level and makes
761 # causes unexpected behaviours at templating level and makes
727 # it harder to extract it in a standalone function. Its
762 # it harder to extract it in a standalone function. Its
728 # behaviour cannot be changed so leave it here for now.
763 # behaviour cannot be changed so leave it here for now.
729 def showparents(**args):
764 def showparents(**args):
730 ctx = args['ctx']
765 ctx = args['ctx']
731 parents = [[('rev', p.rev()), ('node', p.hex())]
766 parents = [[('rev', p.rev()), ('node', p.hex())]
732 for p in self._meaningful_parentrevs(ctx)]
767 for p in self._meaningful_parentrevs(ctx)]
733 return showlist('parent', parents, **args)
768 return showlist('parent', parents, **args)
734
769
735 props = props.copy()
770 props = props.copy()
736 props.update(templatekw.keywords)
771 props.update(templatekw.keywords)
737 props['parents'] = showparents
772 props['parents'] = showparents
738 props['templ'] = self.t
773 props['templ'] = self.t
739 props['ctx'] = ctx
774 props['ctx'] = ctx
740 props['repo'] = self.repo
775 props['repo'] = self.repo
741 props['revcache'] = {'copies': copies}
776 props['revcache'] = {'copies': copies}
742 props['cache'] = self.cache
777 props['cache'] = self.cache
743
778
744 # find correct templates for current mode
779 # find correct templates for current mode
745
780
746 tmplmodes = [
781 tmplmodes = [
747 (True, None),
782 (True, None),
748 (self.ui.verbose, 'verbose'),
783 (self.ui.verbose, 'verbose'),
749 (self.ui.quiet, 'quiet'),
784 (self.ui.quiet, 'quiet'),
750 (self.ui.debugflag, 'debug'),
785 (self.ui.debugflag, 'debug'),
751 ]
786 ]
752
787
753 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
788 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
754 for mode, postfix in tmplmodes:
789 for mode, postfix in tmplmodes:
755 for type in types:
790 for type in types:
756 cur = postfix and ('%s_%s' % (type, postfix)) or type
791 cur = postfix and ('%s_%s' % (type, postfix)) or type
757 if mode and cur in self.t:
792 if mode and cur in self.t:
758 types[type] = cur
793 types[type] = cur
759
794
760 try:
795 try:
761
796
762 # write header
797 # write header
763 if types['header']:
798 if types['header']:
764 h = templater.stringify(self.t(types['header'], **props))
799 h = templater.stringify(self.t(types['header'], **props))
765 if self.buffered:
800 if self.buffered:
766 self.header[ctx.rev()] = h
801 self.header[ctx.rev()] = h
767 else:
802 else:
768 if self.lastheader != h:
803 if self.lastheader != h:
769 self.lastheader = h
804 self.lastheader = h
770 self.ui.write(h)
805 self.ui.write(h)
771
806
772 # write changeset metadata, then patch if requested
807 # write changeset metadata, then patch if requested
773 key = types['changeset']
808 key = types['changeset']
774 self.ui.write(templater.stringify(self.t(key, **props)))
809 self.ui.write(templater.stringify(self.t(key, **props)))
775 self.showpatch(ctx.node(), matchfn)
810 self.showpatch(ctx.node(), matchfn)
776
811
777 if types['footer']:
812 if types['footer']:
778 if not self.footer:
813 if not self.footer:
779 self.footer = templater.stringify(self.t(types['footer'],
814 self.footer = templater.stringify(self.t(types['footer'],
780 **props))
815 **props))
781
816
782 except KeyError, inst:
817 except KeyError, inst:
783 msg = _("%s: no key named '%s'")
818 msg = _("%s: no key named '%s'")
784 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
819 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
785 except SyntaxError, inst:
820 except SyntaxError, inst:
786 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
821 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
787
822
788 def show_changeset(ui, repo, opts, buffered=False):
823 def show_changeset(ui, repo, opts, buffered=False):
789 """show one changeset using template or regular display.
824 """show one changeset using template or regular display.
790
825
791 Display format will be the first non-empty hit of:
826 Display format will be the first non-empty hit of:
792 1. option 'template'
827 1. option 'template'
793 2. option 'style'
828 2. option 'style'
794 3. [ui] setting 'logtemplate'
829 3. [ui] setting 'logtemplate'
795 4. [ui] setting 'style'
830 4. [ui] setting 'style'
796 If all of these values are either the unset or the empty string,
831 If all of these values are either the unset or the empty string,
797 regular display via changeset_printer() is done.
832 regular display via changeset_printer() is done.
798 """
833 """
799 # options
834 # options
800 patch = False
835 patch = False
801 if opts.get('patch') or opts.get('stat'):
836 if opts.get('patch') or opts.get('stat'):
802 patch = scmutil.matchall(repo)
837 patch = scmutil.matchall(repo)
803
838
804 tmpl = opts.get('template')
839 tmpl = opts.get('template')
805 style = None
840 style = None
806 if tmpl:
841 if tmpl:
807 tmpl = templater.parsestring(tmpl, quoted=False)
842 tmpl = templater.parsestring(tmpl, quoted=False)
808 else:
843 else:
809 style = opts.get('style')
844 style = opts.get('style')
810
845
811 # ui settings
846 # ui settings
812 if not (tmpl or style):
847 if not (tmpl or style):
813 tmpl = ui.config('ui', 'logtemplate')
848 tmpl = ui.config('ui', 'logtemplate')
814 if tmpl:
849 if tmpl:
815 tmpl = templater.parsestring(tmpl)
850 tmpl = templater.parsestring(tmpl)
816 else:
851 else:
817 style = util.expandpath(ui.config('ui', 'style', ''))
852 style = util.expandpath(ui.config('ui', 'style', ''))
818
853
819 if not (tmpl or style):
854 if not (tmpl or style):
820 return changeset_printer(ui, repo, patch, opts, buffered)
855 return changeset_printer(ui, repo, patch, opts, buffered)
821
856
822 mapfile = None
857 mapfile = None
823 if style and not tmpl:
858 if style and not tmpl:
824 mapfile = style
859 mapfile = style
825 if not os.path.split(mapfile)[0]:
860 if not os.path.split(mapfile)[0]:
826 mapname = (templater.templatepath('map-cmdline.' + mapfile)
861 mapname = (templater.templatepath('map-cmdline.' + mapfile)
827 or templater.templatepath(mapfile))
862 or templater.templatepath(mapfile))
828 if mapname:
863 if mapname:
829 mapfile = mapname
864 mapfile = mapname
830
865
831 try:
866 try:
832 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
867 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
833 except SyntaxError, inst:
868 except SyntaxError, inst:
834 raise util.Abort(inst.args[0])
869 raise util.Abort(inst.args[0])
835 if tmpl:
870 if tmpl:
836 t.use_template(tmpl)
871 t.use_template(tmpl)
837 return t
872 return t
838
873
839 def finddate(ui, repo, date):
874 def finddate(ui, repo, date):
840 """Find the tipmost changeset that matches the given date spec"""
875 """Find the tipmost changeset that matches the given date spec"""
841
876
842 df = util.matchdate(date)
877 df = util.matchdate(date)
843 m = scmutil.matchall(repo)
878 m = scmutil.matchall(repo)
844 results = {}
879 results = {}
845
880
846 def prep(ctx, fns):
881 def prep(ctx, fns):
847 d = ctx.date()
882 d = ctx.date()
848 if df(d[0]):
883 if df(d[0]):
849 results[ctx.rev()] = d
884 results[ctx.rev()] = d
850
885
851 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
886 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
852 rev = ctx.rev()
887 rev = ctx.rev()
853 if rev in results:
888 if rev in results:
854 ui.status(_("Found revision %s from %s\n") %
889 ui.status(_("Found revision %s from %s\n") %
855 (rev, util.datestr(results[rev])))
890 (rev, util.datestr(results[rev])))
856 return str(rev)
891 return str(rev)
857
892
858 raise util.Abort(_("revision matching date not found"))
893 raise util.Abort(_("revision matching date not found"))
859
894
860 def walkchangerevs(repo, match, opts, prepare):
895 def walkchangerevs(repo, match, opts, prepare):
861 '''Iterate over files and the revs in which they changed.
896 '''Iterate over files and the revs in which they changed.
862
897
863 Callers most commonly need to iterate backwards over the history
898 Callers most commonly need to iterate backwards over the history
864 in which they are interested. Doing so has awful (quadratic-looking)
899 in which they are interested. Doing so has awful (quadratic-looking)
865 performance, so we use iterators in a "windowed" way.
900 performance, so we use iterators in a "windowed" way.
866
901
867 We walk a window of revisions in the desired order. Within the
902 We walk a window of revisions in the desired order. Within the
868 window, we first walk forwards to gather data, then in the desired
903 window, we first walk forwards to gather data, then in the desired
869 order (usually backwards) to display it.
904 order (usually backwards) to display it.
870
905
871 This function returns an iterator yielding contexts. Before
906 This function returns an iterator yielding contexts. Before
872 yielding each context, the iterator will first call the prepare
907 yielding each context, the iterator will first call the prepare
873 function on each context in the window in forward order.'''
908 function on each context in the window in forward order.'''
874
909
875 def increasing_windows(start, end, windowsize=8, sizelimit=512):
910 def increasing_windows(start, end, windowsize=8, sizelimit=512):
876 if start < end:
911 if start < end:
877 while start < end:
912 while start < end:
878 yield start, min(windowsize, end - start)
913 yield start, min(windowsize, end - start)
879 start += windowsize
914 start += windowsize
880 if windowsize < sizelimit:
915 if windowsize < sizelimit:
881 windowsize *= 2
916 windowsize *= 2
882 else:
917 else:
883 while start > end:
918 while start > end:
884 yield start, min(windowsize, start - end - 1)
919 yield start, min(windowsize, start - end - 1)
885 start -= windowsize
920 start -= windowsize
886 if windowsize < sizelimit:
921 if windowsize < sizelimit:
887 windowsize *= 2
922 windowsize *= 2
888
923
889 follow = opts.get('follow') or opts.get('follow_first')
924 follow = opts.get('follow') or opts.get('follow_first')
890
925
891 if not len(repo):
926 if not len(repo):
892 return []
927 return []
893
928
894 if follow:
929 if follow:
895 defrange = '%s:0' % repo['.'].rev()
930 defrange = '%s:0' % repo['.'].rev()
896 else:
931 else:
897 defrange = '-1:0'
932 defrange = '-1:0'
898 revs = scmutil.revrange(repo, opts['rev'] or [defrange])
933 revs = scmutil.revrange(repo, opts['rev'] or [defrange])
899 if not revs:
934 if not revs:
900 return []
935 return []
901 wanted = set()
936 wanted = set()
902 slowpath = match.anypats() or (match.files() and opts.get('removed'))
937 slowpath = match.anypats() or (match.files() and opts.get('removed'))
903 fncache = {}
938 fncache = {}
904 change = util.cachefunc(repo.changectx)
939 change = util.cachefunc(repo.changectx)
905
940
906 # First step is to fill wanted, the set of revisions that we want to yield.
941 # First step is to fill wanted, the set of revisions that we want to yield.
907 # When it does not induce extra cost, we also fill fncache for revisions in
942 # When it does not induce extra cost, we also fill fncache for revisions in
908 # wanted: a cache of filenames that were changed (ctx.files()) and that
943 # wanted: a cache of filenames that were changed (ctx.files()) and that
909 # match the file filtering conditions.
944 # match the file filtering conditions.
910
945
911 if not slowpath and not match.files():
946 if not slowpath and not match.files():
912 # No files, no patterns. Display all revs.
947 # No files, no patterns. Display all revs.
913 wanted = set(revs)
948 wanted = set(revs)
914 copies = []
949 copies = []
915
950
916 if not slowpath:
951 if not slowpath:
917 # We only have to read through the filelog to find wanted revisions
952 # We only have to read through the filelog to find wanted revisions
918
953
919 minrev, maxrev = min(revs), max(revs)
954 minrev, maxrev = min(revs), max(revs)
920 def filerevgen(filelog, last):
955 def filerevgen(filelog, last):
921 """
956 """
922 Only files, no patterns. Check the history of each file.
957 Only files, no patterns. Check the history of each file.
923
958
924 Examines filelog entries within minrev, maxrev linkrev range
959 Examines filelog entries within minrev, maxrev linkrev range
925 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
960 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
926 tuples in backwards order
961 tuples in backwards order
927 """
962 """
928 cl_count = len(repo)
963 cl_count = len(repo)
929 revs = []
964 revs = []
930 for j in xrange(0, last + 1):
965 for j in xrange(0, last + 1):
931 linkrev = filelog.linkrev(j)
966 linkrev = filelog.linkrev(j)
932 if linkrev < minrev:
967 if linkrev < minrev:
933 continue
968 continue
934 # only yield rev for which we have the changelog, it can
969 # only yield rev for which we have the changelog, it can
935 # happen while doing "hg log" during a pull or commit
970 # happen while doing "hg log" during a pull or commit
936 if linkrev >= cl_count:
971 if linkrev >= cl_count:
937 break
972 break
938
973
939 parentlinkrevs = []
974 parentlinkrevs = []
940 for p in filelog.parentrevs(j):
975 for p in filelog.parentrevs(j):
941 if p != nullrev:
976 if p != nullrev:
942 parentlinkrevs.append(filelog.linkrev(p))
977 parentlinkrevs.append(filelog.linkrev(p))
943 n = filelog.node(j)
978 n = filelog.node(j)
944 revs.append((linkrev, parentlinkrevs,
979 revs.append((linkrev, parentlinkrevs,
945 follow and filelog.renamed(n)))
980 follow and filelog.renamed(n)))
946
981
947 return reversed(revs)
982 return reversed(revs)
948 def iterfiles():
983 def iterfiles():
949 for filename in match.files():
984 for filename in match.files():
950 yield filename, None
985 yield filename, None
951 for filename_node in copies:
986 for filename_node in copies:
952 yield filename_node
987 yield filename_node
953 for file_, node in iterfiles():
988 for file_, node in iterfiles():
954 filelog = repo.file(file_)
989 filelog = repo.file(file_)
955 if not len(filelog):
990 if not len(filelog):
956 if node is None:
991 if node is None:
957 # A zero count may be a directory or deleted file, so
992 # A zero count may be a directory or deleted file, so
958 # try to find matching entries on the slow path.
993 # try to find matching entries on the slow path.
959 if follow:
994 if follow:
960 raise util.Abort(
995 raise util.Abort(
961 _('cannot follow nonexistent file: "%s"') % file_)
996 _('cannot follow nonexistent file: "%s"') % file_)
962 slowpath = True
997 slowpath = True
963 break
998 break
964 else:
999 else:
965 continue
1000 continue
966
1001
967 if node is None:
1002 if node is None:
968 last = len(filelog) - 1
1003 last = len(filelog) - 1
969 else:
1004 else:
970 last = filelog.rev(node)
1005 last = filelog.rev(node)
971
1006
972
1007
973 # keep track of all ancestors of the file
1008 # keep track of all ancestors of the file
974 ancestors = set([filelog.linkrev(last)])
1009 ancestors = set([filelog.linkrev(last)])
975
1010
976 # iterate from latest to oldest revision
1011 # iterate from latest to oldest revision
977 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1012 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
978 if not follow:
1013 if not follow:
979 if rev > maxrev:
1014 if rev > maxrev:
980 continue
1015 continue
981 else:
1016 else:
982 # Note that last might not be the first interesting
1017 # Note that last might not be the first interesting
983 # rev to us:
1018 # rev to us:
984 # if the file has been changed after maxrev, we'll
1019 # if the file has been changed after maxrev, we'll
985 # have linkrev(last) > maxrev, and we still need
1020 # have linkrev(last) > maxrev, and we still need
986 # to explore the file graph
1021 # to explore the file graph
987 if rev not in ancestors:
1022 if rev not in ancestors:
988 continue
1023 continue
989 # XXX insert 1327 fix here
1024 # XXX insert 1327 fix here
990 if flparentlinkrevs:
1025 if flparentlinkrevs:
991 ancestors.update(flparentlinkrevs)
1026 ancestors.update(flparentlinkrevs)
992
1027
993 fncache.setdefault(rev, []).append(file_)
1028 fncache.setdefault(rev, []).append(file_)
994 wanted.add(rev)
1029 wanted.add(rev)
995 if copied:
1030 if copied:
996 copies.append(copied)
1031 copies.append(copied)
997 if slowpath:
1032 if slowpath:
998 # We have to read the changelog to match filenames against
1033 # We have to read the changelog to match filenames against
999 # changed files
1034 # changed files
1000
1035
1001 if follow:
1036 if follow:
1002 raise util.Abort(_('can only follow copies/renames for explicit '
1037 raise util.Abort(_('can only follow copies/renames for explicit '
1003 'filenames'))
1038 'filenames'))
1004
1039
1005 # The slow path checks files modified in every changeset.
1040 # The slow path checks files modified in every changeset.
1006 for i in sorted(revs):
1041 for i in sorted(revs):
1007 ctx = change(i)
1042 ctx = change(i)
1008 matches = filter(match, ctx.files())
1043 matches = filter(match, ctx.files())
1009 if matches:
1044 if matches:
1010 fncache[i] = matches
1045 fncache[i] = matches
1011 wanted.add(i)
1046 wanted.add(i)
1012
1047
1013 class followfilter(object):
1048 class followfilter(object):
1014 def __init__(self, onlyfirst=False):
1049 def __init__(self, onlyfirst=False):
1015 self.startrev = nullrev
1050 self.startrev = nullrev
1016 self.roots = set()
1051 self.roots = set()
1017 self.onlyfirst = onlyfirst
1052 self.onlyfirst = onlyfirst
1018
1053
1019 def match(self, rev):
1054 def match(self, rev):
1020 def realparents(rev):
1055 def realparents(rev):
1021 if self.onlyfirst:
1056 if self.onlyfirst:
1022 return repo.changelog.parentrevs(rev)[0:1]
1057 return repo.changelog.parentrevs(rev)[0:1]
1023 else:
1058 else:
1024 return filter(lambda x: x != nullrev,
1059 return filter(lambda x: x != nullrev,
1025 repo.changelog.parentrevs(rev))
1060 repo.changelog.parentrevs(rev))
1026
1061
1027 if self.startrev == nullrev:
1062 if self.startrev == nullrev:
1028 self.startrev = rev
1063 self.startrev = rev
1029 return True
1064 return True
1030
1065
1031 if rev > self.startrev:
1066 if rev > self.startrev:
1032 # forward: all descendants
1067 # forward: all descendants
1033 if not self.roots:
1068 if not self.roots:
1034 self.roots.add(self.startrev)
1069 self.roots.add(self.startrev)
1035 for parent in realparents(rev):
1070 for parent in realparents(rev):
1036 if parent in self.roots:
1071 if parent in self.roots:
1037 self.roots.add(rev)
1072 self.roots.add(rev)
1038 return True
1073 return True
1039 else:
1074 else:
1040 # backwards: all parents
1075 # backwards: all parents
1041 if not self.roots:
1076 if not self.roots:
1042 self.roots.update(realparents(self.startrev))
1077 self.roots.update(realparents(self.startrev))
1043 if rev in self.roots:
1078 if rev in self.roots:
1044 self.roots.remove(rev)
1079 self.roots.remove(rev)
1045 self.roots.update(realparents(rev))
1080 self.roots.update(realparents(rev))
1046 return True
1081 return True
1047
1082
1048 return False
1083 return False
1049
1084
1050 # it might be worthwhile to do this in the iterator if the rev range
1085 # it might be worthwhile to do this in the iterator if the rev range
1051 # is descending and the prune args are all within that range
1086 # is descending and the prune args are all within that range
1052 for rev in opts.get('prune', ()):
1087 for rev in opts.get('prune', ()):
1053 rev = repo.changelog.rev(repo.lookup(rev))
1088 rev = repo.changelog.rev(repo.lookup(rev))
1054 ff = followfilter()
1089 ff = followfilter()
1055 stop = min(revs[0], revs[-1])
1090 stop = min(revs[0], revs[-1])
1056 for x in xrange(rev, stop - 1, -1):
1091 for x in xrange(rev, stop - 1, -1):
1057 if ff.match(x):
1092 if ff.match(x):
1058 wanted.discard(x)
1093 wanted.discard(x)
1059
1094
1060 # Now that wanted is correctly initialized, we can iterate over the
1095 # Now that wanted is correctly initialized, we can iterate over the
1061 # revision range, yielding only revisions in wanted.
1096 # revision range, yielding only revisions in wanted.
1062 def iterate():
1097 def iterate():
1063 if follow and not match.files():
1098 if follow and not match.files():
1064 ff = followfilter(onlyfirst=opts.get('follow_first'))
1099 ff = followfilter(onlyfirst=opts.get('follow_first'))
1065 def want(rev):
1100 def want(rev):
1066 return ff.match(rev) and rev in wanted
1101 return ff.match(rev) and rev in wanted
1067 else:
1102 else:
1068 def want(rev):
1103 def want(rev):
1069 return rev in wanted
1104 return rev in wanted
1070
1105
1071 for i, window in increasing_windows(0, len(revs)):
1106 for i, window in increasing_windows(0, len(revs)):
1072 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1107 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1073 for rev in sorted(nrevs):
1108 for rev in sorted(nrevs):
1074 fns = fncache.get(rev)
1109 fns = fncache.get(rev)
1075 ctx = change(rev)
1110 ctx = change(rev)
1076 if not fns:
1111 if not fns:
1077 def fns_generator():
1112 def fns_generator():
1078 for f in ctx.files():
1113 for f in ctx.files():
1079 if match(f):
1114 if match(f):
1080 yield f
1115 yield f
1081 fns = fns_generator()
1116 fns = fns_generator()
1082 prepare(ctx, fns)
1117 prepare(ctx, fns)
1083 for rev in nrevs:
1118 for rev in nrevs:
1084 yield change(rev)
1119 yield change(rev)
1085 return iterate()
1120 return iterate()
1086
1121
1087 def add(ui, repo, match, dryrun, listsubrepos, prefix):
1122 def add(ui, repo, match, dryrun, listsubrepos, prefix):
1088 join = lambda f: os.path.join(prefix, f)
1123 join = lambda f: os.path.join(prefix, f)
1089 bad = []
1124 bad = []
1090 oldbad = match.bad
1125 oldbad = match.bad
1091 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1126 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1092 names = []
1127 names = []
1093 wctx = repo[None]
1128 wctx = repo[None]
1094 cca = None
1129 cca = None
1095 abort, warn = scmutil.checkportabilityalert(ui)
1130 abort, warn = scmutil.checkportabilityalert(ui)
1096 if abort or warn:
1131 if abort or warn:
1097 cca = scmutil.casecollisionauditor(ui, abort, wctx)
1132 cca = scmutil.casecollisionauditor(ui, abort, wctx)
1098 for f in repo.walk(match):
1133 for f in repo.walk(match):
1099 exact = match.exact(f)
1134 exact = match.exact(f)
1100 if exact or f not in repo.dirstate:
1135 if exact or f not in repo.dirstate:
1101 if cca:
1136 if cca:
1102 cca(f)
1137 cca(f)
1103 names.append(f)
1138 names.append(f)
1104 if ui.verbose or not exact:
1139 if ui.verbose or not exact:
1105 ui.status(_('adding %s\n') % match.rel(join(f)))
1140 ui.status(_('adding %s\n') % match.rel(join(f)))
1106
1141
1107 if listsubrepos:
1142 if listsubrepos:
1108 for subpath in wctx.substate:
1143 for subpath in wctx.substate:
1109 sub = wctx.sub(subpath)
1144 sub = wctx.sub(subpath)
1110 try:
1145 try:
1111 submatch = matchmod.narrowmatcher(subpath, match)
1146 submatch = matchmod.narrowmatcher(subpath, match)
1112 bad.extend(sub.add(ui, submatch, dryrun, prefix))
1147 bad.extend(sub.add(ui, submatch, dryrun, prefix))
1113 except error.LookupError:
1148 except error.LookupError:
1114 ui.status(_("skipping missing subrepository: %s\n")
1149 ui.status(_("skipping missing subrepository: %s\n")
1115 % join(subpath))
1150 % join(subpath))
1116
1151
1117 if not dryrun:
1152 if not dryrun:
1118 rejected = wctx.add(names, prefix)
1153 rejected = wctx.add(names, prefix)
1119 bad.extend(f for f in rejected if f in match.files())
1154 bad.extend(f for f in rejected if f in match.files())
1120 return bad
1155 return bad
1121
1156
1122 def commit(ui, repo, commitfunc, pats, opts):
1157 def commit(ui, repo, commitfunc, pats, opts):
1123 '''commit the specified files or all outstanding changes'''
1158 '''commit the specified files or all outstanding changes'''
1124 date = opts.get('date')
1159 date = opts.get('date')
1125 if date:
1160 if date:
1126 opts['date'] = util.parsedate(date)
1161 opts['date'] = util.parsedate(date)
1127 message = logmessage(opts)
1162 message = logmessage(opts)
1128
1163
1129 # extract addremove carefully -- this function can be called from a command
1164 # extract addremove carefully -- this function can be called from a command
1130 # that doesn't support addremove
1165 # that doesn't support addremove
1131 if opts.get('addremove'):
1166 if opts.get('addremove'):
1132 scmutil.addremove(repo, pats, opts)
1167 scmutil.addremove(repo, pats, opts)
1133
1168
1134 return commitfunc(ui, repo, message, scmutil.match(repo, pats, opts), opts)
1169 return commitfunc(ui, repo, message, scmutil.match(repo, pats, opts), opts)
1135
1170
1136 def commiteditor(repo, ctx, subs):
1171 def commiteditor(repo, ctx, subs):
1137 if ctx.description():
1172 if ctx.description():
1138 return ctx.description()
1173 return ctx.description()
1139 return commitforceeditor(repo, ctx, subs)
1174 return commitforceeditor(repo, ctx, subs)
1140
1175
1141 def commitforceeditor(repo, ctx, subs):
1176 def commitforceeditor(repo, ctx, subs):
1142 edittext = []
1177 edittext = []
1143 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1178 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1144 if ctx.description():
1179 if ctx.description():
1145 edittext.append(ctx.description())
1180 edittext.append(ctx.description())
1146 edittext.append("")
1181 edittext.append("")
1147 edittext.append("") # Empty line between message and comments.
1182 edittext.append("") # Empty line between message and comments.
1148 edittext.append(_("HG: Enter commit message."
1183 edittext.append(_("HG: Enter commit message."
1149 " Lines beginning with 'HG:' are removed."))
1184 " Lines beginning with 'HG:' are removed."))
1150 edittext.append(_("HG: Leave message empty to abort commit."))
1185 edittext.append(_("HG: Leave message empty to abort commit."))
1151 edittext.append("HG: --")
1186 edittext.append("HG: --")
1152 edittext.append(_("HG: user: %s") % ctx.user())
1187 edittext.append(_("HG: user: %s") % ctx.user())
1153 if ctx.p2():
1188 if ctx.p2():
1154 edittext.append(_("HG: branch merge"))
1189 edittext.append(_("HG: branch merge"))
1155 if ctx.branch():
1190 if ctx.branch():
1156 edittext.append(_("HG: branch '%s'") % ctx.branch())
1191 edittext.append(_("HG: branch '%s'") % ctx.branch())
1157 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1192 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1158 edittext.extend([_("HG: added %s") % f for f in added])
1193 edittext.extend([_("HG: added %s") % f for f in added])
1159 edittext.extend([_("HG: changed %s") % f for f in modified])
1194 edittext.extend([_("HG: changed %s") % f for f in modified])
1160 edittext.extend([_("HG: removed %s") % f for f in removed])
1195 edittext.extend([_("HG: removed %s") % f for f in removed])
1161 if not added and not modified and not removed:
1196 if not added and not modified and not removed:
1162 edittext.append(_("HG: no files changed"))
1197 edittext.append(_("HG: no files changed"))
1163 edittext.append("")
1198 edittext.append("")
1164 # run editor in the repository root
1199 # run editor in the repository root
1165 olddir = os.getcwd()
1200 olddir = os.getcwd()
1166 os.chdir(repo.root)
1201 os.chdir(repo.root)
1167 text = repo.ui.edit("\n".join(edittext), ctx.user())
1202 text = repo.ui.edit("\n".join(edittext), ctx.user())
1168 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1203 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1169 os.chdir(olddir)
1204 os.chdir(olddir)
1170
1205
1171 if not text.strip():
1206 if not text.strip():
1172 raise util.Abort(_("empty commit message"))
1207 raise util.Abort(_("empty commit message"))
1173
1208
1174 return text
1209 return text
1175
1210
1176 def command(table):
1211 def command(table):
1177 '''returns a function object bound to table which can be used as
1212 '''returns a function object bound to table which can be used as
1178 a decorator for populating table as a command table'''
1213 a decorator for populating table as a command table'''
1179
1214
1180 def cmd(name, options, synopsis=None):
1215 def cmd(name, options, synopsis=None):
1181 def decorator(func):
1216 def decorator(func):
1182 if synopsis:
1217 if synopsis:
1183 table[name] = func, options, synopsis
1218 table[name] = func, options, synopsis
1184 else:
1219 else:
1185 table[name] = func, options
1220 table[name] = func, options
1186 return func
1221 return func
1187 return decorator
1222 return decorator
1188
1223
1189 return cmd
1224 return cmd
@@ -1,5022 +1,5012 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, sys, difflib, time, tempfile
11 import os, re, sys, difflib, time, tempfile
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
15 import merge as mergemod
15 import merge as mergemod
16 import minirst, revset
16 import minirst, revset
17 import dagparser, context, simplemerge
17 import dagparser, context, simplemerge
18 import random, setdiscovery, treediscovery, dagutil
18 import random, setdiscovery, treediscovery, dagutil
19
19
20 table = {}
20 table = {}
21
21
22 command = cmdutil.command(table)
22 command = cmdutil.command(table)
23
23
24 # common command options
24 # common command options
25
25
26 globalopts = [
26 globalopts = [
27 ('R', 'repository', '',
27 ('R', 'repository', '',
28 _('repository root directory or name of overlay bundle file'),
28 _('repository root directory or name of overlay bundle file'),
29 _('REPO')),
29 _('REPO')),
30 ('', 'cwd', '',
30 ('', 'cwd', '',
31 _('change working directory'), _('DIR')),
31 _('change working directory'), _('DIR')),
32 ('y', 'noninteractive', None,
32 ('y', 'noninteractive', None,
33 _('do not prompt, assume \'yes\' for any required answers')),
33 _('do not prompt, assume \'yes\' for any required answers')),
34 ('q', 'quiet', None, _('suppress output')),
34 ('q', 'quiet', None, _('suppress output')),
35 ('v', 'verbose', None, _('enable additional output')),
35 ('v', 'verbose', None, _('enable additional output')),
36 ('', 'config', [],
36 ('', 'config', [],
37 _('set/override config option (use \'section.name=value\')'),
37 _('set/override config option (use \'section.name=value\')'),
38 _('CONFIG')),
38 _('CONFIG')),
39 ('', 'debug', None, _('enable debugging output')),
39 ('', 'debug', None, _('enable debugging output')),
40 ('', 'debugger', None, _('start debugger')),
40 ('', 'debugger', None, _('start debugger')),
41 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
41 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
42 _('ENCODE')),
42 _('ENCODE')),
43 ('', 'encodingmode', encoding.encodingmode,
43 ('', 'encodingmode', encoding.encodingmode,
44 _('set the charset encoding mode'), _('MODE')),
44 _('set the charset encoding mode'), _('MODE')),
45 ('', 'traceback', None, _('always print a traceback on exception')),
45 ('', 'traceback', None, _('always print a traceback on exception')),
46 ('', 'time', None, _('time how long the command takes')),
46 ('', 'time', None, _('time how long the command takes')),
47 ('', 'profile', None, _('print command execution profile')),
47 ('', 'profile', None, _('print command execution profile')),
48 ('', 'version', None, _('output version information and exit')),
48 ('', 'version', None, _('output version information and exit')),
49 ('h', 'help', None, _('display help and exit')),
49 ('h', 'help', None, _('display help and exit')),
50 ]
50 ]
51
51
52 dryrunopts = [('n', 'dry-run', None,
52 dryrunopts = [('n', 'dry-run', None,
53 _('do not perform actions, just print output'))]
53 _('do not perform actions, just print output'))]
54
54
55 remoteopts = [
55 remoteopts = [
56 ('e', 'ssh', '',
56 ('e', 'ssh', '',
57 _('specify ssh command to use'), _('CMD')),
57 _('specify ssh command to use'), _('CMD')),
58 ('', 'remotecmd', '',
58 ('', 'remotecmd', '',
59 _('specify hg command to run on the remote side'), _('CMD')),
59 _('specify hg command to run on the remote side'), _('CMD')),
60 ('', 'insecure', None,
60 ('', 'insecure', None,
61 _('do not verify server certificate (ignoring web.cacerts config)')),
61 _('do not verify server certificate (ignoring web.cacerts config)')),
62 ]
62 ]
63
63
64 walkopts = [
64 walkopts = [
65 ('I', 'include', [],
65 ('I', 'include', [],
66 _('include names matching the given patterns'), _('PATTERN')),
66 _('include names matching the given patterns'), _('PATTERN')),
67 ('X', 'exclude', [],
67 ('X', 'exclude', [],
68 _('exclude names matching the given patterns'), _('PATTERN')),
68 _('exclude names matching the given patterns'), _('PATTERN')),
69 ]
69 ]
70
70
71 commitopts = [
71 commitopts = [
72 ('m', 'message', '',
72 ('m', 'message', '',
73 _('use text as commit message'), _('TEXT')),
73 _('use text as commit message'), _('TEXT')),
74 ('l', 'logfile', '',
74 ('l', 'logfile', '',
75 _('read commit message from file'), _('FILE')),
75 _('read commit message from file'), _('FILE')),
76 ]
76 ]
77
77
78 commitopts2 = [
78 commitopts2 = [
79 ('d', 'date', '',
79 ('d', 'date', '',
80 _('record the specified date as commit date'), _('DATE')),
80 _('record the specified date as commit date'), _('DATE')),
81 ('u', 'user', '',
81 ('u', 'user', '',
82 _('record the specified user as committer'), _('USER')),
82 _('record the specified user as committer'), _('USER')),
83 ]
83 ]
84
84
85 templateopts = [
85 templateopts = [
86 ('', 'style', '',
86 ('', 'style', '',
87 _('display using template map file'), _('STYLE')),
87 _('display using template map file'), _('STYLE')),
88 ('', 'template', '',
88 ('', 'template', '',
89 _('display with template'), _('TEMPLATE')),
89 _('display with template'), _('TEMPLATE')),
90 ]
90 ]
91
91
92 logopts = [
92 logopts = [
93 ('p', 'patch', None, _('show patch')),
93 ('p', 'patch', None, _('show patch')),
94 ('g', 'git', None, _('use git extended diff format')),
94 ('g', 'git', None, _('use git extended diff format')),
95 ('l', 'limit', '',
95 ('l', 'limit', '',
96 _('limit number of changes displayed'), _('NUM')),
96 _('limit number of changes displayed'), _('NUM')),
97 ('M', 'no-merges', None, _('do not show merges')),
97 ('M', 'no-merges', None, _('do not show merges')),
98 ('', 'stat', None, _('output diffstat-style summary of changes')),
98 ('', 'stat', None, _('output diffstat-style summary of changes')),
99 ] + templateopts
99 ] + templateopts
100
100
101 diffopts = [
101 diffopts = [
102 ('a', 'text', None, _('treat all files as text')),
102 ('a', 'text', None, _('treat all files as text')),
103 ('g', 'git', None, _('use git extended diff format')),
103 ('g', 'git', None, _('use git extended diff format')),
104 ('', 'nodates', None, _('omit dates from diff headers'))
104 ('', 'nodates', None, _('omit dates from diff headers'))
105 ]
105 ]
106
106
107 diffopts2 = [
107 diffopts2 = [
108 ('p', 'show-function', None, _('show which function each change is in')),
108 ('p', 'show-function', None, _('show which function each change is in')),
109 ('', 'reverse', None, _('produce a diff that undoes the changes')),
109 ('', 'reverse', None, _('produce a diff that undoes the changes')),
110 ('w', 'ignore-all-space', None,
110 ('w', 'ignore-all-space', None,
111 _('ignore white space when comparing lines')),
111 _('ignore white space when comparing lines')),
112 ('b', 'ignore-space-change', None,
112 ('b', 'ignore-space-change', None,
113 _('ignore changes in the amount of white space')),
113 _('ignore changes in the amount of white space')),
114 ('B', 'ignore-blank-lines', None,
114 ('B', 'ignore-blank-lines', None,
115 _('ignore changes whose lines are all blank')),
115 _('ignore changes whose lines are all blank')),
116 ('U', 'unified', '',
116 ('U', 'unified', '',
117 _('number of lines of context to show'), _('NUM')),
117 _('number of lines of context to show'), _('NUM')),
118 ('', 'stat', None, _('output diffstat-style summary of changes')),
118 ('', 'stat', None, _('output diffstat-style summary of changes')),
119 ]
119 ]
120
120
121 similarityopts = [
121 similarityopts = [
122 ('s', 'similarity', '',
122 ('s', 'similarity', '',
123 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
123 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
124 ]
124 ]
125
125
126 subrepoopts = [
126 subrepoopts = [
127 ('S', 'subrepos', None,
127 ('S', 'subrepos', None,
128 _('recurse into subrepositories'))
128 _('recurse into subrepositories'))
129 ]
129 ]
130
130
131 # Commands start here, listed alphabetically
131 # Commands start here, listed alphabetically
132
132
133 @command('^add',
133 @command('^add',
134 walkopts + subrepoopts + dryrunopts,
134 walkopts + subrepoopts + dryrunopts,
135 _('[OPTION]... [FILE]...'))
135 _('[OPTION]... [FILE]...'))
136 def add(ui, repo, *pats, **opts):
136 def add(ui, repo, *pats, **opts):
137 """add the specified files on the next commit
137 """add the specified files on the next commit
138
138
139 Schedule files to be version controlled and added to the
139 Schedule files to be version controlled and added to the
140 repository.
140 repository.
141
141
142 The files will be added to the repository at the next commit. To
142 The files will be added to the repository at the next commit. To
143 undo an add before that, see :hg:`forget`.
143 undo an add before that, see :hg:`forget`.
144
144
145 If no names are given, add all files to the repository.
145 If no names are given, add all files to the repository.
146
146
147 .. container:: verbose
147 .. container:: verbose
148
148
149 An example showing how new (unknown) files are added
149 An example showing how new (unknown) files are added
150 automatically by :hg:`add`::
150 automatically by :hg:`add`::
151
151
152 $ ls
152 $ ls
153 foo.c
153 foo.c
154 $ hg status
154 $ hg status
155 ? foo.c
155 ? foo.c
156 $ hg add
156 $ hg add
157 adding foo.c
157 adding foo.c
158 $ hg status
158 $ hg status
159 A foo.c
159 A foo.c
160
160
161 Returns 0 if all files are successfully added.
161 Returns 0 if all files are successfully added.
162 """
162 """
163
163
164 m = scmutil.match(repo, pats, opts)
164 m = scmutil.match(repo, pats, opts)
165 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
165 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
166 opts.get('subrepos'), prefix="")
166 opts.get('subrepos'), prefix="")
167 return rejected and 1 or 0
167 return rejected and 1 or 0
168
168
169 @command('addremove',
169 @command('addremove',
170 similarityopts + walkopts + dryrunopts,
170 similarityopts + walkopts + dryrunopts,
171 _('[OPTION]... [FILE]...'))
171 _('[OPTION]... [FILE]...'))
172 def addremove(ui, repo, *pats, **opts):
172 def addremove(ui, repo, *pats, **opts):
173 """add all new files, delete all missing files
173 """add all new files, delete all missing files
174
174
175 Add all new files and remove all missing files from the
175 Add all new files and remove all missing files from the
176 repository.
176 repository.
177
177
178 New files are ignored if they match any of the patterns in
178 New files are ignored if they match any of the patterns in
179 ``.hgignore``. As with add, these changes take effect at the next
179 ``.hgignore``. As with add, these changes take effect at the next
180 commit.
180 commit.
181
181
182 Use the -s/--similarity option to detect renamed files. With a
182 Use the -s/--similarity option to detect renamed files. With a
183 parameter greater than 0, this compares every removed file with
183 parameter greater than 0, this compares every removed file with
184 every added file and records those similar enough as renames. This
184 every added file and records those similar enough as renames. This
185 option takes a percentage between 0 (disabled) and 100 (files must
185 option takes a percentage between 0 (disabled) and 100 (files must
186 be identical) as its parameter. Detecting renamed files this way
186 be identical) as its parameter. Detecting renamed files this way
187 can be expensive. After using this option, :hg:`status -C` can be
187 can be expensive. After using this option, :hg:`status -C` can be
188 used to check which files were identified as moved or renamed.
188 used to check which files were identified as moved or renamed.
189
189
190 Returns 0 if all files are successfully added.
190 Returns 0 if all files are successfully added.
191 """
191 """
192 try:
192 try:
193 sim = float(opts.get('similarity') or 100)
193 sim = float(opts.get('similarity') or 100)
194 except ValueError:
194 except ValueError:
195 raise util.Abort(_('similarity must be a number'))
195 raise util.Abort(_('similarity must be a number'))
196 if sim < 0 or sim > 100:
196 if sim < 0 or sim > 100:
197 raise util.Abort(_('similarity must be between 0 and 100'))
197 raise util.Abort(_('similarity must be between 0 and 100'))
198 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
198 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
199
199
200 @command('^annotate|blame',
200 @command('^annotate|blame',
201 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
201 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
202 ('', 'follow', None,
202 ('', 'follow', None,
203 _('follow copies/renames and list the filename (DEPRECATED)')),
203 _('follow copies/renames and list the filename (DEPRECATED)')),
204 ('', 'no-follow', None, _("don't follow copies and renames")),
204 ('', 'no-follow', None, _("don't follow copies and renames")),
205 ('a', 'text', None, _('treat all files as text')),
205 ('a', 'text', None, _('treat all files as text')),
206 ('u', 'user', None, _('list the author (long with -v)')),
206 ('u', 'user', None, _('list the author (long with -v)')),
207 ('f', 'file', None, _('list the filename')),
207 ('f', 'file', None, _('list the filename')),
208 ('d', 'date', None, _('list the date (short with -q)')),
208 ('d', 'date', None, _('list the date (short with -q)')),
209 ('n', 'number', None, _('list the revision number (default)')),
209 ('n', 'number', None, _('list the revision number (default)')),
210 ('c', 'changeset', None, _('list the changeset')),
210 ('c', 'changeset', None, _('list the changeset')),
211 ('l', 'line-number', None, _('show line number at the first appearance'))
211 ('l', 'line-number', None, _('show line number at the first appearance'))
212 ] + walkopts,
212 ] + walkopts,
213 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
213 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
214 def annotate(ui, repo, *pats, **opts):
214 def annotate(ui, repo, *pats, **opts):
215 """show changeset information by line for each file
215 """show changeset information by line for each file
216
216
217 List changes in files, showing the revision id responsible for
217 List changes in files, showing the revision id responsible for
218 each line
218 each line
219
219
220 This command is useful for discovering when a change was made and
220 This command is useful for discovering when a change was made and
221 by whom.
221 by whom.
222
222
223 Without the -a/--text option, annotate will avoid processing files
223 Without the -a/--text option, annotate will avoid processing files
224 it detects as binary. With -a, annotate will annotate the file
224 it detects as binary. With -a, annotate will annotate the file
225 anyway, although the results will probably be neither useful
225 anyway, although the results will probably be neither useful
226 nor desirable.
226 nor desirable.
227
227
228 Returns 0 on success.
228 Returns 0 on success.
229 """
229 """
230 if opts.get('follow'):
230 if opts.get('follow'):
231 # --follow is deprecated and now just an alias for -f/--file
231 # --follow is deprecated and now just an alias for -f/--file
232 # to mimic the behavior of Mercurial before version 1.5
232 # to mimic the behavior of Mercurial before version 1.5
233 opts['file'] = True
233 opts['file'] = True
234
234
235 datefunc = ui.quiet and util.shortdate or util.datestr
235 datefunc = ui.quiet and util.shortdate or util.datestr
236 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
236 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
237
237
238 if not pats:
238 if not pats:
239 raise util.Abort(_('at least one filename or pattern is required'))
239 raise util.Abort(_('at least one filename or pattern is required'))
240
240
241 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
241 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
242 ('number', lambda x: str(x[0].rev())),
242 ('number', lambda x: str(x[0].rev())),
243 ('changeset', lambda x: short(x[0].node())),
243 ('changeset', lambda x: short(x[0].node())),
244 ('date', getdate),
244 ('date', getdate),
245 ('file', lambda x: x[0].path()),
245 ('file', lambda x: x[0].path()),
246 ]
246 ]
247
247
248 if (not opts.get('user') and not opts.get('changeset')
248 if (not opts.get('user') and not opts.get('changeset')
249 and not opts.get('date') and not opts.get('file')):
249 and not opts.get('date') and not opts.get('file')):
250 opts['number'] = True
250 opts['number'] = True
251
251
252 linenumber = opts.get('line_number') is not None
252 linenumber = opts.get('line_number') is not None
253 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
253 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
254 raise util.Abort(_('at least one of -n/-c is required for -l'))
254 raise util.Abort(_('at least one of -n/-c is required for -l'))
255
255
256 funcmap = [func for op, func in opmap if opts.get(op)]
256 funcmap = [func for op, func in opmap if opts.get(op)]
257 if linenumber:
257 if linenumber:
258 lastfunc = funcmap[-1]
258 lastfunc = funcmap[-1]
259 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
259 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
260
260
261 def bad(x, y):
261 def bad(x, y):
262 raise util.Abort("%s: %s" % (x, y))
262 raise util.Abort("%s: %s" % (x, y))
263
263
264 ctx = scmutil.revsingle(repo, opts.get('rev'))
264 ctx = scmutil.revsingle(repo, opts.get('rev'))
265 m = scmutil.match(repo, pats, opts)
265 m = scmutil.match(repo, pats, opts)
266 m.bad = bad
266 m.bad = bad
267 follow = not opts.get('no_follow')
267 follow = not opts.get('no_follow')
268 for abs in ctx.walk(m):
268 for abs in ctx.walk(m):
269 fctx = ctx[abs]
269 fctx = ctx[abs]
270 if not opts.get('text') and util.binary(fctx.data()):
270 if not opts.get('text') and util.binary(fctx.data()):
271 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
271 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
272 continue
272 continue
273
273
274 lines = fctx.annotate(follow=follow, linenumber=linenumber)
274 lines = fctx.annotate(follow=follow, linenumber=linenumber)
275 pieces = []
275 pieces = []
276
276
277 for f in funcmap:
277 for f in funcmap:
278 l = [f(n) for n, dummy in lines]
278 l = [f(n) for n, dummy in lines]
279 if l:
279 if l:
280 sized = [(x, encoding.colwidth(x)) for x in l]
280 sized = [(x, encoding.colwidth(x)) for x in l]
281 ml = max([w for x, w in sized])
281 ml = max([w for x, w in sized])
282 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
282 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
283
283
284 if pieces:
284 if pieces:
285 for p, l in zip(zip(*pieces), lines):
285 for p, l in zip(zip(*pieces), lines):
286 ui.write("%s: %s" % (" ".join(p), l[1]))
286 ui.write("%s: %s" % (" ".join(p), l[1]))
287
287
288 @command('archive',
288 @command('archive',
289 [('', 'no-decode', None, _('do not pass files through decoders')),
289 [('', 'no-decode', None, _('do not pass files through decoders')),
290 ('p', 'prefix', '', _('directory prefix for files in archive'),
290 ('p', 'prefix', '', _('directory prefix for files in archive'),
291 _('PREFIX')),
291 _('PREFIX')),
292 ('r', 'rev', '', _('revision to distribute'), _('REV')),
292 ('r', 'rev', '', _('revision to distribute'), _('REV')),
293 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
293 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
294 ] + subrepoopts + walkopts,
294 ] + subrepoopts + walkopts,
295 _('[OPTION]... DEST'))
295 _('[OPTION]... DEST'))
296 def archive(ui, repo, dest, **opts):
296 def archive(ui, repo, dest, **opts):
297 '''create an unversioned archive of a repository revision
297 '''create an unversioned archive of a repository revision
298
298
299 By default, the revision used is the parent of the working
299 By default, the revision used is the parent of the working
300 directory; use -r/--rev to specify a different revision.
300 directory; use -r/--rev to specify a different revision.
301
301
302 The archive type is automatically detected based on file
302 The archive type is automatically detected based on file
303 extension (or override using -t/--type).
303 extension (or override using -t/--type).
304
304
305 Valid types are:
305 Valid types are:
306
306
307 :``files``: a directory full of files (default)
307 :``files``: a directory full of files (default)
308 :``tar``: tar archive, uncompressed
308 :``tar``: tar archive, uncompressed
309 :``tbz2``: tar archive, compressed using bzip2
309 :``tbz2``: tar archive, compressed using bzip2
310 :``tgz``: tar archive, compressed using gzip
310 :``tgz``: tar archive, compressed using gzip
311 :``uzip``: zip archive, uncompressed
311 :``uzip``: zip archive, uncompressed
312 :``zip``: zip archive, compressed using deflate
312 :``zip``: zip archive, compressed using deflate
313
313
314 The exact name of the destination archive or directory is given
314 The exact name of the destination archive or directory is given
315 using a format string; see :hg:`help export` for details.
315 using a format string; see :hg:`help export` for details.
316
316
317 Each member added to an archive file has a directory prefix
317 Each member added to an archive file has a directory prefix
318 prepended. Use -p/--prefix to specify a format string for the
318 prepended. Use -p/--prefix to specify a format string for the
319 prefix. The default is the basename of the archive, with suffixes
319 prefix. The default is the basename of the archive, with suffixes
320 removed.
320 removed.
321
321
322 Returns 0 on success.
322 Returns 0 on success.
323 '''
323 '''
324
324
325 ctx = scmutil.revsingle(repo, opts.get('rev'))
325 ctx = scmutil.revsingle(repo, opts.get('rev'))
326 if not ctx:
326 if not ctx:
327 raise util.Abort(_('no working directory: please specify a revision'))
327 raise util.Abort(_('no working directory: please specify a revision'))
328 node = ctx.node()
328 node = ctx.node()
329 dest = cmdutil.makefilename(repo, dest, node)
329 dest = cmdutil.makefilename(repo, dest, node)
330 if os.path.realpath(dest) == repo.root:
330 if os.path.realpath(dest) == repo.root:
331 raise util.Abort(_('repository root cannot be destination'))
331 raise util.Abort(_('repository root cannot be destination'))
332
332
333 kind = opts.get('type') or archival.guesskind(dest) or 'files'
333 kind = opts.get('type') or archival.guesskind(dest) or 'files'
334 prefix = opts.get('prefix')
334 prefix = opts.get('prefix')
335
335
336 if dest == '-':
336 if dest == '-':
337 if kind == 'files':
337 if kind == 'files':
338 raise util.Abort(_('cannot archive plain files to stdout'))
338 raise util.Abort(_('cannot archive plain files to stdout'))
339 dest = sys.stdout
339 dest = sys.stdout
340 if not prefix:
340 if not prefix:
341 prefix = os.path.basename(repo.root) + '-%h'
341 prefix = os.path.basename(repo.root) + '-%h'
342
342
343 prefix = cmdutil.makefilename(repo, prefix, node)
343 prefix = cmdutil.makefilename(repo, prefix, node)
344 matchfn = scmutil.match(repo, [], opts)
344 matchfn = scmutil.match(repo, [], opts)
345 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
345 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
346 matchfn, prefix, subrepos=opts.get('subrepos'))
346 matchfn, prefix, subrepos=opts.get('subrepos'))
347
347
348 @command('backout',
348 @command('backout',
349 [('', 'merge', None, _('merge with old dirstate parent after backout')),
349 [('', 'merge', None, _('merge with old dirstate parent after backout')),
350 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
350 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
351 ('t', 'tool', '', _('specify merge tool')),
351 ('t', 'tool', '', _('specify merge tool')),
352 ('r', 'rev', '', _('revision to backout'), _('REV')),
352 ('r', 'rev', '', _('revision to backout'), _('REV')),
353 ] + walkopts + commitopts + commitopts2,
353 ] + walkopts + commitopts + commitopts2,
354 _('[OPTION]... [-r] REV'))
354 _('[OPTION]... [-r] REV'))
355 def backout(ui, repo, node=None, rev=None, **opts):
355 def backout(ui, repo, node=None, rev=None, **opts):
356 '''reverse effect of earlier changeset
356 '''reverse effect of earlier changeset
357
357
358 Prepare a new changeset with the effect of REV undone in the
358 Prepare a new changeset with the effect of REV undone in the
359 current working directory.
359 current working directory.
360
360
361 If REV is the parent of the working directory, then this new changeset
361 If REV is the parent of the working directory, then this new changeset
362 is committed automatically. Otherwise, hg needs to merge the
362 is committed automatically. Otherwise, hg needs to merge the
363 changes and the merged result is left uncommitted.
363 changes and the merged result is left uncommitted.
364
364
365 By default, the pending changeset will have one parent,
365 By default, the pending changeset will have one parent,
366 maintaining a linear history. With --merge, the pending changeset
366 maintaining a linear history. With --merge, the pending changeset
367 will instead have two parents: the old parent of the working
367 will instead have two parents: the old parent of the working
368 directory and a new child of REV that simply undoes REV.
368 directory and a new child of REV that simply undoes REV.
369
369
370 Before version 1.7, the behavior without --merge was equivalent to
370 Before version 1.7, the behavior without --merge was equivalent to
371 specifying --merge followed by :hg:`update --clean .` to cancel
371 specifying --merge followed by :hg:`update --clean .` to cancel
372 the merge and leave the child of REV as a head to be merged
372 the merge and leave the child of REV as a head to be merged
373 separately.
373 separately.
374
374
375 See :hg:`help dates` for a list of formats valid for -d/--date.
375 See :hg:`help dates` for a list of formats valid for -d/--date.
376
376
377 Returns 0 on success.
377 Returns 0 on success.
378 '''
378 '''
379 if rev and node:
379 if rev and node:
380 raise util.Abort(_("please specify just one revision"))
380 raise util.Abort(_("please specify just one revision"))
381
381
382 if not rev:
382 if not rev:
383 rev = node
383 rev = node
384
384
385 if not rev:
385 if not rev:
386 raise util.Abort(_("please specify a revision to backout"))
386 raise util.Abort(_("please specify a revision to backout"))
387
387
388 date = opts.get('date')
388 date = opts.get('date')
389 if date:
389 if date:
390 opts['date'] = util.parsedate(date)
390 opts['date'] = util.parsedate(date)
391
391
392 cmdutil.bailifchanged(repo)
392 cmdutil.bailifchanged(repo)
393 node = scmutil.revsingle(repo, rev).node()
393 node = scmutil.revsingle(repo, rev).node()
394
394
395 op1, op2 = repo.dirstate.parents()
395 op1, op2 = repo.dirstate.parents()
396 a = repo.changelog.ancestor(op1, node)
396 a = repo.changelog.ancestor(op1, node)
397 if a != node:
397 if a != node:
398 raise util.Abort(_('cannot backout change on a different branch'))
398 raise util.Abort(_('cannot backout change on a different branch'))
399
399
400 p1, p2 = repo.changelog.parents(node)
400 p1, p2 = repo.changelog.parents(node)
401 if p1 == nullid:
401 if p1 == nullid:
402 raise util.Abort(_('cannot backout a change with no parents'))
402 raise util.Abort(_('cannot backout a change with no parents'))
403 if p2 != nullid:
403 if p2 != nullid:
404 if not opts.get('parent'):
404 if not opts.get('parent'):
405 raise util.Abort(_('cannot backout a merge changeset without '
405 raise util.Abort(_('cannot backout a merge changeset without '
406 '--parent'))
406 '--parent'))
407 p = repo.lookup(opts['parent'])
407 p = repo.lookup(opts['parent'])
408 if p not in (p1, p2):
408 if p not in (p1, p2):
409 raise util.Abort(_('%s is not a parent of %s') %
409 raise util.Abort(_('%s is not a parent of %s') %
410 (short(p), short(node)))
410 (short(p), short(node)))
411 parent = p
411 parent = p
412 else:
412 else:
413 if opts.get('parent'):
413 if opts.get('parent'):
414 raise util.Abort(_('cannot use --parent on non-merge changeset'))
414 raise util.Abort(_('cannot use --parent on non-merge changeset'))
415 parent = p1
415 parent = p1
416
416
417 # the backout should appear on the same branch
417 # the backout should appear on the same branch
418 branch = repo.dirstate.branch()
418 branch = repo.dirstate.branch()
419 hg.clean(repo, node, show_stats=False)
419 hg.clean(repo, node, show_stats=False)
420 repo.dirstate.setbranch(branch)
420 repo.dirstate.setbranch(branch)
421 revert_opts = opts.copy()
421 revert_opts = opts.copy()
422 revert_opts['date'] = None
422 revert_opts['date'] = None
423 revert_opts['all'] = True
423 revert_opts['all'] = True
424 revert_opts['rev'] = hex(parent)
424 revert_opts['rev'] = hex(parent)
425 revert_opts['no_backup'] = None
425 revert_opts['no_backup'] = None
426 revert(ui, repo, **revert_opts)
426 revert(ui, repo, **revert_opts)
427 if not opts.get('merge') and op1 != node:
427 if not opts.get('merge') and op1 != node:
428 try:
428 try:
429 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
429 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
430 return hg.update(repo, op1)
430 return hg.update(repo, op1)
431 finally:
431 finally:
432 ui.setconfig('ui', 'forcemerge', '')
432 ui.setconfig('ui', 'forcemerge', '')
433
433
434 commit_opts = opts.copy()
434 commit_opts = opts.copy()
435 commit_opts['addremove'] = False
435 commit_opts['addremove'] = False
436 if not commit_opts['message'] and not commit_opts['logfile']:
436 if not commit_opts['message'] and not commit_opts['logfile']:
437 # we don't translate commit messages
437 # we don't translate commit messages
438 commit_opts['message'] = "Backed out changeset %s" % short(node)
438 commit_opts['message'] = "Backed out changeset %s" % short(node)
439 commit_opts['force_editor'] = True
439 commit_opts['force_editor'] = True
440 commit(ui, repo, **commit_opts)
440 commit(ui, repo, **commit_opts)
441 def nice(node):
441 def nice(node):
442 return '%d:%s' % (repo.changelog.rev(node), short(node))
442 return '%d:%s' % (repo.changelog.rev(node), short(node))
443 ui.status(_('changeset %s backs out changeset %s\n') %
443 ui.status(_('changeset %s backs out changeset %s\n') %
444 (nice(repo.changelog.tip()), nice(node)))
444 (nice(repo.changelog.tip()), nice(node)))
445 if opts.get('merge') and op1 != node:
445 if opts.get('merge') and op1 != node:
446 hg.clean(repo, op1, show_stats=False)
446 hg.clean(repo, op1, show_stats=False)
447 ui.status(_('merging with changeset %s\n')
447 ui.status(_('merging with changeset %s\n')
448 % nice(repo.changelog.tip()))
448 % nice(repo.changelog.tip()))
449 try:
449 try:
450 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
450 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
451 return hg.merge(repo, hex(repo.changelog.tip()))
451 return hg.merge(repo, hex(repo.changelog.tip()))
452 finally:
452 finally:
453 ui.setconfig('ui', 'forcemerge', '')
453 ui.setconfig('ui', 'forcemerge', '')
454 return 0
454 return 0
455
455
456 @command('bisect',
456 @command('bisect',
457 [('r', 'reset', False, _('reset bisect state')),
457 [('r', 'reset', False, _('reset bisect state')),
458 ('g', 'good', False, _('mark changeset good')),
458 ('g', 'good', False, _('mark changeset good')),
459 ('b', 'bad', False, _('mark changeset bad')),
459 ('b', 'bad', False, _('mark changeset bad')),
460 ('s', 'skip', False, _('skip testing changeset')),
460 ('s', 'skip', False, _('skip testing changeset')),
461 ('e', 'extend', False, _('extend the bisect range')),
461 ('e', 'extend', False, _('extend the bisect range')),
462 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
462 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
463 ('U', 'noupdate', False, _('do not update to target'))],
463 ('U', 'noupdate', False, _('do not update to target'))],
464 _("[-gbsr] [-U] [-c CMD] [REV]"))
464 _("[-gbsr] [-U] [-c CMD] [REV]"))
465 def bisect(ui, repo, rev=None, extra=None, command=None,
465 def bisect(ui, repo, rev=None, extra=None, command=None,
466 reset=None, good=None, bad=None, skip=None, extend=None,
466 reset=None, good=None, bad=None, skip=None, extend=None,
467 noupdate=None):
467 noupdate=None):
468 """subdivision search of changesets
468 """subdivision search of changesets
469
469
470 This command helps to find changesets which introduce problems. To
470 This command helps to find changesets which introduce problems. To
471 use, mark the earliest changeset you know exhibits the problem as
471 use, mark the earliest changeset you know exhibits the problem as
472 bad, then mark the latest changeset which is free from the problem
472 bad, then mark the latest changeset which is free from the problem
473 as good. Bisect will update your working directory to a revision
473 as good. Bisect will update your working directory to a revision
474 for testing (unless the -U/--noupdate option is specified). Once
474 for testing (unless the -U/--noupdate option is specified). Once
475 you have performed tests, mark the working directory as good or
475 you have performed tests, mark the working directory as good or
476 bad, and bisect will either update to another candidate changeset
476 bad, and bisect will either update to another candidate changeset
477 or announce that it has found the bad revision.
477 or announce that it has found the bad revision.
478
478
479 As a shortcut, you can also use the revision argument to mark a
479 As a shortcut, you can also use the revision argument to mark a
480 revision as good or bad without checking it out first.
480 revision as good or bad without checking it out first.
481
481
482 If you supply a command, it will be used for automatic bisection.
482 If you supply a command, it will be used for automatic bisection.
483 Its exit status will be used to mark revisions as good or bad:
483 Its exit status will be used to mark revisions as good or bad:
484 status 0 means good, 125 means to skip the revision, 127
484 status 0 means good, 125 means to skip the revision, 127
485 (command not found) will abort the bisection, and any other
485 (command not found) will abort the bisection, and any other
486 non-zero exit status means the revision is bad.
486 non-zero exit status means the revision is bad.
487
487
488 Returns 0 on success.
488 Returns 0 on success.
489 """
489 """
490 def extendbisectrange(nodes, good):
490 def extendbisectrange(nodes, good):
491 # bisect is incomplete when it ends on a merge node and
491 # bisect is incomplete when it ends on a merge node and
492 # one of the parent was not checked.
492 # one of the parent was not checked.
493 parents = repo[nodes[0]].parents()
493 parents = repo[nodes[0]].parents()
494 if len(parents) > 1:
494 if len(parents) > 1:
495 side = good and state['bad'] or state['good']
495 side = good and state['bad'] or state['good']
496 num = len(set(i.node() for i in parents) & set(side))
496 num = len(set(i.node() for i in parents) & set(side))
497 if num == 1:
497 if num == 1:
498 return parents[0].ancestor(parents[1])
498 return parents[0].ancestor(parents[1])
499 return None
499 return None
500
500
501 def print_result(nodes, good):
501 def print_result(nodes, good):
502 displayer = cmdutil.show_changeset(ui, repo, {})
502 displayer = cmdutil.show_changeset(ui, repo, {})
503 if len(nodes) == 1:
503 if len(nodes) == 1:
504 # narrowed it down to a single revision
504 # narrowed it down to a single revision
505 if good:
505 if good:
506 ui.write(_("The first good revision is:\n"))
506 ui.write(_("The first good revision is:\n"))
507 else:
507 else:
508 ui.write(_("The first bad revision is:\n"))
508 ui.write(_("The first bad revision is:\n"))
509 displayer.show(repo[nodes[0]])
509 displayer.show(repo[nodes[0]])
510 extendnode = extendbisectrange(nodes, good)
510 extendnode = extendbisectrange(nodes, good)
511 if extendnode is not None:
511 if extendnode is not None:
512 ui.write(_('Not all ancestors of this changeset have been'
512 ui.write(_('Not all ancestors of this changeset have been'
513 ' checked.\nUse bisect --extend to continue the '
513 ' checked.\nUse bisect --extend to continue the '
514 'bisection from\nthe common ancestor, %s.\n')
514 'bisection from\nthe common ancestor, %s.\n')
515 % extendnode)
515 % extendnode)
516 else:
516 else:
517 # multiple possible revisions
517 # multiple possible revisions
518 if good:
518 if good:
519 ui.write(_("Due to skipped revisions, the first "
519 ui.write(_("Due to skipped revisions, the first "
520 "good revision could be any of:\n"))
520 "good revision could be any of:\n"))
521 else:
521 else:
522 ui.write(_("Due to skipped revisions, the first "
522 ui.write(_("Due to skipped revisions, the first "
523 "bad revision could be any of:\n"))
523 "bad revision could be any of:\n"))
524 for n in nodes:
524 for n in nodes:
525 displayer.show(repo[n])
525 displayer.show(repo[n])
526 displayer.close()
526 displayer.close()
527
527
528 def check_state(state, interactive=True):
528 def check_state(state, interactive=True):
529 if not state['good'] or not state['bad']:
529 if not state['good'] or not state['bad']:
530 if (good or bad or skip or reset) and interactive:
530 if (good or bad or skip or reset) and interactive:
531 return
531 return
532 if not state['good']:
532 if not state['good']:
533 raise util.Abort(_('cannot bisect (no known good revisions)'))
533 raise util.Abort(_('cannot bisect (no known good revisions)'))
534 else:
534 else:
535 raise util.Abort(_('cannot bisect (no known bad revisions)'))
535 raise util.Abort(_('cannot bisect (no known bad revisions)'))
536 return True
536 return True
537
537
538 # backward compatibility
538 # backward compatibility
539 if rev in "good bad reset init".split():
539 if rev in "good bad reset init".split():
540 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
540 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
541 cmd, rev, extra = rev, extra, None
541 cmd, rev, extra = rev, extra, None
542 if cmd == "good":
542 if cmd == "good":
543 good = True
543 good = True
544 elif cmd == "bad":
544 elif cmd == "bad":
545 bad = True
545 bad = True
546 else:
546 else:
547 reset = True
547 reset = True
548 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
548 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
549 raise util.Abort(_('incompatible arguments'))
549 raise util.Abort(_('incompatible arguments'))
550
550
551 if reset:
551 if reset:
552 p = repo.join("bisect.state")
552 p = repo.join("bisect.state")
553 if os.path.exists(p):
553 if os.path.exists(p):
554 os.unlink(p)
554 os.unlink(p)
555 return
555 return
556
556
557 state = hbisect.load_state(repo)
557 state = hbisect.load_state(repo)
558
558
559 if command:
559 if command:
560 changesets = 1
560 changesets = 1
561 try:
561 try:
562 while changesets:
562 while changesets:
563 # update state
563 # update state
564 status = util.system(command)
564 status = util.system(command)
565 if status == 125:
565 if status == 125:
566 transition = "skip"
566 transition = "skip"
567 elif status == 0:
567 elif status == 0:
568 transition = "good"
568 transition = "good"
569 # status < 0 means process was killed
569 # status < 0 means process was killed
570 elif status == 127:
570 elif status == 127:
571 raise util.Abort(_("failed to execute %s") % command)
571 raise util.Abort(_("failed to execute %s") % command)
572 elif status < 0:
572 elif status < 0:
573 raise util.Abort(_("%s killed") % command)
573 raise util.Abort(_("%s killed") % command)
574 else:
574 else:
575 transition = "bad"
575 transition = "bad"
576 ctx = scmutil.revsingle(repo, rev)
576 ctx = scmutil.revsingle(repo, rev)
577 rev = None # clear for future iterations
577 rev = None # clear for future iterations
578 state[transition].append(ctx.node())
578 state[transition].append(ctx.node())
579 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
579 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
580 check_state(state, interactive=False)
580 check_state(state, interactive=False)
581 # bisect
581 # bisect
582 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
582 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
583 # update to next check
583 # update to next check
584 cmdutil.bailifchanged(repo)
584 cmdutil.bailifchanged(repo)
585 hg.clean(repo, nodes[0], show_stats=False)
585 hg.clean(repo, nodes[0], show_stats=False)
586 finally:
586 finally:
587 hbisect.save_state(repo, state)
587 hbisect.save_state(repo, state)
588 print_result(nodes, good)
588 print_result(nodes, good)
589 return
589 return
590
590
591 # update state
591 # update state
592
592
593 if rev:
593 if rev:
594 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
594 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
595 else:
595 else:
596 nodes = [repo.lookup('.')]
596 nodes = [repo.lookup('.')]
597
597
598 if good or bad or skip:
598 if good or bad or skip:
599 if good:
599 if good:
600 state['good'] += nodes
600 state['good'] += nodes
601 elif bad:
601 elif bad:
602 state['bad'] += nodes
602 state['bad'] += nodes
603 elif skip:
603 elif skip:
604 state['skip'] += nodes
604 state['skip'] += nodes
605 hbisect.save_state(repo, state)
605 hbisect.save_state(repo, state)
606
606
607 if not check_state(state):
607 if not check_state(state):
608 return
608 return
609
609
610 # actually bisect
610 # actually bisect
611 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
611 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
612 if extend:
612 if extend:
613 if not changesets:
613 if not changesets:
614 extendnode = extendbisectrange(nodes, good)
614 extendnode = extendbisectrange(nodes, good)
615 if extendnode is not None:
615 if extendnode is not None:
616 ui.write(_("Extending search to changeset %d:%s\n"
616 ui.write(_("Extending search to changeset %d:%s\n"
617 % (extendnode.rev(), extendnode)))
617 % (extendnode.rev(), extendnode)))
618 if noupdate:
618 if noupdate:
619 return
619 return
620 cmdutil.bailifchanged(repo)
620 cmdutil.bailifchanged(repo)
621 return hg.clean(repo, extendnode.node())
621 return hg.clean(repo, extendnode.node())
622 raise util.Abort(_("nothing to extend"))
622 raise util.Abort(_("nothing to extend"))
623
623
624 if changesets == 0:
624 if changesets == 0:
625 print_result(nodes, good)
625 print_result(nodes, good)
626 else:
626 else:
627 assert len(nodes) == 1 # only a single node can be tested next
627 assert len(nodes) == 1 # only a single node can be tested next
628 node = nodes[0]
628 node = nodes[0]
629 # compute the approximate number of remaining tests
629 # compute the approximate number of remaining tests
630 tests, size = 0, 2
630 tests, size = 0, 2
631 while size <= changesets:
631 while size <= changesets:
632 tests, size = tests + 1, size * 2
632 tests, size = tests + 1, size * 2
633 rev = repo.changelog.rev(node)
633 rev = repo.changelog.rev(node)
634 ui.write(_("Testing changeset %d:%s "
634 ui.write(_("Testing changeset %d:%s "
635 "(%d changesets remaining, ~%d tests)\n")
635 "(%d changesets remaining, ~%d tests)\n")
636 % (rev, short(node), changesets, tests))
636 % (rev, short(node), changesets, tests))
637 if not noupdate:
637 if not noupdate:
638 cmdutil.bailifchanged(repo)
638 cmdutil.bailifchanged(repo)
639 return hg.clean(repo, node)
639 return hg.clean(repo, node)
640
640
641 @command('bookmarks',
641 @command('bookmarks',
642 [('f', 'force', False, _('force')),
642 [('f', 'force', False, _('force')),
643 ('r', 'rev', '', _('revision'), _('REV')),
643 ('r', 'rev', '', _('revision'), _('REV')),
644 ('d', 'delete', False, _('delete a given bookmark')),
644 ('d', 'delete', False, _('delete a given bookmark')),
645 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
645 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
646 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
646 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
647 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
647 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
648 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
648 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
649 rename=None, inactive=False):
649 rename=None, inactive=False):
650 '''track a line of development with movable markers
650 '''track a line of development with movable markers
651
651
652 Bookmarks are pointers to certain commits that move when
652 Bookmarks are pointers to certain commits that move when
653 committing. Bookmarks are local. They can be renamed, copied and
653 committing. Bookmarks are local. They can be renamed, copied and
654 deleted. It is possible to use bookmark names in :hg:`merge` and
654 deleted. It is possible to use bookmark names in :hg:`merge` and
655 :hg:`update` to merge and update respectively to a given bookmark.
655 :hg:`update` to merge and update respectively to a given bookmark.
656
656
657 You can use :hg:`bookmark NAME` to set a bookmark on the working
657 You can use :hg:`bookmark NAME` to set a bookmark on the working
658 directory's parent revision with the given name. If you specify
658 directory's parent revision with the given name. If you specify
659 a revision using -r REV (where REV may be an existing bookmark),
659 a revision using -r REV (where REV may be an existing bookmark),
660 the bookmark is assigned to that revision.
660 the bookmark is assigned to that revision.
661
661
662 Bookmarks can be pushed and pulled between repositories (see :hg:`help
662 Bookmarks can be pushed and pulled between repositories (see :hg:`help
663 push` and :hg:`help pull`). This requires both the local and remote
663 push` and :hg:`help pull`). This requires both the local and remote
664 repositories to support bookmarks. For versions prior to 1.8, this means
664 repositories to support bookmarks. For versions prior to 1.8, this means
665 the bookmarks extension must be enabled.
665 the bookmarks extension must be enabled.
666 '''
666 '''
667 hexfn = ui.debugflag and hex or short
667 hexfn = ui.debugflag and hex or short
668 marks = repo._bookmarks
668 marks = repo._bookmarks
669 cur = repo.changectx('.').node()
669 cur = repo.changectx('.').node()
670
670
671 if rename:
671 if rename:
672 if rename not in marks:
672 if rename not in marks:
673 raise util.Abort(_("bookmark '%s' does not exist") % rename)
673 raise util.Abort(_("bookmark '%s' does not exist") % rename)
674 if mark in marks and not force:
674 if mark in marks and not force:
675 raise util.Abort(_("bookmark '%s' already exists "
675 raise util.Abort(_("bookmark '%s' already exists "
676 "(use -f to force)") % mark)
676 "(use -f to force)") % mark)
677 if mark is None:
677 if mark is None:
678 raise util.Abort(_("new bookmark name required"))
678 raise util.Abort(_("new bookmark name required"))
679 marks[mark] = marks[rename]
679 marks[mark] = marks[rename]
680 if repo._bookmarkcurrent == rename and not inactive:
680 if repo._bookmarkcurrent == rename and not inactive:
681 bookmarks.setcurrent(repo, mark)
681 bookmarks.setcurrent(repo, mark)
682 del marks[rename]
682 del marks[rename]
683 bookmarks.write(repo)
683 bookmarks.write(repo)
684 return
684 return
685
685
686 if delete:
686 if delete:
687 if mark is None:
687 if mark is None:
688 raise util.Abort(_("bookmark name required"))
688 raise util.Abort(_("bookmark name required"))
689 if mark not in marks:
689 if mark not in marks:
690 raise util.Abort(_("bookmark '%s' does not exist") % mark)
690 raise util.Abort(_("bookmark '%s' does not exist") % mark)
691 if mark == repo._bookmarkcurrent:
691 if mark == repo._bookmarkcurrent:
692 bookmarks.setcurrent(repo, None)
692 bookmarks.setcurrent(repo, None)
693 del marks[mark]
693 del marks[mark]
694 bookmarks.write(repo)
694 bookmarks.write(repo)
695 return
695 return
696
696
697 if mark is not None:
697 if mark is not None:
698 if "\n" in mark:
698 if "\n" in mark:
699 raise util.Abort(_("bookmark name cannot contain newlines"))
699 raise util.Abort(_("bookmark name cannot contain newlines"))
700 mark = mark.strip()
700 mark = mark.strip()
701 if not mark:
701 if not mark:
702 raise util.Abort(_("bookmark names cannot consist entirely of "
702 raise util.Abort(_("bookmark names cannot consist entirely of "
703 "whitespace"))
703 "whitespace"))
704 if inactive and mark == repo._bookmarkcurrent:
704 if inactive and mark == repo._bookmarkcurrent:
705 bookmarks.setcurrent(repo, None)
705 bookmarks.setcurrent(repo, None)
706 return
706 return
707 if mark in marks and not force:
707 if mark in marks and not force:
708 raise util.Abort(_("bookmark '%s' already exists "
708 raise util.Abort(_("bookmark '%s' already exists "
709 "(use -f to force)") % mark)
709 "(use -f to force)") % mark)
710 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
710 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
711 and not force):
711 and not force):
712 raise util.Abort(
712 raise util.Abort(
713 _("a bookmark cannot have the name of an existing branch"))
713 _("a bookmark cannot have the name of an existing branch"))
714 if rev:
714 if rev:
715 marks[mark] = repo.lookup(rev)
715 marks[mark] = repo.lookup(rev)
716 else:
716 else:
717 marks[mark] = repo.changectx('.').node()
717 marks[mark] = repo.changectx('.').node()
718 if not inactive and repo.changectx('.').node() == marks[mark]:
718 if not inactive and repo.changectx('.').node() == marks[mark]:
719 bookmarks.setcurrent(repo, mark)
719 bookmarks.setcurrent(repo, mark)
720 bookmarks.write(repo)
720 bookmarks.write(repo)
721 return
721 return
722
722
723 if mark is None:
723 if mark is None:
724 if rev:
724 if rev:
725 raise util.Abort(_("bookmark name required"))
725 raise util.Abort(_("bookmark name required"))
726 if len(marks) == 0:
726 if len(marks) == 0:
727 ui.status(_("no bookmarks set\n"))
727 ui.status(_("no bookmarks set\n"))
728 else:
728 else:
729 for bmark, n in sorted(marks.iteritems()):
729 for bmark, n in sorted(marks.iteritems()):
730 current = repo._bookmarkcurrent
730 current = repo._bookmarkcurrent
731 if bmark == current and n == cur:
731 if bmark == current and n == cur:
732 prefix, label = '*', 'bookmarks.current'
732 prefix, label = '*', 'bookmarks.current'
733 else:
733 else:
734 prefix, label = ' ', ''
734 prefix, label = ' ', ''
735
735
736 if ui.quiet:
736 if ui.quiet:
737 ui.write("%s\n" % bmark, label=label)
737 ui.write("%s\n" % bmark, label=label)
738 else:
738 else:
739 ui.write(" %s %-25s %d:%s\n" % (
739 ui.write(" %s %-25s %d:%s\n" % (
740 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
740 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
741 label=label)
741 label=label)
742 return
742 return
743
743
744 @command('branch',
744 @command('branch',
745 [('f', 'force', None,
745 [('f', 'force', None,
746 _('set branch name even if it shadows an existing branch')),
746 _('set branch name even if it shadows an existing branch')),
747 ('C', 'clean', None, _('reset branch name to parent branch name'))],
747 ('C', 'clean', None, _('reset branch name to parent branch name'))],
748 _('[-fC] [NAME]'))
748 _('[-fC] [NAME]'))
749 def branch(ui, repo, label=None, **opts):
749 def branch(ui, repo, label=None, **opts):
750 """set or show the current branch name
750 """set or show the current branch name
751
751
752 With no argument, show the current branch name. With one argument,
752 With no argument, show the current branch name. With one argument,
753 set the working directory branch name (the branch will not exist
753 set the working directory branch name (the branch will not exist
754 in the repository until the next commit). Standard practice
754 in the repository until the next commit). Standard practice
755 recommends that primary development take place on the 'default'
755 recommends that primary development take place on the 'default'
756 branch.
756 branch.
757
757
758 Unless -f/--force is specified, branch will not let you set a
758 Unless -f/--force is specified, branch will not let you set a
759 branch name that already exists, even if it's inactive.
759 branch name that already exists, even if it's inactive.
760
760
761 Use -C/--clean to reset the working directory branch to that of
761 Use -C/--clean to reset the working directory branch to that of
762 the parent of the working directory, negating a previous branch
762 the parent of the working directory, negating a previous branch
763 change.
763 change.
764
764
765 Use the command :hg:`update` to switch to an existing branch. Use
765 Use the command :hg:`update` to switch to an existing branch. Use
766 :hg:`commit --close-branch` to mark this branch as closed.
766 :hg:`commit --close-branch` to mark this branch as closed.
767
767
768 Returns 0 on success.
768 Returns 0 on success.
769 """
769 """
770
770
771 if opts.get('clean'):
771 if opts.get('clean'):
772 label = repo[None].p1().branch()
772 label = repo[None].p1().branch()
773 repo.dirstate.setbranch(label)
773 repo.dirstate.setbranch(label)
774 ui.status(_('reset working directory to branch %s\n') % label)
774 ui.status(_('reset working directory to branch %s\n') % label)
775 elif label:
775 elif label:
776 if not opts.get('force') and label in repo.branchtags():
776 if not opts.get('force') and label in repo.branchtags():
777 if label not in [p.branch() for p in repo.parents()]:
777 if label not in [p.branch() for p in repo.parents()]:
778 raise util.Abort(_('a branch of the same name already exists'),
778 raise util.Abort(_('a branch of the same name already exists'),
779 # i18n: "it" refers to an existing branch
779 # i18n: "it" refers to an existing branch
780 hint=_("use 'hg update' to switch to it"))
780 hint=_("use 'hg update' to switch to it"))
781 repo.dirstate.setbranch(label)
781 repo.dirstate.setbranch(label)
782 ui.status(_('marked working directory as branch %s\n') % label)
782 ui.status(_('marked working directory as branch %s\n') % label)
783 else:
783 else:
784 ui.write("%s\n" % repo.dirstate.branch())
784 ui.write("%s\n" % repo.dirstate.branch())
785
785
786 @command('branches',
786 @command('branches',
787 [('a', 'active', False, _('show only branches that have unmerged heads')),
787 [('a', 'active', False, _('show only branches that have unmerged heads')),
788 ('c', 'closed', False, _('show normal and closed branches'))],
788 ('c', 'closed', False, _('show normal and closed branches'))],
789 _('[-ac]'))
789 _('[-ac]'))
790 def branches(ui, repo, active=False, closed=False):
790 def branches(ui, repo, active=False, closed=False):
791 """list repository named branches
791 """list repository named branches
792
792
793 List the repository's named branches, indicating which ones are
793 List the repository's named branches, indicating which ones are
794 inactive. If -c/--closed is specified, also list branches which have
794 inactive. If -c/--closed is specified, also list branches which have
795 been marked closed (see :hg:`commit --close-branch`).
795 been marked closed (see :hg:`commit --close-branch`).
796
796
797 If -a/--active is specified, only show active branches. A branch
797 If -a/--active is specified, only show active branches. A branch
798 is considered active if it contains repository heads.
798 is considered active if it contains repository heads.
799
799
800 Use the command :hg:`update` to switch to an existing branch.
800 Use the command :hg:`update` to switch to an existing branch.
801
801
802 Returns 0.
802 Returns 0.
803 """
803 """
804
804
805 hexfunc = ui.debugflag and hex or short
805 hexfunc = ui.debugflag and hex or short
806 activebranches = [repo[n].branch() for n in repo.heads()]
806 activebranches = [repo[n].branch() for n in repo.heads()]
807 def testactive(tag, node):
807 def testactive(tag, node):
808 realhead = tag in activebranches
808 realhead = tag in activebranches
809 open = node in repo.branchheads(tag, closed=False)
809 open = node in repo.branchheads(tag, closed=False)
810 return realhead and open
810 return realhead and open
811 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
811 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
812 for tag, node in repo.branchtags().items()],
812 for tag, node in repo.branchtags().items()],
813 reverse=True)
813 reverse=True)
814
814
815 for isactive, node, tag in branches:
815 for isactive, node, tag in branches:
816 if (not active) or isactive:
816 if (not active) or isactive:
817 if ui.quiet:
817 if ui.quiet:
818 ui.write("%s\n" % tag)
818 ui.write("%s\n" % tag)
819 else:
819 else:
820 hn = repo.lookup(node)
820 hn = repo.lookup(node)
821 if isactive:
821 if isactive:
822 label = 'branches.active'
822 label = 'branches.active'
823 notice = ''
823 notice = ''
824 elif hn not in repo.branchheads(tag, closed=False):
824 elif hn not in repo.branchheads(tag, closed=False):
825 if not closed:
825 if not closed:
826 continue
826 continue
827 label = 'branches.closed'
827 label = 'branches.closed'
828 notice = _(' (closed)')
828 notice = _(' (closed)')
829 else:
829 else:
830 label = 'branches.inactive'
830 label = 'branches.inactive'
831 notice = _(' (inactive)')
831 notice = _(' (inactive)')
832 if tag == repo.dirstate.branch():
832 if tag == repo.dirstate.branch():
833 label = 'branches.current'
833 label = 'branches.current'
834 rev = str(node).rjust(31 - encoding.colwidth(tag))
834 rev = str(node).rjust(31 - encoding.colwidth(tag))
835 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
835 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
836 tag = ui.label(tag, label)
836 tag = ui.label(tag, label)
837 ui.write("%s %s%s\n" % (tag, rev, notice))
837 ui.write("%s %s%s\n" % (tag, rev, notice))
838
838
839 @command('bundle',
839 @command('bundle',
840 [('f', 'force', None, _('run even when the destination is unrelated')),
840 [('f', 'force', None, _('run even when the destination is unrelated')),
841 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
841 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
842 _('REV')),
842 _('REV')),
843 ('b', 'branch', [], _('a specific branch you would like to bundle'),
843 ('b', 'branch', [], _('a specific branch you would like to bundle'),
844 _('BRANCH')),
844 _('BRANCH')),
845 ('', 'base', [],
845 ('', 'base', [],
846 _('a base changeset assumed to be available at the destination'),
846 _('a base changeset assumed to be available at the destination'),
847 _('REV')),
847 _('REV')),
848 ('a', 'all', None, _('bundle all changesets in the repository')),
848 ('a', 'all', None, _('bundle all changesets in the repository')),
849 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
849 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
850 ] + remoteopts,
850 ] + remoteopts,
851 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
851 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
852 def bundle(ui, repo, fname, dest=None, **opts):
852 def bundle(ui, repo, fname, dest=None, **opts):
853 """create a changegroup file
853 """create a changegroup file
854
854
855 Generate a compressed changegroup file collecting changesets not
855 Generate a compressed changegroup file collecting changesets not
856 known to be in another repository.
856 known to be in another repository.
857
857
858 If you omit the destination repository, then hg assumes the
858 If you omit the destination repository, then hg assumes the
859 destination will have all the nodes you specify with --base
859 destination will have all the nodes you specify with --base
860 parameters. To create a bundle containing all changesets, use
860 parameters. To create a bundle containing all changesets, use
861 -a/--all (or --base null).
861 -a/--all (or --base null).
862
862
863 You can change compression method with the -t/--type option.
863 You can change compression method with the -t/--type option.
864 The available compression methods are: none, bzip2, and
864 The available compression methods are: none, bzip2, and
865 gzip (by default, bundles are compressed using bzip2).
865 gzip (by default, bundles are compressed using bzip2).
866
866
867 The bundle file can then be transferred using conventional means
867 The bundle file can then be transferred using conventional means
868 and applied to another repository with the unbundle or pull
868 and applied to another repository with the unbundle or pull
869 command. This is useful when direct push and pull are not
869 command. This is useful when direct push and pull are not
870 available or when exporting an entire repository is undesirable.
870 available or when exporting an entire repository is undesirable.
871
871
872 Applying bundles preserves all changeset contents including
872 Applying bundles preserves all changeset contents including
873 permissions, copy/rename information, and revision history.
873 permissions, copy/rename information, and revision history.
874
874
875 Returns 0 on success, 1 if no changes found.
875 Returns 0 on success, 1 if no changes found.
876 """
876 """
877 revs = None
877 revs = None
878 if 'rev' in opts:
878 if 'rev' in opts:
879 revs = scmutil.revrange(repo, opts['rev'])
879 revs = scmutil.revrange(repo, opts['rev'])
880
880
881 if opts.get('all'):
881 if opts.get('all'):
882 base = ['null']
882 base = ['null']
883 else:
883 else:
884 base = scmutil.revrange(repo, opts.get('base'))
884 base = scmutil.revrange(repo, opts.get('base'))
885 if base:
885 if base:
886 if dest:
886 if dest:
887 raise util.Abort(_("--base is incompatible with specifying "
887 raise util.Abort(_("--base is incompatible with specifying "
888 "a destination"))
888 "a destination"))
889 common = [repo.lookup(rev) for rev in base]
889 common = [repo.lookup(rev) for rev in base]
890 heads = revs and map(repo.lookup, revs) or revs
890 heads = revs and map(repo.lookup, revs) or revs
891 else:
891 else:
892 dest = ui.expandpath(dest or 'default-push', dest or 'default')
892 dest = ui.expandpath(dest or 'default-push', dest or 'default')
893 dest, branches = hg.parseurl(dest, opts.get('branch'))
893 dest, branches = hg.parseurl(dest, opts.get('branch'))
894 other = hg.repository(hg.remoteui(repo, opts), dest)
894 other = hg.repository(hg.remoteui(repo, opts), dest)
895 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
895 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
896 heads = revs and map(repo.lookup, revs) or revs
896 heads = revs and map(repo.lookup, revs) or revs
897 common, outheads = discovery.findcommonoutgoing(repo, other,
897 common, outheads = discovery.findcommonoutgoing(repo, other,
898 onlyheads=heads,
898 onlyheads=heads,
899 force=opts.get('force'))
899 force=opts.get('force'))
900
900
901 cg = repo.getbundle('bundle', common=common, heads=heads)
901 cg = repo.getbundle('bundle', common=common, heads=heads)
902 if not cg:
902 if not cg:
903 ui.status(_("no changes found\n"))
903 ui.status(_("no changes found\n"))
904 return 1
904 return 1
905
905
906 bundletype = opts.get('type', 'bzip2').lower()
906 bundletype = opts.get('type', 'bzip2').lower()
907 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
907 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
908 bundletype = btypes.get(bundletype)
908 bundletype = btypes.get(bundletype)
909 if bundletype not in changegroup.bundletypes:
909 if bundletype not in changegroup.bundletypes:
910 raise util.Abort(_('unknown bundle type specified with --type'))
910 raise util.Abort(_('unknown bundle type specified with --type'))
911
911
912 changegroup.writebundle(cg, fname, bundletype)
912 changegroup.writebundle(cg, fname, bundletype)
913
913
914 @command('cat',
914 @command('cat',
915 [('o', 'output', '',
915 [('o', 'output', '',
916 _('print output to file with formatted name'), _('FORMAT')),
916 _('print output to file with formatted name'), _('FORMAT')),
917 ('r', 'rev', '', _('print the given revision'), _('REV')),
917 ('r', 'rev', '', _('print the given revision'), _('REV')),
918 ('', 'decode', None, _('apply any matching decode filter')),
918 ('', 'decode', None, _('apply any matching decode filter')),
919 ] + walkopts,
919 ] + walkopts,
920 _('[OPTION]... FILE...'))
920 _('[OPTION]... FILE...'))
921 def cat(ui, repo, file1, *pats, **opts):
921 def cat(ui, repo, file1, *pats, **opts):
922 """output the current or given revision of files
922 """output the current or given revision of files
923
923
924 Print the specified files as they were at the given revision. If
924 Print the specified files as they were at the given revision. If
925 no revision is given, the parent of the working directory is used,
925 no revision is given, the parent of the working directory is used,
926 or tip if no revision is checked out.
926 or tip if no revision is checked out.
927
927
928 Output may be to a file, in which case the name of the file is
928 Output may be to a file, in which case the name of the file is
929 given using a format string. The formatting rules are the same as
929 given using a format string. The formatting rules are the same as
930 for the export command, with the following additions:
930 for the export command, with the following additions:
931
931
932 :``%s``: basename of file being printed
932 :``%s``: basename of file being printed
933 :``%d``: dirname of file being printed, or '.' if in repository root
933 :``%d``: dirname of file being printed, or '.' if in repository root
934 :``%p``: root-relative path name of file being printed
934 :``%p``: root-relative path name of file being printed
935
935
936 Returns 0 on success.
936 Returns 0 on success.
937 """
937 """
938 ctx = scmutil.revsingle(repo, opts.get('rev'))
938 ctx = scmutil.revsingle(repo, opts.get('rev'))
939 err = 1
939 err = 1
940 m = scmutil.match(repo, (file1,) + pats, opts)
940 m = scmutil.match(repo, (file1,) + pats, opts)
941 for abs in ctx.walk(m):
941 for abs in ctx.walk(m):
942 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
942 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
943 pathname=abs)
943 pathname=abs)
944 data = ctx[abs].data()
944 data = ctx[abs].data()
945 if opts.get('decode'):
945 if opts.get('decode'):
946 data = repo.wwritedata(abs, data)
946 data = repo.wwritedata(abs, data)
947 fp.write(data)
947 fp.write(data)
948 fp.close()
948 fp.close()
949 err = 0
949 err = 0
950 return err
950 return err
951
951
952 @command('^clone',
952 @command('^clone',
953 [('U', 'noupdate', None,
953 [('U', 'noupdate', None,
954 _('the clone will include an empty working copy (only a repository)')),
954 _('the clone will include an empty working copy (only a repository)')),
955 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
955 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
956 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
956 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
957 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
957 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
958 ('', 'pull', None, _('use pull protocol to copy metadata')),
958 ('', 'pull', None, _('use pull protocol to copy metadata')),
959 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
959 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
960 ] + remoteopts,
960 ] + remoteopts,
961 _('[OPTION]... SOURCE [DEST]'))
961 _('[OPTION]... SOURCE [DEST]'))
962 def clone(ui, source, dest=None, **opts):
962 def clone(ui, source, dest=None, **opts):
963 """make a copy of an existing repository
963 """make a copy of an existing repository
964
964
965 Create a copy of an existing repository in a new directory.
965 Create a copy of an existing repository in a new directory.
966
966
967 If no destination directory name is specified, it defaults to the
967 If no destination directory name is specified, it defaults to the
968 basename of the source.
968 basename of the source.
969
969
970 The location of the source is added to the new repository's
970 The location of the source is added to the new repository's
971 ``.hg/hgrc`` file, as the default to be used for future pulls.
971 ``.hg/hgrc`` file, as the default to be used for future pulls.
972
972
973 See :hg:`help urls` for valid source format details.
973 See :hg:`help urls` for valid source format details.
974
974
975 It is possible to specify an ``ssh://`` URL as the destination, but no
975 It is possible to specify an ``ssh://`` URL as the destination, but no
976 ``.hg/hgrc`` and working directory will be created on the remote side.
976 ``.hg/hgrc`` and working directory will be created on the remote side.
977 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
977 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
978
978
979 A set of changesets (tags, or branch names) to pull may be specified
979 A set of changesets (tags, or branch names) to pull may be specified
980 by listing each changeset (tag, or branch name) with -r/--rev.
980 by listing each changeset (tag, or branch name) with -r/--rev.
981 If -r/--rev is used, the cloned repository will contain only a subset
981 If -r/--rev is used, the cloned repository will contain only a subset
982 of the changesets of the source repository. Only the set of changesets
982 of the changesets of the source repository. Only the set of changesets
983 defined by all -r/--rev options (including all their ancestors)
983 defined by all -r/--rev options (including all their ancestors)
984 will be pulled into the destination repository.
984 will be pulled into the destination repository.
985 No subsequent changesets (including subsequent tags) will be present
985 No subsequent changesets (including subsequent tags) will be present
986 in the destination.
986 in the destination.
987
987
988 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
988 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
989 local source repositories.
989 local source repositories.
990
990
991 For efficiency, hardlinks are used for cloning whenever the source
991 For efficiency, hardlinks are used for cloning whenever the source
992 and destination are on the same filesystem (note this applies only
992 and destination are on the same filesystem (note this applies only
993 to the repository data, not to the working directory). Some
993 to the repository data, not to the working directory). Some
994 filesystems, such as AFS, implement hardlinking incorrectly, but
994 filesystems, such as AFS, implement hardlinking incorrectly, but
995 do not report errors. In these cases, use the --pull option to
995 do not report errors. In these cases, use the --pull option to
996 avoid hardlinking.
996 avoid hardlinking.
997
997
998 In some cases, you can clone repositories and the working directory
998 In some cases, you can clone repositories and the working directory
999 using full hardlinks with ::
999 using full hardlinks with ::
1000
1000
1001 $ cp -al REPO REPOCLONE
1001 $ cp -al REPO REPOCLONE
1002
1002
1003 This is the fastest way to clone, but it is not always safe. The
1003 This is the fastest way to clone, but it is not always safe. The
1004 operation is not atomic (making sure REPO is not modified during
1004 operation is not atomic (making sure REPO is not modified during
1005 the operation is up to you) and you have to make sure your editor
1005 the operation is up to you) and you have to make sure your editor
1006 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
1006 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
1007 this is not compatible with certain extensions that place their
1007 this is not compatible with certain extensions that place their
1008 metadata under the .hg directory, such as mq.
1008 metadata under the .hg directory, such as mq.
1009
1009
1010 Mercurial will update the working directory to the first applicable
1010 Mercurial will update the working directory to the first applicable
1011 revision from this list:
1011 revision from this list:
1012
1012
1013 a) null if -U or the source repository has no changesets
1013 a) null if -U or the source repository has no changesets
1014 b) if -u . and the source repository is local, the first parent of
1014 b) if -u . and the source repository is local, the first parent of
1015 the source repository's working directory
1015 the source repository's working directory
1016 c) the changeset specified with -u (if a branch name, this means the
1016 c) the changeset specified with -u (if a branch name, this means the
1017 latest head of that branch)
1017 latest head of that branch)
1018 d) the changeset specified with -r
1018 d) the changeset specified with -r
1019 e) the tipmost head specified with -b
1019 e) the tipmost head specified with -b
1020 f) the tipmost head specified with the url#branch source syntax
1020 f) the tipmost head specified with the url#branch source syntax
1021 g) the tipmost head of the default branch
1021 g) the tipmost head of the default branch
1022 h) tip
1022 h) tip
1023
1023
1024 Returns 0 on success.
1024 Returns 0 on success.
1025 """
1025 """
1026 if opts.get('noupdate') and opts.get('updaterev'):
1026 if opts.get('noupdate') and opts.get('updaterev'):
1027 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1027 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1028
1028
1029 r = hg.clone(hg.remoteui(ui, opts), source, dest,
1029 r = hg.clone(hg.remoteui(ui, opts), source, dest,
1030 pull=opts.get('pull'),
1030 pull=opts.get('pull'),
1031 stream=opts.get('uncompressed'),
1031 stream=opts.get('uncompressed'),
1032 rev=opts.get('rev'),
1032 rev=opts.get('rev'),
1033 update=opts.get('updaterev') or not opts.get('noupdate'),
1033 update=opts.get('updaterev') or not opts.get('noupdate'),
1034 branch=opts.get('branch'))
1034 branch=opts.get('branch'))
1035
1035
1036 return r is None
1036 return r is None
1037
1037
1038 @command('^commit|ci',
1038 @command('^commit|ci',
1039 [('A', 'addremove', None,
1039 [('A', 'addremove', None,
1040 _('mark new/missing files as added/removed before committing')),
1040 _('mark new/missing files as added/removed before committing')),
1041 ('', 'close-branch', None,
1041 ('', 'close-branch', None,
1042 _('mark a branch as closed, hiding it from the branch list')),
1042 _('mark a branch as closed, hiding it from the branch list')),
1043 ] + walkopts + commitopts + commitopts2,
1043 ] + walkopts + commitopts + commitopts2,
1044 _('[OPTION]... [FILE]...'))
1044 _('[OPTION]... [FILE]...'))
1045 def commit(ui, repo, *pats, **opts):
1045 def commit(ui, repo, *pats, **opts):
1046 """commit the specified files or all outstanding changes
1046 """commit the specified files or all outstanding changes
1047
1047
1048 Commit changes to the given files into the repository. Unlike a
1048 Commit changes to the given files into the repository. Unlike a
1049 centralized SCM, this operation is a local operation. See
1049 centralized SCM, this operation is a local operation. See
1050 :hg:`push` for a way to actively distribute your changes.
1050 :hg:`push` for a way to actively distribute your changes.
1051
1051
1052 If a list of files is omitted, all changes reported by :hg:`status`
1052 If a list of files is omitted, all changes reported by :hg:`status`
1053 will be committed.
1053 will be committed.
1054
1054
1055 If you are committing the result of a merge, do not provide any
1055 If you are committing the result of a merge, do not provide any
1056 filenames or -I/-X filters.
1056 filenames or -I/-X filters.
1057
1057
1058 If no commit message is specified, Mercurial starts your
1058 If no commit message is specified, Mercurial starts your
1059 configured editor where you can enter a message. In case your
1059 configured editor where you can enter a message. In case your
1060 commit fails, you will find a backup of your message in
1060 commit fails, you will find a backup of your message in
1061 ``.hg/last-message.txt``.
1061 ``.hg/last-message.txt``.
1062
1062
1063 See :hg:`help dates` for a list of formats valid for -d/--date.
1063 See :hg:`help dates` for a list of formats valid for -d/--date.
1064
1064
1065 Returns 0 on success, 1 if nothing changed.
1065 Returns 0 on success, 1 if nothing changed.
1066 """
1066 """
1067 extra = {}
1067 extra = {}
1068 if opts.get('close_branch'):
1068 if opts.get('close_branch'):
1069 if repo['.'].node() not in repo.branchheads():
1069 if repo['.'].node() not in repo.branchheads():
1070 # The topo heads set is included in the branch heads set of the
1070 # The topo heads set is included in the branch heads set of the
1071 # current branch, so it's sufficient to test branchheads
1071 # current branch, so it's sufficient to test branchheads
1072 raise util.Abort(_('can only close branch heads'))
1072 raise util.Abort(_('can only close branch heads'))
1073 extra['close'] = 1
1073 extra['close'] = 1
1074 e = cmdutil.commiteditor
1074 e = cmdutil.commiteditor
1075 if opts.get('force_editor'):
1075 if opts.get('force_editor'):
1076 e = cmdutil.commitforceeditor
1076 e = cmdutil.commitforceeditor
1077
1077
1078 def commitfunc(ui, repo, message, match, opts):
1078 def commitfunc(ui, repo, message, match, opts):
1079 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1079 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1080 editor=e, extra=extra)
1080 editor=e, extra=extra)
1081
1081
1082 branch = repo[None].branch()
1082 branch = repo[None].branch()
1083 bheads = repo.branchheads(branch)
1083 bheads = repo.branchheads(branch)
1084
1084
1085 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1085 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1086 if not node:
1086 if not node:
1087 stat = repo.status(match=scmutil.match(repo, pats, opts))
1087 stat = repo.status(match=scmutil.match(repo, pats, opts))
1088 if stat[3]:
1088 if stat[3]:
1089 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1089 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1090 % len(stat[3]))
1090 % len(stat[3]))
1091 else:
1091 else:
1092 ui.status(_("nothing changed\n"))
1092 ui.status(_("nothing changed\n"))
1093 return 1
1093 return 1
1094
1094
1095 ctx = repo[node]
1095 ctx = repo[node]
1096 parents = ctx.parents()
1096 parents = ctx.parents()
1097
1097
1098 if bheads and not [x for x in parents
1098 if bheads and not [x for x in parents
1099 if x.node() in bheads and x.branch() == branch]:
1099 if x.node() in bheads and x.branch() == branch]:
1100 ui.status(_('created new head\n'))
1100 ui.status(_('created new head\n'))
1101 # The message is not printed for initial roots. For the other
1101 # The message is not printed for initial roots. For the other
1102 # changesets, it is printed in the following situations:
1102 # changesets, it is printed in the following situations:
1103 #
1103 #
1104 # Par column: for the 2 parents with ...
1104 # Par column: for the 2 parents with ...
1105 # N: null or no parent
1105 # N: null or no parent
1106 # B: parent is on another named branch
1106 # B: parent is on another named branch
1107 # C: parent is a regular non head changeset
1107 # C: parent is a regular non head changeset
1108 # H: parent was a branch head of the current branch
1108 # H: parent was a branch head of the current branch
1109 # Msg column: whether we print "created new head" message
1109 # Msg column: whether we print "created new head" message
1110 # In the following, it is assumed that there already exists some
1110 # In the following, it is assumed that there already exists some
1111 # initial branch heads of the current branch, otherwise nothing is
1111 # initial branch heads of the current branch, otherwise nothing is
1112 # printed anyway.
1112 # printed anyway.
1113 #
1113 #
1114 # Par Msg Comment
1114 # Par Msg Comment
1115 # NN y additional topo root
1115 # NN y additional topo root
1116 #
1116 #
1117 # BN y additional branch root
1117 # BN y additional branch root
1118 # CN y additional topo head
1118 # CN y additional topo head
1119 # HN n usual case
1119 # HN n usual case
1120 #
1120 #
1121 # BB y weird additional branch root
1121 # BB y weird additional branch root
1122 # CB y branch merge
1122 # CB y branch merge
1123 # HB n merge with named branch
1123 # HB n merge with named branch
1124 #
1124 #
1125 # CC y additional head from merge
1125 # CC y additional head from merge
1126 # CH n merge with a head
1126 # CH n merge with a head
1127 #
1127 #
1128 # HH n head merge: head count decreases
1128 # HH n head merge: head count decreases
1129
1129
1130 if not opts.get('close_branch'):
1130 if not opts.get('close_branch'):
1131 for r in parents:
1131 for r in parents:
1132 if r.extra().get('close') and r.branch() == branch:
1132 if r.extra().get('close') and r.branch() == branch:
1133 ui.status(_('reopening closed branch head %d\n') % r)
1133 ui.status(_('reopening closed branch head %d\n') % r)
1134
1134
1135 if ui.debugflag:
1135 if ui.debugflag:
1136 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1136 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1137 elif ui.verbose:
1137 elif ui.verbose:
1138 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1138 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1139
1139
1140 @command('copy|cp',
1140 @command('copy|cp',
1141 [('A', 'after', None, _('record a copy that has already occurred')),
1141 [('A', 'after', None, _('record a copy that has already occurred')),
1142 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1142 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1143 ] + walkopts + dryrunopts,
1143 ] + walkopts + dryrunopts,
1144 _('[OPTION]... [SOURCE]... DEST'))
1144 _('[OPTION]... [SOURCE]... DEST'))
1145 def copy(ui, repo, *pats, **opts):
1145 def copy(ui, repo, *pats, **opts):
1146 """mark files as copied for the next commit
1146 """mark files as copied for the next commit
1147
1147
1148 Mark dest as having copies of source files. If dest is a
1148 Mark dest as having copies of source files. If dest is a
1149 directory, copies are put in that directory. If dest is a file,
1149 directory, copies are put in that directory. If dest is a file,
1150 the source must be a single file.
1150 the source must be a single file.
1151
1151
1152 By default, this command copies the contents of files as they
1152 By default, this command copies the contents of files as they
1153 exist in the working directory. If invoked with -A/--after, the
1153 exist in the working directory. If invoked with -A/--after, the
1154 operation is recorded, but no copying is performed.
1154 operation is recorded, but no copying is performed.
1155
1155
1156 This command takes effect with the next commit. To undo a copy
1156 This command takes effect with the next commit. To undo a copy
1157 before that, see :hg:`revert`.
1157 before that, see :hg:`revert`.
1158
1158
1159 Returns 0 on success, 1 if errors are encountered.
1159 Returns 0 on success, 1 if errors are encountered.
1160 """
1160 """
1161 wlock = repo.wlock(False)
1161 wlock = repo.wlock(False)
1162 try:
1162 try:
1163 return cmdutil.copy(ui, repo, pats, opts)
1163 return cmdutil.copy(ui, repo, pats, opts)
1164 finally:
1164 finally:
1165 wlock.release()
1165 wlock.release()
1166
1166
1167 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1167 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1168 def debugancestor(ui, repo, *args):
1168 def debugancestor(ui, repo, *args):
1169 """find the ancestor revision of two revisions in a given index"""
1169 """find the ancestor revision of two revisions in a given index"""
1170 if len(args) == 3:
1170 if len(args) == 3:
1171 index, rev1, rev2 = args
1171 index, rev1, rev2 = args
1172 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1172 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1173 lookup = r.lookup
1173 lookup = r.lookup
1174 elif len(args) == 2:
1174 elif len(args) == 2:
1175 if not repo:
1175 if not repo:
1176 raise util.Abort(_("there is no Mercurial repository here "
1176 raise util.Abort(_("there is no Mercurial repository here "
1177 "(.hg not found)"))
1177 "(.hg not found)"))
1178 rev1, rev2 = args
1178 rev1, rev2 = args
1179 r = repo.changelog
1179 r = repo.changelog
1180 lookup = repo.lookup
1180 lookup = repo.lookup
1181 else:
1181 else:
1182 raise util.Abort(_('either two or three arguments required'))
1182 raise util.Abort(_('either two or three arguments required'))
1183 a = r.ancestor(lookup(rev1), lookup(rev2))
1183 a = r.ancestor(lookup(rev1), lookup(rev2))
1184 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1184 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1185
1185
1186 @command('debugbuilddag',
1186 @command('debugbuilddag',
1187 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1187 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1188 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1188 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1189 ('n', 'new-file', None, _('add new file at each rev'))],
1189 ('n', 'new-file', None, _('add new file at each rev'))],
1190 _('[OPTION]... [TEXT]'))
1190 _('[OPTION]... [TEXT]'))
1191 def debugbuilddag(ui, repo, text=None,
1191 def debugbuilddag(ui, repo, text=None,
1192 mergeable_file=False,
1192 mergeable_file=False,
1193 overwritten_file=False,
1193 overwritten_file=False,
1194 new_file=False):
1194 new_file=False):
1195 """builds a repo with a given DAG from scratch in the current empty repo
1195 """builds a repo with a given DAG from scratch in the current empty repo
1196
1196
1197 The description of the DAG is read from stdin if not given on the
1197 The description of the DAG is read from stdin if not given on the
1198 command line.
1198 command line.
1199
1199
1200 Elements:
1200 Elements:
1201
1201
1202 - "+n" is a linear run of n nodes based on the current default parent
1202 - "+n" is a linear run of n nodes based on the current default parent
1203 - "." is a single node based on the current default parent
1203 - "." is a single node based on the current default parent
1204 - "$" resets the default parent to null (implied at the start);
1204 - "$" resets the default parent to null (implied at the start);
1205 otherwise the default parent is always the last node created
1205 otherwise the default parent is always the last node created
1206 - "<p" sets the default parent to the backref p
1206 - "<p" sets the default parent to the backref p
1207 - "*p" is a fork at parent p, which is a backref
1207 - "*p" is a fork at parent p, which is a backref
1208 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1208 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1209 - "/p2" is a merge of the preceding node and p2
1209 - "/p2" is a merge of the preceding node and p2
1210 - ":tag" defines a local tag for the preceding node
1210 - ":tag" defines a local tag for the preceding node
1211 - "@branch" sets the named branch for subsequent nodes
1211 - "@branch" sets the named branch for subsequent nodes
1212 - "#...\\n" is a comment up to the end of the line
1212 - "#...\\n" is a comment up to the end of the line
1213
1213
1214 Whitespace between the above elements is ignored.
1214 Whitespace between the above elements is ignored.
1215
1215
1216 A backref is either
1216 A backref is either
1217
1217
1218 - a number n, which references the node curr-n, where curr is the current
1218 - a number n, which references the node curr-n, where curr is the current
1219 node, or
1219 node, or
1220 - the name of a local tag you placed earlier using ":tag", or
1220 - the name of a local tag you placed earlier using ":tag", or
1221 - empty to denote the default parent.
1221 - empty to denote the default parent.
1222
1222
1223 All string valued-elements are either strictly alphanumeric, or must
1223 All string valued-elements are either strictly alphanumeric, or must
1224 be enclosed in double quotes ("..."), with "\\" as escape character.
1224 be enclosed in double quotes ("..."), with "\\" as escape character.
1225 """
1225 """
1226
1226
1227 if text is None:
1227 if text is None:
1228 ui.status(_("reading DAG from stdin\n"))
1228 ui.status(_("reading DAG from stdin\n"))
1229 text = sys.stdin.read()
1229 text = sys.stdin.read()
1230
1230
1231 cl = repo.changelog
1231 cl = repo.changelog
1232 if len(cl) > 0:
1232 if len(cl) > 0:
1233 raise util.Abort(_('repository is not empty'))
1233 raise util.Abort(_('repository is not empty'))
1234
1234
1235 # determine number of revs in DAG
1235 # determine number of revs in DAG
1236 total = 0
1236 total = 0
1237 for type, data in dagparser.parsedag(text):
1237 for type, data in dagparser.parsedag(text):
1238 if type == 'n':
1238 if type == 'n':
1239 total += 1
1239 total += 1
1240
1240
1241 if mergeable_file:
1241 if mergeable_file:
1242 linesperrev = 2
1242 linesperrev = 2
1243 # make a file with k lines per rev
1243 # make a file with k lines per rev
1244 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1244 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1245 initialmergedlines.append("")
1245 initialmergedlines.append("")
1246
1246
1247 tags = []
1247 tags = []
1248
1248
1249 tr = repo.transaction("builddag")
1249 tr = repo.transaction("builddag")
1250 try:
1250 try:
1251
1251
1252 at = -1
1252 at = -1
1253 atbranch = 'default'
1253 atbranch = 'default'
1254 nodeids = []
1254 nodeids = []
1255 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1255 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1256 for type, data in dagparser.parsedag(text):
1256 for type, data in dagparser.parsedag(text):
1257 if type == 'n':
1257 if type == 'n':
1258 ui.note('node %s\n' % str(data))
1258 ui.note('node %s\n' % str(data))
1259 id, ps = data
1259 id, ps = data
1260
1260
1261 files = []
1261 files = []
1262 fctxs = {}
1262 fctxs = {}
1263
1263
1264 p2 = None
1264 p2 = None
1265 if mergeable_file:
1265 if mergeable_file:
1266 fn = "mf"
1266 fn = "mf"
1267 p1 = repo[ps[0]]
1267 p1 = repo[ps[0]]
1268 if len(ps) > 1:
1268 if len(ps) > 1:
1269 p2 = repo[ps[1]]
1269 p2 = repo[ps[1]]
1270 pa = p1.ancestor(p2)
1270 pa = p1.ancestor(p2)
1271 base, local, other = [x[fn].data() for x in pa, p1, p2]
1271 base, local, other = [x[fn].data() for x in pa, p1, p2]
1272 m3 = simplemerge.Merge3Text(base, local, other)
1272 m3 = simplemerge.Merge3Text(base, local, other)
1273 ml = [l.strip() for l in m3.merge_lines()]
1273 ml = [l.strip() for l in m3.merge_lines()]
1274 ml.append("")
1274 ml.append("")
1275 elif at > 0:
1275 elif at > 0:
1276 ml = p1[fn].data().split("\n")
1276 ml = p1[fn].data().split("\n")
1277 else:
1277 else:
1278 ml = initialmergedlines
1278 ml = initialmergedlines
1279 ml[id * linesperrev] += " r%i" % id
1279 ml[id * linesperrev] += " r%i" % id
1280 mergedtext = "\n".join(ml)
1280 mergedtext = "\n".join(ml)
1281 files.append(fn)
1281 files.append(fn)
1282 fctxs[fn] = context.memfilectx(fn, mergedtext)
1282 fctxs[fn] = context.memfilectx(fn, mergedtext)
1283
1283
1284 if overwritten_file:
1284 if overwritten_file:
1285 fn = "of"
1285 fn = "of"
1286 files.append(fn)
1286 files.append(fn)
1287 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1287 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1288
1288
1289 if new_file:
1289 if new_file:
1290 fn = "nf%i" % id
1290 fn = "nf%i" % id
1291 files.append(fn)
1291 files.append(fn)
1292 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1292 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1293 if len(ps) > 1:
1293 if len(ps) > 1:
1294 if not p2:
1294 if not p2:
1295 p2 = repo[ps[1]]
1295 p2 = repo[ps[1]]
1296 for fn in p2:
1296 for fn in p2:
1297 if fn.startswith("nf"):
1297 if fn.startswith("nf"):
1298 files.append(fn)
1298 files.append(fn)
1299 fctxs[fn] = p2[fn]
1299 fctxs[fn] = p2[fn]
1300
1300
1301 def fctxfn(repo, cx, path):
1301 def fctxfn(repo, cx, path):
1302 return fctxs.get(path)
1302 return fctxs.get(path)
1303
1303
1304 if len(ps) == 0 or ps[0] < 0:
1304 if len(ps) == 0 or ps[0] < 0:
1305 pars = [None, None]
1305 pars = [None, None]
1306 elif len(ps) == 1:
1306 elif len(ps) == 1:
1307 pars = [nodeids[ps[0]], None]
1307 pars = [nodeids[ps[0]], None]
1308 else:
1308 else:
1309 pars = [nodeids[p] for p in ps]
1309 pars = [nodeids[p] for p in ps]
1310 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1310 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1311 date=(id, 0),
1311 date=(id, 0),
1312 user="debugbuilddag",
1312 user="debugbuilddag",
1313 extra={'branch': atbranch})
1313 extra={'branch': atbranch})
1314 nodeid = repo.commitctx(cx)
1314 nodeid = repo.commitctx(cx)
1315 nodeids.append(nodeid)
1315 nodeids.append(nodeid)
1316 at = id
1316 at = id
1317 elif type == 'l':
1317 elif type == 'l':
1318 id, name = data
1318 id, name = data
1319 ui.note('tag %s\n' % name)
1319 ui.note('tag %s\n' % name)
1320 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1320 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1321 elif type == 'a':
1321 elif type == 'a':
1322 ui.note('branch %s\n' % data)
1322 ui.note('branch %s\n' % data)
1323 atbranch = data
1323 atbranch = data
1324 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1324 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1325 tr.close()
1325 tr.close()
1326 finally:
1326 finally:
1327 ui.progress(_('building'), None)
1327 ui.progress(_('building'), None)
1328 tr.release()
1328 tr.release()
1329
1329
1330 if tags:
1330 if tags:
1331 repo.opener.write("localtags", "".join(tags))
1331 repo.opener.write("localtags", "".join(tags))
1332
1332
1333 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1333 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1334 def debugbundle(ui, bundlepath, all=None, **opts):
1334 def debugbundle(ui, bundlepath, all=None, **opts):
1335 """lists the contents of a bundle"""
1335 """lists the contents of a bundle"""
1336 f = url.open(ui, bundlepath)
1336 f = url.open(ui, bundlepath)
1337 try:
1337 try:
1338 gen = changegroup.readbundle(f, bundlepath)
1338 gen = changegroup.readbundle(f, bundlepath)
1339 if all:
1339 if all:
1340 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1340 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1341
1341
1342 def showchunks(named):
1342 def showchunks(named):
1343 ui.write("\n%s\n" % named)
1343 ui.write("\n%s\n" % named)
1344 chain = None
1344 chain = None
1345 while 1:
1345 while 1:
1346 chunkdata = gen.deltachunk(chain)
1346 chunkdata = gen.deltachunk(chain)
1347 if not chunkdata:
1347 if not chunkdata:
1348 break
1348 break
1349 node = chunkdata['node']
1349 node = chunkdata['node']
1350 p1 = chunkdata['p1']
1350 p1 = chunkdata['p1']
1351 p2 = chunkdata['p2']
1351 p2 = chunkdata['p2']
1352 cs = chunkdata['cs']
1352 cs = chunkdata['cs']
1353 deltabase = chunkdata['deltabase']
1353 deltabase = chunkdata['deltabase']
1354 delta = chunkdata['delta']
1354 delta = chunkdata['delta']
1355 ui.write("%s %s %s %s %s %s\n" %
1355 ui.write("%s %s %s %s %s %s\n" %
1356 (hex(node), hex(p1), hex(p2),
1356 (hex(node), hex(p1), hex(p2),
1357 hex(cs), hex(deltabase), len(delta)))
1357 hex(cs), hex(deltabase), len(delta)))
1358 chain = node
1358 chain = node
1359
1359
1360 chunkdata = gen.changelogheader()
1360 chunkdata = gen.changelogheader()
1361 showchunks("changelog")
1361 showchunks("changelog")
1362 chunkdata = gen.manifestheader()
1362 chunkdata = gen.manifestheader()
1363 showchunks("manifest")
1363 showchunks("manifest")
1364 while 1:
1364 while 1:
1365 chunkdata = gen.filelogheader()
1365 chunkdata = gen.filelogheader()
1366 if not chunkdata:
1366 if not chunkdata:
1367 break
1367 break
1368 fname = chunkdata['filename']
1368 fname = chunkdata['filename']
1369 showchunks(fname)
1369 showchunks(fname)
1370 else:
1370 else:
1371 chunkdata = gen.changelogheader()
1371 chunkdata = gen.changelogheader()
1372 chain = None
1372 chain = None
1373 while 1:
1373 while 1:
1374 chunkdata = gen.deltachunk(chain)
1374 chunkdata = gen.deltachunk(chain)
1375 if not chunkdata:
1375 if not chunkdata:
1376 break
1376 break
1377 node = chunkdata['node']
1377 node = chunkdata['node']
1378 ui.write("%s\n" % hex(node))
1378 ui.write("%s\n" % hex(node))
1379 chain = node
1379 chain = node
1380 finally:
1380 finally:
1381 f.close()
1381 f.close()
1382
1382
1383 @command('debugcheckstate', [], '')
1383 @command('debugcheckstate', [], '')
1384 def debugcheckstate(ui, repo):
1384 def debugcheckstate(ui, repo):
1385 """validate the correctness of the current dirstate"""
1385 """validate the correctness of the current dirstate"""
1386 parent1, parent2 = repo.dirstate.parents()
1386 parent1, parent2 = repo.dirstate.parents()
1387 m1 = repo[parent1].manifest()
1387 m1 = repo[parent1].manifest()
1388 m2 = repo[parent2].manifest()
1388 m2 = repo[parent2].manifest()
1389 errors = 0
1389 errors = 0
1390 for f in repo.dirstate:
1390 for f in repo.dirstate:
1391 state = repo.dirstate[f]
1391 state = repo.dirstate[f]
1392 if state in "nr" and f not in m1:
1392 if state in "nr" and f not in m1:
1393 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1393 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1394 errors += 1
1394 errors += 1
1395 if state in "a" and f in m1:
1395 if state in "a" and f in m1:
1396 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1396 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1397 errors += 1
1397 errors += 1
1398 if state in "m" and f not in m1 and f not in m2:
1398 if state in "m" and f not in m1 and f not in m2:
1399 ui.warn(_("%s in state %s, but not in either manifest\n") %
1399 ui.warn(_("%s in state %s, but not in either manifest\n") %
1400 (f, state))
1400 (f, state))
1401 errors += 1
1401 errors += 1
1402 for f in m1:
1402 for f in m1:
1403 state = repo.dirstate[f]
1403 state = repo.dirstate[f]
1404 if state not in "nrm":
1404 if state not in "nrm":
1405 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1405 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1406 errors += 1
1406 errors += 1
1407 if errors:
1407 if errors:
1408 error = _(".hg/dirstate inconsistent with current parent's manifest")
1408 error = _(".hg/dirstate inconsistent with current parent's manifest")
1409 raise util.Abort(error)
1409 raise util.Abort(error)
1410
1410
1411 @command('debugcommands', [], _('[COMMAND]'))
1411 @command('debugcommands', [], _('[COMMAND]'))
1412 def debugcommands(ui, cmd='', *args):
1412 def debugcommands(ui, cmd='', *args):
1413 """list all available commands and options"""
1413 """list all available commands and options"""
1414 for cmd, vals in sorted(table.iteritems()):
1414 for cmd, vals in sorted(table.iteritems()):
1415 cmd = cmd.split('|')[0].strip('^')
1415 cmd = cmd.split('|')[0].strip('^')
1416 opts = ', '.join([i[1] for i in vals[1]])
1416 opts = ', '.join([i[1] for i in vals[1]])
1417 ui.write('%s: %s\n' % (cmd, opts))
1417 ui.write('%s: %s\n' % (cmd, opts))
1418
1418
1419 @command('debugcomplete',
1419 @command('debugcomplete',
1420 [('o', 'options', None, _('show the command options'))],
1420 [('o', 'options', None, _('show the command options'))],
1421 _('[-o] CMD'))
1421 _('[-o] CMD'))
1422 def debugcomplete(ui, cmd='', **opts):
1422 def debugcomplete(ui, cmd='', **opts):
1423 """returns the completion list associated with the given command"""
1423 """returns the completion list associated with the given command"""
1424
1424
1425 if opts.get('options'):
1425 if opts.get('options'):
1426 options = []
1426 options = []
1427 otables = [globalopts]
1427 otables = [globalopts]
1428 if cmd:
1428 if cmd:
1429 aliases, entry = cmdutil.findcmd(cmd, table, False)
1429 aliases, entry = cmdutil.findcmd(cmd, table, False)
1430 otables.append(entry[1])
1430 otables.append(entry[1])
1431 for t in otables:
1431 for t in otables:
1432 for o in t:
1432 for o in t:
1433 if "(DEPRECATED)" in o[3]:
1433 if "(DEPRECATED)" in o[3]:
1434 continue
1434 continue
1435 if o[0]:
1435 if o[0]:
1436 options.append('-%s' % o[0])
1436 options.append('-%s' % o[0])
1437 options.append('--%s' % o[1])
1437 options.append('--%s' % o[1])
1438 ui.write("%s\n" % "\n".join(options))
1438 ui.write("%s\n" % "\n".join(options))
1439 return
1439 return
1440
1440
1441 cmdlist = cmdutil.findpossible(cmd, table)
1441 cmdlist = cmdutil.findpossible(cmd, table)
1442 if ui.verbose:
1442 if ui.verbose:
1443 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1443 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1444 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1444 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1445
1445
1446 @command('debugdag',
1446 @command('debugdag',
1447 [('t', 'tags', None, _('use tags as labels')),
1447 [('t', 'tags', None, _('use tags as labels')),
1448 ('b', 'branches', None, _('annotate with branch names')),
1448 ('b', 'branches', None, _('annotate with branch names')),
1449 ('', 'dots', None, _('use dots for runs')),
1449 ('', 'dots', None, _('use dots for runs')),
1450 ('s', 'spaces', None, _('separate elements by spaces'))],
1450 ('s', 'spaces', None, _('separate elements by spaces'))],
1451 _('[OPTION]... [FILE [REV]...]'))
1451 _('[OPTION]... [FILE [REV]...]'))
1452 def debugdag(ui, repo, file_=None, *revs, **opts):
1452 def debugdag(ui, repo, file_=None, *revs, **opts):
1453 """format the changelog or an index DAG as a concise textual description
1453 """format the changelog or an index DAG as a concise textual description
1454
1454
1455 If you pass a revlog index, the revlog's DAG is emitted. If you list
1455 If you pass a revlog index, the revlog's DAG is emitted. If you list
1456 revision numbers, they get labelled in the output as rN.
1456 revision numbers, they get labelled in the output as rN.
1457
1457
1458 Otherwise, the changelog DAG of the current repo is emitted.
1458 Otherwise, the changelog DAG of the current repo is emitted.
1459 """
1459 """
1460 spaces = opts.get('spaces')
1460 spaces = opts.get('spaces')
1461 dots = opts.get('dots')
1461 dots = opts.get('dots')
1462 if file_:
1462 if file_:
1463 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1463 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1464 revs = set((int(r) for r in revs))
1464 revs = set((int(r) for r in revs))
1465 def events():
1465 def events():
1466 for r in rlog:
1466 for r in rlog:
1467 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1467 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1468 if r in revs:
1468 if r in revs:
1469 yield 'l', (r, "r%i" % r)
1469 yield 'l', (r, "r%i" % r)
1470 elif repo:
1470 elif repo:
1471 cl = repo.changelog
1471 cl = repo.changelog
1472 tags = opts.get('tags')
1472 tags = opts.get('tags')
1473 branches = opts.get('branches')
1473 branches = opts.get('branches')
1474 if tags:
1474 if tags:
1475 labels = {}
1475 labels = {}
1476 for l, n in repo.tags().items():
1476 for l, n in repo.tags().items():
1477 labels.setdefault(cl.rev(n), []).append(l)
1477 labels.setdefault(cl.rev(n), []).append(l)
1478 def events():
1478 def events():
1479 b = "default"
1479 b = "default"
1480 for r in cl:
1480 for r in cl:
1481 if branches:
1481 if branches:
1482 newb = cl.read(cl.node(r))[5]['branch']
1482 newb = cl.read(cl.node(r))[5]['branch']
1483 if newb != b:
1483 if newb != b:
1484 yield 'a', newb
1484 yield 'a', newb
1485 b = newb
1485 b = newb
1486 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1486 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1487 if tags:
1487 if tags:
1488 ls = labels.get(r)
1488 ls = labels.get(r)
1489 if ls:
1489 if ls:
1490 for l in ls:
1490 for l in ls:
1491 yield 'l', (r, l)
1491 yield 'l', (r, l)
1492 else:
1492 else:
1493 raise util.Abort(_('need repo for changelog dag'))
1493 raise util.Abort(_('need repo for changelog dag'))
1494
1494
1495 for line in dagparser.dagtextlines(events(),
1495 for line in dagparser.dagtextlines(events(),
1496 addspaces=spaces,
1496 addspaces=spaces,
1497 wraplabels=True,
1497 wraplabels=True,
1498 wrapannotations=True,
1498 wrapannotations=True,
1499 wrapnonlinear=dots,
1499 wrapnonlinear=dots,
1500 usedots=dots,
1500 usedots=dots,
1501 maxlinewidth=70):
1501 maxlinewidth=70):
1502 ui.write(line)
1502 ui.write(line)
1503 ui.write("\n")
1503 ui.write("\n")
1504
1504
1505 @command('debugdata', [], _('FILE REV'))
1505 @command('debugdata',
1506 def debugdata(ui, repo, file_, rev):
1506 [('c', 'changelog', False, _('open changelog')),
1507 ('m', 'manifest', False, _('open manifest'))],
1508 _('-c|-m|FILE REV'))
1509 def debugdata(ui, repo, file_, rev = None, **opts):
1507 """dump the contents of a data file revision"""
1510 """dump the contents of a data file revision"""
1508 r = None
1511 if opts.get('changelog') or opts.get('manifest'):
1509 if repo:
1512 file_, rev = None, file_
1510 filelog = repo.file(file_)
1513 elif rev is None:
1511 if len(filelog):
1514 raise error.CommandError('debugdata', _('invalid arguments'))
1512 r = filelog
1515 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1513 if not r:
1514 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
1515 file_[:-2] + ".i")
1516 try:
1516 try:
1517 ui.write(r.revision(r.lookup(rev)))
1517 ui.write(r.revision(r.lookup(rev)))
1518 except KeyError:
1518 except KeyError:
1519 raise util.Abort(_('invalid revision identifier %s') % rev)
1519 raise util.Abort(_('invalid revision identifier %s') % rev)
1520
1520
1521 @command('debugdate',
1521 @command('debugdate',
1522 [('e', 'extended', None, _('try extended date formats'))],
1522 [('e', 'extended', None, _('try extended date formats'))],
1523 _('[-e] DATE [RANGE]'))
1523 _('[-e] DATE [RANGE]'))
1524 def debugdate(ui, date, range=None, **opts):
1524 def debugdate(ui, date, range=None, **opts):
1525 """parse and display a date"""
1525 """parse and display a date"""
1526 if opts["extended"]:
1526 if opts["extended"]:
1527 d = util.parsedate(date, util.extendeddateformats)
1527 d = util.parsedate(date, util.extendeddateformats)
1528 else:
1528 else:
1529 d = util.parsedate(date)
1529 d = util.parsedate(date)
1530 ui.write("internal: %s %s\n" % d)
1530 ui.write("internal: %s %s\n" % d)
1531 ui.write("standard: %s\n" % util.datestr(d))
1531 ui.write("standard: %s\n" % util.datestr(d))
1532 if range:
1532 if range:
1533 m = util.matchdate(range)
1533 m = util.matchdate(range)
1534 ui.write("match: %s\n" % m(d[0]))
1534 ui.write("match: %s\n" % m(d[0]))
1535
1535
1536 @command('debugdiscovery',
1536 @command('debugdiscovery',
1537 [('', 'old', None, _('use old-style discovery')),
1537 [('', 'old', None, _('use old-style discovery')),
1538 ('', 'nonheads', None,
1538 ('', 'nonheads', None,
1539 _('use old-style discovery with non-heads included')),
1539 _('use old-style discovery with non-heads included')),
1540 ] + remoteopts,
1540 ] + remoteopts,
1541 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1541 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1542 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1542 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1543 """runs the changeset discovery protocol in isolation"""
1543 """runs the changeset discovery protocol in isolation"""
1544 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1544 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1545 remote = hg.repository(hg.remoteui(repo, opts), remoteurl)
1545 remote = hg.repository(hg.remoteui(repo, opts), remoteurl)
1546 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1546 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1547
1547
1548 # make sure tests are repeatable
1548 # make sure tests are repeatable
1549 random.seed(12323)
1549 random.seed(12323)
1550
1550
1551 def doit(localheads, remoteheads):
1551 def doit(localheads, remoteheads):
1552 if opts.get('old'):
1552 if opts.get('old'):
1553 if localheads:
1553 if localheads:
1554 raise util.Abort('cannot use localheads with old style discovery')
1554 raise util.Abort('cannot use localheads with old style discovery')
1555 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1555 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1556 force=True)
1556 force=True)
1557 common = set(common)
1557 common = set(common)
1558 if not opts.get('nonheads'):
1558 if not opts.get('nonheads'):
1559 ui.write("unpruned common: %s\n" % " ".join([short(n)
1559 ui.write("unpruned common: %s\n" % " ".join([short(n)
1560 for n in common]))
1560 for n in common]))
1561 dag = dagutil.revlogdag(repo.changelog)
1561 dag = dagutil.revlogdag(repo.changelog)
1562 all = dag.ancestorset(dag.internalizeall(common))
1562 all = dag.ancestorset(dag.internalizeall(common))
1563 common = dag.externalizeall(dag.headsetofconnecteds(all))
1563 common = dag.externalizeall(dag.headsetofconnecteds(all))
1564 else:
1564 else:
1565 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1565 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1566 common = set(common)
1566 common = set(common)
1567 rheads = set(hds)
1567 rheads = set(hds)
1568 lheads = set(repo.heads())
1568 lheads = set(repo.heads())
1569 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1569 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1570 if lheads <= common:
1570 if lheads <= common:
1571 ui.write("local is subset\n")
1571 ui.write("local is subset\n")
1572 elif rheads <= common:
1572 elif rheads <= common:
1573 ui.write("remote is subset\n")
1573 ui.write("remote is subset\n")
1574
1574
1575 serverlogs = opts.get('serverlog')
1575 serverlogs = opts.get('serverlog')
1576 if serverlogs:
1576 if serverlogs:
1577 for filename in serverlogs:
1577 for filename in serverlogs:
1578 logfile = open(filename, 'r')
1578 logfile = open(filename, 'r')
1579 try:
1579 try:
1580 line = logfile.readline()
1580 line = logfile.readline()
1581 while line:
1581 while line:
1582 parts = line.strip().split(';')
1582 parts = line.strip().split(';')
1583 op = parts[1]
1583 op = parts[1]
1584 if op == 'cg':
1584 if op == 'cg':
1585 pass
1585 pass
1586 elif op == 'cgss':
1586 elif op == 'cgss':
1587 doit(parts[2].split(' '), parts[3].split(' '))
1587 doit(parts[2].split(' '), parts[3].split(' '))
1588 elif op == 'unb':
1588 elif op == 'unb':
1589 doit(parts[3].split(' '), parts[2].split(' '))
1589 doit(parts[3].split(' '), parts[2].split(' '))
1590 line = logfile.readline()
1590 line = logfile.readline()
1591 finally:
1591 finally:
1592 logfile.close()
1592 logfile.close()
1593
1593
1594 else:
1594 else:
1595 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1595 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1596 opts.get('remote_head'))
1596 opts.get('remote_head'))
1597 localrevs = opts.get('local_head')
1597 localrevs = opts.get('local_head')
1598 doit(localrevs, remoterevs)
1598 doit(localrevs, remoterevs)
1599
1599
1600 @command('debugfsinfo', [], _('[PATH]'))
1600 @command('debugfsinfo', [], _('[PATH]'))
1601 def debugfsinfo(ui, path = "."):
1601 def debugfsinfo(ui, path = "."):
1602 """show information detected about current filesystem"""
1602 """show information detected about current filesystem"""
1603 util.writefile('.debugfsinfo', '')
1603 util.writefile('.debugfsinfo', '')
1604 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1604 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1605 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1605 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1606 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1606 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1607 and 'yes' or 'no'))
1607 and 'yes' or 'no'))
1608 os.unlink('.debugfsinfo')
1608 os.unlink('.debugfsinfo')
1609
1609
1610 @command('debuggetbundle',
1610 @command('debuggetbundle',
1611 [('H', 'head', [], _('id of head node'), _('ID')),
1611 [('H', 'head', [], _('id of head node'), _('ID')),
1612 ('C', 'common', [], _('id of common node'), _('ID')),
1612 ('C', 'common', [], _('id of common node'), _('ID')),
1613 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1613 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1614 _('REPO FILE [-H|-C ID]...'))
1614 _('REPO FILE [-H|-C ID]...'))
1615 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1615 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1616 """retrieves a bundle from a repo
1616 """retrieves a bundle from a repo
1617
1617
1618 Every ID must be a full-length hex node id string. Saves the bundle to the
1618 Every ID must be a full-length hex node id string. Saves the bundle to the
1619 given file.
1619 given file.
1620 """
1620 """
1621 repo = hg.repository(ui, repopath)
1621 repo = hg.repository(ui, repopath)
1622 if not repo.capable('getbundle'):
1622 if not repo.capable('getbundle'):
1623 raise util.Abort("getbundle() not supported by target repository")
1623 raise util.Abort("getbundle() not supported by target repository")
1624 args = {}
1624 args = {}
1625 if common:
1625 if common:
1626 args['common'] = [bin(s) for s in common]
1626 args['common'] = [bin(s) for s in common]
1627 if head:
1627 if head:
1628 args['heads'] = [bin(s) for s in head]
1628 args['heads'] = [bin(s) for s in head]
1629 bundle = repo.getbundle('debug', **args)
1629 bundle = repo.getbundle('debug', **args)
1630
1630
1631 bundletype = opts.get('type', 'bzip2').lower()
1631 bundletype = opts.get('type', 'bzip2').lower()
1632 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1632 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1633 bundletype = btypes.get(bundletype)
1633 bundletype = btypes.get(bundletype)
1634 if bundletype not in changegroup.bundletypes:
1634 if bundletype not in changegroup.bundletypes:
1635 raise util.Abort(_('unknown bundle type specified with --type'))
1635 raise util.Abort(_('unknown bundle type specified with --type'))
1636 changegroup.writebundle(bundle, bundlepath, bundletype)
1636 changegroup.writebundle(bundle, bundlepath, bundletype)
1637
1637
1638 @command('debugignore', [], '')
1638 @command('debugignore', [], '')
1639 def debugignore(ui, repo, *values, **opts):
1639 def debugignore(ui, repo, *values, **opts):
1640 """display the combined ignore pattern"""
1640 """display the combined ignore pattern"""
1641 ignore = repo.dirstate._ignore
1641 ignore = repo.dirstate._ignore
1642 if hasattr(ignore, 'includepat'):
1642 if hasattr(ignore, 'includepat'):
1643 ui.write("%s\n" % ignore.includepat)
1643 ui.write("%s\n" % ignore.includepat)
1644 else:
1644 else:
1645 raise util.Abort(_("no ignore patterns found"))
1645 raise util.Abort(_("no ignore patterns found"))
1646
1646
1647 @command('debugindex',
1647 @command('debugindex',
1648 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1648 [('c', 'changelog', False, _('open changelog')),
1649 _('FILE'))
1649 ('m', 'manifest', False, _('open manifest')),
1650 def debugindex(ui, repo, file_, **opts):
1650 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1651 _('[-f FORMAT] -c|-m|FILE'))
1652 def debugindex(ui, repo, file_ = None, **opts):
1651 """dump the contents of an index file"""
1653 """dump the contents of an index file"""
1652 r = None
1654 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1653 if repo:
1654 filelog = repo.file(file_)
1655 if len(filelog):
1656 r = filelog
1657
1658 format = opts.get('format', 0)
1655 format = opts.get('format', 0)
1659 if format not in (0, 1):
1656 if format not in (0, 1):
1660 raise util.Abort(_("unknown format %d") % format)
1657 raise util.Abort(_("unknown format %d") % format)
1661
1658
1662 if not r:
1663 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1664
1665 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1659 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1666 if generaldelta:
1660 if generaldelta:
1667 basehdr = ' delta'
1661 basehdr = ' delta'
1668 else:
1662 else:
1669 basehdr = ' base'
1663 basehdr = ' base'
1670
1664
1671 if format == 0:
1665 if format == 0:
1672 ui.write(" rev offset length " + basehdr + " linkrev"
1666 ui.write(" rev offset length " + basehdr + " linkrev"
1673 " nodeid p1 p2\n")
1667 " nodeid p1 p2\n")
1674 elif format == 1:
1668 elif format == 1:
1675 ui.write(" rev flag offset length"
1669 ui.write(" rev flag offset length"
1676 " size " + basehdr + " link p1 p2 nodeid\n")
1670 " size " + basehdr + " link p1 p2 nodeid\n")
1677
1671
1678 for i in r:
1672 for i in r:
1679 node = r.node(i)
1673 node = r.node(i)
1680 if generaldelta:
1674 if generaldelta:
1681 base = r.deltaparent(i)
1675 base = r.deltaparent(i)
1682 else:
1676 else:
1683 base = r.chainbase(i)
1677 base = r.chainbase(i)
1684 if format == 0:
1678 if format == 0:
1685 try:
1679 try:
1686 pp = r.parents(node)
1680 pp = r.parents(node)
1687 except:
1681 except:
1688 pp = [nullid, nullid]
1682 pp = [nullid, nullid]
1689 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1683 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1690 i, r.start(i), r.length(i), base, r.linkrev(i),
1684 i, r.start(i), r.length(i), base, r.linkrev(i),
1691 short(node), short(pp[0]), short(pp[1])))
1685 short(node), short(pp[0]), short(pp[1])))
1692 elif format == 1:
1686 elif format == 1:
1693 pr = r.parentrevs(i)
1687 pr = r.parentrevs(i)
1694 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1688 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1695 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1689 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1696 base, r.linkrev(i), pr[0], pr[1], short(node)))
1690 base, r.linkrev(i), pr[0], pr[1], short(node)))
1697
1691
1698 @command('debugindexdot', [], _('FILE'))
1692 @command('debugindexdot', [], _('FILE'))
1699 def debugindexdot(ui, repo, file_):
1693 def debugindexdot(ui, repo, file_):
1700 """dump an index DAG as a graphviz dot file"""
1694 """dump an index DAG as a graphviz dot file"""
1701 r = None
1695 r = None
1702 if repo:
1696 if repo:
1703 filelog = repo.file(file_)
1697 filelog = repo.file(file_)
1704 if len(filelog):
1698 if len(filelog):
1705 r = filelog
1699 r = filelog
1706 if not r:
1700 if not r:
1707 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1701 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1708 ui.write("digraph G {\n")
1702 ui.write("digraph G {\n")
1709 for i in r:
1703 for i in r:
1710 node = r.node(i)
1704 node = r.node(i)
1711 pp = r.parents(node)
1705 pp = r.parents(node)
1712 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1706 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1713 if pp[1] != nullid:
1707 if pp[1] != nullid:
1714 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1708 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1715 ui.write("}\n")
1709 ui.write("}\n")
1716
1710
1717 @command('debuginstall', [], '')
1711 @command('debuginstall', [], '')
1718 def debuginstall(ui):
1712 def debuginstall(ui):
1719 '''test Mercurial installation
1713 '''test Mercurial installation
1720
1714
1721 Returns 0 on success.
1715 Returns 0 on success.
1722 '''
1716 '''
1723
1717
1724 def writetemp(contents):
1718 def writetemp(contents):
1725 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1719 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1726 f = os.fdopen(fd, "wb")
1720 f = os.fdopen(fd, "wb")
1727 f.write(contents)
1721 f.write(contents)
1728 f.close()
1722 f.close()
1729 return name
1723 return name
1730
1724
1731 problems = 0
1725 problems = 0
1732
1726
1733 # encoding
1727 # encoding
1734 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1728 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1735 try:
1729 try:
1736 encoding.fromlocal("test")
1730 encoding.fromlocal("test")
1737 except util.Abort, inst:
1731 except util.Abort, inst:
1738 ui.write(" %s\n" % inst)
1732 ui.write(" %s\n" % inst)
1739 ui.write(_(" (check that your locale is properly set)\n"))
1733 ui.write(_(" (check that your locale is properly set)\n"))
1740 problems += 1
1734 problems += 1
1741
1735
1742 # compiled modules
1736 # compiled modules
1743 ui.status(_("Checking installed modules (%s)...\n")
1737 ui.status(_("Checking installed modules (%s)...\n")
1744 % os.path.dirname(__file__))
1738 % os.path.dirname(__file__))
1745 try:
1739 try:
1746 import bdiff, mpatch, base85, osutil
1740 import bdiff, mpatch, base85, osutil
1747 except Exception, inst:
1741 except Exception, inst:
1748 ui.write(" %s\n" % inst)
1742 ui.write(" %s\n" % inst)
1749 ui.write(_(" One or more extensions could not be found"))
1743 ui.write(_(" One or more extensions could not be found"))
1750 ui.write(_(" (check that you compiled the extensions)\n"))
1744 ui.write(_(" (check that you compiled the extensions)\n"))
1751 problems += 1
1745 problems += 1
1752
1746
1753 # templates
1747 # templates
1754 ui.status(_("Checking templates...\n"))
1748 ui.status(_("Checking templates...\n"))
1755 try:
1749 try:
1756 import templater
1750 import templater
1757 templater.templater(templater.templatepath("map-cmdline.default"))
1751 templater.templater(templater.templatepath("map-cmdline.default"))
1758 except Exception, inst:
1752 except Exception, inst:
1759 ui.write(" %s\n" % inst)
1753 ui.write(" %s\n" % inst)
1760 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1754 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1761 problems += 1
1755 problems += 1
1762
1756
1763 # editor
1757 # editor
1764 ui.status(_("Checking commit editor...\n"))
1758 ui.status(_("Checking commit editor...\n"))
1765 editor = ui.geteditor()
1759 editor = ui.geteditor()
1766 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1760 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1767 if not cmdpath:
1761 if not cmdpath:
1768 if editor == 'vi':
1762 if editor == 'vi':
1769 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1763 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1770 ui.write(_(" (specify a commit editor in your configuration"
1764 ui.write(_(" (specify a commit editor in your configuration"
1771 " file)\n"))
1765 " file)\n"))
1772 else:
1766 else:
1773 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1767 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1774 ui.write(_(" (specify a commit editor in your configuration"
1768 ui.write(_(" (specify a commit editor in your configuration"
1775 " file)\n"))
1769 " file)\n"))
1776 problems += 1
1770 problems += 1
1777
1771
1778 # check username
1772 # check username
1779 ui.status(_("Checking username...\n"))
1773 ui.status(_("Checking username...\n"))
1780 try:
1774 try:
1781 ui.username()
1775 ui.username()
1782 except util.Abort, e:
1776 except util.Abort, e:
1783 ui.write(" %s\n" % e)
1777 ui.write(" %s\n" % e)
1784 ui.write(_(" (specify a username in your configuration file)\n"))
1778 ui.write(_(" (specify a username in your configuration file)\n"))
1785 problems += 1
1779 problems += 1
1786
1780
1787 if not problems:
1781 if not problems:
1788 ui.status(_("No problems detected\n"))
1782 ui.status(_("No problems detected\n"))
1789 else:
1783 else:
1790 ui.write(_("%s problems detected,"
1784 ui.write(_("%s problems detected,"
1791 " please check your install!\n") % problems)
1785 " please check your install!\n") % problems)
1792
1786
1793 return problems
1787 return problems
1794
1788
1795 @command('debugknown', [], _('REPO ID...'))
1789 @command('debugknown', [], _('REPO ID...'))
1796 def debugknown(ui, repopath, *ids, **opts):
1790 def debugknown(ui, repopath, *ids, **opts):
1797 """test whether node ids are known to a repo
1791 """test whether node ids are known to a repo
1798
1792
1799 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1793 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1800 indicating unknown/known.
1794 indicating unknown/known.
1801 """
1795 """
1802 repo = hg.repository(ui, repopath)
1796 repo = hg.repository(ui, repopath)
1803 if not repo.capable('known'):
1797 if not repo.capable('known'):
1804 raise util.Abort("known() not supported by target repository")
1798 raise util.Abort("known() not supported by target repository")
1805 flags = repo.known([bin(s) for s in ids])
1799 flags = repo.known([bin(s) for s in ids])
1806 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1800 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1807
1801
1808 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1802 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1809 def debugpushkey(ui, repopath, namespace, *keyinfo):
1803 def debugpushkey(ui, repopath, namespace, *keyinfo):
1810 '''access the pushkey key/value protocol
1804 '''access the pushkey key/value protocol
1811
1805
1812 With two args, list the keys in the given namespace.
1806 With two args, list the keys in the given namespace.
1813
1807
1814 With five args, set a key to new if it currently is set to old.
1808 With five args, set a key to new if it currently is set to old.
1815 Reports success or failure.
1809 Reports success or failure.
1816 '''
1810 '''
1817
1811
1818 target = hg.repository(ui, repopath)
1812 target = hg.repository(ui, repopath)
1819 if keyinfo:
1813 if keyinfo:
1820 key, old, new = keyinfo
1814 key, old, new = keyinfo
1821 r = target.pushkey(namespace, key, old, new)
1815 r = target.pushkey(namespace, key, old, new)
1822 ui.status(str(r) + '\n')
1816 ui.status(str(r) + '\n')
1823 return not r
1817 return not r
1824 else:
1818 else:
1825 for k, v in target.listkeys(namespace).iteritems():
1819 for k, v in target.listkeys(namespace).iteritems():
1826 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1820 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1827 v.encode('string-escape')))
1821 v.encode('string-escape')))
1828
1822
1829 @command('debugrebuildstate',
1823 @command('debugrebuildstate',
1830 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1824 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1831 _('[-r REV] [REV]'))
1825 _('[-r REV] [REV]'))
1832 def debugrebuildstate(ui, repo, rev="tip"):
1826 def debugrebuildstate(ui, repo, rev="tip"):
1833 """rebuild the dirstate as it would look like for the given revision"""
1827 """rebuild the dirstate as it would look like for the given revision"""
1834 ctx = scmutil.revsingle(repo, rev)
1828 ctx = scmutil.revsingle(repo, rev)
1835 wlock = repo.wlock()
1829 wlock = repo.wlock()
1836 try:
1830 try:
1837 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1831 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1838 finally:
1832 finally:
1839 wlock.release()
1833 wlock.release()
1840
1834
1841 @command('debugrename',
1835 @command('debugrename',
1842 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1836 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1843 _('[-r REV] FILE'))
1837 _('[-r REV] FILE'))
1844 def debugrename(ui, repo, file1, *pats, **opts):
1838 def debugrename(ui, repo, file1, *pats, **opts):
1845 """dump rename information"""
1839 """dump rename information"""
1846
1840
1847 ctx = scmutil.revsingle(repo, opts.get('rev'))
1841 ctx = scmutil.revsingle(repo, opts.get('rev'))
1848 m = scmutil.match(repo, (file1,) + pats, opts)
1842 m = scmutil.match(repo, (file1,) + pats, opts)
1849 for abs in ctx.walk(m):
1843 for abs in ctx.walk(m):
1850 fctx = ctx[abs]
1844 fctx = ctx[abs]
1851 o = fctx.filelog().renamed(fctx.filenode())
1845 o = fctx.filelog().renamed(fctx.filenode())
1852 rel = m.rel(abs)
1846 rel = m.rel(abs)
1853 if o:
1847 if o:
1854 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1848 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1855 else:
1849 else:
1856 ui.write(_("%s not renamed\n") % rel)
1850 ui.write(_("%s not renamed\n") % rel)
1857
1851
1858 @command('debugrevlog', [], _('FILE'))
1852 @command('debugrevlog',
1859 def debugrevlog(ui, repo, file_):
1853 [('c', 'changelog', False, _('open changelog')),
1854 ('m', 'manifest', False, _('open manifest'))],
1855 _('-c|-m|FILE'))
1856 def debugrevlog(ui, repo, file_ = None, **opts):
1860 """show data and statistics about a revlog"""
1857 """show data and statistics about a revlog"""
1861 r = None
1858 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1862 if repo:
1863 filelog = repo.file(file_)
1864 if len(filelog):
1865 r = filelog
1866 if not r:
1867 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1868
1869 v = r.version
1859 v = r.version
1870 format = v & 0xFFFF
1860 format = v & 0xFFFF
1871 flags = []
1861 flags = []
1872 gdelta = False
1862 gdelta = False
1873 if v & revlog.REVLOGNGINLINEDATA:
1863 if v & revlog.REVLOGNGINLINEDATA:
1874 flags.append('inline')
1864 flags.append('inline')
1875 if v & revlog.REVLOGGENERALDELTA:
1865 if v & revlog.REVLOGGENERALDELTA:
1876 gdelta = True
1866 gdelta = True
1877 flags.append('generaldelta')
1867 flags.append('generaldelta')
1878 if not flags:
1868 if not flags:
1879 flags = ['(none)']
1869 flags = ['(none)']
1880
1870
1881 nummerges = 0
1871 nummerges = 0
1882 numfull = 0
1872 numfull = 0
1883 numprev = 0
1873 numprev = 0
1884 nump1 = 0
1874 nump1 = 0
1885 nump2 = 0
1875 nump2 = 0
1886 numother = 0
1876 numother = 0
1887 nump1prev = 0
1877 nump1prev = 0
1888 nump2prev = 0
1878 nump2prev = 0
1889 chainlengths = []
1879 chainlengths = []
1890
1880
1891 datasize = [None, 0, 0L]
1881 datasize = [None, 0, 0L]
1892 fullsize = [None, 0, 0L]
1882 fullsize = [None, 0, 0L]
1893 deltasize = [None, 0, 0L]
1883 deltasize = [None, 0, 0L]
1894
1884
1895 def addsize(size, l):
1885 def addsize(size, l):
1896 if l[0] is None or size < l[0]:
1886 if l[0] is None or size < l[0]:
1897 l[0] = size
1887 l[0] = size
1898 if size > l[1]:
1888 if size > l[1]:
1899 l[1] = size
1889 l[1] = size
1900 l[2] += size
1890 l[2] += size
1901
1891
1902 numrevs = len(r)
1892 numrevs = len(r)
1903 for rev in xrange(numrevs):
1893 for rev in xrange(numrevs):
1904 p1, p2 = r.parentrevs(rev)
1894 p1, p2 = r.parentrevs(rev)
1905 delta = r.deltaparent(rev)
1895 delta = r.deltaparent(rev)
1906 if format > 0:
1896 if format > 0:
1907 addsize(r.rawsize(rev), datasize)
1897 addsize(r.rawsize(rev), datasize)
1908 if p2 != nullrev:
1898 if p2 != nullrev:
1909 nummerges += 1
1899 nummerges += 1
1910 size = r.length(rev)
1900 size = r.length(rev)
1911 if delta == nullrev:
1901 if delta == nullrev:
1912 chainlengths.append(0)
1902 chainlengths.append(0)
1913 numfull += 1
1903 numfull += 1
1914 addsize(size, fullsize)
1904 addsize(size, fullsize)
1915 else:
1905 else:
1916 chainlengths.append(chainlengths[delta] + 1)
1906 chainlengths.append(chainlengths[delta] + 1)
1917 addsize(size, deltasize)
1907 addsize(size, deltasize)
1918 if delta == rev - 1:
1908 if delta == rev - 1:
1919 numprev += 1
1909 numprev += 1
1920 if delta == p1:
1910 if delta == p1:
1921 nump1prev += 1
1911 nump1prev += 1
1922 elif delta == p2:
1912 elif delta == p2:
1923 nump2prev += 1
1913 nump2prev += 1
1924 elif delta == p1:
1914 elif delta == p1:
1925 nump1 += 1
1915 nump1 += 1
1926 elif delta == p2:
1916 elif delta == p2:
1927 nump2 += 1
1917 nump2 += 1
1928 elif delta != nullrev:
1918 elif delta != nullrev:
1929 numother += 1
1919 numother += 1
1930
1920
1931 numdeltas = numrevs - numfull
1921 numdeltas = numrevs - numfull
1932 numoprev = numprev - nump1prev - nump2prev
1922 numoprev = numprev - nump1prev - nump2prev
1933 totalrawsize = datasize[2]
1923 totalrawsize = datasize[2]
1934 datasize[2] /= numrevs
1924 datasize[2] /= numrevs
1935 fulltotal = fullsize[2]
1925 fulltotal = fullsize[2]
1936 fullsize[2] /= numfull
1926 fullsize[2] /= numfull
1937 deltatotal = deltasize[2]
1927 deltatotal = deltasize[2]
1938 deltasize[2] /= numrevs - numfull
1928 deltasize[2] /= numrevs - numfull
1939 totalsize = fulltotal + deltatotal
1929 totalsize = fulltotal + deltatotal
1940 avgchainlen = sum(chainlengths) / numrevs
1930 avgchainlen = sum(chainlengths) / numrevs
1941 compratio = totalrawsize / totalsize
1931 compratio = totalrawsize / totalsize
1942
1932
1943 basedfmtstr = '%%%dd\n'
1933 basedfmtstr = '%%%dd\n'
1944 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1934 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1945
1935
1946 def dfmtstr(max):
1936 def dfmtstr(max):
1947 return basedfmtstr % len(str(max))
1937 return basedfmtstr % len(str(max))
1948 def pcfmtstr(max, padding=0):
1938 def pcfmtstr(max, padding=0):
1949 return basepcfmtstr % (len(str(max)), ' ' * padding)
1939 return basepcfmtstr % (len(str(max)), ' ' * padding)
1950
1940
1951 def pcfmt(value, total):
1941 def pcfmt(value, total):
1952 return (value, 100 * float(value) / total)
1942 return (value, 100 * float(value) / total)
1953
1943
1954 ui.write('format : %d\n' % format)
1944 ui.write('format : %d\n' % format)
1955 ui.write('flags : %s\n' % ', '.join(flags))
1945 ui.write('flags : %s\n' % ', '.join(flags))
1956
1946
1957 ui.write('\n')
1947 ui.write('\n')
1958 fmt = pcfmtstr(totalsize)
1948 fmt = pcfmtstr(totalsize)
1959 fmt2 = dfmtstr(totalsize)
1949 fmt2 = dfmtstr(totalsize)
1960 ui.write('revisions : ' + fmt2 % numrevs)
1950 ui.write('revisions : ' + fmt2 % numrevs)
1961 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
1951 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
1962 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
1952 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
1963 ui.write('revisions : ' + fmt2 % numrevs)
1953 ui.write('revisions : ' + fmt2 % numrevs)
1964 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
1954 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
1965 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
1955 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
1966 ui.write('revision size : ' + fmt2 % totalsize)
1956 ui.write('revision size : ' + fmt2 % totalsize)
1967 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
1957 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
1968 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
1958 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
1969
1959
1970 ui.write('\n')
1960 ui.write('\n')
1971 fmt = dfmtstr(max(avgchainlen, compratio))
1961 fmt = dfmtstr(max(avgchainlen, compratio))
1972 ui.write('avg chain length : ' + fmt % avgchainlen)
1962 ui.write('avg chain length : ' + fmt % avgchainlen)
1973 ui.write('compression ratio : ' + fmt % compratio)
1963 ui.write('compression ratio : ' + fmt % compratio)
1974
1964
1975 if format > 0:
1965 if format > 0:
1976 ui.write('\n')
1966 ui.write('\n')
1977 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
1967 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
1978 % tuple(datasize))
1968 % tuple(datasize))
1979 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
1969 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
1980 % tuple(fullsize))
1970 % tuple(fullsize))
1981 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
1971 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
1982 % tuple(deltasize))
1972 % tuple(deltasize))
1983
1973
1984 if numdeltas > 0:
1974 if numdeltas > 0:
1985 ui.write('\n')
1975 ui.write('\n')
1986 fmt = pcfmtstr(numdeltas)
1976 fmt = pcfmtstr(numdeltas)
1987 fmt2 = pcfmtstr(numdeltas, 4)
1977 fmt2 = pcfmtstr(numdeltas, 4)
1988 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
1978 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
1989 if numprev > 0:
1979 if numprev > 0:
1990 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
1980 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
1991 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
1981 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
1992 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
1982 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
1993 if gdelta:
1983 if gdelta:
1994 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
1984 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
1995 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
1985 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
1996 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
1986 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
1997
1987
1998 @command('debugrevspec', [], ('REVSPEC'))
1988 @command('debugrevspec', [], ('REVSPEC'))
1999 def debugrevspec(ui, repo, expr):
1989 def debugrevspec(ui, repo, expr):
2000 '''parse and apply a revision specification'''
1990 '''parse and apply a revision specification'''
2001 if ui.verbose:
1991 if ui.verbose:
2002 tree = revset.parse(expr)[0]
1992 tree = revset.parse(expr)[0]
2003 ui.note(tree, "\n")
1993 ui.note(tree, "\n")
2004 newtree = revset.findaliases(ui, tree)
1994 newtree = revset.findaliases(ui, tree)
2005 if newtree != tree:
1995 if newtree != tree:
2006 ui.note(newtree, "\n")
1996 ui.note(newtree, "\n")
2007 func = revset.match(ui, expr)
1997 func = revset.match(ui, expr)
2008 for c in func(repo, range(len(repo))):
1998 for c in func(repo, range(len(repo))):
2009 ui.write("%s\n" % c)
1999 ui.write("%s\n" % c)
2010
2000
2011 @command('debugsetparents', [], _('REV1 [REV2]'))
2001 @command('debugsetparents', [], _('REV1 [REV2]'))
2012 def debugsetparents(ui, repo, rev1, rev2=None):
2002 def debugsetparents(ui, repo, rev1, rev2=None):
2013 """manually set the parents of the current working directory
2003 """manually set the parents of the current working directory
2014
2004
2015 This is useful for writing repository conversion tools, but should
2005 This is useful for writing repository conversion tools, but should
2016 be used with care.
2006 be used with care.
2017
2007
2018 Returns 0 on success.
2008 Returns 0 on success.
2019 """
2009 """
2020
2010
2021 r1 = scmutil.revsingle(repo, rev1).node()
2011 r1 = scmutil.revsingle(repo, rev1).node()
2022 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2012 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2023
2013
2024 wlock = repo.wlock()
2014 wlock = repo.wlock()
2025 try:
2015 try:
2026 repo.dirstate.setparents(r1, r2)
2016 repo.dirstate.setparents(r1, r2)
2027 finally:
2017 finally:
2028 wlock.release()
2018 wlock.release()
2029
2019
2030 @command('debugstate',
2020 @command('debugstate',
2031 [('', 'nodates', None, _('do not display the saved mtime')),
2021 [('', 'nodates', None, _('do not display the saved mtime')),
2032 ('', 'datesort', None, _('sort by saved mtime'))],
2022 ('', 'datesort', None, _('sort by saved mtime'))],
2033 _('[OPTION]...'))
2023 _('[OPTION]...'))
2034 def debugstate(ui, repo, nodates=None, datesort=None):
2024 def debugstate(ui, repo, nodates=None, datesort=None):
2035 """show the contents of the current dirstate"""
2025 """show the contents of the current dirstate"""
2036 timestr = ""
2026 timestr = ""
2037 showdate = not nodates
2027 showdate = not nodates
2038 if datesort:
2028 if datesort:
2039 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2029 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2040 else:
2030 else:
2041 keyfunc = None # sort by filename
2031 keyfunc = None # sort by filename
2042 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2032 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2043 if showdate:
2033 if showdate:
2044 if ent[3] == -1:
2034 if ent[3] == -1:
2045 # Pad or slice to locale representation
2035 # Pad or slice to locale representation
2046 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2036 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2047 time.localtime(0)))
2037 time.localtime(0)))
2048 timestr = 'unset'
2038 timestr = 'unset'
2049 timestr = (timestr[:locale_len] +
2039 timestr = (timestr[:locale_len] +
2050 ' ' * (locale_len - len(timestr)))
2040 ' ' * (locale_len - len(timestr)))
2051 else:
2041 else:
2052 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2042 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2053 time.localtime(ent[3]))
2043 time.localtime(ent[3]))
2054 if ent[1] & 020000:
2044 if ent[1] & 020000:
2055 mode = 'lnk'
2045 mode = 'lnk'
2056 else:
2046 else:
2057 mode = '%3o' % (ent[1] & 0777)
2047 mode = '%3o' % (ent[1] & 0777)
2058 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2048 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2059 for f in repo.dirstate.copies():
2049 for f in repo.dirstate.copies():
2060 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2050 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2061
2051
2062 @command('debugsub',
2052 @command('debugsub',
2063 [('r', 'rev', '',
2053 [('r', 'rev', '',
2064 _('revision to check'), _('REV'))],
2054 _('revision to check'), _('REV'))],
2065 _('[-r REV] [REV]'))
2055 _('[-r REV] [REV]'))
2066 def debugsub(ui, repo, rev=None):
2056 def debugsub(ui, repo, rev=None):
2067 ctx = scmutil.revsingle(repo, rev, None)
2057 ctx = scmutil.revsingle(repo, rev, None)
2068 for k, v in sorted(ctx.substate.items()):
2058 for k, v in sorted(ctx.substate.items()):
2069 ui.write('path %s\n' % k)
2059 ui.write('path %s\n' % k)
2070 ui.write(' source %s\n' % v[0])
2060 ui.write(' source %s\n' % v[0])
2071 ui.write(' revision %s\n' % v[1])
2061 ui.write(' revision %s\n' % v[1])
2072
2062
2073 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2063 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2074 def debugwalk(ui, repo, *pats, **opts):
2064 def debugwalk(ui, repo, *pats, **opts):
2075 """show how files match on given patterns"""
2065 """show how files match on given patterns"""
2076 m = scmutil.match(repo, pats, opts)
2066 m = scmutil.match(repo, pats, opts)
2077 items = list(repo.walk(m))
2067 items = list(repo.walk(m))
2078 if not items:
2068 if not items:
2079 return
2069 return
2080 fmt = 'f %%-%ds %%-%ds %%s' % (
2070 fmt = 'f %%-%ds %%-%ds %%s' % (
2081 max([len(abs) for abs in items]),
2071 max([len(abs) for abs in items]),
2082 max([len(m.rel(abs)) for abs in items]))
2072 max([len(m.rel(abs)) for abs in items]))
2083 for abs in items:
2073 for abs in items:
2084 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2074 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2085 ui.write("%s\n" % line.rstrip())
2075 ui.write("%s\n" % line.rstrip())
2086
2076
2087 @command('debugwireargs',
2077 @command('debugwireargs',
2088 [('', 'three', '', 'three'),
2078 [('', 'three', '', 'three'),
2089 ('', 'four', '', 'four'),
2079 ('', 'four', '', 'four'),
2090 ('', 'five', '', 'five'),
2080 ('', 'five', '', 'five'),
2091 ] + remoteopts,
2081 ] + remoteopts,
2092 _('REPO [OPTIONS]... [ONE [TWO]]'))
2082 _('REPO [OPTIONS]... [ONE [TWO]]'))
2093 def debugwireargs(ui, repopath, *vals, **opts):
2083 def debugwireargs(ui, repopath, *vals, **opts):
2094 repo = hg.repository(hg.remoteui(ui, opts), repopath)
2084 repo = hg.repository(hg.remoteui(ui, opts), repopath)
2095 for opt in remoteopts:
2085 for opt in remoteopts:
2096 del opts[opt[1]]
2086 del opts[opt[1]]
2097 args = {}
2087 args = {}
2098 for k, v in opts.iteritems():
2088 for k, v in opts.iteritems():
2099 if v:
2089 if v:
2100 args[k] = v
2090 args[k] = v
2101 # run twice to check that we don't mess up the stream for the next command
2091 # run twice to check that we don't mess up the stream for the next command
2102 res1 = repo.debugwireargs(*vals, **args)
2092 res1 = repo.debugwireargs(*vals, **args)
2103 res2 = repo.debugwireargs(*vals, **args)
2093 res2 = repo.debugwireargs(*vals, **args)
2104 ui.write("%s\n" % res1)
2094 ui.write("%s\n" % res1)
2105 if res1 != res2:
2095 if res1 != res2:
2106 ui.warn("%s\n" % res2)
2096 ui.warn("%s\n" % res2)
2107
2097
2108 @command('^diff',
2098 @command('^diff',
2109 [('r', 'rev', [], _('revision'), _('REV')),
2099 [('r', 'rev', [], _('revision'), _('REV')),
2110 ('c', 'change', '', _('change made by revision'), _('REV'))
2100 ('c', 'change', '', _('change made by revision'), _('REV'))
2111 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2101 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2112 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2102 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2113 def diff(ui, repo, *pats, **opts):
2103 def diff(ui, repo, *pats, **opts):
2114 """diff repository (or selected files)
2104 """diff repository (or selected files)
2115
2105
2116 Show differences between revisions for the specified files.
2106 Show differences between revisions for the specified files.
2117
2107
2118 Differences between files are shown using the unified diff format.
2108 Differences between files are shown using the unified diff format.
2119
2109
2120 .. note::
2110 .. note::
2121 diff may generate unexpected results for merges, as it will
2111 diff may generate unexpected results for merges, as it will
2122 default to comparing against the working directory's first
2112 default to comparing against the working directory's first
2123 parent changeset if no revisions are specified.
2113 parent changeset if no revisions are specified.
2124
2114
2125 When two revision arguments are given, then changes are shown
2115 When two revision arguments are given, then changes are shown
2126 between those revisions. If only one revision is specified then
2116 between those revisions. If only one revision is specified then
2127 that revision is compared to the working directory, and, when no
2117 that revision is compared to the working directory, and, when no
2128 revisions are specified, the working directory files are compared
2118 revisions are specified, the working directory files are compared
2129 to its parent.
2119 to its parent.
2130
2120
2131 Alternatively you can specify -c/--change with a revision to see
2121 Alternatively you can specify -c/--change with a revision to see
2132 the changes in that changeset relative to its first parent.
2122 the changes in that changeset relative to its first parent.
2133
2123
2134 Without the -a/--text option, diff will avoid generating diffs of
2124 Without the -a/--text option, diff will avoid generating diffs of
2135 files it detects as binary. With -a, diff will generate a diff
2125 files it detects as binary. With -a, diff will generate a diff
2136 anyway, probably with undesirable results.
2126 anyway, probably with undesirable results.
2137
2127
2138 Use the -g/--git option to generate diffs in the git extended diff
2128 Use the -g/--git option to generate diffs in the git extended diff
2139 format. For more information, read :hg:`help diffs`.
2129 format. For more information, read :hg:`help diffs`.
2140
2130
2141 Returns 0 on success.
2131 Returns 0 on success.
2142 """
2132 """
2143
2133
2144 revs = opts.get('rev')
2134 revs = opts.get('rev')
2145 change = opts.get('change')
2135 change = opts.get('change')
2146 stat = opts.get('stat')
2136 stat = opts.get('stat')
2147 reverse = opts.get('reverse')
2137 reverse = opts.get('reverse')
2148
2138
2149 if revs and change:
2139 if revs and change:
2150 msg = _('cannot specify --rev and --change at the same time')
2140 msg = _('cannot specify --rev and --change at the same time')
2151 raise util.Abort(msg)
2141 raise util.Abort(msg)
2152 elif change:
2142 elif change:
2153 node2 = scmutil.revsingle(repo, change, None).node()
2143 node2 = scmutil.revsingle(repo, change, None).node()
2154 node1 = repo[node2].p1().node()
2144 node1 = repo[node2].p1().node()
2155 else:
2145 else:
2156 node1, node2 = scmutil.revpair(repo, revs)
2146 node1, node2 = scmutil.revpair(repo, revs)
2157
2147
2158 if reverse:
2148 if reverse:
2159 node1, node2 = node2, node1
2149 node1, node2 = node2, node1
2160
2150
2161 diffopts = patch.diffopts(ui, opts)
2151 diffopts = patch.diffopts(ui, opts)
2162 m = scmutil.match(repo, pats, opts)
2152 m = scmutil.match(repo, pats, opts)
2163 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2153 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2164 listsubrepos=opts.get('subrepos'))
2154 listsubrepos=opts.get('subrepos'))
2165
2155
2166 @command('^export',
2156 @command('^export',
2167 [('o', 'output', '',
2157 [('o', 'output', '',
2168 _('print output to file with formatted name'), _('FORMAT')),
2158 _('print output to file with formatted name'), _('FORMAT')),
2169 ('', 'switch-parent', None, _('diff against the second parent')),
2159 ('', 'switch-parent', None, _('diff against the second parent')),
2170 ('r', 'rev', [], _('revisions to export'), _('REV')),
2160 ('r', 'rev', [], _('revisions to export'), _('REV')),
2171 ] + diffopts,
2161 ] + diffopts,
2172 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2162 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2173 def export(ui, repo, *changesets, **opts):
2163 def export(ui, repo, *changesets, **opts):
2174 """dump the header and diffs for one or more changesets
2164 """dump the header and diffs for one or more changesets
2175
2165
2176 Print the changeset header and diffs for one or more revisions.
2166 Print the changeset header and diffs for one or more revisions.
2177
2167
2178 The information shown in the changeset header is: author, date,
2168 The information shown in the changeset header is: author, date,
2179 branch name (if non-default), changeset hash, parent(s) and commit
2169 branch name (if non-default), changeset hash, parent(s) and commit
2180 comment.
2170 comment.
2181
2171
2182 .. note::
2172 .. note::
2183 export may generate unexpected diff output for merge
2173 export may generate unexpected diff output for merge
2184 changesets, as it will compare the merge changeset against its
2174 changesets, as it will compare the merge changeset against its
2185 first parent only.
2175 first parent only.
2186
2176
2187 Output may be to a file, in which case the name of the file is
2177 Output may be to a file, in which case the name of the file is
2188 given using a format string. The formatting rules are as follows:
2178 given using a format string. The formatting rules are as follows:
2189
2179
2190 :``%%``: literal "%" character
2180 :``%%``: literal "%" character
2191 :``%H``: changeset hash (40 hexadecimal digits)
2181 :``%H``: changeset hash (40 hexadecimal digits)
2192 :``%N``: number of patches being generated
2182 :``%N``: number of patches being generated
2193 :``%R``: changeset revision number
2183 :``%R``: changeset revision number
2194 :``%b``: basename of the exporting repository
2184 :``%b``: basename of the exporting repository
2195 :``%h``: short-form changeset hash (12 hexadecimal digits)
2185 :``%h``: short-form changeset hash (12 hexadecimal digits)
2196 :``%n``: zero-padded sequence number, starting at 1
2186 :``%n``: zero-padded sequence number, starting at 1
2197 :``%r``: zero-padded changeset revision number
2187 :``%r``: zero-padded changeset revision number
2198
2188
2199 Without the -a/--text option, export will avoid generating diffs
2189 Without the -a/--text option, export will avoid generating diffs
2200 of files it detects as binary. With -a, export will generate a
2190 of files it detects as binary. With -a, export will generate a
2201 diff anyway, probably with undesirable results.
2191 diff anyway, probably with undesirable results.
2202
2192
2203 Use the -g/--git option to generate diffs in the git extended diff
2193 Use the -g/--git option to generate diffs in the git extended diff
2204 format. See :hg:`help diffs` for more information.
2194 format. See :hg:`help diffs` for more information.
2205
2195
2206 With the --switch-parent option, the diff will be against the
2196 With the --switch-parent option, the diff will be against the
2207 second parent. It can be useful to review a merge.
2197 second parent. It can be useful to review a merge.
2208
2198
2209 Returns 0 on success.
2199 Returns 0 on success.
2210 """
2200 """
2211 changesets += tuple(opts.get('rev', []))
2201 changesets += tuple(opts.get('rev', []))
2212 if not changesets:
2202 if not changesets:
2213 raise util.Abort(_("export requires at least one changeset"))
2203 raise util.Abort(_("export requires at least one changeset"))
2214 revs = scmutil.revrange(repo, changesets)
2204 revs = scmutil.revrange(repo, changesets)
2215 if len(revs) > 1:
2205 if len(revs) > 1:
2216 ui.note(_('exporting patches:\n'))
2206 ui.note(_('exporting patches:\n'))
2217 else:
2207 else:
2218 ui.note(_('exporting patch:\n'))
2208 ui.note(_('exporting patch:\n'))
2219 cmdutil.export(repo, revs, template=opts.get('output'),
2209 cmdutil.export(repo, revs, template=opts.get('output'),
2220 switch_parent=opts.get('switch_parent'),
2210 switch_parent=opts.get('switch_parent'),
2221 opts=patch.diffopts(ui, opts))
2211 opts=patch.diffopts(ui, opts))
2222
2212
2223 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2213 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2224 def forget(ui, repo, *pats, **opts):
2214 def forget(ui, repo, *pats, **opts):
2225 """forget the specified files on the next commit
2215 """forget the specified files on the next commit
2226
2216
2227 Mark the specified files so they will no longer be tracked
2217 Mark the specified files so they will no longer be tracked
2228 after the next commit.
2218 after the next commit.
2229
2219
2230 This only removes files from the current branch, not from the
2220 This only removes files from the current branch, not from the
2231 entire project history, and it does not delete them from the
2221 entire project history, and it does not delete them from the
2232 working directory.
2222 working directory.
2233
2223
2234 To undo a forget before the next commit, see :hg:`add`.
2224 To undo a forget before the next commit, see :hg:`add`.
2235
2225
2236 Returns 0 on success.
2226 Returns 0 on success.
2237 """
2227 """
2238
2228
2239 if not pats:
2229 if not pats:
2240 raise util.Abort(_('no files specified'))
2230 raise util.Abort(_('no files specified'))
2241
2231
2242 m = scmutil.match(repo, pats, opts)
2232 m = scmutil.match(repo, pats, opts)
2243 s = repo.status(match=m, clean=True)
2233 s = repo.status(match=m, clean=True)
2244 forget = sorted(s[0] + s[1] + s[3] + s[6])
2234 forget = sorted(s[0] + s[1] + s[3] + s[6])
2245 errs = 0
2235 errs = 0
2246
2236
2247 for f in m.files():
2237 for f in m.files():
2248 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2238 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2249 ui.warn(_('not removing %s: file is already untracked\n')
2239 ui.warn(_('not removing %s: file is already untracked\n')
2250 % m.rel(f))
2240 % m.rel(f))
2251 errs = 1
2241 errs = 1
2252
2242
2253 for f in forget:
2243 for f in forget:
2254 if ui.verbose or not m.exact(f):
2244 if ui.verbose or not m.exact(f):
2255 ui.status(_('removing %s\n') % m.rel(f))
2245 ui.status(_('removing %s\n') % m.rel(f))
2256
2246
2257 repo[None].remove(forget, unlink=False)
2247 repo[None].remove(forget, unlink=False)
2258 return errs
2248 return errs
2259
2249
2260 @command('grep',
2250 @command('grep',
2261 [('0', 'print0', None, _('end fields with NUL')),
2251 [('0', 'print0', None, _('end fields with NUL')),
2262 ('', 'all', None, _('print all revisions that match')),
2252 ('', 'all', None, _('print all revisions that match')),
2263 ('a', 'text', None, _('treat all files as text')),
2253 ('a', 'text', None, _('treat all files as text')),
2264 ('f', 'follow', None,
2254 ('f', 'follow', None,
2265 _('follow changeset history,'
2255 _('follow changeset history,'
2266 ' or file history across copies and renames')),
2256 ' or file history across copies and renames')),
2267 ('i', 'ignore-case', None, _('ignore case when matching')),
2257 ('i', 'ignore-case', None, _('ignore case when matching')),
2268 ('l', 'files-with-matches', None,
2258 ('l', 'files-with-matches', None,
2269 _('print only filenames and revisions that match')),
2259 _('print only filenames and revisions that match')),
2270 ('n', 'line-number', None, _('print matching line numbers')),
2260 ('n', 'line-number', None, _('print matching line numbers')),
2271 ('r', 'rev', [],
2261 ('r', 'rev', [],
2272 _('only search files changed within revision range'), _('REV')),
2262 _('only search files changed within revision range'), _('REV')),
2273 ('u', 'user', None, _('list the author (long with -v)')),
2263 ('u', 'user', None, _('list the author (long with -v)')),
2274 ('d', 'date', None, _('list the date (short with -q)')),
2264 ('d', 'date', None, _('list the date (short with -q)')),
2275 ] + walkopts,
2265 ] + walkopts,
2276 _('[OPTION]... PATTERN [FILE]...'))
2266 _('[OPTION]... PATTERN [FILE]...'))
2277 def grep(ui, repo, pattern, *pats, **opts):
2267 def grep(ui, repo, pattern, *pats, **opts):
2278 """search for a pattern in specified files and revisions
2268 """search for a pattern in specified files and revisions
2279
2269
2280 Search revisions of files for a regular expression.
2270 Search revisions of files for a regular expression.
2281
2271
2282 This command behaves differently than Unix grep. It only accepts
2272 This command behaves differently than Unix grep. It only accepts
2283 Python/Perl regexps. It searches repository history, not the
2273 Python/Perl regexps. It searches repository history, not the
2284 working directory. It always prints the revision number in which a
2274 working directory. It always prints the revision number in which a
2285 match appears.
2275 match appears.
2286
2276
2287 By default, grep only prints output for the first revision of a
2277 By default, grep only prints output for the first revision of a
2288 file in which it finds a match. To get it to print every revision
2278 file in which it finds a match. To get it to print every revision
2289 that contains a change in match status ("-" for a match that
2279 that contains a change in match status ("-" for a match that
2290 becomes a non-match, or "+" for a non-match that becomes a match),
2280 becomes a non-match, or "+" for a non-match that becomes a match),
2291 use the --all flag.
2281 use the --all flag.
2292
2282
2293 Returns 0 if a match is found, 1 otherwise.
2283 Returns 0 if a match is found, 1 otherwise.
2294 """
2284 """
2295 reflags = 0
2285 reflags = 0
2296 if opts.get('ignore_case'):
2286 if opts.get('ignore_case'):
2297 reflags |= re.I
2287 reflags |= re.I
2298 try:
2288 try:
2299 regexp = re.compile(pattern, reflags)
2289 regexp = re.compile(pattern, reflags)
2300 except re.error, inst:
2290 except re.error, inst:
2301 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2291 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2302 return 1
2292 return 1
2303 sep, eol = ':', '\n'
2293 sep, eol = ':', '\n'
2304 if opts.get('print0'):
2294 if opts.get('print0'):
2305 sep = eol = '\0'
2295 sep = eol = '\0'
2306
2296
2307 getfile = util.lrucachefunc(repo.file)
2297 getfile = util.lrucachefunc(repo.file)
2308
2298
2309 def matchlines(body):
2299 def matchlines(body):
2310 begin = 0
2300 begin = 0
2311 linenum = 0
2301 linenum = 0
2312 while True:
2302 while True:
2313 match = regexp.search(body, begin)
2303 match = regexp.search(body, begin)
2314 if not match:
2304 if not match:
2315 break
2305 break
2316 mstart, mend = match.span()
2306 mstart, mend = match.span()
2317 linenum += body.count('\n', begin, mstart) + 1
2307 linenum += body.count('\n', begin, mstart) + 1
2318 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2308 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2319 begin = body.find('\n', mend) + 1 or len(body)
2309 begin = body.find('\n', mend) + 1 or len(body)
2320 lend = begin - 1
2310 lend = begin - 1
2321 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2311 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2322
2312
2323 class linestate(object):
2313 class linestate(object):
2324 def __init__(self, line, linenum, colstart, colend):
2314 def __init__(self, line, linenum, colstart, colend):
2325 self.line = line
2315 self.line = line
2326 self.linenum = linenum
2316 self.linenum = linenum
2327 self.colstart = colstart
2317 self.colstart = colstart
2328 self.colend = colend
2318 self.colend = colend
2329
2319
2330 def __hash__(self):
2320 def __hash__(self):
2331 return hash((self.linenum, self.line))
2321 return hash((self.linenum, self.line))
2332
2322
2333 def __eq__(self, other):
2323 def __eq__(self, other):
2334 return self.line == other.line
2324 return self.line == other.line
2335
2325
2336 matches = {}
2326 matches = {}
2337 copies = {}
2327 copies = {}
2338 def grepbody(fn, rev, body):
2328 def grepbody(fn, rev, body):
2339 matches[rev].setdefault(fn, [])
2329 matches[rev].setdefault(fn, [])
2340 m = matches[rev][fn]
2330 m = matches[rev][fn]
2341 for lnum, cstart, cend, line in matchlines(body):
2331 for lnum, cstart, cend, line in matchlines(body):
2342 s = linestate(line, lnum, cstart, cend)
2332 s = linestate(line, lnum, cstart, cend)
2343 m.append(s)
2333 m.append(s)
2344
2334
2345 def difflinestates(a, b):
2335 def difflinestates(a, b):
2346 sm = difflib.SequenceMatcher(None, a, b)
2336 sm = difflib.SequenceMatcher(None, a, b)
2347 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2337 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2348 if tag == 'insert':
2338 if tag == 'insert':
2349 for i in xrange(blo, bhi):
2339 for i in xrange(blo, bhi):
2350 yield ('+', b[i])
2340 yield ('+', b[i])
2351 elif tag == 'delete':
2341 elif tag == 'delete':
2352 for i in xrange(alo, ahi):
2342 for i in xrange(alo, ahi):
2353 yield ('-', a[i])
2343 yield ('-', a[i])
2354 elif tag == 'replace':
2344 elif tag == 'replace':
2355 for i in xrange(alo, ahi):
2345 for i in xrange(alo, ahi):
2356 yield ('-', a[i])
2346 yield ('-', a[i])
2357 for i in xrange(blo, bhi):
2347 for i in xrange(blo, bhi):
2358 yield ('+', b[i])
2348 yield ('+', b[i])
2359
2349
2360 def display(fn, ctx, pstates, states):
2350 def display(fn, ctx, pstates, states):
2361 rev = ctx.rev()
2351 rev = ctx.rev()
2362 datefunc = ui.quiet and util.shortdate or util.datestr
2352 datefunc = ui.quiet and util.shortdate or util.datestr
2363 found = False
2353 found = False
2364 filerevmatches = {}
2354 filerevmatches = {}
2365 def binary():
2355 def binary():
2366 flog = getfile(fn)
2356 flog = getfile(fn)
2367 return util.binary(flog.read(ctx.filenode(fn)))
2357 return util.binary(flog.read(ctx.filenode(fn)))
2368
2358
2369 if opts.get('all'):
2359 if opts.get('all'):
2370 iter = difflinestates(pstates, states)
2360 iter = difflinestates(pstates, states)
2371 else:
2361 else:
2372 iter = [('', l) for l in states]
2362 iter = [('', l) for l in states]
2373 for change, l in iter:
2363 for change, l in iter:
2374 cols = [fn, str(rev)]
2364 cols = [fn, str(rev)]
2375 before, match, after = None, None, None
2365 before, match, after = None, None, None
2376 if opts.get('line_number'):
2366 if opts.get('line_number'):
2377 cols.append(str(l.linenum))
2367 cols.append(str(l.linenum))
2378 if opts.get('all'):
2368 if opts.get('all'):
2379 cols.append(change)
2369 cols.append(change)
2380 if opts.get('user'):
2370 if opts.get('user'):
2381 cols.append(ui.shortuser(ctx.user()))
2371 cols.append(ui.shortuser(ctx.user()))
2382 if opts.get('date'):
2372 if opts.get('date'):
2383 cols.append(datefunc(ctx.date()))
2373 cols.append(datefunc(ctx.date()))
2384 if opts.get('files_with_matches'):
2374 if opts.get('files_with_matches'):
2385 c = (fn, rev)
2375 c = (fn, rev)
2386 if c in filerevmatches:
2376 if c in filerevmatches:
2387 continue
2377 continue
2388 filerevmatches[c] = 1
2378 filerevmatches[c] = 1
2389 else:
2379 else:
2390 before = l.line[:l.colstart]
2380 before = l.line[:l.colstart]
2391 match = l.line[l.colstart:l.colend]
2381 match = l.line[l.colstart:l.colend]
2392 after = l.line[l.colend:]
2382 after = l.line[l.colend:]
2393 ui.write(sep.join(cols))
2383 ui.write(sep.join(cols))
2394 if before is not None:
2384 if before is not None:
2395 if not opts.get('text') and binary():
2385 if not opts.get('text') and binary():
2396 ui.write(sep + " Binary file matches")
2386 ui.write(sep + " Binary file matches")
2397 else:
2387 else:
2398 ui.write(sep + before)
2388 ui.write(sep + before)
2399 ui.write(match, label='grep.match')
2389 ui.write(match, label='grep.match')
2400 ui.write(after)
2390 ui.write(after)
2401 ui.write(eol)
2391 ui.write(eol)
2402 found = True
2392 found = True
2403 return found
2393 return found
2404
2394
2405 skip = {}
2395 skip = {}
2406 revfiles = {}
2396 revfiles = {}
2407 matchfn = scmutil.match(repo, pats, opts)
2397 matchfn = scmutil.match(repo, pats, opts)
2408 found = False
2398 found = False
2409 follow = opts.get('follow')
2399 follow = opts.get('follow')
2410
2400
2411 def prep(ctx, fns):
2401 def prep(ctx, fns):
2412 rev = ctx.rev()
2402 rev = ctx.rev()
2413 pctx = ctx.p1()
2403 pctx = ctx.p1()
2414 parent = pctx.rev()
2404 parent = pctx.rev()
2415 matches.setdefault(rev, {})
2405 matches.setdefault(rev, {})
2416 matches.setdefault(parent, {})
2406 matches.setdefault(parent, {})
2417 files = revfiles.setdefault(rev, [])
2407 files = revfiles.setdefault(rev, [])
2418 for fn in fns:
2408 for fn in fns:
2419 flog = getfile(fn)
2409 flog = getfile(fn)
2420 try:
2410 try:
2421 fnode = ctx.filenode(fn)
2411 fnode = ctx.filenode(fn)
2422 except error.LookupError:
2412 except error.LookupError:
2423 continue
2413 continue
2424
2414
2425 copied = flog.renamed(fnode)
2415 copied = flog.renamed(fnode)
2426 copy = follow and copied and copied[0]
2416 copy = follow and copied and copied[0]
2427 if copy:
2417 if copy:
2428 copies.setdefault(rev, {})[fn] = copy
2418 copies.setdefault(rev, {})[fn] = copy
2429 if fn in skip:
2419 if fn in skip:
2430 if copy:
2420 if copy:
2431 skip[copy] = True
2421 skip[copy] = True
2432 continue
2422 continue
2433 files.append(fn)
2423 files.append(fn)
2434
2424
2435 if fn not in matches[rev]:
2425 if fn not in matches[rev]:
2436 grepbody(fn, rev, flog.read(fnode))
2426 grepbody(fn, rev, flog.read(fnode))
2437
2427
2438 pfn = copy or fn
2428 pfn = copy or fn
2439 if pfn not in matches[parent]:
2429 if pfn not in matches[parent]:
2440 try:
2430 try:
2441 fnode = pctx.filenode(pfn)
2431 fnode = pctx.filenode(pfn)
2442 grepbody(pfn, parent, flog.read(fnode))
2432 grepbody(pfn, parent, flog.read(fnode))
2443 except error.LookupError:
2433 except error.LookupError:
2444 pass
2434 pass
2445
2435
2446 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2436 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2447 rev = ctx.rev()
2437 rev = ctx.rev()
2448 parent = ctx.p1().rev()
2438 parent = ctx.p1().rev()
2449 for fn in sorted(revfiles.get(rev, [])):
2439 for fn in sorted(revfiles.get(rev, [])):
2450 states = matches[rev][fn]
2440 states = matches[rev][fn]
2451 copy = copies.get(rev, {}).get(fn)
2441 copy = copies.get(rev, {}).get(fn)
2452 if fn in skip:
2442 if fn in skip:
2453 if copy:
2443 if copy:
2454 skip[copy] = True
2444 skip[copy] = True
2455 continue
2445 continue
2456 pstates = matches.get(parent, {}).get(copy or fn, [])
2446 pstates = matches.get(parent, {}).get(copy or fn, [])
2457 if pstates or states:
2447 if pstates or states:
2458 r = display(fn, ctx, pstates, states)
2448 r = display(fn, ctx, pstates, states)
2459 found = found or r
2449 found = found or r
2460 if r and not opts.get('all'):
2450 if r and not opts.get('all'):
2461 skip[fn] = True
2451 skip[fn] = True
2462 if copy:
2452 if copy:
2463 skip[copy] = True
2453 skip[copy] = True
2464 del matches[rev]
2454 del matches[rev]
2465 del revfiles[rev]
2455 del revfiles[rev]
2466
2456
2467 return not found
2457 return not found
2468
2458
2469 @command('heads',
2459 @command('heads',
2470 [('r', 'rev', '',
2460 [('r', 'rev', '',
2471 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2461 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2472 ('t', 'topo', False, _('show topological heads only')),
2462 ('t', 'topo', False, _('show topological heads only')),
2473 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2463 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2474 ('c', 'closed', False, _('show normal and closed branch heads')),
2464 ('c', 'closed', False, _('show normal and closed branch heads')),
2475 ] + templateopts,
2465 ] + templateopts,
2476 _('[-ac] [-r STARTREV] [REV]...'))
2466 _('[-ac] [-r STARTREV] [REV]...'))
2477 def heads(ui, repo, *branchrevs, **opts):
2467 def heads(ui, repo, *branchrevs, **opts):
2478 """show current repository heads or show branch heads
2468 """show current repository heads or show branch heads
2479
2469
2480 With no arguments, show all repository branch heads.
2470 With no arguments, show all repository branch heads.
2481
2471
2482 Repository "heads" are changesets with no child changesets. They are
2472 Repository "heads" are changesets with no child changesets. They are
2483 where development generally takes place and are the usual targets
2473 where development generally takes place and are the usual targets
2484 for update and merge operations. Branch heads are changesets that have
2474 for update and merge operations. Branch heads are changesets that have
2485 no child changeset on the same branch.
2475 no child changeset on the same branch.
2486
2476
2487 If one or more REVs are given, only branch heads on the branches
2477 If one or more REVs are given, only branch heads on the branches
2488 associated with the specified changesets are shown.
2478 associated with the specified changesets are shown.
2489
2479
2490 If -c/--closed is specified, also show branch heads marked closed
2480 If -c/--closed is specified, also show branch heads marked closed
2491 (see :hg:`commit --close-branch`).
2481 (see :hg:`commit --close-branch`).
2492
2482
2493 If STARTREV is specified, only those heads that are descendants of
2483 If STARTREV is specified, only those heads that are descendants of
2494 STARTREV will be displayed.
2484 STARTREV will be displayed.
2495
2485
2496 If -t/--topo is specified, named branch mechanics will be ignored and only
2486 If -t/--topo is specified, named branch mechanics will be ignored and only
2497 changesets without children will be shown.
2487 changesets without children will be shown.
2498
2488
2499 Returns 0 if matching heads are found, 1 if not.
2489 Returns 0 if matching heads are found, 1 if not.
2500 """
2490 """
2501
2491
2502 start = None
2492 start = None
2503 if 'rev' in opts:
2493 if 'rev' in opts:
2504 start = scmutil.revsingle(repo, opts['rev'], None).node()
2494 start = scmutil.revsingle(repo, opts['rev'], None).node()
2505
2495
2506 if opts.get('topo'):
2496 if opts.get('topo'):
2507 heads = [repo[h] for h in repo.heads(start)]
2497 heads = [repo[h] for h in repo.heads(start)]
2508 else:
2498 else:
2509 heads = []
2499 heads = []
2510 for b, ls in repo.branchmap().iteritems():
2500 for b, ls in repo.branchmap().iteritems():
2511 if start is None:
2501 if start is None:
2512 heads += [repo[h] for h in ls]
2502 heads += [repo[h] for h in ls]
2513 continue
2503 continue
2514 startrev = repo.changelog.rev(start)
2504 startrev = repo.changelog.rev(start)
2515 descendants = set(repo.changelog.descendants(startrev))
2505 descendants = set(repo.changelog.descendants(startrev))
2516 descendants.add(startrev)
2506 descendants.add(startrev)
2517 rev = repo.changelog.rev
2507 rev = repo.changelog.rev
2518 heads += [repo[h] for h in ls if rev(h) in descendants]
2508 heads += [repo[h] for h in ls if rev(h) in descendants]
2519
2509
2520 if branchrevs:
2510 if branchrevs:
2521 branches = set(repo[br].branch() for br in branchrevs)
2511 branches = set(repo[br].branch() for br in branchrevs)
2522 heads = [h for h in heads if h.branch() in branches]
2512 heads = [h for h in heads if h.branch() in branches]
2523
2513
2524 if not opts.get('closed'):
2514 if not opts.get('closed'):
2525 heads = [h for h in heads if not h.extra().get('close')]
2515 heads = [h for h in heads if not h.extra().get('close')]
2526
2516
2527 if opts.get('active') and branchrevs:
2517 if opts.get('active') and branchrevs:
2528 dagheads = repo.heads(start)
2518 dagheads = repo.heads(start)
2529 heads = [h for h in heads if h.node() in dagheads]
2519 heads = [h for h in heads if h.node() in dagheads]
2530
2520
2531 if branchrevs:
2521 if branchrevs:
2532 haveheads = set(h.branch() for h in heads)
2522 haveheads = set(h.branch() for h in heads)
2533 if branches - haveheads:
2523 if branches - haveheads:
2534 headless = ', '.join(b for b in branches - haveheads)
2524 headless = ', '.join(b for b in branches - haveheads)
2535 msg = _('no open branch heads found on branches %s')
2525 msg = _('no open branch heads found on branches %s')
2536 if opts.get('rev'):
2526 if opts.get('rev'):
2537 msg += _(' (started at %s)' % opts['rev'])
2527 msg += _(' (started at %s)' % opts['rev'])
2538 ui.warn((msg + '\n') % headless)
2528 ui.warn((msg + '\n') % headless)
2539
2529
2540 if not heads:
2530 if not heads:
2541 return 1
2531 return 1
2542
2532
2543 heads = sorted(heads, key=lambda x: -x.rev())
2533 heads = sorted(heads, key=lambda x: -x.rev())
2544 displayer = cmdutil.show_changeset(ui, repo, opts)
2534 displayer = cmdutil.show_changeset(ui, repo, opts)
2545 for ctx in heads:
2535 for ctx in heads:
2546 displayer.show(ctx)
2536 displayer.show(ctx)
2547 displayer.close()
2537 displayer.close()
2548
2538
2549 @command('help',
2539 @command('help',
2550 [('e', 'extension', None, _('show only help for extensions')),
2540 [('e', 'extension', None, _('show only help for extensions')),
2551 ('c', 'command', None, _('show only help for commands'))],
2541 ('c', 'command', None, _('show only help for commands'))],
2552 _('[-ec] [TOPIC]'))
2542 _('[-ec] [TOPIC]'))
2553 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True, **opts):
2543 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True, **opts):
2554 """show help for a given topic or a help overview
2544 """show help for a given topic or a help overview
2555
2545
2556 With no arguments, print a list of commands with short help messages.
2546 With no arguments, print a list of commands with short help messages.
2557
2547
2558 Given a topic, extension, or command name, print help for that
2548 Given a topic, extension, or command name, print help for that
2559 topic.
2549 topic.
2560
2550
2561 Returns 0 if successful.
2551 Returns 0 if successful.
2562 """
2552 """
2563 option_lists = []
2553 option_lists = []
2564 textwidth = min(ui.termwidth(), 80) - 2
2554 textwidth = min(ui.termwidth(), 80) - 2
2565
2555
2566 def addglobalopts(aliases):
2556 def addglobalopts(aliases):
2567 if ui.verbose:
2557 if ui.verbose:
2568 option_lists.append((_("global options:"), globalopts))
2558 option_lists.append((_("global options:"), globalopts))
2569 if name == 'shortlist':
2559 if name == 'shortlist':
2570 option_lists.append((_('use "hg help" for the full list '
2560 option_lists.append((_('use "hg help" for the full list '
2571 'of commands'), ()))
2561 'of commands'), ()))
2572 else:
2562 else:
2573 if name == 'shortlist':
2563 if name == 'shortlist':
2574 msg = _('use "hg help" for the full list of commands '
2564 msg = _('use "hg help" for the full list of commands '
2575 'or "hg -v" for details')
2565 'or "hg -v" for details')
2576 elif name and not full:
2566 elif name and not full:
2577 msg = _('use "hg help %s" to show the full help text' % name)
2567 msg = _('use "hg help %s" to show the full help text' % name)
2578 elif aliases:
2568 elif aliases:
2579 msg = _('use "hg -v help%s" to show builtin aliases and '
2569 msg = _('use "hg -v help%s" to show builtin aliases and '
2580 'global options') % (name and " " + name or "")
2570 'global options') % (name and " " + name or "")
2581 else:
2571 else:
2582 msg = _('use "hg -v help %s" to show global options') % name
2572 msg = _('use "hg -v help %s" to show global options') % name
2583 option_lists.append((msg, ()))
2573 option_lists.append((msg, ()))
2584
2574
2585 def helpcmd(name):
2575 def helpcmd(name):
2586 if with_version:
2576 if with_version:
2587 version_(ui)
2577 version_(ui)
2588 ui.write('\n')
2578 ui.write('\n')
2589
2579
2590 try:
2580 try:
2591 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2581 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2592 except error.AmbiguousCommand, inst:
2582 except error.AmbiguousCommand, inst:
2593 # py3k fix: except vars can't be used outside the scope of the
2583 # py3k fix: except vars can't be used outside the scope of the
2594 # except block, nor can be used inside a lambda. python issue4617
2584 # except block, nor can be used inside a lambda. python issue4617
2595 prefix = inst.args[0]
2585 prefix = inst.args[0]
2596 select = lambda c: c.lstrip('^').startswith(prefix)
2586 select = lambda c: c.lstrip('^').startswith(prefix)
2597 helplist(_('list of commands:\n\n'), select)
2587 helplist(_('list of commands:\n\n'), select)
2598 return
2588 return
2599
2589
2600 # check if it's an invalid alias and display its error if it is
2590 # check if it's an invalid alias and display its error if it is
2601 if getattr(entry[0], 'badalias', False):
2591 if getattr(entry[0], 'badalias', False):
2602 if not unknowncmd:
2592 if not unknowncmd:
2603 entry[0](ui)
2593 entry[0](ui)
2604 return
2594 return
2605
2595
2606 # synopsis
2596 # synopsis
2607 if len(entry) > 2:
2597 if len(entry) > 2:
2608 if entry[2].startswith('hg'):
2598 if entry[2].startswith('hg'):
2609 ui.write("%s\n" % entry[2])
2599 ui.write("%s\n" % entry[2])
2610 else:
2600 else:
2611 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2601 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2612 else:
2602 else:
2613 ui.write('hg %s\n' % aliases[0])
2603 ui.write('hg %s\n' % aliases[0])
2614
2604
2615 # aliases
2605 # aliases
2616 if full and not ui.quiet and len(aliases) > 1:
2606 if full and not ui.quiet and len(aliases) > 1:
2617 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2607 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2618
2608
2619 # description
2609 # description
2620 doc = gettext(entry[0].__doc__)
2610 doc = gettext(entry[0].__doc__)
2621 if not doc:
2611 if not doc:
2622 doc = _("(no help text available)")
2612 doc = _("(no help text available)")
2623 if hasattr(entry[0], 'definition'): # aliased command
2613 if hasattr(entry[0], 'definition'): # aliased command
2624 if entry[0].definition.startswith('!'): # shell alias
2614 if entry[0].definition.startswith('!'): # shell alias
2625 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2615 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2626 else:
2616 else:
2627 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2617 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2628 if ui.quiet or not full:
2618 if ui.quiet or not full:
2629 doc = doc.splitlines()[0]
2619 doc = doc.splitlines()[0]
2630 keep = ui.verbose and ['verbose'] or []
2620 keep = ui.verbose and ['verbose'] or []
2631 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2621 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2632 ui.write("\n%s\n" % formatted)
2622 ui.write("\n%s\n" % formatted)
2633 if pruned:
2623 if pruned:
2634 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2624 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2635
2625
2636 if not ui.quiet:
2626 if not ui.quiet:
2637 # options
2627 # options
2638 if entry[1]:
2628 if entry[1]:
2639 option_lists.append((_("options:\n"), entry[1]))
2629 option_lists.append((_("options:\n"), entry[1]))
2640
2630
2641 addglobalopts(False)
2631 addglobalopts(False)
2642
2632
2643 # check if this command shadows a non-trivial (multi-line)
2633 # check if this command shadows a non-trivial (multi-line)
2644 # extension help text
2634 # extension help text
2645 try:
2635 try:
2646 mod = extensions.find(name)
2636 mod = extensions.find(name)
2647 doc = gettext(mod.__doc__) or ''
2637 doc = gettext(mod.__doc__) or ''
2648 if '\n' in doc.strip():
2638 if '\n' in doc.strip():
2649 msg = _('use "hg help -e %s" to show help for '
2639 msg = _('use "hg help -e %s" to show help for '
2650 'the %s extension') % (name, name)
2640 'the %s extension') % (name, name)
2651 ui.write('\n%s\n' % msg)
2641 ui.write('\n%s\n' % msg)
2652 except KeyError:
2642 except KeyError:
2653 pass
2643 pass
2654
2644
2655 def helplist(header, select=None):
2645 def helplist(header, select=None):
2656 h = {}
2646 h = {}
2657 cmds = {}
2647 cmds = {}
2658 for c, e in table.iteritems():
2648 for c, e in table.iteritems():
2659 f = c.split("|", 1)[0]
2649 f = c.split("|", 1)[0]
2660 if select and not select(f):
2650 if select and not select(f):
2661 continue
2651 continue
2662 if (not select and name != 'shortlist' and
2652 if (not select and name != 'shortlist' and
2663 e[0].__module__ != __name__):
2653 e[0].__module__ != __name__):
2664 continue
2654 continue
2665 if name == "shortlist" and not f.startswith("^"):
2655 if name == "shortlist" and not f.startswith("^"):
2666 continue
2656 continue
2667 f = f.lstrip("^")
2657 f = f.lstrip("^")
2668 if not ui.debugflag and f.startswith("debug"):
2658 if not ui.debugflag and f.startswith("debug"):
2669 continue
2659 continue
2670 doc = e[0].__doc__
2660 doc = e[0].__doc__
2671 if doc and 'DEPRECATED' in doc and not ui.verbose:
2661 if doc and 'DEPRECATED' in doc and not ui.verbose:
2672 continue
2662 continue
2673 doc = gettext(doc)
2663 doc = gettext(doc)
2674 if not doc:
2664 if not doc:
2675 doc = _("(no help text available)")
2665 doc = _("(no help text available)")
2676 h[f] = doc.splitlines()[0].rstrip()
2666 h[f] = doc.splitlines()[0].rstrip()
2677 cmds[f] = c.lstrip("^")
2667 cmds[f] = c.lstrip("^")
2678
2668
2679 if not h:
2669 if not h:
2680 ui.status(_('no commands defined\n'))
2670 ui.status(_('no commands defined\n'))
2681 return
2671 return
2682
2672
2683 ui.status(header)
2673 ui.status(header)
2684 fns = sorted(h)
2674 fns = sorted(h)
2685 m = max(map(len, fns))
2675 m = max(map(len, fns))
2686 for f in fns:
2676 for f in fns:
2687 if ui.verbose:
2677 if ui.verbose:
2688 commands = cmds[f].replace("|",", ")
2678 commands = cmds[f].replace("|",", ")
2689 ui.write(" %s:\n %s\n"%(commands, h[f]))
2679 ui.write(" %s:\n %s\n"%(commands, h[f]))
2690 else:
2680 else:
2691 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2681 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2692 initindent=' %-*s ' % (m, f),
2682 initindent=' %-*s ' % (m, f),
2693 hangindent=' ' * (m + 4))))
2683 hangindent=' ' * (m + 4))))
2694
2684
2695 if not ui.quiet:
2685 if not ui.quiet:
2696 addglobalopts(True)
2686 addglobalopts(True)
2697
2687
2698 def helptopic(name):
2688 def helptopic(name):
2699 for names, header, doc in help.helptable:
2689 for names, header, doc in help.helptable:
2700 if name in names:
2690 if name in names:
2701 break
2691 break
2702 else:
2692 else:
2703 raise error.UnknownCommand(name)
2693 raise error.UnknownCommand(name)
2704
2694
2705 # description
2695 # description
2706 if not doc:
2696 if not doc:
2707 doc = _("(no help text available)")
2697 doc = _("(no help text available)")
2708 if hasattr(doc, '__call__'):
2698 if hasattr(doc, '__call__'):
2709 doc = doc()
2699 doc = doc()
2710
2700
2711 ui.write("%s\n\n" % header)
2701 ui.write("%s\n\n" % header)
2712 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2702 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2713 try:
2703 try:
2714 cmdutil.findcmd(name, table)
2704 cmdutil.findcmd(name, table)
2715 ui.write(_('\nuse "hg help -c %s" to see help for '
2705 ui.write(_('\nuse "hg help -c %s" to see help for '
2716 'the %s command\n') % (name, name))
2706 'the %s command\n') % (name, name))
2717 except error.UnknownCommand:
2707 except error.UnknownCommand:
2718 pass
2708 pass
2719
2709
2720 def helpext(name):
2710 def helpext(name):
2721 try:
2711 try:
2722 mod = extensions.find(name)
2712 mod = extensions.find(name)
2723 doc = gettext(mod.__doc__) or _('no help text available')
2713 doc = gettext(mod.__doc__) or _('no help text available')
2724 except KeyError:
2714 except KeyError:
2725 mod = None
2715 mod = None
2726 doc = extensions.disabledext(name)
2716 doc = extensions.disabledext(name)
2727 if not doc:
2717 if not doc:
2728 raise error.UnknownCommand(name)
2718 raise error.UnknownCommand(name)
2729
2719
2730 if '\n' not in doc:
2720 if '\n' not in doc:
2731 head, tail = doc, ""
2721 head, tail = doc, ""
2732 else:
2722 else:
2733 head, tail = doc.split('\n', 1)
2723 head, tail = doc.split('\n', 1)
2734 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2724 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2735 if tail:
2725 if tail:
2736 ui.write(minirst.format(tail, textwidth))
2726 ui.write(minirst.format(tail, textwidth))
2737 ui.status('\n\n')
2727 ui.status('\n\n')
2738
2728
2739 if mod:
2729 if mod:
2740 try:
2730 try:
2741 ct = mod.cmdtable
2731 ct = mod.cmdtable
2742 except AttributeError:
2732 except AttributeError:
2743 ct = {}
2733 ct = {}
2744 modcmds = set([c.split('|', 1)[0] for c in ct])
2734 modcmds = set([c.split('|', 1)[0] for c in ct])
2745 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2735 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2746 else:
2736 else:
2747 ui.write(_('use "hg help extensions" for information on enabling '
2737 ui.write(_('use "hg help extensions" for information on enabling '
2748 'extensions\n'))
2738 'extensions\n'))
2749
2739
2750 def helpextcmd(name):
2740 def helpextcmd(name):
2751 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2741 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2752 doc = gettext(mod.__doc__).splitlines()[0]
2742 doc = gettext(mod.__doc__).splitlines()[0]
2753
2743
2754 msg = help.listexts(_("'%s' is provided by the following "
2744 msg = help.listexts(_("'%s' is provided by the following "
2755 "extension:") % cmd, {ext: doc}, indent=4)
2745 "extension:") % cmd, {ext: doc}, indent=4)
2756 ui.write(minirst.format(msg, textwidth))
2746 ui.write(minirst.format(msg, textwidth))
2757 ui.write('\n\n')
2747 ui.write('\n\n')
2758 ui.write(_('use "hg help extensions" for information on enabling '
2748 ui.write(_('use "hg help extensions" for information on enabling '
2759 'extensions\n'))
2749 'extensions\n'))
2760
2750
2761 if name and name != 'shortlist':
2751 if name and name != 'shortlist':
2762 i = None
2752 i = None
2763 if unknowncmd:
2753 if unknowncmd:
2764 queries = (helpextcmd,)
2754 queries = (helpextcmd,)
2765 elif opts.get('extension'):
2755 elif opts.get('extension'):
2766 queries = (helpext,)
2756 queries = (helpext,)
2767 elif opts.get('command'):
2757 elif opts.get('command'):
2768 queries = (helpcmd,)
2758 queries = (helpcmd,)
2769 else:
2759 else:
2770 queries = (helptopic, helpcmd, helpext, helpextcmd)
2760 queries = (helptopic, helpcmd, helpext, helpextcmd)
2771 for f in queries:
2761 for f in queries:
2772 try:
2762 try:
2773 f(name)
2763 f(name)
2774 i = None
2764 i = None
2775 break
2765 break
2776 except error.UnknownCommand, inst:
2766 except error.UnknownCommand, inst:
2777 i = inst
2767 i = inst
2778 if i:
2768 if i:
2779 raise i
2769 raise i
2780
2770
2781 else:
2771 else:
2782 # program name
2772 # program name
2783 if ui.verbose or with_version:
2773 if ui.verbose or with_version:
2784 version_(ui)
2774 version_(ui)
2785 else:
2775 else:
2786 ui.status(_("Mercurial Distributed SCM\n"))
2776 ui.status(_("Mercurial Distributed SCM\n"))
2787 ui.status('\n')
2777 ui.status('\n')
2788
2778
2789 # list of commands
2779 # list of commands
2790 if name == "shortlist":
2780 if name == "shortlist":
2791 header = _('basic commands:\n\n')
2781 header = _('basic commands:\n\n')
2792 else:
2782 else:
2793 header = _('list of commands:\n\n')
2783 header = _('list of commands:\n\n')
2794
2784
2795 helplist(header)
2785 helplist(header)
2796 if name != 'shortlist':
2786 if name != 'shortlist':
2797 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2787 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2798 if text:
2788 if text:
2799 ui.write("\n%s\n" % minirst.format(text, textwidth))
2789 ui.write("\n%s\n" % minirst.format(text, textwidth))
2800
2790
2801 # list all option lists
2791 # list all option lists
2802 opt_output = []
2792 opt_output = []
2803 multioccur = False
2793 multioccur = False
2804 for title, options in option_lists:
2794 for title, options in option_lists:
2805 opt_output.append(("\n%s" % title, None))
2795 opt_output.append(("\n%s" % title, None))
2806 for option in options:
2796 for option in options:
2807 if len(option) == 5:
2797 if len(option) == 5:
2808 shortopt, longopt, default, desc, optlabel = option
2798 shortopt, longopt, default, desc, optlabel = option
2809 else:
2799 else:
2810 shortopt, longopt, default, desc = option
2800 shortopt, longopt, default, desc = option
2811 optlabel = _("VALUE") # default label
2801 optlabel = _("VALUE") # default label
2812
2802
2813 if _("DEPRECATED") in desc and not ui.verbose:
2803 if _("DEPRECATED") in desc and not ui.verbose:
2814 continue
2804 continue
2815 if isinstance(default, list):
2805 if isinstance(default, list):
2816 numqualifier = " %s [+]" % optlabel
2806 numqualifier = " %s [+]" % optlabel
2817 multioccur = True
2807 multioccur = True
2818 elif (default is not None) and not isinstance(default, bool):
2808 elif (default is not None) and not isinstance(default, bool):
2819 numqualifier = " %s" % optlabel
2809 numqualifier = " %s" % optlabel
2820 else:
2810 else:
2821 numqualifier = ""
2811 numqualifier = ""
2822 opt_output.append(("%2s%s" %
2812 opt_output.append(("%2s%s" %
2823 (shortopt and "-%s" % shortopt,
2813 (shortopt and "-%s" % shortopt,
2824 longopt and " --%s%s" %
2814 longopt and " --%s%s" %
2825 (longopt, numqualifier)),
2815 (longopt, numqualifier)),
2826 "%s%s" % (desc,
2816 "%s%s" % (desc,
2827 default
2817 default
2828 and _(" (default: %s)") % default
2818 and _(" (default: %s)") % default
2829 or "")))
2819 or "")))
2830 if multioccur:
2820 if multioccur:
2831 msg = _("\n[+] marked option can be specified multiple times")
2821 msg = _("\n[+] marked option can be specified multiple times")
2832 if ui.verbose and name != 'shortlist':
2822 if ui.verbose and name != 'shortlist':
2833 opt_output.append((msg, None))
2823 opt_output.append((msg, None))
2834 else:
2824 else:
2835 opt_output.insert(-1, (msg, None))
2825 opt_output.insert(-1, (msg, None))
2836
2826
2837 if not name:
2827 if not name:
2838 ui.write(_("\nadditional help topics:\n\n"))
2828 ui.write(_("\nadditional help topics:\n\n"))
2839 topics = []
2829 topics = []
2840 for names, header, doc in help.helptable:
2830 for names, header, doc in help.helptable:
2841 topics.append((sorted(names, key=len, reverse=True)[0], header))
2831 topics.append((sorted(names, key=len, reverse=True)[0], header))
2842 topics_len = max([len(s[0]) for s in topics])
2832 topics_len = max([len(s[0]) for s in topics])
2843 for t, desc in topics:
2833 for t, desc in topics:
2844 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2834 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2845
2835
2846 if opt_output:
2836 if opt_output:
2847 colwidth = encoding.colwidth
2837 colwidth = encoding.colwidth
2848 # normalize: (opt or message, desc or None, width of opt)
2838 # normalize: (opt or message, desc or None, width of opt)
2849 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2839 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2850 for opt, desc in opt_output]
2840 for opt, desc in opt_output]
2851 hanging = max([e[2] for e in entries])
2841 hanging = max([e[2] for e in entries])
2852 for opt, desc, width in entries:
2842 for opt, desc, width in entries:
2853 if desc:
2843 if desc:
2854 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2844 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2855 hangindent = ' ' * (hanging + 3)
2845 hangindent = ' ' * (hanging + 3)
2856 ui.write('%s\n' % (util.wrap(desc, textwidth,
2846 ui.write('%s\n' % (util.wrap(desc, textwidth,
2857 initindent=initindent,
2847 initindent=initindent,
2858 hangindent=hangindent)))
2848 hangindent=hangindent)))
2859 else:
2849 else:
2860 ui.write("%s\n" % opt)
2850 ui.write("%s\n" % opt)
2861
2851
2862 @command('identify|id',
2852 @command('identify|id',
2863 [('r', 'rev', '',
2853 [('r', 'rev', '',
2864 _('identify the specified revision'), _('REV')),
2854 _('identify the specified revision'), _('REV')),
2865 ('n', 'num', None, _('show local revision number')),
2855 ('n', 'num', None, _('show local revision number')),
2866 ('i', 'id', None, _('show global revision id')),
2856 ('i', 'id', None, _('show global revision id')),
2867 ('b', 'branch', None, _('show branch')),
2857 ('b', 'branch', None, _('show branch')),
2868 ('t', 'tags', None, _('show tags')),
2858 ('t', 'tags', None, _('show tags')),
2869 ('B', 'bookmarks', None, _('show bookmarks'))],
2859 ('B', 'bookmarks', None, _('show bookmarks'))],
2870 _('[-nibtB] [-r REV] [SOURCE]'))
2860 _('[-nibtB] [-r REV] [SOURCE]'))
2871 def identify(ui, repo, source=None, rev=None,
2861 def identify(ui, repo, source=None, rev=None,
2872 num=None, id=None, branch=None, tags=None, bookmarks=None):
2862 num=None, id=None, branch=None, tags=None, bookmarks=None):
2873 """identify the working copy or specified revision
2863 """identify the working copy or specified revision
2874
2864
2875 Print a summary identifying the repository state at REV using one or
2865 Print a summary identifying the repository state at REV using one or
2876 two parent hash identifiers, followed by a "+" if the working
2866 two parent hash identifiers, followed by a "+" if the working
2877 directory has uncommitted changes, the branch name (if not default),
2867 directory has uncommitted changes, the branch name (if not default),
2878 a list of tags, and a list of bookmarks.
2868 a list of tags, and a list of bookmarks.
2879
2869
2880 When REV is not given, print a summary of the current state of the
2870 When REV is not given, print a summary of the current state of the
2881 repository.
2871 repository.
2882
2872
2883 Specifying a path to a repository root or Mercurial bundle will
2873 Specifying a path to a repository root or Mercurial bundle will
2884 cause lookup to operate on that repository/bundle.
2874 cause lookup to operate on that repository/bundle.
2885
2875
2886 Returns 0 if successful.
2876 Returns 0 if successful.
2887 """
2877 """
2888
2878
2889 if not repo and not source:
2879 if not repo and not source:
2890 raise util.Abort(_("there is no Mercurial repository here "
2880 raise util.Abort(_("there is no Mercurial repository here "
2891 "(.hg not found)"))
2881 "(.hg not found)"))
2892
2882
2893 hexfunc = ui.debugflag and hex or short
2883 hexfunc = ui.debugflag and hex or short
2894 default = not (num or id or branch or tags or bookmarks)
2884 default = not (num or id or branch or tags or bookmarks)
2895 output = []
2885 output = []
2896 revs = []
2886 revs = []
2897
2887
2898 if source:
2888 if source:
2899 source, branches = hg.parseurl(ui.expandpath(source))
2889 source, branches = hg.parseurl(ui.expandpath(source))
2900 repo = hg.repository(ui, source)
2890 repo = hg.repository(ui, source)
2901 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2891 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2902
2892
2903 if not repo.local():
2893 if not repo.local():
2904 if num or branch or tags:
2894 if num or branch or tags:
2905 raise util.Abort(
2895 raise util.Abort(
2906 _("can't query remote revision number, branch, or tags"))
2896 _("can't query remote revision number, branch, or tags"))
2907 if not rev and revs:
2897 if not rev and revs:
2908 rev = revs[0]
2898 rev = revs[0]
2909 if not rev:
2899 if not rev:
2910 rev = "tip"
2900 rev = "tip"
2911
2901
2912 remoterev = repo.lookup(rev)
2902 remoterev = repo.lookup(rev)
2913 if default or id:
2903 if default or id:
2914 output = [hexfunc(remoterev)]
2904 output = [hexfunc(remoterev)]
2915
2905
2916 def getbms():
2906 def getbms():
2917 bms = []
2907 bms = []
2918
2908
2919 if 'bookmarks' in repo.listkeys('namespaces'):
2909 if 'bookmarks' in repo.listkeys('namespaces'):
2920 hexremoterev = hex(remoterev)
2910 hexremoterev = hex(remoterev)
2921 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2911 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2922 if bmr == hexremoterev]
2912 if bmr == hexremoterev]
2923
2913
2924 return bms
2914 return bms
2925
2915
2926 if bookmarks:
2916 if bookmarks:
2927 output.extend(getbms())
2917 output.extend(getbms())
2928 elif default and not ui.quiet:
2918 elif default and not ui.quiet:
2929 # multiple bookmarks for a single parent separated by '/'
2919 # multiple bookmarks for a single parent separated by '/'
2930 bm = '/'.join(getbms())
2920 bm = '/'.join(getbms())
2931 if bm:
2921 if bm:
2932 output.append(bm)
2922 output.append(bm)
2933 else:
2923 else:
2934 if not rev:
2924 if not rev:
2935 ctx = repo[None]
2925 ctx = repo[None]
2936 parents = ctx.parents()
2926 parents = ctx.parents()
2937 changed = ""
2927 changed = ""
2938 if default or id or num:
2928 if default or id or num:
2939 changed = util.any(repo.status()) and "+" or ""
2929 changed = util.any(repo.status()) and "+" or ""
2940 if default or id:
2930 if default or id:
2941 output = ["%s%s" %
2931 output = ["%s%s" %
2942 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2932 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2943 if num:
2933 if num:
2944 output.append("%s%s" %
2934 output.append("%s%s" %
2945 ('+'.join([str(p.rev()) for p in parents]), changed))
2935 ('+'.join([str(p.rev()) for p in parents]), changed))
2946 else:
2936 else:
2947 ctx = scmutil.revsingle(repo, rev)
2937 ctx = scmutil.revsingle(repo, rev)
2948 if default or id:
2938 if default or id:
2949 output = [hexfunc(ctx.node())]
2939 output = [hexfunc(ctx.node())]
2950 if num:
2940 if num:
2951 output.append(str(ctx.rev()))
2941 output.append(str(ctx.rev()))
2952
2942
2953 if default and not ui.quiet:
2943 if default and not ui.quiet:
2954 b = ctx.branch()
2944 b = ctx.branch()
2955 if b != 'default':
2945 if b != 'default':
2956 output.append("(%s)" % b)
2946 output.append("(%s)" % b)
2957
2947
2958 # multiple tags for a single parent separated by '/'
2948 # multiple tags for a single parent separated by '/'
2959 t = '/'.join(ctx.tags())
2949 t = '/'.join(ctx.tags())
2960 if t:
2950 if t:
2961 output.append(t)
2951 output.append(t)
2962
2952
2963 # multiple bookmarks for a single parent separated by '/'
2953 # multiple bookmarks for a single parent separated by '/'
2964 bm = '/'.join(ctx.bookmarks())
2954 bm = '/'.join(ctx.bookmarks())
2965 if bm:
2955 if bm:
2966 output.append(bm)
2956 output.append(bm)
2967 else:
2957 else:
2968 if branch:
2958 if branch:
2969 output.append(ctx.branch())
2959 output.append(ctx.branch())
2970
2960
2971 if tags:
2961 if tags:
2972 output.extend(ctx.tags())
2962 output.extend(ctx.tags())
2973
2963
2974 if bookmarks:
2964 if bookmarks:
2975 output.extend(ctx.bookmarks())
2965 output.extend(ctx.bookmarks())
2976
2966
2977 ui.write("%s\n" % ' '.join(output))
2967 ui.write("%s\n" % ' '.join(output))
2978
2968
2979 @command('import|patch',
2969 @command('import|patch',
2980 [('p', 'strip', 1,
2970 [('p', 'strip', 1,
2981 _('directory strip option for patch. This has the same '
2971 _('directory strip option for patch. This has the same '
2982 'meaning as the corresponding patch option'), _('NUM')),
2972 'meaning as the corresponding patch option'), _('NUM')),
2983 ('b', 'base', '', _('base path'), _('PATH')),
2973 ('b', 'base', '', _('base path'), _('PATH')),
2984 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
2974 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
2985 ('', 'no-commit', None,
2975 ('', 'no-commit', None,
2986 _("don't commit, just update the working directory")),
2976 _("don't commit, just update the working directory")),
2987 ('', 'exact', None,
2977 ('', 'exact', None,
2988 _('apply patch to the nodes from which it was generated')),
2978 _('apply patch to the nodes from which it was generated')),
2989 ('', 'import-branch', None,
2979 ('', 'import-branch', None,
2990 _('use any branch information in patch (implied by --exact)'))] +
2980 _('use any branch information in patch (implied by --exact)'))] +
2991 commitopts + commitopts2 + similarityopts,
2981 commitopts + commitopts2 + similarityopts,
2992 _('[OPTION]... PATCH...'))
2982 _('[OPTION]... PATCH...'))
2993 def import_(ui, repo, patch1, *patches, **opts):
2983 def import_(ui, repo, patch1, *patches, **opts):
2994 """import an ordered set of patches
2984 """import an ordered set of patches
2995
2985
2996 Import a list of patches and commit them individually (unless
2986 Import a list of patches and commit them individually (unless
2997 --no-commit is specified).
2987 --no-commit is specified).
2998
2988
2999 If there are outstanding changes in the working directory, import
2989 If there are outstanding changes in the working directory, import
3000 will abort unless given the -f/--force flag.
2990 will abort unless given the -f/--force flag.
3001
2991
3002 You can import a patch straight from a mail message. Even patches
2992 You can import a patch straight from a mail message. Even patches
3003 as attachments work (to use the body part, it must have type
2993 as attachments work (to use the body part, it must have type
3004 text/plain or text/x-patch). From and Subject headers of email
2994 text/plain or text/x-patch). From and Subject headers of email
3005 message are used as default committer and commit message. All
2995 message are used as default committer and commit message. All
3006 text/plain body parts before first diff are added to commit
2996 text/plain body parts before first diff are added to commit
3007 message.
2997 message.
3008
2998
3009 If the imported patch was generated by :hg:`export`, user and
2999 If the imported patch was generated by :hg:`export`, user and
3010 description from patch override values from message headers and
3000 description from patch override values from message headers and
3011 body. Values given on command line with -m/--message and -u/--user
3001 body. Values given on command line with -m/--message and -u/--user
3012 override these.
3002 override these.
3013
3003
3014 If --exact is specified, import will set the working directory to
3004 If --exact is specified, import will set the working directory to
3015 the parent of each patch before applying it, and will abort if the
3005 the parent of each patch before applying it, and will abort if the
3016 resulting changeset has a different ID than the one recorded in
3006 resulting changeset has a different ID than the one recorded in
3017 the patch. This may happen due to character set problems or other
3007 the patch. This may happen due to character set problems or other
3018 deficiencies in the text patch format.
3008 deficiencies in the text patch format.
3019
3009
3020 With -s/--similarity, hg will attempt to discover renames and
3010 With -s/--similarity, hg will attempt to discover renames and
3021 copies in the patch in the same way as 'addremove'.
3011 copies in the patch in the same way as 'addremove'.
3022
3012
3023 To read a patch from standard input, use "-" as the patch name. If
3013 To read a patch from standard input, use "-" as the patch name. If
3024 a URL is specified, the patch will be downloaded from it.
3014 a URL is specified, the patch will be downloaded from it.
3025 See :hg:`help dates` for a list of formats valid for -d/--date.
3015 See :hg:`help dates` for a list of formats valid for -d/--date.
3026
3016
3027 Returns 0 on success.
3017 Returns 0 on success.
3028 """
3018 """
3029 patches = (patch1,) + patches
3019 patches = (patch1,) + patches
3030
3020
3031 date = opts.get('date')
3021 date = opts.get('date')
3032 if date:
3022 if date:
3033 opts['date'] = util.parsedate(date)
3023 opts['date'] = util.parsedate(date)
3034
3024
3035 try:
3025 try:
3036 sim = float(opts.get('similarity') or 0)
3026 sim = float(opts.get('similarity') or 0)
3037 except ValueError:
3027 except ValueError:
3038 raise util.Abort(_('similarity must be a number'))
3028 raise util.Abort(_('similarity must be a number'))
3039 if sim < 0 or sim > 100:
3029 if sim < 0 or sim > 100:
3040 raise util.Abort(_('similarity must be between 0 and 100'))
3030 raise util.Abort(_('similarity must be between 0 and 100'))
3041
3031
3042 if opts.get('exact') or not opts.get('force'):
3032 if opts.get('exact') or not opts.get('force'):
3043 cmdutil.bailifchanged(repo)
3033 cmdutil.bailifchanged(repo)
3044
3034
3045 d = opts["base"]
3035 d = opts["base"]
3046 strip = opts["strip"]
3036 strip = opts["strip"]
3047 wlock = lock = None
3037 wlock = lock = None
3048 msgs = []
3038 msgs = []
3049
3039
3050 def tryone(ui, hunk):
3040 def tryone(ui, hunk):
3051 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3041 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3052 patch.extract(ui, hunk)
3042 patch.extract(ui, hunk)
3053
3043
3054 if not tmpname:
3044 if not tmpname:
3055 return None
3045 return None
3056 commitid = _('to working directory')
3046 commitid = _('to working directory')
3057
3047
3058 try:
3048 try:
3059 cmdline_message = cmdutil.logmessage(opts)
3049 cmdline_message = cmdutil.logmessage(opts)
3060 if cmdline_message:
3050 if cmdline_message:
3061 # pickup the cmdline msg
3051 # pickup the cmdline msg
3062 message = cmdline_message
3052 message = cmdline_message
3063 elif message:
3053 elif message:
3064 # pickup the patch msg
3054 # pickup the patch msg
3065 message = message.strip()
3055 message = message.strip()
3066 else:
3056 else:
3067 # launch the editor
3057 # launch the editor
3068 message = None
3058 message = None
3069 ui.debug('message:\n%s\n' % message)
3059 ui.debug('message:\n%s\n' % message)
3070
3060
3071 wp = repo.parents()
3061 wp = repo.parents()
3072 if opts.get('exact'):
3062 if opts.get('exact'):
3073 if not nodeid or not p1:
3063 if not nodeid or not p1:
3074 raise util.Abort(_('not a Mercurial patch'))
3064 raise util.Abort(_('not a Mercurial patch'))
3075 p1 = repo.lookup(p1)
3065 p1 = repo.lookup(p1)
3076 p2 = repo.lookup(p2 or hex(nullid))
3066 p2 = repo.lookup(p2 or hex(nullid))
3077
3067
3078 if p1 != wp[0].node():
3068 if p1 != wp[0].node():
3079 hg.clean(repo, p1)
3069 hg.clean(repo, p1)
3080 repo.dirstate.setparents(p1, p2)
3070 repo.dirstate.setparents(p1, p2)
3081 elif p2:
3071 elif p2:
3082 try:
3072 try:
3083 p1 = repo.lookup(p1)
3073 p1 = repo.lookup(p1)
3084 p2 = repo.lookup(p2)
3074 p2 = repo.lookup(p2)
3085 if p1 == wp[0].node():
3075 if p1 == wp[0].node():
3086 repo.dirstate.setparents(p1, p2)
3076 repo.dirstate.setparents(p1, p2)
3087 except error.RepoError:
3077 except error.RepoError:
3088 pass
3078 pass
3089 if opts.get('exact') or opts.get('import_branch'):
3079 if opts.get('exact') or opts.get('import_branch'):
3090 repo.dirstate.setbranch(branch or 'default')
3080 repo.dirstate.setbranch(branch or 'default')
3091
3081
3092 files = {}
3082 files = {}
3093 patch.patch(ui, repo, tmpname, strip=strip, cwd=repo.root,
3083 patch.patch(ui, repo, tmpname, strip=strip, cwd=repo.root,
3094 files=files, eolmode=None, similarity=sim / 100.0)
3084 files=files, eolmode=None, similarity=sim / 100.0)
3095 files = list(files)
3085 files = list(files)
3096 if opts.get('no_commit'):
3086 if opts.get('no_commit'):
3097 if message:
3087 if message:
3098 msgs.append(message)
3088 msgs.append(message)
3099 else:
3089 else:
3100 if opts.get('exact'):
3090 if opts.get('exact'):
3101 m = None
3091 m = None
3102 else:
3092 else:
3103 m = scmutil.matchfiles(repo, files or [])
3093 m = scmutil.matchfiles(repo, files or [])
3104 n = repo.commit(message, opts.get('user') or user,
3094 n = repo.commit(message, opts.get('user') or user,
3105 opts.get('date') or date, match=m,
3095 opts.get('date') or date, match=m,
3106 editor=cmdutil.commiteditor)
3096 editor=cmdutil.commiteditor)
3107 if opts.get('exact'):
3097 if opts.get('exact'):
3108 if hex(n) != nodeid:
3098 if hex(n) != nodeid:
3109 repo.rollback()
3099 repo.rollback()
3110 raise util.Abort(_('patch is damaged'
3100 raise util.Abort(_('patch is damaged'
3111 ' or loses information'))
3101 ' or loses information'))
3112 # Force a dirstate write so that the next transaction
3102 # Force a dirstate write so that the next transaction
3113 # backups an up-do-date file.
3103 # backups an up-do-date file.
3114 repo.dirstate.write()
3104 repo.dirstate.write()
3115 if n:
3105 if n:
3116 commitid = short(n)
3106 commitid = short(n)
3117
3107
3118 return commitid
3108 return commitid
3119 finally:
3109 finally:
3120 os.unlink(tmpname)
3110 os.unlink(tmpname)
3121
3111
3122 try:
3112 try:
3123 wlock = repo.wlock()
3113 wlock = repo.wlock()
3124 lock = repo.lock()
3114 lock = repo.lock()
3125 lastcommit = None
3115 lastcommit = None
3126 for p in patches:
3116 for p in patches:
3127 pf = os.path.join(d, p)
3117 pf = os.path.join(d, p)
3128
3118
3129 if pf == '-':
3119 if pf == '-':
3130 ui.status(_("applying patch from stdin\n"))
3120 ui.status(_("applying patch from stdin\n"))
3131 pf = sys.stdin
3121 pf = sys.stdin
3132 else:
3122 else:
3133 ui.status(_("applying %s\n") % p)
3123 ui.status(_("applying %s\n") % p)
3134 pf = url.open(ui, pf)
3124 pf = url.open(ui, pf)
3135
3125
3136 haspatch = False
3126 haspatch = False
3137 for hunk in patch.split(pf):
3127 for hunk in patch.split(pf):
3138 commitid = tryone(ui, hunk)
3128 commitid = tryone(ui, hunk)
3139 if commitid:
3129 if commitid:
3140 haspatch = True
3130 haspatch = True
3141 if lastcommit:
3131 if lastcommit:
3142 ui.status(_('applied %s\n') % lastcommit)
3132 ui.status(_('applied %s\n') % lastcommit)
3143 lastcommit = commitid
3133 lastcommit = commitid
3144
3134
3145 if not haspatch:
3135 if not haspatch:
3146 raise util.Abort(_('no diffs found'))
3136 raise util.Abort(_('no diffs found'))
3147
3137
3148 if msgs:
3138 if msgs:
3149 repo.opener.write('last-message.txt', '\n* * *\n'.join(msgs))
3139 repo.opener.write('last-message.txt', '\n* * *\n'.join(msgs))
3150 finally:
3140 finally:
3151 release(lock, wlock)
3141 release(lock, wlock)
3152
3142
3153 @command('incoming|in',
3143 @command('incoming|in',
3154 [('f', 'force', None,
3144 [('f', 'force', None,
3155 _('run even if remote repository is unrelated')),
3145 _('run even if remote repository is unrelated')),
3156 ('n', 'newest-first', None, _('show newest record first')),
3146 ('n', 'newest-first', None, _('show newest record first')),
3157 ('', 'bundle', '',
3147 ('', 'bundle', '',
3158 _('file to store the bundles into'), _('FILE')),
3148 _('file to store the bundles into'), _('FILE')),
3159 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3149 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3160 ('B', 'bookmarks', False, _("compare bookmarks")),
3150 ('B', 'bookmarks', False, _("compare bookmarks")),
3161 ('b', 'branch', [],
3151 ('b', 'branch', [],
3162 _('a specific branch you would like to pull'), _('BRANCH')),
3152 _('a specific branch you would like to pull'), _('BRANCH')),
3163 ] + logopts + remoteopts + subrepoopts,
3153 ] + logopts + remoteopts + subrepoopts,
3164 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3154 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3165 def incoming(ui, repo, source="default", **opts):
3155 def incoming(ui, repo, source="default", **opts):
3166 """show new changesets found in source
3156 """show new changesets found in source
3167
3157
3168 Show new changesets found in the specified path/URL or the default
3158 Show new changesets found in the specified path/URL or the default
3169 pull location. These are the changesets that would have been pulled
3159 pull location. These are the changesets that would have been pulled
3170 if a pull at the time you issued this command.
3160 if a pull at the time you issued this command.
3171
3161
3172 For remote repository, using --bundle avoids downloading the
3162 For remote repository, using --bundle avoids downloading the
3173 changesets twice if the incoming is followed by a pull.
3163 changesets twice if the incoming is followed by a pull.
3174
3164
3175 See pull for valid source format details.
3165 See pull for valid source format details.
3176
3166
3177 Returns 0 if there are incoming changes, 1 otherwise.
3167 Returns 0 if there are incoming changes, 1 otherwise.
3178 """
3168 """
3179 if opts.get('bundle') and opts.get('subrepos'):
3169 if opts.get('bundle') and opts.get('subrepos'):
3180 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3170 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3181
3171
3182 if opts.get('bookmarks'):
3172 if opts.get('bookmarks'):
3183 source, branches = hg.parseurl(ui.expandpath(source),
3173 source, branches = hg.parseurl(ui.expandpath(source),
3184 opts.get('branch'))
3174 opts.get('branch'))
3185 other = hg.repository(hg.remoteui(repo, opts), source)
3175 other = hg.repository(hg.remoteui(repo, opts), source)
3186 if 'bookmarks' not in other.listkeys('namespaces'):
3176 if 'bookmarks' not in other.listkeys('namespaces'):
3187 ui.warn(_("remote doesn't support bookmarks\n"))
3177 ui.warn(_("remote doesn't support bookmarks\n"))
3188 return 0
3178 return 0
3189 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3179 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3190 return bookmarks.diff(ui, repo, other)
3180 return bookmarks.diff(ui, repo, other)
3191
3181
3192 ret = hg.incoming(ui, repo, source, opts)
3182 ret = hg.incoming(ui, repo, source, opts)
3193 return ret
3183 return ret
3194
3184
3195 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3185 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3196 def init(ui, dest=".", **opts):
3186 def init(ui, dest=".", **opts):
3197 """create a new repository in the given directory
3187 """create a new repository in the given directory
3198
3188
3199 Initialize a new repository in the given directory. If the given
3189 Initialize a new repository in the given directory. If the given
3200 directory does not exist, it will be created.
3190 directory does not exist, it will be created.
3201
3191
3202 If no directory is given, the current directory is used.
3192 If no directory is given, the current directory is used.
3203
3193
3204 It is possible to specify an ``ssh://`` URL as the destination.
3194 It is possible to specify an ``ssh://`` URL as the destination.
3205 See :hg:`help urls` for more information.
3195 See :hg:`help urls` for more information.
3206
3196
3207 Returns 0 on success.
3197 Returns 0 on success.
3208 """
3198 """
3209 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
3199 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
3210
3200
3211 @command('locate',
3201 @command('locate',
3212 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3202 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3213 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3203 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3214 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3204 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3215 ] + walkopts,
3205 ] + walkopts,
3216 _('[OPTION]... [PATTERN]...'))
3206 _('[OPTION]... [PATTERN]...'))
3217 def locate(ui, repo, *pats, **opts):
3207 def locate(ui, repo, *pats, **opts):
3218 """locate files matching specific patterns
3208 """locate files matching specific patterns
3219
3209
3220 Print files under Mercurial control in the working directory whose
3210 Print files under Mercurial control in the working directory whose
3221 names match the given patterns.
3211 names match the given patterns.
3222
3212
3223 By default, this command searches all directories in the working
3213 By default, this command searches all directories in the working
3224 directory. To search just the current directory and its
3214 directory. To search just the current directory and its
3225 subdirectories, use "--include .".
3215 subdirectories, use "--include .".
3226
3216
3227 If no patterns are given to match, this command prints the names
3217 If no patterns are given to match, this command prints the names
3228 of all files under Mercurial control in the working directory.
3218 of all files under Mercurial control in the working directory.
3229
3219
3230 If you want to feed the output of this command into the "xargs"
3220 If you want to feed the output of this command into the "xargs"
3231 command, use the -0 option to both this command and "xargs". This
3221 command, use the -0 option to both this command and "xargs". This
3232 will avoid the problem of "xargs" treating single filenames that
3222 will avoid the problem of "xargs" treating single filenames that
3233 contain whitespace as multiple filenames.
3223 contain whitespace as multiple filenames.
3234
3224
3235 Returns 0 if a match is found, 1 otherwise.
3225 Returns 0 if a match is found, 1 otherwise.
3236 """
3226 """
3237 end = opts.get('print0') and '\0' or '\n'
3227 end = opts.get('print0') and '\0' or '\n'
3238 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3228 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3239
3229
3240 ret = 1
3230 ret = 1
3241 m = scmutil.match(repo, pats, opts, default='relglob')
3231 m = scmutil.match(repo, pats, opts, default='relglob')
3242 m.bad = lambda x, y: False
3232 m.bad = lambda x, y: False
3243 for abs in repo[rev].walk(m):
3233 for abs in repo[rev].walk(m):
3244 if not rev and abs not in repo.dirstate:
3234 if not rev and abs not in repo.dirstate:
3245 continue
3235 continue
3246 if opts.get('fullpath'):
3236 if opts.get('fullpath'):
3247 ui.write(repo.wjoin(abs), end)
3237 ui.write(repo.wjoin(abs), end)
3248 else:
3238 else:
3249 ui.write(((pats and m.rel(abs)) or abs), end)
3239 ui.write(((pats and m.rel(abs)) or abs), end)
3250 ret = 0
3240 ret = 0
3251
3241
3252 return ret
3242 return ret
3253
3243
3254 @command('^log|history',
3244 @command('^log|history',
3255 [('f', 'follow', None,
3245 [('f', 'follow', None,
3256 _('follow changeset history, or file history across copies and renames')),
3246 _('follow changeset history, or file history across copies and renames')),
3257 ('', 'follow-first', None,
3247 ('', 'follow-first', None,
3258 _('only follow the first parent of merge changesets')),
3248 _('only follow the first parent of merge changesets')),
3259 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3249 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3260 ('C', 'copies', None, _('show copied files')),
3250 ('C', 'copies', None, _('show copied files')),
3261 ('k', 'keyword', [],
3251 ('k', 'keyword', [],
3262 _('do case-insensitive search for a given text'), _('TEXT')),
3252 _('do case-insensitive search for a given text'), _('TEXT')),
3263 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3253 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3264 ('', 'removed', None, _('include revisions where files were removed')),
3254 ('', 'removed', None, _('include revisions where files were removed')),
3265 ('m', 'only-merges', None, _('show only merges')),
3255 ('m', 'only-merges', None, _('show only merges')),
3266 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3256 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3267 ('', 'only-branch', [],
3257 ('', 'only-branch', [],
3268 _('show only changesets within the given named branch (DEPRECATED)'),
3258 _('show only changesets within the given named branch (DEPRECATED)'),
3269 _('BRANCH')),
3259 _('BRANCH')),
3270 ('b', 'branch', [],
3260 ('b', 'branch', [],
3271 _('show changesets within the given named branch'), _('BRANCH')),
3261 _('show changesets within the given named branch'), _('BRANCH')),
3272 ('P', 'prune', [],
3262 ('P', 'prune', [],
3273 _('do not display revision or any of its ancestors'), _('REV')),
3263 _('do not display revision or any of its ancestors'), _('REV')),
3274 ] + logopts + walkopts,
3264 ] + logopts + walkopts,
3275 _('[OPTION]... [FILE]'))
3265 _('[OPTION]... [FILE]'))
3276 def log(ui, repo, *pats, **opts):
3266 def log(ui, repo, *pats, **opts):
3277 """show revision history of entire repository or files
3267 """show revision history of entire repository or files
3278
3268
3279 Print the revision history of the specified files or the entire
3269 Print the revision history of the specified files or the entire
3280 project.
3270 project.
3281
3271
3282 File history is shown without following rename or copy history of
3272 File history is shown without following rename or copy history of
3283 files. Use -f/--follow with a filename to follow history across
3273 files. Use -f/--follow with a filename to follow history across
3284 renames and copies. --follow without a filename will only show
3274 renames and copies. --follow without a filename will only show
3285 ancestors or descendants of the starting revision. --follow-first
3275 ancestors or descendants of the starting revision. --follow-first
3286 only follows the first parent of merge revisions.
3276 only follows the first parent of merge revisions.
3287
3277
3288 If no revision range is specified, the default is ``tip:0`` unless
3278 If no revision range is specified, the default is ``tip:0`` unless
3289 --follow is set, in which case the working directory parent is
3279 --follow is set, in which case the working directory parent is
3290 used as the starting revision. You can specify a revision set for
3280 used as the starting revision. You can specify a revision set for
3291 log, see :hg:`help revsets` for more information.
3281 log, see :hg:`help revsets` for more information.
3292
3282
3293 See :hg:`help dates` for a list of formats valid for -d/--date.
3283 See :hg:`help dates` for a list of formats valid for -d/--date.
3294
3284
3295 By default this command prints revision number and changeset id,
3285 By default this command prints revision number and changeset id,
3296 tags, non-trivial parents, user, date and time, and a summary for
3286 tags, non-trivial parents, user, date and time, and a summary for
3297 each commit. When the -v/--verbose switch is used, the list of
3287 each commit. When the -v/--verbose switch is used, the list of
3298 changed files and full commit message are shown.
3288 changed files and full commit message are shown.
3299
3289
3300 .. note::
3290 .. note::
3301 log -p/--patch may generate unexpected diff output for merge
3291 log -p/--patch may generate unexpected diff output for merge
3302 changesets, as it will only compare the merge changeset against
3292 changesets, as it will only compare the merge changeset against
3303 its first parent. Also, only files different from BOTH parents
3293 its first parent. Also, only files different from BOTH parents
3304 will appear in files:.
3294 will appear in files:.
3305
3295
3306 Returns 0 on success.
3296 Returns 0 on success.
3307 """
3297 """
3308
3298
3309 matchfn = scmutil.match(repo, pats, opts)
3299 matchfn = scmutil.match(repo, pats, opts)
3310 limit = cmdutil.loglimit(opts)
3300 limit = cmdutil.loglimit(opts)
3311 count = 0
3301 count = 0
3312
3302
3313 endrev = None
3303 endrev = None
3314 if opts.get('copies') and opts.get('rev'):
3304 if opts.get('copies') and opts.get('rev'):
3315 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3305 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3316
3306
3317 df = False
3307 df = False
3318 if opts["date"]:
3308 if opts["date"]:
3319 df = util.matchdate(opts["date"])
3309 df = util.matchdate(opts["date"])
3320
3310
3321 branches = opts.get('branch', []) + opts.get('only_branch', [])
3311 branches = opts.get('branch', []) + opts.get('only_branch', [])
3322 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3312 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3323
3313
3324 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3314 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3325 def prep(ctx, fns):
3315 def prep(ctx, fns):
3326 rev = ctx.rev()
3316 rev = ctx.rev()
3327 parents = [p for p in repo.changelog.parentrevs(rev)
3317 parents = [p for p in repo.changelog.parentrevs(rev)
3328 if p != nullrev]
3318 if p != nullrev]
3329 if opts.get('no_merges') and len(parents) == 2:
3319 if opts.get('no_merges') and len(parents) == 2:
3330 return
3320 return
3331 if opts.get('only_merges') and len(parents) != 2:
3321 if opts.get('only_merges') and len(parents) != 2:
3332 return
3322 return
3333 if opts.get('branch') and ctx.branch() not in opts['branch']:
3323 if opts.get('branch') and ctx.branch() not in opts['branch']:
3334 return
3324 return
3335 if df and not df(ctx.date()[0]):
3325 if df and not df(ctx.date()[0]):
3336 return
3326 return
3337 if opts['user'] and not [k for k in opts['user']
3327 if opts['user'] and not [k for k in opts['user']
3338 if k.lower() in ctx.user().lower()]:
3328 if k.lower() in ctx.user().lower()]:
3339 return
3329 return
3340 if opts.get('keyword'):
3330 if opts.get('keyword'):
3341 for k in [kw.lower() for kw in opts['keyword']]:
3331 for k in [kw.lower() for kw in opts['keyword']]:
3342 if (k in ctx.user().lower() or
3332 if (k in ctx.user().lower() or
3343 k in ctx.description().lower() or
3333 k in ctx.description().lower() or
3344 k in " ".join(ctx.files()).lower()):
3334 k in " ".join(ctx.files()).lower()):
3345 break
3335 break
3346 else:
3336 else:
3347 return
3337 return
3348
3338
3349 copies = None
3339 copies = None
3350 if opts.get('copies') and rev:
3340 if opts.get('copies') and rev:
3351 copies = []
3341 copies = []
3352 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3342 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3353 for fn in ctx.files():
3343 for fn in ctx.files():
3354 rename = getrenamed(fn, rev)
3344 rename = getrenamed(fn, rev)
3355 if rename:
3345 if rename:
3356 copies.append((fn, rename[0]))
3346 copies.append((fn, rename[0]))
3357
3347
3358 revmatchfn = None
3348 revmatchfn = None
3359 if opts.get('patch') or opts.get('stat'):
3349 if opts.get('patch') or opts.get('stat'):
3360 if opts.get('follow') or opts.get('follow_first'):
3350 if opts.get('follow') or opts.get('follow_first'):
3361 # note: this might be wrong when following through merges
3351 # note: this might be wrong when following through merges
3362 revmatchfn = scmutil.match(repo, fns, default='path')
3352 revmatchfn = scmutil.match(repo, fns, default='path')
3363 else:
3353 else:
3364 revmatchfn = matchfn
3354 revmatchfn = matchfn
3365
3355
3366 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3356 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3367
3357
3368 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3358 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3369 if count == limit:
3359 if count == limit:
3370 break
3360 break
3371 if displayer.flush(ctx.rev()):
3361 if displayer.flush(ctx.rev()):
3372 count += 1
3362 count += 1
3373 displayer.close()
3363 displayer.close()
3374
3364
3375 @command('manifest',
3365 @command('manifest',
3376 [('r', 'rev', '', _('revision to display'), _('REV'))],
3366 [('r', 'rev', '', _('revision to display'), _('REV'))],
3377 _('[-r REV]'))
3367 _('[-r REV]'))
3378 def manifest(ui, repo, node=None, rev=None):
3368 def manifest(ui, repo, node=None, rev=None):
3379 """output the current or given revision of the project manifest
3369 """output the current or given revision of the project manifest
3380
3370
3381 Print a list of version controlled files for the given revision.
3371 Print a list of version controlled files for the given revision.
3382 If no revision is given, the first parent of the working directory
3372 If no revision is given, the first parent of the working directory
3383 is used, or the null revision if no revision is checked out.
3373 is used, or the null revision if no revision is checked out.
3384
3374
3385 With -v, print file permissions, symlink and executable bits.
3375 With -v, print file permissions, symlink and executable bits.
3386 With --debug, print file revision hashes.
3376 With --debug, print file revision hashes.
3387
3377
3388 Returns 0 on success.
3378 Returns 0 on success.
3389 """
3379 """
3390
3380
3391 if rev and node:
3381 if rev and node:
3392 raise util.Abort(_("please specify just one revision"))
3382 raise util.Abort(_("please specify just one revision"))
3393
3383
3394 if not node:
3384 if not node:
3395 node = rev
3385 node = rev
3396
3386
3397 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3387 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3398 ctx = scmutil.revsingle(repo, node)
3388 ctx = scmutil.revsingle(repo, node)
3399 for f in ctx:
3389 for f in ctx:
3400 if ui.debugflag:
3390 if ui.debugflag:
3401 ui.write("%40s " % hex(ctx.manifest()[f]))
3391 ui.write("%40s " % hex(ctx.manifest()[f]))
3402 if ui.verbose:
3392 if ui.verbose:
3403 ui.write(decor[ctx.flags(f)])
3393 ui.write(decor[ctx.flags(f)])
3404 ui.write("%s\n" % f)
3394 ui.write("%s\n" % f)
3405
3395
3406 @command('^merge',
3396 @command('^merge',
3407 [('f', 'force', None, _('force a merge with outstanding changes')),
3397 [('f', 'force', None, _('force a merge with outstanding changes')),
3408 ('t', 'tool', '', _('specify merge tool')),
3398 ('t', 'tool', '', _('specify merge tool')),
3409 ('r', 'rev', '', _('revision to merge'), _('REV')),
3399 ('r', 'rev', '', _('revision to merge'), _('REV')),
3410 ('P', 'preview', None,
3400 ('P', 'preview', None,
3411 _('review revisions to merge (no merge is performed)'))],
3401 _('review revisions to merge (no merge is performed)'))],
3412 _('[-P] [-f] [[-r] REV]'))
3402 _('[-P] [-f] [[-r] REV]'))
3413 def merge(ui, repo, node=None, **opts):
3403 def merge(ui, repo, node=None, **opts):
3414 """merge working directory with another revision
3404 """merge working directory with another revision
3415
3405
3416 The current working directory is updated with all changes made in
3406 The current working directory is updated with all changes made in
3417 the requested revision since the last common predecessor revision.
3407 the requested revision since the last common predecessor revision.
3418
3408
3419 Files that changed between either parent are marked as changed for
3409 Files that changed between either parent are marked as changed for
3420 the next commit and a commit must be performed before any further
3410 the next commit and a commit must be performed before any further
3421 updates to the repository are allowed. The next commit will have
3411 updates to the repository are allowed. The next commit will have
3422 two parents.
3412 two parents.
3423
3413
3424 ``--tool`` can be used to specify the merge tool used for file
3414 ``--tool`` can be used to specify the merge tool used for file
3425 merges. It overrides the HGMERGE environment variable and your
3415 merges. It overrides the HGMERGE environment variable and your
3426 configuration files. See :hg:`help merge-tools` for options.
3416 configuration files. See :hg:`help merge-tools` for options.
3427
3417
3428 If no revision is specified, the working directory's parent is a
3418 If no revision is specified, the working directory's parent is a
3429 head revision, and the current branch contains exactly one other
3419 head revision, and the current branch contains exactly one other
3430 head, the other head is merged with by default. Otherwise, an
3420 head, the other head is merged with by default. Otherwise, an
3431 explicit revision with which to merge with must be provided.
3421 explicit revision with which to merge with must be provided.
3432
3422
3433 :hg:`resolve` must be used to resolve unresolved files.
3423 :hg:`resolve` must be used to resolve unresolved files.
3434
3424
3435 To undo an uncommitted merge, use :hg:`update --clean .` which
3425 To undo an uncommitted merge, use :hg:`update --clean .` which
3436 will check out a clean copy of the original merge parent, losing
3426 will check out a clean copy of the original merge parent, losing
3437 all changes.
3427 all changes.
3438
3428
3439 Returns 0 on success, 1 if there are unresolved files.
3429 Returns 0 on success, 1 if there are unresolved files.
3440 """
3430 """
3441
3431
3442 if opts.get('rev') and node:
3432 if opts.get('rev') and node:
3443 raise util.Abort(_("please specify just one revision"))
3433 raise util.Abort(_("please specify just one revision"))
3444 if not node:
3434 if not node:
3445 node = opts.get('rev')
3435 node = opts.get('rev')
3446
3436
3447 if not node:
3437 if not node:
3448 branch = repo[None].branch()
3438 branch = repo[None].branch()
3449 bheads = repo.branchheads(branch)
3439 bheads = repo.branchheads(branch)
3450 if len(bheads) > 2:
3440 if len(bheads) > 2:
3451 raise util.Abort(_("branch '%s' has %d heads - "
3441 raise util.Abort(_("branch '%s' has %d heads - "
3452 "please merge with an explicit rev")
3442 "please merge with an explicit rev")
3453 % (branch, len(bheads)),
3443 % (branch, len(bheads)),
3454 hint=_("run 'hg heads .' to see heads"))
3444 hint=_("run 'hg heads .' to see heads"))
3455
3445
3456 parent = repo.dirstate.p1()
3446 parent = repo.dirstate.p1()
3457 if len(bheads) == 1:
3447 if len(bheads) == 1:
3458 if len(repo.heads()) > 1:
3448 if len(repo.heads()) > 1:
3459 raise util.Abort(_("branch '%s' has one head - "
3449 raise util.Abort(_("branch '%s' has one head - "
3460 "please merge with an explicit rev")
3450 "please merge with an explicit rev")
3461 % branch,
3451 % branch,
3462 hint=_("run 'hg heads' to see all heads"))
3452 hint=_("run 'hg heads' to see all heads"))
3463 msg = _('there is nothing to merge')
3453 msg = _('there is nothing to merge')
3464 if parent != repo.lookup(repo[None].branch()):
3454 if parent != repo.lookup(repo[None].branch()):
3465 msg = _('%s - use "hg update" instead') % msg
3455 msg = _('%s - use "hg update" instead') % msg
3466 raise util.Abort(msg)
3456 raise util.Abort(msg)
3467
3457
3468 if parent not in bheads:
3458 if parent not in bheads:
3469 raise util.Abort(_('working directory not at a head revision'),
3459 raise util.Abort(_('working directory not at a head revision'),
3470 hint=_("use 'hg update' or merge with an "
3460 hint=_("use 'hg update' or merge with an "
3471 "explicit revision"))
3461 "explicit revision"))
3472 node = parent == bheads[0] and bheads[-1] or bheads[0]
3462 node = parent == bheads[0] and bheads[-1] or bheads[0]
3473 else:
3463 else:
3474 node = scmutil.revsingle(repo, node).node()
3464 node = scmutil.revsingle(repo, node).node()
3475
3465
3476 if opts.get('preview'):
3466 if opts.get('preview'):
3477 # find nodes that are ancestors of p2 but not of p1
3467 # find nodes that are ancestors of p2 but not of p1
3478 p1 = repo.lookup('.')
3468 p1 = repo.lookup('.')
3479 p2 = repo.lookup(node)
3469 p2 = repo.lookup(node)
3480 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3470 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3481
3471
3482 displayer = cmdutil.show_changeset(ui, repo, opts)
3472 displayer = cmdutil.show_changeset(ui, repo, opts)
3483 for node in nodes:
3473 for node in nodes:
3484 displayer.show(repo[node])
3474 displayer.show(repo[node])
3485 displayer.close()
3475 displayer.close()
3486 return 0
3476 return 0
3487
3477
3488 try:
3478 try:
3489 # ui.forcemerge is an internal variable, do not document
3479 # ui.forcemerge is an internal variable, do not document
3490 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3480 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3491 return hg.merge(repo, node, force=opts.get('force'))
3481 return hg.merge(repo, node, force=opts.get('force'))
3492 finally:
3482 finally:
3493 ui.setconfig('ui', 'forcemerge', '')
3483 ui.setconfig('ui', 'forcemerge', '')
3494
3484
3495 @command('outgoing|out',
3485 @command('outgoing|out',
3496 [('f', 'force', None, _('run even when the destination is unrelated')),
3486 [('f', 'force', None, _('run even when the destination is unrelated')),
3497 ('r', 'rev', [],
3487 ('r', 'rev', [],
3498 _('a changeset intended to be included in the destination'), _('REV')),
3488 _('a changeset intended to be included in the destination'), _('REV')),
3499 ('n', 'newest-first', None, _('show newest record first')),
3489 ('n', 'newest-first', None, _('show newest record first')),
3500 ('B', 'bookmarks', False, _('compare bookmarks')),
3490 ('B', 'bookmarks', False, _('compare bookmarks')),
3501 ('b', 'branch', [], _('a specific branch you would like to push'),
3491 ('b', 'branch', [], _('a specific branch you would like to push'),
3502 _('BRANCH')),
3492 _('BRANCH')),
3503 ] + logopts + remoteopts + subrepoopts,
3493 ] + logopts + remoteopts + subrepoopts,
3504 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3494 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3505 def outgoing(ui, repo, dest=None, **opts):
3495 def outgoing(ui, repo, dest=None, **opts):
3506 """show changesets not found in the destination
3496 """show changesets not found in the destination
3507
3497
3508 Show changesets not found in the specified destination repository
3498 Show changesets not found in the specified destination repository
3509 or the default push location. These are the changesets that would
3499 or the default push location. These are the changesets that would
3510 be pushed if a push was requested.
3500 be pushed if a push was requested.
3511
3501
3512 See pull for details of valid destination formats.
3502 See pull for details of valid destination formats.
3513
3503
3514 Returns 0 if there are outgoing changes, 1 otherwise.
3504 Returns 0 if there are outgoing changes, 1 otherwise.
3515 """
3505 """
3516
3506
3517 if opts.get('bookmarks'):
3507 if opts.get('bookmarks'):
3518 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3508 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3519 dest, branches = hg.parseurl(dest, opts.get('branch'))
3509 dest, branches = hg.parseurl(dest, opts.get('branch'))
3520 other = hg.repository(hg.remoteui(repo, opts), dest)
3510 other = hg.repository(hg.remoteui(repo, opts), dest)
3521 if 'bookmarks' not in other.listkeys('namespaces'):
3511 if 'bookmarks' not in other.listkeys('namespaces'):
3522 ui.warn(_("remote doesn't support bookmarks\n"))
3512 ui.warn(_("remote doesn't support bookmarks\n"))
3523 return 0
3513 return 0
3524 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3514 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3525 return bookmarks.diff(ui, other, repo)
3515 return bookmarks.diff(ui, other, repo)
3526
3516
3527 ret = hg.outgoing(ui, repo, dest, opts)
3517 ret = hg.outgoing(ui, repo, dest, opts)
3528 return ret
3518 return ret
3529
3519
3530 @command('parents',
3520 @command('parents',
3531 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3521 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3532 ] + templateopts,
3522 ] + templateopts,
3533 _('[-r REV] [FILE]'))
3523 _('[-r REV] [FILE]'))
3534 def parents(ui, repo, file_=None, **opts):
3524 def parents(ui, repo, file_=None, **opts):
3535 """show the parents of the working directory or revision
3525 """show the parents of the working directory or revision
3536
3526
3537 Print the working directory's parent revisions. If a revision is
3527 Print the working directory's parent revisions. If a revision is
3538 given via -r/--rev, the parent of that revision will be printed.
3528 given via -r/--rev, the parent of that revision will be printed.
3539 If a file argument is given, the revision in which the file was
3529 If a file argument is given, the revision in which the file was
3540 last changed (before the working directory revision or the
3530 last changed (before the working directory revision or the
3541 argument to --rev if given) is printed.
3531 argument to --rev if given) is printed.
3542
3532
3543 Returns 0 on success.
3533 Returns 0 on success.
3544 """
3534 """
3545
3535
3546 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3536 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3547
3537
3548 if file_:
3538 if file_:
3549 m = scmutil.match(repo, (file_,), opts)
3539 m = scmutil.match(repo, (file_,), opts)
3550 if m.anypats() or len(m.files()) != 1:
3540 if m.anypats() or len(m.files()) != 1:
3551 raise util.Abort(_('can only specify an explicit filename'))
3541 raise util.Abort(_('can only specify an explicit filename'))
3552 file_ = m.files()[0]
3542 file_ = m.files()[0]
3553 filenodes = []
3543 filenodes = []
3554 for cp in ctx.parents():
3544 for cp in ctx.parents():
3555 if not cp:
3545 if not cp:
3556 continue
3546 continue
3557 try:
3547 try:
3558 filenodes.append(cp.filenode(file_))
3548 filenodes.append(cp.filenode(file_))
3559 except error.LookupError:
3549 except error.LookupError:
3560 pass
3550 pass
3561 if not filenodes:
3551 if not filenodes:
3562 raise util.Abort(_("'%s' not found in manifest!") % file_)
3552 raise util.Abort(_("'%s' not found in manifest!") % file_)
3563 fl = repo.file(file_)
3553 fl = repo.file(file_)
3564 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3554 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3565 else:
3555 else:
3566 p = [cp.node() for cp in ctx.parents()]
3556 p = [cp.node() for cp in ctx.parents()]
3567
3557
3568 displayer = cmdutil.show_changeset(ui, repo, opts)
3558 displayer = cmdutil.show_changeset(ui, repo, opts)
3569 for n in p:
3559 for n in p:
3570 if n != nullid:
3560 if n != nullid:
3571 displayer.show(repo[n])
3561 displayer.show(repo[n])
3572 displayer.close()
3562 displayer.close()
3573
3563
3574 @command('paths', [], _('[NAME]'))
3564 @command('paths', [], _('[NAME]'))
3575 def paths(ui, repo, search=None):
3565 def paths(ui, repo, search=None):
3576 """show aliases for remote repositories
3566 """show aliases for remote repositories
3577
3567
3578 Show definition of symbolic path name NAME. If no name is given,
3568 Show definition of symbolic path name NAME. If no name is given,
3579 show definition of all available names.
3569 show definition of all available names.
3580
3570
3581 Path names are defined in the [paths] section of your
3571 Path names are defined in the [paths] section of your
3582 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3572 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3583 repository, ``.hg/hgrc`` is used, too.
3573 repository, ``.hg/hgrc`` is used, too.
3584
3574
3585 The path names ``default`` and ``default-push`` have a special
3575 The path names ``default`` and ``default-push`` have a special
3586 meaning. When performing a push or pull operation, they are used
3576 meaning. When performing a push or pull operation, they are used
3587 as fallbacks if no location is specified on the command-line.
3577 as fallbacks if no location is specified on the command-line.
3588 When ``default-push`` is set, it will be used for push and
3578 When ``default-push`` is set, it will be used for push and
3589 ``default`` will be used for pull; otherwise ``default`` is used
3579 ``default`` will be used for pull; otherwise ``default`` is used
3590 as the fallback for both. When cloning a repository, the clone
3580 as the fallback for both. When cloning a repository, the clone
3591 source is written as ``default`` in ``.hg/hgrc``. Note that
3581 source is written as ``default`` in ``.hg/hgrc``. Note that
3592 ``default`` and ``default-push`` apply to all inbound (e.g.
3582 ``default`` and ``default-push`` apply to all inbound (e.g.
3593 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3583 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3594 :hg:`bundle`) operations.
3584 :hg:`bundle`) operations.
3595
3585
3596 See :hg:`help urls` for more information.
3586 See :hg:`help urls` for more information.
3597
3587
3598 Returns 0 on success.
3588 Returns 0 on success.
3599 """
3589 """
3600 if search:
3590 if search:
3601 for name, path in ui.configitems("paths"):
3591 for name, path in ui.configitems("paths"):
3602 if name == search:
3592 if name == search:
3603 ui.write("%s\n" % util.hidepassword(path))
3593 ui.write("%s\n" % util.hidepassword(path))
3604 return
3594 return
3605 ui.warn(_("not found!\n"))
3595 ui.warn(_("not found!\n"))
3606 return 1
3596 return 1
3607 else:
3597 else:
3608 for name, path in ui.configitems("paths"):
3598 for name, path in ui.configitems("paths"):
3609 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3599 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3610
3600
3611 def postincoming(ui, repo, modheads, optupdate, checkout):
3601 def postincoming(ui, repo, modheads, optupdate, checkout):
3612 if modheads == 0:
3602 if modheads == 0:
3613 return
3603 return
3614 if optupdate:
3604 if optupdate:
3615 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
3605 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
3616 return hg.update(repo, checkout)
3606 return hg.update(repo, checkout)
3617 else:
3607 else:
3618 ui.status(_("not updating, since new heads added\n"))
3608 ui.status(_("not updating, since new heads added\n"))
3619 if modheads > 1:
3609 if modheads > 1:
3620 currentbranchheads = len(repo.branchheads())
3610 currentbranchheads = len(repo.branchheads())
3621 if currentbranchheads == modheads:
3611 if currentbranchheads == modheads:
3622 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3612 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3623 elif currentbranchheads > 1:
3613 elif currentbranchheads > 1:
3624 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3614 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3625 else:
3615 else:
3626 ui.status(_("(run 'hg heads' to see heads)\n"))
3616 ui.status(_("(run 'hg heads' to see heads)\n"))
3627 else:
3617 else:
3628 ui.status(_("(run 'hg update' to get a working copy)\n"))
3618 ui.status(_("(run 'hg update' to get a working copy)\n"))
3629
3619
3630 @command('^pull',
3620 @command('^pull',
3631 [('u', 'update', None,
3621 [('u', 'update', None,
3632 _('update to new branch head if changesets were pulled')),
3622 _('update to new branch head if changesets were pulled')),
3633 ('f', 'force', None, _('run even when remote repository is unrelated')),
3623 ('f', 'force', None, _('run even when remote repository is unrelated')),
3634 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3624 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3635 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3625 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3636 ('b', 'branch', [], _('a specific branch you would like to pull'),
3626 ('b', 'branch', [], _('a specific branch you would like to pull'),
3637 _('BRANCH')),
3627 _('BRANCH')),
3638 ] + remoteopts,
3628 ] + remoteopts,
3639 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3629 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3640 def pull(ui, repo, source="default", **opts):
3630 def pull(ui, repo, source="default", **opts):
3641 """pull changes from the specified source
3631 """pull changes from the specified source
3642
3632
3643 Pull changes from a remote repository to a local one.
3633 Pull changes from a remote repository to a local one.
3644
3634
3645 This finds all changes from the repository at the specified path
3635 This finds all changes from the repository at the specified path
3646 or URL and adds them to a local repository (the current one unless
3636 or URL and adds them to a local repository (the current one unless
3647 -R is specified). By default, this does not update the copy of the
3637 -R is specified). By default, this does not update the copy of the
3648 project in the working directory.
3638 project in the working directory.
3649
3639
3650 Use :hg:`incoming` if you want to see what would have been added
3640 Use :hg:`incoming` if you want to see what would have been added
3651 by a pull at the time you issued this command. If you then decide
3641 by a pull at the time you issued this command. If you then decide
3652 to add those changes to the repository, you should use :hg:`pull
3642 to add those changes to the repository, you should use :hg:`pull
3653 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3643 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3654
3644
3655 If SOURCE is omitted, the 'default' path will be used.
3645 If SOURCE is omitted, the 'default' path will be used.
3656 See :hg:`help urls` for more information.
3646 See :hg:`help urls` for more information.
3657
3647
3658 Returns 0 on success, 1 if an update had unresolved files.
3648 Returns 0 on success, 1 if an update had unresolved files.
3659 """
3649 """
3660 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3650 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3661 other = hg.repository(hg.remoteui(repo, opts), source)
3651 other = hg.repository(hg.remoteui(repo, opts), source)
3662 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3652 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3663 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3653 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3664
3654
3665 if opts.get('bookmark'):
3655 if opts.get('bookmark'):
3666 if not revs:
3656 if not revs:
3667 revs = []
3657 revs = []
3668 rb = other.listkeys('bookmarks')
3658 rb = other.listkeys('bookmarks')
3669 for b in opts['bookmark']:
3659 for b in opts['bookmark']:
3670 if b not in rb:
3660 if b not in rb:
3671 raise util.Abort(_('remote bookmark %s not found!') % b)
3661 raise util.Abort(_('remote bookmark %s not found!') % b)
3672 revs.append(rb[b])
3662 revs.append(rb[b])
3673
3663
3674 if revs:
3664 if revs:
3675 try:
3665 try:
3676 revs = [other.lookup(rev) for rev in revs]
3666 revs = [other.lookup(rev) for rev in revs]
3677 except error.CapabilityError:
3667 except error.CapabilityError:
3678 err = _("other repository doesn't support revision lookup, "
3668 err = _("other repository doesn't support revision lookup, "
3679 "so a rev cannot be specified.")
3669 "so a rev cannot be specified.")
3680 raise util.Abort(err)
3670 raise util.Abort(err)
3681
3671
3682 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3672 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3683 bookmarks.updatefromremote(ui, repo, other)
3673 bookmarks.updatefromremote(ui, repo, other)
3684 if checkout:
3674 if checkout:
3685 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3675 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3686 repo._subtoppath = source
3676 repo._subtoppath = source
3687 try:
3677 try:
3688 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3678 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3689
3679
3690 finally:
3680 finally:
3691 del repo._subtoppath
3681 del repo._subtoppath
3692
3682
3693 # update specified bookmarks
3683 # update specified bookmarks
3694 if opts.get('bookmark'):
3684 if opts.get('bookmark'):
3695 for b in opts['bookmark']:
3685 for b in opts['bookmark']:
3696 # explicit pull overrides local bookmark if any
3686 # explicit pull overrides local bookmark if any
3697 ui.status(_("importing bookmark %s\n") % b)
3687 ui.status(_("importing bookmark %s\n") % b)
3698 repo._bookmarks[b] = repo[rb[b]].node()
3688 repo._bookmarks[b] = repo[rb[b]].node()
3699 bookmarks.write(repo)
3689 bookmarks.write(repo)
3700
3690
3701 return ret
3691 return ret
3702
3692
3703 @command('^push',
3693 @command('^push',
3704 [('f', 'force', None, _('force push')),
3694 [('f', 'force', None, _('force push')),
3705 ('r', 'rev', [],
3695 ('r', 'rev', [],
3706 _('a changeset intended to be included in the destination'),
3696 _('a changeset intended to be included in the destination'),
3707 _('REV')),
3697 _('REV')),
3708 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3698 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3709 ('b', 'branch', [],
3699 ('b', 'branch', [],
3710 _('a specific branch you would like to push'), _('BRANCH')),
3700 _('a specific branch you would like to push'), _('BRANCH')),
3711 ('', 'new-branch', False, _('allow pushing a new branch')),
3701 ('', 'new-branch', False, _('allow pushing a new branch')),
3712 ] + remoteopts,
3702 ] + remoteopts,
3713 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3703 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3714 def push(ui, repo, dest=None, **opts):
3704 def push(ui, repo, dest=None, **opts):
3715 """push changes to the specified destination
3705 """push changes to the specified destination
3716
3706
3717 Push changesets from the local repository to the specified
3707 Push changesets from the local repository to the specified
3718 destination.
3708 destination.
3719
3709
3720 This operation is symmetrical to pull: it is identical to a pull
3710 This operation is symmetrical to pull: it is identical to a pull
3721 in the destination repository from the current one.
3711 in the destination repository from the current one.
3722
3712
3723 By default, push will not allow creation of new heads at the
3713 By default, push will not allow creation of new heads at the
3724 destination, since multiple heads would make it unclear which head
3714 destination, since multiple heads would make it unclear which head
3725 to use. In this situation, it is recommended to pull and merge
3715 to use. In this situation, it is recommended to pull and merge
3726 before pushing.
3716 before pushing.
3727
3717
3728 Use --new-branch if you want to allow push to create a new named
3718 Use --new-branch if you want to allow push to create a new named
3729 branch that is not present at the destination. This allows you to
3719 branch that is not present at the destination. This allows you to
3730 only create a new branch without forcing other changes.
3720 only create a new branch without forcing other changes.
3731
3721
3732 Use -f/--force to override the default behavior and push all
3722 Use -f/--force to override the default behavior and push all
3733 changesets on all branches.
3723 changesets on all branches.
3734
3724
3735 If -r/--rev is used, the specified revision and all its ancestors
3725 If -r/--rev is used, the specified revision and all its ancestors
3736 will be pushed to the remote repository.
3726 will be pushed to the remote repository.
3737
3727
3738 Please see :hg:`help urls` for important details about ``ssh://``
3728 Please see :hg:`help urls` for important details about ``ssh://``
3739 URLs. If DESTINATION is omitted, a default path will be used.
3729 URLs. If DESTINATION is omitted, a default path will be used.
3740
3730
3741 Returns 0 if push was successful, 1 if nothing to push.
3731 Returns 0 if push was successful, 1 if nothing to push.
3742 """
3732 """
3743
3733
3744 if opts.get('bookmark'):
3734 if opts.get('bookmark'):
3745 for b in opts['bookmark']:
3735 for b in opts['bookmark']:
3746 # translate -B options to -r so changesets get pushed
3736 # translate -B options to -r so changesets get pushed
3747 if b in repo._bookmarks:
3737 if b in repo._bookmarks:
3748 opts.setdefault('rev', []).append(b)
3738 opts.setdefault('rev', []).append(b)
3749 else:
3739 else:
3750 # if we try to push a deleted bookmark, translate it to null
3740 # if we try to push a deleted bookmark, translate it to null
3751 # this lets simultaneous -r, -b options continue working
3741 # this lets simultaneous -r, -b options continue working
3752 opts.setdefault('rev', []).append("null")
3742 opts.setdefault('rev', []).append("null")
3753
3743
3754 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3744 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3755 dest, branches = hg.parseurl(dest, opts.get('branch'))
3745 dest, branches = hg.parseurl(dest, opts.get('branch'))
3756 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3746 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3757 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3747 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3758 other = hg.repository(hg.remoteui(repo, opts), dest)
3748 other = hg.repository(hg.remoteui(repo, opts), dest)
3759 if revs:
3749 if revs:
3760 revs = [repo.lookup(rev) for rev in revs]
3750 revs = [repo.lookup(rev) for rev in revs]
3761
3751
3762 repo._subtoppath = dest
3752 repo._subtoppath = dest
3763 try:
3753 try:
3764 # push subrepos depth-first for coherent ordering
3754 # push subrepos depth-first for coherent ordering
3765 c = repo['']
3755 c = repo['']
3766 subs = c.substate # only repos that are committed
3756 subs = c.substate # only repos that are committed
3767 for s in sorted(subs):
3757 for s in sorted(subs):
3768 if not c.sub(s).push(opts.get('force')):
3758 if not c.sub(s).push(opts.get('force')):
3769 return False
3759 return False
3770 finally:
3760 finally:
3771 del repo._subtoppath
3761 del repo._subtoppath
3772 result = repo.push(other, opts.get('force'), revs=revs,
3762 result = repo.push(other, opts.get('force'), revs=revs,
3773 newbranch=opts.get('new_branch'))
3763 newbranch=opts.get('new_branch'))
3774
3764
3775 result = (result == 0)
3765 result = (result == 0)
3776
3766
3777 if opts.get('bookmark'):
3767 if opts.get('bookmark'):
3778 rb = other.listkeys('bookmarks')
3768 rb = other.listkeys('bookmarks')
3779 for b in opts['bookmark']:
3769 for b in opts['bookmark']:
3780 # explicit push overrides remote bookmark if any
3770 # explicit push overrides remote bookmark if any
3781 if b in repo._bookmarks:
3771 if b in repo._bookmarks:
3782 ui.status(_("exporting bookmark %s\n") % b)
3772 ui.status(_("exporting bookmark %s\n") % b)
3783 new = repo[b].hex()
3773 new = repo[b].hex()
3784 elif b in rb:
3774 elif b in rb:
3785 ui.status(_("deleting remote bookmark %s\n") % b)
3775 ui.status(_("deleting remote bookmark %s\n") % b)
3786 new = '' # delete
3776 new = '' # delete
3787 else:
3777 else:
3788 ui.warn(_('bookmark %s does not exist on the local '
3778 ui.warn(_('bookmark %s does not exist on the local '
3789 'or remote repository!\n') % b)
3779 'or remote repository!\n') % b)
3790 return 2
3780 return 2
3791 old = rb.get(b, '')
3781 old = rb.get(b, '')
3792 r = other.pushkey('bookmarks', b, old, new)
3782 r = other.pushkey('bookmarks', b, old, new)
3793 if not r:
3783 if not r:
3794 ui.warn(_('updating bookmark %s failed!\n') % b)
3784 ui.warn(_('updating bookmark %s failed!\n') % b)
3795 if not result:
3785 if not result:
3796 result = 2
3786 result = 2
3797
3787
3798 return result
3788 return result
3799
3789
3800 @command('recover', [])
3790 @command('recover', [])
3801 def recover(ui, repo):
3791 def recover(ui, repo):
3802 """roll back an interrupted transaction
3792 """roll back an interrupted transaction
3803
3793
3804 Recover from an interrupted commit or pull.
3794 Recover from an interrupted commit or pull.
3805
3795
3806 This command tries to fix the repository status after an
3796 This command tries to fix the repository status after an
3807 interrupted operation. It should only be necessary when Mercurial
3797 interrupted operation. It should only be necessary when Mercurial
3808 suggests it.
3798 suggests it.
3809
3799
3810 Returns 0 if successful, 1 if nothing to recover or verify fails.
3800 Returns 0 if successful, 1 if nothing to recover or verify fails.
3811 """
3801 """
3812 if repo.recover():
3802 if repo.recover():
3813 return hg.verify(repo)
3803 return hg.verify(repo)
3814 return 1
3804 return 1
3815
3805
3816 @command('^remove|rm',
3806 @command('^remove|rm',
3817 [('A', 'after', None, _('record delete for missing files')),
3807 [('A', 'after', None, _('record delete for missing files')),
3818 ('f', 'force', None,
3808 ('f', 'force', None,
3819 _('remove (and delete) file even if added or modified')),
3809 _('remove (and delete) file even if added or modified')),
3820 ] + walkopts,
3810 ] + walkopts,
3821 _('[OPTION]... FILE...'))
3811 _('[OPTION]... FILE...'))
3822 def remove(ui, repo, *pats, **opts):
3812 def remove(ui, repo, *pats, **opts):
3823 """remove the specified files on the next commit
3813 """remove the specified files on the next commit
3824
3814
3825 Schedule the indicated files for removal from the repository.
3815 Schedule the indicated files for removal from the repository.
3826
3816
3827 This only removes files from the current branch, not from the
3817 This only removes files from the current branch, not from the
3828 entire project history. -A/--after can be used to remove only
3818 entire project history. -A/--after can be used to remove only
3829 files that have already been deleted, -f/--force can be used to
3819 files that have already been deleted, -f/--force can be used to
3830 force deletion, and -Af can be used to remove files from the next
3820 force deletion, and -Af can be used to remove files from the next
3831 revision without deleting them from the working directory.
3821 revision without deleting them from the working directory.
3832
3822
3833 The following table details the behavior of remove for different
3823 The following table details the behavior of remove for different
3834 file states (columns) and option combinations (rows). The file
3824 file states (columns) and option combinations (rows). The file
3835 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3825 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3836 reported by :hg:`status`). The actions are Warn, Remove (from
3826 reported by :hg:`status`). The actions are Warn, Remove (from
3837 branch) and Delete (from disk)::
3827 branch) and Delete (from disk)::
3838
3828
3839 A C M !
3829 A C M !
3840 none W RD W R
3830 none W RD W R
3841 -f R RD RD R
3831 -f R RD RD R
3842 -A W W W R
3832 -A W W W R
3843 -Af R R R R
3833 -Af R R R R
3844
3834
3845 This command schedules the files to be removed at the next commit.
3835 This command schedules the files to be removed at the next commit.
3846 To undo a remove before that, see :hg:`revert`.
3836 To undo a remove before that, see :hg:`revert`.
3847
3837
3848 Returns 0 on success, 1 if any warnings encountered.
3838 Returns 0 on success, 1 if any warnings encountered.
3849 """
3839 """
3850
3840
3851 ret = 0
3841 ret = 0
3852 after, force = opts.get('after'), opts.get('force')
3842 after, force = opts.get('after'), opts.get('force')
3853 if not pats and not after:
3843 if not pats and not after:
3854 raise util.Abort(_('no files specified'))
3844 raise util.Abort(_('no files specified'))
3855
3845
3856 m = scmutil.match(repo, pats, opts)
3846 m = scmutil.match(repo, pats, opts)
3857 s = repo.status(match=m, clean=True)
3847 s = repo.status(match=m, clean=True)
3858 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3848 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3859
3849
3860 for f in m.files():
3850 for f in m.files():
3861 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3851 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3862 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3852 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3863 ret = 1
3853 ret = 1
3864
3854
3865 if force:
3855 if force:
3866 remove, forget = modified + deleted + clean, added
3856 remove, forget = modified + deleted + clean, added
3867 elif after:
3857 elif after:
3868 remove, forget = deleted, []
3858 remove, forget = deleted, []
3869 for f in modified + added + clean:
3859 for f in modified + added + clean:
3870 ui.warn(_('not removing %s: file still exists (use -f'
3860 ui.warn(_('not removing %s: file still exists (use -f'
3871 ' to force removal)\n') % m.rel(f))
3861 ' to force removal)\n') % m.rel(f))
3872 ret = 1
3862 ret = 1
3873 else:
3863 else:
3874 remove, forget = deleted + clean, []
3864 remove, forget = deleted + clean, []
3875 for f in modified:
3865 for f in modified:
3876 ui.warn(_('not removing %s: file is modified (use -f'
3866 ui.warn(_('not removing %s: file is modified (use -f'
3877 ' to force removal)\n') % m.rel(f))
3867 ' to force removal)\n') % m.rel(f))
3878 ret = 1
3868 ret = 1
3879 for f in added:
3869 for f in added:
3880 ui.warn(_('not removing %s: file has been marked for add (use -f'
3870 ui.warn(_('not removing %s: file has been marked for add (use -f'
3881 ' to force removal)\n') % m.rel(f))
3871 ' to force removal)\n') % m.rel(f))
3882 ret = 1
3872 ret = 1
3883
3873
3884 for f in sorted(remove + forget):
3874 for f in sorted(remove + forget):
3885 if ui.verbose or not m.exact(f):
3875 if ui.verbose or not m.exact(f):
3886 ui.status(_('removing %s\n') % m.rel(f))
3876 ui.status(_('removing %s\n') % m.rel(f))
3887
3877
3888 repo[None].forget(forget)
3878 repo[None].forget(forget)
3889 repo[None].remove(remove, unlink=not after)
3879 repo[None].remove(remove, unlink=not after)
3890 return ret
3880 return ret
3891
3881
3892 @command('rename|move|mv',
3882 @command('rename|move|mv',
3893 [('A', 'after', None, _('record a rename that has already occurred')),
3883 [('A', 'after', None, _('record a rename that has already occurred')),
3894 ('f', 'force', None, _('forcibly copy over an existing managed file')),
3884 ('f', 'force', None, _('forcibly copy over an existing managed file')),
3895 ] + walkopts + dryrunopts,
3885 ] + walkopts + dryrunopts,
3896 _('[OPTION]... SOURCE... DEST'))
3886 _('[OPTION]... SOURCE... DEST'))
3897 def rename(ui, repo, *pats, **opts):
3887 def rename(ui, repo, *pats, **opts):
3898 """rename files; equivalent of copy + remove
3888 """rename files; equivalent of copy + remove
3899
3889
3900 Mark dest as copies of sources; mark sources for deletion. If dest
3890 Mark dest as copies of sources; mark sources for deletion. If dest
3901 is a directory, copies are put in that directory. If dest is a
3891 is a directory, copies are put in that directory. If dest is a
3902 file, there can only be one source.
3892 file, there can only be one source.
3903
3893
3904 By default, this command copies the contents of files as they
3894 By default, this command copies the contents of files as they
3905 exist in the working directory. If invoked with -A/--after, the
3895 exist in the working directory. If invoked with -A/--after, the
3906 operation is recorded, but no copying is performed.
3896 operation is recorded, but no copying is performed.
3907
3897
3908 This command takes effect at the next commit. To undo a rename
3898 This command takes effect at the next commit. To undo a rename
3909 before that, see :hg:`revert`.
3899 before that, see :hg:`revert`.
3910
3900
3911 Returns 0 on success, 1 if errors are encountered.
3901 Returns 0 on success, 1 if errors are encountered.
3912 """
3902 """
3913 wlock = repo.wlock(False)
3903 wlock = repo.wlock(False)
3914 try:
3904 try:
3915 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3905 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3916 finally:
3906 finally:
3917 wlock.release()
3907 wlock.release()
3918
3908
3919 @command('resolve',
3909 @command('resolve',
3920 [('a', 'all', None, _('select all unresolved files')),
3910 [('a', 'all', None, _('select all unresolved files')),
3921 ('l', 'list', None, _('list state of files needing merge')),
3911 ('l', 'list', None, _('list state of files needing merge')),
3922 ('m', 'mark', None, _('mark files as resolved')),
3912 ('m', 'mark', None, _('mark files as resolved')),
3923 ('u', 'unmark', None, _('mark files as unresolved')),
3913 ('u', 'unmark', None, _('mark files as unresolved')),
3924 ('t', 'tool', '', _('specify merge tool')),
3914 ('t', 'tool', '', _('specify merge tool')),
3925 ('n', 'no-status', None, _('hide status prefix'))]
3915 ('n', 'no-status', None, _('hide status prefix'))]
3926 + walkopts,
3916 + walkopts,
3927 _('[OPTION]... [FILE]...'))
3917 _('[OPTION]... [FILE]...'))
3928 def resolve(ui, repo, *pats, **opts):
3918 def resolve(ui, repo, *pats, **opts):
3929 """redo merges or set/view the merge status of files
3919 """redo merges or set/view the merge status of files
3930
3920
3931 Merges with unresolved conflicts are often the result of
3921 Merges with unresolved conflicts are often the result of
3932 non-interactive merging using the ``internal:merge`` configuration
3922 non-interactive merging using the ``internal:merge`` configuration
3933 setting, or a command-line merge tool like ``diff3``. The resolve
3923 setting, or a command-line merge tool like ``diff3``. The resolve
3934 command is used to manage the files involved in a merge, after
3924 command is used to manage the files involved in a merge, after
3935 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3925 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3936 working directory must have two parents).
3926 working directory must have two parents).
3937
3927
3938 The resolve command can be used in the following ways:
3928 The resolve command can be used in the following ways:
3939
3929
3940 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3930 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3941 files, discarding any previous merge attempts. Re-merging is not
3931 files, discarding any previous merge attempts. Re-merging is not
3942 performed for files already marked as resolved. Use ``--all/-a``
3932 performed for files already marked as resolved. Use ``--all/-a``
3943 to selects all unresolved files. ``--tool`` can be used to specify
3933 to selects all unresolved files. ``--tool`` can be used to specify
3944 the merge tool used for the given files. It overrides the HGMERGE
3934 the merge tool used for the given files. It overrides the HGMERGE
3945 environment variable and your configuration files.
3935 environment variable and your configuration files.
3946
3936
3947 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3937 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3948 (e.g. after having manually fixed-up the files). The default is
3938 (e.g. after having manually fixed-up the files). The default is
3949 to mark all unresolved files.
3939 to mark all unresolved files.
3950
3940
3951 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3941 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3952 default is to mark all resolved files.
3942 default is to mark all resolved files.
3953
3943
3954 - :hg:`resolve -l`: list files which had or still have conflicts.
3944 - :hg:`resolve -l`: list files which had or still have conflicts.
3955 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3945 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3956
3946
3957 Note that Mercurial will not let you commit files with unresolved
3947 Note that Mercurial will not let you commit files with unresolved
3958 merge conflicts. You must use :hg:`resolve -m ...` before you can
3948 merge conflicts. You must use :hg:`resolve -m ...` before you can
3959 commit after a conflicting merge.
3949 commit after a conflicting merge.
3960
3950
3961 Returns 0 on success, 1 if any files fail a resolve attempt.
3951 Returns 0 on success, 1 if any files fail a resolve attempt.
3962 """
3952 """
3963
3953
3964 all, mark, unmark, show, nostatus = \
3954 all, mark, unmark, show, nostatus = \
3965 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3955 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3966
3956
3967 if (show and (mark or unmark)) or (mark and unmark):
3957 if (show and (mark or unmark)) or (mark and unmark):
3968 raise util.Abort(_("too many options specified"))
3958 raise util.Abort(_("too many options specified"))
3969 if pats and all:
3959 if pats and all:
3970 raise util.Abort(_("can't specify --all and patterns"))
3960 raise util.Abort(_("can't specify --all and patterns"))
3971 if not (all or pats or show or mark or unmark):
3961 if not (all or pats or show or mark or unmark):
3972 raise util.Abort(_('no files or directories specified; '
3962 raise util.Abort(_('no files or directories specified; '
3973 'use --all to remerge all files'))
3963 'use --all to remerge all files'))
3974
3964
3975 ms = mergemod.mergestate(repo)
3965 ms = mergemod.mergestate(repo)
3976 m = scmutil.match(repo, pats, opts)
3966 m = scmutil.match(repo, pats, opts)
3977 ret = 0
3967 ret = 0
3978
3968
3979 for f in ms:
3969 for f in ms:
3980 if m(f):
3970 if m(f):
3981 if show:
3971 if show:
3982 if nostatus:
3972 if nostatus:
3983 ui.write("%s\n" % f)
3973 ui.write("%s\n" % f)
3984 else:
3974 else:
3985 ui.write("%s %s\n" % (ms[f].upper(), f),
3975 ui.write("%s %s\n" % (ms[f].upper(), f),
3986 label='resolve.' +
3976 label='resolve.' +
3987 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3977 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3988 elif mark:
3978 elif mark:
3989 ms.mark(f, "r")
3979 ms.mark(f, "r")
3990 elif unmark:
3980 elif unmark:
3991 ms.mark(f, "u")
3981 ms.mark(f, "u")
3992 else:
3982 else:
3993 wctx = repo[None]
3983 wctx = repo[None]
3994 mctx = wctx.parents()[-1]
3984 mctx = wctx.parents()[-1]
3995
3985
3996 # backup pre-resolve (merge uses .orig for its own purposes)
3986 # backup pre-resolve (merge uses .orig for its own purposes)
3997 a = repo.wjoin(f)
3987 a = repo.wjoin(f)
3998 util.copyfile(a, a + ".resolve")
3988 util.copyfile(a, a + ".resolve")
3999
3989
4000 try:
3990 try:
4001 # resolve file
3991 # resolve file
4002 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3992 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4003 if ms.resolve(f, wctx, mctx):
3993 if ms.resolve(f, wctx, mctx):
4004 ret = 1
3994 ret = 1
4005 finally:
3995 finally:
4006 ui.setconfig('ui', 'forcemerge', '')
3996 ui.setconfig('ui', 'forcemerge', '')
4007
3997
4008 # replace filemerge's .orig file with our resolve file
3998 # replace filemerge's .orig file with our resolve file
4009 util.rename(a + ".resolve", a + ".orig")
3999 util.rename(a + ".resolve", a + ".orig")
4010
4000
4011 ms.commit()
4001 ms.commit()
4012 return ret
4002 return ret
4013
4003
4014 @command('revert',
4004 @command('revert',
4015 [('a', 'all', None, _('revert all changes when no arguments given')),
4005 [('a', 'all', None, _('revert all changes when no arguments given')),
4016 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4006 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4017 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4007 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4018 ('', 'no-backup', None, _('do not save backup copies of files')),
4008 ('', 'no-backup', None, _('do not save backup copies of files')),
4019 ] + walkopts + dryrunopts,
4009 ] + walkopts + dryrunopts,
4020 _('[OPTION]... [-r REV] [NAME]...'))
4010 _('[OPTION]... [-r REV] [NAME]...'))
4021 def revert(ui, repo, *pats, **opts):
4011 def revert(ui, repo, *pats, **opts):
4022 """restore individual files or directories to an earlier state
4012 """restore individual files or directories to an earlier state
4023
4013
4024 .. note::
4014 .. note::
4025 This command is most likely not what you are looking for.
4015 This command is most likely not what you are looking for.
4026 Revert will partially overwrite content in the working
4016 Revert will partially overwrite content in the working
4027 directory without changing the working directory parents. Use
4017 directory without changing the working directory parents. Use
4028 :hg:`update -r rev` to check out earlier revisions, or
4018 :hg:`update -r rev` to check out earlier revisions, or
4029 :hg:`update --clean .` to undo a merge which has added another
4019 :hg:`update --clean .` to undo a merge which has added another
4030 parent.
4020 parent.
4031
4021
4032 With no revision specified, revert the named files or directories
4022 With no revision specified, revert the named files or directories
4033 to the contents they had in the parent of the working directory.
4023 to the contents they had in the parent of the working directory.
4034 This restores the contents of the affected files to an unmodified
4024 This restores the contents of the affected files to an unmodified
4035 state and unschedules adds, removes, copies, and renames. If the
4025 state and unschedules adds, removes, copies, and renames. If the
4036 working directory has two parents, you must explicitly specify a
4026 working directory has two parents, you must explicitly specify a
4037 revision.
4027 revision.
4038
4028
4039 Using the -r/--rev option, revert the given files or directories
4029 Using the -r/--rev option, revert the given files or directories
4040 to their contents as of a specific revision. This can be helpful
4030 to their contents as of a specific revision. This can be helpful
4041 to "roll back" some or all of an earlier change. See :hg:`help
4031 to "roll back" some or all of an earlier change. See :hg:`help
4042 dates` for a list of formats valid for -d/--date.
4032 dates` for a list of formats valid for -d/--date.
4043
4033
4044 Revert modifies the working directory. It does not commit any
4034 Revert modifies the working directory. It does not commit any
4045 changes, or change the parent of the working directory. If you
4035 changes, or change the parent of the working directory. If you
4046 revert to a revision other than the parent of the working
4036 revert to a revision other than the parent of the working
4047 directory, the reverted files will thus appear modified
4037 directory, the reverted files will thus appear modified
4048 afterwards.
4038 afterwards.
4049
4039
4050 If a file has been deleted, it is restored. Files scheduled for
4040 If a file has been deleted, it is restored. Files scheduled for
4051 addition are just unscheduled and left as they are. If the
4041 addition are just unscheduled and left as they are. If the
4052 executable mode of a file was changed, it is reset.
4042 executable mode of a file was changed, it is reset.
4053
4043
4054 If names are given, all files matching the names are reverted.
4044 If names are given, all files matching the names are reverted.
4055 If no arguments are given, no files are reverted.
4045 If no arguments are given, no files are reverted.
4056
4046
4057 Modified files are saved with a .orig suffix before reverting.
4047 Modified files are saved with a .orig suffix before reverting.
4058 To disable these backups, use --no-backup.
4048 To disable these backups, use --no-backup.
4059
4049
4060 Returns 0 on success.
4050 Returns 0 on success.
4061 """
4051 """
4062
4052
4063 if opts.get("date"):
4053 if opts.get("date"):
4064 if opts.get("rev"):
4054 if opts.get("rev"):
4065 raise util.Abort(_("you can't specify a revision and a date"))
4055 raise util.Abort(_("you can't specify a revision and a date"))
4066 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4056 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4067
4057
4068 parent, p2 = repo.dirstate.parents()
4058 parent, p2 = repo.dirstate.parents()
4069 if not opts.get('rev') and p2 != nullid:
4059 if not opts.get('rev') and p2 != nullid:
4070 raise util.Abort(_('uncommitted merge - '
4060 raise util.Abort(_('uncommitted merge - '
4071 'use "hg update", see "hg help revert"'))
4061 'use "hg update", see "hg help revert"'))
4072
4062
4073 if not pats and not opts.get('all'):
4063 if not pats and not opts.get('all'):
4074 raise util.Abort(_('no files or directories specified; '
4064 raise util.Abort(_('no files or directories specified; '
4075 'use --all to revert the whole repo'))
4065 'use --all to revert the whole repo'))
4076
4066
4077 ctx = scmutil.revsingle(repo, opts.get('rev'))
4067 ctx = scmutil.revsingle(repo, opts.get('rev'))
4078 node = ctx.node()
4068 node = ctx.node()
4079 mf = ctx.manifest()
4069 mf = ctx.manifest()
4080 if node == parent:
4070 if node == parent:
4081 pmf = mf
4071 pmf = mf
4082 else:
4072 else:
4083 pmf = None
4073 pmf = None
4084
4074
4085 # need all matching names in dirstate and manifest of target rev,
4075 # need all matching names in dirstate and manifest of target rev,
4086 # so have to walk both. do not print errors if files exist in one
4076 # so have to walk both. do not print errors if files exist in one
4087 # but not other.
4077 # but not other.
4088
4078
4089 names = {}
4079 names = {}
4090
4080
4091 wlock = repo.wlock()
4081 wlock = repo.wlock()
4092 try:
4082 try:
4093 # walk dirstate.
4083 # walk dirstate.
4094
4084
4095 m = scmutil.match(repo, pats, opts)
4085 m = scmutil.match(repo, pats, opts)
4096 m.bad = lambda x, y: False
4086 m.bad = lambda x, y: False
4097 for abs in repo.walk(m):
4087 for abs in repo.walk(m):
4098 names[abs] = m.rel(abs), m.exact(abs)
4088 names[abs] = m.rel(abs), m.exact(abs)
4099
4089
4100 # walk target manifest.
4090 # walk target manifest.
4101
4091
4102 def badfn(path, msg):
4092 def badfn(path, msg):
4103 if path in names:
4093 if path in names:
4104 return
4094 return
4105 path_ = path + '/'
4095 path_ = path + '/'
4106 for f in names:
4096 for f in names:
4107 if f.startswith(path_):
4097 if f.startswith(path_):
4108 return
4098 return
4109 ui.warn("%s: %s\n" % (m.rel(path), msg))
4099 ui.warn("%s: %s\n" % (m.rel(path), msg))
4110
4100
4111 m = scmutil.match(repo, pats, opts)
4101 m = scmutil.match(repo, pats, opts)
4112 m.bad = badfn
4102 m.bad = badfn
4113 for abs in repo[node].walk(m):
4103 for abs in repo[node].walk(m):
4114 if abs not in names:
4104 if abs not in names:
4115 names[abs] = m.rel(abs), m.exact(abs)
4105 names[abs] = m.rel(abs), m.exact(abs)
4116
4106
4117 m = scmutil.matchfiles(repo, names)
4107 m = scmutil.matchfiles(repo, names)
4118 changes = repo.status(match=m)[:4]
4108 changes = repo.status(match=m)[:4]
4119 modified, added, removed, deleted = map(set, changes)
4109 modified, added, removed, deleted = map(set, changes)
4120
4110
4121 # if f is a rename, also revert the source
4111 # if f is a rename, also revert the source
4122 cwd = repo.getcwd()
4112 cwd = repo.getcwd()
4123 for f in added:
4113 for f in added:
4124 src = repo.dirstate.copied(f)
4114 src = repo.dirstate.copied(f)
4125 if src and src not in names and repo.dirstate[src] == 'r':
4115 if src and src not in names and repo.dirstate[src] == 'r':
4126 removed.add(src)
4116 removed.add(src)
4127 names[src] = (repo.pathto(src, cwd), True)
4117 names[src] = (repo.pathto(src, cwd), True)
4128
4118
4129 def removeforget(abs):
4119 def removeforget(abs):
4130 if repo.dirstate[abs] == 'a':
4120 if repo.dirstate[abs] == 'a':
4131 return _('forgetting %s\n')
4121 return _('forgetting %s\n')
4132 return _('removing %s\n')
4122 return _('removing %s\n')
4133
4123
4134 revert = ([], _('reverting %s\n'))
4124 revert = ([], _('reverting %s\n'))
4135 add = ([], _('adding %s\n'))
4125 add = ([], _('adding %s\n'))
4136 remove = ([], removeforget)
4126 remove = ([], removeforget)
4137 undelete = ([], _('undeleting %s\n'))
4127 undelete = ([], _('undeleting %s\n'))
4138
4128
4139 disptable = (
4129 disptable = (
4140 # dispatch table:
4130 # dispatch table:
4141 # file state
4131 # file state
4142 # action if in target manifest
4132 # action if in target manifest
4143 # action if not in target manifest
4133 # action if not in target manifest
4144 # make backup if in target manifest
4134 # make backup if in target manifest
4145 # make backup if not in target manifest
4135 # make backup if not in target manifest
4146 (modified, revert, remove, True, True),
4136 (modified, revert, remove, True, True),
4147 (added, revert, remove, True, False),
4137 (added, revert, remove, True, False),
4148 (removed, undelete, None, False, False),
4138 (removed, undelete, None, False, False),
4149 (deleted, revert, remove, False, False),
4139 (deleted, revert, remove, False, False),
4150 )
4140 )
4151
4141
4152 for abs, (rel, exact) in sorted(names.items()):
4142 for abs, (rel, exact) in sorted(names.items()):
4153 mfentry = mf.get(abs)
4143 mfentry = mf.get(abs)
4154 target = repo.wjoin(abs)
4144 target = repo.wjoin(abs)
4155 def handle(xlist, dobackup):
4145 def handle(xlist, dobackup):
4156 xlist[0].append(abs)
4146 xlist[0].append(abs)
4157 if (dobackup and not opts.get('no_backup') and
4147 if (dobackup and not opts.get('no_backup') and
4158 os.path.lexists(target)):
4148 os.path.lexists(target)):
4159 bakname = "%s.orig" % rel
4149 bakname = "%s.orig" % rel
4160 ui.note(_('saving current version of %s as %s\n') %
4150 ui.note(_('saving current version of %s as %s\n') %
4161 (rel, bakname))
4151 (rel, bakname))
4162 if not opts.get('dry_run'):
4152 if not opts.get('dry_run'):
4163 util.rename(target, bakname)
4153 util.rename(target, bakname)
4164 if ui.verbose or not exact:
4154 if ui.verbose or not exact:
4165 msg = xlist[1]
4155 msg = xlist[1]
4166 if not isinstance(msg, basestring):
4156 if not isinstance(msg, basestring):
4167 msg = msg(abs)
4157 msg = msg(abs)
4168 ui.status(msg % rel)
4158 ui.status(msg % rel)
4169 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4159 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4170 if abs not in table:
4160 if abs not in table:
4171 continue
4161 continue
4172 # file has changed in dirstate
4162 # file has changed in dirstate
4173 if mfentry:
4163 if mfentry:
4174 handle(hitlist, backuphit)
4164 handle(hitlist, backuphit)
4175 elif misslist is not None:
4165 elif misslist is not None:
4176 handle(misslist, backupmiss)
4166 handle(misslist, backupmiss)
4177 break
4167 break
4178 else:
4168 else:
4179 if abs not in repo.dirstate:
4169 if abs not in repo.dirstate:
4180 if mfentry:
4170 if mfentry:
4181 handle(add, True)
4171 handle(add, True)
4182 elif exact:
4172 elif exact:
4183 ui.warn(_('file not managed: %s\n') % rel)
4173 ui.warn(_('file not managed: %s\n') % rel)
4184 continue
4174 continue
4185 # file has not changed in dirstate
4175 # file has not changed in dirstate
4186 if node == parent:
4176 if node == parent:
4187 if exact:
4177 if exact:
4188 ui.warn(_('no changes needed to %s\n') % rel)
4178 ui.warn(_('no changes needed to %s\n') % rel)
4189 continue
4179 continue
4190 if pmf is None:
4180 if pmf is None:
4191 # only need parent manifest in this unlikely case,
4181 # only need parent manifest in this unlikely case,
4192 # so do not read by default
4182 # so do not read by default
4193 pmf = repo[parent].manifest()
4183 pmf = repo[parent].manifest()
4194 if abs in pmf:
4184 if abs in pmf:
4195 if mfentry:
4185 if mfentry:
4196 # if version of file is same in parent and target
4186 # if version of file is same in parent and target
4197 # manifests, do nothing
4187 # manifests, do nothing
4198 if (pmf[abs] != mfentry or
4188 if (pmf[abs] != mfentry or
4199 pmf.flags(abs) != mf.flags(abs)):
4189 pmf.flags(abs) != mf.flags(abs)):
4200 handle(revert, False)
4190 handle(revert, False)
4201 else:
4191 else:
4202 handle(remove, False)
4192 handle(remove, False)
4203
4193
4204 if not opts.get('dry_run'):
4194 if not opts.get('dry_run'):
4205 def checkout(f):
4195 def checkout(f):
4206 fc = ctx[f]
4196 fc = ctx[f]
4207 repo.wwrite(f, fc.data(), fc.flags())
4197 repo.wwrite(f, fc.data(), fc.flags())
4208
4198
4209 audit_path = scmutil.pathauditor(repo.root)
4199 audit_path = scmutil.pathauditor(repo.root)
4210 for f in remove[0]:
4200 for f in remove[0]:
4211 if repo.dirstate[f] == 'a':
4201 if repo.dirstate[f] == 'a':
4212 repo.dirstate.forget(f)
4202 repo.dirstate.forget(f)
4213 continue
4203 continue
4214 audit_path(f)
4204 audit_path(f)
4215 try:
4205 try:
4216 util.unlinkpath(repo.wjoin(f))
4206 util.unlinkpath(repo.wjoin(f))
4217 except OSError:
4207 except OSError:
4218 pass
4208 pass
4219 repo.dirstate.remove(f)
4209 repo.dirstate.remove(f)
4220
4210
4221 normal = None
4211 normal = None
4222 if node == parent:
4212 if node == parent:
4223 # We're reverting to our parent. If possible, we'd like status
4213 # We're reverting to our parent. If possible, we'd like status
4224 # to report the file as clean. We have to use normallookup for
4214 # to report the file as clean. We have to use normallookup for
4225 # merges to avoid losing information about merged/dirty files.
4215 # merges to avoid losing information about merged/dirty files.
4226 if p2 != nullid:
4216 if p2 != nullid:
4227 normal = repo.dirstate.normallookup
4217 normal = repo.dirstate.normallookup
4228 else:
4218 else:
4229 normal = repo.dirstate.normal
4219 normal = repo.dirstate.normal
4230 for f in revert[0]:
4220 for f in revert[0]:
4231 checkout(f)
4221 checkout(f)
4232 if normal:
4222 if normal:
4233 normal(f)
4223 normal(f)
4234
4224
4235 for f in add[0]:
4225 for f in add[0]:
4236 checkout(f)
4226 checkout(f)
4237 repo.dirstate.add(f)
4227 repo.dirstate.add(f)
4238
4228
4239 normal = repo.dirstate.normallookup
4229 normal = repo.dirstate.normallookup
4240 if node == parent and p2 == nullid:
4230 if node == parent and p2 == nullid:
4241 normal = repo.dirstate.normal
4231 normal = repo.dirstate.normal
4242 for f in undelete[0]:
4232 for f in undelete[0]:
4243 checkout(f)
4233 checkout(f)
4244 normal(f)
4234 normal(f)
4245
4235
4246 finally:
4236 finally:
4247 wlock.release()
4237 wlock.release()
4248
4238
4249 @command('rollback', dryrunopts)
4239 @command('rollback', dryrunopts)
4250 def rollback(ui, repo, **opts):
4240 def rollback(ui, repo, **opts):
4251 """roll back the last transaction (dangerous)
4241 """roll back the last transaction (dangerous)
4252
4242
4253 This command should be used with care. There is only one level of
4243 This command should be used with care. There is only one level of
4254 rollback, and there is no way to undo a rollback. It will also
4244 rollback, and there is no way to undo a rollback. It will also
4255 restore the dirstate at the time of the last transaction, losing
4245 restore the dirstate at the time of the last transaction, losing
4256 any dirstate changes since that time. This command does not alter
4246 any dirstate changes since that time. This command does not alter
4257 the working directory.
4247 the working directory.
4258
4248
4259 Transactions are used to encapsulate the effects of all commands
4249 Transactions are used to encapsulate the effects of all commands
4260 that create new changesets or propagate existing changesets into a
4250 that create new changesets or propagate existing changesets into a
4261 repository. For example, the following commands are transactional,
4251 repository. For example, the following commands are transactional,
4262 and their effects can be rolled back:
4252 and their effects can be rolled back:
4263
4253
4264 - commit
4254 - commit
4265 - import
4255 - import
4266 - pull
4256 - pull
4267 - push (with this repository as the destination)
4257 - push (with this repository as the destination)
4268 - unbundle
4258 - unbundle
4269
4259
4270 This command is not intended for use on public repositories. Once
4260 This command is not intended for use on public repositories. Once
4271 changes are visible for pull by other users, rolling a transaction
4261 changes are visible for pull by other users, rolling a transaction
4272 back locally is ineffective (someone else may already have pulled
4262 back locally is ineffective (someone else may already have pulled
4273 the changes). Furthermore, a race is possible with readers of the
4263 the changes). Furthermore, a race is possible with readers of the
4274 repository; for example an in-progress pull from the repository
4264 repository; for example an in-progress pull from the repository
4275 may fail if a rollback is performed.
4265 may fail if a rollback is performed.
4276
4266
4277 Returns 0 on success, 1 if no rollback data is available.
4267 Returns 0 on success, 1 if no rollback data is available.
4278 """
4268 """
4279 return repo.rollback(opts.get('dry_run'))
4269 return repo.rollback(opts.get('dry_run'))
4280
4270
4281 @command('root', [])
4271 @command('root', [])
4282 def root(ui, repo):
4272 def root(ui, repo):
4283 """print the root (top) of the current working directory
4273 """print the root (top) of the current working directory
4284
4274
4285 Print the root directory of the current repository.
4275 Print the root directory of the current repository.
4286
4276
4287 Returns 0 on success.
4277 Returns 0 on success.
4288 """
4278 """
4289 ui.write(repo.root + "\n")
4279 ui.write(repo.root + "\n")
4290
4280
4291 @command('^serve',
4281 @command('^serve',
4292 [('A', 'accesslog', '', _('name of access log file to write to'),
4282 [('A', 'accesslog', '', _('name of access log file to write to'),
4293 _('FILE')),
4283 _('FILE')),
4294 ('d', 'daemon', None, _('run server in background')),
4284 ('d', 'daemon', None, _('run server in background')),
4295 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4285 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4296 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4286 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4297 # use string type, then we can check if something was passed
4287 # use string type, then we can check if something was passed
4298 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4288 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4299 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4289 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4300 _('ADDR')),
4290 _('ADDR')),
4301 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4291 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4302 _('PREFIX')),
4292 _('PREFIX')),
4303 ('n', 'name', '',
4293 ('n', 'name', '',
4304 _('name to show in web pages (default: working directory)'), _('NAME')),
4294 _('name to show in web pages (default: working directory)'), _('NAME')),
4305 ('', 'web-conf', '',
4295 ('', 'web-conf', '',
4306 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4296 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4307 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4297 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4308 _('FILE')),
4298 _('FILE')),
4309 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4299 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4310 ('', 'stdio', None, _('for remote clients')),
4300 ('', 'stdio', None, _('for remote clients')),
4311 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4301 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4312 ('', 'style', '', _('template style to use'), _('STYLE')),
4302 ('', 'style', '', _('template style to use'), _('STYLE')),
4313 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4303 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4314 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4304 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4315 _('[OPTION]...'))
4305 _('[OPTION]...'))
4316 def serve(ui, repo, **opts):
4306 def serve(ui, repo, **opts):
4317 """start stand-alone webserver
4307 """start stand-alone webserver
4318
4308
4319 Start a local HTTP repository browser and pull server. You can use
4309 Start a local HTTP repository browser and pull server. You can use
4320 this for ad-hoc sharing and browsing of repositories. It is
4310 this for ad-hoc sharing and browsing of repositories. It is
4321 recommended to use a real web server to serve a repository for
4311 recommended to use a real web server to serve a repository for
4322 longer periods of time.
4312 longer periods of time.
4323
4313
4324 Please note that the server does not implement access control.
4314 Please note that the server does not implement access control.
4325 This means that, by default, anybody can read from the server and
4315 This means that, by default, anybody can read from the server and
4326 nobody can write to it by default. Set the ``web.allow_push``
4316 nobody can write to it by default. Set the ``web.allow_push``
4327 option to ``*`` to allow everybody to push to the server. You
4317 option to ``*`` to allow everybody to push to the server. You
4328 should use a real web server if you need to authenticate users.
4318 should use a real web server if you need to authenticate users.
4329
4319
4330 By default, the server logs accesses to stdout and errors to
4320 By default, the server logs accesses to stdout and errors to
4331 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4321 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4332 files.
4322 files.
4333
4323
4334 To have the server choose a free port number to listen on, specify
4324 To have the server choose a free port number to listen on, specify
4335 a port number of 0; in this case, the server will print the port
4325 a port number of 0; in this case, the server will print the port
4336 number it uses.
4326 number it uses.
4337
4327
4338 Returns 0 on success.
4328 Returns 0 on success.
4339 """
4329 """
4340
4330
4341 if opts["stdio"]:
4331 if opts["stdio"]:
4342 if repo is None:
4332 if repo is None:
4343 raise error.RepoError(_("There is no Mercurial repository here"
4333 raise error.RepoError(_("There is no Mercurial repository here"
4344 " (.hg not found)"))
4334 " (.hg not found)"))
4345 s = sshserver.sshserver(ui, repo)
4335 s = sshserver.sshserver(ui, repo)
4346 s.serve_forever()
4336 s.serve_forever()
4347
4337
4348 # this way we can check if something was given in the command-line
4338 # this way we can check if something was given in the command-line
4349 if opts.get('port'):
4339 if opts.get('port'):
4350 opts['port'] = util.getport(opts.get('port'))
4340 opts['port'] = util.getport(opts.get('port'))
4351
4341
4352 baseui = repo and repo.baseui or ui
4342 baseui = repo and repo.baseui or ui
4353 optlist = ("name templates style address port prefix ipv6"
4343 optlist = ("name templates style address port prefix ipv6"
4354 " accesslog errorlog certificate encoding")
4344 " accesslog errorlog certificate encoding")
4355 for o in optlist.split():
4345 for o in optlist.split():
4356 val = opts.get(o, '')
4346 val = opts.get(o, '')
4357 if val in (None, ''): # should check against default options instead
4347 if val in (None, ''): # should check against default options instead
4358 continue
4348 continue
4359 baseui.setconfig("web", o, val)
4349 baseui.setconfig("web", o, val)
4360 if repo and repo.ui != baseui:
4350 if repo and repo.ui != baseui:
4361 repo.ui.setconfig("web", o, val)
4351 repo.ui.setconfig("web", o, val)
4362
4352
4363 o = opts.get('web_conf') or opts.get('webdir_conf')
4353 o = opts.get('web_conf') or opts.get('webdir_conf')
4364 if not o:
4354 if not o:
4365 if not repo:
4355 if not repo:
4366 raise error.RepoError(_("There is no Mercurial repository"
4356 raise error.RepoError(_("There is no Mercurial repository"
4367 " here (.hg not found)"))
4357 " here (.hg not found)"))
4368 o = repo.root
4358 o = repo.root
4369
4359
4370 app = hgweb.hgweb(o, baseui=ui)
4360 app = hgweb.hgweb(o, baseui=ui)
4371
4361
4372 class service(object):
4362 class service(object):
4373 def init(self):
4363 def init(self):
4374 util.setsignalhandler()
4364 util.setsignalhandler()
4375 self.httpd = hgweb.server.create_server(ui, app)
4365 self.httpd = hgweb.server.create_server(ui, app)
4376
4366
4377 if opts['port'] and not ui.verbose:
4367 if opts['port'] and not ui.verbose:
4378 return
4368 return
4379
4369
4380 if self.httpd.prefix:
4370 if self.httpd.prefix:
4381 prefix = self.httpd.prefix.strip('/') + '/'
4371 prefix = self.httpd.prefix.strip('/') + '/'
4382 else:
4372 else:
4383 prefix = ''
4373 prefix = ''
4384
4374
4385 port = ':%d' % self.httpd.port
4375 port = ':%d' % self.httpd.port
4386 if port == ':80':
4376 if port == ':80':
4387 port = ''
4377 port = ''
4388
4378
4389 bindaddr = self.httpd.addr
4379 bindaddr = self.httpd.addr
4390 if bindaddr == '0.0.0.0':
4380 if bindaddr == '0.0.0.0':
4391 bindaddr = '*'
4381 bindaddr = '*'
4392 elif ':' in bindaddr: # IPv6
4382 elif ':' in bindaddr: # IPv6
4393 bindaddr = '[%s]' % bindaddr
4383 bindaddr = '[%s]' % bindaddr
4394
4384
4395 fqaddr = self.httpd.fqaddr
4385 fqaddr = self.httpd.fqaddr
4396 if ':' in fqaddr:
4386 if ':' in fqaddr:
4397 fqaddr = '[%s]' % fqaddr
4387 fqaddr = '[%s]' % fqaddr
4398 if opts['port']:
4388 if opts['port']:
4399 write = ui.status
4389 write = ui.status
4400 else:
4390 else:
4401 write = ui.write
4391 write = ui.write
4402 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4392 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4403 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4393 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4404
4394
4405 def run(self):
4395 def run(self):
4406 self.httpd.serve_forever()
4396 self.httpd.serve_forever()
4407
4397
4408 service = service()
4398 service = service()
4409
4399
4410 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4400 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4411
4401
4412 @command('showconfig|debugconfig',
4402 @command('showconfig|debugconfig',
4413 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4403 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4414 _('[-u] [NAME]...'))
4404 _('[-u] [NAME]...'))
4415 def showconfig(ui, repo, *values, **opts):
4405 def showconfig(ui, repo, *values, **opts):
4416 """show combined config settings from all hgrc files
4406 """show combined config settings from all hgrc files
4417
4407
4418 With no arguments, print names and values of all config items.
4408 With no arguments, print names and values of all config items.
4419
4409
4420 With one argument of the form section.name, print just the value
4410 With one argument of the form section.name, print just the value
4421 of that config item.
4411 of that config item.
4422
4412
4423 With multiple arguments, print names and values of all config
4413 With multiple arguments, print names and values of all config
4424 items with matching section names.
4414 items with matching section names.
4425
4415
4426 With --debug, the source (filename and line number) is printed
4416 With --debug, the source (filename and line number) is printed
4427 for each config item.
4417 for each config item.
4428
4418
4429 Returns 0 on success.
4419 Returns 0 on success.
4430 """
4420 """
4431
4421
4432 for f in scmutil.rcpath():
4422 for f in scmutil.rcpath():
4433 ui.debug(_('read config from: %s\n') % f)
4423 ui.debug(_('read config from: %s\n') % f)
4434 untrusted = bool(opts.get('untrusted'))
4424 untrusted = bool(opts.get('untrusted'))
4435 if values:
4425 if values:
4436 sections = [v for v in values if '.' not in v]
4426 sections = [v for v in values if '.' not in v]
4437 items = [v for v in values if '.' in v]
4427 items = [v for v in values if '.' in v]
4438 if len(items) > 1 or items and sections:
4428 if len(items) > 1 or items and sections:
4439 raise util.Abort(_('only one config item permitted'))
4429 raise util.Abort(_('only one config item permitted'))
4440 for section, name, value in ui.walkconfig(untrusted=untrusted):
4430 for section, name, value in ui.walkconfig(untrusted=untrusted):
4441 value = str(value).replace('\n', '\\n')
4431 value = str(value).replace('\n', '\\n')
4442 sectname = section + '.' + name
4432 sectname = section + '.' + name
4443 if values:
4433 if values:
4444 for v in values:
4434 for v in values:
4445 if v == section:
4435 if v == section:
4446 ui.debug('%s: ' %
4436 ui.debug('%s: ' %
4447 ui.configsource(section, name, untrusted))
4437 ui.configsource(section, name, untrusted))
4448 ui.write('%s=%s\n' % (sectname, value))
4438 ui.write('%s=%s\n' % (sectname, value))
4449 elif v == sectname:
4439 elif v == sectname:
4450 ui.debug('%s: ' %
4440 ui.debug('%s: ' %
4451 ui.configsource(section, name, untrusted))
4441 ui.configsource(section, name, untrusted))
4452 ui.write(value, '\n')
4442 ui.write(value, '\n')
4453 else:
4443 else:
4454 ui.debug('%s: ' %
4444 ui.debug('%s: ' %
4455 ui.configsource(section, name, untrusted))
4445 ui.configsource(section, name, untrusted))
4456 ui.write('%s=%s\n' % (sectname, value))
4446 ui.write('%s=%s\n' % (sectname, value))
4457
4447
4458 @command('^status|st',
4448 @command('^status|st',
4459 [('A', 'all', None, _('show status of all files')),
4449 [('A', 'all', None, _('show status of all files')),
4460 ('m', 'modified', None, _('show only modified files')),
4450 ('m', 'modified', None, _('show only modified files')),
4461 ('a', 'added', None, _('show only added files')),
4451 ('a', 'added', None, _('show only added files')),
4462 ('r', 'removed', None, _('show only removed files')),
4452 ('r', 'removed', None, _('show only removed files')),
4463 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4453 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4464 ('c', 'clean', None, _('show only files without changes')),
4454 ('c', 'clean', None, _('show only files without changes')),
4465 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4455 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4466 ('i', 'ignored', None, _('show only ignored files')),
4456 ('i', 'ignored', None, _('show only ignored files')),
4467 ('n', 'no-status', None, _('hide status prefix')),
4457 ('n', 'no-status', None, _('hide status prefix')),
4468 ('C', 'copies', None, _('show source of copied files')),
4458 ('C', 'copies', None, _('show source of copied files')),
4469 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4459 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4470 ('', 'rev', [], _('show difference from revision'), _('REV')),
4460 ('', 'rev', [], _('show difference from revision'), _('REV')),
4471 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4461 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4472 ] + walkopts + subrepoopts,
4462 ] + walkopts + subrepoopts,
4473 _('[OPTION]... [FILE]...'))
4463 _('[OPTION]... [FILE]...'))
4474 def status(ui, repo, *pats, **opts):
4464 def status(ui, repo, *pats, **opts):
4475 """show changed files in the working directory
4465 """show changed files in the working directory
4476
4466
4477 Show status of files in the repository. If names are given, only
4467 Show status of files in the repository. If names are given, only
4478 files that match are shown. Files that are clean or ignored or
4468 files that match are shown. Files that are clean or ignored or
4479 the source of a copy/move operation, are not listed unless
4469 the source of a copy/move operation, are not listed unless
4480 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4470 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4481 Unless options described with "show only ..." are given, the
4471 Unless options described with "show only ..." are given, the
4482 options -mardu are used.
4472 options -mardu are used.
4483
4473
4484 Option -q/--quiet hides untracked (unknown and ignored) files
4474 Option -q/--quiet hides untracked (unknown and ignored) files
4485 unless explicitly requested with -u/--unknown or -i/--ignored.
4475 unless explicitly requested with -u/--unknown or -i/--ignored.
4486
4476
4487 .. note::
4477 .. note::
4488 status may appear to disagree with diff if permissions have
4478 status may appear to disagree with diff if permissions have
4489 changed or a merge has occurred. The standard diff format does
4479 changed or a merge has occurred. The standard diff format does
4490 not report permission changes and diff only reports changes
4480 not report permission changes and diff only reports changes
4491 relative to one merge parent.
4481 relative to one merge parent.
4492
4482
4493 If one revision is given, it is used as the base revision.
4483 If one revision is given, it is used as the base revision.
4494 If two revisions are given, the differences between them are
4484 If two revisions are given, the differences between them are
4495 shown. The --change option can also be used as a shortcut to list
4485 shown. The --change option can also be used as a shortcut to list
4496 the changed files of a revision from its first parent.
4486 the changed files of a revision from its first parent.
4497
4487
4498 The codes used to show the status of files are::
4488 The codes used to show the status of files are::
4499
4489
4500 M = modified
4490 M = modified
4501 A = added
4491 A = added
4502 R = removed
4492 R = removed
4503 C = clean
4493 C = clean
4504 ! = missing (deleted by non-hg command, but still tracked)
4494 ! = missing (deleted by non-hg command, but still tracked)
4505 ? = not tracked
4495 ? = not tracked
4506 I = ignored
4496 I = ignored
4507 = origin of the previous file listed as A (added)
4497 = origin of the previous file listed as A (added)
4508
4498
4509 Returns 0 on success.
4499 Returns 0 on success.
4510 """
4500 """
4511
4501
4512 revs = opts.get('rev')
4502 revs = opts.get('rev')
4513 change = opts.get('change')
4503 change = opts.get('change')
4514
4504
4515 if revs and change:
4505 if revs and change:
4516 msg = _('cannot specify --rev and --change at the same time')
4506 msg = _('cannot specify --rev and --change at the same time')
4517 raise util.Abort(msg)
4507 raise util.Abort(msg)
4518 elif change:
4508 elif change:
4519 node2 = repo.lookup(change)
4509 node2 = repo.lookup(change)
4520 node1 = repo[node2].p1().node()
4510 node1 = repo[node2].p1().node()
4521 else:
4511 else:
4522 node1, node2 = scmutil.revpair(repo, revs)
4512 node1, node2 = scmutil.revpair(repo, revs)
4523
4513
4524 cwd = (pats and repo.getcwd()) or ''
4514 cwd = (pats and repo.getcwd()) or ''
4525 end = opts.get('print0') and '\0' or '\n'
4515 end = opts.get('print0') and '\0' or '\n'
4526 copy = {}
4516 copy = {}
4527 states = 'modified added removed deleted unknown ignored clean'.split()
4517 states = 'modified added removed deleted unknown ignored clean'.split()
4528 show = [k for k in states if opts.get(k)]
4518 show = [k for k in states if opts.get(k)]
4529 if opts.get('all'):
4519 if opts.get('all'):
4530 show += ui.quiet and (states[:4] + ['clean']) or states
4520 show += ui.quiet and (states[:4] + ['clean']) or states
4531 if not show:
4521 if not show:
4532 show = ui.quiet and states[:4] or states[:5]
4522 show = ui.quiet and states[:4] or states[:5]
4533
4523
4534 stat = repo.status(node1, node2, scmutil.match(repo, pats, opts),
4524 stat = repo.status(node1, node2, scmutil.match(repo, pats, opts),
4535 'ignored' in show, 'clean' in show, 'unknown' in show,
4525 'ignored' in show, 'clean' in show, 'unknown' in show,
4536 opts.get('subrepos'))
4526 opts.get('subrepos'))
4537 changestates = zip(states, 'MAR!?IC', stat)
4527 changestates = zip(states, 'MAR!?IC', stat)
4538
4528
4539 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4529 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4540 ctxn = repo[nullid]
4530 ctxn = repo[nullid]
4541 ctx1 = repo[node1]
4531 ctx1 = repo[node1]
4542 ctx2 = repo[node2]
4532 ctx2 = repo[node2]
4543 added = stat[1]
4533 added = stat[1]
4544 if node2 is None:
4534 if node2 is None:
4545 added = stat[0] + stat[1] # merged?
4535 added = stat[0] + stat[1] # merged?
4546
4536
4547 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4537 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4548 if k in added:
4538 if k in added:
4549 copy[k] = v
4539 copy[k] = v
4550 elif v in added:
4540 elif v in added:
4551 copy[v] = k
4541 copy[v] = k
4552
4542
4553 for state, char, files in changestates:
4543 for state, char, files in changestates:
4554 if state in show:
4544 if state in show:
4555 format = "%s %%s%s" % (char, end)
4545 format = "%s %%s%s" % (char, end)
4556 if opts.get('no_status'):
4546 if opts.get('no_status'):
4557 format = "%%s%s" % end
4547 format = "%%s%s" % end
4558
4548
4559 for f in files:
4549 for f in files:
4560 ui.write(format % repo.pathto(f, cwd),
4550 ui.write(format % repo.pathto(f, cwd),
4561 label='status.' + state)
4551 label='status.' + state)
4562 if f in copy:
4552 if f in copy:
4563 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4553 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4564 label='status.copied')
4554 label='status.copied')
4565
4555
4566 @command('^summary|sum',
4556 @command('^summary|sum',
4567 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4557 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4568 def summary(ui, repo, **opts):
4558 def summary(ui, repo, **opts):
4569 """summarize working directory state
4559 """summarize working directory state
4570
4560
4571 This generates a brief summary of the working directory state,
4561 This generates a brief summary of the working directory state,
4572 including parents, branch, commit status, and available updates.
4562 including parents, branch, commit status, and available updates.
4573
4563
4574 With the --remote option, this will check the default paths for
4564 With the --remote option, this will check the default paths for
4575 incoming and outgoing changes. This can be time-consuming.
4565 incoming and outgoing changes. This can be time-consuming.
4576
4566
4577 Returns 0 on success.
4567 Returns 0 on success.
4578 """
4568 """
4579
4569
4580 ctx = repo[None]
4570 ctx = repo[None]
4581 parents = ctx.parents()
4571 parents = ctx.parents()
4582 pnode = parents[0].node()
4572 pnode = parents[0].node()
4583
4573
4584 for p in parents:
4574 for p in parents:
4585 # label with log.changeset (instead of log.parent) since this
4575 # label with log.changeset (instead of log.parent) since this
4586 # shows a working directory parent *changeset*:
4576 # shows a working directory parent *changeset*:
4587 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4577 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4588 label='log.changeset')
4578 label='log.changeset')
4589 ui.write(' '.join(p.tags()), label='log.tag')
4579 ui.write(' '.join(p.tags()), label='log.tag')
4590 if p.bookmarks():
4580 if p.bookmarks():
4591 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
4581 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
4592 if p.rev() == -1:
4582 if p.rev() == -1:
4593 if not len(repo):
4583 if not len(repo):
4594 ui.write(_(' (empty repository)'))
4584 ui.write(_(' (empty repository)'))
4595 else:
4585 else:
4596 ui.write(_(' (no revision checked out)'))
4586 ui.write(_(' (no revision checked out)'))
4597 ui.write('\n')
4587 ui.write('\n')
4598 if p.description():
4588 if p.description():
4599 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4589 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4600 label='log.summary')
4590 label='log.summary')
4601
4591
4602 branch = ctx.branch()
4592 branch = ctx.branch()
4603 bheads = repo.branchheads(branch)
4593 bheads = repo.branchheads(branch)
4604 m = _('branch: %s\n') % branch
4594 m = _('branch: %s\n') % branch
4605 if branch != 'default':
4595 if branch != 'default':
4606 ui.write(m, label='log.branch')
4596 ui.write(m, label='log.branch')
4607 else:
4597 else:
4608 ui.status(m, label='log.branch')
4598 ui.status(m, label='log.branch')
4609
4599
4610 st = list(repo.status(unknown=True))[:6]
4600 st = list(repo.status(unknown=True))[:6]
4611
4601
4612 c = repo.dirstate.copies()
4602 c = repo.dirstate.copies()
4613 copied, renamed = [], []
4603 copied, renamed = [], []
4614 for d, s in c.iteritems():
4604 for d, s in c.iteritems():
4615 if s in st[2]:
4605 if s in st[2]:
4616 st[2].remove(s)
4606 st[2].remove(s)
4617 renamed.append(d)
4607 renamed.append(d)
4618 else:
4608 else:
4619 copied.append(d)
4609 copied.append(d)
4620 if d in st[1]:
4610 if d in st[1]:
4621 st[1].remove(d)
4611 st[1].remove(d)
4622 st.insert(3, renamed)
4612 st.insert(3, renamed)
4623 st.insert(4, copied)
4613 st.insert(4, copied)
4624
4614
4625 ms = mergemod.mergestate(repo)
4615 ms = mergemod.mergestate(repo)
4626 st.append([f for f in ms if ms[f] == 'u'])
4616 st.append([f for f in ms if ms[f] == 'u'])
4627
4617
4628 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4618 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4629 st.append(subs)
4619 st.append(subs)
4630
4620
4631 labels = [ui.label(_('%d modified'), 'status.modified'),
4621 labels = [ui.label(_('%d modified'), 'status.modified'),
4632 ui.label(_('%d added'), 'status.added'),
4622 ui.label(_('%d added'), 'status.added'),
4633 ui.label(_('%d removed'), 'status.removed'),
4623 ui.label(_('%d removed'), 'status.removed'),
4634 ui.label(_('%d renamed'), 'status.copied'),
4624 ui.label(_('%d renamed'), 'status.copied'),
4635 ui.label(_('%d copied'), 'status.copied'),
4625 ui.label(_('%d copied'), 'status.copied'),
4636 ui.label(_('%d deleted'), 'status.deleted'),
4626 ui.label(_('%d deleted'), 'status.deleted'),
4637 ui.label(_('%d unknown'), 'status.unknown'),
4627 ui.label(_('%d unknown'), 'status.unknown'),
4638 ui.label(_('%d ignored'), 'status.ignored'),
4628 ui.label(_('%d ignored'), 'status.ignored'),
4639 ui.label(_('%d unresolved'), 'resolve.unresolved'),
4629 ui.label(_('%d unresolved'), 'resolve.unresolved'),
4640 ui.label(_('%d subrepos'), 'status.modified')]
4630 ui.label(_('%d subrepos'), 'status.modified')]
4641 t = []
4631 t = []
4642 for s, l in zip(st, labels):
4632 for s, l in zip(st, labels):
4643 if s:
4633 if s:
4644 t.append(l % len(s))
4634 t.append(l % len(s))
4645
4635
4646 t = ', '.join(t)
4636 t = ', '.join(t)
4647 cleanworkdir = False
4637 cleanworkdir = False
4648
4638
4649 if len(parents) > 1:
4639 if len(parents) > 1:
4650 t += _(' (merge)')
4640 t += _(' (merge)')
4651 elif branch != parents[0].branch():
4641 elif branch != parents[0].branch():
4652 t += _(' (new branch)')
4642 t += _(' (new branch)')
4653 elif (parents[0].extra().get('close') and
4643 elif (parents[0].extra().get('close') and
4654 pnode in repo.branchheads(branch, closed=True)):
4644 pnode in repo.branchheads(branch, closed=True)):
4655 t += _(' (head closed)')
4645 t += _(' (head closed)')
4656 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4646 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4657 t += _(' (clean)')
4647 t += _(' (clean)')
4658 cleanworkdir = True
4648 cleanworkdir = True
4659 elif pnode not in bheads:
4649 elif pnode not in bheads:
4660 t += _(' (new branch head)')
4650 t += _(' (new branch head)')
4661
4651
4662 if cleanworkdir:
4652 if cleanworkdir:
4663 ui.status(_('commit: %s\n') % t.strip())
4653 ui.status(_('commit: %s\n') % t.strip())
4664 else:
4654 else:
4665 ui.write(_('commit: %s\n') % t.strip())
4655 ui.write(_('commit: %s\n') % t.strip())
4666
4656
4667 # all ancestors of branch heads - all ancestors of parent = new csets
4657 # all ancestors of branch heads - all ancestors of parent = new csets
4668 new = [0] * len(repo)
4658 new = [0] * len(repo)
4669 cl = repo.changelog
4659 cl = repo.changelog
4670 for a in [cl.rev(n) for n in bheads]:
4660 for a in [cl.rev(n) for n in bheads]:
4671 new[a] = 1
4661 new[a] = 1
4672 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
4662 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
4673 new[a] = 1
4663 new[a] = 1
4674 for a in [p.rev() for p in parents]:
4664 for a in [p.rev() for p in parents]:
4675 if a >= 0:
4665 if a >= 0:
4676 new[a] = 0
4666 new[a] = 0
4677 for a in cl.ancestors(*[p.rev() for p in parents]):
4667 for a in cl.ancestors(*[p.rev() for p in parents]):
4678 new[a] = 0
4668 new[a] = 0
4679 new = sum(new)
4669 new = sum(new)
4680
4670
4681 if new == 0:
4671 if new == 0:
4682 ui.status(_('update: (current)\n'))
4672 ui.status(_('update: (current)\n'))
4683 elif pnode not in bheads:
4673 elif pnode not in bheads:
4684 ui.write(_('update: %d new changesets (update)\n') % new)
4674 ui.write(_('update: %d new changesets (update)\n') % new)
4685 else:
4675 else:
4686 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4676 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4687 (new, len(bheads)))
4677 (new, len(bheads)))
4688
4678
4689 if opts.get('remote'):
4679 if opts.get('remote'):
4690 t = []
4680 t = []
4691 source, branches = hg.parseurl(ui.expandpath('default'))
4681 source, branches = hg.parseurl(ui.expandpath('default'))
4692 other = hg.repository(hg.remoteui(repo, {}), source)
4682 other = hg.repository(hg.remoteui(repo, {}), source)
4693 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4683 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4694 ui.debug('comparing with %s\n' % util.hidepassword(source))
4684 ui.debug('comparing with %s\n' % util.hidepassword(source))
4695 repo.ui.pushbuffer()
4685 repo.ui.pushbuffer()
4696 commoninc = discovery.findcommonincoming(repo, other)
4686 commoninc = discovery.findcommonincoming(repo, other)
4697 _common, incoming, _rheads = commoninc
4687 _common, incoming, _rheads = commoninc
4698 repo.ui.popbuffer()
4688 repo.ui.popbuffer()
4699 if incoming:
4689 if incoming:
4700 t.append(_('1 or more incoming'))
4690 t.append(_('1 or more incoming'))
4701
4691
4702 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4692 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4703 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4693 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4704 if source != dest:
4694 if source != dest:
4705 other = hg.repository(hg.remoteui(repo, {}), dest)
4695 other = hg.repository(hg.remoteui(repo, {}), dest)
4706 commoninc = None
4696 commoninc = None
4707 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4697 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4708 repo.ui.pushbuffer()
4698 repo.ui.pushbuffer()
4709 common, outheads = discovery.findcommonoutgoing(repo, other,
4699 common, outheads = discovery.findcommonoutgoing(repo, other,
4710 commoninc=commoninc)
4700 commoninc=commoninc)
4711 repo.ui.popbuffer()
4701 repo.ui.popbuffer()
4712 o = repo.changelog.findmissing(common=common, heads=outheads)
4702 o = repo.changelog.findmissing(common=common, heads=outheads)
4713 if o:
4703 if o:
4714 t.append(_('%d outgoing') % len(o))
4704 t.append(_('%d outgoing') % len(o))
4715 if 'bookmarks' in other.listkeys('namespaces'):
4705 if 'bookmarks' in other.listkeys('namespaces'):
4716 lmarks = repo.listkeys('bookmarks')
4706 lmarks = repo.listkeys('bookmarks')
4717 rmarks = other.listkeys('bookmarks')
4707 rmarks = other.listkeys('bookmarks')
4718 diff = set(rmarks) - set(lmarks)
4708 diff = set(rmarks) - set(lmarks)
4719 if len(diff) > 0:
4709 if len(diff) > 0:
4720 t.append(_('%d incoming bookmarks') % len(diff))
4710 t.append(_('%d incoming bookmarks') % len(diff))
4721 diff = set(lmarks) - set(rmarks)
4711 diff = set(lmarks) - set(rmarks)
4722 if len(diff) > 0:
4712 if len(diff) > 0:
4723 t.append(_('%d outgoing bookmarks') % len(diff))
4713 t.append(_('%d outgoing bookmarks') % len(diff))
4724
4714
4725 if t:
4715 if t:
4726 ui.write(_('remote: %s\n') % (', '.join(t)))
4716 ui.write(_('remote: %s\n') % (', '.join(t)))
4727 else:
4717 else:
4728 ui.status(_('remote: (synced)\n'))
4718 ui.status(_('remote: (synced)\n'))
4729
4719
4730 @command('tag',
4720 @command('tag',
4731 [('f', 'force', None, _('force tag')),
4721 [('f', 'force', None, _('force tag')),
4732 ('l', 'local', None, _('make the tag local')),
4722 ('l', 'local', None, _('make the tag local')),
4733 ('r', 'rev', '', _('revision to tag'), _('REV')),
4723 ('r', 'rev', '', _('revision to tag'), _('REV')),
4734 ('', 'remove', None, _('remove a tag')),
4724 ('', 'remove', None, _('remove a tag')),
4735 # -l/--local is already there, commitopts cannot be used
4725 # -l/--local is already there, commitopts cannot be used
4736 ('e', 'edit', None, _('edit commit message')),
4726 ('e', 'edit', None, _('edit commit message')),
4737 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
4727 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
4738 ] + commitopts2,
4728 ] + commitopts2,
4739 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
4729 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
4740 def tag(ui, repo, name1, *names, **opts):
4730 def tag(ui, repo, name1, *names, **opts):
4741 """add one or more tags for the current or given revision
4731 """add one or more tags for the current or given revision
4742
4732
4743 Name a particular revision using <name>.
4733 Name a particular revision using <name>.
4744
4734
4745 Tags are used to name particular revisions of the repository and are
4735 Tags are used to name particular revisions of the repository and are
4746 very useful to compare different revisions, to go back to significant
4736 very useful to compare different revisions, to go back to significant
4747 earlier versions or to mark branch points as releases, etc. Changing
4737 earlier versions or to mark branch points as releases, etc. Changing
4748 an existing tag is normally disallowed; use -f/--force to override.
4738 an existing tag is normally disallowed; use -f/--force to override.
4749
4739
4750 If no revision is given, the parent of the working directory is
4740 If no revision is given, the parent of the working directory is
4751 used, or tip if no revision is checked out.
4741 used, or tip if no revision is checked out.
4752
4742
4753 To facilitate version control, distribution, and merging of tags,
4743 To facilitate version control, distribution, and merging of tags,
4754 they are stored as a file named ".hgtags" which is managed similarly
4744 they are stored as a file named ".hgtags" which is managed similarly
4755 to other project files and can be hand-edited if necessary. This
4745 to other project files and can be hand-edited if necessary. This
4756 also means that tagging creates a new commit. The file
4746 also means that tagging creates a new commit. The file
4757 ".hg/localtags" is used for local tags (not shared among
4747 ".hg/localtags" is used for local tags (not shared among
4758 repositories).
4748 repositories).
4759
4749
4760 Tag commits are usually made at the head of a branch. If the parent
4750 Tag commits are usually made at the head of a branch. If the parent
4761 of the working directory is not a branch head, :hg:`tag` aborts; use
4751 of the working directory is not a branch head, :hg:`tag` aborts; use
4762 -f/--force to force the tag commit to be based on a non-head
4752 -f/--force to force the tag commit to be based on a non-head
4763 changeset.
4753 changeset.
4764
4754
4765 See :hg:`help dates` for a list of formats valid for -d/--date.
4755 See :hg:`help dates` for a list of formats valid for -d/--date.
4766
4756
4767 Since tag names have priority over branch names during revision
4757 Since tag names have priority over branch names during revision
4768 lookup, using an existing branch name as a tag name is discouraged.
4758 lookup, using an existing branch name as a tag name is discouraged.
4769
4759
4770 Returns 0 on success.
4760 Returns 0 on success.
4771 """
4761 """
4772
4762
4773 rev_ = "."
4763 rev_ = "."
4774 names = [t.strip() for t in (name1,) + names]
4764 names = [t.strip() for t in (name1,) + names]
4775 if len(names) != len(set(names)):
4765 if len(names) != len(set(names)):
4776 raise util.Abort(_('tag names must be unique'))
4766 raise util.Abort(_('tag names must be unique'))
4777 for n in names:
4767 for n in names:
4778 if n in ['tip', '.', 'null']:
4768 if n in ['tip', '.', 'null']:
4779 raise util.Abort(_("the name '%s' is reserved") % n)
4769 raise util.Abort(_("the name '%s' is reserved") % n)
4780 if not n:
4770 if not n:
4781 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4771 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4782 if opts.get('rev') and opts.get('remove'):
4772 if opts.get('rev') and opts.get('remove'):
4783 raise util.Abort(_("--rev and --remove are incompatible"))
4773 raise util.Abort(_("--rev and --remove are incompatible"))
4784 if opts.get('rev'):
4774 if opts.get('rev'):
4785 rev_ = opts['rev']
4775 rev_ = opts['rev']
4786 message = opts.get('message')
4776 message = opts.get('message')
4787 if opts.get('remove'):
4777 if opts.get('remove'):
4788 expectedtype = opts.get('local') and 'local' or 'global'
4778 expectedtype = opts.get('local') and 'local' or 'global'
4789 for n in names:
4779 for n in names:
4790 if not repo.tagtype(n):
4780 if not repo.tagtype(n):
4791 raise util.Abort(_("tag '%s' does not exist") % n)
4781 raise util.Abort(_("tag '%s' does not exist") % n)
4792 if repo.tagtype(n) != expectedtype:
4782 if repo.tagtype(n) != expectedtype:
4793 if expectedtype == 'global':
4783 if expectedtype == 'global':
4794 raise util.Abort(_("tag '%s' is not a global tag") % n)
4784 raise util.Abort(_("tag '%s' is not a global tag") % n)
4795 else:
4785 else:
4796 raise util.Abort(_("tag '%s' is not a local tag") % n)
4786 raise util.Abort(_("tag '%s' is not a local tag") % n)
4797 rev_ = nullid
4787 rev_ = nullid
4798 if not message:
4788 if not message:
4799 # we don't translate commit messages
4789 # we don't translate commit messages
4800 message = 'Removed tag %s' % ', '.join(names)
4790 message = 'Removed tag %s' % ', '.join(names)
4801 elif not opts.get('force'):
4791 elif not opts.get('force'):
4802 for n in names:
4792 for n in names:
4803 if n in repo.tags():
4793 if n in repo.tags():
4804 raise util.Abort(_("tag '%s' already exists "
4794 raise util.Abort(_("tag '%s' already exists "
4805 "(use -f to force)") % n)
4795 "(use -f to force)") % n)
4806 if not opts.get('local'):
4796 if not opts.get('local'):
4807 p1, p2 = repo.dirstate.parents()
4797 p1, p2 = repo.dirstate.parents()
4808 if p2 != nullid:
4798 if p2 != nullid:
4809 raise util.Abort(_('uncommitted merge'))
4799 raise util.Abort(_('uncommitted merge'))
4810 bheads = repo.branchheads()
4800 bheads = repo.branchheads()
4811 if not opts.get('force') and bheads and p1 not in bheads:
4801 if not opts.get('force') and bheads and p1 not in bheads:
4812 raise util.Abort(_('not at a branch head (use -f to force)'))
4802 raise util.Abort(_('not at a branch head (use -f to force)'))
4813 r = scmutil.revsingle(repo, rev_).node()
4803 r = scmutil.revsingle(repo, rev_).node()
4814
4804
4815 if not message:
4805 if not message:
4816 # we don't translate commit messages
4806 # we don't translate commit messages
4817 message = ('Added tag %s for changeset %s' %
4807 message = ('Added tag %s for changeset %s' %
4818 (', '.join(names), short(r)))
4808 (', '.join(names), short(r)))
4819
4809
4820 date = opts.get('date')
4810 date = opts.get('date')
4821 if date:
4811 if date:
4822 date = util.parsedate(date)
4812 date = util.parsedate(date)
4823
4813
4824 if opts.get('edit'):
4814 if opts.get('edit'):
4825 message = ui.edit(message, ui.username())
4815 message = ui.edit(message, ui.username())
4826
4816
4827 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4817 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4828
4818
4829 @command('tags', [], '')
4819 @command('tags', [], '')
4830 def tags(ui, repo):
4820 def tags(ui, repo):
4831 """list repository tags
4821 """list repository tags
4832
4822
4833 This lists both regular and local tags. When the -v/--verbose
4823 This lists both regular and local tags. When the -v/--verbose
4834 switch is used, a third column "local" is printed for local tags.
4824 switch is used, a third column "local" is printed for local tags.
4835
4825
4836 Returns 0 on success.
4826 Returns 0 on success.
4837 """
4827 """
4838
4828
4839 hexfunc = ui.debugflag and hex or short
4829 hexfunc = ui.debugflag and hex or short
4840 tagtype = ""
4830 tagtype = ""
4841
4831
4842 for t, n in reversed(repo.tagslist()):
4832 for t, n in reversed(repo.tagslist()):
4843 if ui.quiet:
4833 if ui.quiet:
4844 ui.write("%s\n" % t)
4834 ui.write("%s\n" % t)
4845 continue
4835 continue
4846
4836
4847 hn = hexfunc(n)
4837 hn = hexfunc(n)
4848 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4838 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4849 spaces = " " * (30 - encoding.colwidth(t))
4839 spaces = " " * (30 - encoding.colwidth(t))
4850
4840
4851 if ui.verbose:
4841 if ui.verbose:
4852 if repo.tagtype(t) == 'local':
4842 if repo.tagtype(t) == 'local':
4853 tagtype = " local"
4843 tagtype = " local"
4854 else:
4844 else:
4855 tagtype = ""
4845 tagtype = ""
4856 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4846 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4857
4847
4858 @command('tip',
4848 @command('tip',
4859 [('p', 'patch', None, _('show patch')),
4849 [('p', 'patch', None, _('show patch')),
4860 ('g', 'git', None, _('use git extended diff format')),
4850 ('g', 'git', None, _('use git extended diff format')),
4861 ] + templateopts,
4851 ] + templateopts,
4862 _('[-p] [-g]'))
4852 _('[-p] [-g]'))
4863 def tip(ui, repo, **opts):
4853 def tip(ui, repo, **opts):
4864 """show the tip revision
4854 """show the tip revision
4865
4855
4866 The tip revision (usually just called the tip) is the changeset
4856 The tip revision (usually just called the tip) is the changeset
4867 most recently added to the repository (and therefore the most
4857 most recently added to the repository (and therefore the most
4868 recently changed head).
4858 recently changed head).
4869
4859
4870 If you have just made a commit, that commit will be the tip. If
4860 If you have just made a commit, that commit will be the tip. If
4871 you have just pulled changes from another repository, the tip of
4861 you have just pulled changes from another repository, the tip of
4872 that repository becomes the current tip. The "tip" tag is special
4862 that repository becomes the current tip. The "tip" tag is special
4873 and cannot be renamed or assigned to a different changeset.
4863 and cannot be renamed or assigned to a different changeset.
4874
4864
4875 Returns 0 on success.
4865 Returns 0 on success.
4876 """
4866 """
4877 displayer = cmdutil.show_changeset(ui, repo, opts)
4867 displayer = cmdutil.show_changeset(ui, repo, opts)
4878 displayer.show(repo[len(repo) - 1])
4868 displayer.show(repo[len(repo) - 1])
4879 displayer.close()
4869 displayer.close()
4880
4870
4881 @command('unbundle',
4871 @command('unbundle',
4882 [('u', 'update', None,
4872 [('u', 'update', None,
4883 _('update to new branch head if changesets were unbundled'))],
4873 _('update to new branch head if changesets were unbundled'))],
4884 _('[-u] FILE...'))
4874 _('[-u] FILE...'))
4885 def unbundle(ui, repo, fname1, *fnames, **opts):
4875 def unbundle(ui, repo, fname1, *fnames, **opts):
4886 """apply one or more changegroup files
4876 """apply one or more changegroup files
4887
4877
4888 Apply one or more compressed changegroup files generated by the
4878 Apply one or more compressed changegroup files generated by the
4889 bundle command.
4879 bundle command.
4890
4880
4891 Returns 0 on success, 1 if an update has unresolved files.
4881 Returns 0 on success, 1 if an update has unresolved files.
4892 """
4882 """
4893 fnames = (fname1,) + fnames
4883 fnames = (fname1,) + fnames
4894
4884
4895 lock = repo.lock()
4885 lock = repo.lock()
4896 wc = repo['.']
4886 wc = repo['.']
4897 try:
4887 try:
4898 for fname in fnames:
4888 for fname in fnames:
4899 f = url.open(ui, fname)
4889 f = url.open(ui, fname)
4900 gen = changegroup.readbundle(f, fname)
4890 gen = changegroup.readbundle(f, fname)
4901 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4891 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4902 lock=lock)
4892 lock=lock)
4903 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
4893 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
4904 finally:
4894 finally:
4905 lock.release()
4895 lock.release()
4906 return postincoming(ui, repo, modheads, opts.get('update'), None)
4896 return postincoming(ui, repo, modheads, opts.get('update'), None)
4907
4897
4908 @command('^update|up|checkout|co',
4898 @command('^update|up|checkout|co',
4909 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4899 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4910 ('c', 'check', None,
4900 ('c', 'check', None,
4911 _('update across branches if no uncommitted changes')),
4901 _('update across branches if no uncommitted changes')),
4912 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4902 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4913 ('r', 'rev', '', _('revision'), _('REV'))],
4903 ('r', 'rev', '', _('revision'), _('REV'))],
4914 _('[-c] [-C] [-d DATE] [[-r] REV]'))
4904 _('[-c] [-C] [-d DATE] [[-r] REV]'))
4915 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4905 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4916 """update working directory (or switch revisions)
4906 """update working directory (or switch revisions)
4917
4907
4918 Update the repository's working directory to the specified
4908 Update the repository's working directory to the specified
4919 changeset. If no changeset is specified, update to the tip of the
4909 changeset. If no changeset is specified, update to the tip of the
4920 current named branch.
4910 current named branch.
4921
4911
4922 If the changeset is not a descendant of the working directory's
4912 If the changeset is not a descendant of the working directory's
4923 parent, the update is aborted. With the -c/--check option, the
4913 parent, the update is aborted. With the -c/--check option, the
4924 working directory is checked for uncommitted changes; if none are
4914 working directory is checked for uncommitted changes; if none are
4925 found, the working directory is updated to the specified
4915 found, the working directory is updated to the specified
4926 changeset.
4916 changeset.
4927
4917
4928 The following rules apply when the working directory contains
4918 The following rules apply when the working directory contains
4929 uncommitted changes:
4919 uncommitted changes:
4930
4920
4931 1. If neither -c/--check nor -C/--clean is specified, and if
4921 1. If neither -c/--check nor -C/--clean is specified, and if
4932 the requested changeset is an ancestor or descendant of
4922 the requested changeset is an ancestor or descendant of
4933 the working directory's parent, the uncommitted changes
4923 the working directory's parent, the uncommitted changes
4934 are merged into the requested changeset and the merged
4924 are merged into the requested changeset and the merged
4935 result is left uncommitted. If the requested changeset is
4925 result is left uncommitted. If the requested changeset is
4936 not an ancestor or descendant (that is, it is on another
4926 not an ancestor or descendant (that is, it is on another
4937 branch), the update is aborted and the uncommitted changes
4927 branch), the update is aborted and the uncommitted changes
4938 are preserved.
4928 are preserved.
4939
4929
4940 2. With the -c/--check option, the update is aborted and the
4930 2. With the -c/--check option, the update is aborted and the
4941 uncommitted changes are preserved.
4931 uncommitted changes are preserved.
4942
4932
4943 3. With the -C/--clean option, uncommitted changes are discarded and
4933 3. With the -C/--clean option, uncommitted changes are discarded and
4944 the working directory is updated to the requested changeset.
4934 the working directory is updated to the requested changeset.
4945
4935
4946 Use null as the changeset to remove the working directory (like
4936 Use null as the changeset to remove the working directory (like
4947 :hg:`clone -U`).
4937 :hg:`clone -U`).
4948
4938
4949 If you want to update just one file to an older changeset, use
4939 If you want to update just one file to an older changeset, use
4950 :hg:`revert`.
4940 :hg:`revert`.
4951
4941
4952 See :hg:`help dates` for a list of formats valid for -d/--date.
4942 See :hg:`help dates` for a list of formats valid for -d/--date.
4953
4943
4954 Returns 0 on success, 1 if there are unresolved files.
4944 Returns 0 on success, 1 if there are unresolved files.
4955 """
4945 """
4956 if rev and node:
4946 if rev and node:
4957 raise util.Abort(_("please specify just one revision"))
4947 raise util.Abort(_("please specify just one revision"))
4958
4948
4959 if rev is None or rev == '':
4949 if rev is None or rev == '':
4960 rev = node
4950 rev = node
4961
4951
4962 # if we defined a bookmark, we have to remember the original bookmark name
4952 # if we defined a bookmark, we have to remember the original bookmark name
4963 brev = rev
4953 brev = rev
4964 rev = scmutil.revsingle(repo, rev, rev).rev()
4954 rev = scmutil.revsingle(repo, rev, rev).rev()
4965
4955
4966 if check and clean:
4956 if check and clean:
4967 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4957 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4968
4958
4969 if check:
4959 if check:
4970 # we could use dirty() but we can ignore merge and branch trivia
4960 # we could use dirty() but we can ignore merge and branch trivia
4971 c = repo[None]
4961 c = repo[None]
4972 if c.modified() or c.added() or c.removed():
4962 if c.modified() or c.added() or c.removed():
4973 raise util.Abort(_("uncommitted local changes"))
4963 raise util.Abort(_("uncommitted local changes"))
4974
4964
4975 if date:
4965 if date:
4976 if rev is not None:
4966 if rev is not None:
4977 raise util.Abort(_("you can't specify a revision and a date"))
4967 raise util.Abort(_("you can't specify a revision and a date"))
4978 rev = cmdutil.finddate(ui, repo, date)
4968 rev = cmdutil.finddate(ui, repo, date)
4979
4969
4980 if clean or check:
4970 if clean or check:
4981 ret = hg.clean(repo, rev)
4971 ret = hg.clean(repo, rev)
4982 else:
4972 else:
4983 ret = hg.update(repo, rev)
4973 ret = hg.update(repo, rev)
4984
4974
4985 if brev in repo._bookmarks:
4975 if brev in repo._bookmarks:
4986 bookmarks.setcurrent(repo, brev)
4976 bookmarks.setcurrent(repo, brev)
4987
4977
4988 return ret
4978 return ret
4989
4979
4990 @command('verify', [])
4980 @command('verify', [])
4991 def verify(ui, repo):
4981 def verify(ui, repo):
4992 """verify the integrity of the repository
4982 """verify the integrity of the repository
4993
4983
4994 Verify the integrity of the current repository.
4984 Verify the integrity of the current repository.
4995
4985
4996 This will perform an extensive check of the repository's
4986 This will perform an extensive check of the repository's
4997 integrity, validating the hashes and checksums of each entry in
4987 integrity, validating the hashes and checksums of each entry in
4998 the changelog, manifest, and tracked files, as well as the
4988 the changelog, manifest, and tracked files, as well as the
4999 integrity of their crosslinks and indices.
4989 integrity of their crosslinks and indices.
5000
4990
5001 Returns 0 on success, 1 if errors are encountered.
4991 Returns 0 on success, 1 if errors are encountered.
5002 """
4992 """
5003 return hg.verify(repo)
4993 return hg.verify(repo)
5004
4994
5005 @command('version', [])
4995 @command('version', [])
5006 def version_(ui):
4996 def version_(ui):
5007 """output version and copyright information"""
4997 """output version and copyright information"""
5008 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4998 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5009 % util.version())
4999 % util.version())
5010 ui.status(_(
5000 ui.status(_(
5011 "(see http://mercurial.selenic.com for more information)\n"
5001 "(see http://mercurial.selenic.com for more information)\n"
5012 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5002 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5013 "This is free software; see the source for copying conditions. "
5003 "This is free software; see the source for copying conditions. "
5014 "There is NO\nwarranty; "
5004 "There is NO\nwarranty; "
5015 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5005 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5016 ))
5006 ))
5017
5007
5018 norepo = ("clone init version help debugcommands debugcomplete"
5008 norepo = ("clone init version help debugcommands debugcomplete"
5019 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5009 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5020 " debugknown debuggetbundle debugbundle")
5010 " debugknown debuggetbundle debugbundle")
5021 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5011 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5022 " debugdata debugindex debugindexdot")
5012 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,220 +1,220 b''
1 $ hg init test
1 $ hg init test
2 $ cd test
2 $ cd test
3
3
4 $ echo 0 >> afile
4 $ echo 0 >> afile
5 $ hg add afile
5 $ hg add afile
6 $ hg commit -m "0.0"
6 $ hg commit -m "0.0"
7
7
8 $ echo 1 >> afile
8 $ echo 1 >> afile
9 $ hg commit -m "0.1"
9 $ hg commit -m "0.1"
10
10
11 $ echo 2 >> afile
11 $ echo 2 >> afile
12 $ hg commit -m "0.2"
12 $ hg commit -m "0.2"
13
13
14 $ echo 3 >> afile
14 $ echo 3 >> afile
15 $ hg commit -m "0.3"
15 $ hg commit -m "0.3"
16
16
17 $ hg update -C 0
17 $ hg update -C 0
18 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
18 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
19
19
20 $ echo 1 >> afile
20 $ echo 1 >> afile
21 $ hg commit -m "1.1"
21 $ hg commit -m "1.1"
22 created new head
22 created new head
23
23
24 $ echo 2 >> afile
24 $ echo 2 >> afile
25 $ hg commit -m "1.2"
25 $ hg commit -m "1.2"
26
26
27 $ echo a line > fred
27 $ echo a line > fred
28 $ echo 3 >> afile
28 $ echo 3 >> afile
29 $ hg add fred
29 $ hg add fred
30 $ hg commit -m "1.3"
30 $ hg commit -m "1.3"
31 $ hg mv afile adifferentfile
31 $ hg mv afile adifferentfile
32 $ hg commit -m "1.3m"
32 $ hg commit -m "1.3m"
33
33
34 $ hg update -C 3
34 $ hg update -C 3
35 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
35 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
36
36
37 $ hg mv afile anotherfile
37 $ hg mv afile anotherfile
38 $ hg commit -m "0.3m"
38 $ hg commit -m "0.3m"
39
39
40 $ hg debugindex -f 1 afile
40 $ hg debugindex -f 1 afile
41 rev flag offset length size base link p1 p2 nodeid
41 rev flag offset length size base link p1 p2 nodeid
42 0 0000 0 3 2 0 0 -1 -1 362fef284ce2
42 0 0000 0 3 2 0 0 -1 -1 362fef284ce2
43 1 0000 3 5 4 1 1 0 -1 125144f7e028
43 1 0000 3 5 4 1 1 0 -1 125144f7e028
44 2 0000 8 7 6 2 2 1 -1 4c982badb186
44 2 0000 8 7 6 2 2 1 -1 4c982badb186
45 3 0000 15 9 8 3 3 2 -1 19b1fc555737
45 3 0000 15 9 8 3 3 2 -1 19b1fc555737
46
46
47 $ hg debugindex adifferentfile
47 $ hg debugindex adifferentfile
48 rev offset length base linkrev nodeid p1 p2
48 rev offset length base linkrev nodeid p1 p2
49 0 0 75 0 7 2565f3199a74 000000000000 000000000000
49 0 0 75 0 7 2565f3199a74 000000000000 000000000000
50
50
51 $ hg debugindex anotherfile
51 $ hg debugindex anotherfile
52 rev offset length base linkrev nodeid p1 p2
52 rev offset length base linkrev nodeid p1 p2
53 0 0 75 0 8 2565f3199a74 000000000000 000000000000
53 0 0 75 0 8 2565f3199a74 000000000000 000000000000
54
54
55 $ hg debugindex fred
55 $ hg debugindex fred
56 rev offset length base linkrev nodeid p1 p2
56 rev offset length base linkrev nodeid p1 p2
57 0 0 8 0 6 12ab3bcc5ea4 000000000000 000000000000
57 0 0 8 0 6 12ab3bcc5ea4 000000000000 000000000000
58
58
59 $ hg debugindex .hg/store/00manifest.i
59 $ hg debugindex --manifest
60 rev offset length base linkrev nodeid p1 p2
60 rev offset length base linkrev nodeid p1 p2
61 0 0 48 0 0 43eadb1d2d06 000000000000 000000000000
61 0 0 48 0 0 43eadb1d2d06 000000000000 000000000000
62 1 48 48 1 1 8b89697eba2c 43eadb1d2d06 000000000000
62 1 48 48 1 1 8b89697eba2c 43eadb1d2d06 000000000000
63 2 96 48 2 2 626a32663c2f 8b89697eba2c 000000000000
63 2 96 48 2 2 626a32663c2f 8b89697eba2c 000000000000
64 3 144 48 3 3 f54c32f13478 626a32663c2f 000000000000
64 3 144 48 3 3 f54c32f13478 626a32663c2f 000000000000
65 4 192 58 3 6 de68e904d169 626a32663c2f 000000000000
65 4 192 58 3 6 de68e904d169 626a32663c2f 000000000000
66 5 250 68 3 7 09bb521d218d de68e904d169 000000000000
66 5 250 68 3 7 09bb521d218d de68e904d169 000000000000
67 6 318 54 6 8 1fde233dfb0f f54c32f13478 000000000000
67 6 318 54 6 8 1fde233dfb0f f54c32f13478 000000000000
68
68
69 $ hg verify
69 $ hg verify
70 checking changesets
70 checking changesets
71 checking manifests
71 checking manifests
72 crosschecking files in changesets and manifests
72 crosschecking files in changesets and manifests
73 checking files
73 checking files
74 4 files, 9 changesets, 7 total revisions
74 4 files, 9 changesets, 7 total revisions
75
75
76 $ cd ..
76 $ cd ..
77
77
78 $ for i in 0 1 2 3 4 5 6 7 8; do
78 $ for i in 0 1 2 3 4 5 6 7 8; do
79 > echo
79 > echo
80 > echo ---- hg clone -r "$i" test test-"$i"
80 > echo ---- hg clone -r "$i" test test-"$i"
81 > hg clone -r "$i" test test-"$i"
81 > hg clone -r "$i" test test-"$i"
82 > cd test-"$i"
82 > cd test-"$i"
83 > hg verify
83 > hg verify
84 > cd ..
84 > cd ..
85 > done
85 > done
86
86
87 ---- hg clone -r 0 test test-0
87 ---- hg clone -r 0 test test-0
88 adding changesets
88 adding changesets
89 adding manifests
89 adding manifests
90 adding file changes
90 adding file changes
91 added 1 changesets with 1 changes to 1 files
91 added 1 changesets with 1 changes to 1 files
92 updating to branch default
92 updating to branch default
93 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
93 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
94 checking changesets
94 checking changesets
95 checking manifests
95 checking manifests
96 crosschecking files in changesets and manifests
96 crosschecking files in changesets and manifests
97 checking files
97 checking files
98 1 files, 1 changesets, 1 total revisions
98 1 files, 1 changesets, 1 total revisions
99
99
100 ---- hg clone -r 1 test test-1
100 ---- hg clone -r 1 test test-1
101 adding changesets
101 adding changesets
102 adding manifests
102 adding manifests
103 adding file changes
103 adding file changes
104 added 2 changesets with 2 changes to 1 files
104 added 2 changesets with 2 changes to 1 files
105 updating to branch default
105 updating to branch default
106 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
106 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
107 checking changesets
107 checking changesets
108 checking manifests
108 checking manifests
109 crosschecking files in changesets and manifests
109 crosschecking files in changesets and manifests
110 checking files
110 checking files
111 1 files, 2 changesets, 2 total revisions
111 1 files, 2 changesets, 2 total revisions
112
112
113 ---- hg clone -r 2 test test-2
113 ---- hg clone -r 2 test test-2
114 adding changesets
114 adding changesets
115 adding manifests
115 adding manifests
116 adding file changes
116 adding file changes
117 added 3 changesets with 3 changes to 1 files
117 added 3 changesets with 3 changes to 1 files
118 updating to branch default
118 updating to branch default
119 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
119 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 checking changesets
120 checking changesets
121 checking manifests
121 checking manifests
122 crosschecking files in changesets and manifests
122 crosschecking files in changesets and manifests
123 checking files
123 checking files
124 1 files, 3 changesets, 3 total revisions
124 1 files, 3 changesets, 3 total revisions
125
125
126 ---- hg clone -r 3 test test-3
126 ---- hg clone -r 3 test test-3
127 adding changesets
127 adding changesets
128 adding manifests
128 adding manifests
129 adding file changes
129 adding file changes
130 added 4 changesets with 4 changes to 1 files
130 added 4 changesets with 4 changes to 1 files
131 updating to branch default
131 updating to branch default
132 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
132 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
133 checking changesets
133 checking changesets
134 checking manifests
134 checking manifests
135 crosschecking files in changesets and manifests
135 crosschecking files in changesets and manifests
136 checking files
136 checking files
137 1 files, 4 changesets, 4 total revisions
137 1 files, 4 changesets, 4 total revisions
138
138
139 ---- hg clone -r 4 test test-4
139 ---- hg clone -r 4 test test-4
140 adding changesets
140 adding changesets
141 adding manifests
141 adding manifests
142 adding file changes
142 adding file changes
143 added 2 changesets with 2 changes to 1 files
143 added 2 changesets with 2 changes to 1 files
144 updating to branch default
144 updating to branch default
145 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
145 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
146 checking changesets
146 checking changesets
147 checking manifests
147 checking manifests
148 crosschecking files in changesets and manifests
148 crosschecking files in changesets and manifests
149 checking files
149 checking files
150 1 files, 2 changesets, 2 total revisions
150 1 files, 2 changesets, 2 total revisions
151
151
152 ---- hg clone -r 5 test test-5
152 ---- hg clone -r 5 test test-5
153 adding changesets
153 adding changesets
154 adding manifests
154 adding manifests
155 adding file changes
155 adding file changes
156 added 3 changesets with 3 changes to 1 files
156 added 3 changesets with 3 changes to 1 files
157 updating to branch default
157 updating to branch default
158 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
158 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
159 checking changesets
159 checking changesets
160 checking manifests
160 checking manifests
161 crosschecking files in changesets and manifests
161 crosschecking files in changesets and manifests
162 checking files
162 checking files
163 1 files, 3 changesets, 3 total revisions
163 1 files, 3 changesets, 3 total revisions
164
164
165 ---- hg clone -r 6 test test-6
165 ---- hg clone -r 6 test test-6
166 adding changesets
166 adding changesets
167 adding manifests
167 adding manifests
168 adding file changes
168 adding file changes
169 added 4 changesets with 5 changes to 2 files
169 added 4 changesets with 5 changes to 2 files
170 updating to branch default
170 updating to branch default
171 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
171 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
172 checking changesets
172 checking changesets
173 checking manifests
173 checking manifests
174 crosschecking files in changesets and manifests
174 crosschecking files in changesets and manifests
175 checking files
175 checking files
176 2 files, 4 changesets, 5 total revisions
176 2 files, 4 changesets, 5 total revisions
177
177
178 ---- hg clone -r 7 test test-7
178 ---- hg clone -r 7 test test-7
179 adding changesets
179 adding changesets
180 adding manifests
180 adding manifests
181 adding file changes
181 adding file changes
182 added 5 changesets with 6 changes to 3 files
182 added 5 changesets with 6 changes to 3 files
183 updating to branch default
183 updating to branch default
184 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
184 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
185 checking changesets
185 checking changesets
186 checking manifests
186 checking manifests
187 crosschecking files in changesets and manifests
187 crosschecking files in changesets and manifests
188 checking files
188 checking files
189 3 files, 5 changesets, 6 total revisions
189 3 files, 5 changesets, 6 total revisions
190
190
191 ---- hg clone -r 8 test test-8
191 ---- hg clone -r 8 test test-8
192 adding changesets
192 adding changesets
193 adding manifests
193 adding manifests
194 adding file changes
194 adding file changes
195 added 5 changesets with 5 changes to 2 files
195 added 5 changesets with 5 changes to 2 files
196 updating to branch default
196 updating to branch default
197 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
197 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
198 checking changesets
198 checking changesets
199 checking manifests
199 checking manifests
200 crosschecking files in changesets and manifests
200 crosschecking files in changesets and manifests
201 checking files
201 checking files
202 2 files, 5 changesets, 5 total revisions
202 2 files, 5 changesets, 5 total revisions
203
203
204 $ cd test-8
204 $ cd test-8
205 $ hg pull ../test-7
205 $ hg pull ../test-7
206 pulling from ../test-7
206 pulling from ../test-7
207 searching for changes
207 searching for changes
208 adding changesets
208 adding changesets
209 adding manifests
209 adding manifests
210 adding file changes
210 adding file changes
211 added 4 changesets with 2 changes to 3 files (+1 heads)
211 added 4 changesets with 2 changes to 3 files (+1 heads)
212 (run 'hg heads' to see heads, 'hg merge' to merge)
212 (run 'hg heads' to see heads, 'hg merge' to merge)
213 $ hg verify
213 $ hg verify
214 checking changesets
214 checking changesets
215 checking manifests
215 checking manifests
216 crosschecking files in changesets and manifests
216 crosschecking files in changesets and manifests
217 checking files
217 checking files
218 4 files, 9 changesets, 7 total revisions
218 4 files, 9 changesets, 7 total revisions
219 $ cd ..
219 $ cd ..
220
220
@@ -1,265 +1,265 b''
1 Show all commands except debug commands
1 Show all commands except debug commands
2 $ hg debugcomplete
2 $ hg debugcomplete
3 add
3 add
4 addremove
4 addremove
5 annotate
5 annotate
6 archive
6 archive
7 backout
7 backout
8 bisect
8 bisect
9 bookmarks
9 bookmarks
10 branch
10 branch
11 branches
11 branches
12 bundle
12 bundle
13 cat
13 cat
14 clone
14 clone
15 commit
15 commit
16 copy
16 copy
17 diff
17 diff
18 export
18 export
19 forget
19 forget
20 grep
20 grep
21 heads
21 heads
22 help
22 help
23 identify
23 identify
24 import
24 import
25 incoming
25 incoming
26 init
26 init
27 locate
27 locate
28 log
28 log
29 manifest
29 manifest
30 merge
30 merge
31 outgoing
31 outgoing
32 parents
32 parents
33 paths
33 paths
34 pull
34 pull
35 push
35 push
36 recover
36 recover
37 remove
37 remove
38 rename
38 rename
39 resolve
39 resolve
40 revert
40 revert
41 rollback
41 rollback
42 root
42 root
43 serve
43 serve
44 showconfig
44 showconfig
45 status
45 status
46 summary
46 summary
47 tag
47 tag
48 tags
48 tags
49 tip
49 tip
50 unbundle
50 unbundle
51 update
51 update
52 verify
52 verify
53 version
53 version
54
54
55 Show all commands that start with "a"
55 Show all commands that start with "a"
56 $ hg debugcomplete a
56 $ hg debugcomplete a
57 add
57 add
58 addremove
58 addremove
59 annotate
59 annotate
60 archive
60 archive
61
61
62 Do not show debug commands if there are other candidates
62 Do not show debug commands if there are other candidates
63 $ hg debugcomplete d
63 $ hg debugcomplete d
64 diff
64 diff
65
65
66 Show debug commands if there are no other candidates
66 Show debug commands if there are no other candidates
67 $ hg debugcomplete debug
67 $ hg debugcomplete debug
68 debugancestor
68 debugancestor
69 debugbuilddag
69 debugbuilddag
70 debugbundle
70 debugbundle
71 debugcheckstate
71 debugcheckstate
72 debugcommands
72 debugcommands
73 debugcomplete
73 debugcomplete
74 debugconfig
74 debugconfig
75 debugdag
75 debugdag
76 debugdata
76 debugdata
77 debugdate
77 debugdate
78 debugdiscovery
78 debugdiscovery
79 debugfsinfo
79 debugfsinfo
80 debuggetbundle
80 debuggetbundle
81 debugignore
81 debugignore
82 debugindex
82 debugindex
83 debugindexdot
83 debugindexdot
84 debuginstall
84 debuginstall
85 debugknown
85 debugknown
86 debugpushkey
86 debugpushkey
87 debugrebuildstate
87 debugrebuildstate
88 debugrename
88 debugrename
89 debugrevlog
89 debugrevlog
90 debugrevspec
90 debugrevspec
91 debugsetparents
91 debugsetparents
92 debugstate
92 debugstate
93 debugsub
93 debugsub
94 debugwalk
94 debugwalk
95 debugwireargs
95 debugwireargs
96
96
97 Do not show the alias of a debug command if there are other candidates
97 Do not show the alias of a debug command if there are other candidates
98 (this should hide rawcommit)
98 (this should hide rawcommit)
99 $ hg debugcomplete r
99 $ hg debugcomplete r
100 recover
100 recover
101 remove
101 remove
102 rename
102 rename
103 resolve
103 resolve
104 revert
104 revert
105 rollback
105 rollback
106 root
106 root
107 Show the alias of a debug command if there are no other candidates
107 Show the alias of a debug command if there are no other candidates
108 $ hg debugcomplete rawc
108 $ hg debugcomplete rawc
109
109
110
110
111 Show the global options
111 Show the global options
112 $ hg debugcomplete --options | sort
112 $ hg debugcomplete --options | sort
113 --config
113 --config
114 --cwd
114 --cwd
115 --debug
115 --debug
116 --debugger
116 --debugger
117 --encoding
117 --encoding
118 --encodingmode
118 --encodingmode
119 --help
119 --help
120 --noninteractive
120 --noninteractive
121 --profile
121 --profile
122 --quiet
122 --quiet
123 --repository
123 --repository
124 --time
124 --time
125 --traceback
125 --traceback
126 --verbose
126 --verbose
127 --version
127 --version
128 -R
128 -R
129 -h
129 -h
130 -q
130 -q
131 -v
131 -v
132 -y
132 -y
133
133
134 Show the options for the "serve" command
134 Show the options for the "serve" command
135 $ hg debugcomplete --options serve | sort
135 $ hg debugcomplete --options serve | sort
136 --accesslog
136 --accesslog
137 --address
137 --address
138 --certificate
138 --certificate
139 --config
139 --config
140 --cwd
140 --cwd
141 --daemon
141 --daemon
142 --daemon-pipefds
142 --daemon-pipefds
143 --debug
143 --debug
144 --debugger
144 --debugger
145 --encoding
145 --encoding
146 --encodingmode
146 --encodingmode
147 --errorlog
147 --errorlog
148 --help
148 --help
149 --ipv6
149 --ipv6
150 --name
150 --name
151 --noninteractive
151 --noninteractive
152 --pid-file
152 --pid-file
153 --port
153 --port
154 --prefix
154 --prefix
155 --profile
155 --profile
156 --quiet
156 --quiet
157 --repository
157 --repository
158 --stdio
158 --stdio
159 --style
159 --style
160 --templates
160 --templates
161 --time
161 --time
162 --traceback
162 --traceback
163 --verbose
163 --verbose
164 --version
164 --version
165 --web-conf
165 --web-conf
166 -6
166 -6
167 -A
167 -A
168 -E
168 -E
169 -R
169 -R
170 -a
170 -a
171 -d
171 -d
172 -h
172 -h
173 -n
173 -n
174 -p
174 -p
175 -q
175 -q
176 -t
176 -t
177 -v
177 -v
178 -y
178 -y
179
179
180 Show an error if we use --options with an ambiguous abbreviation
180 Show an error if we use --options with an ambiguous abbreviation
181 $ hg debugcomplete --options s
181 $ hg debugcomplete --options s
182 hg: command 's' is ambiguous:
182 hg: command 's' is ambiguous:
183 serve showconfig status summary
183 serve showconfig status summary
184 [255]
184 [255]
185
185
186 Show all commands + options
186 Show all commands + options
187 $ hg debugcommands
187 $ hg debugcommands
188 add: include, exclude, subrepos, dry-run
188 add: include, exclude, subrepos, dry-run
189 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, include, exclude
189 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, include, exclude
190 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
190 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
191 commit: addremove, close-branch, include, exclude, message, logfile, date, user
191 commit: addremove, close-branch, include, exclude, message, logfile, date, user
192 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
192 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
193 export: output, switch-parent, rev, text, git, nodates
193 export: output, switch-parent, rev, text, git, nodates
194 forget: include, exclude
194 forget: include, exclude
195 init: ssh, remotecmd, insecure
195 init: ssh, remotecmd, insecure
196 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, style, template, include, exclude
196 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, style, template, include, exclude
197 merge: force, tool, rev, preview
197 merge: force, tool, rev, preview
198 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
198 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
199 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
199 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
200 remove: after, force, include, exclude
200 remove: after, force, include, exclude
201 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, templates, style, ipv6, certificate
201 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, templates, style, ipv6, certificate
202 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
202 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
203 summary: remote
203 summary: remote
204 update: clean, check, date, rev
204 update: clean, check, date, rev
205 addremove: similarity, include, exclude, dry-run
205 addremove: similarity, include, exclude, dry-run
206 archive: no-decode, prefix, rev, type, subrepos, include, exclude
206 archive: no-decode, prefix, rev, type, subrepos, include, exclude
207 backout: merge, parent, tool, rev, include, exclude, message, logfile, date, user
207 backout: merge, parent, tool, rev, include, exclude, message, logfile, date, user
208 bisect: reset, good, bad, skip, extend, command, noupdate
208 bisect: reset, good, bad, skip, extend, command, noupdate
209 bookmarks: force, rev, delete, rename, inactive
209 bookmarks: force, rev, delete, rename, inactive
210 branch: force, clean
210 branch: force, clean
211 branches: active, closed
211 branches: active, closed
212 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
212 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
213 cat: output, rev, decode, include, exclude
213 cat: output, rev, decode, include, exclude
214 copy: after, force, include, exclude, dry-run
214 copy: after, force, include, exclude, dry-run
215 debugancestor:
215 debugancestor:
216 debugbuilddag: mergeable-file, overwritten-file, new-file
216 debugbuilddag: mergeable-file, overwritten-file, new-file
217 debugbundle: all
217 debugbundle: all
218 debugcheckstate:
218 debugcheckstate:
219 debugcommands:
219 debugcommands:
220 debugcomplete: options
220 debugcomplete: options
221 debugdag: tags, branches, dots, spaces
221 debugdag: tags, branches, dots, spaces
222 debugdata:
222 debugdata: changelog, manifest
223 debugdate: extended
223 debugdate: extended
224 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
224 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
225 debugfsinfo:
225 debugfsinfo:
226 debuggetbundle: head, common, type
226 debuggetbundle: head, common, type
227 debugignore:
227 debugignore:
228 debugindex: format
228 debugindex: changelog, manifest, format
229 debugindexdot:
229 debugindexdot:
230 debuginstall:
230 debuginstall:
231 debugknown:
231 debugknown:
232 debugpushkey:
232 debugpushkey:
233 debugrebuildstate: rev
233 debugrebuildstate: rev
234 debugrename: rev
234 debugrename: rev
235 debugrevlog:
235 debugrevlog: changelog, manifest
236 debugrevspec:
236 debugrevspec:
237 debugsetparents:
237 debugsetparents:
238 debugstate: nodates, datesort
238 debugstate: nodates, datesort
239 debugsub: rev
239 debugsub: rev
240 debugwalk: include, exclude
240 debugwalk: include, exclude
241 debugwireargs: three, four, five, ssh, remotecmd, insecure
241 debugwireargs: three, four, five, ssh, remotecmd, insecure
242 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
242 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
243 heads: rev, topo, active, closed, style, template
243 heads: rev, topo, active, closed, style, template
244 help: extension, command
244 help: extension, command
245 identify: rev, num, id, branch, tags, bookmarks
245 identify: rev, num, id, branch, tags, bookmarks
246 import: strip, base, force, no-commit, exact, import-branch, message, logfile, date, user, similarity
246 import: strip, base, force, no-commit, exact, import-branch, message, logfile, date, user, similarity
247 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
247 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
248 locate: rev, print0, fullpath, include, exclude
248 locate: rev, print0, fullpath, include, exclude
249 manifest: rev
249 manifest: rev
250 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
250 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
251 parents: rev, style, template
251 parents: rev, style, template
252 paths:
252 paths:
253 recover:
253 recover:
254 rename: after, force, include, exclude, dry-run
254 rename: after, force, include, exclude, dry-run
255 resolve: all, list, mark, unmark, tool, no-status, include, exclude
255 resolve: all, list, mark, unmark, tool, no-status, include, exclude
256 revert: all, date, rev, no-backup, include, exclude, dry-run
256 revert: all, date, rev, no-backup, include, exclude, dry-run
257 rollback: dry-run
257 rollback: dry-run
258 root:
258 root:
259 showconfig: untrusted
259 showconfig: untrusted
260 tag: force, local, rev, remove, edit, message, date, user
260 tag: force, local, rev, remove, edit, message, date, user
261 tags:
261 tags:
262 tip: patch, git, style, template
262 tip: patch, git, style, template
263 unbundle: update
263 unbundle: update
264 verify:
264 verify:
265 version:
265 version:
@@ -1,101 +1,101 b''
1 $ hg init
1 $ hg init
2
2
3 $ echo foo > a
3 $ echo foo > a
4 $ echo foo > b
4 $ echo foo > b
5 $ hg add a b
5 $ hg add a b
6
6
7 $ hg ci -m "test"
7 $ hg ci -m "test"
8
8
9 $ echo blah > a
9 $ echo blah > a
10
10
11 $ hg ci -m "branch a"
11 $ hg ci -m "branch a"
12
12
13 $ hg co 0
13 $ hg co 0
14 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
14 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
15
15
16 $ echo blah > b
16 $ echo blah > b
17
17
18 $ hg ci -m "branch b"
18 $ hg ci -m "branch b"
19 created new head
19 created new head
20 $ HGMERGE=true hg merge 1
20 $ HGMERGE=true hg merge 1
21 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
22 (branch merge, don't forget to commit)
22 (branch merge, don't forget to commit)
23
23
24 $ hg ci -m "merge b/a -> blah"
24 $ hg ci -m "merge b/a -> blah"
25
25
26 $ hg co 1
26 $ hg co 1
27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
28 $ HGMERGE=true hg merge 2
28 $ HGMERGE=true hg merge 2
29 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
29 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
30 (branch merge, don't forget to commit)
30 (branch merge, don't forget to commit)
31 $ hg ci -m "merge a/b -> blah"
31 $ hg ci -m "merge a/b -> blah"
32 created new head
32 created new head
33
33
34 $ hg log
34 $ hg log
35 changeset: 4:2ee31f665a86
35 changeset: 4:2ee31f665a86
36 tag: tip
36 tag: tip
37 parent: 1:96155394af80
37 parent: 1:96155394af80
38 parent: 2:92cc4c306b19
38 parent: 2:92cc4c306b19
39 user: test
39 user: test
40 date: Thu Jan 01 00:00:00 1970 +0000
40 date: Thu Jan 01 00:00:00 1970 +0000
41 summary: merge a/b -> blah
41 summary: merge a/b -> blah
42
42
43 changeset: 3:e16a66a37edd
43 changeset: 3:e16a66a37edd
44 parent: 2:92cc4c306b19
44 parent: 2:92cc4c306b19
45 parent: 1:96155394af80
45 parent: 1:96155394af80
46 user: test
46 user: test
47 date: Thu Jan 01 00:00:00 1970 +0000
47 date: Thu Jan 01 00:00:00 1970 +0000
48 summary: merge b/a -> blah
48 summary: merge b/a -> blah
49
49
50 changeset: 2:92cc4c306b19
50 changeset: 2:92cc4c306b19
51 parent: 0:5e0375449e74
51 parent: 0:5e0375449e74
52 user: test
52 user: test
53 date: Thu Jan 01 00:00:00 1970 +0000
53 date: Thu Jan 01 00:00:00 1970 +0000
54 summary: branch b
54 summary: branch b
55
55
56 changeset: 1:96155394af80
56 changeset: 1:96155394af80
57 user: test
57 user: test
58 date: Thu Jan 01 00:00:00 1970 +0000
58 date: Thu Jan 01 00:00:00 1970 +0000
59 summary: branch a
59 summary: branch a
60
60
61 changeset: 0:5e0375449e74
61 changeset: 0:5e0375449e74
62 user: test
62 user: test
63 date: Thu Jan 01 00:00:00 1970 +0000
63 date: Thu Jan 01 00:00:00 1970 +0000
64 summary: test
64 summary: test
65
65
66 $ hg debugindex .hg/store/00changelog.i
66 $ hg debugindex --changelog
67 rev offset length base linkrev nodeid p1 p2
67 rev offset length base linkrev nodeid p1 p2
68 0 0 60 0 0 5e0375449e74 000000000000 000000000000
68 0 0 60 0 0 5e0375449e74 000000000000 000000000000
69 1 60 62 1 1 96155394af80 5e0375449e74 000000000000
69 1 60 62 1 1 96155394af80 5e0375449e74 000000000000
70 2 122 62 2 2 92cc4c306b19 5e0375449e74 000000000000
70 2 122 62 2 2 92cc4c306b19 5e0375449e74 000000000000
71 3 184 69 3 3 e16a66a37edd 92cc4c306b19 96155394af80
71 3 184 69 3 3 e16a66a37edd 92cc4c306b19 96155394af80
72 4 253 29 3 4 2ee31f665a86 96155394af80 92cc4c306b19
72 4 253 29 3 4 2ee31f665a86 96155394af80 92cc4c306b19
73
73
74 revision 1
74 revision 1
75 $ hg manifest --debug 1
75 $ hg manifest --debug 1
76 79d7492df40aa0fa093ec4209be78043c181f094 644 a
76 79d7492df40aa0fa093ec4209be78043c181f094 644 a
77 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 b
77 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 b
78 revision 2
78 revision 2
79 $ hg manifest --debug 2
79 $ hg manifest --debug 2
80 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 a
80 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 a
81 79d7492df40aa0fa093ec4209be78043c181f094 644 b
81 79d7492df40aa0fa093ec4209be78043c181f094 644 b
82 revision 3
82 revision 3
83 $ hg manifest --debug 3
83 $ hg manifest --debug 3
84 79d7492df40aa0fa093ec4209be78043c181f094 644 a
84 79d7492df40aa0fa093ec4209be78043c181f094 644 a
85 79d7492df40aa0fa093ec4209be78043c181f094 644 b
85 79d7492df40aa0fa093ec4209be78043c181f094 644 b
86 revision 4
86 revision 4
87 $ hg manifest --debug 4
87 $ hg manifest --debug 4
88 79d7492df40aa0fa093ec4209be78043c181f094 644 a
88 79d7492df40aa0fa093ec4209be78043c181f094 644 a
89 79d7492df40aa0fa093ec4209be78043c181f094 644 b
89 79d7492df40aa0fa093ec4209be78043c181f094 644 b
90
90
91 $ hg debugindex a
91 $ hg debugindex a
92 rev offset length base linkrev nodeid p1 p2
92 rev offset length base linkrev nodeid p1 p2
93 0 0 5 0 0 2ed2a3912a0b 000000000000 000000000000
93 0 0 5 0 0 2ed2a3912a0b 000000000000 000000000000
94 1 5 6 1 1 79d7492df40a 2ed2a3912a0b 000000000000
94 1 5 6 1 1 79d7492df40a 2ed2a3912a0b 000000000000
95
95
96 $ hg verify
96 $ hg verify
97 checking changesets
97 checking changesets
98 checking manifests
98 checking manifests
99 crosschecking files in changesets and manifests
99 crosschecking files in changesets and manifests
100 checking files
100 checking files
101 2 files, 5 changesets, 4 total revisions
101 2 files, 5 changesets, 4 total revisions
@@ -1,148 +1,148 b''
1 This test makes sure that we don't mark a file as merged with its ancestor
1 This test makes sure that we don't mark a file as merged with its ancestor
2 when we do a merge.
2 when we do a merge.
3
3
4 $ cat <<EOF > merge
4 $ cat <<EOF > merge
5 > import sys, os
5 > import sys, os
6 > print "merging for", os.path.basename(sys.argv[1])
6 > print "merging for", os.path.basename(sys.argv[1])
7 > EOF
7 > EOF
8 $ HGMERGE="python ../merge"; export HGMERGE
8 $ HGMERGE="python ../merge"; export HGMERGE
9
9
10 Creating base:
10 Creating base:
11
11
12 $ hg init a
12 $ hg init a
13 $ cd a
13 $ cd a
14 $ echo 1 > foo
14 $ echo 1 > foo
15 $ echo 1 > bar
15 $ echo 1 > bar
16 $ echo 1 > baz
16 $ echo 1 > baz
17 $ echo 1 > quux
17 $ echo 1 > quux
18 $ hg add foo bar baz quux
18 $ hg add foo bar baz quux
19 $ hg commit -m "base"
19 $ hg commit -m "base"
20
20
21 $ cd ..
21 $ cd ..
22 $ hg clone a b
22 $ hg clone a b
23 updating to branch default
23 updating to branch default
24 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
24 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
25
25
26 Creating branch a:
26 Creating branch a:
27
27
28 $ cd a
28 $ cd a
29 $ echo 2a > foo
29 $ echo 2a > foo
30 $ echo 2a > bar
30 $ echo 2a > bar
31 $ hg commit -m "branch a"
31 $ hg commit -m "branch a"
32
32
33 Creating branch b:
33 Creating branch b:
34
34
35 $ cd ..
35 $ cd ..
36 $ cd b
36 $ cd b
37 $ echo 2b > foo
37 $ echo 2b > foo
38 $ echo 2b > baz
38 $ echo 2b > baz
39 $ hg commit -m "branch b"
39 $ hg commit -m "branch b"
40
40
41 We shouldn't have anything but n state here:
41 We shouldn't have anything but n state here:
42
42
43 $ hg debugstate --nodates | grep -v "^n"
43 $ hg debugstate --nodates | grep -v "^n"
44 [1]
44 [1]
45
45
46 Merging:
46 Merging:
47
47
48 $ hg pull ../a
48 $ hg pull ../a
49 pulling from ../a
49 pulling from ../a
50 searching for changes
50 searching for changes
51 adding changesets
51 adding changesets
52 adding manifests
52 adding manifests
53 adding file changes
53 adding file changes
54 added 1 changesets with 2 changes to 2 files (+1 heads)
54 added 1 changesets with 2 changes to 2 files (+1 heads)
55 (run 'hg heads' to see heads, 'hg merge' to merge)
55 (run 'hg heads' to see heads, 'hg merge' to merge)
56
56
57 $ hg merge -v
57 $ hg merge -v
58 resolving manifests
58 resolving manifests
59 getting bar
59 getting bar
60 merging foo
60 merging foo
61 merging for foo
61 merging for foo
62 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
62 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
63 (branch merge, don't forget to commit)
63 (branch merge, don't forget to commit)
64
64
65 $ echo 2m > foo
65 $ echo 2m > foo
66 $ echo 2b > baz
66 $ echo 2b > baz
67 $ echo new > quux
67 $ echo new > quux
68
68
69 We shouldn't have anything but foo in merge state here:
69 We shouldn't have anything but foo in merge state here:
70
70
71 $ hg debugstate --nodates | grep "^m"
71 $ hg debugstate --nodates | grep "^m"
72 m 644 3 foo
72 m 644 3 foo
73
73
74 $ hg ci -m "merge"
74 $ hg ci -m "merge"
75
75
76 main: we should have a merge here:
76 main: we should have a merge here:
77
77
78 $ hg debugindex .hg/store/00changelog.i
78 $ hg debugindex --changelog
79 rev offset length base linkrev nodeid p1 p2
79 rev offset length base linkrev nodeid p1 p2
80 0 0 73 0 0 cdca01651b96 000000000000 000000000000
80 0 0 73 0 0 cdca01651b96 000000000000 000000000000
81 1 73 68 1 1 f6718a9cb7f3 cdca01651b96 000000000000
81 1 73 68 1 1 f6718a9cb7f3 cdca01651b96 000000000000
82 2 141 68 2 2 bdd988058d16 cdca01651b96 000000000000
82 2 141 68 2 2 bdd988058d16 cdca01651b96 000000000000
83 3 209 66 3 3 d8a521142a3c f6718a9cb7f3 bdd988058d16
83 3 209 66 3 3 d8a521142a3c f6718a9cb7f3 bdd988058d16
84
84
85 log should show foo and quux changed:
85 log should show foo and quux changed:
86
86
87 $ hg log -v -r tip
87 $ hg log -v -r tip
88 changeset: 3:d8a521142a3c
88 changeset: 3:d8a521142a3c
89 tag: tip
89 tag: tip
90 parent: 1:f6718a9cb7f3
90 parent: 1:f6718a9cb7f3
91 parent: 2:bdd988058d16
91 parent: 2:bdd988058d16
92 user: test
92 user: test
93 date: Thu Jan 01 00:00:00 1970 +0000
93 date: Thu Jan 01 00:00:00 1970 +0000
94 files: foo quux
94 files: foo quux
95 description:
95 description:
96 merge
96 merge
97
97
98
98
99
99
100 foo: we should have a merge here:
100 foo: we should have a merge here:
101
101
102 $ hg debugindex foo
102 $ hg debugindex foo
103 rev offset length base linkrev nodeid p1 p2
103 rev offset length base linkrev nodeid p1 p2
104 0 0 3 0 0 b8e02f643373 000000000000 000000000000
104 0 0 3 0 0 b8e02f643373 000000000000 000000000000
105 1 3 4 1 1 2ffeddde1b65 b8e02f643373 000000000000
105 1 3 4 1 1 2ffeddde1b65 b8e02f643373 000000000000
106 2 7 4 2 2 33d1fb69067a b8e02f643373 000000000000
106 2 7 4 2 2 33d1fb69067a b8e02f643373 000000000000
107 3 11 4 3 3 aa27919ee430 2ffeddde1b65 33d1fb69067a
107 3 11 4 3 3 aa27919ee430 2ffeddde1b65 33d1fb69067a
108
108
109 bar: we should not have a merge here:
109 bar: we should not have a merge here:
110
110
111 $ hg debugindex bar
111 $ hg debugindex bar
112 rev offset length base linkrev nodeid p1 p2
112 rev offset length base linkrev nodeid p1 p2
113 0 0 3 0 0 b8e02f643373 000000000000 000000000000
113 0 0 3 0 0 b8e02f643373 000000000000 000000000000
114 1 3 4 1 2 33d1fb69067a b8e02f643373 000000000000
114 1 3 4 1 2 33d1fb69067a b8e02f643373 000000000000
115
115
116 baz: we should not have a merge here:
116 baz: we should not have a merge here:
117
117
118 $ hg debugindex baz
118 $ hg debugindex baz
119 rev offset length base linkrev nodeid p1 p2
119 rev offset length base linkrev nodeid p1 p2
120 0 0 3 0 0 b8e02f643373 000000000000 000000000000
120 0 0 3 0 0 b8e02f643373 000000000000 000000000000
121 1 3 4 1 1 2ffeddde1b65 b8e02f643373 000000000000
121 1 3 4 1 1 2ffeddde1b65 b8e02f643373 000000000000
122
122
123 quux: we should not have a merge here:
123 quux: we should not have a merge here:
124
124
125 $ hg debugindex quux
125 $ hg debugindex quux
126 rev offset length base linkrev nodeid p1 p2
126 rev offset length base linkrev nodeid p1 p2
127 0 0 3 0 0 b8e02f643373 000000000000 000000000000
127 0 0 3 0 0 b8e02f643373 000000000000 000000000000
128 1 3 5 1 3 6128c0f33108 b8e02f643373 000000000000
128 1 3 5 1 3 6128c0f33108 b8e02f643373 000000000000
129
129
130 Manifest entries should match tips of all files:
130 Manifest entries should match tips of all files:
131
131
132 $ hg manifest --debug
132 $ hg manifest --debug
133 33d1fb69067a0139622a3fa3b7ba1cdb1367972e 644 bar
133 33d1fb69067a0139622a3fa3b7ba1cdb1367972e 644 bar
134 2ffeddde1b65b4827f6746174a145474129fa2ce 644 baz
134 2ffeddde1b65b4827f6746174a145474129fa2ce 644 baz
135 aa27919ee4303cfd575e1fb932dd64d75aa08be4 644 foo
135 aa27919ee4303cfd575e1fb932dd64d75aa08be4 644 foo
136 6128c0f33108e8cfbb4e0824d13ae48b466d7280 644 quux
136 6128c0f33108e8cfbb4e0824d13ae48b466d7280 644 quux
137
137
138 Everything should be clean now:
138 Everything should be clean now:
139
139
140 $ hg status
140 $ hg status
141
141
142 $ hg verify
142 $ hg verify
143 checking changesets
143 checking changesets
144 checking manifests
144 checking manifests
145 crosschecking files in changesets and manifests
145 crosschecking files in changesets and manifests
146 checking files
146 checking files
147 4 files, 4 changesets, 10 total revisions
147 4 files, 4 changesets, 10 total revisions
148
148
@@ -1,143 +1,143 b''
1 test stripping of filelogs where the linkrev doesn't always increase
1 test stripping of filelogs where the linkrev doesn't always increase
2
2
3 $ echo '[extensions]' >> $HGRCPATH
3 $ echo '[extensions]' >> $HGRCPATH
4 $ echo 'hgext.mq =' >> $HGRCPATH
4 $ echo 'hgext.mq =' >> $HGRCPATH
5 $ hg init orig
5 $ hg init orig
6 $ cd orig
6 $ cd orig
7 $ commit()
7 $ commit()
8 > {
8 > {
9 > hg up -qC null
9 > hg up -qC null
10 > count=1
10 > count=1
11 > for i in "$@"; do
11 > for i in "$@"; do
12 > for f in $i; do
12 > for f in $i; do
13 > echo $count > $f
13 > echo $count > $f
14 > done
14 > done
15 > count=`expr $count + 1`
15 > count=`expr $count + 1`
16 > done
16 > done
17 > hg commit -qAm "$*"
17 > hg commit -qAm "$*"
18 > }
18 > }
19
19
20 2 1 0 2 0 1 2
20 2 1 0 2 0 1 2
21
21
22 $ commit '201 210'
22 $ commit '201 210'
23 $ commit '102 120' '210'
23 $ commit '102 120' '210'
24 $ commit '021'
24 $ commit '021'
25 $ commit '201' '021 120'
25 $ commit '201' '021 120'
26 $ commit '012 021' '102 201' '120 210'
26 $ commit '012 021' '102 201' '120 210'
27 $ commit 'manifest-file'
27 $ commit 'manifest-file'
28 $ commit '102 120' '012 210' '021 201'
28 $ commit '102 120' '012 210' '021 201'
29 $ commit '201 210' '021 120' '012 102'
29 $ commit '201 210' '021 120' '012 102'
30 $ HGUSER=another-user; export HGUSER
30 $ HGUSER=another-user; export HGUSER
31 $ commit 'manifest-file'
31 $ commit 'manifest-file'
32 $ commit '012' 'manifest-file'
32 $ commit '012' 'manifest-file'
33 $ cd ..
33 $ cd ..
34 $ hg clone -q -U -r -1 -r -2 -r -3 -r -4 -r -6 orig crossed
34 $ hg clone -q -U -r -1 -r -2 -r -3 -r -4 -r -6 orig crossed
35 $ cd crossed
35 $ cd crossed
36 $ hg debugindex .hg/store/00manifest.i
36 $ hg debugindex --manifest
37 rev offset length base linkrev nodeid p1 p2
37 rev offset length base linkrev nodeid p1 p2
38 0 0 112 0 0 6f105cbb914d 000000000000 000000000000
38 0 0 112 0 0 6f105cbb914d 000000000000 000000000000
39 1 112 56 1 3 1b55917b3699 000000000000 000000000000
39 1 112 56 1 3 1b55917b3699 000000000000 000000000000
40 2 168 123 1 1 8f3d04e263e5 000000000000 000000000000
40 2 168 123 1 1 8f3d04e263e5 000000000000 000000000000
41 3 291 122 1 2 f0ef8726ac4f 000000000000 000000000000
41 3 291 122 1 2 f0ef8726ac4f 000000000000 000000000000
42 4 413 87 4 4 0b76e38b4070 000000000000 000000000000
42 4 413 87 4 4 0b76e38b4070 000000000000 000000000000
43
43
44 $ for i in 012 021 102 120 201 210 manifest-file; do
44 $ for i in 012 021 102 120 201 210 manifest-file; do
45 > echo $i
45 > echo $i
46 > hg debugindex $i
46 > hg debugindex $i
47 > echo
47 > echo
48 > done
48 > done
49 012
49 012
50 rev offset length base linkrev nodeid p1 p2
50 rev offset length base linkrev nodeid p1 p2
51 0 0 3 0 0 b8e02f643373 000000000000 000000000000
51 0 0 3 0 0 b8e02f643373 000000000000 000000000000
52 1 3 3 1 1 5d9299349fc0 000000000000 000000000000
52 1 3 3 1 1 5d9299349fc0 000000000000 000000000000
53 2 6 3 2 2 2661d26c6496 000000000000 000000000000
53 2 6 3 2 2 2661d26c6496 000000000000 000000000000
54
54
55 021
55 021
56 rev offset length base linkrev nodeid p1 p2
56 rev offset length base linkrev nodeid p1 p2
57 0 0 3 0 0 b8e02f643373 000000000000 000000000000
57 0 0 3 0 0 b8e02f643373 000000000000 000000000000
58 1 3 3 1 2 5d9299349fc0 000000000000 000000000000
58 1 3 3 1 2 5d9299349fc0 000000000000 000000000000
59 2 6 3 2 1 2661d26c6496 000000000000 000000000000
59 2 6 3 2 1 2661d26c6496 000000000000 000000000000
60
60
61 102
61 102
62 rev offset length base linkrev nodeid p1 p2
62 rev offset length base linkrev nodeid p1 p2
63 0 0 3 0 1 b8e02f643373 000000000000 000000000000
63 0 0 3 0 1 b8e02f643373 000000000000 000000000000
64 1 3 3 1 0 5d9299349fc0 000000000000 000000000000
64 1 3 3 1 0 5d9299349fc0 000000000000 000000000000
65 2 6 3 2 2 2661d26c6496 000000000000 000000000000
65 2 6 3 2 2 2661d26c6496 000000000000 000000000000
66
66
67 120
67 120
68 rev offset length base linkrev nodeid p1 p2
68 rev offset length base linkrev nodeid p1 p2
69 0 0 3 0 1 b8e02f643373 000000000000 000000000000
69 0 0 3 0 1 b8e02f643373 000000000000 000000000000
70 1 3 3 1 2 5d9299349fc0 000000000000 000000000000
70 1 3 3 1 2 5d9299349fc0 000000000000 000000000000
71 2 6 3 2 0 2661d26c6496 000000000000 000000000000
71 2 6 3 2 0 2661d26c6496 000000000000 000000000000
72
72
73 201
73 201
74 rev offset length base linkrev nodeid p1 p2
74 rev offset length base linkrev nodeid p1 p2
75 0 0 3 0 2 b8e02f643373 000000000000 000000000000
75 0 0 3 0 2 b8e02f643373 000000000000 000000000000
76 1 3 3 1 0 5d9299349fc0 000000000000 000000000000
76 1 3 3 1 0 5d9299349fc0 000000000000 000000000000
77 2 6 3 2 1 2661d26c6496 000000000000 000000000000
77 2 6 3 2 1 2661d26c6496 000000000000 000000000000
78
78
79 210
79 210
80 rev offset length base linkrev nodeid p1 p2
80 rev offset length base linkrev nodeid p1 p2
81 0 0 3 0 2 b8e02f643373 000000000000 000000000000
81 0 0 3 0 2 b8e02f643373 000000000000 000000000000
82 1 3 3 1 1 5d9299349fc0 000000000000 000000000000
82 1 3 3 1 1 5d9299349fc0 000000000000 000000000000
83 2 6 3 2 0 2661d26c6496 000000000000 000000000000
83 2 6 3 2 0 2661d26c6496 000000000000 000000000000
84
84
85 manifest-file
85 manifest-file
86 rev offset length base linkrev nodeid p1 p2
86 rev offset length base linkrev nodeid p1 p2
87 0 0 3 0 3 b8e02f643373 000000000000 000000000000
87 0 0 3 0 3 b8e02f643373 000000000000 000000000000
88 1 3 3 1 4 5d9299349fc0 000000000000 000000000000
88 1 3 3 1 4 5d9299349fc0 000000000000 000000000000
89
89
90 $ cd ..
90 $ cd ..
91 $ for i in 0 1 2 3 4; do
91 $ for i in 0 1 2 3 4; do
92 > hg clone -q -U --pull crossed $i
92 > hg clone -q -U --pull crossed $i
93 > echo "% Trying to strip revision $i"
93 > echo "% Trying to strip revision $i"
94 > hg --cwd $i strip $i
94 > hg --cwd $i strip $i
95 > echo "% Verifying"
95 > echo "% Verifying"
96 > hg --cwd $i verify
96 > hg --cwd $i verify
97 > echo
97 > echo
98 > done
98 > done
99 % Trying to strip revision 0
99 % Trying to strip revision 0
100 saved backup bundle to $TESTTMP/0/.hg/strip-backup/*-backup.hg (glob)
100 saved backup bundle to $TESTTMP/0/.hg/strip-backup/*-backup.hg (glob)
101 % Verifying
101 % Verifying
102 checking changesets
102 checking changesets
103 checking manifests
103 checking manifests
104 crosschecking files in changesets and manifests
104 crosschecking files in changesets and manifests
105 checking files
105 checking files
106 7 files, 4 changesets, 15 total revisions
106 7 files, 4 changesets, 15 total revisions
107
107
108 % Trying to strip revision 1
108 % Trying to strip revision 1
109 saved backup bundle to $TESTTMP/1/.hg/strip-backup/*-backup.hg (glob)
109 saved backup bundle to $TESTTMP/1/.hg/strip-backup/*-backup.hg (glob)
110 % Verifying
110 % Verifying
111 checking changesets
111 checking changesets
112 checking manifests
112 checking manifests
113 crosschecking files in changesets and manifests
113 crosschecking files in changesets and manifests
114 checking files
114 checking files
115 7 files, 4 changesets, 14 total revisions
115 7 files, 4 changesets, 14 total revisions
116
116
117 % Trying to strip revision 2
117 % Trying to strip revision 2
118 saved backup bundle to $TESTTMP/2/.hg/strip-backup/*-backup.hg (glob)
118 saved backup bundle to $TESTTMP/2/.hg/strip-backup/*-backup.hg (glob)
119 % Verifying
119 % Verifying
120 checking changesets
120 checking changesets
121 checking manifests
121 checking manifests
122 crosschecking files in changesets and manifests
122 crosschecking files in changesets and manifests
123 checking files
123 checking files
124 7 files, 4 changesets, 14 total revisions
124 7 files, 4 changesets, 14 total revisions
125
125
126 % Trying to strip revision 3
126 % Trying to strip revision 3
127 saved backup bundle to $TESTTMP/3/.hg/strip-backup/*-backup.hg (glob)
127 saved backup bundle to $TESTTMP/3/.hg/strip-backup/*-backup.hg (glob)
128 % Verifying
128 % Verifying
129 checking changesets
129 checking changesets
130 checking manifests
130 checking manifests
131 crosschecking files in changesets and manifests
131 crosschecking files in changesets and manifests
132 checking files
132 checking files
133 7 files, 4 changesets, 19 total revisions
133 7 files, 4 changesets, 19 total revisions
134
134
135 % Trying to strip revision 4
135 % Trying to strip revision 4
136 saved backup bundle to $TESTTMP/4/.hg/strip-backup/*-backup.hg (glob)
136 saved backup bundle to $TESTTMP/4/.hg/strip-backup/*-backup.hg (glob)
137 % Verifying
137 % Verifying
138 checking changesets
138 checking changesets
139 checking manifests
139 checking manifests
140 crosschecking files in changesets and manifests
140 crosschecking files in changesets and manifests
141 checking files
141 checking files
142 7 files, 4 changesets, 19 total revisions
142 7 files, 4 changesets, 19 total revisions
143
143
General Comments 0
You need to be logged in to leave comments. Login now