##// END OF EJS Templates
debugobsolete: extract marker display in a dedicated function...
Pierre-Yves David -
r20470:78f4c2b7 default
parent child Browse files
Show More
@@ -1,2167 +1,2180
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, nullid, nullrev, short
8 from node import hex, nullid, nullrev, short
9 from i18n import _
9 from i18n import _
10 import os, sys, errno, re, tempfile
10 import os, sys, errno, re, tempfile
11 import util, scmutil, templater, patch, error, templatekw, revlog, copies
11 import util, scmutil, templater, patch, error, templatekw, revlog, copies
12 import match as matchmod
12 import match as matchmod
13 import context, repair, graphmod, revset, phases, obsolete, pathutil
13 import context, repair, graphmod, revset, phases, obsolete, pathutil
14 import changelog
14 import changelog
15 import bookmarks
15 import bookmarks
16 import lock as lockmod
16 import lock as lockmod
17
17
18 def parsealiases(cmd):
18 def parsealiases(cmd):
19 return cmd.lstrip("^").split("|")
19 return cmd.lstrip("^").split("|")
20
20
21 def findpossible(cmd, table, strict=False):
21 def findpossible(cmd, table, strict=False):
22 """
22 """
23 Return cmd -> (aliases, command table entry)
23 Return cmd -> (aliases, command table entry)
24 for each matching command.
24 for each matching command.
25 Return debug commands (or their aliases) only if no normal command matches.
25 Return debug commands (or their aliases) only if no normal command matches.
26 """
26 """
27 choice = {}
27 choice = {}
28 debugchoice = {}
28 debugchoice = {}
29
29
30 if cmd in table:
30 if cmd in table:
31 # short-circuit exact matches, "log" alias beats "^log|history"
31 # short-circuit exact matches, "log" alias beats "^log|history"
32 keys = [cmd]
32 keys = [cmd]
33 else:
33 else:
34 keys = table.keys()
34 keys = table.keys()
35
35
36 for e in keys:
36 for e in keys:
37 aliases = parsealiases(e)
37 aliases = parsealiases(e)
38 found = None
38 found = None
39 if cmd in aliases:
39 if cmd in aliases:
40 found = cmd
40 found = cmd
41 elif not strict:
41 elif not strict:
42 for a in aliases:
42 for a in aliases:
43 if a.startswith(cmd):
43 if a.startswith(cmd):
44 found = a
44 found = a
45 break
45 break
46 if found is not None:
46 if found is not None:
47 if aliases[0].startswith("debug") or found.startswith("debug"):
47 if aliases[0].startswith("debug") or found.startswith("debug"):
48 debugchoice[found] = (aliases, table[e])
48 debugchoice[found] = (aliases, table[e])
49 else:
49 else:
50 choice[found] = (aliases, table[e])
50 choice[found] = (aliases, table[e])
51
51
52 if not choice and debugchoice:
52 if not choice and debugchoice:
53 choice = debugchoice
53 choice = debugchoice
54
54
55 return choice
55 return choice
56
56
57 def findcmd(cmd, table, strict=True):
57 def findcmd(cmd, table, strict=True):
58 """Return (aliases, command table entry) for command string."""
58 """Return (aliases, command table entry) for command string."""
59 choice = findpossible(cmd, table, strict)
59 choice = findpossible(cmd, table, strict)
60
60
61 if cmd in choice:
61 if cmd in choice:
62 return choice[cmd]
62 return choice[cmd]
63
63
64 if len(choice) > 1:
64 if len(choice) > 1:
65 clist = choice.keys()
65 clist = choice.keys()
66 clist.sort()
66 clist.sort()
67 raise error.AmbiguousCommand(cmd, clist)
67 raise error.AmbiguousCommand(cmd, clist)
68
68
69 if choice:
69 if choice:
70 return choice.values()[0]
70 return choice.values()[0]
71
71
72 raise error.UnknownCommand(cmd)
72 raise error.UnknownCommand(cmd)
73
73
74 def findrepo(p):
74 def findrepo(p):
75 while not os.path.isdir(os.path.join(p, ".hg")):
75 while not os.path.isdir(os.path.join(p, ".hg")):
76 oldp, p = p, os.path.dirname(p)
76 oldp, p = p, os.path.dirname(p)
77 if p == oldp:
77 if p == oldp:
78 return None
78 return None
79
79
80 return p
80 return p
81
81
82 def bailifchanged(repo):
82 def bailifchanged(repo):
83 if repo.dirstate.p2() != nullid:
83 if repo.dirstate.p2() != nullid:
84 raise util.Abort(_('outstanding uncommitted merge'))
84 raise util.Abort(_('outstanding uncommitted merge'))
85 modified, added, removed, deleted = repo.status()[:4]
85 modified, added, removed, deleted = repo.status()[:4]
86 if modified or added or removed or deleted:
86 if modified or added or removed or deleted:
87 raise util.Abort(_('uncommitted changes'))
87 raise util.Abort(_('uncommitted changes'))
88 ctx = repo[None]
88 ctx = repo[None]
89 for s in sorted(ctx.substate):
89 for s in sorted(ctx.substate):
90 if ctx.sub(s).dirty():
90 if ctx.sub(s).dirty():
91 raise util.Abort(_("uncommitted changes in subrepo %s") % s)
91 raise util.Abort(_("uncommitted changes in subrepo %s") % s)
92
92
93 def logmessage(ui, opts):
93 def logmessage(ui, opts):
94 """ get the log message according to -m and -l option """
94 """ get the log message according to -m and -l option """
95 message = opts.get('message')
95 message = opts.get('message')
96 logfile = opts.get('logfile')
96 logfile = opts.get('logfile')
97
97
98 if message and logfile:
98 if message and logfile:
99 raise util.Abort(_('options --message and --logfile are mutually '
99 raise util.Abort(_('options --message and --logfile are mutually '
100 'exclusive'))
100 'exclusive'))
101 if not message and logfile:
101 if not message and logfile:
102 try:
102 try:
103 if logfile == '-':
103 if logfile == '-':
104 message = ui.fin.read()
104 message = ui.fin.read()
105 else:
105 else:
106 message = '\n'.join(util.readfile(logfile).splitlines())
106 message = '\n'.join(util.readfile(logfile).splitlines())
107 except IOError, inst:
107 except IOError, inst:
108 raise util.Abort(_("can't read commit message '%s': %s") %
108 raise util.Abort(_("can't read commit message '%s': %s") %
109 (logfile, inst.strerror))
109 (logfile, inst.strerror))
110 return message
110 return message
111
111
112 def loglimit(opts):
112 def loglimit(opts):
113 """get the log limit according to option -l/--limit"""
113 """get the log limit according to option -l/--limit"""
114 limit = opts.get('limit')
114 limit = opts.get('limit')
115 if limit:
115 if limit:
116 try:
116 try:
117 limit = int(limit)
117 limit = int(limit)
118 except ValueError:
118 except ValueError:
119 raise util.Abort(_('limit must be a positive integer'))
119 raise util.Abort(_('limit must be a positive integer'))
120 if limit <= 0:
120 if limit <= 0:
121 raise util.Abort(_('limit must be positive'))
121 raise util.Abort(_('limit must be positive'))
122 else:
122 else:
123 limit = None
123 limit = None
124 return limit
124 return limit
125
125
126 def makefilename(repo, pat, node, desc=None,
126 def makefilename(repo, pat, node, desc=None,
127 total=None, seqno=None, revwidth=None, pathname=None):
127 total=None, seqno=None, revwidth=None, pathname=None):
128 node_expander = {
128 node_expander = {
129 'H': lambda: hex(node),
129 'H': lambda: hex(node),
130 'R': lambda: str(repo.changelog.rev(node)),
130 'R': lambda: str(repo.changelog.rev(node)),
131 'h': lambda: short(node),
131 'h': lambda: short(node),
132 'm': lambda: re.sub('[^\w]', '_', str(desc))
132 'm': lambda: re.sub('[^\w]', '_', str(desc))
133 }
133 }
134 expander = {
134 expander = {
135 '%': lambda: '%',
135 '%': lambda: '%',
136 'b': lambda: os.path.basename(repo.root),
136 'b': lambda: os.path.basename(repo.root),
137 }
137 }
138
138
139 try:
139 try:
140 if node:
140 if node:
141 expander.update(node_expander)
141 expander.update(node_expander)
142 if node:
142 if node:
143 expander['r'] = (lambda:
143 expander['r'] = (lambda:
144 str(repo.changelog.rev(node)).zfill(revwidth or 0))
144 str(repo.changelog.rev(node)).zfill(revwidth or 0))
145 if total is not None:
145 if total is not None:
146 expander['N'] = lambda: str(total)
146 expander['N'] = lambda: str(total)
147 if seqno is not None:
147 if seqno is not None:
148 expander['n'] = lambda: str(seqno)
148 expander['n'] = lambda: str(seqno)
149 if total is not None and seqno is not None:
149 if total is not None and seqno is not None:
150 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
150 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
151 if pathname is not None:
151 if pathname is not None:
152 expander['s'] = lambda: os.path.basename(pathname)
152 expander['s'] = lambda: os.path.basename(pathname)
153 expander['d'] = lambda: os.path.dirname(pathname) or '.'
153 expander['d'] = lambda: os.path.dirname(pathname) or '.'
154 expander['p'] = lambda: pathname
154 expander['p'] = lambda: pathname
155
155
156 newname = []
156 newname = []
157 patlen = len(pat)
157 patlen = len(pat)
158 i = 0
158 i = 0
159 while i < patlen:
159 while i < patlen:
160 c = pat[i]
160 c = pat[i]
161 if c == '%':
161 if c == '%':
162 i += 1
162 i += 1
163 c = pat[i]
163 c = pat[i]
164 c = expander[c]()
164 c = expander[c]()
165 newname.append(c)
165 newname.append(c)
166 i += 1
166 i += 1
167 return ''.join(newname)
167 return ''.join(newname)
168 except KeyError, inst:
168 except KeyError, inst:
169 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
169 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
170 inst.args[0])
170 inst.args[0])
171
171
172 def makefileobj(repo, pat, node=None, desc=None, total=None,
172 def makefileobj(repo, pat, node=None, desc=None, total=None,
173 seqno=None, revwidth=None, mode='wb', modemap=None,
173 seqno=None, revwidth=None, mode='wb', modemap=None,
174 pathname=None):
174 pathname=None):
175
175
176 writable = mode not in ('r', 'rb')
176 writable = mode not in ('r', 'rb')
177
177
178 if not pat or pat == '-':
178 if not pat or pat == '-':
179 fp = writable and repo.ui.fout or repo.ui.fin
179 fp = writable and repo.ui.fout or repo.ui.fin
180 if util.safehasattr(fp, 'fileno'):
180 if util.safehasattr(fp, 'fileno'):
181 return os.fdopen(os.dup(fp.fileno()), mode)
181 return os.fdopen(os.dup(fp.fileno()), mode)
182 else:
182 else:
183 # if this fp can't be duped properly, return
183 # if this fp can't be duped properly, return
184 # a dummy object that can be closed
184 # a dummy object that can be closed
185 class wrappedfileobj(object):
185 class wrappedfileobj(object):
186 noop = lambda x: None
186 noop = lambda x: None
187 def __init__(self, f):
187 def __init__(self, f):
188 self.f = f
188 self.f = f
189 def __getattr__(self, attr):
189 def __getattr__(self, attr):
190 if attr == 'close':
190 if attr == 'close':
191 return self.noop
191 return self.noop
192 else:
192 else:
193 return getattr(self.f, attr)
193 return getattr(self.f, attr)
194
194
195 return wrappedfileobj(fp)
195 return wrappedfileobj(fp)
196 if util.safehasattr(pat, 'write') and writable:
196 if util.safehasattr(pat, 'write') and writable:
197 return pat
197 return pat
198 if util.safehasattr(pat, 'read') and 'r' in mode:
198 if util.safehasattr(pat, 'read') and 'r' in mode:
199 return pat
199 return pat
200 fn = makefilename(repo, pat, node, desc, total, seqno, revwidth, pathname)
200 fn = makefilename(repo, pat, node, desc, total, seqno, revwidth, pathname)
201 if modemap is not None:
201 if modemap is not None:
202 mode = modemap.get(fn, mode)
202 mode = modemap.get(fn, mode)
203 if mode == 'wb':
203 if mode == 'wb':
204 modemap[fn] = 'ab'
204 modemap[fn] = 'ab'
205 return open(fn, mode)
205 return open(fn, mode)
206
206
207 def openrevlog(repo, cmd, file_, opts):
207 def openrevlog(repo, cmd, file_, opts):
208 """opens the changelog, manifest, a filelog or a given revlog"""
208 """opens the changelog, manifest, a filelog or a given revlog"""
209 cl = opts['changelog']
209 cl = opts['changelog']
210 mf = opts['manifest']
210 mf = opts['manifest']
211 msg = None
211 msg = None
212 if cl and mf:
212 if cl and mf:
213 msg = _('cannot specify --changelog and --manifest at the same time')
213 msg = _('cannot specify --changelog and --manifest at the same time')
214 elif cl or mf:
214 elif cl or mf:
215 if file_:
215 if file_:
216 msg = _('cannot specify filename with --changelog or --manifest')
216 msg = _('cannot specify filename with --changelog or --manifest')
217 elif not repo:
217 elif not repo:
218 msg = _('cannot specify --changelog or --manifest '
218 msg = _('cannot specify --changelog or --manifest '
219 'without a repository')
219 'without a repository')
220 if msg:
220 if msg:
221 raise util.Abort(msg)
221 raise util.Abort(msg)
222
222
223 r = None
223 r = None
224 if repo:
224 if repo:
225 if cl:
225 if cl:
226 r = repo.changelog
226 r = repo.changelog
227 elif mf:
227 elif mf:
228 r = repo.manifest
228 r = repo.manifest
229 elif file_:
229 elif file_:
230 filelog = repo.file(file_)
230 filelog = repo.file(file_)
231 if len(filelog):
231 if len(filelog):
232 r = filelog
232 r = filelog
233 if not r:
233 if not r:
234 if not file_:
234 if not file_:
235 raise error.CommandError(cmd, _('invalid arguments'))
235 raise error.CommandError(cmd, _('invalid arguments'))
236 if not os.path.isfile(file_):
236 if not os.path.isfile(file_):
237 raise util.Abort(_("revlog '%s' not found") % file_)
237 raise util.Abort(_("revlog '%s' not found") % file_)
238 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
238 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
239 file_[:-2] + ".i")
239 file_[:-2] + ".i")
240 return r
240 return r
241
241
242 def copy(ui, repo, pats, opts, rename=False):
242 def copy(ui, repo, pats, opts, rename=False):
243 # called with the repo lock held
243 # called with the repo lock held
244 #
244 #
245 # hgsep => pathname that uses "/" to separate directories
245 # hgsep => pathname that uses "/" to separate directories
246 # ossep => pathname that uses os.sep to separate directories
246 # ossep => pathname that uses os.sep to separate directories
247 cwd = repo.getcwd()
247 cwd = repo.getcwd()
248 targets = {}
248 targets = {}
249 after = opts.get("after")
249 after = opts.get("after")
250 dryrun = opts.get("dry_run")
250 dryrun = opts.get("dry_run")
251 wctx = repo[None]
251 wctx = repo[None]
252
252
253 def walkpat(pat):
253 def walkpat(pat):
254 srcs = []
254 srcs = []
255 badstates = after and '?' or '?r'
255 badstates = after and '?' or '?r'
256 m = scmutil.match(repo[None], [pat], opts, globbed=True)
256 m = scmutil.match(repo[None], [pat], opts, globbed=True)
257 for abs in repo.walk(m):
257 for abs in repo.walk(m):
258 state = repo.dirstate[abs]
258 state = repo.dirstate[abs]
259 rel = m.rel(abs)
259 rel = m.rel(abs)
260 exact = m.exact(abs)
260 exact = m.exact(abs)
261 if state in badstates:
261 if state in badstates:
262 if exact and state == '?':
262 if exact and state == '?':
263 ui.warn(_('%s: not copying - file is not managed\n') % rel)
263 ui.warn(_('%s: not copying - file is not managed\n') % rel)
264 if exact and state == 'r':
264 if exact and state == 'r':
265 ui.warn(_('%s: not copying - file has been marked for'
265 ui.warn(_('%s: not copying - file has been marked for'
266 ' remove\n') % rel)
266 ' remove\n') % rel)
267 continue
267 continue
268 # abs: hgsep
268 # abs: hgsep
269 # rel: ossep
269 # rel: ossep
270 srcs.append((abs, rel, exact))
270 srcs.append((abs, rel, exact))
271 return srcs
271 return srcs
272
272
273 # abssrc: hgsep
273 # abssrc: hgsep
274 # relsrc: ossep
274 # relsrc: ossep
275 # otarget: ossep
275 # otarget: ossep
276 def copyfile(abssrc, relsrc, otarget, exact):
276 def copyfile(abssrc, relsrc, otarget, exact):
277 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
277 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
278 if '/' in abstarget:
278 if '/' in abstarget:
279 # We cannot normalize abstarget itself, this would prevent
279 # We cannot normalize abstarget itself, this would prevent
280 # case only renames, like a => A.
280 # case only renames, like a => A.
281 abspath, absname = abstarget.rsplit('/', 1)
281 abspath, absname = abstarget.rsplit('/', 1)
282 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
282 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
283 reltarget = repo.pathto(abstarget, cwd)
283 reltarget = repo.pathto(abstarget, cwd)
284 target = repo.wjoin(abstarget)
284 target = repo.wjoin(abstarget)
285 src = repo.wjoin(abssrc)
285 src = repo.wjoin(abssrc)
286 state = repo.dirstate[abstarget]
286 state = repo.dirstate[abstarget]
287
287
288 scmutil.checkportable(ui, abstarget)
288 scmutil.checkportable(ui, abstarget)
289
289
290 # check for collisions
290 # check for collisions
291 prevsrc = targets.get(abstarget)
291 prevsrc = targets.get(abstarget)
292 if prevsrc is not None:
292 if prevsrc is not None:
293 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
293 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
294 (reltarget, repo.pathto(abssrc, cwd),
294 (reltarget, repo.pathto(abssrc, cwd),
295 repo.pathto(prevsrc, cwd)))
295 repo.pathto(prevsrc, cwd)))
296 return
296 return
297
297
298 # check for overwrites
298 # check for overwrites
299 exists = os.path.lexists(target)
299 exists = os.path.lexists(target)
300 samefile = False
300 samefile = False
301 if exists and abssrc != abstarget:
301 if exists and abssrc != abstarget:
302 if (repo.dirstate.normalize(abssrc) ==
302 if (repo.dirstate.normalize(abssrc) ==
303 repo.dirstate.normalize(abstarget)):
303 repo.dirstate.normalize(abstarget)):
304 if not rename:
304 if not rename:
305 ui.warn(_("%s: can't copy - same file\n") % reltarget)
305 ui.warn(_("%s: can't copy - same file\n") % reltarget)
306 return
306 return
307 exists = False
307 exists = False
308 samefile = True
308 samefile = True
309
309
310 if not after and exists or after and state in 'mn':
310 if not after and exists or after and state in 'mn':
311 if not opts['force']:
311 if not opts['force']:
312 ui.warn(_('%s: not overwriting - file exists\n') %
312 ui.warn(_('%s: not overwriting - file exists\n') %
313 reltarget)
313 reltarget)
314 return
314 return
315
315
316 if after:
316 if after:
317 if not exists:
317 if not exists:
318 if rename:
318 if rename:
319 ui.warn(_('%s: not recording move - %s does not exist\n') %
319 ui.warn(_('%s: not recording move - %s does not exist\n') %
320 (relsrc, reltarget))
320 (relsrc, reltarget))
321 else:
321 else:
322 ui.warn(_('%s: not recording copy - %s does not exist\n') %
322 ui.warn(_('%s: not recording copy - %s does not exist\n') %
323 (relsrc, reltarget))
323 (relsrc, reltarget))
324 return
324 return
325 elif not dryrun:
325 elif not dryrun:
326 try:
326 try:
327 if exists:
327 if exists:
328 os.unlink(target)
328 os.unlink(target)
329 targetdir = os.path.dirname(target) or '.'
329 targetdir = os.path.dirname(target) or '.'
330 if not os.path.isdir(targetdir):
330 if not os.path.isdir(targetdir):
331 os.makedirs(targetdir)
331 os.makedirs(targetdir)
332 if samefile:
332 if samefile:
333 tmp = target + "~hgrename"
333 tmp = target + "~hgrename"
334 os.rename(src, tmp)
334 os.rename(src, tmp)
335 os.rename(tmp, target)
335 os.rename(tmp, target)
336 else:
336 else:
337 util.copyfile(src, target)
337 util.copyfile(src, target)
338 srcexists = True
338 srcexists = True
339 except IOError, inst:
339 except IOError, inst:
340 if inst.errno == errno.ENOENT:
340 if inst.errno == errno.ENOENT:
341 ui.warn(_('%s: deleted in working copy\n') % relsrc)
341 ui.warn(_('%s: deleted in working copy\n') % relsrc)
342 srcexists = False
342 srcexists = False
343 else:
343 else:
344 ui.warn(_('%s: cannot copy - %s\n') %
344 ui.warn(_('%s: cannot copy - %s\n') %
345 (relsrc, inst.strerror))
345 (relsrc, inst.strerror))
346 return True # report a failure
346 return True # report a failure
347
347
348 if ui.verbose or not exact:
348 if ui.verbose or not exact:
349 if rename:
349 if rename:
350 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
350 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
351 else:
351 else:
352 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
352 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
353
353
354 targets[abstarget] = abssrc
354 targets[abstarget] = abssrc
355
355
356 # fix up dirstate
356 # fix up dirstate
357 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
357 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
358 dryrun=dryrun, cwd=cwd)
358 dryrun=dryrun, cwd=cwd)
359 if rename and not dryrun:
359 if rename and not dryrun:
360 if not after and srcexists and not samefile:
360 if not after and srcexists and not samefile:
361 util.unlinkpath(repo.wjoin(abssrc))
361 util.unlinkpath(repo.wjoin(abssrc))
362 wctx.forget([abssrc])
362 wctx.forget([abssrc])
363
363
364 # pat: ossep
364 # pat: ossep
365 # dest ossep
365 # dest ossep
366 # srcs: list of (hgsep, hgsep, ossep, bool)
366 # srcs: list of (hgsep, hgsep, ossep, bool)
367 # return: function that takes hgsep and returns ossep
367 # return: function that takes hgsep and returns ossep
368 def targetpathfn(pat, dest, srcs):
368 def targetpathfn(pat, dest, srcs):
369 if os.path.isdir(pat):
369 if os.path.isdir(pat):
370 abspfx = pathutil.canonpath(repo.root, cwd, pat)
370 abspfx = pathutil.canonpath(repo.root, cwd, pat)
371 abspfx = util.localpath(abspfx)
371 abspfx = util.localpath(abspfx)
372 if destdirexists:
372 if destdirexists:
373 striplen = len(os.path.split(abspfx)[0])
373 striplen = len(os.path.split(abspfx)[0])
374 else:
374 else:
375 striplen = len(abspfx)
375 striplen = len(abspfx)
376 if striplen:
376 if striplen:
377 striplen += len(os.sep)
377 striplen += len(os.sep)
378 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
378 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
379 elif destdirexists:
379 elif destdirexists:
380 res = lambda p: os.path.join(dest,
380 res = lambda p: os.path.join(dest,
381 os.path.basename(util.localpath(p)))
381 os.path.basename(util.localpath(p)))
382 else:
382 else:
383 res = lambda p: dest
383 res = lambda p: dest
384 return res
384 return res
385
385
386 # pat: ossep
386 # pat: ossep
387 # dest ossep
387 # dest ossep
388 # srcs: list of (hgsep, hgsep, ossep, bool)
388 # srcs: list of (hgsep, hgsep, ossep, bool)
389 # return: function that takes hgsep and returns ossep
389 # return: function that takes hgsep and returns ossep
390 def targetpathafterfn(pat, dest, srcs):
390 def targetpathafterfn(pat, dest, srcs):
391 if matchmod.patkind(pat):
391 if matchmod.patkind(pat):
392 # a mercurial pattern
392 # a mercurial pattern
393 res = lambda p: os.path.join(dest,
393 res = lambda p: os.path.join(dest,
394 os.path.basename(util.localpath(p)))
394 os.path.basename(util.localpath(p)))
395 else:
395 else:
396 abspfx = pathutil.canonpath(repo.root, cwd, pat)
396 abspfx = pathutil.canonpath(repo.root, cwd, pat)
397 if len(abspfx) < len(srcs[0][0]):
397 if len(abspfx) < len(srcs[0][0]):
398 # A directory. Either the target path contains the last
398 # A directory. Either the target path contains the last
399 # component of the source path or it does not.
399 # component of the source path or it does not.
400 def evalpath(striplen):
400 def evalpath(striplen):
401 score = 0
401 score = 0
402 for s in srcs:
402 for s in srcs:
403 t = os.path.join(dest, util.localpath(s[0])[striplen:])
403 t = os.path.join(dest, util.localpath(s[0])[striplen:])
404 if os.path.lexists(t):
404 if os.path.lexists(t):
405 score += 1
405 score += 1
406 return score
406 return score
407
407
408 abspfx = util.localpath(abspfx)
408 abspfx = util.localpath(abspfx)
409 striplen = len(abspfx)
409 striplen = len(abspfx)
410 if striplen:
410 if striplen:
411 striplen += len(os.sep)
411 striplen += len(os.sep)
412 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
412 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
413 score = evalpath(striplen)
413 score = evalpath(striplen)
414 striplen1 = len(os.path.split(abspfx)[0])
414 striplen1 = len(os.path.split(abspfx)[0])
415 if striplen1:
415 if striplen1:
416 striplen1 += len(os.sep)
416 striplen1 += len(os.sep)
417 if evalpath(striplen1) > score:
417 if evalpath(striplen1) > score:
418 striplen = striplen1
418 striplen = striplen1
419 res = lambda p: os.path.join(dest,
419 res = lambda p: os.path.join(dest,
420 util.localpath(p)[striplen:])
420 util.localpath(p)[striplen:])
421 else:
421 else:
422 # a file
422 # a file
423 if destdirexists:
423 if destdirexists:
424 res = lambda p: os.path.join(dest,
424 res = lambda p: os.path.join(dest,
425 os.path.basename(util.localpath(p)))
425 os.path.basename(util.localpath(p)))
426 else:
426 else:
427 res = lambda p: dest
427 res = lambda p: dest
428 return res
428 return res
429
429
430
430
431 pats = scmutil.expandpats(pats)
431 pats = scmutil.expandpats(pats)
432 if not pats:
432 if not pats:
433 raise util.Abort(_('no source or destination specified'))
433 raise util.Abort(_('no source or destination specified'))
434 if len(pats) == 1:
434 if len(pats) == 1:
435 raise util.Abort(_('no destination specified'))
435 raise util.Abort(_('no destination specified'))
436 dest = pats.pop()
436 dest = pats.pop()
437 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
437 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
438 if not destdirexists:
438 if not destdirexists:
439 if len(pats) > 1 or matchmod.patkind(pats[0]):
439 if len(pats) > 1 or matchmod.patkind(pats[0]):
440 raise util.Abort(_('with multiple sources, destination must be an '
440 raise util.Abort(_('with multiple sources, destination must be an '
441 'existing directory'))
441 'existing directory'))
442 if util.endswithsep(dest):
442 if util.endswithsep(dest):
443 raise util.Abort(_('destination %s is not a directory') % dest)
443 raise util.Abort(_('destination %s is not a directory') % dest)
444
444
445 tfn = targetpathfn
445 tfn = targetpathfn
446 if after:
446 if after:
447 tfn = targetpathafterfn
447 tfn = targetpathafterfn
448 copylist = []
448 copylist = []
449 for pat in pats:
449 for pat in pats:
450 srcs = walkpat(pat)
450 srcs = walkpat(pat)
451 if not srcs:
451 if not srcs:
452 continue
452 continue
453 copylist.append((tfn(pat, dest, srcs), srcs))
453 copylist.append((tfn(pat, dest, srcs), srcs))
454 if not copylist:
454 if not copylist:
455 raise util.Abort(_('no files to copy'))
455 raise util.Abort(_('no files to copy'))
456
456
457 errors = 0
457 errors = 0
458 for targetpath, srcs in copylist:
458 for targetpath, srcs in copylist:
459 for abssrc, relsrc, exact in srcs:
459 for abssrc, relsrc, exact in srcs:
460 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
460 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
461 errors += 1
461 errors += 1
462
462
463 if errors:
463 if errors:
464 ui.warn(_('(consider using --after)\n'))
464 ui.warn(_('(consider using --after)\n'))
465
465
466 return errors != 0
466 return errors != 0
467
467
468 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
468 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
469 runargs=None, appendpid=False):
469 runargs=None, appendpid=False):
470 '''Run a command as a service.'''
470 '''Run a command as a service.'''
471
471
472 def writepid(pid):
472 def writepid(pid):
473 if opts['pid_file']:
473 if opts['pid_file']:
474 mode = appendpid and 'a' or 'w'
474 mode = appendpid and 'a' or 'w'
475 fp = open(opts['pid_file'], mode)
475 fp = open(opts['pid_file'], mode)
476 fp.write(str(pid) + '\n')
476 fp.write(str(pid) + '\n')
477 fp.close()
477 fp.close()
478
478
479 if opts['daemon'] and not opts['daemon_pipefds']:
479 if opts['daemon'] and not opts['daemon_pipefds']:
480 # Signal child process startup with file removal
480 # Signal child process startup with file removal
481 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
481 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
482 os.close(lockfd)
482 os.close(lockfd)
483 try:
483 try:
484 if not runargs:
484 if not runargs:
485 runargs = util.hgcmd() + sys.argv[1:]
485 runargs = util.hgcmd() + sys.argv[1:]
486 runargs.append('--daemon-pipefds=%s' % lockpath)
486 runargs.append('--daemon-pipefds=%s' % lockpath)
487 # Don't pass --cwd to the child process, because we've already
487 # Don't pass --cwd to the child process, because we've already
488 # changed directory.
488 # changed directory.
489 for i in xrange(1, len(runargs)):
489 for i in xrange(1, len(runargs)):
490 if runargs[i].startswith('--cwd='):
490 if runargs[i].startswith('--cwd='):
491 del runargs[i]
491 del runargs[i]
492 break
492 break
493 elif runargs[i].startswith('--cwd'):
493 elif runargs[i].startswith('--cwd'):
494 del runargs[i:i + 2]
494 del runargs[i:i + 2]
495 break
495 break
496 def condfn():
496 def condfn():
497 return not os.path.exists(lockpath)
497 return not os.path.exists(lockpath)
498 pid = util.rundetached(runargs, condfn)
498 pid = util.rundetached(runargs, condfn)
499 if pid < 0:
499 if pid < 0:
500 raise util.Abort(_('child process failed to start'))
500 raise util.Abort(_('child process failed to start'))
501 writepid(pid)
501 writepid(pid)
502 finally:
502 finally:
503 try:
503 try:
504 os.unlink(lockpath)
504 os.unlink(lockpath)
505 except OSError, e:
505 except OSError, e:
506 if e.errno != errno.ENOENT:
506 if e.errno != errno.ENOENT:
507 raise
507 raise
508 if parentfn:
508 if parentfn:
509 return parentfn(pid)
509 return parentfn(pid)
510 else:
510 else:
511 return
511 return
512
512
513 if initfn:
513 if initfn:
514 initfn()
514 initfn()
515
515
516 if not opts['daemon']:
516 if not opts['daemon']:
517 writepid(os.getpid())
517 writepid(os.getpid())
518
518
519 if opts['daemon_pipefds']:
519 if opts['daemon_pipefds']:
520 lockpath = opts['daemon_pipefds']
520 lockpath = opts['daemon_pipefds']
521 try:
521 try:
522 os.setsid()
522 os.setsid()
523 except AttributeError:
523 except AttributeError:
524 pass
524 pass
525 os.unlink(lockpath)
525 os.unlink(lockpath)
526 util.hidewindow()
526 util.hidewindow()
527 sys.stdout.flush()
527 sys.stdout.flush()
528 sys.stderr.flush()
528 sys.stderr.flush()
529
529
530 nullfd = os.open(os.devnull, os.O_RDWR)
530 nullfd = os.open(os.devnull, os.O_RDWR)
531 logfilefd = nullfd
531 logfilefd = nullfd
532 if logfile:
532 if logfile:
533 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
533 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
534 os.dup2(nullfd, 0)
534 os.dup2(nullfd, 0)
535 os.dup2(logfilefd, 1)
535 os.dup2(logfilefd, 1)
536 os.dup2(logfilefd, 2)
536 os.dup2(logfilefd, 2)
537 if nullfd not in (0, 1, 2):
537 if nullfd not in (0, 1, 2):
538 os.close(nullfd)
538 os.close(nullfd)
539 if logfile and logfilefd not in (0, 1, 2):
539 if logfile and logfilefd not in (0, 1, 2):
540 os.close(logfilefd)
540 os.close(logfilefd)
541
541
542 if runfn:
542 if runfn:
543 return runfn()
543 return runfn()
544
544
545 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
545 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
546 opts=None):
546 opts=None):
547 '''export changesets as hg patches.'''
547 '''export changesets as hg patches.'''
548
548
549 total = len(revs)
549 total = len(revs)
550 revwidth = max([len(str(rev)) for rev in revs])
550 revwidth = max([len(str(rev)) for rev in revs])
551 filemode = {}
551 filemode = {}
552
552
553 def single(rev, seqno, fp):
553 def single(rev, seqno, fp):
554 ctx = repo[rev]
554 ctx = repo[rev]
555 node = ctx.node()
555 node = ctx.node()
556 parents = [p.node() for p in ctx.parents() if p]
556 parents = [p.node() for p in ctx.parents() if p]
557 branch = ctx.branch()
557 branch = ctx.branch()
558 if switch_parent:
558 if switch_parent:
559 parents.reverse()
559 parents.reverse()
560 prev = (parents and parents[0]) or nullid
560 prev = (parents and parents[0]) or nullid
561
561
562 shouldclose = False
562 shouldclose = False
563 if not fp and len(template) > 0:
563 if not fp and len(template) > 0:
564 desc_lines = ctx.description().rstrip().split('\n')
564 desc_lines = ctx.description().rstrip().split('\n')
565 desc = desc_lines[0] #Commit always has a first line.
565 desc = desc_lines[0] #Commit always has a first line.
566 fp = makefileobj(repo, template, node, desc=desc, total=total,
566 fp = makefileobj(repo, template, node, desc=desc, total=total,
567 seqno=seqno, revwidth=revwidth, mode='wb',
567 seqno=seqno, revwidth=revwidth, mode='wb',
568 modemap=filemode)
568 modemap=filemode)
569 if fp != template:
569 if fp != template:
570 shouldclose = True
570 shouldclose = True
571 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
571 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
572 repo.ui.note("%s\n" % fp.name)
572 repo.ui.note("%s\n" % fp.name)
573
573
574 if not fp:
574 if not fp:
575 write = repo.ui.write
575 write = repo.ui.write
576 else:
576 else:
577 def write(s, **kw):
577 def write(s, **kw):
578 fp.write(s)
578 fp.write(s)
579
579
580
580
581 write("# HG changeset patch\n")
581 write("# HG changeset patch\n")
582 write("# User %s\n" % ctx.user())
582 write("# User %s\n" % ctx.user())
583 write("# Date %d %d\n" % ctx.date())
583 write("# Date %d %d\n" % ctx.date())
584 write("# %s\n" % util.datestr(ctx.date()))
584 write("# %s\n" % util.datestr(ctx.date()))
585 if branch and branch != 'default':
585 if branch and branch != 'default':
586 write("# Branch %s\n" % branch)
586 write("# Branch %s\n" % branch)
587 write("# Node ID %s\n" % hex(node))
587 write("# Node ID %s\n" % hex(node))
588 write("# Parent %s\n" % hex(prev))
588 write("# Parent %s\n" % hex(prev))
589 if len(parents) > 1:
589 if len(parents) > 1:
590 write("# Parent %s\n" % hex(parents[1]))
590 write("# Parent %s\n" % hex(parents[1]))
591 write(ctx.description().rstrip())
591 write(ctx.description().rstrip())
592 write("\n\n")
592 write("\n\n")
593
593
594 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
594 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
595 write(chunk, label=label)
595 write(chunk, label=label)
596
596
597 if shouldclose:
597 if shouldclose:
598 fp.close()
598 fp.close()
599
599
600 for seqno, rev in enumerate(revs):
600 for seqno, rev in enumerate(revs):
601 single(rev, seqno + 1, fp)
601 single(rev, seqno + 1, fp)
602
602
603 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
603 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
604 changes=None, stat=False, fp=None, prefix='',
604 changes=None, stat=False, fp=None, prefix='',
605 listsubrepos=False):
605 listsubrepos=False):
606 '''show diff or diffstat.'''
606 '''show diff or diffstat.'''
607 if fp is None:
607 if fp is None:
608 write = ui.write
608 write = ui.write
609 else:
609 else:
610 def write(s, **kw):
610 def write(s, **kw):
611 fp.write(s)
611 fp.write(s)
612
612
613 if stat:
613 if stat:
614 diffopts = diffopts.copy(context=0)
614 diffopts = diffopts.copy(context=0)
615 width = 80
615 width = 80
616 if not ui.plain():
616 if not ui.plain():
617 width = ui.termwidth()
617 width = ui.termwidth()
618 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
618 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
619 prefix=prefix)
619 prefix=prefix)
620 for chunk, label in patch.diffstatui(util.iterlines(chunks),
620 for chunk, label in patch.diffstatui(util.iterlines(chunks),
621 width=width,
621 width=width,
622 git=diffopts.git):
622 git=diffopts.git):
623 write(chunk, label=label)
623 write(chunk, label=label)
624 else:
624 else:
625 for chunk, label in patch.diffui(repo, node1, node2, match,
625 for chunk, label in patch.diffui(repo, node1, node2, match,
626 changes, diffopts, prefix=prefix):
626 changes, diffopts, prefix=prefix):
627 write(chunk, label=label)
627 write(chunk, label=label)
628
628
629 if listsubrepos:
629 if listsubrepos:
630 ctx1 = repo[node1]
630 ctx1 = repo[node1]
631 ctx2 = repo[node2]
631 ctx2 = repo[node2]
632 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
632 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
633 tempnode2 = node2
633 tempnode2 = node2
634 try:
634 try:
635 if node2 is not None:
635 if node2 is not None:
636 tempnode2 = ctx2.substate[subpath][1]
636 tempnode2 = ctx2.substate[subpath][1]
637 except KeyError:
637 except KeyError:
638 # A subrepo that existed in node1 was deleted between node1 and
638 # A subrepo that existed in node1 was deleted between node1 and
639 # node2 (inclusive). Thus, ctx2's substate won't contain that
639 # node2 (inclusive). Thus, ctx2's substate won't contain that
640 # subpath. The best we can do is to ignore it.
640 # subpath. The best we can do is to ignore it.
641 tempnode2 = None
641 tempnode2 = None
642 submatch = matchmod.narrowmatcher(subpath, match)
642 submatch = matchmod.narrowmatcher(subpath, match)
643 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
643 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
644 stat=stat, fp=fp, prefix=prefix)
644 stat=stat, fp=fp, prefix=prefix)
645
645
646 class changeset_printer(object):
646 class changeset_printer(object):
647 '''show changeset information when templating not requested.'''
647 '''show changeset information when templating not requested.'''
648
648
649 def __init__(self, ui, repo, patch, diffopts, buffered):
649 def __init__(self, ui, repo, patch, diffopts, buffered):
650 self.ui = ui
650 self.ui = ui
651 self.repo = repo
651 self.repo = repo
652 self.buffered = buffered
652 self.buffered = buffered
653 self.patch = patch
653 self.patch = patch
654 self.diffopts = diffopts
654 self.diffopts = diffopts
655 self.header = {}
655 self.header = {}
656 self.hunk = {}
656 self.hunk = {}
657 self.lastheader = None
657 self.lastheader = None
658 self.footer = None
658 self.footer = None
659
659
660 def flush(self, rev):
660 def flush(self, rev):
661 if rev in self.header:
661 if rev in self.header:
662 h = self.header[rev]
662 h = self.header[rev]
663 if h != self.lastheader:
663 if h != self.lastheader:
664 self.lastheader = h
664 self.lastheader = h
665 self.ui.write(h)
665 self.ui.write(h)
666 del self.header[rev]
666 del self.header[rev]
667 if rev in self.hunk:
667 if rev in self.hunk:
668 self.ui.write(self.hunk[rev])
668 self.ui.write(self.hunk[rev])
669 del self.hunk[rev]
669 del self.hunk[rev]
670 return 1
670 return 1
671 return 0
671 return 0
672
672
673 def close(self):
673 def close(self):
674 if self.footer:
674 if self.footer:
675 self.ui.write(self.footer)
675 self.ui.write(self.footer)
676
676
677 def show(self, ctx, copies=None, matchfn=None, **props):
677 def show(self, ctx, copies=None, matchfn=None, **props):
678 if self.buffered:
678 if self.buffered:
679 self.ui.pushbuffer()
679 self.ui.pushbuffer()
680 self._show(ctx, copies, matchfn, props)
680 self._show(ctx, copies, matchfn, props)
681 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
681 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
682 else:
682 else:
683 self._show(ctx, copies, matchfn, props)
683 self._show(ctx, copies, matchfn, props)
684
684
685 def _show(self, ctx, copies, matchfn, props):
685 def _show(self, ctx, copies, matchfn, props):
686 '''show a single changeset or file revision'''
686 '''show a single changeset or file revision'''
687 changenode = ctx.node()
687 changenode = ctx.node()
688 rev = ctx.rev()
688 rev = ctx.rev()
689
689
690 if self.ui.quiet:
690 if self.ui.quiet:
691 self.ui.write("%d:%s\n" % (rev, short(changenode)),
691 self.ui.write("%d:%s\n" % (rev, short(changenode)),
692 label='log.node')
692 label='log.node')
693 return
693 return
694
694
695 log = self.repo.changelog
695 log = self.repo.changelog
696 date = util.datestr(ctx.date())
696 date = util.datestr(ctx.date())
697
697
698 hexfunc = self.ui.debugflag and hex or short
698 hexfunc = self.ui.debugflag and hex or short
699
699
700 parents = [(p, hexfunc(log.node(p)))
700 parents = [(p, hexfunc(log.node(p)))
701 for p in self._meaningful_parentrevs(log, rev)]
701 for p in self._meaningful_parentrevs(log, rev)]
702
702
703 # i18n: column positioning for "hg log"
703 # i18n: column positioning for "hg log"
704 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
704 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
705 label='log.changeset changeset.%s' % ctx.phasestr())
705 label='log.changeset changeset.%s' % ctx.phasestr())
706
706
707 branch = ctx.branch()
707 branch = ctx.branch()
708 # don't show the default branch name
708 # don't show the default branch name
709 if branch != 'default':
709 if branch != 'default':
710 # i18n: column positioning for "hg log"
710 # i18n: column positioning for "hg log"
711 self.ui.write(_("branch: %s\n") % branch,
711 self.ui.write(_("branch: %s\n") % branch,
712 label='log.branch')
712 label='log.branch')
713 for bookmark in self.repo.nodebookmarks(changenode):
713 for bookmark in self.repo.nodebookmarks(changenode):
714 # i18n: column positioning for "hg log"
714 # i18n: column positioning for "hg log"
715 self.ui.write(_("bookmark: %s\n") % bookmark,
715 self.ui.write(_("bookmark: %s\n") % bookmark,
716 label='log.bookmark')
716 label='log.bookmark')
717 for tag in self.repo.nodetags(changenode):
717 for tag in self.repo.nodetags(changenode):
718 # i18n: column positioning for "hg log"
718 # i18n: column positioning for "hg log"
719 self.ui.write(_("tag: %s\n") % tag,
719 self.ui.write(_("tag: %s\n") % tag,
720 label='log.tag')
720 label='log.tag')
721 if self.ui.debugflag and ctx.phase():
721 if self.ui.debugflag and ctx.phase():
722 # i18n: column positioning for "hg log"
722 # i18n: column positioning for "hg log"
723 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
723 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
724 label='log.phase')
724 label='log.phase')
725 for parent in parents:
725 for parent in parents:
726 # i18n: column positioning for "hg log"
726 # i18n: column positioning for "hg log"
727 self.ui.write(_("parent: %d:%s\n") % parent,
727 self.ui.write(_("parent: %d:%s\n") % parent,
728 label='log.parent changeset.%s' % ctx.phasestr())
728 label='log.parent changeset.%s' % ctx.phasestr())
729
729
730 if self.ui.debugflag:
730 if self.ui.debugflag:
731 mnode = ctx.manifestnode()
731 mnode = ctx.manifestnode()
732 # i18n: column positioning for "hg log"
732 # i18n: column positioning for "hg log"
733 self.ui.write(_("manifest: %d:%s\n") %
733 self.ui.write(_("manifest: %d:%s\n") %
734 (self.repo.manifest.rev(mnode), hex(mnode)),
734 (self.repo.manifest.rev(mnode), hex(mnode)),
735 label='ui.debug log.manifest')
735 label='ui.debug log.manifest')
736 # i18n: column positioning for "hg log"
736 # i18n: column positioning for "hg log"
737 self.ui.write(_("user: %s\n") % ctx.user(),
737 self.ui.write(_("user: %s\n") % ctx.user(),
738 label='log.user')
738 label='log.user')
739 # i18n: column positioning for "hg log"
739 # i18n: column positioning for "hg log"
740 self.ui.write(_("date: %s\n") % date,
740 self.ui.write(_("date: %s\n") % date,
741 label='log.date')
741 label='log.date')
742
742
743 if self.ui.debugflag:
743 if self.ui.debugflag:
744 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
744 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
745 for key, value in zip([# i18n: column positioning for "hg log"
745 for key, value in zip([# i18n: column positioning for "hg log"
746 _("files:"),
746 _("files:"),
747 # i18n: column positioning for "hg log"
747 # i18n: column positioning for "hg log"
748 _("files+:"),
748 _("files+:"),
749 # i18n: column positioning for "hg log"
749 # i18n: column positioning for "hg log"
750 _("files-:")], files):
750 _("files-:")], files):
751 if value:
751 if value:
752 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
752 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
753 label='ui.debug log.files')
753 label='ui.debug log.files')
754 elif ctx.files() and self.ui.verbose:
754 elif ctx.files() and self.ui.verbose:
755 # i18n: column positioning for "hg log"
755 # i18n: column positioning for "hg log"
756 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
756 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
757 label='ui.note log.files')
757 label='ui.note log.files')
758 if copies and self.ui.verbose:
758 if copies and self.ui.verbose:
759 copies = ['%s (%s)' % c for c in copies]
759 copies = ['%s (%s)' % c for c in copies]
760 # i18n: column positioning for "hg log"
760 # i18n: column positioning for "hg log"
761 self.ui.write(_("copies: %s\n") % ' '.join(copies),
761 self.ui.write(_("copies: %s\n") % ' '.join(copies),
762 label='ui.note log.copies')
762 label='ui.note log.copies')
763
763
764 extra = ctx.extra()
764 extra = ctx.extra()
765 if extra and self.ui.debugflag:
765 if extra and self.ui.debugflag:
766 for key, value in sorted(extra.items()):
766 for key, value in sorted(extra.items()):
767 # i18n: column positioning for "hg log"
767 # i18n: column positioning for "hg log"
768 self.ui.write(_("extra: %s=%s\n")
768 self.ui.write(_("extra: %s=%s\n")
769 % (key, value.encode('string_escape')),
769 % (key, value.encode('string_escape')),
770 label='ui.debug log.extra')
770 label='ui.debug log.extra')
771
771
772 description = ctx.description().strip()
772 description = ctx.description().strip()
773 if description:
773 if description:
774 if self.ui.verbose:
774 if self.ui.verbose:
775 self.ui.write(_("description:\n"),
775 self.ui.write(_("description:\n"),
776 label='ui.note log.description')
776 label='ui.note log.description')
777 self.ui.write(description,
777 self.ui.write(description,
778 label='ui.note log.description')
778 label='ui.note log.description')
779 self.ui.write("\n\n")
779 self.ui.write("\n\n")
780 else:
780 else:
781 # i18n: column positioning for "hg log"
781 # i18n: column positioning for "hg log"
782 self.ui.write(_("summary: %s\n") %
782 self.ui.write(_("summary: %s\n") %
783 description.splitlines()[0],
783 description.splitlines()[0],
784 label='log.summary')
784 label='log.summary')
785 self.ui.write("\n")
785 self.ui.write("\n")
786
786
787 self.showpatch(changenode, matchfn)
787 self.showpatch(changenode, matchfn)
788
788
789 def showpatch(self, node, matchfn):
789 def showpatch(self, node, matchfn):
790 if not matchfn:
790 if not matchfn:
791 matchfn = self.patch
791 matchfn = self.patch
792 if matchfn:
792 if matchfn:
793 stat = self.diffopts.get('stat')
793 stat = self.diffopts.get('stat')
794 diff = self.diffopts.get('patch')
794 diff = self.diffopts.get('patch')
795 diffopts = patch.diffopts(self.ui, self.diffopts)
795 diffopts = patch.diffopts(self.ui, self.diffopts)
796 prev = self.repo.changelog.parents(node)[0]
796 prev = self.repo.changelog.parents(node)[0]
797 if stat:
797 if stat:
798 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
798 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
799 match=matchfn, stat=True)
799 match=matchfn, stat=True)
800 if diff:
800 if diff:
801 if stat:
801 if stat:
802 self.ui.write("\n")
802 self.ui.write("\n")
803 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
803 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
804 match=matchfn, stat=False)
804 match=matchfn, stat=False)
805 self.ui.write("\n")
805 self.ui.write("\n")
806
806
807 def _meaningful_parentrevs(self, log, rev):
807 def _meaningful_parentrevs(self, log, rev):
808 """Return list of meaningful (or all if debug) parentrevs for rev.
808 """Return list of meaningful (or all if debug) parentrevs for rev.
809
809
810 For merges (two non-nullrev revisions) both parents are meaningful.
810 For merges (two non-nullrev revisions) both parents are meaningful.
811 Otherwise the first parent revision is considered meaningful if it
811 Otherwise the first parent revision is considered meaningful if it
812 is not the preceding revision.
812 is not the preceding revision.
813 """
813 """
814 parents = log.parentrevs(rev)
814 parents = log.parentrevs(rev)
815 if not self.ui.debugflag and parents[1] == nullrev:
815 if not self.ui.debugflag and parents[1] == nullrev:
816 if parents[0] >= rev - 1:
816 if parents[0] >= rev - 1:
817 parents = []
817 parents = []
818 else:
818 else:
819 parents = [parents[0]]
819 parents = [parents[0]]
820 return parents
820 return parents
821
821
822
822
823 class changeset_templater(changeset_printer):
823 class changeset_templater(changeset_printer):
824 '''format changeset information.'''
824 '''format changeset information.'''
825
825
826 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
826 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
827 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
827 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
828 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
828 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
829 defaulttempl = {
829 defaulttempl = {
830 'parent': '{rev}:{node|formatnode} ',
830 'parent': '{rev}:{node|formatnode} ',
831 'manifest': '{rev}:{node|formatnode}',
831 'manifest': '{rev}:{node|formatnode}',
832 'file_copy': '{name} ({source})',
832 'file_copy': '{name} ({source})',
833 'extra': '{key}={value|stringescape}'
833 'extra': '{key}={value|stringescape}'
834 }
834 }
835 # filecopy is preserved for compatibility reasons
835 # filecopy is preserved for compatibility reasons
836 defaulttempl['filecopy'] = defaulttempl['file_copy']
836 defaulttempl['filecopy'] = defaulttempl['file_copy']
837 self.t = templater.templater(mapfile, {'formatnode': formatnode},
837 self.t = templater.templater(mapfile, {'formatnode': formatnode},
838 cache=defaulttempl)
838 cache=defaulttempl)
839 self.cache = {}
839 self.cache = {}
840
840
841 def use_template(self, t):
841 def use_template(self, t):
842 '''set template string to use'''
842 '''set template string to use'''
843 self.t.cache['changeset'] = t
843 self.t.cache['changeset'] = t
844
844
845 def _meaningful_parentrevs(self, ctx):
845 def _meaningful_parentrevs(self, ctx):
846 """Return list of meaningful (or all if debug) parentrevs for rev.
846 """Return list of meaningful (or all if debug) parentrevs for rev.
847 """
847 """
848 parents = ctx.parents()
848 parents = ctx.parents()
849 if len(parents) > 1:
849 if len(parents) > 1:
850 return parents
850 return parents
851 if self.ui.debugflag:
851 if self.ui.debugflag:
852 return [parents[0], self.repo['null']]
852 return [parents[0], self.repo['null']]
853 if parents[0].rev() >= ctx.rev() - 1:
853 if parents[0].rev() >= ctx.rev() - 1:
854 return []
854 return []
855 return parents
855 return parents
856
856
857 def _show(self, ctx, copies, matchfn, props):
857 def _show(self, ctx, copies, matchfn, props):
858 '''show a single changeset or file revision'''
858 '''show a single changeset or file revision'''
859
859
860 showlist = templatekw.showlist
860 showlist = templatekw.showlist
861
861
862 # showparents() behaviour depends on ui trace level which
862 # showparents() behaviour depends on ui trace level which
863 # causes unexpected behaviours at templating level and makes
863 # causes unexpected behaviours at templating level and makes
864 # it harder to extract it in a standalone function. Its
864 # it harder to extract it in a standalone function. Its
865 # behaviour cannot be changed so leave it here for now.
865 # behaviour cannot be changed so leave it here for now.
866 def showparents(**args):
866 def showparents(**args):
867 ctx = args['ctx']
867 ctx = args['ctx']
868 parents = [[('rev', p.rev()), ('node', p.hex())]
868 parents = [[('rev', p.rev()), ('node', p.hex())]
869 for p in self._meaningful_parentrevs(ctx)]
869 for p in self._meaningful_parentrevs(ctx)]
870 return showlist('parent', parents, **args)
870 return showlist('parent', parents, **args)
871
871
872 props = props.copy()
872 props = props.copy()
873 props.update(templatekw.keywords)
873 props.update(templatekw.keywords)
874 props['parents'] = showparents
874 props['parents'] = showparents
875 props['templ'] = self.t
875 props['templ'] = self.t
876 props['ctx'] = ctx
876 props['ctx'] = ctx
877 props['repo'] = self.repo
877 props['repo'] = self.repo
878 props['revcache'] = {'copies': copies}
878 props['revcache'] = {'copies': copies}
879 props['cache'] = self.cache
879 props['cache'] = self.cache
880
880
881 # find correct templates for current mode
881 # find correct templates for current mode
882
882
883 tmplmodes = [
883 tmplmodes = [
884 (True, None),
884 (True, None),
885 (self.ui.verbose, 'verbose'),
885 (self.ui.verbose, 'verbose'),
886 (self.ui.quiet, 'quiet'),
886 (self.ui.quiet, 'quiet'),
887 (self.ui.debugflag, 'debug'),
887 (self.ui.debugflag, 'debug'),
888 ]
888 ]
889
889
890 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
890 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
891 for mode, postfix in tmplmodes:
891 for mode, postfix in tmplmodes:
892 for type in types:
892 for type in types:
893 cur = postfix and ('%s_%s' % (type, postfix)) or type
893 cur = postfix and ('%s_%s' % (type, postfix)) or type
894 if mode and cur in self.t:
894 if mode and cur in self.t:
895 types[type] = cur
895 types[type] = cur
896
896
897 try:
897 try:
898
898
899 # write header
899 # write header
900 if types['header']:
900 if types['header']:
901 h = templater.stringify(self.t(types['header'], **props))
901 h = templater.stringify(self.t(types['header'], **props))
902 if self.buffered:
902 if self.buffered:
903 self.header[ctx.rev()] = h
903 self.header[ctx.rev()] = h
904 else:
904 else:
905 if self.lastheader != h:
905 if self.lastheader != h:
906 self.lastheader = h
906 self.lastheader = h
907 self.ui.write(h)
907 self.ui.write(h)
908
908
909 # write changeset metadata, then patch if requested
909 # write changeset metadata, then patch if requested
910 key = types['changeset']
910 key = types['changeset']
911 self.ui.write(templater.stringify(self.t(key, **props)))
911 self.ui.write(templater.stringify(self.t(key, **props)))
912 self.showpatch(ctx.node(), matchfn)
912 self.showpatch(ctx.node(), matchfn)
913
913
914 if types['footer']:
914 if types['footer']:
915 if not self.footer:
915 if not self.footer:
916 self.footer = templater.stringify(self.t(types['footer'],
916 self.footer = templater.stringify(self.t(types['footer'],
917 **props))
917 **props))
918
918
919 except KeyError, inst:
919 except KeyError, inst:
920 msg = _("%s: no key named '%s'")
920 msg = _("%s: no key named '%s'")
921 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
921 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
922 except SyntaxError, inst:
922 except SyntaxError, inst:
923 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
923 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
924
924
925 def show_changeset(ui, repo, opts, buffered=False):
925 def show_changeset(ui, repo, opts, buffered=False):
926 """show one changeset using template or regular display.
926 """show one changeset using template or regular display.
927
927
928 Display format will be the first non-empty hit of:
928 Display format will be the first non-empty hit of:
929 1. option 'template'
929 1. option 'template'
930 2. option 'style'
930 2. option 'style'
931 3. [ui] setting 'logtemplate'
931 3. [ui] setting 'logtemplate'
932 4. [ui] setting 'style'
932 4. [ui] setting 'style'
933 If all of these values are either the unset or the empty string,
933 If all of these values are either the unset or the empty string,
934 regular display via changeset_printer() is done.
934 regular display via changeset_printer() is done.
935 """
935 """
936 # options
936 # options
937 patch = None
937 patch = None
938 if opts.get('patch') or opts.get('stat'):
938 if opts.get('patch') or opts.get('stat'):
939 patch = scmutil.matchall(repo)
939 patch = scmutil.matchall(repo)
940
940
941 tmpl = opts.get('template')
941 tmpl = opts.get('template')
942 style = None
942 style = None
943 if not tmpl:
943 if not tmpl:
944 style = opts.get('style')
944 style = opts.get('style')
945
945
946 # ui settings
946 # ui settings
947 if not (tmpl or style):
947 if not (tmpl or style):
948 tmpl = ui.config('ui', 'logtemplate')
948 tmpl = ui.config('ui', 'logtemplate')
949 if tmpl:
949 if tmpl:
950 try:
950 try:
951 tmpl = templater.parsestring(tmpl)
951 tmpl = templater.parsestring(tmpl)
952 except SyntaxError:
952 except SyntaxError:
953 tmpl = templater.parsestring(tmpl, quoted=False)
953 tmpl = templater.parsestring(tmpl, quoted=False)
954 else:
954 else:
955 style = util.expandpath(ui.config('ui', 'style', ''))
955 style = util.expandpath(ui.config('ui', 'style', ''))
956
956
957 if not (tmpl or style):
957 if not (tmpl or style):
958 return changeset_printer(ui, repo, patch, opts, buffered)
958 return changeset_printer(ui, repo, patch, opts, buffered)
959
959
960 mapfile = None
960 mapfile = None
961 if style and not tmpl:
961 if style and not tmpl:
962 mapfile = style
962 mapfile = style
963 if not os.path.split(mapfile)[0]:
963 if not os.path.split(mapfile)[0]:
964 mapname = (templater.templatepath('map-cmdline.' + mapfile)
964 mapname = (templater.templatepath('map-cmdline.' + mapfile)
965 or templater.templatepath(mapfile))
965 or templater.templatepath(mapfile))
966 if mapname:
966 if mapname:
967 mapfile = mapname
967 mapfile = mapname
968
968
969 try:
969 try:
970 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
970 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
971 except SyntaxError, inst:
971 except SyntaxError, inst:
972 raise util.Abort(inst.args[0])
972 raise util.Abort(inst.args[0])
973 if tmpl:
973 if tmpl:
974 t.use_template(tmpl)
974 t.use_template(tmpl)
975 return t
975 return t
976
976
977 def showmarker(ui, marker):
978 """utility function to display obsolescence marker in a readable way
979
980 To be used by debug function."""
981 ui.write(hex(marker.precnode()))
982 for repl in marker.succnodes():
983 ui.write(' ')
984 ui.write(hex(repl))
985 ui.write(' %X ' % marker._data[2])
986 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
987 sorted(marker.metadata().items()))))
988 ui.write('\n')
989
977 def finddate(ui, repo, date):
990 def finddate(ui, repo, date):
978 """Find the tipmost changeset that matches the given date spec"""
991 """Find the tipmost changeset that matches the given date spec"""
979
992
980 df = util.matchdate(date)
993 df = util.matchdate(date)
981 m = scmutil.matchall(repo)
994 m = scmutil.matchall(repo)
982 results = {}
995 results = {}
983
996
984 def prep(ctx, fns):
997 def prep(ctx, fns):
985 d = ctx.date()
998 d = ctx.date()
986 if df(d[0]):
999 if df(d[0]):
987 results[ctx.rev()] = d
1000 results[ctx.rev()] = d
988
1001
989 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1002 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
990 rev = ctx.rev()
1003 rev = ctx.rev()
991 if rev in results:
1004 if rev in results:
992 ui.status(_("found revision %s from %s\n") %
1005 ui.status(_("found revision %s from %s\n") %
993 (rev, util.datestr(results[rev])))
1006 (rev, util.datestr(results[rev])))
994 return str(rev)
1007 return str(rev)
995
1008
996 raise util.Abort(_("revision matching date not found"))
1009 raise util.Abort(_("revision matching date not found"))
997
1010
998 def increasingwindows(start, end, windowsize=8, sizelimit=512):
1011 def increasingwindows(start, end, windowsize=8, sizelimit=512):
999 if start < end:
1012 if start < end:
1000 while start < end:
1013 while start < end:
1001 yield start, min(windowsize, end - start)
1014 yield start, min(windowsize, end - start)
1002 start += windowsize
1015 start += windowsize
1003 if windowsize < sizelimit:
1016 if windowsize < sizelimit:
1004 windowsize *= 2
1017 windowsize *= 2
1005 else:
1018 else:
1006 while start > end:
1019 while start > end:
1007 yield start, min(windowsize, start - end - 1)
1020 yield start, min(windowsize, start - end - 1)
1008 start -= windowsize
1021 start -= windowsize
1009 if windowsize < sizelimit:
1022 if windowsize < sizelimit:
1010 windowsize *= 2
1023 windowsize *= 2
1011
1024
1012 class FileWalkError(Exception):
1025 class FileWalkError(Exception):
1013 pass
1026 pass
1014
1027
1015 def walkfilerevs(repo, match, follow, revs, fncache):
1028 def walkfilerevs(repo, match, follow, revs, fncache):
1016 '''Walks the file history for the matched files.
1029 '''Walks the file history for the matched files.
1017
1030
1018 Returns the changeset revs that are involved in the file history.
1031 Returns the changeset revs that are involved in the file history.
1019
1032
1020 Throws FileWalkError if the file history can't be walked using
1033 Throws FileWalkError if the file history can't be walked using
1021 filelogs alone.
1034 filelogs alone.
1022 '''
1035 '''
1023 wanted = set()
1036 wanted = set()
1024 copies = []
1037 copies = []
1025 minrev, maxrev = min(revs), max(revs)
1038 minrev, maxrev = min(revs), max(revs)
1026 def filerevgen(filelog, last):
1039 def filerevgen(filelog, last):
1027 """
1040 """
1028 Only files, no patterns. Check the history of each file.
1041 Only files, no patterns. Check the history of each file.
1029
1042
1030 Examines filelog entries within minrev, maxrev linkrev range
1043 Examines filelog entries within minrev, maxrev linkrev range
1031 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1044 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1032 tuples in backwards order
1045 tuples in backwards order
1033 """
1046 """
1034 cl_count = len(repo)
1047 cl_count = len(repo)
1035 revs = []
1048 revs = []
1036 for j in xrange(0, last + 1):
1049 for j in xrange(0, last + 1):
1037 linkrev = filelog.linkrev(j)
1050 linkrev = filelog.linkrev(j)
1038 if linkrev < minrev:
1051 if linkrev < minrev:
1039 continue
1052 continue
1040 # only yield rev for which we have the changelog, it can
1053 # only yield rev for which we have the changelog, it can
1041 # happen while doing "hg log" during a pull or commit
1054 # happen while doing "hg log" during a pull or commit
1042 if linkrev >= cl_count:
1055 if linkrev >= cl_count:
1043 break
1056 break
1044
1057
1045 parentlinkrevs = []
1058 parentlinkrevs = []
1046 for p in filelog.parentrevs(j):
1059 for p in filelog.parentrevs(j):
1047 if p != nullrev:
1060 if p != nullrev:
1048 parentlinkrevs.append(filelog.linkrev(p))
1061 parentlinkrevs.append(filelog.linkrev(p))
1049 n = filelog.node(j)
1062 n = filelog.node(j)
1050 revs.append((linkrev, parentlinkrevs,
1063 revs.append((linkrev, parentlinkrevs,
1051 follow and filelog.renamed(n)))
1064 follow and filelog.renamed(n)))
1052
1065
1053 return reversed(revs)
1066 return reversed(revs)
1054 def iterfiles():
1067 def iterfiles():
1055 pctx = repo['.']
1068 pctx = repo['.']
1056 for filename in match.files():
1069 for filename in match.files():
1057 if follow:
1070 if follow:
1058 if filename not in pctx:
1071 if filename not in pctx:
1059 raise util.Abort(_('cannot follow file not in parent '
1072 raise util.Abort(_('cannot follow file not in parent '
1060 'revision: "%s"') % filename)
1073 'revision: "%s"') % filename)
1061 yield filename, pctx[filename].filenode()
1074 yield filename, pctx[filename].filenode()
1062 else:
1075 else:
1063 yield filename, None
1076 yield filename, None
1064 for filename_node in copies:
1077 for filename_node in copies:
1065 yield filename_node
1078 yield filename_node
1066
1079
1067 for file_, node in iterfiles():
1080 for file_, node in iterfiles():
1068 filelog = repo.file(file_)
1081 filelog = repo.file(file_)
1069 if not len(filelog):
1082 if not len(filelog):
1070 if node is None:
1083 if node is None:
1071 # A zero count may be a directory or deleted file, so
1084 # A zero count may be a directory or deleted file, so
1072 # try to find matching entries on the slow path.
1085 # try to find matching entries on the slow path.
1073 if follow:
1086 if follow:
1074 raise util.Abort(
1087 raise util.Abort(
1075 _('cannot follow nonexistent file: "%s"') % file_)
1088 _('cannot follow nonexistent file: "%s"') % file_)
1076 raise FileWalkError("Cannot walk via filelog")
1089 raise FileWalkError("Cannot walk via filelog")
1077 else:
1090 else:
1078 continue
1091 continue
1079
1092
1080 if node is None:
1093 if node is None:
1081 last = len(filelog) - 1
1094 last = len(filelog) - 1
1082 else:
1095 else:
1083 last = filelog.rev(node)
1096 last = filelog.rev(node)
1084
1097
1085
1098
1086 # keep track of all ancestors of the file
1099 # keep track of all ancestors of the file
1087 ancestors = set([filelog.linkrev(last)])
1100 ancestors = set([filelog.linkrev(last)])
1088
1101
1089 # iterate from latest to oldest revision
1102 # iterate from latest to oldest revision
1090 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1103 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1091 if not follow:
1104 if not follow:
1092 if rev > maxrev:
1105 if rev > maxrev:
1093 continue
1106 continue
1094 else:
1107 else:
1095 # Note that last might not be the first interesting
1108 # Note that last might not be the first interesting
1096 # rev to us:
1109 # rev to us:
1097 # if the file has been changed after maxrev, we'll
1110 # if the file has been changed after maxrev, we'll
1098 # have linkrev(last) > maxrev, and we still need
1111 # have linkrev(last) > maxrev, and we still need
1099 # to explore the file graph
1112 # to explore the file graph
1100 if rev not in ancestors:
1113 if rev not in ancestors:
1101 continue
1114 continue
1102 # XXX insert 1327 fix here
1115 # XXX insert 1327 fix here
1103 if flparentlinkrevs:
1116 if flparentlinkrevs:
1104 ancestors.update(flparentlinkrevs)
1117 ancestors.update(flparentlinkrevs)
1105
1118
1106 fncache.setdefault(rev, []).append(file_)
1119 fncache.setdefault(rev, []).append(file_)
1107 wanted.add(rev)
1120 wanted.add(rev)
1108 if copied:
1121 if copied:
1109 copies.append(copied)
1122 copies.append(copied)
1110
1123
1111 return wanted
1124 return wanted
1112
1125
1113 def walkchangerevs(repo, match, opts, prepare):
1126 def walkchangerevs(repo, match, opts, prepare):
1114 '''Iterate over files and the revs in which they changed.
1127 '''Iterate over files and the revs in which they changed.
1115
1128
1116 Callers most commonly need to iterate backwards over the history
1129 Callers most commonly need to iterate backwards over the history
1117 in which they are interested. Doing so has awful (quadratic-looking)
1130 in which they are interested. Doing so has awful (quadratic-looking)
1118 performance, so we use iterators in a "windowed" way.
1131 performance, so we use iterators in a "windowed" way.
1119
1132
1120 We walk a window of revisions in the desired order. Within the
1133 We walk a window of revisions in the desired order. Within the
1121 window, we first walk forwards to gather data, then in the desired
1134 window, we first walk forwards to gather data, then in the desired
1122 order (usually backwards) to display it.
1135 order (usually backwards) to display it.
1123
1136
1124 This function returns an iterator yielding contexts. Before
1137 This function returns an iterator yielding contexts. Before
1125 yielding each context, the iterator will first call the prepare
1138 yielding each context, the iterator will first call the prepare
1126 function on each context in the window in forward order.'''
1139 function on each context in the window in forward order.'''
1127
1140
1128 follow = opts.get('follow') or opts.get('follow_first')
1141 follow = opts.get('follow') or opts.get('follow_first')
1129
1142
1130 if opts.get('rev'):
1143 if opts.get('rev'):
1131 revs = scmutil.revrange(repo, opts.get('rev'))
1144 revs = scmutil.revrange(repo, opts.get('rev'))
1132 elif follow:
1145 elif follow:
1133 revs = repo.revs('reverse(:.)')
1146 revs = repo.revs('reverse(:.)')
1134 else:
1147 else:
1135 revs = revset.baseset(repo)
1148 revs = revset.baseset(repo)
1136 revs.reverse()
1149 revs.reverse()
1137 if not revs:
1150 if not revs:
1138 return []
1151 return []
1139 wanted = set()
1152 wanted = set()
1140 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1153 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1141 fncache = {}
1154 fncache = {}
1142 change = repo.changectx
1155 change = repo.changectx
1143 revs = revset.baseset(revs)
1156 revs = revset.baseset(revs)
1144
1157
1145 # First step is to fill wanted, the set of revisions that we want to yield.
1158 # First step is to fill wanted, the set of revisions that we want to yield.
1146 # When it does not induce extra cost, we also fill fncache for revisions in
1159 # When it does not induce extra cost, we also fill fncache for revisions in
1147 # wanted: a cache of filenames that were changed (ctx.files()) and that
1160 # wanted: a cache of filenames that were changed (ctx.files()) and that
1148 # match the file filtering conditions.
1161 # match the file filtering conditions.
1149
1162
1150 if not slowpath and not match.files():
1163 if not slowpath and not match.files():
1151 # No files, no patterns. Display all revs.
1164 # No files, no patterns. Display all revs.
1152 wanted = set(revs)
1165 wanted = set(revs)
1153
1166
1154 if not slowpath and match.files():
1167 if not slowpath and match.files():
1155 # We only have to read through the filelog to find wanted revisions
1168 # We only have to read through the filelog to find wanted revisions
1156
1169
1157 try:
1170 try:
1158 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1171 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1159 except FileWalkError:
1172 except FileWalkError:
1160 slowpath = True
1173 slowpath = True
1161
1174
1162 # We decided to fall back to the slowpath because at least one
1175 # We decided to fall back to the slowpath because at least one
1163 # of the paths was not a file. Check to see if at least one of them
1176 # of the paths was not a file. Check to see if at least one of them
1164 # existed in history, otherwise simply return
1177 # existed in history, otherwise simply return
1165 for path in match.files():
1178 for path in match.files():
1166 if path == '.' or path in repo.store:
1179 if path == '.' or path in repo.store:
1167 break
1180 break
1168 else:
1181 else:
1169 return []
1182 return []
1170
1183
1171 if slowpath:
1184 if slowpath:
1172 # We have to read the changelog to match filenames against
1185 # We have to read the changelog to match filenames against
1173 # changed files
1186 # changed files
1174
1187
1175 if follow:
1188 if follow:
1176 raise util.Abort(_('can only follow copies/renames for explicit '
1189 raise util.Abort(_('can only follow copies/renames for explicit '
1177 'filenames'))
1190 'filenames'))
1178
1191
1179 # The slow path checks files modified in every changeset.
1192 # The slow path checks files modified in every changeset.
1180 # This is really slow on large repos, so compute the set lazily.
1193 # This is really slow on large repos, so compute the set lazily.
1181 class lazywantedset(object):
1194 class lazywantedset(object):
1182 def __init__(self):
1195 def __init__(self):
1183 self.set = set()
1196 self.set = set()
1184 self.revs = set(revs)
1197 self.revs = set(revs)
1185
1198
1186 # No need to worry about locality here because it will be accessed
1199 # No need to worry about locality here because it will be accessed
1187 # in the same order as the increasing window below.
1200 # in the same order as the increasing window below.
1188 def __contains__(self, value):
1201 def __contains__(self, value):
1189 if value in self.set:
1202 if value in self.set:
1190 return True
1203 return True
1191 elif not value in self.revs:
1204 elif not value in self.revs:
1192 return False
1205 return False
1193 else:
1206 else:
1194 self.revs.discard(value)
1207 self.revs.discard(value)
1195 ctx = change(value)
1208 ctx = change(value)
1196 matches = filter(match, ctx.files())
1209 matches = filter(match, ctx.files())
1197 if matches:
1210 if matches:
1198 fncache[value] = matches
1211 fncache[value] = matches
1199 self.set.add(value)
1212 self.set.add(value)
1200 return True
1213 return True
1201 return False
1214 return False
1202
1215
1203 def discard(self, value):
1216 def discard(self, value):
1204 self.revs.discard(value)
1217 self.revs.discard(value)
1205 self.set.discard(value)
1218 self.set.discard(value)
1206
1219
1207 wanted = lazywantedset()
1220 wanted = lazywantedset()
1208
1221
1209 class followfilter(object):
1222 class followfilter(object):
1210 def __init__(self, onlyfirst=False):
1223 def __init__(self, onlyfirst=False):
1211 self.startrev = nullrev
1224 self.startrev = nullrev
1212 self.roots = set()
1225 self.roots = set()
1213 self.onlyfirst = onlyfirst
1226 self.onlyfirst = onlyfirst
1214
1227
1215 def match(self, rev):
1228 def match(self, rev):
1216 def realparents(rev):
1229 def realparents(rev):
1217 if self.onlyfirst:
1230 if self.onlyfirst:
1218 return repo.changelog.parentrevs(rev)[0:1]
1231 return repo.changelog.parentrevs(rev)[0:1]
1219 else:
1232 else:
1220 return filter(lambda x: x != nullrev,
1233 return filter(lambda x: x != nullrev,
1221 repo.changelog.parentrevs(rev))
1234 repo.changelog.parentrevs(rev))
1222
1235
1223 if self.startrev == nullrev:
1236 if self.startrev == nullrev:
1224 self.startrev = rev
1237 self.startrev = rev
1225 return True
1238 return True
1226
1239
1227 if rev > self.startrev:
1240 if rev > self.startrev:
1228 # forward: all descendants
1241 # forward: all descendants
1229 if not self.roots:
1242 if not self.roots:
1230 self.roots.add(self.startrev)
1243 self.roots.add(self.startrev)
1231 for parent in realparents(rev):
1244 for parent in realparents(rev):
1232 if parent in self.roots:
1245 if parent in self.roots:
1233 self.roots.add(rev)
1246 self.roots.add(rev)
1234 return True
1247 return True
1235 else:
1248 else:
1236 # backwards: all parents
1249 # backwards: all parents
1237 if not self.roots:
1250 if not self.roots:
1238 self.roots.update(realparents(self.startrev))
1251 self.roots.update(realparents(self.startrev))
1239 if rev in self.roots:
1252 if rev in self.roots:
1240 self.roots.remove(rev)
1253 self.roots.remove(rev)
1241 self.roots.update(realparents(rev))
1254 self.roots.update(realparents(rev))
1242 return True
1255 return True
1243
1256
1244 return False
1257 return False
1245
1258
1246 # it might be worthwhile to do this in the iterator if the rev range
1259 # it might be worthwhile to do this in the iterator if the rev range
1247 # is descending and the prune args are all within that range
1260 # is descending and the prune args are all within that range
1248 for rev in opts.get('prune', ()):
1261 for rev in opts.get('prune', ()):
1249 rev = repo[rev].rev()
1262 rev = repo[rev].rev()
1250 ff = followfilter()
1263 ff = followfilter()
1251 stop = min(revs[0], revs[-1])
1264 stop = min(revs[0], revs[-1])
1252 for x in xrange(rev, stop - 1, -1):
1265 for x in xrange(rev, stop - 1, -1):
1253 if ff.match(x):
1266 if ff.match(x):
1254 wanted.discard(x)
1267 wanted.discard(x)
1255
1268
1256 # Choose a small initial window if we will probably only visit a
1269 # Choose a small initial window if we will probably only visit a
1257 # few commits.
1270 # few commits.
1258 limit = loglimit(opts)
1271 limit = loglimit(opts)
1259 windowsize = 8
1272 windowsize = 8
1260 if limit:
1273 if limit:
1261 windowsize = min(limit, windowsize)
1274 windowsize = min(limit, windowsize)
1262
1275
1263 # Now that wanted is correctly initialized, we can iterate over the
1276 # Now that wanted is correctly initialized, we can iterate over the
1264 # revision range, yielding only revisions in wanted.
1277 # revision range, yielding only revisions in wanted.
1265 def iterate():
1278 def iterate():
1266 if follow and not match.files():
1279 if follow and not match.files():
1267 ff = followfilter(onlyfirst=opts.get('follow_first'))
1280 ff = followfilter(onlyfirst=opts.get('follow_first'))
1268 def want(rev):
1281 def want(rev):
1269 return ff.match(rev) and rev in wanted
1282 return ff.match(rev) and rev in wanted
1270 else:
1283 else:
1271 def want(rev):
1284 def want(rev):
1272 return rev in wanted
1285 return rev in wanted
1273
1286
1274 for i, window in increasingwindows(0, len(revs), windowsize):
1287 for i, window in increasingwindows(0, len(revs), windowsize):
1275 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1288 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1276 for rev in sorted(nrevs):
1289 for rev in sorted(nrevs):
1277 fns = fncache.get(rev)
1290 fns = fncache.get(rev)
1278 ctx = change(rev)
1291 ctx = change(rev)
1279 if not fns:
1292 if not fns:
1280 def fns_generator():
1293 def fns_generator():
1281 for f in ctx.files():
1294 for f in ctx.files():
1282 if match(f):
1295 if match(f):
1283 yield f
1296 yield f
1284 fns = fns_generator()
1297 fns = fns_generator()
1285 prepare(ctx, fns)
1298 prepare(ctx, fns)
1286 for rev in nrevs:
1299 for rev in nrevs:
1287 yield change(rev)
1300 yield change(rev)
1288 return iterate()
1301 return iterate()
1289
1302
1290 def _makegraphfilematcher(repo, pats, followfirst):
1303 def _makegraphfilematcher(repo, pats, followfirst):
1291 # When displaying a revision with --patch --follow FILE, we have
1304 # When displaying a revision with --patch --follow FILE, we have
1292 # to know which file of the revision must be diffed. With
1305 # to know which file of the revision must be diffed. With
1293 # --follow, we want the names of the ancestors of FILE in the
1306 # --follow, we want the names of the ancestors of FILE in the
1294 # revision, stored in "fcache". "fcache" is populated by
1307 # revision, stored in "fcache". "fcache" is populated by
1295 # reproducing the graph traversal already done by --follow revset
1308 # reproducing the graph traversal already done by --follow revset
1296 # and relating linkrevs to file names (which is not "correct" but
1309 # and relating linkrevs to file names (which is not "correct" but
1297 # good enough).
1310 # good enough).
1298 fcache = {}
1311 fcache = {}
1299 fcacheready = [False]
1312 fcacheready = [False]
1300 pctx = repo['.']
1313 pctx = repo['.']
1301 wctx = repo[None]
1314 wctx = repo[None]
1302
1315
1303 def populate():
1316 def populate():
1304 for fn in pats:
1317 for fn in pats:
1305 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1318 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1306 for c in i:
1319 for c in i:
1307 fcache.setdefault(c.linkrev(), set()).add(c.path())
1320 fcache.setdefault(c.linkrev(), set()).add(c.path())
1308
1321
1309 def filematcher(rev):
1322 def filematcher(rev):
1310 if not fcacheready[0]:
1323 if not fcacheready[0]:
1311 # Lazy initialization
1324 # Lazy initialization
1312 fcacheready[0] = True
1325 fcacheready[0] = True
1313 populate()
1326 populate()
1314 return scmutil.match(wctx, fcache.get(rev, []), default='path')
1327 return scmutil.match(wctx, fcache.get(rev, []), default='path')
1315
1328
1316 return filematcher
1329 return filematcher
1317
1330
1318 def _makegraphlogrevset(repo, pats, opts, revs):
1331 def _makegraphlogrevset(repo, pats, opts, revs):
1319 """Return (expr, filematcher) where expr is a revset string built
1332 """Return (expr, filematcher) where expr is a revset string built
1320 from log options and file patterns or None. If --stat or --patch
1333 from log options and file patterns or None. If --stat or --patch
1321 are not passed filematcher is None. Otherwise it is a callable
1334 are not passed filematcher is None. Otherwise it is a callable
1322 taking a revision number and returning a match objects filtering
1335 taking a revision number and returning a match objects filtering
1323 the files to be detailed when displaying the revision.
1336 the files to be detailed when displaying the revision.
1324 """
1337 """
1325 opt2revset = {
1338 opt2revset = {
1326 'no_merges': ('not merge()', None),
1339 'no_merges': ('not merge()', None),
1327 'only_merges': ('merge()', None),
1340 'only_merges': ('merge()', None),
1328 '_ancestors': ('ancestors(%(val)s)', None),
1341 '_ancestors': ('ancestors(%(val)s)', None),
1329 '_fancestors': ('_firstancestors(%(val)s)', None),
1342 '_fancestors': ('_firstancestors(%(val)s)', None),
1330 '_descendants': ('descendants(%(val)s)', None),
1343 '_descendants': ('descendants(%(val)s)', None),
1331 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1344 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1332 '_matchfiles': ('_matchfiles(%(val)s)', None),
1345 '_matchfiles': ('_matchfiles(%(val)s)', None),
1333 'date': ('date(%(val)r)', None),
1346 'date': ('date(%(val)r)', None),
1334 'branch': ('branch(%(val)r)', ' or '),
1347 'branch': ('branch(%(val)r)', ' or '),
1335 '_patslog': ('filelog(%(val)r)', ' or '),
1348 '_patslog': ('filelog(%(val)r)', ' or '),
1336 '_patsfollow': ('follow(%(val)r)', ' or '),
1349 '_patsfollow': ('follow(%(val)r)', ' or '),
1337 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1350 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1338 'keyword': ('keyword(%(val)r)', ' or '),
1351 'keyword': ('keyword(%(val)r)', ' or '),
1339 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1352 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1340 'user': ('user(%(val)r)', ' or '),
1353 'user': ('user(%(val)r)', ' or '),
1341 }
1354 }
1342
1355
1343 opts = dict(opts)
1356 opts = dict(opts)
1344 # follow or not follow?
1357 # follow or not follow?
1345 follow = opts.get('follow') or opts.get('follow_first')
1358 follow = opts.get('follow') or opts.get('follow_first')
1346 followfirst = opts.get('follow_first') and 1 or 0
1359 followfirst = opts.get('follow_first') and 1 or 0
1347 # --follow with FILE behaviour depends on revs...
1360 # --follow with FILE behaviour depends on revs...
1348 startrev = revs[0]
1361 startrev = revs[0]
1349 followdescendants = (len(revs) > 1 and revs[0] < revs[1]) and 1 or 0
1362 followdescendants = (len(revs) > 1 and revs[0] < revs[1]) and 1 or 0
1350
1363
1351 # branch and only_branch are really aliases and must be handled at
1364 # branch and only_branch are really aliases and must be handled at
1352 # the same time
1365 # the same time
1353 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1366 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1354 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1367 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1355 # pats/include/exclude are passed to match.match() directly in
1368 # pats/include/exclude are passed to match.match() directly in
1356 # _matchfiles() revset but walkchangerevs() builds its matcher with
1369 # _matchfiles() revset but walkchangerevs() builds its matcher with
1357 # scmutil.match(). The difference is input pats are globbed on
1370 # scmutil.match(). The difference is input pats are globbed on
1358 # platforms without shell expansion (windows).
1371 # platforms without shell expansion (windows).
1359 pctx = repo[None]
1372 pctx = repo[None]
1360 match, pats = scmutil.matchandpats(pctx, pats, opts)
1373 match, pats = scmutil.matchandpats(pctx, pats, opts)
1361 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1374 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1362 if not slowpath:
1375 if not slowpath:
1363 for f in match.files():
1376 for f in match.files():
1364 if follow and f not in pctx:
1377 if follow and f not in pctx:
1365 raise util.Abort(_('cannot follow file not in parent '
1378 raise util.Abort(_('cannot follow file not in parent '
1366 'revision: "%s"') % f)
1379 'revision: "%s"') % f)
1367 filelog = repo.file(f)
1380 filelog = repo.file(f)
1368 if not filelog:
1381 if not filelog:
1369 # A zero count may be a directory or deleted file, so
1382 # A zero count may be a directory or deleted file, so
1370 # try to find matching entries on the slow path.
1383 # try to find matching entries on the slow path.
1371 if follow:
1384 if follow:
1372 raise util.Abort(
1385 raise util.Abort(
1373 _('cannot follow nonexistent file: "%s"') % f)
1386 _('cannot follow nonexistent file: "%s"') % f)
1374 slowpath = True
1387 slowpath = True
1375
1388
1376 # We decided to fall back to the slowpath because at least one
1389 # We decided to fall back to the slowpath because at least one
1377 # of the paths was not a file. Check to see if at least one of them
1390 # of the paths was not a file. Check to see if at least one of them
1378 # existed in history - in that case, we'll continue down the
1391 # existed in history - in that case, we'll continue down the
1379 # slowpath; otherwise, we can turn off the slowpath
1392 # slowpath; otherwise, we can turn off the slowpath
1380 if slowpath:
1393 if slowpath:
1381 for path in match.files():
1394 for path in match.files():
1382 if path == '.' or path in repo.store:
1395 if path == '.' or path in repo.store:
1383 break
1396 break
1384 else:
1397 else:
1385 slowpath = False
1398 slowpath = False
1386
1399
1387 if slowpath:
1400 if slowpath:
1388 # See walkchangerevs() slow path.
1401 # See walkchangerevs() slow path.
1389 #
1402 #
1390 if follow:
1403 if follow:
1391 raise util.Abort(_('can only follow copies/renames for explicit '
1404 raise util.Abort(_('can only follow copies/renames for explicit '
1392 'filenames'))
1405 'filenames'))
1393 # pats/include/exclude cannot be represented as separate
1406 # pats/include/exclude cannot be represented as separate
1394 # revset expressions as their filtering logic applies at file
1407 # revset expressions as their filtering logic applies at file
1395 # level. For instance "-I a -X a" matches a revision touching
1408 # level. For instance "-I a -X a" matches a revision touching
1396 # "a" and "b" while "file(a) and not file(b)" does
1409 # "a" and "b" while "file(a) and not file(b)" does
1397 # not. Besides, filesets are evaluated against the working
1410 # not. Besides, filesets are evaluated against the working
1398 # directory.
1411 # directory.
1399 matchargs = ['r:', 'd:relpath']
1412 matchargs = ['r:', 'd:relpath']
1400 for p in pats:
1413 for p in pats:
1401 matchargs.append('p:' + p)
1414 matchargs.append('p:' + p)
1402 for p in opts.get('include', []):
1415 for p in opts.get('include', []):
1403 matchargs.append('i:' + p)
1416 matchargs.append('i:' + p)
1404 for p in opts.get('exclude', []):
1417 for p in opts.get('exclude', []):
1405 matchargs.append('x:' + p)
1418 matchargs.append('x:' + p)
1406 matchargs = ','.join(('%r' % p) for p in matchargs)
1419 matchargs = ','.join(('%r' % p) for p in matchargs)
1407 opts['_matchfiles'] = matchargs
1420 opts['_matchfiles'] = matchargs
1408 else:
1421 else:
1409 if follow:
1422 if follow:
1410 fpats = ('_patsfollow', '_patsfollowfirst')
1423 fpats = ('_patsfollow', '_patsfollowfirst')
1411 fnopats = (('_ancestors', '_fancestors'),
1424 fnopats = (('_ancestors', '_fancestors'),
1412 ('_descendants', '_fdescendants'))
1425 ('_descendants', '_fdescendants'))
1413 if pats:
1426 if pats:
1414 # follow() revset interprets its file argument as a
1427 # follow() revset interprets its file argument as a
1415 # manifest entry, so use match.files(), not pats.
1428 # manifest entry, so use match.files(), not pats.
1416 opts[fpats[followfirst]] = list(match.files())
1429 opts[fpats[followfirst]] = list(match.files())
1417 else:
1430 else:
1418 opts[fnopats[followdescendants][followfirst]] = str(startrev)
1431 opts[fnopats[followdescendants][followfirst]] = str(startrev)
1419 else:
1432 else:
1420 opts['_patslog'] = list(pats)
1433 opts['_patslog'] = list(pats)
1421
1434
1422 filematcher = None
1435 filematcher = None
1423 if opts.get('patch') or opts.get('stat'):
1436 if opts.get('patch') or opts.get('stat'):
1424 if follow:
1437 if follow:
1425 filematcher = _makegraphfilematcher(repo, pats, followfirst)
1438 filematcher = _makegraphfilematcher(repo, pats, followfirst)
1426 else:
1439 else:
1427 filematcher = lambda rev: match
1440 filematcher = lambda rev: match
1428
1441
1429 expr = []
1442 expr = []
1430 for op, val in opts.iteritems():
1443 for op, val in opts.iteritems():
1431 if not val:
1444 if not val:
1432 continue
1445 continue
1433 if op not in opt2revset:
1446 if op not in opt2revset:
1434 continue
1447 continue
1435 revop, andor = opt2revset[op]
1448 revop, andor = opt2revset[op]
1436 if '%(val)' not in revop:
1449 if '%(val)' not in revop:
1437 expr.append(revop)
1450 expr.append(revop)
1438 else:
1451 else:
1439 if not isinstance(val, list):
1452 if not isinstance(val, list):
1440 e = revop % {'val': val}
1453 e = revop % {'val': val}
1441 else:
1454 else:
1442 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1455 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1443 expr.append(e)
1456 expr.append(e)
1444
1457
1445 if expr:
1458 if expr:
1446 expr = '(' + ' and '.join(expr) + ')'
1459 expr = '(' + ' and '.join(expr) + ')'
1447 else:
1460 else:
1448 expr = None
1461 expr = None
1449 return expr, filematcher
1462 return expr, filematcher
1450
1463
1451 def getgraphlogrevs(repo, pats, opts):
1464 def getgraphlogrevs(repo, pats, opts):
1452 """Return (revs, expr, filematcher) where revs is an iterable of
1465 """Return (revs, expr, filematcher) where revs is an iterable of
1453 revision numbers, expr is a revset string built from log options
1466 revision numbers, expr is a revset string built from log options
1454 and file patterns or None, and used to filter 'revs'. If --stat or
1467 and file patterns or None, and used to filter 'revs'. If --stat or
1455 --patch are not passed filematcher is None. Otherwise it is a
1468 --patch are not passed filematcher is None. Otherwise it is a
1456 callable taking a revision number and returning a match objects
1469 callable taking a revision number and returning a match objects
1457 filtering the files to be detailed when displaying the revision.
1470 filtering the files to be detailed when displaying the revision.
1458 """
1471 """
1459 if not len(repo):
1472 if not len(repo):
1460 return [], None, None
1473 return [], None, None
1461 limit = loglimit(opts)
1474 limit = loglimit(opts)
1462 # Default --rev value depends on --follow but --follow behaviour
1475 # Default --rev value depends on --follow but --follow behaviour
1463 # depends on revisions resolved from --rev...
1476 # depends on revisions resolved from --rev...
1464 follow = opts.get('follow') or opts.get('follow_first')
1477 follow = opts.get('follow') or opts.get('follow_first')
1465 possiblyunsorted = False # whether revs might need sorting
1478 possiblyunsorted = False # whether revs might need sorting
1466 if opts.get('rev'):
1479 if opts.get('rev'):
1467 revs = scmutil.revrange(repo, opts['rev'])
1480 revs = scmutil.revrange(repo, opts['rev'])
1468 # Don't sort here because _makegraphlogrevset might depend on the
1481 # Don't sort here because _makegraphlogrevset might depend on the
1469 # order of revs
1482 # order of revs
1470 possiblyunsorted = True
1483 possiblyunsorted = True
1471 else:
1484 else:
1472 if follow and len(repo) > 0:
1485 if follow and len(repo) > 0:
1473 revs = repo.revs('reverse(:.)')
1486 revs = repo.revs('reverse(:.)')
1474 else:
1487 else:
1475 revs = revset.baseset(repo.changelog)
1488 revs = revset.baseset(repo.changelog)
1476 revs.reverse()
1489 revs.reverse()
1477 if not revs:
1490 if not revs:
1478 return [], None, None
1491 return [], None, None
1479 revs = revset.baseset(revs)
1492 revs = revset.baseset(revs)
1480 expr, filematcher = _makegraphlogrevset(repo, pats, opts, revs)
1493 expr, filematcher = _makegraphlogrevset(repo, pats, opts, revs)
1481 if possiblyunsorted:
1494 if possiblyunsorted:
1482 revs.sort(reverse=True)
1495 revs.sort(reverse=True)
1483 if expr:
1496 if expr:
1484 # Revset matchers often operate faster on revisions in changelog
1497 # Revset matchers often operate faster on revisions in changelog
1485 # order, because most filters deal with the changelog.
1498 # order, because most filters deal with the changelog.
1486 revs.reverse()
1499 revs.reverse()
1487 matcher = revset.match(repo.ui, expr)
1500 matcher = revset.match(repo.ui, expr)
1488 # Revset matches can reorder revisions. "A or B" typically returns
1501 # Revset matches can reorder revisions. "A or B" typically returns
1489 # returns the revision matching A then the revision matching B. Sort
1502 # returns the revision matching A then the revision matching B. Sort
1490 # again to fix that.
1503 # again to fix that.
1491 revs = matcher(repo, revs)
1504 revs = matcher(repo, revs)
1492 revs.sort(reverse=True)
1505 revs.sort(reverse=True)
1493 if limit is not None:
1506 if limit is not None:
1494 revs = revs[:limit]
1507 revs = revs[:limit]
1495
1508
1496 return revs, expr, filematcher
1509 return revs, expr, filematcher
1497
1510
1498 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
1511 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
1499 filematcher=None):
1512 filematcher=None):
1500 seen, state = [], graphmod.asciistate()
1513 seen, state = [], graphmod.asciistate()
1501 for rev, type, ctx, parents in dag:
1514 for rev, type, ctx, parents in dag:
1502 char = 'o'
1515 char = 'o'
1503 if ctx.node() in showparents:
1516 if ctx.node() in showparents:
1504 char = '@'
1517 char = '@'
1505 elif ctx.obsolete():
1518 elif ctx.obsolete():
1506 char = 'x'
1519 char = 'x'
1507 copies = None
1520 copies = None
1508 if getrenamed and ctx.rev():
1521 if getrenamed and ctx.rev():
1509 copies = []
1522 copies = []
1510 for fn in ctx.files():
1523 for fn in ctx.files():
1511 rename = getrenamed(fn, ctx.rev())
1524 rename = getrenamed(fn, ctx.rev())
1512 if rename:
1525 if rename:
1513 copies.append((fn, rename[0]))
1526 copies.append((fn, rename[0]))
1514 revmatchfn = None
1527 revmatchfn = None
1515 if filematcher is not None:
1528 if filematcher is not None:
1516 revmatchfn = filematcher(ctx.rev())
1529 revmatchfn = filematcher(ctx.rev())
1517 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
1530 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
1518 lines = displayer.hunk.pop(rev).split('\n')
1531 lines = displayer.hunk.pop(rev).split('\n')
1519 if not lines[-1]:
1532 if not lines[-1]:
1520 del lines[-1]
1533 del lines[-1]
1521 displayer.flush(rev)
1534 displayer.flush(rev)
1522 edges = edgefn(type, char, lines, seen, rev, parents)
1535 edges = edgefn(type, char, lines, seen, rev, parents)
1523 for type, char, lines, coldata in edges:
1536 for type, char, lines, coldata in edges:
1524 graphmod.ascii(ui, state, type, char, lines, coldata)
1537 graphmod.ascii(ui, state, type, char, lines, coldata)
1525 displayer.close()
1538 displayer.close()
1526
1539
1527 def graphlog(ui, repo, *pats, **opts):
1540 def graphlog(ui, repo, *pats, **opts):
1528 # Parameters are identical to log command ones
1541 # Parameters are identical to log command ones
1529 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
1542 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
1530 revdag = graphmod.dagwalker(repo, revs)
1543 revdag = graphmod.dagwalker(repo, revs)
1531
1544
1532 getrenamed = None
1545 getrenamed = None
1533 if opts.get('copies'):
1546 if opts.get('copies'):
1534 endrev = None
1547 endrev = None
1535 if opts.get('rev'):
1548 if opts.get('rev'):
1536 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
1549 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
1537 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
1550 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
1538 displayer = show_changeset(ui, repo, opts, buffered=True)
1551 displayer = show_changeset(ui, repo, opts, buffered=True)
1539 showparents = [ctx.node() for ctx in repo[None].parents()]
1552 showparents = [ctx.node() for ctx in repo[None].parents()]
1540 displaygraph(ui, revdag, displayer, showparents,
1553 displaygraph(ui, revdag, displayer, showparents,
1541 graphmod.asciiedges, getrenamed, filematcher)
1554 graphmod.asciiedges, getrenamed, filematcher)
1542
1555
1543 def checkunsupportedgraphflags(pats, opts):
1556 def checkunsupportedgraphflags(pats, opts):
1544 for op in ["newest_first"]:
1557 for op in ["newest_first"]:
1545 if op in opts and opts[op]:
1558 if op in opts and opts[op]:
1546 raise util.Abort(_("-G/--graph option is incompatible with --%s")
1559 raise util.Abort(_("-G/--graph option is incompatible with --%s")
1547 % op.replace("_", "-"))
1560 % op.replace("_", "-"))
1548
1561
1549 def graphrevs(repo, nodes, opts):
1562 def graphrevs(repo, nodes, opts):
1550 limit = loglimit(opts)
1563 limit = loglimit(opts)
1551 nodes.reverse()
1564 nodes.reverse()
1552 if limit is not None:
1565 if limit is not None:
1553 nodes = nodes[:limit]
1566 nodes = nodes[:limit]
1554 return graphmod.nodes(repo, nodes)
1567 return graphmod.nodes(repo, nodes)
1555
1568
1556 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1569 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1557 join = lambda f: os.path.join(prefix, f)
1570 join = lambda f: os.path.join(prefix, f)
1558 bad = []
1571 bad = []
1559 oldbad = match.bad
1572 oldbad = match.bad
1560 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1573 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1561 names = []
1574 names = []
1562 wctx = repo[None]
1575 wctx = repo[None]
1563 cca = None
1576 cca = None
1564 abort, warn = scmutil.checkportabilityalert(ui)
1577 abort, warn = scmutil.checkportabilityalert(ui)
1565 if abort or warn:
1578 if abort or warn:
1566 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
1579 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
1567 for f in repo.walk(match):
1580 for f in repo.walk(match):
1568 exact = match.exact(f)
1581 exact = match.exact(f)
1569 if exact or not explicitonly and f not in repo.dirstate:
1582 if exact or not explicitonly and f not in repo.dirstate:
1570 if cca:
1583 if cca:
1571 cca(f)
1584 cca(f)
1572 names.append(f)
1585 names.append(f)
1573 if ui.verbose or not exact:
1586 if ui.verbose or not exact:
1574 ui.status(_('adding %s\n') % match.rel(join(f)))
1587 ui.status(_('adding %s\n') % match.rel(join(f)))
1575
1588
1576 for subpath in sorted(wctx.substate):
1589 for subpath in sorted(wctx.substate):
1577 sub = wctx.sub(subpath)
1590 sub = wctx.sub(subpath)
1578 try:
1591 try:
1579 submatch = matchmod.narrowmatcher(subpath, match)
1592 submatch = matchmod.narrowmatcher(subpath, match)
1580 if listsubrepos:
1593 if listsubrepos:
1581 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1594 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1582 False))
1595 False))
1583 else:
1596 else:
1584 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1597 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1585 True))
1598 True))
1586 except error.LookupError:
1599 except error.LookupError:
1587 ui.status(_("skipping missing subrepository: %s\n")
1600 ui.status(_("skipping missing subrepository: %s\n")
1588 % join(subpath))
1601 % join(subpath))
1589
1602
1590 if not dryrun:
1603 if not dryrun:
1591 rejected = wctx.add(names, prefix)
1604 rejected = wctx.add(names, prefix)
1592 bad.extend(f for f in rejected if f in match.files())
1605 bad.extend(f for f in rejected if f in match.files())
1593 return bad
1606 return bad
1594
1607
1595 def forget(ui, repo, match, prefix, explicitonly):
1608 def forget(ui, repo, match, prefix, explicitonly):
1596 join = lambda f: os.path.join(prefix, f)
1609 join = lambda f: os.path.join(prefix, f)
1597 bad = []
1610 bad = []
1598 oldbad = match.bad
1611 oldbad = match.bad
1599 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1612 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1600 wctx = repo[None]
1613 wctx = repo[None]
1601 forgot = []
1614 forgot = []
1602 s = repo.status(match=match, clean=True)
1615 s = repo.status(match=match, clean=True)
1603 forget = sorted(s[0] + s[1] + s[3] + s[6])
1616 forget = sorted(s[0] + s[1] + s[3] + s[6])
1604 if explicitonly:
1617 if explicitonly:
1605 forget = [f for f in forget if match.exact(f)]
1618 forget = [f for f in forget if match.exact(f)]
1606
1619
1607 for subpath in sorted(wctx.substate):
1620 for subpath in sorted(wctx.substate):
1608 sub = wctx.sub(subpath)
1621 sub = wctx.sub(subpath)
1609 try:
1622 try:
1610 submatch = matchmod.narrowmatcher(subpath, match)
1623 submatch = matchmod.narrowmatcher(subpath, match)
1611 subbad, subforgot = sub.forget(ui, submatch, prefix)
1624 subbad, subforgot = sub.forget(ui, submatch, prefix)
1612 bad.extend([subpath + '/' + f for f in subbad])
1625 bad.extend([subpath + '/' + f for f in subbad])
1613 forgot.extend([subpath + '/' + f for f in subforgot])
1626 forgot.extend([subpath + '/' + f for f in subforgot])
1614 except error.LookupError:
1627 except error.LookupError:
1615 ui.status(_("skipping missing subrepository: %s\n")
1628 ui.status(_("skipping missing subrepository: %s\n")
1616 % join(subpath))
1629 % join(subpath))
1617
1630
1618 if not explicitonly:
1631 if not explicitonly:
1619 for f in match.files():
1632 for f in match.files():
1620 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
1633 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
1621 if f not in forgot:
1634 if f not in forgot:
1622 if os.path.exists(match.rel(join(f))):
1635 if os.path.exists(match.rel(join(f))):
1623 ui.warn(_('not removing %s: '
1636 ui.warn(_('not removing %s: '
1624 'file is already untracked\n')
1637 'file is already untracked\n')
1625 % match.rel(join(f)))
1638 % match.rel(join(f)))
1626 bad.append(f)
1639 bad.append(f)
1627
1640
1628 for f in forget:
1641 for f in forget:
1629 if ui.verbose or not match.exact(f):
1642 if ui.verbose or not match.exact(f):
1630 ui.status(_('removing %s\n') % match.rel(join(f)))
1643 ui.status(_('removing %s\n') % match.rel(join(f)))
1631
1644
1632 rejected = wctx.forget(forget, prefix)
1645 rejected = wctx.forget(forget, prefix)
1633 bad.extend(f for f in rejected if f in match.files())
1646 bad.extend(f for f in rejected if f in match.files())
1634 forgot.extend(forget)
1647 forgot.extend(forget)
1635 return bad, forgot
1648 return bad, forgot
1636
1649
1637 def duplicatecopies(repo, rev, fromrev):
1650 def duplicatecopies(repo, rev, fromrev):
1638 '''reproduce copies from fromrev to rev in the dirstate'''
1651 '''reproduce copies from fromrev to rev in the dirstate'''
1639 for dst, src in copies.pathcopies(repo[fromrev], repo[rev]).iteritems():
1652 for dst, src in copies.pathcopies(repo[fromrev], repo[rev]).iteritems():
1640 # copies.pathcopies returns backward renames, so dst might not
1653 # copies.pathcopies returns backward renames, so dst might not
1641 # actually be in the dirstate
1654 # actually be in the dirstate
1642 if repo.dirstate[dst] in "nma":
1655 if repo.dirstate[dst] in "nma":
1643 repo.dirstate.copy(src, dst)
1656 repo.dirstate.copy(src, dst)
1644
1657
1645 def commit(ui, repo, commitfunc, pats, opts):
1658 def commit(ui, repo, commitfunc, pats, opts):
1646 '''commit the specified files or all outstanding changes'''
1659 '''commit the specified files or all outstanding changes'''
1647 date = opts.get('date')
1660 date = opts.get('date')
1648 if date:
1661 if date:
1649 opts['date'] = util.parsedate(date)
1662 opts['date'] = util.parsedate(date)
1650 message = logmessage(ui, opts)
1663 message = logmessage(ui, opts)
1651
1664
1652 # extract addremove carefully -- this function can be called from a command
1665 # extract addremove carefully -- this function can be called from a command
1653 # that doesn't support addremove
1666 # that doesn't support addremove
1654 if opts.get('addremove'):
1667 if opts.get('addremove'):
1655 scmutil.addremove(repo, pats, opts)
1668 scmutil.addremove(repo, pats, opts)
1656
1669
1657 return commitfunc(ui, repo, message,
1670 return commitfunc(ui, repo, message,
1658 scmutil.match(repo[None], pats, opts), opts)
1671 scmutil.match(repo[None], pats, opts), opts)
1659
1672
1660 def amend(ui, repo, commitfunc, old, extra, pats, opts):
1673 def amend(ui, repo, commitfunc, old, extra, pats, opts):
1661 ui.note(_('amending changeset %s\n') % old)
1674 ui.note(_('amending changeset %s\n') % old)
1662 base = old.p1()
1675 base = old.p1()
1663
1676
1664 wlock = lock = newid = None
1677 wlock = lock = newid = None
1665 try:
1678 try:
1666 wlock = repo.wlock()
1679 wlock = repo.wlock()
1667 lock = repo.lock()
1680 lock = repo.lock()
1668 tr = repo.transaction('amend')
1681 tr = repo.transaction('amend')
1669 try:
1682 try:
1670 # See if we got a message from -m or -l, if not, open the editor
1683 # See if we got a message from -m or -l, if not, open the editor
1671 # with the message of the changeset to amend
1684 # with the message of the changeset to amend
1672 message = logmessage(ui, opts)
1685 message = logmessage(ui, opts)
1673 # ensure logfile does not conflict with later enforcement of the
1686 # ensure logfile does not conflict with later enforcement of the
1674 # message. potential logfile content has been processed by
1687 # message. potential logfile content has been processed by
1675 # `logmessage` anyway.
1688 # `logmessage` anyway.
1676 opts.pop('logfile')
1689 opts.pop('logfile')
1677 # First, do a regular commit to record all changes in the working
1690 # First, do a regular commit to record all changes in the working
1678 # directory (if there are any)
1691 # directory (if there are any)
1679 ui.callhooks = False
1692 ui.callhooks = False
1680 currentbookmark = repo._bookmarkcurrent
1693 currentbookmark = repo._bookmarkcurrent
1681 try:
1694 try:
1682 repo._bookmarkcurrent = None
1695 repo._bookmarkcurrent = None
1683 opts['message'] = 'temporary amend commit for %s' % old
1696 opts['message'] = 'temporary amend commit for %s' % old
1684 node = commit(ui, repo, commitfunc, pats, opts)
1697 node = commit(ui, repo, commitfunc, pats, opts)
1685 finally:
1698 finally:
1686 repo._bookmarkcurrent = currentbookmark
1699 repo._bookmarkcurrent = currentbookmark
1687 ui.callhooks = True
1700 ui.callhooks = True
1688 ctx = repo[node]
1701 ctx = repo[node]
1689
1702
1690 # Participating changesets:
1703 # Participating changesets:
1691 #
1704 #
1692 # node/ctx o - new (intermediate) commit that contains changes
1705 # node/ctx o - new (intermediate) commit that contains changes
1693 # | from working dir to go into amending commit
1706 # | from working dir to go into amending commit
1694 # | (or a workingctx if there were no changes)
1707 # | (or a workingctx if there were no changes)
1695 # |
1708 # |
1696 # old o - changeset to amend
1709 # old o - changeset to amend
1697 # |
1710 # |
1698 # base o - parent of amending changeset
1711 # base o - parent of amending changeset
1699
1712
1700 # Update extra dict from amended commit (e.g. to preserve graft
1713 # Update extra dict from amended commit (e.g. to preserve graft
1701 # source)
1714 # source)
1702 extra.update(old.extra())
1715 extra.update(old.extra())
1703
1716
1704 # Also update it from the intermediate commit or from the wctx
1717 # Also update it from the intermediate commit or from the wctx
1705 extra.update(ctx.extra())
1718 extra.update(ctx.extra())
1706
1719
1707 if len(old.parents()) > 1:
1720 if len(old.parents()) > 1:
1708 # ctx.files() isn't reliable for merges, so fall back to the
1721 # ctx.files() isn't reliable for merges, so fall back to the
1709 # slower repo.status() method
1722 # slower repo.status() method
1710 files = set([fn for st in repo.status(base, old)[:3]
1723 files = set([fn for st in repo.status(base, old)[:3]
1711 for fn in st])
1724 for fn in st])
1712 else:
1725 else:
1713 files = set(old.files())
1726 files = set(old.files())
1714
1727
1715 # Second, we use either the commit we just did, or if there were no
1728 # Second, we use either the commit we just did, or if there were no
1716 # changes the parent of the working directory as the version of the
1729 # changes the parent of the working directory as the version of the
1717 # files in the final amend commit
1730 # files in the final amend commit
1718 if node:
1731 if node:
1719 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
1732 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
1720
1733
1721 user = ctx.user()
1734 user = ctx.user()
1722 date = ctx.date()
1735 date = ctx.date()
1723 # Recompute copies (avoid recording a -> b -> a)
1736 # Recompute copies (avoid recording a -> b -> a)
1724 copied = copies.pathcopies(base, ctx)
1737 copied = copies.pathcopies(base, ctx)
1725
1738
1726 # Prune files which were reverted by the updates: if old
1739 # Prune files which were reverted by the updates: if old
1727 # introduced file X and our intermediate commit, node,
1740 # introduced file X and our intermediate commit, node,
1728 # renamed that file, then those two files are the same and
1741 # renamed that file, then those two files are the same and
1729 # we can discard X from our list of files. Likewise if X
1742 # we can discard X from our list of files. Likewise if X
1730 # was deleted, it's no longer relevant
1743 # was deleted, it's no longer relevant
1731 files.update(ctx.files())
1744 files.update(ctx.files())
1732
1745
1733 def samefile(f):
1746 def samefile(f):
1734 if f in ctx.manifest():
1747 if f in ctx.manifest():
1735 a = ctx.filectx(f)
1748 a = ctx.filectx(f)
1736 if f in base.manifest():
1749 if f in base.manifest():
1737 b = base.filectx(f)
1750 b = base.filectx(f)
1738 return (not a.cmp(b)
1751 return (not a.cmp(b)
1739 and a.flags() == b.flags())
1752 and a.flags() == b.flags())
1740 else:
1753 else:
1741 return False
1754 return False
1742 else:
1755 else:
1743 return f not in base.manifest()
1756 return f not in base.manifest()
1744 files = [f for f in files if not samefile(f)]
1757 files = [f for f in files if not samefile(f)]
1745
1758
1746 def filectxfn(repo, ctx_, path):
1759 def filectxfn(repo, ctx_, path):
1747 try:
1760 try:
1748 fctx = ctx[path]
1761 fctx = ctx[path]
1749 flags = fctx.flags()
1762 flags = fctx.flags()
1750 mctx = context.memfilectx(fctx.path(), fctx.data(),
1763 mctx = context.memfilectx(fctx.path(), fctx.data(),
1751 islink='l' in flags,
1764 islink='l' in flags,
1752 isexec='x' in flags,
1765 isexec='x' in flags,
1753 copied=copied.get(path))
1766 copied=copied.get(path))
1754 return mctx
1767 return mctx
1755 except KeyError:
1768 except KeyError:
1756 raise IOError
1769 raise IOError
1757 else:
1770 else:
1758 ui.note(_('copying changeset %s to %s\n') % (old, base))
1771 ui.note(_('copying changeset %s to %s\n') % (old, base))
1759
1772
1760 # Use version of files as in the old cset
1773 # Use version of files as in the old cset
1761 def filectxfn(repo, ctx_, path):
1774 def filectxfn(repo, ctx_, path):
1762 try:
1775 try:
1763 return old.filectx(path)
1776 return old.filectx(path)
1764 except KeyError:
1777 except KeyError:
1765 raise IOError
1778 raise IOError
1766
1779
1767 user = opts.get('user') or old.user()
1780 user = opts.get('user') or old.user()
1768 date = opts.get('date') or old.date()
1781 date = opts.get('date') or old.date()
1769 editmsg = False
1782 editmsg = False
1770 if not message:
1783 if not message:
1771 editmsg = True
1784 editmsg = True
1772 message = old.description()
1785 message = old.description()
1773
1786
1774 pureextra = extra.copy()
1787 pureextra = extra.copy()
1775 extra['amend_source'] = old.hex()
1788 extra['amend_source'] = old.hex()
1776
1789
1777 new = context.memctx(repo,
1790 new = context.memctx(repo,
1778 parents=[base.node(), old.p2().node()],
1791 parents=[base.node(), old.p2().node()],
1779 text=message,
1792 text=message,
1780 files=files,
1793 files=files,
1781 filectxfn=filectxfn,
1794 filectxfn=filectxfn,
1782 user=user,
1795 user=user,
1783 date=date,
1796 date=date,
1784 extra=extra)
1797 extra=extra)
1785 if editmsg:
1798 if editmsg:
1786 new._text = commitforceeditor(repo, new, [])
1799 new._text = commitforceeditor(repo, new, [])
1787
1800
1788 newdesc = changelog.stripdesc(new.description())
1801 newdesc = changelog.stripdesc(new.description())
1789 if ((not node)
1802 if ((not node)
1790 and newdesc == old.description()
1803 and newdesc == old.description()
1791 and user == old.user()
1804 and user == old.user()
1792 and date == old.date()
1805 and date == old.date()
1793 and pureextra == old.extra()):
1806 and pureextra == old.extra()):
1794 # nothing changed. continuing here would create a new node
1807 # nothing changed. continuing here would create a new node
1795 # anyway because of the amend_source noise.
1808 # anyway because of the amend_source noise.
1796 #
1809 #
1797 # This not what we expect from amend.
1810 # This not what we expect from amend.
1798 return old.node()
1811 return old.node()
1799
1812
1800 ph = repo.ui.config('phases', 'new-commit', phases.draft)
1813 ph = repo.ui.config('phases', 'new-commit', phases.draft)
1801 try:
1814 try:
1802 repo.ui.setconfig('phases', 'new-commit', old.phase())
1815 repo.ui.setconfig('phases', 'new-commit', old.phase())
1803 newid = repo.commitctx(new)
1816 newid = repo.commitctx(new)
1804 finally:
1817 finally:
1805 repo.ui.setconfig('phases', 'new-commit', ph)
1818 repo.ui.setconfig('phases', 'new-commit', ph)
1806 if newid != old.node():
1819 if newid != old.node():
1807 # Reroute the working copy parent to the new changeset
1820 # Reroute the working copy parent to the new changeset
1808 repo.setparents(newid, nullid)
1821 repo.setparents(newid, nullid)
1809
1822
1810 # Move bookmarks from old parent to amend commit
1823 # Move bookmarks from old parent to amend commit
1811 bms = repo.nodebookmarks(old.node())
1824 bms = repo.nodebookmarks(old.node())
1812 if bms:
1825 if bms:
1813 marks = repo._bookmarks
1826 marks = repo._bookmarks
1814 for bm in bms:
1827 for bm in bms:
1815 marks[bm] = newid
1828 marks[bm] = newid
1816 marks.write()
1829 marks.write()
1817 #commit the whole amend process
1830 #commit the whole amend process
1818 if obsolete._enabled and newid != old.node():
1831 if obsolete._enabled and newid != old.node():
1819 # mark the new changeset as successor of the rewritten one
1832 # mark the new changeset as successor of the rewritten one
1820 new = repo[newid]
1833 new = repo[newid]
1821 obs = [(old, (new,))]
1834 obs = [(old, (new,))]
1822 if node:
1835 if node:
1823 obs.append((ctx, ()))
1836 obs.append((ctx, ()))
1824
1837
1825 obsolete.createmarkers(repo, obs)
1838 obsolete.createmarkers(repo, obs)
1826 tr.close()
1839 tr.close()
1827 finally:
1840 finally:
1828 tr.release()
1841 tr.release()
1829 if (not obsolete._enabled) and newid != old.node():
1842 if (not obsolete._enabled) and newid != old.node():
1830 # Strip the intermediate commit (if there was one) and the amended
1843 # Strip the intermediate commit (if there was one) and the amended
1831 # commit
1844 # commit
1832 if node:
1845 if node:
1833 ui.note(_('stripping intermediate changeset %s\n') % ctx)
1846 ui.note(_('stripping intermediate changeset %s\n') % ctx)
1834 ui.note(_('stripping amended changeset %s\n') % old)
1847 ui.note(_('stripping amended changeset %s\n') % old)
1835 repair.strip(ui, repo, old.node(), topic='amend-backup')
1848 repair.strip(ui, repo, old.node(), topic='amend-backup')
1836 finally:
1849 finally:
1837 if newid is None:
1850 if newid is None:
1838 repo.dirstate.invalidate()
1851 repo.dirstate.invalidate()
1839 lockmod.release(lock, wlock)
1852 lockmod.release(lock, wlock)
1840 return newid
1853 return newid
1841
1854
1842 def commiteditor(repo, ctx, subs):
1855 def commiteditor(repo, ctx, subs):
1843 if ctx.description():
1856 if ctx.description():
1844 return ctx.description()
1857 return ctx.description()
1845 return commitforceeditor(repo, ctx, subs)
1858 return commitforceeditor(repo, ctx, subs)
1846
1859
1847 def commitforceeditor(repo, ctx, subs):
1860 def commitforceeditor(repo, ctx, subs):
1848 edittext = []
1861 edittext = []
1849 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1862 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1850 if ctx.description():
1863 if ctx.description():
1851 edittext.append(ctx.description())
1864 edittext.append(ctx.description())
1852 edittext.append("")
1865 edittext.append("")
1853 edittext.append("") # Empty line between message and comments.
1866 edittext.append("") # Empty line between message and comments.
1854 edittext.append(_("HG: Enter commit message."
1867 edittext.append(_("HG: Enter commit message."
1855 " Lines beginning with 'HG:' are removed."))
1868 " Lines beginning with 'HG:' are removed."))
1856 edittext.append(_("HG: Leave message empty to abort commit."))
1869 edittext.append(_("HG: Leave message empty to abort commit."))
1857 edittext.append("HG: --")
1870 edittext.append("HG: --")
1858 edittext.append(_("HG: user: %s") % ctx.user())
1871 edittext.append(_("HG: user: %s") % ctx.user())
1859 if ctx.p2():
1872 if ctx.p2():
1860 edittext.append(_("HG: branch merge"))
1873 edittext.append(_("HG: branch merge"))
1861 if ctx.branch():
1874 if ctx.branch():
1862 edittext.append(_("HG: branch '%s'") % ctx.branch())
1875 edittext.append(_("HG: branch '%s'") % ctx.branch())
1863 if bookmarks.iscurrent(repo):
1876 if bookmarks.iscurrent(repo):
1864 edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
1877 edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
1865 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1878 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1866 edittext.extend([_("HG: added %s") % f for f in added])
1879 edittext.extend([_("HG: added %s") % f for f in added])
1867 edittext.extend([_("HG: changed %s") % f for f in modified])
1880 edittext.extend([_("HG: changed %s") % f for f in modified])
1868 edittext.extend([_("HG: removed %s") % f for f in removed])
1881 edittext.extend([_("HG: removed %s") % f for f in removed])
1869 if not added and not modified and not removed:
1882 if not added and not modified and not removed:
1870 edittext.append(_("HG: no files changed"))
1883 edittext.append(_("HG: no files changed"))
1871 edittext.append("")
1884 edittext.append("")
1872 # run editor in the repository root
1885 # run editor in the repository root
1873 olddir = os.getcwd()
1886 olddir = os.getcwd()
1874 os.chdir(repo.root)
1887 os.chdir(repo.root)
1875 text = repo.ui.edit("\n".join(edittext), ctx.user())
1888 text = repo.ui.edit("\n".join(edittext), ctx.user())
1876 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1889 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1877 os.chdir(olddir)
1890 os.chdir(olddir)
1878
1891
1879 if not text.strip():
1892 if not text.strip():
1880 raise util.Abort(_("empty commit message"))
1893 raise util.Abort(_("empty commit message"))
1881
1894
1882 return text
1895 return text
1883
1896
1884 def commitstatus(repo, node, branch, bheads=None, opts={}):
1897 def commitstatus(repo, node, branch, bheads=None, opts={}):
1885 ctx = repo[node]
1898 ctx = repo[node]
1886 parents = ctx.parents()
1899 parents = ctx.parents()
1887
1900
1888 if (not opts.get('amend') and bheads and node not in bheads and not
1901 if (not opts.get('amend') and bheads and node not in bheads and not
1889 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1902 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1890 repo.ui.status(_('created new head\n'))
1903 repo.ui.status(_('created new head\n'))
1891 # The message is not printed for initial roots. For the other
1904 # The message is not printed for initial roots. For the other
1892 # changesets, it is printed in the following situations:
1905 # changesets, it is printed in the following situations:
1893 #
1906 #
1894 # Par column: for the 2 parents with ...
1907 # Par column: for the 2 parents with ...
1895 # N: null or no parent
1908 # N: null or no parent
1896 # B: parent is on another named branch
1909 # B: parent is on another named branch
1897 # C: parent is a regular non head changeset
1910 # C: parent is a regular non head changeset
1898 # H: parent was a branch head of the current branch
1911 # H: parent was a branch head of the current branch
1899 # Msg column: whether we print "created new head" message
1912 # Msg column: whether we print "created new head" message
1900 # In the following, it is assumed that there already exists some
1913 # In the following, it is assumed that there already exists some
1901 # initial branch heads of the current branch, otherwise nothing is
1914 # initial branch heads of the current branch, otherwise nothing is
1902 # printed anyway.
1915 # printed anyway.
1903 #
1916 #
1904 # Par Msg Comment
1917 # Par Msg Comment
1905 # N N y additional topo root
1918 # N N y additional topo root
1906 #
1919 #
1907 # B N y additional branch root
1920 # B N y additional branch root
1908 # C N y additional topo head
1921 # C N y additional topo head
1909 # H N n usual case
1922 # H N n usual case
1910 #
1923 #
1911 # B B y weird additional branch root
1924 # B B y weird additional branch root
1912 # C B y branch merge
1925 # C B y branch merge
1913 # H B n merge with named branch
1926 # H B n merge with named branch
1914 #
1927 #
1915 # C C y additional head from merge
1928 # C C y additional head from merge
1916 # C H n merge with a head
1929 # C H n merge with a head
1917 #
1930 #
1918 # H H n head merge: head count decreases
1931 # H H n head merge: head count decreases
1919
1932
1920 if not opts.get('close_branch'):
1933 if not opts.get('close_branch'):
1921 for r in parents:
1934 for r in parents:
1922 if r.closesbranch() and r.branch() == branch:
1935 if r.closesbranch() and r.branch() == branch:
1923 repo.ui.status(_('reopening closed branch head %d\n') % r)
1936 repo.ui.status(_('reopening closed branch head %d\n') % r)
1924
1937
1925 if repo.ui.debugflag:
1938 if repo.ui.debugflag:
1926 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1939 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1927 elif repo.ui.verbose:
1940 elif repo.ui.verbose:
1928 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1941 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1929
1942
1930 def revert(ui, repo, ctx, parents, *pats, **opts):
1943 def revert(ui, repo, ctx, parents, *pats, **opts):
1931 parent, p2 = parents
1944 parent, p2 = parents
1932 node = ctx.node()
1945 node = ctx.node()
1933
1946
1934 mf = ctx.manifest()
1947 mf = ctx.manifest()
1935 if node == parent:
1948 if node == parent:
1936 pmf = mf
1949 pmf = mf
1937 else:
1950 else:
1938 pmf = None
1951 pmf = None
1939
1952
1940 # need all matching names in dirstate and manifest of target rev,
1953 # need all matching names in dirstate and manifest of target rev,
1941 # so have to walk both. do not print errors if files exist in one
1954 # so have to walk both. do not print errors if files exist in one
1942 # but not other.
1955 # but not other.
1943
1956
1944 names = {}
1957 names = {}
1945
1958
1946 wlock = repo.wlock()
1959 wlock = repo.wlock()
1947 try:
1960 try:
1948 # walk dirstate.
1961 # walk dirstate.
1949
1962
1950 m = scmutil.match(repo[None], pats, opts)
1963 m = scmutil.match(repo[None], pats, opts)
1951 m.bad = lambda x, y: False
1964 m.bad = lambda x, y: False
1952 for abs in repo.walk(m):
1965 for abs in repo.walk(m):
1953 names[abs] = m.rel(abs), m.exact(abs)
1966 names[abs] = m.rel(abs), m.exact(abs)
1954
1967
1955 # walk target manifest.
1968 # walk target manifest.
1956
1969
1957 def badfn(path, msg):
1970 def badfn(path, msg):
1958 if path in names:
1971 if path in names:
1959 return
1972 return
1960 if path in ctx.substate:
1973 if path in ctx.substate:
1961 return
1974 return
1962 path_ = path + '/'
1975 path_ = path + '/'
1963 for f in names:
1976 for f in names:
1964 if f.startswith(path_):
1977 if f.startswith(path_):
1965 return
1978 return
1966 ui.warn("%s: %s\n" % (m.rel(path), msg))
1979 ui.warn("%s: %s\n" % (m.rel(path), msg))
1967
1980
1968 m = scmutil.match(ctx, pats, opts)
1981 m = scmutil.match(ctx, pats, opts)
1969 m.bad = badfn
1982 m.bad = badfn
1970 for abs in ctx.walk(m):
1983 for abs in ctx.walk(m):
1971 if abs not in names:
1984 if abs not in names:
1972 names[abs] = m.rel(abs), m.exact(abs)
1985 names[abs] = m.rel(abs), m.exact(abs)
1973
1986
1974 # get the list of subrepos that must be reverted
1987 # get the list of subrepos that must be reverted
1975 targetsubs = sorted(s for s in ctx.substate if m(s))
1988 targetsubs = sorted(s for s in ctx.substate if m(s))
1976 m = scmutil.matchfiles(repo, names)
1989 m = scmutil.matchfiles(repo, names)
1977 changes = repo.status(match=m)[:4]
1990 changes = repo.status(match=m)[:4]
1978 modified, added, removed, deleted = map(set, changes)
1991 modified, added, removed, deleted = map(set, changes)
1979
1992
1980 # if f is a rename, also revert the source
1993 # if f is a rename, also revert the source
1981 cwd = repo.getcwd()
1994 cwd = repo.getcwd()
1982 for f in added:
1995 for f in added:
1983 src = repo.dirstate.copied(f)
1996 src = repo.dirstate.copied(f)
1984 if src and src not in names and repo.dirstate[src] == 'r':
1997 if src and src not in names and repo.dirstate[src] == 'r':
1985 removed.add(src)
1998 removed.add(src)
1986 names[src] = (repo.pathto(src, cwd), True)
1999 names[src] = (repo.pathto(src, cwd), True)
1987
2000
1988 def removeforget(abs):
2001 def removeforget(abs):
1989 if repo.dirstate[abs] == 'a':
2002 if repo.dirstate[abs] == 'a':
1990 return _('forgetting %s\n')
2003 return _('forgetting %s\n')
1991 return _('removing %s\n')
2004 return _('removing %s\n')
1992
2005
1993 revert = ([], _('reverting %s\n'))
2006 revert = ([], _('reverting %s\n'))
1994 add = ([], _('adding %s\n'))
2007 add = ([], _('adding %s\n'))
1995 remove = ([], removeforget)
2008 remove = ([], removeforget)
1996 undelete = ([], _('undeleting %s\n'))
2009 undelete = ([], _('undeleting %s\n'))
1997
2010
1998 disptable = (
2011 disptable = (
1999 # dispatch table:
2012 # dispatch table:
2000 # file state
2013 # file state
2001 # action if in target manifest
2014 # action if in target manifest
2002 # action if not in target manifest
2015 # action if not in target manifest
2003 # make backup if in target manifest
2016 # make backup if in target manifest
2004 # make backup if not in target manifest
2017 # make backup if not in target manifest
2005 (modified, revert, remove, True, True),
2018 (modified, revert, remove, True, True),
2006 (added, revert, remove, True, False),
2019 (added, revert, remove, True, False),
2007 (removed, undelete, None, True, False),
2020 (removed, undelete, None, True, False),
2008 (deleted, revert, remove, False, False),
2021 (deleted, revert, remove, False, False),
2009 )
2022 )
2010
2023
2011 for abs, (rel, exact) in sorted(names.items()):
2024 for abs, (rel, exact) in sorted(names.items()):
2012 mfentry = mf.get(abs)
2025 mfentry = mf.get(abs)
2013 target = repo.wjoin(abs)
2026 target = repo.wjoin(abs)
2014 def handle(xlist, dobackup):
2027 def handle(xlist, dobackup):
2015 xlist[0].append(abs)
2028 xlist[0].append(abs)
2016 if (dobackup and not opts.get('no_backup') and
2029 if (dobackup and not opts.get('no_backup') and
2017 os.path.lexists(target) and
2030 os.path.lexists(target) and
2018 abs in ctx and repo[None][abs].cmp(ctx[abs])):
2031 abs in ctx and repo[None][abs].cmp(ctx[abs])):
2019 bakname = "%s.orig" % rel
2032 bakname = "%s.orig" % rel
2020 ui.note(_('saving current version of %s as %s\n') %
2033 ui.note(_('saving current version of %s as %s\n') %
2021 (rel, bakname))
2034 (rel, bakname))
2022 if not opts.get('dry_run'):
2035 if not opts.get('dry_run'):
2023 util.rename(target, bakname)
2036 util.rename(target, bakname)
2024 if ui.verbose or not exact:
2037 if ui.verbose or not exact:
2025 msg = xlist[1]
2038 msg = xlist[1]
2026 if not isinstance(msg, basestring):
2039 if not isinstance(msg, basestring):
2027 msg = msg(abs)
2040 msg = msg(abs)
2028 ui.status(msg % rel)
2041 ui.status(msg % rel)
2029 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2042 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2030 if abs not in table:
2043 if abs not in table:
2031 continue
2044 continue
2032 # file has changed in dirstate
2045 # file has changed in dirstate
2033 if mfentry:
2046 if mfentry:
2034 handle(hitlist, backuphit)
2047 handle(hitlist, backuphit)
2035 elif misslist is not None:
2048 elif misslist is not None:
2036 handle(misslist, backupmiss)
2049 handle(misslist, backupmiss)
2037 break
2050 break
2038 else:
2051 else:
2039 if abs not in repo.dirstate:
2052 if abs not in repo.dirstate:
2040 if mfentry:
2053 if mfentry:
2041 handle(add, True)
2054 handle(add, True)
2042 elif exact:
2055 elif exact:
2043 ui.warn(_('file not managed: %s\n') % rel)
2056 ui.warn(_('file not managed: %s\n') % rel)
2044 continue
2057 continue
2045 # file has not changed in dirstate
2058 # file has not changed in dirstate
2046 if node == parent:
2059 if node == parent:
2047 if exact:
2060 if exact:
2048 ui.warn(_('no changes needed to %s\n') % rel)
2061 ui.warn(_('no changes needed to %s\n') % rel)
2049 continue
2062 continue
2050 if pmf is None:
2063 if pmf is None:
2051 # only need parent manifest in this unlikely case,
2064 # only need parent manifest in this unlikely case,
2052 # so do not read by default
2065 # so do not read by default
2053 pmf = repo[parent].manifest()
2066 pmf = repo[parent].manifest()
2054 if abs in pmf and mfentry:
2067 if abs in pmf and mfentry:
2055 # if version of file is same in parent and target
2068 # if version of file is same in parent and target
2056 # manifests, do nothing
2069 # manifests, do nothing
2057 if (pmf[abs] != mfentry or
2070 if (pmf[abs] != mfentry or
2058 pmf.flags(abs) != mf.flags(abs)):
2071 pmf.flags(abs) != mf.flags(abs)):
2059 handle(revert, False)
2072 handle(revert, False)
2060 else:
2073 else:
2061 handle(remove, False)
2074 handle(remove, False)
2062
2075
2063 if not opts.get('dry_run'):
2076 if not opts.get('dry_run'):
2064 def checkout(f):
2077 def checkout(f):
2065 fc = ctx[f]
2078 fc = ctx[f]
2066 repo.wwrite(f, fc.data(), fc.flags())
2079 repo.wwrite(f, fc.data(), fc.flags())
2067
2080
2068 audit_path = pathutil.pathauditor(repo.root)
2081 audit_path = pathutil.pathauditor(repo.root)
2069 for f in remove[0]:
2082 for f in remove[0]:
2070 if repo.dirstate[f] == 'a':
2083 if repo.dirstate[f] == 'a':
2071 repo.dirstate.drop(f)
2084 repo.dirstate.drop(f)
2072 continue
2085 continue
2073 audit_path(f)
2086 audit_path(f)
2074 try:
2087 try:
2075 util.unlinkpath(repo.wjoin(f))
2088 util.unlinkpath(repo.wjoin(f))
2076 except OSError:
2089 except OSError:
2077 pass
2090 pass
2078 repo.dirstate.remove(f)
2091 repo.dirstate.remove(f)
2079
2092
2080 normal = None
2093 normal = None
2081 if node == parent:
2094 if node == parent:
2082 # We're reverting to our parent. If possible, we'd like status
2095 # We're reverting to our parent. If possible, we'd like status
2083 # to report the file as clean. We have to use normallookup for
2096 # to report the file as clean. We have to use normallookup for
2084 # merges to avoid losing information about merged/dirty files.
2097 # merges to avoid losing information about merged/dirty files.
2085 if p2 != nullid:
2098 if p2 != nullid:
2086 normal = repo.dirstate.normallookup
2099 normal = repo.dirstate.normallookup
2087 else:
2100 else:
2088 normal = repo.dirstate.normal
2101 normal = repo.dirstate.normal
2089 for f in revert[0]:
2102 for f in revert[0]:
2090 checkout(f)
2103 checkout(f)
2091 if normal:
2104 if normal:
2092 normal(f)
2105 normal(f)
2093
2106
2094 for f in add[0]:
2107 for f in add[0]:
2095 checkout(f)
2108 checkout(f)
2096 repo.dirstate.add(f)
2109 repo.dirstate.add(f)
2097
2110
2098 normal = repo.dirstate.normallookup
2111 normal = repo.dirstate.normallookup
2099 if node == parent and p2 == nullid:
2112 if node == parent and p2 == nullid:
2100 normal = repo.dirstate.normal
2113 normal = repo.dirstate.normal
2101 for f in undelete[0]:
2114 for f in undelete[0]:
2102 checkout(f)
2115 checkout(f)
2103 normal(f)
2116 normal(f)
2104
2117
2105 copied = copies.pathcopies(repo[parent], ctx)
2118 copied = copies.pathcopies(repo[parent], ctx)
2106
2119
2107 for f in add[0] + undelete[0] + revert[0]:
2120 for f in add[0] + undelete[0] + revert[0]:
2108 if f in copied:
2121 if f in copied:
2109 repo.dirstate.copy(copied[f], f)
2122 repo.dirstate.copy(copied[f], f)
2110
2123
2111 if targetsubs:
2124 if targetsubs:
2112 # Revert the subrepos on the revert list
2125 # Revert the subrepos on the revert list
2113 for sub in targetsubs:
2126 for sub in targetsubs:
2114 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
2127 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
2115 finally:
2128 finally:
2116 wlock.release()
2129 wlock.release()
2117
2130
2118 def command(table):
2131 def command(table):
2119 '''returns a function object bound to table which can be used as
2132 '''returns a function object bound to table which can be used as
2120 a decorator for populating table as a command table'''
2133 a decorator for populating table as a command table'''
2121
2134
2122 def cmd(name, options=(), synopsis=None):
2135 def cmd(name, options=(), synopsis=None):
2123 def decorator(func):
2136 def decorator(func):
2124 if synopsis:
2137 if synopsis:
2125 table[name] = func, list(options), synopsis
2138 table[name] = func, list(options), synopsis
2126 else:
2139 else:
2127 table[name] = func, list(options)
2140 table[name] = func, list(options)
2128 return func
2141 return func
2129 return decorator
2142 return decorator
2130
2143
2131 return cmd
2144 return cmd
2132
2145
2133 # a list of (ui, repo) functions called by commands.summary
2146 # a list of (ui, repo) functions called by commands.summary
2134 summaryhooks = util.hooks()
2147 summaryhooks = util.hooks()
2135
2148
2136 # A list of state files kept by multistep operations like graft.
2149 # A list of state files kept by multistep operations like graft.
2137 # Since graft cannot be aborted, it is considered 'clearable' by update.
2150 # Since graft cannot be aborted, it is considered 'clearable' by update.
2138 # note: bisect is intentionally excluded
2151 # note: bisect is intentionally excluded
2139 # (state file, clearable, allowcommit, error, hint)
2152 # (state file, clearable, allowcommit, error, hint)
2140 unfinishedstates = [
2153 unfinishedstates = [
2141 ('graftstate', True, False, _('graft in progress'),
2154 ('graftstate', True, False, _('graft in progress'),
2142 _("use 'hg graft --continue' or 'hg update' to abort")),
2155 _("use 'hg graft --continue' or 'hg update' to abort")),
2143 ('updatestate', True, False, _('last update was interrupted'),
2156 ('updatestate', True, False, _('last update was interrupted'),
2144 _("use 'hg update' to get a consistent checkout"))
2157 _("use 'hg update' to get a consistent checkout"))
2145 ]
2158 ]
2146
2159
2147 def checkunfinished(repo, commit=False):
2160 def checkunfinished(repo, commit=False):
2148 '''Look for an unfinished multistep operation, like graft, and abort
2161 '''Look for an unfinished multistep operation, like graft, and abort
2149 if found. It's probably good to check this right before
2162 if found. It's probably good to check this right before
2150 bailifchanged().
2163 bailifchanged().
2151 '''
2164 '''
2152 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2165 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2153 if commit and allowcommit:
2166 if commit and allowcommit:
2154 continue
2167 continue
2155 if repo.vfs.exists(f):
2168 if repo.vfs.exists(f):
2156 raise util.Abort(msg, hint=hint)
2169 raise util.Abort(msg, hint=hint)
2157
2170
2158 def clearunfinished(repo):
2171 def clearunfinished(repo):
2159 '''Check for unfinished operations (as above), and clear the ones
2172 '''Check for unfinished operations (as above), and clear the ones
2160 that are clearable.
2173 that are clearable.
2161 '''
2174 '''
2162 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2175 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2163 if not clearable and repo.vfs.exists(f):
2176 if not clearable and repo.vfs.exists(f):
2164 raise util.Abort(msg, hint=hint)
2177 raise util.Abort(msg, hint=hint)
2165 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2178 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2166 if clearable and repo.vfs.exists(f):
2179 if clearable and repo.vfs.exists(f):
2167 util.unlink(repo.join(f))
2180 util.unlink(repo.join(f))
@@ -1,5945 +1,5938
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 _
10 from i18n import _
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, copies, error, bookmarks
12 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import patch, help, encoding, templatekw, discovery
13 import patch, help, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, commandserver
15 import sshserver, hgweb, commandserver
16 from hgweb import server as hgweb_server
16 from hgweb import server as hgweb_server
17 import merge as mergemod
17 import merge as mergemod
18 import minirst, revset, fileset
18 import minirst, revset, fileset
19 import dagparser, context, simplemerge, graphmod
19 import dagparser, context, simplemerge, graphmod
20 import random
20 import random
21 import setdiscovery, treediscovery, dagutil, pvec, localrepo
21 import setdiscovery, treediscovery, dagutil, pvec, localrepo
22 import phases, obsolete
22 import phases, obsolete
23
23
24 table = {}
24 table = {}
25
25
26 command = cmdutil.command(table)
26 command = cmdutil.command(table)
27
27
28 # common command options
28 # common command options
29
29
30 globalopts = [
30 globalopts = [
31 ('R', 'repository', '',
31 ('R', 'repository', '',
32 _('repository root directory or name of overlay bundle file'),
32 _('repository root directory or name of overlay bundle file'),
33 _('REPO')),
33 _('REPO')),
34 ('', 'cwd', '',
34 ('', 'cwd', '',
35 _('change working directory'), _('DIR')),
35 _('change working directory'), _('DIR')),
36 ('y', 'noninteractive', None,
36 ('y', 'noninteractive', None,
37 _('do not prompt, automatically pick the first choice for all prompts')),
37 _('do not prompt, automatically pick the first choice for all prompts')),
38 ('q', 'quiet', None, _('suppress output')),
38 ('q', 'quiet', None, _('suppress output')),
39 ('v', 'verbose', None, _('enable additional output')),
39 ('v', 'verbose', None, _('enable additional output')),
40 ('', 'config', [],
40 ('', 'config', [],
41 _('set/override config option (use \'section.name=value\')'),
41 _('set/override config option (use \'section.name=value\')'),
42 _('CONFIG')),
42 _('CONFIG')),
43 ('', 'debug', None, _('enable debugging output')),
43 ('', 'debug', None, _('enable debugging output')),
44 ('', 'debugger', None, _('start debugger')),
44 ('', 'debugger', None, _('start debugger')),
45 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
45 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
46 _('ENCODE')),
46 _('ENCODE')),
47 ('', 'encodingmode', encoding.encodingmode,
47 ('', 'encodingmode', encoding.encodingmode,
48 _('set the charset encoding mode'), _('MODE')),
48 _('set the charset encoding mode'), _('MODE')),
49 ('', 'traceback', None, _('always print a traceback on exception')),
49 ('', 'traceback', None, _('always print a traceback on exception')),
50 ('', 'time', None, _('time how long the command takes')),
50 ('', 'time', None, _('time how long the command takes')),
51 ('', 'profile', None, _('print command execution profile')),
51 ('', 'profile', None, _('print command execution profile')),
52 ('', 'version', None, _('output version information and exit')),
52 ('', 'version', None, _('output version information and exit')),
53 ('h', 'help', None, _('display help and exit')),
53 ('h', 'help', None, _('display help and exit')),
54 ('', 'hidden', False, _('consider hidden changesets')),
54 ('', 'hidden', False, _('consider hidden changesets')),
55 ]
55 ]
56
56
57 dryrunopts = [('n', 'dry-run', None,
57 dryrunopts = [('n', 'dry-run', None,
58 _('do not perform actions, just print output'))]
58 _('do not perform actions, just print output'))]
59
59
60 remoteopts = [
60 remoteopts = [
61 ('e', 'ssh', '',
61 ('e', 'ssh', '',
62 _('specify ssh command to use'), _('CMD')),
62 _('specify ssh command to use'), _('CMD')),
63 ('', 'remotecmd', '',
63 ('', 'remotecmd', '',
64 _('specify hg command to run on the remote side'), _('CMD')),
64 _('specify hg command to run on the remote side'), _('CMD')),
65 ('', 'insecure', None,
65 ('', 'insecure', None,
66 _('do not verify server certificate (ignoring web.cacerts config)')),
66 _('do not verify server certificate (ignoring web.cacerts config)')),
67 ]
67 ]
68
68
69 walkopts = [
69 walkopts = [
70 ('I', 'include', [],
70 ('I', 'include', [],
71 _('include names matching the given patterns'), _('PATTERN')),
71 _('include names matching the given patterns'), _('PATTERN')),
72 ('X', 'exclude', [],
72 ('X', 'exclude', [],
73 _('exclude names matching the given patterns'), _('PATTERN')),
73 _('exclude names matching the given patterns'), _('PATTERN')),
74 ]
74 ]
75
75
76 commitopts = [
76 commitopts = [
77 ('m', 'message', '',
77 ('m', 'message', '',
78 _('use text as commit message'), _('TEXT')),
78 _('use text as commit message'), _('TEXT')),
79 ('l', 'logfile', '',
79 ('l', 'logfile', '',
80 _('read commit message from file'), _('FILE')),
80 _('read commit message from file'), _('FILE')),
81 ]
81 ]
82
82
83 commitopts2 = [
83 commitopts2 = [
84 ('d', 'date', '',
84 ('d', 'date', '',
85 _('record the specified date as commit date'), _('DATE')),
85 _('record the specified date as commit date'), _('DATE')),
86 ('u', 'user', '',
86 ('u', 'user', '',
87 _('record the specified user as committer'), _('USER')),
87 _('record the specified user as committer'), _('USER')),
88 ]
88 ]
89
89
90 templateopts = [
90 templateopts = [
91 ('', 'style', '',
91 ('', 'style', '',
92 _('display using template map file'), _('STYLE')),
92 _('display using template map file'), _('STYLE')),
93 ('', 'template', '',
93 ('', 'template', '',
94 _('display with template'), _('TEMPLATE')),
94 _('display with template'), _('TEMPLATE')),
95 ]
95 ]
96
96
97 logopts = [
97 logopts = [
98 ('p', 'patch', None, _('show patch')),
98 ('p', 'patch', None, _('show patch')),
99 ('g', 'git', None, _('use git extended diff format')),
99 ('g', 'git', None, _('use git extended diff format')),
100 ('l', 'limit', '',
100 ('l', 'limit', '',
101 _('limit number of changes displayed'), _('NUM')),
101 _('limit number of changes displayed'), _('NUM')),
102 ('M', 'no-merges', None, _('do not show merges')),
102 ('M', 'no-merges', None, _('do not show merges')),
103 ('', 'stat', None, _('output diffstat-style summary of changes')),
103 ('', 'stat', None, _('output diffstat-style summary of changes')),
104 ('G', 'graph', None, _("show the revision DAG")),
104 ('G', 'graph', None, _("show the revision DAG")),
105 ] + templateopts
105 ] + templateopts
106
106
107 diffopts = [
107 diffopts = [
108 ('a', 'text', None, _('treat all files as text')),
108 ('a', 'text', None, _('treat all files as text')),
109 ('g', 'git', None, _('use git extended diff format')),
109 ('g', 'git', None, _('use git extended diff format')),
110 ('', 'nodates', None, _('omit dates from diff headers'))
110 ('', 'nodates', None, _('omit dates from diff headers'))
111 ]
111 ]
112
112
113 diffwsopts = [
113 diffwsopts = [
114 ('w', 'ignore-all-space', None,
114 ('w', 'ignore-all-space', None,
115 _('ignore white space when comparing lines')),
115 _('ignore white space when comparing lines')),
116 ('b', 'ignore-space-change', None,
116 ('b', 'ignore-space-change', None,
117 _('ignore changes in the amount of white space')),
117 _('ignore changes in the amount of white space')),
118 ('B', 'ignore-blank-lines', None,
118 ('B', 'ignore-blank-lines', None,
119 _('ignore changes whose lines are all blank')),
119 _('ignore changes whose lines are all blank')),
120 ]
120 ]
121
121
122 diffopts2 = [
122 diffopts2 = [
123 ('p', 'show-function', None, _('show which function each change is in')),
123 ('p', 'show-function', None, _('show which function each change is in')),
124 ('', 'reverse', None, _('produce a diff that undoes the changes')),
124 ('', 'reverse', None, _('produce a diff that undoes the changes')),
125 ] + diffwsopts + [
125 ] + diffwsopts + [
126 ('U', 'unified', '',
126 ('U', 'unified', '',
127 _('number of lines of context to show'), _('NUM')),
127 _('number of lines of context to show'), _('NUM')),
128 ('', 'stat', None, _('output diffstat-style summary of changes')),
128 ('', 'stat', None, _('output diffstat-style summary of changes')),
129 ]
129 ]
130
130
131 mergetoolopts = [
131 mergetoolopts = [
132 ('t', 'tool', '', _('specify merge tool')),
132 ('t', 'tool', '', _('specify merge tool')),
133 ]
133 ]
134
134
135 similarityopts = [
135 similarityopts = [
136 ('s', 'similarity', '',
136 ('s', 'similarity', '',
137 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
137 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
138 ]
138 ]
139
139
140 subrepoopts = [
140 subrepoopts = [
141 ('S', 'subrepos', None,
141 ('S', 'subrepos', None,
142 _('recurse into subrepositories'))
142 _('recurse into subrepositories'))
143 ]
143 ]
144
144
145 # Commands start here, listed alphabetically
145 # Commands start here, listed alphabetically
146
146
147 @command('^add',
147 @command('^add',
148 walkopts + subrepoopts + dryrunopts,
148 walkopts + subrepoopts + dryrunopts,
149 _('[OPTION]... [FILE]...'))
149 _('[OPTION]... [FILE]...'))
150 def add(ui, repo, *pats, **opts):
150 def add(ui, repo, *pats, **opts):
151 """add the specified files on the next commit
151 """add the specified files on the next commit
152
152
153 Schedule files to be version controlled and added to the
153 Schedule files to be version controlled and added to the
154 repository.
154 repository.
155
155
156 The files will be added to the repository at the next commit. To
156 The files will be added to the repository at the next commit. To
157 undo an add before that, see :hg:`forget`.
157 undo an add before that, see :hg:`forget`.
158
158
159 If no names are given, add all files to the repository.
159 If no names are given, add all files to the repository.
160
160
161 .. container:: verbose
161 .. container:: verbose
162
162
163 An example showing how new (unknown) files are added
163 An example showing how new (unknown) files are added
164 automatically by :hg:`add`::
164 automatically by :hg:`add`::
165
165
166 $ ls
166 $ ls
167 foo.c
167 foo.c
168 $ hg status
168 $ hg status
169 ? foo.c
169 ? foo.c
170 $ hg add
170 $ hg add
171 adding foo.c
171 adding foo.c
172 $ hg status
172 $ hg status
173 A foo.c
173 A foo.c
174
174
175 Returns 0 if all files are successfully added.
175 Returns 0 if all files are successfully added.
176 """
176 """
177
177
178 m = scmutil.match(repo[None], pats, opts)
178 m = scmutil.match(repo[None], pats, opts)
179 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
179 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
180 opts.get('subrepos'), prefix="", explicitonly=False)
180 opts.get('subrepos'), prefix="", explicitonly=False)
181 return rejected and 1 or 0
181 return rejected and 1 or 0
182
182
183 @command('addremove',
183 @command('addremove',
184 similarityopts + walkopts + dryrunopts,
184 similarityopts + walkopts + dryrunopts,
185 _('[OPTION]... [FILE]...'))
185 _('[OPTION]... [FILE]...'))
186 def addremove(ui, repo, *pats, **opts):
186 def addremove(ui, repo, *pats, **opts):
187 """add all new files, delete all missing files
187 """add all new files, delete all missing files
188
188
189 Add all new files and remove all missing files from the
189 Add all new files and remove all missing files from the
190 repository.
190 repository.
191
191
192 New files are ignored if they match any of the patterns in
192 New files are ignored if they match any of the patterns in
193 ``.hgignore``. As with add, these changes take effect at the next
193 ``.hgignore``. As with add, these changes take effect at the next
194 commit.
194 commit.
195
195
196 Use the -s/--similarity option to detect renamed files. This
196 Use the -s/--similarity option to detect renamed files. This
197 option takes a percentage between 0 (disabled) and 100 (files must
197 option takes a percentage between 0 (disabled) and 100 (files must
198 be identical) as its parameter. With a parameter greater than 0,
198 be identical) as its parameter. With a parameter greater than 0,
199 this compares every removed file with every added file and records
199 this compares every removed file with every added file and records
200 those similar enough as renames. Detecting renamed files this way
200 those similar enough as renames. Detecting renamed files this way
201 can be expensive. After using this option, :hg:`status -C` can be
201 can be expensive. After using this option, :hg:`status -C` can be
202 used to check which files were identified as moved or renamed. If
202 used to check which files were identified as moved or renamed. If
203 not specified, -s/--similarity defaults to 100 and only renames of
203 not specified, -s/--similarity defaults to 100 and only renames of
204 identical files are detected.
204 identical files are detected.
205
205
206 Returns 0 if all files are successfully added.
206 Returns 0 if all files are successfully added.
207 """
207 """
208 try:
208 try:
209 sim = float(opts.get('similarity') or 100)
209 sim = float(opts.get('similarity') or 100)
210 except ValueError:
210 except ValueError:
211 raise util.Abort(_('similarity must be a number'))
211 raise util.Abort(_('similarity must be a number'))
212 if sim < 0 or sim > 100:
212 if sim < 0 or sim > 100:
213 raise util.Abort(_('similarity must be between 0 and 100'))
213 raise util.Abort(_('similarity must be between 0 and 100'))
214 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
214 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
215
215
216 @command('^annotate|blame',
216 @command('^annotate|blame',
217 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
217 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
218 ('', 'follow', None,
218 ('', 'follow', None,
219 _('follow copies/renames and list the filename (DEPRECATED)')),
219 _('follow copies/renames and list the filename (DEPRECATED)')),
220 ('', 'no-follow', None, _("don't follow copies and renames")),
220 ('', 'no-follow', None, _("don't follow copies and renames")),
221 ('a', 'text', None, _('treat all files as text')),
221 ('a', 'text', None, _('treat all files as text')),
222 ('u', 'user', None, _('list the author (long with -v)')),
222 ('u', 'user', None, _('list the author (long with -v)')),
223 ('f', 'file', None, _('list the filename')),
223 ('f', 'file', None, _('list the filename')),
224 ('d', 'date', None, _('list the date (short with -q)')),
224 ('d', 'date', None, _('list the date (short with -q)')),
225 ('n', 'number', None, _('list the revision number (default)')),
225 ('n', 'number', None, _('list the revision number (default)')),
226 ('c', 'changeset', None, _('list the changeset')),
226 ('c', 'changeset', None, _('list the changeset')),
227 ('l', 'line-number', None, _('show line number at the first appearance'))
227 ('l', 'line-number', None, _('show line number at the first appearance'))
228 ] + diffwsopts + walkopts,
228 ] + diffwsopts + walkopts,
229 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
229 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
230 def annotate(ui, repo, *pats, **opts):
230 def annotate(ui, repo, *pats, **opts):
231 """show changeset information by line for each file
231 """show changeset information by line for each file
232
232
233 List changes in files, showing the revision id responsible for
233 List changes in files, showing the revision id responsible for
234 each line
234 each line
235
235
236 This command is useful for discovering when a change was made and
236 This command is useful for discovering when a change was made and
237 by whom.
237 by whom.
238
238
239 Without the -a/--text option, annotate will avoid processing files
239 Without the -a/--text option, annotate will avoid processing files
240 it detects as binary. With -a, annotate will annotate the file
240 it detects as binary. With -a, annotate will annotate the file
241 anyway, although the results will probably be neither useful
241 anyway, although the results will probably be neither useful
242 nor desirable.
242 nor desirable.
243
243
244 Returns 0 on success.
244 Returns 0 on success.
245 """
245 """
246 if opts.get('follow'):
246 if opts.get('follow'):
247 # --follow is deprecated and now just an alias for -f/--file
247 # --follow is deprecated and now just an alias for -f/--file
248 # to mimic the behavior of Mercurial before version 1.5
248 # to mimic the behavior of Mercurial before version 1.5
249 opts['file'] = True
249 opts['file'] = True
250
250
251 datefunc = ui.quiet and util.shortdate or util.datestr
251 datefunc = ui.quiet and util.shortdate or util.datestr
252 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
252 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
253
253
254 if not pats:
254 if not pats:
255 raise util.Abort(_('at least one filename or pattern is required'))
255 raise util.Abort(_('at least one filename or pattern is required'))
256
256
257 hexfn = ui.debugflag and hex or short
257 hexfn = ui.debugflag and hex or short
258
258
259 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
259 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
260 ('number', ' ', lambda x: str(x[0].rev())),
260 ('number', ' ', lambda x: str(x[0].rev())),
261 ('changeset', ' ', lambda x: hexfn(x[0].node())),
261 ('changeset', ' ', lambda x: hexfn(x[0].node())),
262 ('date', ' ', getdate),
262 ('date', ' ', getdate),
263 ('file', ' ', lambda x: x[0].path()),
263 ('file', ' ', lambda x: x[0].path()),
264 ('line_number', ':', lambda x: str(x[1])),
264 ('line_number', ':', lambda x: str(x[1])),
265 ]
265 ]
266
266
267 if (not opts.get('user') and not opts.get('changeset')
267 if (not opts.get('user') and not opts.get('changeset')
268 and not opts.get('date') and not opts.get('file')):
268 and not opts.get('date') and not opts.get('file')):
269 opts['number'] = True
269 opts['number'] = True
270
270
271 linenumber = opts.get('line_number') is not None
271 linenumber = opts.get('line_number') is not None
272 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
272 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
273 raise util.Abort(_('at least one of -n/-c is required for -l'))
273 raise util.Abort(_('at least one of -n/-c is required for -l'))
274
274
275 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
275 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
276 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
276 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
277
277
278 def bad(x, y):
278 def bad(x, y):
279 raise util.Abort("%s: %s" % (x, y))
279 raise util.Abort("%s: %s" % (x, y))
280
280
281 ctx = scmutil.revsingle(repo, opts.get('rev'))
281 ctx = scmutil.revsingle(repo, opts.get('rev'))
282 m = scmutil.match(ctx, pats, opts)
282 m = scmutil.match(ctx, pats, opts)
283 m.bad = bad
283 m.bad = bad
284 follow = not opts.get('no_follow')
284 follow = not opts.get('no_follow')
285 diffopts = patch.diffopts(ui, opts, section='annotate')
285 diffopts = patch.diffopts(ui, opts, section='annotate')
286 for abs in ctx.walk(m):
286 for abs in ctx.walk(m):
287 fctx = ctx[abs]
287 fctx = ctx[abs]
288 if not opts.get('text') and util.binary(fctx.data()):
288 if not opts.get('text') and util.binary(fctx.data()):
289 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
289 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
290 continue
290 continue
291
291
292 lines = fctx.annotate(follow=follow, linenumber=linenumber,
292 lines = fctx.annotate(follow=follow, linenumber=linenumber,
293 diffopts=diffopts)
293 diffopts=diffopts)
294 pieces = []
294 pieces = []
295
295
296 for f, sep in funcmap:
296 for f, sep in funcmap:
297 l = [f(n) for n, dummy in lines]
297 l = [f(n) for n, dummy in lines]
298 if l:
298 if l:
299 sized = [(x, encoding.colwidth(x)) for x in l]
299 sized = [(x, encoding.colwidth(x)) for x in l]
300 ml = max([w for x, w in sized])
300 ml = max([w for x, w in sized])
301 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
301 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
302 for x, w in sized])
302 for x, w in sized])
303
303
304 if pieces:
304 if pieces:
305 for p, l in zip(zip(*pieces), lines):
305 for p, l in zip(zip(*pieces), lines):
306 ui.write("%s: %s" % ("".join(p), l[1]))
306 ui.write("%s: %s" % ("".join(p), l[1]))
307
307
308 if lines and not lines[-1][1].endswith('\n'):
308 if lines and not lines[-1][1].endswith('\n'):
309 ui.write('\n')
309 ui.write('\n')
310
310
311 @command('archive',
311 @command('archive',
312 [('', 'no-decode', None, _('do not pass files through decoders')),
312 [('', 'no-decode', None, _('do not pass files through decoders')),
313 ('p', 'prefix', '', _('directory prefix for files in archive'),
313 ('p', 'prefix', '', _('directory prefix for files in archive'),
314 _('PREFIX')),
314 _('PREFIX')),
315 ('r', 'rev', '', _('revision to distribute'), _('REV')),
315 ('r', 'rev', '', _('revision to distribute'), _('REV')),
316 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
316 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
317 ] + subrepoopts + walkopts,
317 ] + subrepoopts + walkopts,
318 _('[OPTION]... DEST'))
318 _('[OPTION]... DEST'))
319 def archive(ui, repo, dest, **opts):
319 def archive(ui, repo, dest, **opts):
320 '''create an unversioned archive of a repository revision
320 '''create an unversioned archive of a repository revision
321
321
322 By default, the revision used is the parent of the working
322 By default, the revision used is the parent of the working
323 directory; use -r/--rev to specify a different revision.
323 directory; use -r/--rev to specify a different revision.
324
324
325 The archive type is automatically detected based on file
325 The archive type is automatically detected based on file
326 extension (or override using -t/--type).
326 extension (or override using -t/--type).
327
327
328 .. container:: verbose
328 .. container:: verbose
329
329
330 Examples:
330 Examples:
331
331
332 - create a zip file containing the 1.0 release::
332 - create a zip file containing the 1.0 release::
333
333
334 hg archive -r 1.0 project-1.0.zip
334 hg archive -r 1.0 project-1.0.zip
335
335
336 - create a tarball excluding .hg files::
336 - create a tarball excluding .hg files::
337
337
338 hg archive project.tar.gz -X ".hg*"
338 hg archive project.tar.gz -X ".hg*"
339
339
340 Valid types are:
340 Valid types are:
341
341
342 :``files``: a directory full of files (default)
342 :``files``: a directory full of files (default)
343 :``tar``: tar archive, uncompressed
343 :``tar``: tar archive, uncompressed
344 :``tbz2``: tar archive, compressed using bzip2
344 :``tbz2``: tar archive, compressed using bzip2
345 :``tgz``: tar archive, compressed using gzip
345 :``tgz``: tar archive, compressed using gzip
346 :``uzip``: zip archive, uncompressed
346 :``uzip``: zip archive, uncompressed
347 :``zip``: zip archive, compressed using deflate
347 :``zip``: zip archive, compressed using deflate
348
348
349 The exact name of the destination archive or directory is given
349 The exact name of the destination archive or directory is given
350 using a format string; see :hg:`help export` for details.
350 using a format string; see :hg:`help export` for details.
351
351
352 Each member added to an archive file has a directory prefix
352 Each member added to an archive file has a directory prefix
353 prepended. Use -p/--prefix to specify a format string for the
353 prepended. Use -p/--prefix to specify a format string for the
354 prefix. The default is the basename of the archive, with suffixes
354 prefix. The default is the basename of the archive, with suffixes
355 removed.
355 removed.
356
356
357 Returns 0 on success.
357 Returns 0 on success.
358 '''
358 '''
359
359
360 ctx = scmutil.revsingle(repo, opts.get('rev'))
360 ctx = scmutil.revsingle(repo, opts.get('rev'))
361 if not ctx:
361 if not ctx:
362 raise util.Abort(_('no working directory: please specify a revision'))
362 raise util.Abort(_('no working directory: please specify a revision'))
363 node = ctx.node()
363 node = ctx.node()
364 dest = cmdutil.makefilename(repo, dest, node)
364 dest = cmdutil.makefilename(repo, dest, node)
365 if os.path.realpath(dest) == repo.root:
365 if os.path.realpath(dest) == repo.root:
366 raise util.Abort(_('repository root cannot be destination'))
366 raise util.Abort(_('repository root cannot be destination'))
367
367
368 kind = opts.get('type') or archival.guesskind(dest) or 'files'
368 kind = opts.get('type') or archival.guesskind(dest) or 'files'
369 prefix = opts.get('prefix')
369 prefix = opts.get('prefix')
370
370
371 if dest == '-':
371 if dest == '-':
372 if kind == 'files':
372 if kind == 'files':
373 raise util.Abort(_('cannot archive plain files to stdout'))
373 raise util.Abort(_('cannot archive plain files to stdout'))
374 dest = cmdutil.makefileobj(repo, dest)
374 dest = cmdutil.makefileobj(repo, dest)
375 if not prefix:
375 if not prefix:
376 prefix = os.path.basename(repo.root) + '-%h'
376 prefix = os.path.basename(repo.root) + '-%h'
377
377
378 prefix = cmdutil.makefilename(repo, prefix, node)
378 prefix = cmdutil.makefilename(repo, prefix, node)
379 matchfn = scmutil.match(ctx, [], opts)
379 matchfn = scmutil.match(ctx, [], opts)
380 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
380 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
381 matchfn, prefix, subrepos=opts.get('subrepos'))
381 matchfn, prefix, subrepos=opts.get('subrepos'))
382
382
383 @command('backout',
383 @command('backout',
384 [('', 'merge', None, _('merge with old dirstate parent after backout')),
384 [('', 'merge', None, _('merge with old dirstate parent after backout')),
385 ('', 'parent', '',
385 ('', 'parent', '',
386 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
386 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
387 ('r', 'rev', '', _('revision to backout'), _('REV')),
387 ('r', 'rev', '', _('revision to backout'), _('REV')),
388 ] + mergetoolopts + walkopts + commitopts + commitopts2,
388 ] + mergetoolopts + walkopts + commitopts + commitopts2,
389 _('[OPTION]... [-r] REV'))
389 _('[OPTION]... [-r] REV'))
390 def backout(ui, repo, node=None, rev=None, **opts):
390 def backout(ui, repo, node=None, rev=None, **opts):
391 '''reverse effect of earlier changeset
391 '''reverse effect of earlier changeset
392
392
393 Prepare a new changeset with the effect of REV undone in the
393 Prepare a new changeset with the effect of REV undone in the
394 current working directory.
394 current working directory.
395
395
396 If REV is the parent of the working directory, then this new changeset
396 If REV is the parent of the working directory, then this new changeset
397 is committed automatically. Otherwise, hg needs to merge the
397 is committed automatically. Otherwise, hg needs to merge the
398 changes and the merged result is left uncommitted.
398 changes and the merged result is left uncommitted.
399
399
400 .. note::
400 .. note::
401
401
402 backout cannot be used to fix either an unwanted or
402 backout cannot be used to fix either an unwanted or
403 incorrect merge.
403 incorrect merge.
404
404
405 .. container:: verbose
405 .. container:: verbose
406
406
407 By default, the pending changeset will have one parent,
407 By default, the pending changeset will have one parent,
408 maintaining a linear history. With --merge, the pending
408 maintaining a linear history. With --merge, the pending
409 changeset will instead have two parents: the old parent of the
409 changeset will instead have two parents: the old parent of the
410 working directory and a new child of REV that simply undoes REV.
410 working directory and a new child of REV that simply undoes REV.
411
411
412 Before version 1.7, the behavior without --merge was equivalent
412 Before version 1.7, the behavior without --merge was equivalent
413 to specifying --merge followed by :hg:`update --clean .` to
413 to specifying --merge followed by :hg:`update --clean .` to
414 cancel the merge and leave the child of REV as a head to be
414 cancel the merge and leave the child of REV as a head to be
415 merged separately.
415 merged separately.
416
416
417 See :hg:`help dates` for a list of formats valid for -d/--date.
417 See :hg:`help dates` for a list of formats valid for -d/--date.
418
418
419 Returns 0 on success.
419 Returns 0 on success.
420 '''
420 '''
421 if rev and node:
421 if rev and node:
422 raise util.Abort(_("please specify just one revision"))
422 raise util.Abort(_("please specify just one revision"))
423
423
424 if not rev:
424 if not rev:
425 rev = node
425 rev = node
426
426
427 if not rev:
427 if not rev:
428 raise util.Abort(_("please specify a revision to backout"))
428 raise util.Abort(_("please specify a revision to backout"))
429
429
430 date = opts.get('date')
430 date = opts.get('date')
431 if date:
431 if date:
432 opts['date'] = util.parsedate(date)
432 opts['date'] = util.parsedate(date)
433
433
434 cmdutil.checkunfinished(repo)
434 cmdutil.checkunfinished(repo)
435 cmdutil.bailifchanged(repo)
435 cmdutil.bailifchanged(repo)
436 node = scmutil.revsingle(repo, rev).node()
436 node = scmutil.revsingle(repo, rev).node()
437
437
438 op1, op2 = repo.dirstate.parents()
438 op1, op2 = repo.dirstate.parents()
439 a = repo.changelog.ancestor(op1, node)
439 a = repo.changelog.ancestor(op1, node)
440 if a != node:
440 if a != node:
441 raise util.Abort(_('cannot backout change on a different branch'))
441 raise util.Abort(_('cannot backout change on a different branch'))
442
442
443 p1, p2 = repo.changelog.parents(node)
443 p1, p2 = repo.changelog.parents(node)
444 if p1 == nullid:
444 if p1 == nullid:
445 raise util.Abort(_('cannot backout a change with no parents'))
445 raise util.Abort(_('cannot backout a change with no parents'))
446 if p2 != nullid:
446 if p2 != nullid:
447 if not opts.get('parent'):
447 if not opts.get('parent'):
448 raise util.Abort(_('cannot backout a merge changeset'))
448 raise util.Abort(_('cannot backout a merge changeset'))
449 p = repo.lookup(opts['parent'])
449 p = repo.lookup(opts['parent'])
450 if p not in (p1, p2):
450 if p not in (p1, p2):
451 raise util.Abort(_('%s is not a parent of %s') %
451 raise util.Abort(_('%s is not a parent of %s') %
452 (short(p), short(node)))
452 (short(p), short(node)))
453 parent = p
453 parent = p
454 else:
454 else:
455 if opts.get('parent'):
455 if opts.get('parent'):
456 raise util.Abort(_('cannot use --parent on non-merge changeset'))
456 raise util.Abort(_('cannot use --parent on non-merge changeset'))
457 parent = p1
457 parent = p1
458
458
459 # the backout should appear on the same branch
459 # the backout should appear on the same branch
460 wlock = repo.wlock()
460 wlock = repo.wlock()
461 try:
461 try:
462 branch = repo.dirstate.branch()
462 branch = repo.dirstate.branch()
463 bheads = repo.branchheads(branch)
463 bheads = repo.branchheads(branch)
464 rctx = scmutil.revsingle(repo, hex(parent))
464 rctx = scmutil.revsingle(repo, hex(parent))
465 if not opts.get('merge') and op1 != node:
465 if not opts.get('merge') and op1 != node:
466 try:
466 try:
467 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
467 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
468 stats = mergemod.update(repo, parent, True, True, False,
468 stats = mergemod.update(repo, parent, True, True, False,
469 node, False)
469 node, False)
470 repo.setparents(op1, op2)
470 repo.setparents(op1, op2)
471 hg._showstats(repo, stats)
471 hg._showstats(repo, stats)
472 if stats[3]:
472 if stats[3]:
473 repo.ui.status(_("use 'hg resolve' to retry unresolved "
473 repo.ui.status(_("use 'hg resolve' to retry unresolved "
474 "file merges\n"))
474 "file merges\n"))
475 else:
475 else:
476 msg = _("changeset %s backed out, "
476 msg = _("changeset %s backed out, "
477 "don't forget to commit.\n")
477 "don't forget to commit.\n")
478 ui.status(msg % short(node))
478 ui.status(msg % short(node))
479 return stats[3] > 0
479 return stats[3] > 0
480 finally:
480 finally:
481 ui.setconfig('ui', 'forcemerge', '')
481 ui.setconfig('ui', 'forcemerge', '')
482 else:
482 else:
483 hg.clean(repo, node, show_stats=False)
483 hg.clean(repo, node, show_stats=False)
484 repo.dirstate.setbranch(branch)
484 repo.dirstate.setbranch(branch)
485 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
485 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
486
486
487
487
488 e = cmdutil.commiteditor
488 e = cmdutil.commiteditor
489 if not opts['message'] and not opts['logfile']:
489 if not opts['message'] and not opts['logfile']:
490 # we don't translate commit messages
490 # we don't translate commit messages
491 opts['message'] = "Backed out changeset %s" % short(node)
491 opts['message'] = "Backed out changeset %s" % short(node)
492 e = cmdutil.commitforceeditor
492 e = cmdutil.commitforceeditor
493
493
494 def commitfunc(ui, repo, message, match, opts):
494 def commitfunc(ui, repo, message, match, opts):
495 return repo.commit(message, opts.get('user'), opts.get('date'),
495 return repo.commit(message, opts.get('user'), opts.get('date'),
496 match, editor=e)
496 match, editor=e)
497 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
497 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
498 cmdutil.commitstatus(repo, newnode, branch, bheads)
498 cmdutil.commitstatus(repo, newnode, branch, bheads)
499
499
500 def nice(node):
500 def nice(node):
501 return '%d:%s' % (repo.changelog.rev(node), short(node))
501 return '%d:%s' % (repo.changelog.rev(node), short(node))
502 ui.status(_('changeset %s backs out changeset %s\n') %
502 ui.status(_('changeset %s backs out changeset %s\n') %
503 (nice(repo.changelog.tip()), nice(node)))
503 (nice(repo.changelog.tip()), nice(node)))
504 if opts.get('merge') and op1 != node:
504 if opts.get('merge') and op1 != node:
505 hg.clean(repo, op1, show_stats=False)
505 hg.clean(repo, op1, show_stats=False)
506 ui.status(_('merging with changeset %s\n')
506 ui.status(_('merging with changeset %s\n')
507 % nice(repo.changelog.tip()))
507 % nice(repo.changelog.tip()))
508 try:
508 try:
509 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
509 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
510 return hg.merge(repo, hex(repo.changelog.tip()))
510 return hg.merge(repo, hex(repo.changelog.tip()))
511 finally:
511 finally:
512 ui.setconfig('ui', 'forcemerge', '')
512 ui.setconfig('ui', 'forcemerge', '')
513 finally:
513 finally:
514 wlock.release()
514 wlock.release()
515 return 0
515 return 0
516
516
517 @command('bisect',
517 @command('bisect',
518 [('r', 'reset', False, _('reset bisect state')),
518 [('r', 'reset', False, _('reset bisect state')),
519 ('g', 'good', False, _('mark changeset good')),
519 ('g', 'good', False, _('mark changeset good')),
520 ('b', 'bad', False, _('mark changeset bad')),
520 ('b', 'bad', False, _('mark changeset bad')),
521 ('s', 'skip', False, _('skip testing changeset')),
521 ('s', 'skip', False, _('skip testing changeset')),
522 ('e', 'extend', False, _('extend the bisect range')),
522 ('e', 'extend', False, _('extend the bisect range')),
523 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
523 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
524 ('U', 'noupdate', False, _('do not update to target'))],
524 ('U', 'noupdate', False, _('do not update to target'))],
525 _("[-gbsr] [-U] [-c CMD] [REV]"))
525 _("[-gbsr] [-U] [-c CMD] [REV]"))
526 def bisect(ui, repo, rev=None, extra=None, command=None,
526 def bisect(ui, repo, rev=None, extra=None, command=None,
527 reset=None, good=None, bad=None, skip=None, extend=None,
527 reset=None, good=None, bad=None, skip=None, extend=None,
528 noupdate=None):
528 noupdate=None):
529 """subdivision search of changesets
529 """subdivision search of changesets
530
530
531 This command helps to find changesets which introduce problems. To
531 This command helps to find changesets which introduce problems. To
532 use, mark the earliest changeset you know exhibits the problem as
532 use, mark the earliest changeset you know exhibits the problem as
533 bad, then mark the latest changeset which is free from the problem
533 bad, then mark the latest changeset which is free from the problem
534 as good. Bisect will update your working directory to a revision
534 as good. Bisect will update your working directory to a revision
535 for testing (unless the -U/--noupdate option is specified). Once
535 for testing (unless the -U/--noupdate option is specified). Once
536 you have performed tests, mark the working directory as good or
536 you have performed tests, mark the working directory as good or
537 bad, and bisect will either update to another candidate changeset
537 bad, and bisect will either update to another candidate changeset
538 or announce that it has found the bad revision.
538 or announce that it has found the bad revision.
539
539
540 As a shortcut, you can also use the revision argument to mark a
540 As a shortcut, you can also use the revision argument to mark a
541 revision as good or bad without checking it out first.
541 revision as good or bad without checking it out first.
542
542
543 If you supply a command, it will be used for automatic bisection.
543 If you supply a command, it will be used for automatic bisection.
544 The environment variable HG_NODE will contain the ID of the
544 The environment variable HG_NODE will contain the ID of the
545 changeset being tested. The exit status of the command will be
545 changeset being tested. The exit status of the command will be
546 used to mark revisions as good or bad: status 0 means good, 125
546 used to mark revisions as good or bad: status 0 means good, 125
547 means to skip the revision, 127 (command not found) will abort the
547 means to skip the revision, 127 (command not found) will abort the
548 bisection, and any other non-zero exit status means the revision
548 bisection, and any other non-zero exit status means the revision
549 is bad.
549 is bad.
550
550
551 .. container:: verbose
551 .. container:: verbose
552
552
553 Some examples:
553 Some examples:
554
554
555 - start a bisection with known bad revision 34, and good revision 12::
555 - start a bisection with known bad revision 34, and good revision 12::
556
556
557 hg bisect --bad 34
557 hg bisect --bad 34
558 hg bisect --good 12
558 hg bisect --good 12
559
559
560 - advance the current bisection by marking current revision as good or
560 - advance the current bisection by marking current revision as good or
561 bad::
561 bad::
562
562
563 hg bisect --good
563 hg bisect --good
564 hg bisect --bad
564 hg bisect --bad
565
565
566 - mark the current revision, or a known revision, to be skipped (e.g. if
566 - mark the current revision, or a known revision, to be skipped (e.g. if
567 that revision is not usable because of another issue)::
567 that revision is not usable because of another issue)::
568
568
569 hg bisect --skip
569 hg bisect --skip
570 hg bisect --skip 23
570 hg bisect --skip 23
571
571
572 - skip all revisions that do not touch directories ``foo`` or ``bar``::
572 - skip all revisions that do not touch directories ``foo`` or ``bar``::
573
573
574 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
574 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
575
575
576 - forget the current bisection::
576 - forget the current bisection::
577
577
578 hg bisect --reset
578 hg bisect --reset
579
579
580 - use 'make && make tests' to automatically find the first broken
580 - use 'make && make tests' to automatically find the first broken
581 revision::
581 revision::
582
582
583 hg bisect --reset
583 hg bisect --reset
584 hg bisect --bad 34
584 hg bisect --bad 34
585 hg bisect --good 12
585 hg bisect --good 12
586 hg bisect --command "make && make tests"
586 hg bisect --command "make && make tests"
587
587
588 - see all changesets whose states are already known in the current
588 - see all changesets whose states are already known in the current
589 bisection::
589 bisection::
590
590
591 hg log -r "bisect(pruned)"
591 hg log -r "bisect(pruned)"
592
592
593 - see the changeset currently being bisected (especially useful
593 - see the changeset currently being bisected (especially useful
594 if running with -U/--noupdate)::
594 if running with -U/--noupdate)::
595
595
596 hg log -r "bisect(current)"
596 hg log -r "bisect(current)"
597
597
598 - see all changesets that took part in the current bisection::
598 - see all changesets that took part in the current bisection::
599
599
600 hg log -r "bisect(range)"
600 hg log -r "bisect(range)"
601
601
602 - you can even get a nice graph::
602 - you can even get a nice graph::
603
603
604 hg log --graph -r "bisect(range)"
604 hg log --graph -r "bisect(range)"
605
605
606 See :hg:`help revsets` for more about the `bisect()` keyword.
606 See :hg:`help revsets` for more about the `bisect()` keyword.
607
607
608 Returns 0 on success.
608 Returns 0 on success.
609 """
609 """
610 def extendbisectrange(nodes, good):
610 def extendbisectrange(nodes, good):
611 # bisect is incomplete when it ends on a merge node and
611 # bisect is incomplete when it ends on a merge node and
612 # one of the parent was not checked.
612 # one of the parent was not checked.
613 parents = repo[nodes[0]].parents()
613 parents = repo[nodes[0]].parents()
614 if len(parents) > 1:
614 if len(parents) > 1:
615 side = good and state['bad'] or state['good']
615 side = good and state['bad'] or state['good']
616 num = len(set(i.node() for i in parents) & set(side))
616 num = len(set(i.node() for i in parents) & set(side))
617 if num == 1:
617 if num == 1:
618 return parents[0].ancestor(parents[1])
618 return parents[0].ancestor(parents[1])
619 return None
619 return None
620
620
621 def print_result(nodes, good):
621 def print_result(nodes, good):
622 displayer = cmdutil.show_changeset(ui, repo, {})
622 displayer = cmdutil.show_changeset(ui, repo, {})
623 if len(nodes) == 1:
623 if len(nodes) == 1:
624 # narrowed it down to a single revision
624 # narrowed it down to a single revision
625 if good:
625 if good:
626 ui.write(_("The first good revision is:\n"))
626 ui.write(_("The first good revision is:\n"))
627 else:
627 else:
628 ui.write(_("The first bad revision is:\n"))
628 ui.write(_("The first bad revision is:\n"))
629 displayer.show(repo[nodes[0]])
629 displayer.show(repo[nodes[0]])
630 extendnode = extendbisectrange(nodes, good)
630 extendnode = extendbisectrange(nodes, good)
631 if extendnode is not None:
631 if extendnode is not None:
632 ui.write(_('Not all ancestors of this changeset have been'
632 ui.write(_('Not all ancestors of this changeset have been'
633 ' checked.\nUse bisect --extend to continue the '
633 ' checked.\nUse bisect --extend to continue the '
634 'bisection from\nthe common ancestor, %s.\n')
634 'bisection from\nthe common ancestor, %s.\n')
635 % extendnode)
635 % extendnode)
636 else:
636 else:
637 # multiple possible revisions
637 # multiple possible revisions
638 if good:
638 if good:
639 ui.write(_("Due to skipped revisions, the first "
639 ui.write(_("Due to skipped revisions, the first "
640 "good revision could be any of:\n"))
640 "good revision could be any of:\n"))
641 else:
641 else:
642 ui.write(_("Due to skipped revisions, the first "
642 ui.write(_("Due to skipped revisions, the first "
643 "bad revision could be any of:\n"))
643 "bad revision could be any of:\n"))
644 for n in nodes:
644 for n in nodes:
645 displayer.show(repo[n])
645 displayer.show(repo[n])
646 displayer.close()
646 displayer.close()
647
647
648 def check_state(state, interactive=True):
648 def check_state(state, interactive=True):
649 if not state['good'] or not state['bad']:
649 if not state['good'] or not state['bad']:
650 if (good or bad or skip or reset) and interactive:
650 if (good or bad or skip or reset) and interactive:
651 return
651 return
652 if not state['good']:
652 if not state['good']:
653 raise util.Abort(_('cannot bisect (no known good revisions)'))
653 raise util.Abort(_('cannot bisect (no known good revisions)'))
654 else:
654 else:
655 raise util.Abort(_('cannot bisect (no known bad revisions)'))
655 raise util.Abort(_('cannot bisect (no known bad revisions)'))
656 return True
656 return True
657
657
658 # backward compatibility
658 # backward compatibility
659 if rev in "good bad reset init".split():
659 if rev in "good bad reset init".split():
660 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
660 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
661 cmd, rev, extra = rev, extra, None
661 cmd, rev, extra = rev, extra, None
662 if cmd == "good":
662 if cmd == "good":
663 good = True
663 good = True
664 elif cmd == "bad":
664 elif cmd == "bad":
665 bad = True
665 bad = True
666 else:
666 else:
667 reset = True
667 reset = True
668 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
668 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
669 raise util.Abort(_('incompatible arguments'))
669 raise util.Abort(_('incompatible arguments'))
670
670
671 cmdutil.checkunfinished(repo)
671 cmdutil.checkunfinished(repo)
672
672
673 if reset:
673 if reset:
674 p = repo.join("bisect.state")
674 p = repo.join("bisect.state")
675 if os.path.exists(p):
675 if os.path.exists(p):
676 os.unlink(p)
676 os.unlink(p)
677 return
677 return
678
678
679 state = hbisect.load_state(repo)
679 state = hbisect.load_state(repo)
680
680
681 if command:
681 if command:
682 changesets = 1
682 changesets = 1
683 if noupdate:
683 if noupdate:
684 try:
684 try:
685 node = state['current'][0]
685 node = state['current'][0]
686 except LookupError:
686 except LookupError:
687 raise util.Abort(_('current bisect revision is unknown - '
687 raise util.Abort(_('current bisect revision is unknown - '
688 'start a new bisect to fix'))
688 'start a new bisect to fix'))
689 else:
689 else:
690 node, p2 = repo.dirstate.parents()
690 node, p2 = repo.dirstate.parents()
691 if p2 != nullid:
691 if p2 != nullid:
692 raise util.Abort(_('current bisect revision is a merge'))
692 raise util.Abort(_('current bisect revision is a merge'))
693 try:
693 try:
694 while changesets:
694 while changesets:
695 # update state
695 # update state
696 state['current'] = [node]
696 state['current'] = [node]
697 hbisect.save_state(repo, state)
697 hbisect.save_state(repo, state)
698 status = util.system(command,
698 status = util.system(command,
699 environ={'HG_NODE': hex(node)},
699 environ={'HG_NODE': hex(node)},
700 out=ui.fout)
700 out=ui.fout)
701 if status == 125:
701 if status == 125:
702 transition = "skip"
702 transition = "skip"
703 elif status == 0:
703 elif status == 0:
704 transition = "good"
704 transition = "good"
705 # status < 0 means process was killed
705 # status < 0 means process was killed
706 elif status == 127:
706 elif status == 127:
707 raise util.Abort(_("failed to execute %s") % command)
707 raise util.Abort(_("failed to execute %s") % command)
708 elif status < 0:
708 elif status < 0:
709 raise util.Abort(_("%s killed") % command)
709 raise util.Abort(_("%s killed") % command)
710 else:
710 else:
711 transition = "bad"
711 transition = "bad"
712 ctx = scmutil.revsingle(repo, rev, node)
712 ctx = scmutil.revsingle(repo, rev, node)
713 rev = None # clear for future iterations
713 rev = None # clear for future iterations
714 state[transition].append(ctx.node())
714 state[transition].append(ctx.node())
715 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
715 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
716 check_state(state, interactive=False)
716 check_state(state, interactive=False)
717 # bisect
717 # bisect
718 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
718 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
719 # update to next check
719 # update to next check
720 node = nodes[0]
720 node = nodes[0]
721 if not noupdate:
721 if not noupdate:
722 cmdutil.bailifchanged(repo)
722 cmdutil.bailifchanged(repo)
723 hg.clean(repo, node, show_stats=False)
723 hg.clean(repo, node, show_stats=False)
724 finally:
724 finally:
725 state['current'] = [node]
725 state['current'] = [node]
726 hbisect.save_state(repo, state)
726 hbisect.save_state(repo, state)
727 print_result(nodes, bgood)
727 print_result(nodes, bgood)
728 return
728 return
729
729
730 # update state
730 # update state
731
731
732 if rev:
732 if rev:
733 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
733 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
734 else:
734 else:
735 nodes = [repo.lookup('.')]
735 nodes = [repo.lookup('.')]
736
736
737 if good or bad or skip:
737 if good or bad or skip:
738 if good:
738 if good:
739 state['good'] += nodes
739 state['good'] += nodes
740 elif bad:
740 elif bad:
741 state['bad'] += nodes
741 state['bad'] += nodes
742 elif skip:
742 elif skip:
743 state['skip'] += nodes
743 state['skip'] += nodes
744 hbisect.save_state(repo, state)
744 hbisect.save_state(repo, state)
745
745
746 if not check_state(state):
746 if not check_state(state):
747 return
747 return
748
748
749 # actually bisect
749 # actually bisect
750 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
750 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
751 if extend:
751 if extend:
752 if not changesets:
752 if not changesets:
753 extendnode = extendbisectrange(nodes, good)
753 extendnode = extendbisectrange(nodes, good)
754 if extendnode is not None:
754 if extendnode is not None:
755 ui.write(_("Extending search to changeset %d:%s\n"
755 ui.write(_("Extending search to changeset %d:%s\n"
756 % (extendnode.rev(), extendnode)))
756 % (extendnode.rev(), extendnode)))
757 state['current'] = [extendnode.node()]
757 state['current'] = [extendnode.node()]
758 hbisect.save_state(repo, state)
758 hbisect.save_state(repo, state)
759 if noupdate:
759 if noupdate:
760 return
760 return
761 cmdutil.bailifchanged(repo)
761 cmdutil.bailifchanged(repo)
762 return hg.clean(repo, extendnode.node())
762 return hg.clean(repo, extendnode.node())
763 raise util.Abort(_("nothing to extend"))
763 raise util.Abort(_("nothing to extend"))
764
764
765 if changesets == 0:
765 if changesets == 0:
766 print_result(nodes, good)
766 print_result(nodes, good)
767 else:
767 else:
768 assert len(nodes) == 1 # only a single node can be tested next
768 assert len(nodes) == 1 # only a single node can be tested next
769 node = nodes[0]
769 node = nodes[0]
770 # compute the approximate number of remaining tests
770 # compute the approximate number of remaining tests
771 tests, size = 0, 2
771 tests, size = 0, 2
772 while size <= changesets:
772 while size <= changesets:
773 tests, size = tests + 1, size * 2
773 tests, size = tests + 1, size * 2
774 rev = repo.changelog.rev(node)
774 rev = repo.changelog.rev(node)
775 ui.write(_("Testing changeset %d:%s "
775 ui.write(_("Testing changeset %d:%s "
776 "(%d changesets remaining, ~%d tests)\n")
776 "(%d changesets remaining, ~%d tests)\n")
777 % (rev, short(node), changesets, tests))
777 % (rev, short(node), changesets, tests))
778 state['current'] = [node]
778 state['current'] = [node]
779 hbisect.save_state(repo, state)
779 hbisect.save_state(repo, state)
780 if not noupdate:
780 if not noupdate:
781 cmdutil.bailifchanged(repo)
781 cmdutil.bailifchanged(repo)
782 return hg.clean(repo, node)
782 return hg.clean(repo, node)
783
783
784 @command('bookmarks|bookmark',
784 @command('bookmarks|bookmark',
785 [('f', 'force', False, _('force')),
785 [('f', 'force', False, _('force')),
786 ('r', 'rev', '', _('revision'), _('REV')),
786 ('r', 'rev', '', _('revision'), _('REV')),
787 ('d', 'delete', False, _('delete a given bookmark')),
787 ('d', 'delete', False, _('delete a given bookmark')),
788 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
788 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
789 ('i', 'inactive', False, _('mark a bookmark inactive'))],
789 ('i', 'inactive', False, _('mark a bookmark inactive'))],
790 _('hg bookmarks [OPTIONS]... [NAME]...'))
790 _('hg bookmarks [OPTIONS]... [NAME]...'))
791 def bookmark(ui, repo, *names, **opts):
791 def bookmark(ui, repo, *names, **opts):
792 '''track a line of development with movable markers
792 '''track a line of development with movable markers
793
793
794 Bookmarks are pointers to certain commits that move when committing.
794 Bookmarks are pointers to certain commits that move when committing.
795 Bookmarks are local. They can be renamed, copied and deleted. It is
795 Bookmarks are local. They can be renamed, copied and deleted. It is
796 possible to use :hg:`merge NAME` to merge from a given bookmark, and
796 possible to use :hg:`merge NAME` to merge from a given bookmark, and
797 :hg:`update NAME` to update to a given bookmark.
797 :hg:`update NAME` to update to a given bookmark.
798
798
799 You can use :hg:`bookmark NAME` to set a bookmark on the working
799 You can use :hg:`bookmark NAME` to set a bookmark on the working
800 directory's parent revision with the given name. If you specify
800 directory's parent revision with the given name. If you specify
801 a revision using -r REV (where REV may be an existing bookmark),
801 a revision using -r REV (where REV may be an existing bookmark),
802 the bookmark is assigned to that revision.
802 the bookmark is assigned to that revision.
803
803
804 Bookmarks can be pushed and pulled between repositories (see :hg:`help
804 Bookmarks can be pushed and pulled between repositories (see :hg:`help
805 push` and :hg:`help pull`). This requires both the local and remote
805 push` and :hg:`help pull`). This requires both the local and remote
806 repositories to support bookmarks. For versions prior to 1.8, this means
806 repositories to support bookmarks. For versions prior to 1.8, this means
807 the bookmarks extension must be enabled.
807 the bookmarks extension must be enabled.
808
808
809 If you set a bookmark called '@', new clones of the repository will
809 If you set a bookmark called '@', new clones of the repository will
810 have that revision checked out (and the bookmark made active) by
810 have that revision checked out (and the bookmark made active) by
811 default.
811 default.
812
812
813 With -i/--inactive, the new bookmark will not be made the active
813 With -i/--inactive, the new bookmark will not be made the active
814 bookmark. If -r/--rev is given, the new bookmark will not be made
814 bookmark. If -r/--rev is given, the new bookmark will not be made
815 active even if -i/--inactive is not given. If no NAME is given, the
815 active even if -i/--inactive is not given. If no NAME is given, the
816 current active bookmark will be marked inactive.
816 current active bookmark will be marked inactive.
817 '''
817 '''
818 force = opts.get('force')
818 force = opts.get('force')
819 rev = opts.get('rev')
819 rev = opts.get('rev')
820 delete = opts.get('delete')
820 delete = opts.get('delete')
821 rename = opts.get('rename')
821 rename = opts.get('rename')
822 inactive = opts.get('inactive')
822 inactive = opts.get('inactive')
823
823
824 def checkformat(mark):
824 def checkformat(mark):
825 mark = mark.strip()
825 mark = mark.strip()
826 if not mark:
826 if not mark:
827 raise util.Abort(_("bookmark names cannot consist entirely of "
827 raise util.Abort(_("bookmark names cannot consist entirely of "
828 "whitespace"))
828 "whitespace"))
829 scmutil.checknewlabel(repo, mark, 'bookmark')
829 scmutil.checknewlabel(repo, mark, 'bookmark')
830 return mark
830 return mark
831
831
832 def checkconflict(repo, mark, cur, force=False, target=None):
832 def checkconflict(repo, mark, cur, force=False, target=None):
833 if mark in marks and not force:
833 if mark in marks and not force:
834 if target:
834 if target:
835 if marks[mark] == target and target == cur:
835 if marks[mark] == target and target == cur:
836 # re-activating a bookmark
836 # re-activating a bookmark
837 return
837 return
838 anc = repo.changelog.ancestors([repo[target].rev()])
838 anc = repo.changelog.ancestors([repo[target].rev()])
839 bmctx = repo[marks[mark]]
839 bmctx = repo[marks[mark]]
840 divs = [repo[b].node() for b in marks
840 divs = [repo[b].node() for b in marks
841 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
841 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
842
842
843 # allow resolving a single divergent bookmark even if moving
843 # allow resolving a single divergent bookmark even if moving
844 # the bookmark across branches when a revision is specified
844 # the bookmark across branches when a revision is specified
845 # that contains a divergent bookmark
845 # that contains a divergent bookmark
846 if bmctx.rev() not in anc and target in divs:
846 if bmctx.rev() not in anc and target in divs:
847 bookmarks.deletedivergent(repo, [target], mark)
847 bookmarks.deletedivergent(repo, [target], mark)
848 return
848 return
849
849
850 deletefrom = [b for b in divs
850 deletefrom = [b for b in divs
851 if repo[b].rev() in anc or b == target]
851 if repo[b].rev() in anc or b == target]
852 bookmarks.deletedivergent(repo, deletefrom, mark)
852 bookmarks.deletedivergent(repo, deletefrom, mark)
853 if bookmarks.validdest(repo, bmctx, repo[target]):
853 if bookmarks.validdest(repo, bmctx, repo[target]):
854 ui.status(_("moving bookmark '%s' forward from %s\n") %
854 ui.status(_("moving bookmark '%s' forward from %s\n") %
855 (mark, short(bmctx.node())))
855 (mark, short(bmctx.node())))
856 return
856 return
857 raise util.Abort(_("bookmark '%s' already exists "
857 raise util.Abort(_("bookmark '%s' already exists "
858 "(use -f to force)") % mark)
858 "(use -f to force)") % mark)
859 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
859 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
860 and not force):
860 and not force):
861 raise util.Abort(
861 raise util.Abort(
862 _("a bookmark cannot have the name of an existing branch"))
862 _("a bookmark cannot have the name of an existing branch"))
863
863
864 if delete and rename:
864 if delete and rename:
865 raise util.Abort(_("--delete and --rename are incompatible"))
865 raise util.Abort(_("--delete and --rename are incompatible"))
866 if delete and rev:
866 if delete and rev:
867 raise util.Abort(_("--rev is incompatible with --delete"))
867 raise util.Abort(_("--rev is incompatible with --delete"))
868 if rename and rev:
868 if rename and rev:
869 raise util.Abort(_("--rev is incompatible with --rename"))
869 raise util.Abort(_("--rev is incompatible with --rename"))
870 if not names and (delete or rev):
870 if not names and (delete or rev):
871 raise util.Abort(_("bookmark name required"))
871 raise util.Abort(_("bookmark name required"))
872
872
873 if delete or rename or names or inactive:
873 if delete or rename or names or inactive:
874 wlock = repo.wlock()
874 wlock = repo.wlock()
875 try:
875 try:
876 cur = repo.changectx('.').node()
876 cur = repo.changectx('.').node()
877 marks = repo._bookmarks
877 marks = repo._bookmarks
878 if delete:
878 if delete:
879 for mark in names:
879 for mark in names:
880 if mark not in marks:
880 if mark not in marks:
881 raise util.Abort(_("bookmark '%s' does not exist") %
881 raise util.Abort(_("bookmark '%s' does not exist") %
882 mark)
882 mark)
883 if mark == repo._bookmarkcurrent:
883 if mark == repo._bookmarkcurrent:
884 bookmarks.unsetcurrent(repo)
884 bookmarks.unsetcurrent(repo)
885 del marks[mark]
885 del marks[mark]
886 marks.write()
886 marks.write()
887
887
888 elif rename:
888 elif rename:
889 if not names:
889 if not names:
890 raise util.Abort(_("new bookmark name required"))
890 raise util.Abort(_("new bookmark name required"))
891 elif len(names) > 1:
891 elif len(names) > 1:
892 raise util.Abort(_("only one new bookmark name allowed"))
892 raise util.Abort(_("only one new bookmark name allowed"))
893 mark = checkformat(names[0])
893 mark = checkformat(names[0])
894 if rename not in marks:
894 if rename not in marks:
895 raise util.Abort(_("bookmark '%s' does not exist") % rename)
895 raise util.Abort(_("bookmark '%s' does not exist") % rename)
896 checkconflict(repo, mark, cur, force)
896 checkconflict(repo, mark, cur, force)
897 marks[mark] = marks[rename]
897 marks[mark] = marks[rename]
898 if repo._bookmarkcurrent == rename and not inactive:
898 if repo._bookmarkcurrent == rename and not inactive:
899 bookmarks.setcurrent(repo, mark)
899 bookmarks.setcurrent(repo, mark)
900 del marks[rename]
900 del marks[rename]
901 marks.write()
901 marks.write()
902
902
903 elif names:
903 elif names:
904 newact = None
904 newact = None
905 for mark in names:
905 for mark in names:
906 mark = checkformat(mark)
906 mark = checkformat(mark)
907 if newact is None:
907 if newact is None:
908 newact = mark
908 newact = mark
909 if inactive and mark == repo._bookmarkcurrent:
909 if inactive and mark == repo._bookmarkcurrent:
910 bookmarks.unsetcurrent(repo)
910 bookmarks.unsetcurrent(repo)
911 return
911 return
912 tgt = cur
912 tgt = cur
913 if rev:
913 if rev:
914 tgt = scmutil.revsingle(repo, rev).node()
914 tgt = scmutil.revsingle(repo, rev).node()
915 checkconflict(repo, mark, cur, force, tgt)
915 checkconflict(repo, mark, cur, force, tgt)
916 marks[mark] = tgt
916 marks[mark] = tgt
917 if not inactive and cur == marks[newact] and not rev:
917 if not inactive and cur == marks[newact] and not rev:
918 bookmarks.setcurrent(repo, newact)
918 bookmarks.setcurrent(repo, newact)
919 elif cur != tgt and newact == repo._bookmarkcurrent:
919 elif cur != tgt and newact == repo._bookmarkcurrent:
920 bookmarks.unsetcurrent(repo)
920 bookmarks.unsetcurrent(repo)
921 marks.write()
921 marks.write()
922
922
923 elif inactive:
923 elif inactive:
924 if len(marks) == 0:
924 if len(marks) == 0:
925 ui.status(_("no bookmarks set\n"))
925 ui.status(_("no bookmarks set\n"))
926 elif not repo._bookmarkcurrent:
926 elif not repo._bookmarkcurrent:
927 ui.status(_("no active bookmark\n"))
927 ui.status(_("no active bookmark\n"))
928 else:
928 else:
929 bookmarks.unsetcurrent(repo)
929 bookmarks.unsetcurrent(repo)
930 finally:
930 finally:
931 wlock.release()
931 wlock.release()
932 else: # show bookmarks
932 else: # show bookmarks
933 hexfn = ui.debugflag and hex or short
933 hexfn = ui.debugflag and hex or short
934 marks = repo._bookmarks
934 marks = repo._bookmarks
935 if len(marks) == 0:
935 if len(marks) == 0:
936 ui.status(_("no bookmarks set\n"))
936 ui.status(_("no bookmarks set\n"))
937 else:
937 else:
938 for bmark, n in sorted(marks.iteritems()):
938 for bmark, n in sorted(marks.iteritems()):
939 current = repo._bookmarkcurrent
939 current = repo._bookmarkcurrent
940 if bmark == current:
940 if bmark == current:
941 prefix, label = '*', 'bookmarks.current'
941 prefix, label = '*', 'bookmarks.current'
942 else:
942 else:
943 prefix, label = ' ', ''
943 prefix, label = ' ', ''
944
944
945 if ui.quiet:
945 if ui.quiet:
946 ui.write("%s\n" % bmark, label=label)
946 ui.write("%s\n" % bmark, label=label)
947 else:
947 else:
948 ui.write(" %s %-25s %d:%s\n" % (
948 ui.write(" %s %-25s %d:%s\n" % (
949 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
949 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
950 label=label)
950 label=label)
951
951
952 @command('branch',
952 @command('branch',
953 [('f', 'force', None,
953 [('f', 'force', None,
954 _('set branch name even if it shadows an existing branch')),
954 _('set branch name even if it shadows an existing branch')),
955 ('C', 'clean', None, _('reset branch name to parent branch name'))],
955 ('C', 'clean', None, _('reset branch name to parent branch name'))],
956 _('[-fC] [NAME]'))
956 _('[-fC] [NAME]'))
957 def branch(ui, repo, label=None, **opts):
957 def branch(ui, repo, label=None, **opts):
958 """set or show the current branch name
958 """set or show the current branch name
959
959
960 .. note::
960 .. note::
961
961
962 Branch names are permanent and global. Use :hg:`bookmark` to create a
962 Branch names are permanent and global. Use :hg:`bookmark` to create a
963 light-weight bookmark instead. See :hg:`help glossary` for more
963 light-weight bookmark instead. See :hg:`help glossary` for more
964 information about named branches and bookmarks.
964 information about named branches and bookmarks.
965
965
966 With no argument, show the current branch name. With one argument,
966 With no argument, show the current branch name. With one argument,
967 set the working directory branch name (the branch will not exist
967 set the working directory branch name (the branch will not exist
968 in the repository until the next commit). Standard practice
968 in the repository until the next commit). Standard practice
969 recommends that primary development take place on the 'default'
969 recommends that primary development take place on the 'default'
970 branch.
970 branch.
971
971
972 Unless -f/--force is specified, branch will not let you set a
972 Unless -f/--force is specified, branch will not let you set a
973 branch name that already exists, even if it's inactive.
973 branch name that already exists, even if it's inactive.
974
974
975 Use -C/--clean to reset the working directory branch to that of
975 Use -C/--clean to reset the working directory branch to that of
976 the parent of the working directory, negating a previous branch
976 the parent of the working directory, negating a previous branch
977 change.
977 change.
978
978
979 Use the command :hg:`update` to switch to an existing branch. Use
979 Use the command :hg:`update` to switch to an existing branch. Use
980 :hg:`commit --close-branch` to mark this branch as closed.
980 :hg:`commit --close-branch` to mark this branch as closed.
981
981
982 Returns 0 on success.
982 Returns 0 on success.
983 """
983 """
984 if label:
984 if label:
985 label = label.strip()
985 label = label.strip()
986
986
987 if not opts.get('clean') and not label:
987 if not opts.get('clean') and not label:
988 ui.write("%s\n" % repo.dirstate.branch())
988 ui.write("%s\n" % repo.dirstate.branch())
989 return
989 return
990
990
991 wlock = repo.wlock()
991 wlock = repo.wlock()
992 try:
992 try:
993 if opts.get('clean'):
993 if opts.get('clean'):
994 label = repo[None].p1().branch()
994 label = repo[None].p1().branch()
995 repo.dirstate.setbranch(label)
995 repo.dirstate.setbranch(label)
996 ui.status(_('reset working directory to branch %s\n') % label)
996 ui.status(_('reset working directory to branch %s\n') % label)
997 elif label:
997 elif label:
998 if not opts.get('force') and label in repo.branchmap():
998 if not opts.get('force') and label in repo.branchmap():
999 if label not in [p.branch() for p in repo.parents()]:
999 if label not in [p.branch() for p in repo.parents()]:
1000 raise util.Abort(_('a branch of the same name already'
1000 raise util.Abort(_('a branch of the same name already'
1001 ' exists'),
1001 ' exists'),
1002 # i18n: "it" refers to an existing branch
1002 # i18n: "it" refers to an existing branch
1003 hint=_("use 'hg update' to switch to it"))
1003 hint=_("use 'hg update' to switch to it"))
1004 scmutil.checknewlabel(repo, label, 'branch')
1004 scmutil.checknewlabel(repo, label, 'branch')
1005 repo.dirstate.setbranch(label)
1005 repo.dirstate.setbranch(label)
1006 ui.status(_('marked working directory as branch %s\n') % label)
1006 ui.status(_('marked working directory as branch %s\n') % label)
1007 ui.status(_('(branches are permanent and global, '
1007 ui.status(_('(branches are permanent and global, '
1008 'did you want a bookmark?)\n'))
1008 'did you want a bookmark?)\n'))
1009 finally:
1009 finally:
1010 wlock.release()
1010 wlock.release()
1011
1011
1012 @command('branches',
1012 @command('branches',
1013 [('a', 'active', False, _('show only branches that have unmerged heads')),
1013 [('a', 'active', False, _('show only branches that have unmerged heads')),
1014 ('c', 'closed', False, _('show normal and closed branches'))],
1014 ('c', 'closed', False, _('show normal and closed branches'))],
1015 _('[-ac]'))
1015 _('[-ac]'))
1016 def branches(ui, repo, active=False, closed=False):
1016 def branches(ui, repo, active=False, closed=False):
1017 """list repository named branches
1017 """list repository named branches
1018
1018
1019 List the repository's named branches, indicating which ones are
1019 List the repository's named branches, indicating which ones are
1020 inactive. If -c/--closed is specified, also list branches which have
1020 inactive. If -c/--closed is specified, also list branches which have
1021 been marked closed (see :hg:`commit --close-branch`).
1021 been marked closed (see :hg:`commit --close-branch`).
1022
1022
1023 If -a/--active is specified, only show active branches. A branch
1023 If -a/--active is specified, only show active branches. A branch
1024 is considered active if it contains repository heads.
1024 is considered active if it contains repository heads.
1025
1025
1026 Use the command :hg:`update` to switch to an existing branch.
1026 Use the command :hg:`update` to switch to an existing branch.
1027
1027
1028 Returns 0.
1028 Returns 0.
1029 """
1029 """
1030
1030
1031 hexfunc = ui.debugflag and hex or short
1031 hexfunc = ui.debugflag and hex or short
1032
1032
1033 allheads = set(repo.heads())
1033 allheads = set(repo.heads())
1034 branches = []
1034 branches = []
1035 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1035 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1036 isactive = not isclosed and bool(set(heads) & allheads)
1036 isactive = not isclosed and bool(set(heads) & allheads)
1037 branches.append((tag, repo[tip], isactive, not isclosed))
1037 branches.append((tag, repo[tip], isactive, not isclosed))
1038 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1038 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1039 reverse=True)
1039 reverse=True)
1040
1040
1041 for tag, ctx, isactive, isopen in branches:
1041 for tag, ctx, isactive, isopen in branches:
1042 if (not active) or isactive:
1042 if (not active) or isactive:
1043 if isactive:
1043 if isactive:
1044 label = 'branches.active'
1044 label = 'branches.active'
1045 notice = ''
1045 notice = ''
1046 elif not isopen:
1046 elif not isopen:
1047 if not closed:
1047 if not closed:
1048 continue
1048 continue
1049 label = 'branches.closed'
1049 label = 'branches.closed'
1050 notice = _(' (closed)')
1050 notice = _(' (closed)')
1051 else:
1051 else:
1052 label = 'branches.inactive'
1052 label = 'branches.inactive'
1053 notice = _(' (inactive)')
1053 notice = _(' (inactive)')
1054 if tag == repo.dirstate.branch():
1054 if tag == repo.dirstate.branch():
1055 label = 'branches.current'
1055 label = 'branches.current'
1056 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(tag))
1056 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(tag))
1057 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1057 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1058 'log.changeset changeset.%s' % ctx.phasestr())
1058 'log.changeset changeset.%s' % ctx.phasestr())
1059 labeledtag = ui.label(tag, label)
1059 labeledtag = ui.label(tag, label)
1060 if ui.quiet:
1060 if ui.quiet:
1061 ui.write("%s\n" % labeledtag)
1061 ui.write("%s\n" % labeledtag)
1062 else:
1062 else:
1063 ui.write("%s %s%s\n" % (labeledtag, rev, notice))
1063 ui.write("%s %s%s\n" % (labeledtag, rev, notice))
1064
1064
1065 @command('bundle',
1065 @command('bundle',
1066 [('f', 'force', None, _('run even when the destination is unrelated')),
1066 [('f', 'force', None, _('run even when the destination is unrelated')),
1067 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1067 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1068 _('REV')),
1068 _('REV')),
1069 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1069 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1070 _('BRANCH')),
1070 _('BRANCH')),
1071 ('', 'base', [],
1071 ('', 'base', [],
1072 _('a base changeset assumed to be available at the destination'),
1072 _('a base changeset assumed to be available at the destination'),
1073 _('REV')),
1073 _('REV')),
1074 ('a', 'all', None, _('bundle all changesets in the repository')),
1074 ('a', 'all', None, _('bundle all changesets in the repository')),
1075 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1075 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1076 ] + remoteopts,
1076 ] + remoteopts,
1077 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1077 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1078 def bundle(ui, repo, fname, dest=None, **opts):
1078 def bundle(ui, repo, fname, dest=None, **opts):
1079 """create a changegroup file
1079 """create a changegroup file
1080
1080
1081 Generate a compressed changegroup file collecting changesets not
1081 Generate a compressed changegroup file collecting changesets not
1082 known to be in another repository.
1082 known to be in another repository.
1083
1083
1084 If you omit the destination repository, then hg assumes the
1084 If you omit the destination repository, then hg assumes the
1085 destination will have all the nodes you specify with --base
1085 destination will have all the nodes you specify with --base
1086 parameters. To create a bundle containing all changesets, use
1086 parameters. To create a bundle containing all changesets, use
1087 -a/--all (or --base null).
1087 -a/--all (or --base null).
1088
1088
1089 You can change compression method with the -t/--type option.
1089 You can change compression method with the -t/--type option.
1090 The available compression methods are: none, bzip2, and
1090 The available compression methods are: none, bzip2, and
1091 gzip (by default, bundles are compressed using bzip2).
1091 gzip (by default, bundles are compressed using bzip2).
1092
1092
1093 The bundle file can then be transferred using conventional means
1093 The bundle file can then be transferred using conventional means
1094 and applied to another repository with the unbundle or pull
1094 and applied to another repository with the unbundle or pull
1095 command. This is useful when direct push and pull are not
1095 command. This is useful when direct push and pull are not
1096 available or when exporting an entire repository is undesirable.
1096 available or when exporting an entire repository is undesirable.
1097
1097
1098 Applying bundles preserves all changeset contents including
1098 Applying bundles preserves all changeset contents including
1099 permissions, copy/rename information, and revision history.
1099 permissions, copy/rename information, and revision history.
1100
1100
1101 Returns 0 on success, 1 if no changes found.
1101 Returns 0 on success, 1 if no changes found.
1102 """
1102 """
1103 revs = None
1103 revs = None
1104 if 'rev' in opts:
1104 if 'rev' in opts:
1105 revs = scmutil.revrange(repo, opts['rev'])
1105 revs = scmutil.revrange(repo, opts['rev'])
1106
1106
1107 bundletype = opts.get('type', 'bzip2').lower()
1107 bundletype = opts.get('type', 'bzip2').lower()
1108 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1108 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1109 bundletype = btypes.get(bundletype)
1109 bundletype = btypes.get(bundletype)
1110 if bundletype not in changegroup.bundletypes:
1110 if bundletype not in changegroup.bundletypes:
1111 raise util.Abort(_('unknown bundle type specified with --type'))
1111 raise util.Abort(_('unknown bundle type specified with --type'))
1112
1112
1113 if opts.get('all'):
1113 if opts.get('all'):
1114 base = ['null']
1114 base = ['null']
1115 else:
1115 else:
1116 base = scmutil.revrange(repo, opts.get('base'))
1116 base = scmutil.revrange(repo, opts.get('base'))
1117 # TODO: get desired bundlecaps from command line.
1117 # TODO: get desired bundlecaps from command line.
1118 bundlecaps = None
1118 bundlecaps = None
1119 if base:
1119 if base:
1120 if dest:
1120 if dest:
1121 raise util.Abort(_("--base is incompatible with specifying "
1121 raise util.Abort(_("--base is incompatible with specifying "
1122 "a destination"))
1122 "a destination"))
1123 common = [repo.lookup(rev) for rev in base]
1123 common = [repo.lookup(rev) for rev in base]
1124 heads = revs and map(repo.lookup, revs) or revs
1124 heads = revs and map(repo.lookup, revs) or revs
1125 cg = repo.getbundle('bundle', heads=heads, common=common,
1125 cg = repo.getbundle('bundle', heads=heads, common=common,
1126 bundlecaps=bundlecaps)
1126 bundlecaps=bundlecaps)
1127 outgoing = None
1127 outgoing = None
1128 else:
1128 else:
1129 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1129 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1130 dest, branches = hg.parseurl(dest, opts.get('branch'))
1130 dest, branches = hg.parseurl(dest, opts.get('branch'))
1131 other = hg.peer(repo, opts, dest)
1131 other = hg.peer(repo, opts, dest)
1132 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1132 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1133 heads = revs and map(repo.lookup, revs) or revs
1133 heads = revs and map(repo.lookup, revs) or revs
1134 outgoing = discovery.findcommonoutgoing(repo, other,
1134 outgoing = discovery.findcommonoutgoing(repo, other,
1135 onlyheads=heads,
1135 onlyheads=heads,
1136 force=opts.get('force'),
1136 force=opts.get('force'),
1137 portable=True)
1137 portable=True)
1138 cg = repo.getlocalbundle('bundle', outgoing, bundlecaps)
1138 cg = repo.getlocalbundle('bundle', outgoing, bundlecaps)
1139 if not cg:
1139 if not cg:
1140 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1140 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1141 return 1
1141 return 1
1142
1142
1143 changegroup.writebundle(cg, fname, bundletype)
1143 changegroup.writebundle(cg, fname, bundletype)
1144
1144
1145 @command('cat',
1145 @command('cat',
1146 [('o', 'output', '',
1146 [('o', 'output', '',
1147 _('print output to file with formatted name'), _('FORMAT')),
1147 _('print output to file with formatted name'), _('FORMAT')),
1148 ('r', 'rev', '', _('print the given revision'), _('REV')),
1148 ('r', 'rev', '', _('print the given revision'), _('REV')),
1149 ('', 'decode', None, _('apply any matching decode filter')),
1149 ('', 'decode', None, _('apply any matching decode filter')),
1150 ] + walkopts,
1150 ] + walkopts,
1151 _('[OPTION]... FILE...'))
1151 _('[OPTION]... FILE...'))
1152 def cat(ui, repo, file1, *pats, **opts):
1152 def cat(ui, repo, file1, *pats, **opts):
1153 """output the current or given revision of files
1153 """output the current or given revision of files
1154
1154
1155 Print the specified files as they were at the given revision. If
1155 Print the specified files as they were at the given revision. If
1156 no revision is given, the parent of the working directory is used.
1156 no revision is given, the parent of the working directory is used.
1157
1157
1158 Output may be to a file, in which case the name of the file is
1158 Output may be to a file, in which case the name of the file is
1159 given using a format string. The formatting rules are the same as
1159 given using a format string. The formatting rules are the same as
1160 for the export command, with the following additions:
1160 for the export command, with the following additions:
1161
1161
1162 :``%s``: basename of file being printed
1162 :``%s``: basename of file being printed
1163 :``%d``: dirname of file being printed, or '.' if in repository root
1163 :``%d``: dirname of file being printed, or '.' if in repository root
1164 :``%p``: root-relative path name of file being printed
1164 :``%p``: root-relative path name of file being printed
1165
1165
1166 Returns 0 on success.
1166 Returns 0 on success.
1167 """
1167 """
1168 ctx = scmutil.revsingle(repo, opts.get('rev'))
1168 ctx = scmutil.revsingle(repo, opts.get('rev'))
1169 err = 1
1169 err = 1
1170 m = scmutil.match(ctx, (file1,) + pats, opts)
1170 m = scmutil.match(ctx, (file1,) + pats, opts)
1171
1171
1172 def write(path):
1172 def write(path):
1173 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1173 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1174 pathname=path)
1174 pathname=path)
1175 data = ctx[path].data()
1175 data = ctx[path].data()
1176 if opts.get('decode'):
1176 if opts.get('decode'):
1177 data = repo.wwritedata(path, data)
1177 data = repo.wwritedata(path, data)
1178 fp.write(data)
1178 fp.write(data)
1179 fp.close()
1179 fp.close()
1180
1180
1181 # Automation often uses hg cat on single files, so special case it
1181 # Automation often uses hg cat on single files, so special case it
1182 # for performance to avoid the cost of parsing the manifest.
1182 # for performance to avoid the cost of parsing the manifest.
1183 if len(m.files()) == 1 and not m.anypats():
1183 if len(m.files()) == 1 and not m.anypats():
1184 file = m.files()[0]
1184 file = m.files()[0]
1185 mf = repo.manifest
1185 mf = repo.manifest
1186 mfnode = ctx._changeset[0]
1186 mfnode = ctx._changeset[0]
1187 if mf.find(mfnode, file)[0]:
1187 if mf.find(mfnode, file)[0]:
1188 write(file)
1188 write(file)
1189 return 0
1189 return 0
1190
1190
1191 for abs in ctx.walk(m):
1191 for abs in ctx.walk(m):
1192 write(abs)
1192 write(abs)
1193 err = 0
1193 err = 0
1194 return err
1194 return err
1195
1195
1196 @command('^clone',
1196 @command('^clone',
1197 [('U', 'noupdate', None,
1197 [('U', 'noupdate', None,
1198 _('the clone will include an empty working copy (only a repository)')),
1198 _('the clone will include an empty working copy (only a repository)')),
1199 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1199 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1200 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1200 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1201 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1201 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1202 ('', 'pull', None, _('use pull protocol to copy metadata')),
1202 ('', 'pull', None, _('use pull protocol to copy metadata')),
1203 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1203 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1204 ] + remoteopts,
1204 ] + remoteopts,
1205 _('[OPTION]... SOURCE [DEST]'))
1205 _('[OPTION]... SOURCE [DEST]'))
1206 def clone(ui, source, dest=None, **opts):
1206 def clone(ui, source, dest=None, **opts):
1207 """make a copy of an existing repository
1207 """make a copy of an existing repository
1208
1208
1209 Create a copy of an existing repository in a new directory.
1209 Create a copy of an existing repository in a new directory.
1210
1210
1211 If no destination directory name is specified, it defaults to the
1211 If no destination directory name is specified, it defaults to the
1212 basename of the source.
1212 basename of the source.
1213
1213
1214 The location of the source is added to the new repository's
1214 The location of the source is added to the new repository's
1215 ``.hg/hgrc`` file, as the default to be used for future pulls.
1215 ``.hg/hgrc`` file, as the default to be used for future pulls.
1216
1216
1217 Only local paths and ``ssh://`` URLs are supported as
1217 Only local paths and ``ssh://`` URLs are supported as
1218 destinations. For ``ssh://`` destinations, no working directory or
1218 destinations. For ``ssh://`` destinations, no working directory or
1219 ``.hg/hgrc`` will be created on the remote side.
1219 ``.hg/hgrc`` will be created on the remote side.
1220
1220
1221 To pull only a subset of changesets, specify one or more revisions
1221 To pull only a subset of changesets, specify one or more revisions
1222 identifiers with -r/--rev or branches with -b/--branch. The
1222 identifiers with -r/--rev or branches with -b/--branch. The
1223 resulting clone will contain only the specified changesets and
1223 resulting clone will contain only the specified changesets and
1224 their ancestors. These options (or 'clone src#rev dest') imply
1224 their ancestors. These options (or 'clone src#rev dest') imply
1225 --pull, even for local source repositories. Note that specifying a
1225 --pull, even for local source repositories. Note that specifying a
1226 tag will include the tagged changeset but not the changeset
1226 tag will include the tagged changeset but not the changeset
1227 containing the tag.
1227 containing the tag.
1228
1228
1229 If the source repository has a bookmark called '@' set, that
1229 If the source repository has a bookmark called '@' set, that
1230 revision will be checked out in the new repository by default.
1230 revision will be checked out in the new repository by default.
1231
1231
1232 To check out a particular version, use -u/--update, or
1232 To check out a particular version, use -u/--update, or
1233 -U/--noupdate to create a clone with no working directory.
1233 -U/--noupdate to create a clone with no working directory.
1234
1234
1235 .. container:: verbose
1235 .. container:: verbose
1236
1236
1237 For efficiency, hardlinks are used for cloning whenever the
1237 For efficiency, hardlinks are used for cloning whenever the
1238 source and destination are on the same filesystem (note this
1238 source and destination are on the same filesystem (note this
1239 applies only to the repository data, not to the working
1239 applies only to the repository data, not to the working
1240 directory). Some filesystems, such as AFS, implement hardlinking
1240 directory). Some filesystems, such as AFS, implement hardlinking
1241 incorrectly, but do not report errors. In these cases, use the
1241 incorrectly, but do not report errors. In these cases, use the
1242 --pull option to avoid hardlinking.
1242 --pull option to avoid hardlinking.
1243
1243
1244 In some cases, you can clone repositories and the working
1244 In some cases, you can clone repositories and the working
1245 directory using full hardlinks with ::
1245 directory using full hardlinks with ::
1246
1246
1247 $ cp -al REPO REPOCLONE
1247 $ cp -al REPO REPOCLONE
1248
1248
1249 This is the fastest way to clone, but it is not always safe. The
1249 This is the fastest way to clone, but it is not always safe. The
1250 operation is not atomic (making sure REPO is not modified during
1250 operation is not atomic (making sure REPO is not modified during
1251 the operation is up to you) and you have to make sure your
1251 the operation is up to you) and you have to make sure your
1252 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1252 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1253 so). Also, this is not compatible with certain extensions that
1253 so). Also, this is not compatible with certain extensions that
1254 place their metadata under the .hg directory, such as mq.
1254 place their metadata under the .hg directory, such as mq.
1255
1255
1256 Mercurial will update the working directory to the first applicable
1256 Mercurial will update the working directory to the first applicable
1257 revision from this list:
1257 revision from this list:
1258
1258
1259 a) null if -U or the source repository has no changesets
1259 a) null if -U or the source repository has no changesets
1260 b) if -u . and the source repository is local, the first parent of
1260 b) if -u . and the source repository is local, the first parent of
1261 the source repository's working directory
1261 the source repository's working directory
1262 c) the changeset specified with -u (if a branch name, this means the
1262 c) the changeset specified with -u (if a branch name, this means the
1263 latest head of that branch)
1263 latest head of that branch)
1264 d) the changeset specified with -r
1264 d) the changeset specified with -r
1265 e) the tipmost head specified with -b
1265 e) the tipmost head specified with -b
1266 f) the tipmost head specified with the url#branch source syntax
1266 f) the tipmost head specified with the url#branch source syntax
1267 g) the revision marked with the '@' bookmark, if present
1267 g) the revision marked with the '@' bookmark, if present
1268 h) the tipmost head of the default branch
1268 h) the tipmost head of the default branch
1269 i) tip
1269 i) tip
1270
1270
1271 Examples:
1271 Examples:
1272
1272
1273 - clone a remote repository to a new directory named hg/::
1273 - clone a remote repository to a new directory named hg/::
1274
1274
1275 hg clone http://selenic.com/hg
1275 hg clone http://selenic.com/hg
1276
1276
1277 - create a lightweight local clone::
1277 - create a lightweight local clone::
1278
1278
1279 hg clone project/ project-feature/
1279 hg clone project/ project-feature/
1280
1280
1281 - clone from an absolute path on an ssh server (note double-slash)::
1281 - clone from an absolute path on an ssh server (note double-slash)::
1282
1282
1283 hg clone ssh://user@server//home/projects/alpha/
1283 hg clone ssh://user@server//home/projects/alpha/
1284
1284
1285 - do a high-speed clone over a LAN while checking out a
1285 - do a high-speed clone over a LAN while checking out a
1286 specified version::
1286 specified version::
1287
1287
1288 hg clone --uncompressed http://server/repo -u 1.5
1288 hg clone --uncompressed http://server/repo -u 1.5
1289
1289
1290 - create a repository without changesets after a particular revision::
1290 - create a repository without changesets after a particular revision::
1291
1291
1292 hg clone -r 04e544 experimental/ good/
1292 hg clone -r 04e544 experimental/ good/
1293
1293
1294 - clone (and track) a particular named branch::
1294 - clone (and track) a particular named branch::
1295
1295
1296 hg clone http://selenic.com/hg#stable
1296 hg clone http://selenic.com/hg#stable
1297
1297
1298 See :hg:`help urls` for details on specifying URLs.
1298 See :hg:`help urls` for details on specifying URLs.
1299
1299
1300 Returns 0 on success.
1300 Returns 0 on success.
1301 """
1301 """
1302 if opts.get('noupdate') and opts.get('updaterev'):
1302 if opts.get('noupdate') and opts.get('updaterev'):
1303 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1303 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1304
1304
1305 r = hg.clone(ui, opts, source, dest,
1305 r = hg.clone(ui, opts, source, dest,
1306 pull=opts.get('pull'),
1306 pull=opts.get('pull'),
1307 stream=opts.get('uncompressed'),
1307 stream=opts.get('uncompressed'),
1308 rev=opts.get('rev'),
1308 rev=opts.get('rev'),
1309 update=opts.get('updaterev') or not opts.get('noupdate'),
1309 update=opts.get('updaterev') or not opts.get('noupdate'),
1310 branch=opts.get('branch'))
1310 branch=opts.get('branch'))
1311
1311
1312 return r is None
1312 return r is None
1313
1313
1314 @command('^commit|ci',
1314 @command('^commit|ci',
1315 [('A', 'addremove', None,
1315 [('A', 'addremove', None,
1316 _('mark new/missing files as added/removed before committing')),
1316 _('mark new/missing files as added/removed before committing')),
1317 ('', 'close-branch', None,
1317 ('', 'close-branch', None,
1318 _('mark a branch as closed, hiding it from the branch list')),
1318 _('mark a branch as closed, hiding it from the branch list')),
1319 ('', 'amend', None, _('amend the parent of the working dir')),
1319 ('', 'amend', None, _('amend the parent of the working dir')),
1320 ('s', 'secret', None, _('use the secret phase for committing')),
1320 ('s', 'secret', None, _('use the secret phase for committing')),
1321 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1321 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1322 _('[OPTION]... [FILE]...'))
1322 _('[OPTION]... [FILE]...'))
1323 def commit(ui, repo, *pats, **opts):
1323 def commit(ui, repo, *pats, **opts):
1324 """commit the specified files or all outstanding changes
1324 """commit the specified files or all outstanding changes
1325
1325
1326 Commit changes to the given files into the repository. Unlike a
1326 Commit changes to the given files into the repository. Unlike a
1327 centralized SCM, this operation is a local operation. See
1327 centralized SCM, this operation is a local operation. See
1328 :hg:`push` for a way to actively distribute your changes.
1328 :hg:`push` for a way to actively distribute your changes.
1329
1329
1330 If a list of files is omitted, all changes reported by :hg:`status`
1330 If a list of files is omitted, all changes reported by :hg:`status`
1331 will be committed.
1331 will be committed.
1332
1332
1333 If you are committing the result of a merge, do not provide any
1333 If you are committing the result of a merge, do not provide any
1334 filenames or -I/-X filters.
1334 filenames or -I/-X filters.
1335
1335
1336 If no commit message is specified, Mercurial starts your
1336 If no commit message is specified, Mercurial starts your
1337 configured editor where you can enter a message. In case your
1337 configured editor where you can enter a message. In case your
1338 commit fails, you will find a backup of your message in
1338 commit fails, you will find a backup of your message in
1339 ``.hg/last-message.txt``.
1339 ``.hg/last-message.txt``.
1340
1340
1341 The --amend flag can be used to amend the parent of the
1341 The --amend flag can be used to amend the parent of the
1342 working directory with a new commit that contains the changes
1342 working directory with a new commit that contains the changes
1343 in the parent in addition to those currently reported by :hg:`status`,
1343 in the parent in addition to those currently reported by :hg:`status`,
1344 if there are any. The old commit is stored in a backup bundle in
1344 if there are any. The old commit is stored in a backup bundle in
1345 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1345 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1346 on how to restore it).
1346 on how to restore it).
1347
1347
1348 Message, user and date are taken from the amended commit unless
1348 Message, user and date are taken from the amended commit unless
1349 specified. When a message isn't specified on the command line,
1349 specified. When a message isn't specified on the command line,
1350 the editor will open with the message of the amended commit.
1350 the editor will open with the message of the amended commit.
1351
1351
1352 It is not possible to amend public changesets (see :hg:`help phases`)
1352 It is not possible to amend public changesets (see :hg:`help phases`)
1353 or changesets that have children.
1353 or changesets that have children.
1354
1354
1355 See :hg:`help dates` for a list of formats valid for -d/--date.
1355 See :hg:`help dates` for a list of formats valid for -d/--date.
1356
1356
1357 Returns 0 on success, 1 if nothing changed.
1357 Returns 0 on success, 1 if nothing changed.
1358 """
1358 """
1359 if opts.get('subrepos'):
1359 if opts.get('subrepos'):
1360 if opts.get('amend'):
1360 if opts.get('amend'):
1361 raise util.Abort(_('cannot amend with --subrepos'))
1361 raise util.Abort(_('cannot amend with --subrepos'))
1362 # Let --subrepos on the command line override config setting.
1362 # Let --subrepos on the command line override config setting.
1363 ui.setconfig('ui', 'commitsubrepos', True)
1363 ui.setconfig('ui', 'commitsubrepos', True)
1364
1364
1365 # Save this for restoring it later
1365 # Save this for restoring it later
1366 oldcommitphase = ui.config('phases', 'new-commit')
1366 oldcommitphase = ui.config('phases', 'new-commit')
1367
1367
1368 cmdutil.checkunfinished(repo, commit=True)
1368 cmdutil.checkunfinished(repo, commit=True)
1369
1369
1370 branch = repo[None].branch()
1370 branch = repo[None].branch()
1371 bheads = repo.branchheads(branch)
1371 bheads = repo.branchheads(branch)
1372
1372
1373 extra = {}
1373 extra = {}
1374 if opts.get('close_branch'):
1374 if opts.get('close_branch'):
1375 extra['close'] = 1
1375 extra['close'] = 1
1376
1376
1377 if not bheads:
1377 if not bheads:
1378 raise util.Abort(_('can only close branch heads'))
1378 raise util.Abort(_('can only close branch heads'))
1379 elif opts.get('amend'):
1379 elif opts.get('amend'):
1380 if repo.parents()[0].p1().branch() != branch and \
1380 if repo.parents()[0].p1().branch() != branch and \
1381 repo.parents()[0].p2().branch() != branch:
1381 repo.parents()[0].p2().branch() != branch:
1382 raise util.Abort(_('can only close branch heads'))
1382 raise util.Abort(_('can only close branch heads'))
1383
1383
1384 if opts.get('amend'):
1384 if opts.get('amend'):
1385 if ui.configbool('ui', 'commitsubrepos'):
1385 if ui.configbool('ui', 'commitsubrepos'):
1386 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1386 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1387
1387
1388 old = repo['.']
1388 old = repo['.']
1389 if old.phase() == phases.public:
1389 if old.phase() == phases.public:
1390 raise util.Abort(_('cannot amend public changesets'))
1390 raise util.Abort(_('cannot amend public changesets'))
1391 if len(repo[None].parents()) > 1:
1391 if len(repo[None].parents()) > 1:
1392 raise util.Abort(_('cannot amend while merging'))
1392 raise util.Abort(_('cannot amend while merging'))
1393 if (not obsolete._enabled) and old.children():
1393 if (not obsolete._enabled) and old.children():
1394 raise util.Abort(_('cannot amend changeset with children'))
1394 raise util.Abort(_('cannot amend changeset with children'))
1395
1395
1396 e = cmdutil.commiteditor
1396 e = cmdutil.commiteditor
1397 if opts.get('force_editor'):
1397 if opts.get('force_editor'):
1398 e = cmdutil.commitforceeditor
1398 e = cmdutil.commitforceeditor
1399
1399
1400 def commitfunc(ui, repo, message, match, opts):
1400 def commitfunc(ui, repo, message, match, opts):
1401 editor = e
1401 editor = e
1402 # message contains text from -m or -l, if it's empty,
1402 # message contains text from -m or -l, if it's empty,
1403 # open the editor with the old message
1403 # open the editor with the old message
1404 if not message:
1404 if not message:
1405 message = old.description()
1405 message = old.description()
1406 editor = cmdutil.commitforceeditor
1406 editor = cmdutil.commitforceeditor
1407 try:
1407 try:
1408 if opts.get('secret'):
1408 if opts.get('secret'):
1409 ui.setconfig('phases', 'new-commit', 'secret')
1409 ui.setconfig('phases', 'new-commit', 'secret')
1410
1410
1411 return repo.commit(message,
1411 return repo.commit(message,
1412 opts.get('user') or old.user(),
1412 opts.get('user') or old.user(),
1413 opts.get('date') or old.date(),
1413 opts.get('date') or old.date(),
1414 match,
1414 match,
1415 editor=editor,
1415 editor=editor,
1416 extra=extra)
1416 extra=extra)
1417 finally:
1417 finally:
1418 ui.setconfig('phases', 'new-commit', oldcommitphase)
1418 ui.setconfig('phases', 'new-commit', oldcommitphase)
1419
1419
1420 current = repo._bookmarkcurrent
1420 current = repo._bookmarkcurrent
1421 marks = old.bookmarks()
1421 marks = old.bookmarks()
1422 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1422 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1423 if node == old.node():
1423 if node == old.node():
1424 ui.status(_("nothing changed\n"))
1424 ui.status(_("nothing changed\n"))
1425 return 1
1425 return 1
1426 elif marks:
1426 elif marks:
1427 ui.debug('moving bookmarks %r from %s to %s\n' %
1427 ui.debug('moving bookmarks %r from %s to %s\n' %
1428 (marks, old.hex(), hex(node)))
1428 (marks, old.hex(), hex(node)))
1429 newmarks = repo._bookmarks
1429 newmarks = repo._bookmarks
1430 for bm in marks:
1430 for bm in marks:
1431 newmarks[bm] = node
1431 newmarks[bm] = node
1432 if bm == current:
1432 if bm == current:
1433 bookmarks.setcurrent(repo, bm)
1433 bookmarks.setcurrent(repo, bm)
1434 newmarks.write()
1434 newmarks.write()
1435 else:
1435 else:
1436 e = cmdutil.commiteditor
1436 e = cmdutil.commiteditor
1437 if opts.get('force_editor'):
1437 if opts.get('force_editor'):
1438 e = cmdutil.commitforceeditor
1438 e = cmdutil.commitforceeditor
1439
1439
1440 def commitfunc(ui, repo, message, match, opts):
1440 def commitfunc(ui, repo, message, match, opts):
1441 try:
1441 try:
1442 if opts.get('secret'):
1442 if opts.get('secret'):
1443 ui.setconfig('phases', 'new-commit', 'secret')
1443 ui.setconfig('phases', 'new-commit', 'secret')
1444
1444
1445 return repo.commit(message, opts.get('user'), opts.get('date'),
1445 return repo.commit(message, opts.get('user'), opts.get('date'),
1446 match, editor=e, extra=extra)
1446 match, editor=e, extra=extra)
1447 finally:
1447 finally:
1448 ui.setconfig('phases', 'new-commit', oldcommitphase)
1448 ui.setconfig('phases', 'new-commit', oldcommitphase)
1449
1449
1450
1450
1451 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1451 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1452
1452
1453 if not node:
1453 if not node:
1454 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1454 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1455 if stat[3]:
1455 if stat[3]:
1456 ui.status(_("nothing changed (%d missing files, see "
1456 ui.status(_("nothing changed (%d missing files, see "
1457 "'hg status')\n") % len(stat[3]))
1457 "'hg status')\n") % len(stat[3]))
1458 else:
1458 else:
1459 ui.status(_("nothing changed\n"))
1459 ui.status(_("nothing changed\n"))
1460 return 1
1460 return 1
1461
1461
1462 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1462 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1463
1463
1464 @command('copy|cp',
1464 @command('copy|cp',
1465 [('A', 'after', None, _('record a copy that has already occurred')),
1465 [('A', 'after', None, _('record a copy that has already occurred')),
1466 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1466 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1467 ] + walkopts + dryrunopts,
1467 ] + walkopts + dryrunopts,
1468 _('[OPTION]... [SOURCE]... DEST'))
1468 _('[OPTION]... [SOURCE]... DEST'))
1469 def copy(ui, repo, *pats, **opts):
1469 def copy(ui, repo, *pats, **opts):
1470 """mark files as copied for the next commit
1470 """mark files as copied for the next commit
1471
1471
1472 Mark dest as having copies of source files. If dest is a
1472 Mark dest as having copies of source files. If dest is a
1473 directory, copies are put in that directory. If dest is a file,
1473 directory, copies are put in that directory. If dest is a file,
1474 the source must be a single file.
1474 the source must be a single file.
1475
1475
1476 By default, this command copies the contents of files as they
1476 By default, this command copies the contents of files as they
1477 exist in the working directory. If invoked with -A/--after, the
1477 exist in the working directory. If invoked with -A/--after, the
1478 operation is recorded, but no copying is performed.
1478 operation is recorded, but no copying is performed.
1479
1479
1480 This command takes effect with the next commit. To undo a copy
1480 This command takes effect with the next commit. To undo a copy
1481 before that, see :hg:`revert`.
1481 before that, see :hg:`revert`.
1482
1482
1483 Returns 0 on success, 1 if errors are encountered.
1483 Returns 0 on success, 1 if errors are encountered.
1484 """
1484 """
1485 wlock = repo.wlock(False)
1485 wlock = repo.wlock(False)
1486 try:
1486 try:
1487 return cmdutil.copy(ui, repo, pats, opts)
1487 return cmdutil.copy(ui, repo, pats, opts)
1488 finally:
1488 finally:
1489 wlock.release()
1489 wlock.release()
1490
1490
1491 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1491 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1492 def debugancestor(ui, repo, *args):
1492 def debugancestor(ui, repo, *args):
1493 """find the ancestor revision of two revisions in a given index"""
1493 """find the ancestor revision of two revisions in a given index"""
1494 if len(args) == 3:
1494 if len(args) == 3:
1495 index, rev1, rev2 = args
1495 index, rev1, rev2 = args
1496 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1496 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1497 lookup = r.lookup
1497 lookup = r.lookup
1498 elif len(args) == 2:
1498 elif len(args) == 2:
1499 if not repo:
1499 if not repo:
1500 raise util.Abort(_("there is no Mercurial repository here "
1500 raise util.Abort(_("there is no Mercurial repository here "
1501 "(.hg not found)"))
1501 "(.hg not found)"))
1502 rev1, rev2 = args
1502 rev1, rev2 = args
1503 r = repo.changelog
1503 r = repo.changelog
1504 lookup = repo.lookup
1504 lookup = repo.lookup
1505 else:
1505 else:
1506 raise util.Abort(_('either two or three arguments required'))
1506 raise util.Abort(_('either two or three arguments required'))
1507 a = r.ancestor(lookup(rev1), lookup(rev2))
1507 a = r.ancestor(lookup(rev1), lookup(rev2))
1508 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1508 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1509
1509
1510 @command('debugbuilddag',
1510 @command('debugbuilddag',
1511 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1511 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1512 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1512 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1513 ('n', 'new-file', None, _('add new file at each rev'))],
1513 ('n', 'new-file', None, _('add new file at each rev'))],
1514 _('[OPTION]... [TEXT]'))
1514 _('[OPTION]... [TEXT]'))
1515 def debugbuilddag(ui, repo, text=None,
1515 def debugbuilddag(ui, repo, text=None,
1516 mergeable_file=False,
1516 mergeable_file=False,
1517 overwritten_file=False,
1517 overwritten_file=False,
1518 new_file=False):
1518 new_file=False):
1519 """builds a repo with a given DAG from scratch in the current empty repo
1519 """builds a repo with a given DAG from scratch in the current empty repo
1520
1520
1521 The description of the DAG is read from stdin if not given on the
1521 The description of the DAG is read from stdin if not given on the
1522 command line.
1522 command line.
1523
1523
1524 Elements:
1524 Elements:
1525
1525
1526 - "+n" is a linear run of n nodes based on the current default parent
1526 - "+n" is a linear run of n nodes based on the current default parent
1527 - "." is a single node based on the current default parent
1527 - "." is a single node based on the current default parent
1528 - "$" resets the default parent to null (implied at the start);
1528 - "$" resets the default parent to null (implied at the start);
1529 otherwise the default parent is always the last node created
1529 otherwise the default parent is always the last node created
1530 - "<p" sets the default parent to the backref p
1530 - "<p" sets the default parent to the backref p
1531 - "*p" is a fork at parent p, which is a backref
1531 - "*p" is a fork at parent p, which is a backref
1532 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1532 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1533 - "/p2" is a merge of the preceding node and p2
1533 - "/p2" is a merge of the preceding node and p2
1534 - ":tag" defines a local tag for the preceding node
1534 - ":tag" defines a local tag for the preceding node
1535 - "@branch" sets the named branch for subsequent nodes
1535 - "@branch" sets the named branch for subsequent nodes
1536 - "#...\\n" is a comment up to the end of the line
1536 - "#...\\n" is a comment up to the end of the line
1537
1537
1538 Whitespace between the above elements is ignored.
1538 Whitespace between the above elements is ignored.
1539
1539
1540 A backref is either
1540 A backref is either
1541
1541
1542 - a number n, which references the node curr-n, where curr is the current
1542 - a number n, which references the node curr-n, where curr is the current
1543 node, or
1543 node, or
1544 - the name of a local tag you placed earlier using ":tag", or
1544 - the name of a local tag you placed earlier using ":tag", or
1545 - empty to denote the default parent.
1545 - empty to denote the default parent.
1546
1546
1547 All string valued-elements are either strictly alphanumeric, or must
1547 All string valued-elements are either strictly alphanumeric, or must
1548 be enclosed in double quotes ("..."), with "\\" as escape character.
1548 be enclosed in double quotes ("..."), with "\\" as escape character.
1549 """
1549 """
1550
1550
1551 if text is None:
1551 if text is None:
1552 ui.status(_("reading DAG from stdin\n"))
1552 ui.status(_("reading DAG from stdin\n"))
1553 text = ui.fin.read()
1553 text = ui.fin.read()
1554
1554
1555 cl = repo.changelog
1555 cl = repo.changelog
1556 if len(cl) > 0:
1556 if len(cl) > 0:
1557 raise util.Abort(_('repository is not empty'))
1557 raise util.Abort(_('repository is not empty'))
1558
1558
1559 # determine number of revs in DAG
1559 # determine number of revs in DAG
1560 total = 0
1560 total = 0
1561 for type, data in dagparser.parsedag(text):
1561 for type, data in dagparser.parsedag(text):
1562 if type == 'n':
1562 if type == 'n':
1563 total += 1
1563 total += 1
1564
1564
1565 if mergeable_file:
1565 if mergeable_file:
1566 linesperrev = 2
1566 linesperrev = 2
1567 # make a file with k lines per rev
1567 # make a file with k lines per rev
1568 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1568 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1569 initialmergedlines.append("")
1569 initialmergedlines.append("")
1570
1570
1571 tags = []
1571 tags = []
1572
1572
1573 lock = tr = None
1573 lock = tr = None
1574 try:
1574 try:
1575 lock = repo.lock()
1575 lock = repo.lock()
1576 tr = repo.transaction("builddag")
1576 tr = repo.transaction("builddag")
1577
1577
1578 at = -1
1578 at = -1
1579 atbranch = 'default'
1579 atbranch = 'default'
1580 nodeids = []
1580 nodeids = []
1581 id = 0
1581 id = 0
1582 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1582 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1583 for type, data in dagparser.parsedag(text):
1583 for type, data in dagparser.parsedag(text):
1584 if type == 'n':
1584 if type == 'n':
1585 ui.note(('node %s\n' % str(data)))
1585 ui.note(('node %s\n' % str(data)))
1586 id, ps = data
1586 id, ps = data
1587
1587
1588 files = []
1588 files = []
1589 fctxs = {}
1589 fctxs = {}
1590
1590
1591 p2 = None
1591 p2 = None
1592 if mergeable_file:
1592 if mergeable_file:
1593 fn = "mf"
1593 fn = "mf"
1594 p1 = repo[ps[0]]
1594 p1 = repo[ps[0]]
1595 if len(ps) > 1:
1595 if len(ps) > 1:
1596 p2 = repo[ps[1]]
1596 p2 = repo[ps[1]]
1597 pa = p1.ancestor(p2)
1597 pa = p1.ancestor(p2)
1598 base, local, other = [x[fn].data() for x in (pa, p1,
1598 base, local, other = [x[fn].data() for x in (pa, p1,
1599 p2)]
1599 p2)]
1600 m3 = simplemerge.Merge3Text(base, local, other)
1600 m3 = simplemerge.Merge3Text(base, local, other)
1601 ml = [l.strip() for l in m3.merge_lines()]
1601 ml = [l.strip() for l in m3.merge_lines()]
1602 ml.append("")
1602 ml.append("")
1603 elif at > 0:
1603 elif at > 0:
1604 ml = p1[fn].data().split("\n")
1604 ml = p1[fn].data().split("\n")
1605 else:
1605 else:
1606 ml = initialmergedlines
1606 ml = initialmergedlines
1607 ml[id * linesperrev] += " r%i" % id
1607 ml[id * linesperrev] += " r%i" % id
1608 mergedtext = "\n".join(ml)
1608 mergedtext = "\n".join(ml)
1609 files.append(fn)
1609 files.append(fn)
1610 fctxs[fn] = context.memfilectx(fn, mergedtext)
1610 fctxs[fn] = context.memfilectx(fn, mergedtext)
1611
1611
1612 if overwritten_file:
1612 if overwritten_file:
1613 fn = "of"
1613 fn = "of"
1614 files.append(fn)
1614 files.append(fn)
1615 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1615 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1616
1616
1617 if new_file:
1617 if new_file:
1618 fn = "nf%i" % id
1618 fn = "nf%i" % id
1619 files.append(fn)
1619 files.append(fn)
1620 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1620 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1621 if len(ps) > 1:
1621 if len(ps) > 1:
1622 if not p2:
1622 if not p2:
1623 p2 = repo[ps[1]]
1623 p2 = repo[ps[1]]
1624 for fn in p2:
1624 for fn in p2:
1625 if fn.startswith("nf"):
1625 if fn.startswith("nf"):
1626 files.append(fn)
1626 files.append(fn)
1627 fctxs[fn] = p2[fn]
1627 fctxs[fn] = p2[fn]
1628
1628
1629 def fctxfn(repo, cx, path):
1629 def fctxfn(repo, cx, path):
1630 return fctxs.get(path)
1630 return fctxs.get(path)
1631
1631
1632 if len(ps) == 0 or ps[0] < 0:
1632 if len(ps) == 0 or ps[0] < 0:
1633 pars = [None, None]
1633 pars = [None, None]
1634 elif len(ps) == 1:
1634 elif len(ps) == 1:
1635 pars = [nodeids[ps[0]], None]
1635 pars = [nodeids[ps[0]], None]
1636 else:
1636 else:
1637 pars = [nodeids[p] for p in ps]
1637 pars = [nodeids[p] for p in ps]
1638 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1638 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1639 date=(id, 0),
1639 date=(id, 0),
1640 user="debugbuilddag",
1640 user="debugbuilddag",
1641 extra={'branch': atbranch})
1641 extra={'branch': atbranch})
1642 nodeid = repo.commitctx(cx)
1642 nodeid = repo.commitctx(cx)
1643 nodeids.append(nodeid)
1643 nodeids.append(nodeid)
1644 at = id
1644 at = id
1645 elif type == 'l':
1645 elif type == 'l':
1646 id, name = data
1646 id, name = data
1647 ui.note(('tag %s\n' % name))
1647 ui.note(('tag %s\n' % name))
1648 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1648 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1649 elif type == 'a':
1649 elif type == 'a':
1650 ui.note(('branch %s\n' % data))
1650 ui.note(('branch %s\n' % data))
1651 atbranch = data
1651 atbranch = data
1652 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1652 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1653 tr.close()
1653 tr.close()
1654
1654
1655 if tags:
1655 if tags:
1656 repo.opener.write("localtags", "".join(tags))
1656 repo.opener.write("localtags", "".join(tags))
1657 finally:
1657 finally:
1658 ui.progress(_('building'), None)
1658 ui.progress(_('building'), None)
1659 release(tr, lock)
1659 release(tr, lock)
1660
1660
1661 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1661 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1662 def debugbundle(ui, bundlepath, all=None, **opts):
1662 def debugbundle(ui, bundlepath, all=None, **opts):
1663 """lists the contents of a bundle"""
1663 """lists the contents of a bundle"""
1664 f = hg.openpath(ui, bundlepath)
1664 f = hg.openpath(ui, bundlepath)
1665 try:
1665 try:
1666 gen = changegroup.readbundle(f, bundlepath)
1666 gen = changegroup.readbundle(f, bundlepath)
1667 if all:
1667 if all:
1668 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1668 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1669
1669
1670 def showchunks(named):
1670 def showchunks(named):
1671 ui.write("\n%s\n" % named)
1671 ui.write("\n%s\n" % named)
1672 chain = None
1672 chain = None
1673 while True:
1673 while True:
1674 chunkdata = gen.deltachunk(chain)
1674 chunkdata = gen.deltachunk(chain)
1675 if not chunkdata:
1675 if not chunkdata:
1676 break
1676 break
1677 node = chunkdata['node']
1677 node = chunkdata['node']
1678 p1 = chunkdata['p1']
1678 p1 = chunkdata['p1']
1679 p2 = chunkdata['p2']
1679 p2 = chunkdata['p2']
1680 cs = chunkdata['cs']
1680 cs = chunkdata['cs']
1681 deltabase = chunkdata['deltabase']
1681 deltabase = chunkdata['deltabase']
1682 delta = chunkdata['delta']
1682 delta = chunkdata['delta']
1683 ui.write("%s %s %s %s %s %s\n" %
1683 ui.write("%s %s %s %s %s %s\n" %
1684 (hex(node), hex(p1), hex(p2),
1684 (hex(node), hex(p1), hex(p2),
1685 hex(cs), hex(deltabase), len(delta)))
1685 hex(cs), hex(deltabase), len(delta)))
1686 chain = node
1686 chain = node
1687
1687
1688 chunkdata = gen.changelogheader()
1688 chunkdata = gen.changelogheader()
1689 showchunks("changelog")
1689 showchunks("changelog")
1690 chunkdata = gen.manifestheader()
1690 chunkdata = gen.manifestheader()
1691 showchunks("manifest")
1691 showchunks("manifest")
1692 while True:
1692 while True:
1693 chunkdata = gen.filelogheader()
1693 chunkdata = gen.filelogheader()
1694 if not chunkdata:
1694 if not chunkdata:
1695 break
1695 break
1696 fname = chunkdata['filename']
1696 fname = chunkdata['filename']
1697 showchunks(fname)
1697 showchunks(fname)
1698 else:
1698 else:
1699 chunkdata = gen.changelogheader()
1699 chunkdata = gen.changelogheader()
1700 chain = None
1700 chain = None
1701 while True:
1701 while True:
1702 chunkdata = gen.deltachunk(chain)
1702 chunkdata = gen.deltachunk(chain)
1703 if not chunkdata:
1703 if not chunkdata:
1704 break
1704 break
1705 node = chunkdata['node']
1705 node = chunkdata['node']
1706 ui.write("%s\n" % hex(node))
1706 ui.write("%s\n" % hex(node))
1707 chain = node
1707 chain = node
1708 finally:
1708 finally:
1709 f.close()
1709 f.close()
1710
1710
1711 @command('debugcheckstate', [], '')
1711 @command('debugcheckstate', [], '')
1712 def debugcheckstate(ui, repo):
1712 def debugcheckstate(ui, repo):
1713 """validate the correctness of the current dirstate"""
1713 """validate the correctness of the current dirstate"""
1714 parent1, parent2 = repo.dirstate.parents()
1714 parent1, parent2 = repo.dirstate.parents()
1715 m1 = repo[parent1].manifest()
1715 m1 = repo[parent1].manifest()
1716 m2 = repo[parent2].manifest()
1716 m2 = repo[parent2].manifest()
1717 errors = 0
1717 errors = 0
1718 for f in repo.dirstate:
1718 for f in repo.dirstate:
1719 state = repo.dirstate[f]
1719 state = repo.dirstate[f]
1720 if state in "nr" and f not in m1:
1720 if state in "nr" and f not in m1:
1721 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1721 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1722 errors += 1
1722 errors += 1
1723 if state in "a" and f in m1:
1723 if state in "a" and f in m1:
1724 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1724 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1725 errors += 1
1725 errors += 1
1726 if state in "m" and f not in m1 and f not in m2:
1726 if state in "m" and f not in m1 and f not in m2:
1727 ui.warn(_("%s in state %s, but not in either manifest\n") %
1727 ui.warn(_("%s in state %s, but not in either manifest\n") %
1728 (f, state))
1728 (f, state))
1729 errors += 1
1729 errors += 1
1730 for f in m1:
1730 for f in m1:
1731 state = repo.dirstate[f]
1731 state = repo.dirstate[f]
1732 if state not in "nrm":
1732 if state not in "nrm":
1733 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1733 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1734 errors += 1
1734 errors += 1
1735 if errors:
1735 if errors:
1736 error = _(".hg/dirstate inconsistent with current parent's manifest")
1736 error = _(".hg/dirstate inconsistent with current parent's manifest")
1737 raise util.Abort(error)
1737 raise util.Abort(error)
1738
1738
1739 @command('debugcommands', [], _('[COMMAND]'))
1739 @command('debugcommands', [], _('[COMMAND]'))
1740 def debugcommands(ui, cmd='', *args):
1740 def debugcommands(ui, cmd='', *args):
1741 """list all available commands and options"""
1741 """list all available commands and options"""
1742 for cmd, vals in sorted(table.iteritems()):
1742 for cmd, vals in sorted(table.iteritems()):
1743 cmd = cmd.split('|')[0].strip('^')
1743 cmd = cmd.split('|')[0].strip('^')
1744 opts = ', '.join([i[1] for i in vals[1]])
1744 opts = ', '.join([i[1] for i in vals[1]])
1745 ui.write('%s: %s\n' % (cmd, opts))
1745 ui.write('%s: %s\n' % (cmd, opts))
1746
1746
1747 @command('debugcomplete',
1747 @command('debugcomplete',
1748 [('o', 'options', None, _('show the command options'))],
1748 [('o', 'options', None, _('show the command options'))],
1749 _('[-o] CMD'))
1749 _('[-o] CMD'))
1750 def debugcomplete(ui, cmd='', **opts):
1750 def debugcomplete(ui, cmd='', **opts):
1751 """returns the completion list associated with the given command"""
1751 """returns the completion list associated with the given command"""
1752
1752
1753 if opts.get('options'):
1753 if opts.get('options'):
1754 options = []
1754 options = []
1755 otables = [globalopts]
1755 otables = [globalopts]
1756 if cmd:
1756 if cmd:
1757 aliases, entry = cmdutil.findcmd(cmd, table, False)
1757 aliases, entry = cmdutil.findcmd(cmd, table, False)
1758 otables.append(entry[1])
1758 otables.append(entry[1])
1759 for t in otables:
1759 for t in otables:
1760 for o in t:
1760 for o in t:
1761 if "(DEPRECATED)" in o[3]:
1761 if "(DEPRECATED)" in o[3]:
1762 continue
1762 continue
1763 if o[0]:
1763 if o[0]:
1764 options.append('-%s' % o[0])
1764 options.append('-%s' % o[0])
1765 options.append('--%s' % o[1])
1765 options.append('--%s' % o[1])
1766 ui.write("%s\n" % "\n".join(options))
1766 ui.write("%s\n" % "\n".join(options))
1767 return
1767 return
1768
1768
1769 cmdlist = cmdutil.findpossible(cmd, table)
1769 cmdlist = cmdutil.findpossible(cmd, table)
1770 if ui.verbose:
1770 if ui.verbose:
1771 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1771 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1772 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1772 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1773
1773
1774 @command('debugdag',
1774 @command('debugdag',
1775 [('t', 'tags', None, _('use tags as labels')),
1775 [('t', 'tags', None, _('use tags as labels')),
1776 ('b', 'branches', None, _('annotate with branch names')),
1776 ('b', 'branches', None, _('annotate with branch names')),
1777 ('', 'dots', None, _('use dots for runs')),
1777 ('', 'dots', None, _('use dots for runs')),
1778 ('s', 'spaces', None, _('separate elements by spaces'))],
1778 ('s', 'spaces', None, _('separate elements by spaces'))],
1779 _('[OPTION]... [FILE [REV]...]'))
1779 _('[OPTION]... [FILE [REV]...]'))
1780 def debugdag(ui, repo, file_=None, *revs, **opts):
1780 def debugdag(ui, repo, file_=None, *revs, **opts):
1781 """format the changelog or an index DAG as a concise textual description
1781 """format the changelog or an index DAG as a concise textual description
1782
1782
1783 If you pass a revlog index, the revlog's DAG is emitted. If you list
1783 If you pass a revlog index, the revlog's DAG is emitted. If you list
1784 revision numbers, they get labeled in the output as rN.
1784 revision numbers, they get labeled in the output as rN.
1785
1785
1786 Otherwise, the changelog DAG of the current repo is emitted.
1786 Otherwise, the changelog DAG of the current repo is emitted.
1787 """
1787 """
1788 spaces = opts.get('spaces')
1788 spaces = opts.get('spaces')
1789 dots = opts.get('dots')
1789 dots = opts.get('dots')
1790 if file_:
1790 if file_:
1791 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1791 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1792 revs = set((int(r) for r in revs))
1792 revs = set((int(r) for r in revs))
1793 def events():
1793 def events():
1794 for r in rlog:
1794 for r in rlog:
1795 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1795 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1796 if p != -1)))
1796 if p != -1)))
1797 if r in revs:
1797 if r in revs:
1798 yield 'l', (r, "r%i" % r)
1798 yield 'l', (r, "r%i" % r)
1799 elif repo:
1799 elif repo:
1800 cl = repo.changelog
1800 cl = repo.changelog
1801 tags = opts.get('tags')
1801 tags = opts.get('tags')
1802 branches = opts.get('branches')
1802 branches = opts.get('branches')
1803 if tags:
1803 if tags:
1804 labels = {}
1804 labels = {}
1805 for l, n in repo.tags().items():
1805 for l, n in repo.tags().items():
1806 labels.setdefault(cl.rev(n), []).append(l)
1806 labels.setdefault(cl.rev(n), []).append(l)
1807 def events():
1807 def events():
1808 b = "default"
1808 b = "default"
1809 for r in cl:
1809 for r in cl:
1810 if branches:
1810 if branches:
1811 newb = cl.read(cl.node(r))[5]['branch']
1811 newb = cl.read(cl.node(r))[5]['branch']
1812 if newb != b:
1812 if newb != b:
1813 yield 'a', newb
1813 yield 'a', newb
1814 b = newb
1814 b = newb
1815 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1815 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1816 if p != -1)))
1816 if p != -1)))
1817 if tags:
1817 if tags:
1818 ls = labels.get(r)
1818 ls = labels.get(r)
1819 if ls:
1819 if ls:
1820 for l in ls:
1820 for l in ls:
1821 yield 'l', (r, l)
1821 yield 'l', (r, l)
1822 else:
1822 else:
1823 raise util.Abort(_('need repo for changelog dag'))
1823 raise util.Abort(_('need repo for changelog dag'))
1824
1824
1825 for line in dagparser.dagtextlines(events(),
1825 for line in dagparser.dagtextlines(events(),
1826 addspaces=spaces,
1826 addspaces=spaces,
1827 wraplabels=True,
1827 wraplabels=True,
1828 wrapannotations=True,
1828 wrapannotations=True,
1829 wrapnonlinear=dots,
1829 wrapnonlinear=dots,
1830 usedots=dots,
1830 usedots=dots,
1831 maxlinewidth=70):
1831 maxlinewidth=70):
1832 ui.write(line)
1832 ui.write(line)
1833 ui.write("\n")
1833 ui.write("\n")
1834
1834
1835 @command('debugdata',
1835 @command('debugdata',
1836 [('c', 'changelog', False, _('open changelog')),
1836 [('c', 'changelog', False, _('open changelog')),
1837 ('m', 'manifest', False, _('open manifest'))],
1837 ('m', 'manifest', False, _('open manifest'))],
1838 _('-c|-m|FILE REV'))
1838 _('-c|-m|FILE REV'))
1839 def debugdata(ui, repo, file_, rev=None, **opts):
1839 def debugdata(ui, repo, file_, rev=None, **opts):
1840 """dump the contents of a data file revision"""
1840 """dump the contents of a data file revision"""
1841 if opts.get('changelog') or opts.get('manifest'):
1841 if opts.get('changelog') or opts.get('manifest'):
1842 file_, rev = None, file_
1842 file_, rev = None, file_
1843 elif rev is None:
1843 elif rev is None:
1844 raise error.CommandError('debugdata', _('invalid arguments'))
1844 raise error.CommandError('debugdata', _('invalid arguments'))
1845 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1845 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1846 try:
1846 try:
1847 ui.write(r.revision(r.lookup(rev)))
1847 ui.write(r.revision(r.lookup(rev)))
1848 except KeyError:
1848 except KeyError:
1849 raise util.Abort(_('invalid revision identifier %s') % rev)
1849 raise util.Abort(_('invalid revision identifier %s') % rev)
1850
1850
1851 @command('debugdate',
1851 @command('debugdate',
1852 [('e', 'extended', None, _('try extended date formats'))],
1852 [('e', 'extended', None, _('try extended date formats'))],
1853 _('[-e] DATE [RANGE]'))
1853 _('[-e] DATE [RANGE]'))
1854 def debugdate(ui, date, range=None, **opts):
1854 def debugdate(ui, date, range=None, **opts):
1855 """parse and display a date"""
1855 """parse and display a date"""
1856 if opts["extended"]:
1856 if opts["extended"]:
1857 d = util.parsedate(date, util.extendeddateformats)
1857 d = util.parsedate(date, util.extendeddateformats)
1858 else:
1858 else:
1859 d = util.parsedate(date)
1859 d = util.parsedate(date)
1860 ui.write(("internal: %s %s\n") % d)
1860 ui.write(("internal: %s %s\n") % d)
1861 ui.write(("standard: %s\n") % util.datestr(d))
1861 ui.write(("standard: %s\n") % util.datestr(d))
1862 if range:
1862 if range:
1863 m = util.matchdate(range)
1863 m = util.matchdate(range)
1864 ui.write(("match: %s\n") % m(d[0]))
1864 ui.write(("match: %s\n") % m(d[0]))
1865
1865
1866 @command('debugdiscovery',
1866 @command('debugdiscovery',
1867 [('', 'old', None, _('use old-style discovery')),
1867 [('', 'old', None, _('use old-style discovery')),
1868 ('', 'nonheads', None,
1868 ('', 'nonheads', None,
1869 _('use old-style discovery with non-heads included')),
1869 _('use old-style discovery with non-heads included')),
1870 ] + remoteopts,
1870 ] + remoteopts,
1871 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1871 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1872 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1872 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1873 """runs the changeset discovery protocol in isolation"""
1873 """runs the changeset discovery protocol in isolation"""
1874 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1874 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1875 opts.get('branch'))
1875 opts.get('branch'))
1876 remote = hg.peer(repo, opts, remoteurl)
1876 remote = hg.peer(repo, opts, remoteurl)
1877 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1877 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1878
1878
1879 # make sure tests are repeatable
1879 # make sure tests are repeatable
1880 random.seed(12323)
1880 random.seed(12323)
1881
1881
1882 def doit(localheads, remoteheads, remote=remote):
1882 def doit(localheads, remoteheads, remote=remote):
1883 if opts.get('old'):
1883 if opts.get('old'):
1884 if localheads:
1884 if localheads:
1885 raise util.Abort('cannot use localheads with old style '
1885 raise util.Abort('cannot use localheads with old style '
1886 'discovery')
1886 'discovery')
1887 if not util.safehasattr(remote, 'branches'):
1887 if not util.safehasattr(remote, 'branches'):
1888 # enable in-client legacy support
1888 # enable in-client legacy support
1889 remote = localrepo.locallegacypeer(remote.local())
1889 remote = localrepo.locallegacypeer(remote.local())
1890 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1890 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1891 force=True)
1891 force=True)
1892 common = set(common)
1892 common = set(common)
1893 if not opts.get('nonheads'):
1893 if not opts.get('nonheads'):
1894 ui.write(("unpruned common: %s\n") %
1894 ui.write(("unpruned common: %s\n") %
1895 " ".join(sorted(short(n) for n in common)))
1895 " ".join(sorted(short(n) for n in common)))
1896 dag = dagutil.revlogdag(repo.changelog)
1896 dag = dagutil.revlogdag(repo.changelog)
1897 all = dag.ancestorset(dag.internalizeall(common))
1897 all = dag.ancestorset(dag.internalizeall(common))
1898 common = dag.externalizeall(dag.headsetofconnecteds(all))
1898 common = dag.externalizeall(dag.headsetofconnecteds(all))
1899 else:
1899 else:
1900 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1900 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1901 common = set(common)
1901 common = set(common)
1902 rheads = set(hds)
1902 rheads = set(hds)
1903 lheads = set(repo.heads())
1903 lheads = set(repo.heads())
1904 ui.write(("common heads: %s\n") %
1904 ui.write(("common heads: %s\n") %
1905 " ".join(sorted(short(n) for n in common)))
1905 " ".join(sorted(short(n) for n in common)))
1906 if lheads <= common:
1906 if lheads <= common:
1907 ui.write(("local is subset\n"))
1907 ui.write(("local is subset\n"))
1908 elif rheads <= common:
1908 elif rheads <= common:
1909 ui.write(("remote is subset\n"))
1909 ui.write(("remote is subset\n"))
1910
1910
1911 serverlogs = opts.get('serverlog')
1911 serverlogs = opts.get('serverlog')
1912 if serverlogs:
1912 if serverlogs:
1913 for filename in serverlogs:
1913 for filename in serverlogs:
1914 logfile = open(filename, 'r')
1914 logfile = open(filename, 'r')
1915 try:
1915 try:
1916 line = logfile.readline()
1916 line = logfile.readline()
1917 while line:
1917 while line:
1918 parts = line.strip().split(';')
1918 parts = line.strip().split(';')
1919 op = parts[1]
1919 op = parts[1]
1920 if op == 'cg':
1920 if op == 'cg':
1921 pass
1921 pass
1922 elif op == 'cgss':
1922 elif op == 'cgss':
1923 doit(parts[2].split(' '), parts[3].split(' '))
1923 doit(parts[2].split(' '), parts[3].split(' '))
1924 elif op == 'unb':
1924 elif op == 'unb':
1925 doit(parts[3].split(' '), parts[2].split(' '))
1925 doit(parts[3].split(' '), parts[2].split(' '))
1926 line = logfile.readline()
1926 line = logfile.readline()
1927 finally:
1927 finally:
1928 logfile.close()
1928 logfile.close()
1929
1929
1930 else:
1930 else:
1931 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1931 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1932 opts.get('remote_head'))
1932 opts.get('remote_head'))
1933 localrevs = opts.get('local_head')
1933 localrevs = opts.get('local_head')
1934 doit(localrevs, remoterevs)
1934 doit(localrevs, remoterevs)
1935
1935
1936 @command('debugfileset',
1936 @command('debugfileset',
1937 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1937 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1938 _('[-r REV] FILESPEC'))
1938 _('[-r REV] FILESPEC'))
1939 def debugfileset(ui, repo, expr, **opts):
1939 def debugfileset(ui, repo, expr, **opts):
1940 '''parse and apply a fileset specification'''
1940 '''parse and apply a fileset specification'''
1941 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1941 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1942 if ui.verbose:
1942 if ui.verbose:
1943 tree = fileset.parse(expr)[0]
1943 tree = fileset.parse(expr)[0]
1944 ui.note(tree, "\n")
1944 ui.note(tree, "\n")
1945
1945
1946 for f in ctx.getfileset(expr):
1946 for f in ctx.getfileset(expr):
1947 ui.write("%s\n" % f)
1947 ui.write("%s\n" % f)
1948
1948
1949 @command('debugfsinfo', [], _('[PATH]'))
1949 @command('debugfsinfo', [], _('[PATH]'))
1950 def debugfsinfo(ui, path="."):
1950 def debugfsinfo(ui, path="."):
1951 """show information detected about current filesystem"""
1951 """show information detected about current filesystem"""
1952 util.writefile('.debugfsinfo', '')
1952 util.writefile('.debugfsinfo', '')
1953 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1953 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1954 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1954 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1955 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
1955 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
1956 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1956 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1957 and 'yes' or 'no'))
1957 and 'yes' or 'no'))
1958 os.unlink('.debugfsinfo')
1958 os.unlink('.debugfsinfo')
1959
1959
1960 @command('debuggetbundle',
1960 @command('debuggetbundle',
1961 [('H', 'head', [], _('id of head node'), _('ID')),
1961 [('H', 'head', [], _('id of head node'), _('ID')),
1962 ('C', 'common', [], _('id of common node'), _('ID')),
1962 ('C', 'common', [], _('id of common node'), _('ID')),
1963 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1963 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1964 _('REPO FILE [-H|-C ID]...'))
1964 _('REPO FILE [-H|-C ID]...'))
1965 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1965 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1966 """retrieves a bundle from a repo
1966 """retrieves a bundle from a repo
1967
1967
1968 Every ID must be a full-length hex node id string. Saves the bundle to the
1968 Every ID must be a full-length hex node id string. Saves the bundle to the
1969 given file.
1969 given file.
1970 """
1970 """
1971 repo = hg.peer(ui, opts, repopath)
1971 repo = hg.peer(ui, opts, repopath)
1972 if not repo.capable('getbundle'):
1972 if not repo.capable('getbundle'):
1973 raise util.Abort("getbundle() not supported by target repository")
1973 raise util.Abort("getbundle() not supported by target repository")
1974 args = {}
1974 args = {}
1975 if common:
1975 if common:
1976 args['common'] = [bin(s) for s in common]
1976 args['common'] = [bin(s) for s in common]
1977 if head:
1977 if head:
1978 args['heads'] = [bin(s) for s in head]
1978 args['heads'] = [bin(s) for s in head]
1979 # TODO: get desired bundlecaps from command line.
1979 # TODO: get desired bundlecaps from command line.
1980 args['bundlecaps'] = None
1980 args['bundlecaps'] = None
1981 bundle = repo.getbundle('debug', **args)
1981 bundle = repo.getbundle('debug', **args)
1982
1982
1983 bundletype = opts.get('type', 'bzip2').lower()
1983 bundletype = opts.get('type', 'bzip2').lower()
1984 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1984 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1985 bundletype = btypes.get(bundletype)
1985 bundletype = btypes.get(bundletype)
1986 if bundletype not in changegroup.bundletypes:
1986 if bundletype not in changegroup.bundletypes:
1987 raise util.Abort(_('unknown bundle type specified with --type'))
1987 raise util.Abort(_('unknown bundle type specified with --type'))
1988 changegroup.writebundle(bundle, bundlepath, bundletype)
1988 changegroup.writebundle(bundle, bundlepath, bundletype)
1989
1989
1990 @command('debugignore', [], '')
1990 @command('debugignore', [], '')
1991 def debugignore(ui, repo, *values, **opts):
1991 def debugignore(ui, repo, *values, **opts):
1992 """display the combined ignore pattern"""
1992 """display the combined ignore pattern"""
1993 ignore = repo.dirstate._ignore
1993 ignore = repo.dirstate._ignore
1994 includepat = getattr(ignore, 'includepat', None)
1994 includepat = getattr(ignore, 'includepat', None)
1995 if includepat is not None:
1995 if includepat is not None:
1996 ui.write("%s\n" % includepat)
1996 ui.write("%s\n" % includepat)
1997 else:
1997 else:
1998 raise util.Abort(_("no ignore patterns found"))
1998 raise util.Abort(_("no ignore patterns found"))
1999
1999
2000 @command('debugindex',
2000 @command('debugindex',
2001 [('c', 'changelog', False, _('open changelog')),
2001 [('c', 'changelog', False, _('open changelog')),
2002 ('m', 'manifest', False, _('open manifest')),
2002 ('m', 'manifest', False, _('open manifest')),
2003 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2003 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2004 _('[-f FORMAT] -c|-m|FILE'))
2004 _('[-f FORMAT] -c|-m|FILE'))
2005 def debugindex(ui, repo, file_=None, **opts):
2005 def debugindex(ui, repo, file_=None, **opts):
2006 """dump the contents of an index file"""
2006 """dump the contents of an index file"""
2007 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2007 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2008 format = opts.get('format', 0)
2008 format = opts.get('format', 0)
2009 if format not in (0, 1):
2009 if format not in (0, 1):
2010 raise util.Abort(_("unknown format %d") % format)
2010 raise util.Abort(_("unknown format %d") % format)
2011
2011
2012 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2012 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2013 if generaldelta:
2013 if generaldelta:
2014 basehdr = ' delta'
2014 basehdr = ' delta'
2015 else:
2015 else:
2016 basehdr = ' base'
2016 basehdr = ' base'
2017
2017
2018 if format == 0:
2018 if format == 0:
2019 ui.write(" rev offset length " + basehdr + " linkrev"
2019 ui.write(" rev offset length " + basehdr + " linkrev"
2020 " nodeid p1 p2\n")
2020 " nodeid p1 p2\n")
2021 elif format == 1:
2021 elif format == 1:
2022 ui.write(" rev flag offset length"
2022 ui.write(" rev flag offset length"
2023 " size " + basehdr + " link p1 p2"
2023 " size " + basehdr + " link p1 p2"
2024 " nodeid\n")
2024 " nodeid\n")
2025
2025
2026 for i in r:
2026 for i in r:
2027 node = r.node(i)
2027 node = r.node(i)
2028 if generaldelta:
2028 if generaldelta:
2029 base = r.deltaparent(i)
2029 base = r.deltaparent(i)
2030 else:
2030 else:
2031 base = r.chainbase(i)
2031 base = r.chainbase(i)
2032 if format == 0:
2032 if format == 0:
2033 try:
2033 try:
2034 pp = r.parents(node)
2034 pp = r.parents(node)
2035 except Exception:
2035 except Exception:
2036 pp = [nullid, nullid]
2036 pp = [nullid, nullid]
2037 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2037 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2038 i, r.start(i), r.length(i), base, r.linkrev(i),
2038 i, r.start(i), r.length(i), base, r.linkrev(i),
2039 short(node), short(pp[0]), short(pp[1])))
2039 short(node), short(pp[0]), short(pp[1])))
2040 elif format == 1:
2040 elif format == 1:
2041 pr = r.parentrevs(i)
2041 pr = r.parentrevs(i)
2042 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2042 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2043 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2043 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2044 base, r.linkrev(i), pr[0], pr[1], short(node)))
2044 base, r.linkrev(i), pr[0], pr[1], short(node)))
2045
2045
2046 @command('debugindexdot', [], _('FILE'))
2046 @command('debugindexdot', [], _('FILE'))
2047 def debugindexdot(ui, repo, file_):
2047 def debugindexdot(ui, repo, file_):
2048 """dump an index DAG as a graphviz dot file"""
2048 """dump an index DAG as a graphviz dot file"""
2049 r = None
2049 r = None
2050 if repo:
2050 if repo:
2051 filelog = repo.file(file_)
2051 filelog = repo.file(file_)
2052 if len(filelog):
2052 if len(filelog):
2053 r = filelog
2053 r = filelog
2054 if not r:
2054 if not r:
2055 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2055 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2056 ui.write(("digraph G {\n"))
2056 ui.write(("digraph G {\n"))
2057 for i in r:
2057 for i in r:
2058 node = r.node(i)
2058 node = r.node(i)
2059 pp = r.parents(node)
2059 pp = r.parents(node)
2060 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2060 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2061 if pp[1] != nullid:
2061 if pp[1] != nullid:
2062 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2062 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2063 ui.write("}\n")
2063 ui.write("}\n")
2064
2064
2065 @command('debuginstall', [], '')
2065 @command('debuginstall', [], '')
2066 def debuginstall(ui):
2066 def debuginstall(ui):
2067 '''test Mercurial installation
2067 '''test Mercurial installation
2068
2068
2069 Returns 0 on success.
2069 Returns 0 on success.
2070 '''
2070 '''
2071
2071
2072 def writetemp(contents):
2072 def writetemp(contents):
2073 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2073 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2074 f = os.fdopen(fd, "wb")
2074 f = os.fdopen(fd, "wb")
2075 f.write(contents)
2075 f.write(contents)
2076 f.close()
2076 f.close()
2077 return name
2077 return name
2078
2078
2079 problems = 0
2079 problems = 0
2080
2080
2081 # encoding
2081 # encoding
2082 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2082 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2083 try:
2083 try:
2084 encoding.fromlocal("test")
2084 encoding.fromlocal("test")
2085 except util.Abort, inst:
2085 except util.Abort, inst:
2086 ui.write(" %s\n" % inst)
2086 ui.write(" %s\n" % inst)
2087 ui.write(_(" (check that your locale is properly set)\n"))
2087 ui.write(_(" (check that your locale is properly set)\n"))
2088 problems += 1
2088 problems += 1
2089
2089
2090 # Python lib
2090 # Python lib
2091 ui.status(_("checking Python lib (%s)...\n")
2091 ui.status(_("checking Python lib (%s)...\n")
2092 % os.path.dirname(os.__file__))
2092 % os.path.dirname(os.__file__))
2093
2093
2094 # compiled modules
2094 # compiled modules
2095 ui.status(_("checking installed modules (%s)...\n")
2095 ui.status(_("checking installed modules (%s)...\n")
2096 % os.path.dirname(__file__))
2096 % os.path.dirname(__file__))
2097 try:
2097 try:
2098 import bdiff, mpatch, base85, osutil
2098 import bdiff, mpatch, base85, osutil
2099 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2099 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2100 except Exception, inst:
2100 except Exception, inst:
2101 ui.write(" %s\n" % inst)
2101 ui.write(" %s\n" % inst)
2102 ui.write(_(" One or more extensions could not be found"))
2102 ui.write(_(" One or more extensions could not be found"))
2103 ui.write(_(" (check that you compiled the extensions)\n"))
2103 ui.write(_(" (check that you compiled the extensions)\n"))
2104 problems += 1
2104 problems += 1
2105
2105
2106 # templates
2106 # templates
2107 import templater
2107 import templater
2108 p = templater.templatepath()
2108 p = templater.templatepath()
2109 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2109 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2110 if p:
2110 if p:
2111 m = templater.templatepath("map-cmdline.default")
2111 m = templater.templatepath("map-cmdline.default")
2112 if m:
2112 if m:
2113 # template found, check if it is working
2113 # template found, check if it is working
2114 try:
2114 try:
2115 templater.templater(m)
2115 templater.templater(m)
2116 except Exception, inst:
2116 except Exception, inst:
2117 ui.write(" %s\n" % inst)
2117 ui.write(" %s\n" % inst)
2118 p = None
2118 p = None
2119 else:
2119 else:
2120 ui.write(_(" template 'default' not found\n"))
2120 ui.write(_(" template 'default' not found\n"))
2121 p = None
2121 p = None
2122 else:
2122 else:
2123 ui.write(_(" no template directories found\n"))
2123 ui.write(_(" no template directories found\n"))
2124 if not p:
2124 if not p:
2125 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2125 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2126 problems += 1
2126 problems += 1
2127
2127
2128 # editor
2128 # editor
2129 ui.status(_("checking commit editor...\n"))
2129 ui.status(_("checking commit editor...\n"))
2130 editor = ui.geteditor()
2130 editor = ui.geteditor()
2131 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2131 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2132 if not cmdpath:
2132 if not cmdpath:
2133 if editor == 'vi':
2133 if editor == 'vi':
2134 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2134 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2135 ui.write(_(" (specify a commit editor in your configuration"
2135 ui.write(_(" (specify a commit editor in your configuration"
2136 " file)\n"))
2136 " file)\n"))
2137 else:
2137 else:
2138 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2138 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2139 ui.write(_(" (specify a commit editor in your configuration"
2139 ui.write(_(" (specify a commit editor in your configuration"
2140 " file)\n"))
2140 " file)\n"))
2141 problems += 1
2141 problems += 1
2142
2142
2143 # check username
2143 # check username
2144 ui.status(_("checking username...\n"))
2144 ui.status(_("checking username...\n"))
2145 try:
2145 try:
2146 ui.username()
2146 ui.username()
2147 except util.Abort, e:
2147 except util.Abort, e:
2148 ui.write(" %s\n" % e)
2148 ui.write(" %s\n" % e)
2149 ui.write(_(" (specify a username in your configuration file)\n"))
2149 ui.write(_(" (specify a username in your configuration file)\n"))
2150 problems += 1
2150 problems += 1
2151
2151
2152 if not problems:
2152 if not problems:
2153 ui.status(_("no problems detected\n"))
2153 ui.status(_("no problems detected\n"))
2154 else:
2154 else:
2155 ui.write(_("%s problems detected,"
2155 ui.write(_("%s problems detected,"
2156 " please check your install!\n") % problems)
2156 " please check your install!\n") % problems)
2157
2157
2158 return problems
2158 return problems
2159
2159
2160 @command('debugknown', [], _('REPO ID...'))
2160 @command('debugknown', [], _('REPO ID...'))
2161 def debugknown(ui, repopath, *ids, **opts):
2161 def debugknown(ui, repopath, *ids, **opts):
2162 """test whether node ids are known to a repo
2162 """test whether node ids are known to a repo
2163
2163
2164 Every ID must be a full-length hex node id string. Returns a list of 0s
2164 Every ID must be a full-length hex node id string. Returns a list of 0s
2165 and 1s indicating unknown/known.
2165 and 1s indicating unknown/known.
2166 """
2166 """
2167 repo = hg.peer(ui, opts, repopath)
2167 repo = hg.peer(ui, opts, repopath)
2168 if not repo.capable('known'):
2168 if not repo.capable('known'):
2169 raise util.Abort("known() not supported by target repository")
2169 raise util.Abort("known() not supported by target repository")
2170 flags = repo.known([bin(s) for s in ids])
2170 flags = repo.known([bin(s) for s in ids])
2171 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2171 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2172
2172
2173 @command('debuglabelcomplete', [], _('LABEL...'))
2173 @command('debuglabelcomplete', [], _('LABEL...'))
2174 def debuglabelcomplete(ui, repo, *args):
2174 def debuglabelcomplete(ui, repo, *args):
2175 '''complete "labels" - tags, open branch names, bookmark names'''
2175 '''complete "labels" - tags, open branch names, bookmark names'''
2176
2176
2177 labels = set()
2177 labels = set()
2178 labels.update(t[0] for t in repo.tagslist())
2178 labels.update(t[0] for t in repo.tagslist())
2179 labels.update(repo._bookmarks.keys())
2179 labels.update(repo._bookmarks.keys())
2180 labels.update(tag for (tag, heads, tip, closed)
2180 labels.update(tag for (tag, heads, tip, closed)
2181 in repo.branchmap().iterbranches() if not closed)
2181 in repo.branchmap().iterbranches() if not closed)
2182 completions = set()
2182 completions = set()
2183 if not args:
2183 if not args:
2184 args = ['']
2184 args = ['']
2185 for a in args:
2185 for a in args:
2186 completions.update(l for l in labels if l.startswith(a))
2186 completions.update(l for l in labels if l.startswith(a))
2187 ui.write('\n'.join(sorted(completions)))
2187 ui.write('\n'.join(sorted(completions)))
2188 ui.write('\n')
2188 ui.write('\n')
2189
2189
2190 @command('debugobsolete',
2190 @command('debugobsolete',
2191 [('', 'flags', 0, _('markers flag')),
2191 [('', 'flags', 0, _('markers flag')),
2192 ] + commitopts2,
2192 ] + commitopts2,
2193 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2193 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2194 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2194 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2195 """create arbitrary obsolete marker
2195 """create arbitrary obsolete marker
2196
2196
2197 With no arguments, displays the list of obsolescence markers."""
2197 With no arguments, displays the list of obsolescence markers."""
2198 def parsenodeid(s):
2198 def parsenodeid(s):
2199 try:
2199 try:
2200 # We do not use revsingle/revrange functions here to accept
2200 # We do not use revsingle/revrange functions here to accept
2201 # arbitrary node identifiers, possibly not present in the
2201 # arbitrary node identifiers, possibly not present in the
2202 # local repository.
2202 # local repository.
2203 n = bin(s)
2203 n = bin(s)
2204 if len(n) != len(nullid):
2204 if len(n) != len(nullid):
2205 raise TypeError()
2205 raise TypeError()
2206 return n
2206 return n
2207 except TypeError:
2207 except TypeError:
2208 raise util.Abort('changeset references must be full hexadecimal '
2208 raise util.Abort('changeset references must be full hexadecimal '
2209 'node identifiers')
2209 'node identifiers')
2210
2210
2211 if precursor is not None:
2211 if precursor is not None:
2212 metadata = {}
2212 metadata = {}
2213 if 'date' in opts:
2213 if 'date' in opts:
2214 metadata['date'] = opts['date']
2214 metadata['date'] = opts['date']
2215 metadata['user'] = opts['user'] or ui.username()
2215 metadata['user'] = opts['user'] or ui.username()
2216 succs = tuple(parsenodeid(succ) for succ in successors)
2216 succs = tuple(parsenodeid(succ) for succ in successors)
2217 l = repo.lock()
2217 l = repo.lock()
2218 try:
2218 try:
2219 tr = repo.transaction('debugobsolete')
2219 tr = repo.transaction('debugobsolete')
2220 try:
2220 try:
2221 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2221 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2222 opts['flags'], metadata)
2222 opts['flags'], metadata)
2223 tr.close()
2223 tr.close()
2224 finally:
2224 finally:
2225 tr.release()
2225 tr.release()
2226 finally:
2226 finally:
2227 l.release()
2227 l.release()
2228 else:
2228 else:
2229 for m in obsolete.allmarkers(repo):
2229 for m in obsolete.allmarkers(repo):
2230 ui.write(hex(m.precnode()))
2230 cmdutil.showmarker(ui, m)
2231 for repl in m.succnodes():
2232 ui.write(' ')
2233 ui.write(hex(repl))
2234 ui.write(' %X ' % m._data[2])
2235 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2236 sorted(m.metadata().items()))))
2237 ui.write('\n')
2238
2231
2239 @command('debugpathcomplete',
2232 @command('debugpathcomplete',
2240 [('f', 'full', None, _('complete an entire path')),
2233 [('f', 'full', None, _('complete an entire path')),
2241 ('n', 'normal', None, _('show only normal files')),
2234 ('n', 'normal', None, _('show only normal files')),
2242 ('a', 'added', None, _('show only added files')),
2235 ('a', 'added', None, _('show only added files')),
2243 ('r', 'removed', None, _('show only removed files'))],
2236 ('r', 'removed', None, _('show only removed files'))],
2244 _('FILESPEC...'))
2237 _('FILESPEC...'))
2245 def debugpathcomplete(ui, repo, *specs, **opts):
2238 def debugpathcomplete(ui, repo, *specs, **opts):
2246 '''complete part or all of a tracked path
2239 '''complete part or all of a tracked path
2247
2240
2248 This command supports shells that offer path name completion. It
2241 This command supports shells that offer path name completion. It
2249 currently completes only files already known to the dirstate.
2242 currently completes only files already known to the dirstate.
2250
2243
2251 Completion extends only to the next path segment unless
2244 Completion extends only to the next path segment unless
2252 --full is specified, in which case entire paths are used.'''
2245 --full is specified, in which case entire paths are used.'''
2253
2246
2254 def complete(path, acceptable):
2247 def complete(path, acceptable):
2255 dirstate = repo.dirstate
2248 dirstate = repo.dirstate
2256 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2249 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2257 rootdir = repo.root + os.sep
2250 rootdir = repo.root + os.sep
2258 if spec != repo.root and not spec.startswith(rootdir):
2251 if spec != repo.root and not spec.startswith(rootdir):
2259 return [], []
2252 return [], []
2260 if os.path.isdir(spec):
2253 if os.path.isdir(spec):
2261 spec += '/'
2254 spec += '/'
2262 spec = spec[len(rootdir):]
2255 spec = spec[len(rootdir):]
2263 fixpaths = os.sep != '/'
2256 fixpaths = os.sep != '/'
2264 if fixpaths:
2257 if fixpaths:
2265 spec = spec.replace(os.sep, '/')
2258 spec = spec.replace(os.sep, '/')
2266 speclen = len(spec)
2259 speclen = len(spec)
2267 fullpaths = opts['full']
2260 fullpaths = opts['full']
2268 files, dirs = set(), set()
2261 files, dirs = set(), set()
2269 adddir, addfile = dirs.add, files.add
2262 adddir, addfile = dirs.add, files.add
2270 for f, st in dirstate.iteritems():
2263 for f, st in dirstate.iteritems():
2271 if f.startswith(spec) and st[0] in acceptable:
2264 if f.startswith(spec) and st[0] in acceptable:
2272 if fixpaths:
2265 if fixpaths:
2273 f = f.replace('/', os.sep)
2266 f = f.replace('/', os.sep)
2274 if fullpaths:
2267 if fullpaths:
2275 addfile(f)
2268 addfile(f)
2276 continue
2269 continue
2277 s = f.find(os.sep, speclen)
2270 s = f.find(os.sep, speclen)
2278 if s >= 0:
2271 if s >= 0:
2279 adddir(f[:s])
2272 adddir(f[:s])
2280 else:
2273 else:
2281 addfile(f)
2274 addfile(f)
2282 return files, dirs
2275 return files, dirs
2283
2276
2284 acceptable = ''
2277 acceptable = ''
2285 if opts['normal']:
2278 if opts['normal']:
2286 acceptable += 'nm'
2279 acceptable += 'nm'
2287 if opts['added']:
2280 if opts['added']:
2288 acceptable += 'a'
2281 acceptable += 'a'
2289 if opts['removed']:
2282 if opts['removed']:
2290 acceptable += 'r'
2283 acceptable += 'r'
2291 cwd = repo.getcwd()
2284 cwd = repo.getcwd()
2292 if not specs:
2285 if not specs:
2293 specs = ['.']
2286 specs = ['.']
2294
2287
2295 files, dirs = set(), set()
2288 files, dirs = set(), set()
2296 for spec in specs:
2289 for spec in specs:
2297 f, d = complete(spec, acceptable or 'nmar')
2290 f, d = complete(spec, acceptable or 'nmar')
2298 files.update(f)
2291 files.update(f)
2299 dirs.update(d)
2292 dirs.update(d)
2300 files.update(dirs)
2293 files.update(dirs)
2301 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2294 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2302 ui.write('\n')
2295 ui.write('\n')
2303
2296
2304 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2297 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2305 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2298 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2306 '''access the pushkey key/value protocol
2299 '''access the pushkey key/value protocol
2307
2300
2308 With two args, list the keys in the given namespace.
2301 With two args, list the keys in the given namespace.
2309
2302
2310 With five args, set a key to new if it currently is set to old.
2303 With five args, set a key to new if it currently is set to old.
2311 Reports success or failure.
2304 Reports success or failure.
2312 '''
2305 '''
2313
2306
2314 target = hg.peer(ui, {}, repopath)
2307 target = hg.peer(ui, {}, repopath)
2315 if keyinfo:
2308 if keyinfo:
2316 key, old, new = keyinfo
2309 key, old, new = keyinfo
2317 r = target.pushkey(namespace, key, old, new)
2310 r = target.pushkey(namespace, key, old, new)
2318 ui.status(str(r) + '\n')
2311 ui.status(str(r) + '\n')
2319 return not r
2312 return not r
2320 else:
2313 else:
2321 for k, v in sorted(target.listkeys(namespace).iteritems()):
2314 for k, v in sorted(target.listkeys(namespace).iteritems()):
2322 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2315 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2323 v.encode('string-escape')))
2316 v.encode('string-escape')))
2324
2317
2325 @command('debugpvec', [], _('A B'))
2318 @command('debugpvec', [], _('A B'))
2326 def debugpvec(ui, repo, a, b=None):
2319 def debugpvec(ui, repo, a, b=None):
2327 ca = scmutil.revsingle(repo, a)
2320 ca = scmutil.revsingle(repo, a)
2328 cb = scmutil.revsingle(repo, b)
2321 cb = scmutil.revsingle(repo, b)
2329 pa = pvec.ctxpvec(ca)
2322 pa = pvec.ctxpvec(ca)
2330 pb = pvec.ctxpvec(cb)
2323 pb = pvec.ctxpvec(cb)
2331 if pa == pb:
2324 if pa == pb:
2332 rel = "="
2325 rel = "="
2333 elif pa > pb:
2326 elif pa > pb:
2334 rel = ">"
2327 rel = ">"
2335 elif pa < pb:
2328 elif pa < pb:
2336 rel = "<"
2329 rel = "<"
2337 elif pa | pb:
2330 elif pa | pb:
2338 rel = "|"
2331 rel = "|"
2339 ui.write(_("a: %s\n") % pa)
2332 ui.write(_("a: %s\n") % pa)
2340 ui.write(_("b: %s\n") % pb)
2333 ui.write(_("b: %s\n") % pb)
2341 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2334 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2342 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2335 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2343 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2336 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2344 pa.distance(pb), rel))
2337 pa.distance(pb), rel))
2345
2338
2346 @command('debugrebuilddirstate|debugrebuildstate',
2339 @command('debugrebuilddirstate|debugrebuildstate',
2347 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2340 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2348 _('[-r REV]'))
2341 _('[-r REV]'))
2349 def debugrebuilddirstate(ui, repo, rev):
2342 def debugrebuilddirstate(ui, repo, rev):
2350 """rebuild the dirstate as it would look like for the given revision
2343 """rebuild the dirstate as it would look like for the given revision
2351
2344
2352 If no revision is specified the first current parent will be used.
2345 If no revision is specified the first current parent will be used.
2353
2346
2354 The dirstate will be set to the files of the given revision.
2347 The dirstate will be set to the files of the given revision.
2355 The actual working directory content or existing dirstate
2348 The actual working directory content or existing dirstate
2356 information such as adds or removes is not considered.
2349 information such as adds or removes is not considered.
2357
2350
2358 One use of this command is to make the next :hg:`status` invocation
2351 One use of this command is to make the next :hg:`status` invocation
2359 check the actual file content.
2352 check the actual file content.
2360 """
2353 """
2361 ctx = scmutil.revsingle(repo, rev)
2354 ctx = scmutil.revsingle(repo, rev)
2362 wlock = repo.wlock()
2355 wlock = repo.wlock()
2363 try:
2356 try:
2364 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2357 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2365 finally:
2358 finally:
2366 wlock.release()
2359 wlock.release()
2367
2360
2368 @command('debugrename',
2361 @command('debugrename',
2369 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2362 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2370 _('[-r REV] FILE'))
2363 _('[-r REV] FILE'))
2371 def debugrename(ui, repo, file1, *pats, **opts):
2364 def debugrename(ui, repo, file1, *pats, **opts):
2372 """dump rename information"""
2365 """dump rename information"""
2373
2366
2374 ctx = scmutil.revsingle(repo, opts.get('rev'))
2367 ctx = scmutil.revsingle(repo, opts.get('rev'))
2375 m = scmutil.match(ctx, (file1,) + pats, opts)
2368 m = scmutil.match(ctx, (file1,) + pats, opts)
2376 for abs in ctx.walk(m):
2369 for abs in ctx.walk(m):
2377 fctx = ctx[abs]
2370 fctx = ctx[abs]
2378 o = fctx.filelog().renamed(fctx.filenode())
2371 o = fctx.filelog().renamed(fctx.filenode())
2379 rel = m.rel(abs)
2372 rel = m.rel(abs)
2380 if o:
2373 if o:
2381 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2374 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2382 else:
2375 else:
2383 ui.write(_("%s not renamed\n") % rel)
2376 ui.write(_("%s not renamed\n") % rel)
2384
2377
2385 @command('debugrevlog',
2378 @command('debugrevlog',
2386 [('c', 'changelog', False, _('open changelog')),
2379 [('c', 'changelog', False, _('open changelog')),
2387 ('m', 'manifest', False, _('open manifest')),
2380 ('m', 'manifest', False, _('open manifest')),
2388 ('d', 'dump', False, _('dump index data'))],
2381 ('d', 'dump', False, _('dump index data'))],
2389 _('-c|-m|FILE'))
2382 _('-c|-m|FILE'))
2390 def debugrevlog(ui, repo, file_=None, **opts):
2383 def debugrevlog(ui, repo, file_=None, **opts):
2391 """show data and statistics about a revlog"""
2384 """show data and statistics about a revlog"""
2392 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2385 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2393
2386
2394 if opts.get("dump"):
2387 if opts.get("dump"):
2395 numrevs = len(r)
2388 numrevs = len(r)
2396 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2389 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2397 " rawsize totalsize compression heads\n")
2390 " rawsize totalsize compression heads\n")
2398 ts = 0
2391 ts = 0
2399 heads = set()
2392 heads = set()
2400 for rev in xrange(numrevs):
2393 for rev in xrange(numrevs):
2401 dbase = r.deltaparent(rev)
2394 dbase = r.deltaparent(rev)
2402 if dbase == -1:
2395 if dbase == -1:
2403 dbase = rev
2396 dbase = rev
2404 cbase = r.chainbase(rev)
2397 cbase = r.chainbase(rev)
2405 p1, p2 = r.parentrevs(rev)
2398 p1, p2 = r.parentrevs(rev)
2406 rs = r.rawsize(rev)
2399 rs = r.rawsize(rev)
2407 ts = ts + rs
2400 ts = ts + rs
2408 heads -= set(r.parentrevs(rev))
2401 heads -= set(r.parentrevs(rev))
2409 heads.add(rev)
2402 heads.add(rev)
2410 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2403 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2411 (rev, p1, p2, r.start(rev), r.end(rev),
2404 (rev, p1, p2, r.start(rev), r.end(rev),
2412 r.start(dbase), r.start(cbase),
2405 r.start(dbase), r.start(cbase),
2413 r.start(p1), r.start(p2),
2406 r.start(p1), r.start(p2),
2414 rs, ts, ts / r.end(rev), len(heads)))
2407 rs, ts, ts / r.end(rev), len(heads)))
2415 return 0
2408 return 0
2416
2409
2417 v = r.version
2410 v = r.version
2418 format = v & 0xFFFF
2411 format = v & 0xFFFF
2419 flags = []
2412 flags = []
2420 gdelta = False
2413 gdelta = False
2421 if v & revlog.REVLOGNGINLINEDATA:
2414 if v & revlog.REVLOGNGINLINEDATA:
2422 flags.append('inline')
2415 flags.append('inline')
2423 if v & revlog.REVLOGGENERALDELTA:
2416 if v & revlog.REVLOGGENERALDELTA:
2424 gdelta = True
2417 gdelta = True
2425 flags.append('generaldelta')
2418 flags.append('generaldelta')
2426 if not flags:
2419 if not flags:
2427 flags = ['(none)']
2420 flags = ['(none)']
2428
2421
2429 nummerges = 0
2422 nummerges = 0
2430 numfull = 0
2423 numfull = 0
2431 numprev = 0
2424 numprev = 0
2432 nump1 = 0
2425 nump1 = 0
2433 nump2 = 0
2426 nump2 = 0
2434 numother = 0
2427 numother = 0
2435 nump1prev = 0
2428 nump1prev = 0
2436 nump2prev = 0
2429 nump2prev = 0
2437 chainlengths = []
2430 chainlengths = []
2438
2431
2439 datasize = [None, 0, 0L]
2432 datasize = [None, 0, 0L]
2440 fullsize = [None, 0, 0L]
2433 fullsize = [None, 0, 0L]
2441 deltasize = [None, 0, 0L]
2434 deltasize = [None, 0, 0L]
2442
2435
2443 def addsize(size, l):
2436 def addsize(size, l):
2444 if l[0] is None or size < l[0]:
2437 if l[0] is None or size < l[0]:
2445 l[0] = size
2438 l[0] = size
2446 if size > l[1]:
2439 if size > l[1]:
2447 l[1] = size
2440 l[1] = size
2448 l[2] += size
2441 l[2] += size
2449
2442
2450 numrevs = len(r)
2443 numrevs = len(r)
2451 for rev in xrange(numrevs):
2444 for rev in xrange(numrevs):
2452 p1, p2 = r.parentrevs(rev)
2445 p1, p2 = r.parentrevs(rev)
2453 delta = r.deltaparent(rev)
2446 delta = r.deltaparent(rev)
2454 if format > 0:
2447 if format > 0:
2455 addsize(r.rawsize(rev), datasize)
2448 addsize(r.rawsize(rev), datasize)
2456 if p2 != nullrev:
2449 if p2 != nullrev:
2457 nummerges += 1
2450 nummerges += 1
2458 size = r.length(rev)
2451 size = r.length(rev)
2459 if delta == nullrev:
2452 if delta == nullrev:
2460 chainlengths.append(0)
2453 chainlengths.append(0)
2461 numfull += 1
2454 numfull += 1
2462 addsize(size, fullsize)
2455 addsize(size, fullsize)
2463 else:
2456 else:
2464 chainlengths.append(chainlengths[delta] + 1)
2457 chainlengths.append(chainlengths[delta] + 1)
2465 addsize(size, deltasize)
2458 addsize(size, deltasize)
2466 if delta == rev - 1:
2459 if delta == rev - 1:
2467 numprev += 1
2460 numprev += 1
2468 if delta == p1:
2461 if delta == p1:
2469 nump1prev += 1
2462 nump1prev += 1
2470 elif delta == p2:
2463 elif delta == p2:
2471 nump2prev += 1
2464 nump2prev += 1
2472 elif delta == p1:
2465 elif delta == p1:
2473 nump1 += 1
2466 nump1 += 1
2474 elif delta == p2:
2467 elif delta == p2:
2475 nump2 += 1
2468 nump2 += 1
2476 elif delta != nullrev:
2469 elif delta != nullrev:
2477 numother += 1
2470 numother += 1
2478
2471
2479 # Adjust size min value for empty cases
2472 # Adjust size min value for empty cases
2480 for size in (datasize, fullsize, deltasize):
2473 for size in (datasize, fullsize, deltasize):
2481 if size[0] is None:
2474 if size[0] is None:
2482 size[0] = 0
2475 size[0] = 0
2483
2476
2484 numdeltas = numrevs - numfull
2477 numdeltas = numrevs - numfull
2485 numoprev = numprev - nump1prev - nump2prev
2478 numoprev = numprev - nump1prev - nump2prev
2486 totalrawsize = datasize[2]
2479 totalrawsize = datasize[2]
2487 datasize[2] /= numrevs
2480 datasize[2] /= numrevs
2488 fulltotal = fullsize[2]
2481 fulltotal = fullsize[2]
2489 fullsize[2] /= numfull
2482 fullsize[2] /= numfull
2490 deltatotal = deltasize[2]
2483 deltatotal = deltasize[2]
2491 if numrevs - numfull > 0:
2484 if numrevs - numfull > 0:
2492 deltasize[2] /= numrevs - numfull
2485 deltasize[2] /= numrevs - numfull
2493 totalsize = fulltotal + deltatotal
2486 totalsize = fulltotal + deltatotal
2494 avgchainlen = sum(chainlengths) / numrevs
2487 avgchainlen = sum(chainlengths) / numrevs
2495 compratio = totalrawsize / totalsize
2488 compratio = totalrawsize / totalsize
2496
2489
2497 basedfmtstr = '%%%dd\n'
2490 basedfmtstr = '%%%dd\n'
2498 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2491 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2499
2492
2500 def dfmtstr(max):
2493 def dfmtstr(max):
2501 return basedfmtstr % len(str(max))
2494 return basedfmtstr % len(str(max))
2502 def pcfmtstr(max, padding=0):
2495 def pcfmtstr(max, padding=0):
2503 return basepcfmtstr % (len(str(max)), ' ' * padding)
2496 return basepcfmtstr % (len(str(max)), ' ' * padding)
2504
2497
2505 def pcfmt(value, total):
2498 def pcfmt(value, total):
2506 return (value, 100 * float(value) / total)
2499 return (value, 100 * float(value) / total)
2507
2500
2508 ui.write(('format : %d\n') % format)
2501 ui.write(('format : %d\n') % format)
2509 ui.write(('flags : %s\n') % ', '.join(flags))
2502 ui.write(('flags : %s\n') % ', '.join(flags))
2510
2503
2511 ui.write('\n')
2504 ui.write('\n')
2512 fmt = pcfmtstr(totalsize)
2505 fmt = pcfmtstr(totalsize)
2513 fmt2 = dfmtstr(totalsize)
2506 fmt2 = dfmtstr(totalsize)
2514 ui.write(('revisions : ') + fmt2 % numrevs)
2507 ui.write(('revisions : ') + fmt2 % numrevs)
2515 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2508 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2516 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2509 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2517 ui.write(('revisions : ') + fmt2 % numrevs)
2510 ui.write(('revisions : ') + fmt2 % numrevs)
2518 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2511 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2519 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2512 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2520 ui.write(('revision size : ') + fmt2 % totalsize)
2513 ui.write(('revision size : ') + fmt2 % totalsize)
2521 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2514 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2522 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2515 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2523
2516
2524 ui.write('\n')
2517 ui.write('\n')
2525 fmt = dfmtstr(max(avgchainlen, compratio))
2518 fmt = dfmtstr(max(avgchainlen, compratio))
2526 ui.write(('avg chain length : ') + fmt % avgchainlen)
2519 ui.write(('avg chain length : ') + fmt % avgchainlen)
2527 ui.write(('compression ratio : ') + fmt % compratio)
2520 ui.write(('compression ratio : ') + fmt % compratio)
2528
2521
2529 if format > 0:
2522 if format > 0:
2530 ui.write('\n')
2523 ui.write('\n')
2531 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2524 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2532 % tuple(datasize))
2525 % tuple(datasize))
2533 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2526 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2534 % tuple(fullsize))
2527 % tuple(fullsize))
2535 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2528 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2536 % tuple(deltasize))
2529 % tuple(deltasize))
2537
2530
2538 if numdeltas > 0:
2531 if numdeltas > 0:
2539 ui.write('\n')
2532 ui.write('\n')
2540 fmt = pcfmtstr(numdeltas)
2533 fmt = pcfmtstr(numdeltas)
2541 fmt2 = pcfmtstr(numdeltas, 4)
2534 fmt2 = pcfmtstr(numdeltas, 4)
2542 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2535 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2543 if numprev > 0:
2536 if numprev > 0:
2544 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2537 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2545 numprev))
2538 numprev))
2546 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2539 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2547 numprev))
2540 numprev))
2548 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2541 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2549 numprev))
2542 numprev))
2550 if gdelta:
2543 if gdelta:
2551 ui.write(('deltas against p1 : ')
2544 ui.write(('deltas against p1 : ')
2552 + fmt % pcfmt(nump1, numdeltas))
2545 + fmt % pcfmt(nump1, numdeltas))
2553 ui.write(('deltas against p2 : ')
2546 ui.write(('deltas against p2 : ')
2554 + fmt % pcfmt(nump2, numdeltas))
2547 + fmt % pcfmt(nump2, numdeltas))
2555 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2548 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2556 numdeltas))
2549 numdeltas))
2557
2550
2558 @command('debugrevspec', [], ('REVSPEC'))
2551 @command('debugrevspec', [], ('REVSPEC'))
2559 def debugrevspec(ui, repo, expr):
2552 def debugrevspec(ui, repo, expr):
2560 """parse and apply a revision specification
2553 """parse and apply a revision specification
2561
2554
2562 Use --verbose to print the parsed tree before and after aliases
2555 Use --verbose to print the parsed tree before and after aliases
2563 expansion.
2556 expansion.
2564 """
2557 """
2565 if ui.verbose:
2558 if ui.verbose:
2566 tree = revset.parse(expr)[0]
2559 tree = revset.parse(expr)[0]
2567 ui.note(revset.prettyformat(tree), "\n")
2560 ui.note(revset.prettyformat(tree), "\n")
2568 newtree = revset.findaliases(ui, tree)
2561 newtree = revset.findaliases(ui, tree)
2569 if newtree != tree:
2562 if newtree != tree:
2570 ui.note(revset.prettyformat(newtree), "\n")
2563 ui.note(revset.prettyformat(newtree), "\n")
2571 func = revset.match(ui, expr)
2564 func = revset.match(ui, expr)
2572 for c in func(repo, revset.baseset(range(len(repo)))):
2565 for c in func(repo, revset.baseset(range(len(repo)))):
2573 ui.write("%s\n" % c)
2566 ui.write("%s\n" % c)
2574
2567
2575 @command('debugsetparents', [], _('REV1 [REV2]'))
2568 @command('debugsetparents', [], _('REV1 [REV2]'))
2576 def debugsetparents(ui, repo, rev1, rev2=None):
2569 def debugsetparents(ui, repo, rev1, rev2=None):
2577 """manually set the parents of the current working directory
2570 """manually set the parents of the current working directory
2578
2571
2579 This is useful for writing repository conversion tools, but should
2572 This is useful for writing repository conversion tools, but should
2580 be used with care.
2573 be used with care.
2581
2574
2582 Returns 0 on success.
2575 Returns 0 on success.
2583 """
2576 """
2584
2577
2585 r1 = scmutil.revsingle(repo, rev1).node()
2578 r1 = scmutil.revsingle(repo, rev1).node()
2586 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2579 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2587
2580
2588 wlock = repo.wlock()
2581 wlock = repo.wlock()
2589 try:
2582 try:
2590 repo.setparents(r1, r2)
2583 repo.setparents(r1, r2)
2591 finally:
2584 finally:
2592 wlock.release()
2585 wlock.release()
2593
2586
2594 @command('debugdirstate|debugstate',
2587 @command('debugdirstate|debugstate',
2595 [('', 'nodates', None, _('do not display the saved mtime')),
2588 [('', 'nodates', None, _('do not display the saved mtime')),
2596 ('', 'datesort', None, _('sort by saved mtime'))],
2589 ('', 'datesort', None, _('sort by saved mtime'))],
2597 _('[OPTION]...'))
2590 _('[OPTION]...'))
2598 def debugstate(ui, repo, nodates=None, datesort=None):
2591 def debugstate(ui, repo, nodates=None, datesort=None):
2599 """show the contents of the current dirstate"""
2592 """show the contents of the current dirstate"""
2600 timestr = ""
2593 timestr = ""
2601 showdate = not nodates
2594 showdate = not nodates
2602 if datesort:
2595 if datesort:
2603 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2596 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2604 else:
2597 else:
2605 keyfunc = None # sort by filename
2598 keyfunc = None # sort by filename
2606 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2599 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2607 if showdate:
2600 if showdate:
2608 if ent[3] == -1:
2601 if ent[3] == -1:
2609 # Pad or slice to locale representation
2602 # Pad or slice to locale representation
2610 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2603 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2611 time.localtime(0)))
2604 time.localtime(0)))
2612 timestr = 'unset'
2605 timestr = 'unset'
2613 timestr = (timestr[:locale_len] +
2606 timestr = (timestr[:locale_len] +
2614 ' ' * (locale_len - len(timestr)))
2607 ' ' * (locale_len - len(timestr)))
2615 else:
2608 else:
2616 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2609 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2617 time.localtime(ent[3]))
2610 time.localtime(ent[3]))
2618 if ent[1] & 020000:
2611 if ent[1] & 020000:
2619 mode = 'lnk'
2612 mode = 'lnk'
2620 else:
2613 else:
2621 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2614 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2622 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2615 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2623 for f in repo.dirstate.copies():
2616 for f in repo.dirstate.copies():
2624 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2617 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2625
2618
2626 @command('debugsub',
2619 @command('debugsub',
2627 [('r', 'rev', '',
2620 [('r', 'rev', '',
2628 _('revision to check'), _('REV'))],
2621 _('revision to check'), _('REV'))],
2629 _('[-r REV] [REV]'))
2622 _('[-r REV] [REV]'))
2630 def debugsub(ui, repo, rev=None):
2623 def debugsub(ui, repo, rev=None):
2631 ctx = scmutil.revsingle(repo, rev, None)
2624 ctx = scmutil.revsingle(repo, rev, None)
2632 for k, v in sorted(ctx.substate.items()):
2625 for k, v in sorted(ctx.substate.items()):
2633 ui.write(('path %s\n') % k)
2626 ui.write(('path %s\n') % k)
2634 ui.write((' source %s\n') % v[0])
2627 ui.write((' source %s\n') % v[0])
2635 ui.write((' revision %s\n') % v[1])
2628 ui.write((' revision %s\n') % v[1])
2636
2629
2637 @command('debugsuccessorssets',
2630 @command('debugsuccessorssets',
2638 [],
2631 [],
2639 _('[REV]'))
2632 _('[REV]'))
2640 def debugsuccessorssets(ui, repo, *revs):
2633 def debugsuccessorssets(ui, repo, *revs):
2641 """show set of successors for revision
2634 """show set of successors for revision
2642
2635
2643 A successors set of changeset A is a consistent group of revisions that
2636 A successors set of changeset A is a consistent group of revisions that
2644 succeed A. It contains non-obsolete changesets only.
2637 succeed A. It contains non-obsolete changesets only.
2645
2638
2646 In most cases a changeset A has a single successors set containing a single
2639 In most cases a changeset A has a single successors set containing a single
2647 successor (changeset A replaced by A').
2640 successor (changeset A replaced by A').
2648
2641
2649 A changeset that is made obsolete with no successors are called "pruned".
2642 A changeset that is made obsolete with no successors are called "pruned".
2650 Such changesets have no successors sets at all.
2643 Such changesets have no successors sets at all.
2651
2644
2652 A changeset that has been "split" will have a successors set containing
2645 A changeset that has been "split" will have a successors set containing
2653 more than one successor.
2646 more than one successor.
2654
2647
2655 A changeset that has been rewritten in multiple different ways is called
2648 A changeset that has been rewritten in multiple different ways is called
2656 "divergent". Such changesets have multiple successor sets (each of which
2649 "divergent". Such changesets have multiple successor sets (each of which
2657 may also be split, i.e. have multiple successors).
2650 may also be split, i.e. have multiple successors).
2658
2651
2659 Results are displayed as follows::
2652 Results are displayed as follows::
2660
2653
2661 <rev1>
2654 <rev1>
2662 <successors-1A>
2655 <successors-1A>
2663 <rev2>
2656 <rev2>
2664 <successors-2A>
2657 <successors-2A>
2665 <successors-2B1> <successors-2B2> <successors-2B3>
2658 <successors-2B1> <successors-2B2> <successors-2B3>
2666
2659
2667 Here rev2 has two possible (i.e. divergent) successors sets. The first
2660 Here rev2 has two possible (i.e. divergent) successors sets. The first
2668 holds one element, whereas the second holds three (i.e. the changeset has
2661 holds one element, whereas the second holds three (i.e. the changeset has
2669 been split).
2662 been split).
2670 """
2663 """
2671 # passed to successorssets caching computation from one call to another
2664 # passed to successorssets caching computation from one call to another
2672 cache = {}
2665 cache = {}
2673 ctx2str = str
2666 ctx2str = str
2674 node2str = short
2667 node2str = short
2675 if ui.debug():
2668 if ui.debug():
2676 def ctx2str(ctx):
2669 def ctx2str(ctx):
2677 return ctx.hex()
2670 return ctx.hex()
2678 node2str = hex
2671 node2str = hex
2679 for rev in scmutil.revrange(repo, revs):
2672 for rev in scmutil.revrange(repo, revs):
2680 ctx = repo[rev]
2673 ctx = repo[rev]
2681 ui.write('%s\n'% ctx2str(ctx))
2674 ui.write('%s\n'% ctx2str(ctx))
2682 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2675 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2683 if succsset:
2676 if succsset:
2684 ui.write(' ')
2677 ui.write(' ')
2685 ui.write(node2str(succsset[0]))
2678 ui.write(node2str(succsset[0]))
2686 for node in succsset[1:]:
2679 for node in succsset[1:]:
2687 ui.write(' ')
2680 ui.write(' ')
2688 ui.write(node2str(node))
2681 ui.write(node2str(node))
2689 ui.write('\n')
2682 ui.write('\n')
2690
2683
2691 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2684 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2692 def debugwalk(ui, repo, *pats, **opts):
2685 def debugwalk(ui, repo, *pats, **opts):
2693 """show how files match on given patterns"""
2686 """show how files match on given patterns"""
2694 m = scmutil.match(repo[None], pats, opts)
2687 m = scmutil.match(repo[None], pats, opts)
2695 items = list(repo.walk(m))
2688 items = list(repo.walk(m))
2696 if not items:
2689 if not items:
2697 return
2690 return
2698 f = lambda fn: fn
2691 f = lambda fn: fn
2699 if ui.configbool('ui', 'slash') and os.sep != '/':
2692 if ui.configbool('ui', 'slash') and os.sep != '/':
2700 f = lambda fn: util.normpath(fn)
2693 f = lambda fn: util.normpath(fn)
2701 fmt = 'f %%-%ds %%-%ds %%s' % (
2694 fmt = 'f %%-%ds %%-%ds %%s' % (
2702 max([len(abs) for abs in items]),
2695 max([len(abs) for abs in items]),
2703 max([len(m.rel(abs)) for abs in items]))
2696 max([len(m.rel(abs)) for abs in items]))
2704 for abs in items:
2697 for abs in items:
2705 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2698 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2706 ui.write("%s\n" % line.rstrip())
2699 ui.write("%s\n" % line.rstrip())
2707
2700
2708 @command('debugwireargs',
2701 @command('debugwireargs',
2709 [('', 'three', '', 'three'),
2702 [('', 'three', '', 'three'),
2710 ('', 'four', '', 'four'),
2703 ('', 'four', '', 'four'),
2711 ('', 'five', '', 'five'),
2704 ('', 'five', '', 'five'),
2712 ] + remoteopts,
2705 ] + remoteopts,
2713 _('REPO [OPTIONS]... [ONE [TWO]]'))
2706 _('REPO [OPTIONS]... [ONE [TWO]]'))
2714 def debugwireargs(ui, repopath, *vals, **opts):
2707 def debugwireargs(ui, repopath, *vals, **opts):
2715 repo = hg.peer(ui, opts, repopath)
2708 repo = hg.peer(ui, opts, repopath)
2716 for opt in remoteopts:
2709 for opt in remoteopts:
2717 del opts[opt[1]]
2710 del opts[opt[1]]
2718 args = {}
2711 args = {}
2719 for k, v in opts.iteritems():
2712 for k, v in opts.iteritems():
2720 if v:
2713 if v:
2721 args[k] = v
2714 args[k] = v
2722 # run twice to check that we don't mess up the stream for the next command
2715 # run twice to check that we don't mess up the stream for the next command
2723 res1 = repo.debugwireargs(*vals, **args)
2716 res1 = repo.debugwireargs(*vals, **args)
2724 res2 = repo.debugwireargs(*vals, **args)
2717 res2 = repo.debugwireargs(*vals, **args)
2725 ui.write("%s\n" % res1)
2718 ui.write("%s\n" % res1)
2726 if res1 != res2:
2719 if res1 != res2:
2727 ui.warn("%s\n" % res2)
2720 ui.warn("%s\n" % res2)
2728
2721
2729 @command('^diff',
2722 @command('^diff',
2730 [('r', 'rev', [], _('revision'), _('REV')),
2723 [('r', 'rev', [], _('revision'), _('REV')),
2731 ('c', 'change', '', _('change made by revision'), _('REV'))
2724 ('c', 'change', '', _('change made by revision'), _('REV'))
2732 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2725 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2733 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2726 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2734 def diff(ui, repo, *pats, **opts):
2727 def diff(ui, repo, *pats, **opts):
2735 """diff repository (or selected files)
2728 """diff repository (or selected files)
2736
2729
2737 Show differences between revisions for the specified files.
2730 Show differences between revisions for the specified files.
2738
2731
2739 Differences between files are shown using the unified diff format.
2732 Differences between files are shown using the unified diff format.
2740
2733
2741 .. note::
2734 .. note::
2742
2735
2743 diff may generate unexpected results for merges, as it will
2736 diff may generate unexpected results for merges, as it will
2744 default to comparing against the working directory's first
2737 default to comparing against the working directory's first
2745 parent changeset if no revisions are specified.
2738 parent changeset if no revisions are specified.
2746
2739
2747 When two revision arguments are given, then changes are shown
2740 When two revision arguments are given, then changes are shown
2748 between those revisions. If only one revision is specified then
2741 between those revisions. If only one revision is specified then
2749 that revision is compared to the working directory, and, when no
2742 that revision is compared to the working directory, and, when no
2750 revisions are specified, the working directory files are compared
2743 revisions are specified, the working directory files are compared
2751 to its parent.
2744 to its parent.
2752
2745
2753 Alternatively you can specify -c/--change with a revision to see
2746 Alternatively you can specify -c/--change with a revision to see
2754 the changes in that changeset relative to its first parent.
2747 the changes in that changeset relative to its first parent.
2755
2748
2756 Without the -a/--text option, diff will avoid generating diffs of
2749 Without the -a/--text option, diff will avoid generating diffs of
2757 files it detects as binary. With -a, diff will generate a diff
2750 files it detects as binary. With -a, diff will generate a diff
2758 anyway, probably with undesirable results.
2751 anyway, probably with undesirable results.
2759
2752
2760 Use the -g/--git option to generate diffs in the git extended diff
2753 Use the -g/--git option to generate diffs in the git extended diff
2761 format. For more information, read :hg:`help diffs`.
2754 format. For more information, read :hg:`help diffs`.
2762
2755
2763 .. container:: verbose
2756 .. container:: verbose
2764
2757
2765 Examples:
2758 Examples:
2766
2759
2767 - compare a file in the current working directory to its parent::
2760 - compare a file in the current working directory to its parent::
2768
2761
2769 hg diff foo.c
2762 hg diff foo.c
2770
2763
2771 - compare two historical versions of a directory, with rename info::
2764 - compare two historical versions of a directory, with rename info::
2772
2765
2773 hg diff --git -r 1.0:1.2 lib/
2766 hg diff --git -r 1.0:1.2 lib/
2774
2767
2775 - get change stats relative to the last change on some date::
2768 - get change stats relative to the last change on some date::
2776
2769
2777 hg diff --stat -r "date('may 2')"
2770 hg diff --stat -r "date('may 2')"
2778
2771
2779 - diff all newly-added files that contain a keyword::
2772 - diff all newly-added files that contain a keyword::
2780
2773
2781 hg diff "set:added() and grep(GNU)"
2774 hg diff "set:added() and grep(GNU)"
2782
2775
2783 - compare a revision and its parents::
2776 - compare a revision and its parents::
2784
2777
2785 hg diff -c 9353 # compare against first parent
2778 hg diff -c 9353 # compare against first parent
2786 hg diff -r 9353^:9353 # same using revset syntax
2779 hg diff -r 9353^:9353 # same using revset syntax
2787 hg diff -r 9353^2:9353 # compare against the second parent
2780 hg diff -r 9353^2:9353 # compare against the second parent
2788
2781
2789 Returns 0 on success.
2782 Returns 0 on success.
2790 """
2783 """
2791
2784
2792 revs = opts.get('rev')
2785 revs = opts.get('rev')
2793 change = opts.get('change')
2786 change = opts.get('change')
2794 stat = opts.get('stat')
2787 stat = opts.get('stat')
2795 reverse = opts.get('reverse')
2788 reverse = opts.get('reverse')
2796
2789
2797 if revs and change:
2790 if revs and change:
2798 msg = _('cannot specify --rev and --change at the same time')
2791 msg = _('cannot specify --rev and --change at the same time')
2799 raise util.Abort(msg)
2792 raise util.Abort(msg)
2800 elif change:
2793 elif change:
2801 node2 = scmutil.revsingle(repo, change, None).node()
2794 node2 = scmutil.revsingle(repo, change, None).node()
2802 node1 = repo[node2].p1().node()
2795 node1 = repo[node2].p1().node()
2803 else:
2796 else:
2804 node1, node2 = scmutil.revpair(repo, revs)
2797 node1, node2 = scmutil.revpair(repo, revs)
2805
2798
2806 if reverse:
2799 if reverse:
2807 node1, node2 = node2, node1
2800 node1, node2 = node2, node1
2808
2801
2809 diffopts = patch.diffopts(ui, opts)
2802 diffopts = patch.diffopts(ui, opts)
2810 m = scmutil.match(repo[node2], pats, opts)
2803 m = scmutil.match(repo[node2], pats, opts)
2811 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2804 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2812 listsubrepos=opts.get('subrepos'))
2805 listsubrepos=opts.get('subrepos'))
2813
2806
2814 @command('^export',
2807 @command('^export',
2815 [('o', 'output', '',
2808 [('o', 'output', '',
2816 _('print output to file with formatted name'), _('FORMAT')),
2809 _('print output to file with formatted name'), _('FORMAT')),
2817 ('', 'switch-parent', None, _('diff against the second parent')),
2810 ('', 'switch-parent', None, _('diff against the second parent')),
2818 ('r', 'rev', [], _('revisions to export'), _('REV')),
2811 ('r', 'rev', [], _('revisions to export'), _('REV')),
2819 ] + diffopts,
2812 ] + diffopts,
2820 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2813 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2821 def export(ui, repo, *changesets, **opts):
2814 def export(ui, repo, *changesets, **opts):
2822 """dump the header and diffs for one or more changesets
2815 """dump the header and diffs for one or more changesets
2823
2816
2824 Print the changeset header and diffs for one or more revisions.
2817 Print the changeset header and diffs for one or more revisions.
2825 If no revision is given, the parent of the working directory is used.
2818 If no revision is given, the parent of the working directory is used.
2826
2819
2827 The information shown in the changeset header is: author, date,
2820 The information shown in the changeset header is: author, date,
2828 branch name (if non-default), changeset hash, parent(s) and commit
2821 branch name (if non-default), changeset hash, parent(s) and commit
2829 comment.
2822 comment.
2830
2823
2831 .. note::
2824 .. note::
2832
2825
2833 export may generate unexpected diff output for merge
2826 export may generate unexpected diff output for merge
2834 changesets, as it will compare the merge changeset against its
2827 changesets, as it will compare the merge changeset against its
2835 first parent only.
2828 first parent only.
2836
2829
2837 Output may be to a file, in which case the name of the file is
2830 Output may be to a file, in which case the name of the file is
2838 given using a format string. The formatting rules are as follows:
2831 given using a format string. The formatting rules are as follows:
2839
2832
2840 :``%%``: literal "%" character
2833 :``%%``: literal "%" character
2841 :``%H``: changeset hash (40 hexadecimal digits)
2834 :``%H``: changeset hash (40 hexadecimal digits)
2842 :``%N``: number of patches being generated
2835 :``%N``: number of patches being generated
2843 :``%R``: changeset revision number
2836 :``%R``: changeset revision number
2844 :``%b``: basename of the exporting repository
2837 :``%b``: basename of the exporting repository
2845 :``%h``: short-form changeset hash (12 hexadecimal digits)
2838 :``%h``: short-form changeset hash (12 hexadecimal digits)
2846 :``%m``: first line of the commit message (only alphanumeric characters)
2839 :``%m``: first line of the commit message (only alphanumeric characters)
2847 :``%n``: zero-padded sequence number, starting at 1
2840 :``%n``: zero-padded sequence number, starting at 1
2848 :``%r``: zero-padded changeset revision number
2841 :``%r``: zero-padded changeset revision number
2849
2842
2850 Without the -a/--text option, export will avoid generating diffs
2843 Without the -a/--text option, export will avoid generating diffs
2851 of files it detects as binary. With -a, export will generate a
2844 of files it detects as binary. With -a, export will generate a
2852 diff anyway, probably with undesirable results.
2845 diff anyway, probably with undesirable results.
2853
2846
2854 Use the -g/--git option to generate diffs in the git extended diff
2847 Use the -g/--git option to generate diffs in the git extended diff
2855 format. See :hg:`help diffs` for more information.
2848 format. See :hg:`help diffs` for more information.
2856
2849
2857 With the --switch-parent option, the diff will be against the
2850 With the --switch-parent option, the diff will be against the
2858 second parent. It can be useful to review a merge.
2851 second parent. It can be useful to review a merge.
2859
2852
2860 .. container:: verbose
2853 .. container:: verbose
2861
2854
2862 Examples:
2855 Examples:
2863
2856
2864 - use export and import to transplant a bugfix to the current
2857 - use export and import to transplant a bugfix to the current
2865 branch::
2858 branch::
2866
2859
2867 hg export -r 9353 | hg import -
2860 hg export -r 9353 | hg import -
2868
2861
2869 - export all the changesets between two revisions to a file with
2862 - export all the changesets between two revisions to a file with
2870 rename information::
2863 rename information::
2871
2864
2872 hg export --git -r 123:150 > changes.txt
2865 hg export --git -r 123:150 > changes.txt
2873
2866
2874 - split outgoing changes into a series of patches with
2867 - split outgoing changes into a series of patches with
2875 descriptive names::
2868 descriptive names::
2876
2869
2877 hg export -r "outgoing()" -o "%n-%m.patch"
2870 hg export -r "outgoing()" -o "%n-%m.patch"
2878
2871
2879 Returns 0 on success.
2872 Returns 0 on success.
2880 """
2873 """
2881 changesets += tuple(opts.get('rev', []))
2874 changesets += tuple(opts.get('rev', []))
2882 if not changesets:
2875 if not changesets:
2883 changesets = ['.']
2876 changesets = ['.']
2884 revs = scmutil.revrange(repo, changesets)
2877 revs = scmutil.revrange(repo, changesets)
2885 if not revs:
2878 if not revs:
2886 raise util.Abort(_("export requires at least one changeset"))
2879 raise util.Abort(_("export requires at least one changeset"))
2887 if len(revs) > 1:
2880 if len(revs) > 1:
2888 ui.note(_('exporting patches:\n'))
2881 ui.note(_('exporting patches:\n'))
2889 else:
2882 else:
2890 ui.note(_('exporting patch:\n'))
2883 ui.note(_('exporting patch:\n'))
2891 cmdutil.export(repo, revs, template=opts.get('output'),
2884 cmdutil.export(repo, revs, template=opts.get('output'),
2892 switch_parent=opts.get('switch_parent'),
2885 switch_parent=opts.get('switch_parent'),
2893 opts=patch.diffopts(ui, opts))
2886 opts=patch.diffopts(ui, opts))
2894
2887
2895 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2888 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2896 def forget(ui, repo, *pats, **opts):
2889 def forget(ui, repo, *pats, **opts):
2897 """forget the specified files on the next commit
2890 """forget the specified files on the next commit
2898
2891
2899 Mark the specified files so they will no longer be tracked
2892 Mark the specified files so they will no longer be tracked
2900 after the next commit.
2893 after the next commit.
2901
2894
2902 This only removes files from the current branch, not from the
2895 This only removes files from the current branch, not from the
2903 entire project history, and it does not delete them from the
2896 entire project history, and it does not delete them from the
2904 working directory.
2897 working directory.
2905
2898
2906 To undo a forget before the next commit, see :hg:`add`.
2899 To undo a forget before the next commit, see :hg:`add`.
2907
2900
2908 .. container:: verbose
2901 .. container:: verbose
2909
2902
2910 Examples:
2903 Examples:
2911
2904
2912 - forget newly-added binary files::
2905 - forget newly-added binary files::
2913
2906
2914 hg forget "set:added() and binary()"
2907 hg forget "set:added() and binary()"
2915
2908
2916 - forget files that would be excluded by .hgignore::
2909 - forget files that would be excluded by .hgignore::
2917
2910
2918 hg forget "set:hgignore()"
2911 hg forget "set:hgignore()"
2919
2912
2920 Returns 0 on success.
2913 Returns 0 on success.
2921 """
2914 """
2922
2915
2923 if not pats:
2916 if not pats:
2924 raise util.Abort(_('no files specified'))
2917 raise util.Abort(_('no files specified'))
2925
2918
2926 m = scmutil.match(repo[None], pats, opts)
2919 m = scmutil.match(repo[None], pats, opts)
2927 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2920 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2928 return rejected and 1 or 0
2921 return rejected and 1 or 0
2929
2922
2930 @command(
2923 @command(
2931 'graft',
2924 'graft',
2932 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2925 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2933 ('c', 'continue', False, _('resume interrupted graft')),
2926 ('c', 'continue', False, _('resume interrupted graft')),
2934 ('e', 'edit', False, _('invoke editor on commit messages')),
2927 ('e', 'edit', False, _('invoke editor on commit messages')),
2935 ('', 'log', None, _('append graft info to log message')),
2928 ('', 'log', None, _('append graft info to log message')),
2936 ('D', 'currentdate', False,
2929 ('D', 'currentdate', False,
2937 _('record the current date as commit date')),
2930 _('record the current date as commit date')),
2938 ('U', 'currentuser', False,
2931 ('U', 'currentuser', False,
2939 _('record the current user as committer'), _('DATE'))]
2932 _('record the current user as committer'), _('DATE'))]
2940 + commitopts2 + mergetoolopts + dryrunopts,
2933 + commitopts2 + mergetoolopts + dryrunopts,
2941 _('[OPTION]... [-r] REV...'))
2934 _('[OPTION]... [-r] REV...'))
2942 def graft(ui, repo, *revs, **opts):
2935 def graft(ui, repo, *revs, **opts):
2943 '''copy changes from other branches onto the current branch
2936 '''copy changes from other branches onto the current branch
2944
2937
2945 This command uses Mercurial's merge logic to copy individual
2938 This command uses Mercurial's merge logic to copy individual
2946 changes from other branches without merging branches in the
2939 changes from other branches without merging branches in the
2947 history graph. This is sometimes known as 'backporting' or
2940 history graph. This is sometimes known as 'backporting' or
2948 'cherry-picking'. By default, graft will copy user, date, and
2941 'cherry-picking'. By default, graft will copy user, date, and
2949 description from the source changesets.
2942 description from the source changesets.
2950
2943
2951 Changesets that are ancestors of the current revision, that have
2944 Changesets that are ancestors of the current revision, that have
2952 already been grafted, or that are merges will be skipped.
2945 already been grafted, or that are merges will be skipped.
2953
2946
2954 If --log is specified, log messages will have a comment appended
2947 If --log is specified, log messages will have a comment appended
2955 of the form::
2948 of the form::
2956
2949
2957 (grafted from CHANGESETHASH)
2950 (grafted from CHANGESETHASH)
2958
2951
2959 If a graft merge results in conflicts, the graft process is
2952 If a graft merge results in conflicts, the graft process is
2960 interrupted so that the current merge can be manually resolved.
2953 interrupted so that the current merge can be manually resolved.
2961 Once all conflicts are addressed, the graft process can be
2954 Once all conflicts are addressed, the graft process can be
2962 continued with the -c/--continue option.
2955 continued with the -c/--continue option.
2963
2956
2964 .. note::
2957 .. note::
2965
2958
2966 The -c/--continue option does not reapply earlier options.
2959 The -c/--continue option does not reapply earlier options.
2967
2960
2968 .. container:: verbose
2961 .. container:: verbose
2969
2962
2970 Examples:
2963 Examples:
2971
2964
2972 - copy a single change to the stable branch and edit its description::
2965 - copy a single change to the stable branch and edit its description::
2973
2966
2974 hg update stable
2967 hg update stable
2975 hg graft --edit 9393
2968 hg graft --edit 9393
2976
2969
2977 - graft a range of changesets with one exception, updating dates::
2970 - graft a range of changesets with one exception, updating dates::
2978
2971
2979 hg graft -D "2085::2093 and not 2091"
2972 hg graft -D "2085::2093 and not 2091"
2980
2973
2981 - continue a graft after resolving conflicts::
2974 - continue a graft after resolving conflicts::
2982
2975
2983 hg graft -c
2976 hg graft -c
2984
2977
2985 - show the source of a grafted changeset::
2978 - show the source of a grafted changeset::
2986
2979
2987 hg log --debug -r .
2980 hg log --debug -r .
2988
2981
2989 Returns 0 on successful completion.
2982 Returns 0 on successful completion.
2990 '''
2983 '''
2991
2984
2992 revs = list(revs)
2985 revs = list(revs)
2993 revs.extend(opts['rev'])
2986 revs.extend(opts['rev'])
2994
2987
2995 if not opts.get('user') and opts.get('currentuser'):
2988 if not opts.get('user') and opts.get('currentuser'):
2996 opts['user'] = ui.username()
2989 opts['user'] = ui.username()
2997 if not opts.get('date') and opts.get('currentdate'):
2990 if not opts.get('date') and opts.get('currentdate'):
2998 opts['date'] = "%d %d" % util.makedate()
2991 opts['date'] = "%d %d" % util.makedate()
2999
2992
3000 editor = None
2993 editor = None
3001 if opts.get('edit'):
2994 if opts.get('edit'):
3002 editor = cmdutil.commitforceeditor
2995 editor = cmdutil.commitforceeditor
3003
2996
3004 cont = False
2997 cont = False
3005 if opts['continue']:
2998 if opts['continue']:
3006 cont = True
2999 cont = True
3007 if revs:
3000 if revs:
3008 raise util.Abort(_("can't specify --continue and revisions"))
3001 raise util.Abort(_("can't specify --continue and revisions"))
3009 # read in unfinished revisions
3002 # read in unfinished revisions
3010 try:
3003 try:
3011 nodes = repo.opener.read('graftstate').splitlines()
3004 nodes = repo.opener.read('graftstate').splitlines()
3012 revs = [repo[node].rev() for node in nodes]
3005 revs = [repo[node].rev() for node in nodes]
3013 except IOError, inst:
3006 except IOError, inst:
3014 if inst.errno != errno.ENOENT:
3007 if inst.errno != errno.ENOENT:
3015 raise
3008 raise
3016 raise util.Abort(_("no graft state found, can't continue"))
3009 raise util.Abort(_("no graft state found, can't continue"))
3017 else:
3010 else:
3018 cmdutil.checkunfinished(repo)
3011 cmdutil.checkunfinished(repo)
3019 cmdutil.bailifchanged(repo)
3012 cmdutil.bailifchanged(repo)
3020 if not revs:
3013 if not revs:
3021 raise util.Abort(_('no revisions specified'))
3014 raise util.Abort(_('no revisions specified'))
3022 revs = scmutil.revrange(repo, revs)
3015 revs = scmutil.revrange(repo, revs)
3023
3016
3024 # check for merges
3017 # check for merges
3025 for rev in repo.revs('%ld and merge()', revs):
3018 for rev in repo.revs('%ld and merge()', revs):
3026 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3019 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3027 revs.remove(rev)
3020 revs.remove(rev)
3028 if not revs:
3021 if not revs:
3029 return -1
3022 return -1
3030
3023
3031 # check for ancestors of dest branch
3024 # check for ancestors of dest branch
3032 crev = repo['.'].rev()
3025 crev = repo['.'].rev()
3033 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3026 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3034 # don't mutate while iterating, create a copy
3027 # don't mutate while iterating, create a copy
3035 for rev in list(revs):
3028 for rev in list(revs):
3036 if rev in ancestors:
3029 if rev in ancestors:
3037 ui.warn(_('skipping ancestor revision %s\n') % rev)
3030 ui.warn(_('skipping ancestor revision %s\n') % rev)
3038 revs.remove(rev)
3031 revs.remove(rev)
3039 if not revs:
3032 if not revs:
3040 return -1
3033 return -1
3041
3034
3042 # analyze revs for earlier grafts
3035 # analyze revs for earlier grafts
3043 ids = {}
3036 ids = {}
3044 for ctx in repo.set("%ld", revs):
3037 for ctx in repo.set("%ld", revs):
3045 ids[ctx.hex()] = ctx.rev()
3038 ids[ctx.hex()] = ctx.rev()
3046 n = ctx.extra().get('source')
3039 n = ctx.extra().get('source')
3047 if n:
3040 if n:
3048 ids[n] = ctx.rev()
3041 ids[n] = ctx.rev()
3049
3042
3050 # check ancestors for earlier grafts
3043 # check ancestors for earlier grafts
3051 ui.debug('scanning for duplicate grafts\n')
3044 ui.debug('scanning for duplicate grafts\n')
3052
3045
3053 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3046 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3054 ctx = repo[rev]
3047 ctx = repo[rev]
3055 n = ctx.extra().get('source')
3048 n = ctx.extra().get('source')
3056 if n in ids:
3049 if n in ids:
3057 r = repo[n].rev()
3050 r = repo[n].rev()
3058 if r in revs:
3051 if r in revs:
3059 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3052 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3060 % (r, rev))
3053 % (r, rev))
3061 revs.remove(r)
3054 revs.remove(r)
3062 elif ids[n] in revs:
3055 elif ids[n] in revs:
3063 ui.warn(_('skipping already grafted revision %s '
3056 ui.warn(_('skipping already grafted revision %s '
3064 '(%s also has origin %d)\n') % (ids[n], rev, r))
3057 '(%s also has origin %d)\n') % (ids[n], rev, r))
3065 revs.remove(ids[n])
3058 revs.remove(ids[n])
3066 elif ctx.hex() in ids:
3059 elif ctx.hex() in ids:
3067 r = ids[ctx.hex()]
3060 r = ids[ctx.hex()]
3068 ui.warn(_('skipping already grafted revision %s '
3061 ui.warn(_('skipping already grafted revision %s '
3069 '(was grafted from %d)\n') % (r, rev))
3062 '(was grafted from %d)\n') % (r, rev))
3070 revs.remove(r)
3063 revs.remove(r)
3071 if not revs:
3064 if not revs:
3072 return -1
3065 return -1
3073
3066
3074 wlock = repo.wlock()
3067 wlock = repo.wlock()
3075 try:
3068 try:
3076 current = repo['.']
3069 current = repo['.']
3077 for pos, ctx in enumerate(repo.set("%ld", revs)):
3070 for pos, ctx in enumerate(repo.set("%ld", revs)):
3078
3071
3079 ui.status(_('grafting revision %s\n') % ctx.rev())
3072 ui.status(_('grafting revision %s\n') % ctx.rev())
3080 if opts.get('dry_run'):
3073 if opts.get('dry_run'):
3081 continue
3074 continue
3082
3075
3083 source = ctx.extra().get('source')
3076 source = ctx.extra().get('source')
3084 if not source:
3077 if not source:
3085 source = ctx.hex()
3078 source = ctx.hex()
3086 extra = {'source': source}
3079 extra = {'source': source}
3087 user = ctx.user()
3080 user = ctx.user()
3088 if opts.get('user'):
3081 if opts.get('user'):
3089 user = opts['user']
3082 user = opts['user']
3090 date = ctx.date()
3083 date = ctx.date()
3091 if opts.get('date'):
3084 if opts.get('date'):
3092 date = opts['date']
3085 date = opts['date']
3093 message = ctx.description()
3086 message = ctx.description()
3094 if opts.get('log'):
3087 if opts.get('log'):
3095 message += '\n(grafted from %s)' % ctx.hex()
3088 message += '\n(grafted from %s)' % ctx.hex()
3096
3089
3097 # we don't merge the first commit when continuing
3090 # we don't merge the first commit when continuing
3098 if not cont:
3091 if not cont:
3099 # perform the graft merge with p1(rev) as 'ancestor'
3092 # perform the graft merge with p1(rev) as 'ancestor'
3100 try:
3093 try:
3101 # ui.forcemerge is an internal variable, do not document
3094 # ui.forcemerge is an internal variable, do not document
3102 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3095 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3103 stats = mergemod.update(repo, ctx.node(), True, True, False,
3096 stats = mergemod.update(repo, ctx.node(), True, True, False,
3104 ctx.p1().node())
3097 ctx.p1().node())
3105 finally:
3098 finally:
3106 repo.ui.setconfig('ui', 'forcemerge', '')
3099 repo.ui.setconfig('ui', 'forcemerge', '')
3107 # report any conflicts
3100 # report any conflicts
3108 if stats and stats[3] > 0:
3101 if stats and stats[3] > 0:
3109 # write out state for --continue
3102 # write out state for --continue
3110 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3103 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3111 repo.opener.write('graftstate', ''.join(nodelines))
3104 repo.opener.write('graftstate', ''.join(nodelines))
3112 raise util.Abort(
3105 raise util.Abort(
3113 _("unresolved conflicts, can't continue"),
3106 _("unresolved conflicts, can't continue"),
3114 hint=_('use hg resolve and hg graft --continue'))
3107 hint=_('use hg resolve and hg graft --continue'))
3115 else:
3108 else:
3116 cont = False
3109 cont = False
3117
3110
3118 # drop the second merge parent
3111 # drop the second merge parent
3119 repo.setparents(current.node(), nullid)
3112 repo.setparents(current.node(), nullid)
3120 repo.dirstate.write()
3113 repo.dirstate.write()
3121 # fix up dirstate for copies and renames
3114 # fix up dirstate for copies and renames
3122 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3115 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3123
3116
3124 # commit
3117 # commit
3125 node = repo.commit(text=message, user=user,
3118 node = repo.commit(text=message, user=user,
3126 date=date, extra=extra, editor=editor)
3119 date=date, extra=extra, editor=editor)
3127 if node is None:
3120 if node is None:
3128 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3121 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3129 else:
3122 else:
3130 current = repo[node]
3123 current = repo[node]
3131 finally:
3124 finally:
3132 wlock.release()
3125 wlock.release()
3133
3126
3134 # remove state when we complete successfully
3127 # remove state when we complete successfully
3135 if not opts.get('dry_run'):
3128 if not opts.get('dry_run'):
3136 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3129 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3137
3130
3138 return 0
3131 return 0
3139
3132
3140 @command('grep',
3133 @command('grep',
3141 [('0', 'print0', None, _('end fields with NUL')),
3134 [('0', 'print0', None, _('end fields with NUL')),
3142 ('', 'all', None, _('print all revisions that match')),
3135 ('', 'all', None, _('print all revisions that match')),
3143 ('a', 'text', None, _('treat all files as text')),
3136 ('a', 'text', None, _('treat all files as text')),
3144 ('f', 'follow', None,
3137 ('f', 'follow', None,
3145 _('follow changeset history,'
3138 _('follow changeset history,'
3146 ' or file history across copies and renames')),
3139 ' or file history across copies and renames')),
3147 ('i', 'ignore-case', None, _('ignore case when matching')),
3140 ('i', 'ignore-case', None, _('ignore case when matching')),
3148 ('l', 'files-with-matches', None,
3141 ('l', 'files-with-matches', None,
3149 _('print only filenames and revisions that match')),
3142 _('print only filenames and revisions that match')),
3150 ('n', 'line-number', None, _('print matching line numbers')),
3143 ('n', 'line-number', None, _('print matching line numbers')),
3151 ('r', 'rev', [],
3144 ('r', 'rev', [],
3152 _('only search files changed within revision range'), _('REV')),
3145 _('only search files changed within revision range'), _('REV')),
3153 ('u', 'user', None, _('list the author (long with -v)')),
3146 ('u', 'user', None, _('list the author (long with -v)')),
3154 ('d', 'date', None, _('list the date (short with -q)')),
3147 ('d', 'date', None, _('list the date (short with -q)')),
3155 ] + walkopts,
3148 ] + walkopts,
3156 _('[OPTION]... PATTERN [FILE]...'))
3149 _('[OPTION]... PATTERN [FILE]...'))
3157 def grep(ui, repo, pattern, *pats, **opts):
3150 def grep(ui, repo, pattern, *pats, **opts):
3158 """search for a pattern in specified files and revisions
3151 """search for a pattern in specified files and revisions
3159
3152
3160 Search revisions of files for a regular expression.
3153 Search revisions of files for a regular expression.
3161
3154
3162 This command behaves differently than Unix grep. It only accepts
3155 This command behaves differently than Unix grep. It only accepts
3163 Python/Perl regexps. It searches repository history, not the
3156 Python/Perl regexps. It searches repository history, not the
3164 working directory. It always prints the revision number in which a
3157 working directory. It always prints the revision number in which a
3165 match appears.
3158 match appears.
3166
3159
3167 By default, grep only prints output for the first revision of a
3160 By default, grep only prints output for the first revision of a
3168 file in which it finds a match. To get it to print every revision
3161 file in which it finds a match. To get it to print every revision
3169 that contains a change in match status ("-" for a match that
3162 that contains a change in match status ("-" for a match that
3170 becomes a non-match, or "+" for a non-match that becomes a match),
3163 becomes a non-match, or "+" for a non-match that becomes a match),
3171 use the --all flag.
3164 use the --all flag.
3172
3165
3173 Returns 0 if a match is found, 1 otherwise.
3166 Returns 0 if a match is found, 1 otherwise.
3174 """
3167 """
3175 reflags = re.M
3168 reflags = re.M
3176 if opts.get('ignore_case'):
3169 if opts.get('ignore_case'):
3177 reflags |= re.I
3170 reflags |= re.I
3178 try:
3171 try:
3179 regexp = util.compilere(pattern, reflags)
3172 regexp = util.compilere(pattern, reflags)
3180 except re.error, inst:
3173 except re.error, inst:
3181 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3174 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3182 return 1
3175 return 1
3183 sep, eol = ':', '\n'
3176 sep, eol = ':', '\n'
3184 if opts.get('print0'):
3177 if opts.get('print0'):
3185 sep = eol = '\0'
3178 sep = eol = '\0'
3186
3179
3187 getfile = util.lrucachefunc(repo.file)
3180 getfile = util.lrucachefunc(repo.file)
3188
3181
3189 def matchlines(body):
3182 def matchlines(body):
3190 begin = 0
3183 begin = 0
3191 linenum = 0
3184 linenum = 0
3192 while begin < len(body):
3185 while begin < len(body):
3193 match = regexp.search(body, begin)
3186 match = regexp.search(body, begin)
3194 if not match:
3187 if not match:
3195 break
3188 break
3196 mstart, mend = match.span()
3189 mstart, mend = match.span()
3197 linenum += body.count('\n', begin, mstart) + 1
3190 linenum += body.count('\n', begin, mstart) + 1
3198 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3191 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3199 begin = body.find('\n', mend) + 1 or len(body) + 1
3192 begin = body.find('\n', mend) + 1 or len(body) + 1
3200 lend = begin - 1
3193 lend = begin - 1
3201 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3194 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3202
3195
3203 class linestate(object):
3196 class linestate(object):
3204 def __init__(self, line, linenum, colstart, colend):
3197 def __init__(self, line, linenum, colstart, colend):
3205 self.line = line
3198 self.line = line
3206 self.linenum = linenum
3199 self.linenum = linenum
3207 self.colstart = colstart
3200 self.colstart = colstart
3208 self.colend = colend
3201 self.colend = colend
3209
3202
3210 def __hash__(self):
3203 def __hash__(self):
3211 return hash((self.linenum, self.line))
3204 return hash((self.linenum, self.line))
3212
3205
3213 def __eq__(self, other):
3206 def __eq__(self, other):
3214 return self.line == other.line
3207 return self.line == other.line
3215
3208
3216 matches = {}
3209 matches = {}
3217 copies = {}
3210 copies = {}
3218 def grepbody(fn, rev, body):
3211 def grepbody(fn, rev, body):
3219 matches[rev].setdefault(fn, [])
3212 matches[rev].setdefault(fn, [])
3220 m = matches[rev][fn]
3213 m = matches[rev][fn]
3221 for lnum, cstart, cend, line in matchlines(body):
3214 for lnum, cstart, cend, line in matchlines(body):
3222 s = linestate(line, lnum, cstart, cend)
3215 s = linestate(line, lnum, cstart, cend)
3223 m.append(s)
3216 m.append(s)
3224
3217
3225 def difflinestates(a, b):
3218 def difflinestates(a, b):
3226 sm = difflib.SequenceMatcher(None, a, b)
3219 sm = difflib.SequenceMatcher(None, a, b)
3227 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3220 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3228 if tag == 'insert':
3221 if tag == 'insert':
3229 for i in xrange(blo, bhi):
3222 for i in xrange(blo, bhi):
3230 yield ('+', b[i])
3223 yield ('+', b[i])
3231 elif tag == 'delete':
3224 elif tag == 'delete':
3232 for i in xrange(alo, ahi):
3225 for i in xrange(alo, ahi):
3233 yield ('-', a[i])
3226 yield ('-', a[i])
3234 elif tag == 'replace':
3227 elif tag == 'replace':
3235 for i in xrange(alo, ahi):
3228 for i in xrange(alo, ahi):
3236 yield ('-', a[i])
3229 yield ('-', a[i])
3237 for i in xrange(blo, bhi):
3230 for i in xrange(blo, bhi):
3238 yield ('+', b[i])
3231 yield ('+', b[i])
3239
3232
3240 def display(fn, ctx, pstates, states):
3233 def display(fn, ctx, pstates, states):
3241 rev = ctx.rev()
3234 rev = ctx.rev()
3242 datefunc = ui.quiet and util.shortdate or util.datestr
3235 datefunc = ui.quiet and util.shortdate or util.datestr
3243 found = False
3236 found = False
3244 filerevmatches = {}
3237 filerevmatches = {}
3245 def binary():
3238 def binary():
3246 flog = getfile(fn)
3239 flog = getfile(fn)
3247 return util.binary(flog.read(ctx.filenode(fn)))
3240 return util.binary(flog.read(ctx.filenode(fn)))
3248
3241
3249 if opts.get('all'):
3242 if opts.get('all'):
3250 iter = difflinestates(pstates, states)
3243 iter = difflinestates(pstates, states)
3251 else:
3244 else:
3252 iter = [('', l) for l in states]
3245 iter = [('', l) for l in states]
3253 for change, l in iter:
3246 for change, l in iter:
3254 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3247 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3255 before, match, after = None, None, None
3248 before, match, after = None, None, None
3256
3249
3257 if opts.get('line_number'):
3250 if opts.get('line_number'):
3258 cols.append((str(l.linenum), 'grep.linenumber'))
3251 cols.append((str(l.linenum), 'grep.linenumber'))
3259 if opts.get('all'):
3252 if opts.get('all'):
3260 cols.append((change, 'grep.change'))
3253 cols.append((change, 'grep.change'))
3261 if opts.get('user'):
3254 if opts.get('user'):
3262 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3255 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3263 if opts.get('date'):
3256 if opts.get('date'):
3264 cols.append((datefunc(ctx.date()), 'grep.date'))
3257 cols.append((datefunc(ctx.date()), 'grep.date'))
3265 if opts.get('files_with_matches'):
3258 if opts.get('files_with_matches'):
3266 c = (fn, rev)
3259 c = (fn, rev)
3267 if c in filerevmatches:
3260 if c in filerevmatches:
3268 continue
3261 continue
3269 filerevmatches[c] = 1
3262 filerevmatches[c] = 1
3270 else:
3263 else:
3271 before = l.line[:l.colstart]
3264 before = l.line[:l.colstart]
3272 match = l.line[l.colstart:l.colend]
3265 match = l.line[l.colstart:l.colend]
3273 after = l.line[l.colend:]
3266 after = l.line[l.colend:]
3274 for col, label in cols[:-1]:
3267 for col, label in cols[:-1]:
3275 ui.write(col, label=label)
3268 ui.write(col, label=label)
3276 ui.write(sep, label='grep.sep')
3269 ui.write(sep, label='grep.sep')
3277 ui.write(cols[-1][0], label=cols[-1][1])
3270 ui.write(cols[-1][0], label=cols[-1][1])
3278 if before is not None:
3271 if before is not None:
3279 ui.write(sep, label='grep.sep')
3272 ui.write(sep, label='grep.sep')
3280 if not opts.get('text') and binary():
3273 if not opts.get('text') and binary():
3281 ui.write(" Binary file matches")
3274 ui.write(" Binary file matches")
3282 else:
3275 else:
3283 ui.write(before)
3276 ui.write(before)
3284 ui.write(match, label='grep.match')
3277 ui.write(match, label='grep.match')
3285 ui.write(after)
3278 ui.write(after)
3286 ui.write(eol)
3279 ui.write(eol)
3287 found = True
3280 found = True
3288 return found
3281 return found
3289
3282
3290 skip = {}
3283 skip = {}
3291 revfiles = {}
3284 revfiles = {}
3292 matchfn = scmutil.match(repo[None], pats, opts)
3285 matchfn = scmutil.match(repo[None], pats, opts)
3293 found = False
3286 found = False
3294 follow = opts.get('follow')
3287 follow = opts.get('follow')
3295
3288
3296 def prep(ctx, fns):
3289 def prep(ctx, fns):
3297 rev = ctx.rev()
3290 rev = ctx.rev()
3298 pctx = ctx.p1()
3291 pctx = ctx.p1()
3299 parent = pctx.rev()
3292 parent = pctx.rev()
3300 matches.setdefault(rev, {})
3293 matches.setdefault(rev, {})
3301 matches.setdefault(parent, {})
3294 matches.setdefault(parent, {})
3302 files = revfiles.setdefault(rev, [])
3295 files = revfiles.setdefault(rev, [])
3303 for fn in fns:
3296 for fn in fns:
3304 flog = getfile(fn)
3297 flog = getfile(fn)
3305 try:
3298 try:
3306 fnode = ctx.filenode(fn)
3299 fnode = ctx.filenode(fn)
3307 except error.LookupError:
3300 except error.LookupError:
3308 continue
3301 continue
3309
3302
3310 copied = flog.renamed(fnode)
3303 copied = flog.renamed(fnode)
3311 copy = follow and copied and copied[0]
3304 copy = follow and copied and copied[0]
3312 if copy:
3305 if copy:
3313 copies.setdefault(rev, {})[fn] = copy
3306 copies.setdefault(rev, {})[fn] = copy
3314 if fn in skip:
3307 if fn in skip:
3315 if copy:
3308 if copy:
3316 skip[copy] = True
3309 skip[copy] = True
3317 continue
3310 continue
3318 files.append(fn)
3311 files.append(fn)
3319
3312
3320 if fn not in matches[rev]:
3313 if fn not in matches[rev]:
3321 grepbody(fn, rev, flog.read(fnode))
3314 grepbody(fn, rev, flog.read(fnode))
3322
3315
3323 pfn = copy or fn
3316 pfn = copy or fn
3324 if pfn not in matches[parent]:
3317 if pfn not in matches[parent]:
3325 try:
3318 try:
3326 fnode = pctx.filenode(pfn)
3319 fnode = pctx.filenode(pfn)
3327 grepbody(pfn, parent, flog.read(fnode))
3320 grepbody(pfn, parent, flog.read(fnode))
3328 except error.LookupError:
3321 except error.LookupError:
3329 pass
3322 pass
3330
3323
3331 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3324 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3332 rev = ctx.rev()
3325 rev = ctx.rev()
3333 parent = ctx.p1().rev()
3326 parent = ctx.p1().rev()
3334 for fn in sorted(revfiles.get(rev, [])):
3327 for fn in sorted(revfiles.get(rev, [])):
3335 states = matches[rev][fn]
3328 states = matches[rev][fn]
3336 copy = copies.get(rev, {}).get(fn)
3329 copy = copies.get(rev, {}).get(fn)
3337 if fn in skip:
3330 if fn in skip:
3338 if copy:
3331 if copy:
3339 skip[copy] = True
3332 skip[copy] = True
3340 continue
3333 continue
3341 pstates = matches.get(parent, {}).get(copy or fn, [])
3334 pstates = matches.get(parent, {}).get(copy or fn, [])
3342 if pstates or states:
3335 if pstates or states:
3343 r = display(fn, ctx, pstates, states)
3336 r = display(fn, ctx, pstates, states)
3344 found = found or r
3337 found = found or r
3345 if r and not opts.get('all'):
3338 if r and not opts.get('all'):
3346 skip[fn] = True
3339 skip[fn] = True
3347 if copy:
3340 if copy:
3348 skip[copy] = True
3341 skip[copy] = True
3349 del matches[rev]
3342 del matches[rev]
3350 del revfiles[rev]
3343 del revfiles[rev]
3351
3344
3352 return not found
3345 return not found
3353
3346
3354 @command('heads',
3347 @command('heads',
3355 [('r', 'rev', '',
3348 [('r', 'rev', '',
3356 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3349 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3357 ('t', 'topo', False, _('show topological heads only')),
3350 ('t', 'topo', False, _('show topological heads only')),
3358 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3351 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3359 ('c', 'closed', False, _('show normal and closed branch heads')),
3352 ('c', 'closed', False, _('show normal and closed branch heads')),
3360 ] + templateopts,
3353 ] + templateopts,
3361 _('[-ct] [-r STARTREV] [REV]...'))
3354 _('[-ct] [-r STARTREV] [REV]...'))
3362 def heads(ui, repo, *branchrevs, **opts):
3355 def heads(ui, repo, *branchrevs, **opts):
3363 """show branch heads
3356 """show branch heads
3364
3357
3365 With no arguments, show all open branch heads in the repository.
3358 With no arguments, show all open branch heads in the repository.
3366 Branch heads are changesets that have no descendants on the
3359 Branch heads are changesets that have no descendants on the
3367 same branch. They are where development generally takes place and
3360 same branch. They are where development generally takes place and
3368 are the usual targets for update and merge operations.
3361 are the usual targets for update and merge operations.
3369
3362
3370 If one or more REVs are given, only open branch heads on the
3363 If one or more REVs are given, only open branch heads on the
3371 branches associated with the specified changesets are shown. This
3364 branches associated with the specified changesets are shown. This
3372 means that you can use :hg:`heads .` to see the heads on the
3365 means that you can use :hg:`heads .` to see the heads on the
3373 currently checked-out branch.
3366 currently checked-out branch.
3374
3367
3375 If -c/--closed is specified, also show branch heads marked closed
3368 If -c/--closed is specified, also show branch heads marked closed
3376 (see :hg:`commit --close-branch`).
3369 (see :hg:`commit --close-branch`).
3377
3370
3378 If STARTREV is specified, only those heads that are descendants of
3371 If STARTREV is specified, only those heads that are descendants of
3379 STARTREV will be displayed.
3372 STARTREV will be displayed.
3380
3373
3381 If -t/--topo is specified, named branch mechanics will be ignored and only
3374 If -t/--topo is specified, named branch mechanics will be ignored and only
3382 topological heads (changesets with no children) will be shown.
3375 topological heads (changesets with no children) will be shown.
3383
3376
3384 Returns 0 if matching heads are found, 1 if not.
3377 Returns 0 if matching heads are found, 1 if not.
3385 """
3378 """
3386
3379
3387 start = None
3380 start = None
3388 if 'rev' in opts:
3381 if 'rev' in opts:
3389 start = scmutil.revsingle(repo, opts['rev'], None).node()
3382 start = scmutil.revsingle(repo, opts['rev'], None).node()
3390
3383
3391 if opts.get('topo'):
3384 if opts.get('topo'):
3392 heads = [repo[h] for h in repo.heads(start)]
3385 heads = [repo[h] for h in repo.heads(start)]
3393 else:
3386 else:
3394 heads = []
3387 heads = []
3395 for branch in repo.branchmap():
3388 for branch in repo.branchmap():
3396 heads += repo.branchheads(branch, start, opts.get('closed'))
3389 heads += repo.branchheads(branch, start, opts.get('closed'))
3397 heads = [repo[h] for h in heads]
3390 heads = [repo[h] for h in heads]
3398
3391
3399 if branchrevs:
3392 if branchrevs:
3400 branches = set(repo[br].branch() for br in branchrevs)
3393 branches = set(repo[br].branch() for br in branchrevs)
3401 heads = [h for h in heads if h.branch() in branches]
3394 heads = [h for h in heads if h.branch() in branches]
3402
3395
3403 if opts.get('active') and branchrevs:
3396 if opts.get('active') and branchrevs:
3404 dagheads = repo.heads(start)
3397 dagheads = repo.heads(start)
3405 heads = [h for h in heads if h.node() in dagheads]
3398 heads = [h for h in heads if h.node() in dagheads]
3406
3399
3407 if branchrevs:
3400 if branchrevs:
3408 haveheads = set(h.branch() for h in heads)
3401 haveheads = set(h.branch() for h in heads)
3409 if branches - haveheads:
3402 if branches - haveheads:
3410 headless = ', '.join(b for b in branches - haveheads)
3403 headless = ', '.join(b for b in branches - haveheads)
3411 msg = _('no open branch heads found on branches %s')
3404 msg = _('no open branch heads found on branches %s')
3412 if opts.get('rev'):
3405 if opts.get('rev'):
3413 msg += _(' (started at %s)') % opts['rev']
3406 msg += _(' (started at %s)') % opts['rev']
3414 ui.warn((msg + '\n') % headless)
3407 ui.warn((msg + '\n') % headless)
3415
3408
3416 if not heads:
3409 if not heads:
3417 return 1
3410 return 1
3418
3411
3419 heads = sorted(heads, key=lambda x: -x.rev())
3412 heads = sorted(heads, key=lambda x: -x.rev())
3420 displayer = cmdutil.show_changeset(ui, repo, opts)
3413 displayer = cmdutil.show_changeset(ui, repo, opts)
3421 for ctx in heads:
3414 for ctx in heads:
3422 displayer.show(ctx)
3415 displayer.show(ctx)
3423 displayer.close()
3416 displayer.close()
3424
3417
3425 @command('help',
3418 @command('help',
3426 [('e', 'extension', None, _('show only help for extensions')),
3419 [('e', 'extension', None, _('show only help for extensions')),
3427 ('c', 'command', None, _('show only help for commands')),
3420 ('c', 'command', None, _('show only help for commands')),
3428 ('k', 'keyword', '', _('show topics matching keyword')),
3421 ('k', 'keyword', '', _('show topics matching keyword')),
3429 ],
3422 ],
3430 _('[-ec] [TOPIC]'))
3423 _('[-ec] [TOPIC]'))
3431 def help_(ui, name=None, **opts):
3424 def help_(ui, name=None, **opts):
3432 """show help for a given topic or a help overview
3425 """show help for a given topic or a help overview
3433
3426
3434 With no arguments, print a list of commands with short help messages.
3427 With no arguments, print a list of commands with short help messages.
3435
3428
3436 Given a topic, extension, or command name, print help for that
3429 Given a topic, extension, or command name, print help for that
3437 topic.
3430 topic.
3438
3431
3439 Returns 0 if successful.
3432 Returns 0 if successful.
3440 """
3433 """
3441
3434
3442 textwidth = min(ui.termwidth(), 80) - 2
3435 textwidth = min(ui.termwidth(), 80) - 2
3443
3436
3444 keep = ui.verbose and ['verbose'] or []
3437 keep = ui.verbose and ['verbose'] or []
3445 text = help.help_(ui, name, **opts)
3438 text = help.help_(ui, name, **opts)
3446
3439
3447 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3440 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3448 if 'verbose' in pruned:
3441 if 'verbose' in pruned:
3449 keep.append('omitted')
3442 keep.append('omitted')
3450 else:
3443 else:
3451 keep.append('notomitted')
3444 keep.append('notomitted')
3452 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3445 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3453 ui.write(formatted)
3446 ui.write(formatted)
3454
3447
3455
3448
3456 @command('identify|id',
3449 @command('identify|id',
3457 [('r', 'rev', '',
3450 [('r', 'rev', '',
3458 _('identify the specified revision'), _('REV')),
3451 _('identify the specified revision'), _('REV')),
3459 ('n', 'num', None, _('show local revision number')),
3452 ('n', 'num', None, _('show local revision number')),
3460 ('i', 'id', None, _('show global revision id')),
3453 ('i', 'id', None, _('show global revision id')),
3461 ('b', 'branch', None, _('show branch')),
3454 ('b', 'branch', None, _('show branch')),
3462 ('t', 'tags', None, _('show tags')),
3455 ('t', 'tags', None, _('show tags')),
3463 ('B', 'bookmarks', None, _('show bookmarks')),
3456 ('B', 'bookmarks', None, _('show bookmarks')),
3464 ] + remoteopts,
3457 ] + remoteopts,
3465 _('[-nibtB] [-r REV] [SOURCE]'))
3458 _('[-nibtB] [-r REV] [SOURCE]'))
3466 def identify(ui, repo, source=None, rev=None,
3459 def identify(ui, repo, source=None, rev=None,
3467 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3460 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3468 """identify the working copy or specified revision
3461 """identify the working copy or specified revision
3469
3462
3470 Print a summary identifying the repository state at REV using one or
3463 Print a summary identifying the repository state at REV using one or
3471 two parent hash identifiers, followed by a "+" if the working
3464 two parent hash identifiers, followed by a "+" if the working
3472 directory has uncommitted changes, the branch name (if not default),
3465 directory has uncommitted changes, the branch name (if not default),
3473 a list of tags, and a list of bookmarks.
3466 a list of tags, and a list of bookmarks.
3474
3467
3475 When REV is not given, print a summary of the current state of the
3468 When REV is not given, print a summary of the current state of the
3476 repository.
3469 repository.
3477
3470
3478 Specifying a path to a repository root or Mercurial bundle will
3471 Specifying a path to a repository root or Mercurial bundle will
3479 cause lookup to operate on that repository/bundle.
3472 cause lookup to operate on that repository/bundle.
3480
3473
3481 .. container:: verbose
3474 .. container:: verbose
3482
3475
3483 Examples:
3476 Examples:
3484
3477
3485 - generate a build identifier for the working directory::
3478 - generate a build identifier for the working directory::
3486
3479
3487 hg id --id > build-id.dat
3480 hg id --id > build-id.dat
3488
3481
3489 - find the revision corresponding to a tag::
3482 - find the revision corresponding to a tag::
3490
3483
3491 hg id -n -r 1.3
3484 hg id -n -r 1.3
3492
3485
3493 - check the most recent revision of a remote repository::
3486 - check the most recent revision of a remote repository::
3494
3487
3495 hg id -r tip http://selenic.com/hg/
3488 hg id -r tip http://selenic.com/hg/
3496
3489
3497 Returns 0 if successful.
3490 Returns 0 if successful.
3498 """
3491 """
3499
3492
3500 if not repo and not source:
3493 if not repo and not source:
3501 raise util.Abort(_("there is no Mercurial repository here "
3494 raise util.Abort(_("there is no Mercurial repository here "
3502 "(.hg not found)"))
3495 "(.hg not found)"))
3503
3496
3504 hexfunc = ui.debugflag and hex or short
3497 hexfunc = ui.debugflag and hex or short
3505 default = not (num or id or branch or tags or bookmarks)
3498 default = not (num or id or branch or tags or bookmarks)
3506 output = []
3499 output = []
3507 revs = []
3500 revs = []
3508
3501
3509 if source:
3502 if source:
3510 source, branches = hg.parseurl(ui.expandpath(source))
3503 source, branches = hg.parseurl(ui.expandpath(source))
3511 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3504 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3512 repo = peer.local()
3505 repo = peer.local()
3513 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3506 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3514
3507
3515 if not repo:
3508 if not repo:
3516 if num or branch or tags:
3509 if num or branch or tags:
3517 raise util.Abort(
3510 raise util.Abort(
3518 _("can't query remote revision number, branch, or tags"))
3511 _("can't query remote revision number, branch, or tags"))
3519 if not rev and revs:
3512 if not rev and revs:
3520 rev = revs[0]
3513 rev = revs[0]
3521 if not rev:
3514 if not rev:
3522 rev = "tip"
3515 rev = "tip"
3523
3516
3524 remoterev = peer.lookup(rev)
3517 remoterev = peer.lookup(rev)
3525 if default or id:
3518 if default or id:
3526 output = [hexfunc(remoterev)]
3519 output = [hexfunc(remoterev)]
3527
3520
3528 def getbms():
3521 def getbms():
3529 bms = []
3522 bms = []
3530
3523
3531 if 'bookmarks' in peer.listkeys('namespaces'):
3524 if 'bookmarks' in peer.listkeys('namespaces'):
3532 hexremoterev = hex(remoterev)
3525 hexremoterev = hex(remoterev)
3533 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3526 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3534 if bmr == hexremoterev]
3527 if bmr == hexremoterev]
3535
3528
3536 return sorted(bms)
3529 return sorted(bms)
3537
3530
3538 if bookmarks:
3531 if bookmarks:
3539 output.extend(getbms())
3532 output.extend(getbms())
3540 elif default and not ui.quiet:
3533 elif default and not ui.quiet:
3541 # multiple bookmarks for a single parent separated by '/'
3534 # multiple bookmarks for a single parent separated by '/'
3542 bm = '/'.join(getbms())
3535 bm = '/'.join(getbms())
3543 if bm:
3536 if bm:
3544 output.append(bm)
3537 output.append(bm)
3545 else:
3538 else:
3546 if not rev:
3539 if not rev:
3547 ctx = repo[None]
3540 ctx = repo[None]
3548 parents = ctx.parents()
3541 parents = ctx.parents()
3549 changed = ""
3542 changed = ""
3550 if default or id or num:
3543 if default or id or num:
3551 if (util.any(repo.status())
3544 if (util.any(repo.status())
3552 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3545 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3553 changed = '+'
3546 changed = '+'
3554 if default or id:
3547 if default or id:
3555 output = ["%s%s" %
3548 output = ["%s%s" %
3556 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3549 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3557 if num:
3550 if num:
3558 output.append("%s%s" %
3551 output.append("%s%s" %
3559 ('+'.join([str(p.rev()) for p in parents]), changed))
3552 ('+'.join([str(p.rev()) for p in parents]), changed))
3560 else:
3553 else:
3561 ctx = scmutil.revsingle(repo, rev)
3554 ctx = scmutil.revsingle(repo, rev)
3562 if default or id:
3555 if default or id:
3563 output = [hexfunc(ctx.node())]
3556 output = [hexfunc(ctx.node())]
3564 if num:
3557 if num:
3565 output.append(str(ctx.rev()))
3558 output.append(str(ctx.rev()))
3566
3559
3567 if default and not ui.quiet:
3560 if default and not ui.quiet:
3568 b = ctx.branch()
3561 b = ctx.branch()
3569 if b != 'default':
3562 if b != 'default':
3570 output.append("(%s)" % b)
3563 output.append("(%s)" % b)
3571
3564
3572 # multiple tags for a single parent separated by '/'
3565 # multiple tags for a single parent separated by '/'
3573 t = '/'.join(ctx.tags())
3566 t = '/'.join(ctx.tags())
3574 if t:
3567 if t:
3575 output.append(t)
3568 output.append(t)
3576
3569
3577 # multiple bookmarks for a single parent separated by '/'
3570 # multiple bookmarks for a single parent separated by '/'
3578 bm = '/'.join(ctx.bookmarks())
3571 bm = '/'.join(ctx.bookmarks())
3579 if bm:
3572 if bm:
3580 output.append(bm)
3573 output.append(bm)
3581 else:
3574 else:
3582 if branch:
3575 if branch:
3583 output.append(ctx.branch())
3576 output.append(ctx.branch())
3584
3577
3585 if tags:
3578 if tags:
3586 output.extend(ctx.tags())
3579 output.extend(ctx.tags())
3587
3580
3588 if bookmarks:
3581 if bookmarks:
3589 output.extend(ctx.bookmarks())
3582 output.extend(ctx.bookmarks())
3590
3583
3591 ui.write("%s\n" % ' '.join(output))
3584 ui.write("%s\n" % ' '.join(output))
3592
3585
3593 @command('import|patch',
3586 @command('import|patch',
3594 [('p', 'strip', 1,
3587 [('p', 'strip', 1,
3595 _('directory strip option for patch. This has the same '
3588 _('directory strip option for patch. This has the same '
3596 'meaning as the corresponding patch option'), _('NUM')),
3589 'meaning as the corresponding patch option'), _('NUM')),
3597 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3590 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3598 ('e', 'edit', False, _('invoke editor on commit messages')),
3591 ('e', 'edit', False, _('invoke editor on commit messages')),
3599 ('f', 'force', None,
3592 ('f', 'force', None,
3600 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3593 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3601 ('', 'no-commit', None,
3594 ('', 'no-commit', None,
3602 _("don't commit, just update the working directory")),
3595 _("don't commit, just update the working directory")),
3603 ('', 'bypass', None,
3596 ('', 'bypass', None,
3604 _("apply patch without touching the working directory")),
3597 _("apply patch without touching the working directory")),
3605 ('', 'exact', None,
3598 ('', 'exact', None,
3606 _('apply patch to the nodes from which it was generated')),
3599 _('apply patch to the nodes from which it was generated')),
3607 ('', 'import-branch', None,
3600 ('', 'import-branch', None,
3608 _('use any branch information in patch (implied by --exact)'))] +
3601 _('use any branch information in patch (implied by --exact)'))] +
3609 commitopts + commitopts2 + similarityopts,
3602 commitopts + commitopts2 + similarityopts,
3610 _('[OPTION]... PATCH...'))
3603 _('[OPTION]... PATCH...'))
3611 def import_(ui, repo, patch1=None, *patches, **opts):
3604 def import_(ui, repo, patch1=None, *patches, **opts):
3612 """import an ordered set of patches
3605 """import an ordered set of patches
3613
3606
3614 Import a list of patches and commit them individually (unless
3607 Import a list of patches and commit them individually (unless
3615 --no-commit is specified).
3608 --no-commit is specified).
3616
3609
3617 Because import first applies changes to the working directory,
3610 Because import first applies changes to the working directory,
3618 import will abort if there are outstanding changes.
3611 import will abort if there are outstanding changes.
3619
3612
3620 You can import a patch straight from a mail message. Even patches
3613 You can import a patch straight from a mail message. Even patches
3621 as attachments work (to use the body part, it must have type
3614 as attachments work (to use the body part, it must have type
3622 text/plain or text/x-patch). From and Subject headers of email
3615 text/plain or text/x-patch). From and Subject headers of email
3623 message are used as default committer and commit message. All
3616 message are used as default committer and commit message. All
3624 text/plain body parts before first diff are added to commit
3617 text/plain body parts before first diff are added to commit
3625 message.
3618 message.
3626
3619
3627 If the imported patch was generated by :hg:`export`, user and
3620 If the imported patch was generated by :hg:`export`, user and
3628 description from patch override values from message headers and
3621 description from patch override values from message headers and
3629 body. Values given on command line with -m/--message and -u/--user
3622 body. Values given on command line with -m/--message and -u/--user
3630 override these.
3623 override these.
3631
3624
3632 If --exact is specified, import will set the working directory to
3625 If --exact is specified, import will set the working directory to
3633 the parent of each patch before applying it, and will abort if the
3626 the parent of each patch before applying it, and will abort if the
3634 resulting changeset has a different ID than the one recorded in
3627 resulting changeset has a different ID than the one recorded in
3635 the patch. This may happen due to character set problems or other
3628 the patch. This may happen due to character set problems or other
3636 deficiencies in the text patch format.
3629 deficiencies in the text patch format.
3637
3630
3638 Use --bypass to apply and commit patches directly to the
3631 Use --bypass to apply and commit patches directly to the
3639 repository, not touching the working directory. Without --exact,
3632 repository, not touching the working directory. Without --exact,
3640 patches will be applied on top of the working directory parent
3633 patches will be applied on top of the working directory parent
3641 revision.
3634 revision.
3642
3635
3643 With -s/--similarity, hg will attempt to discover renames and
3636 With -s/--similarity, hg will attempt to discover renames and
3644 copies in the patch in the same way as :hg:`addremove`.
3637 copies in the patch in the same way as :hg:`addremove`.
3645
3638
3646 To read a patch from standard input, use "-" as the patch name. If
3639 To read a patch from standard input, use "-" as the patch name. If
3647 a URL is specified, the patch will be downloaded from it.
3640 a URL is specified, the patch will be downloaded from it.
3648 See :hg:`help dates` for a list of formats valid for -d/--date.
3641 See :hg:`help dates` for a list of formats valid for -d/--date.
3649
3642
3650 .. container:: verbose
3643 .. container:: verbose
3651
3644
3652 Examples:
3645 Examples:
3653
3646
3654 - import a traditional patch from a website and detect renames::
3647 - import a traditional patch from a website and detect renames::
3655
3648
3656 hg import -s 80 http://example.com/bugfix.patch
3649 hg import -s 80 http://example.com/bugfix.patch
3657
3650
3658 - import a changeset from an hgweb server::
3651 - import a changeset from an hgweb server::
3659
3652
3660 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3653 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3661
3654
3662 - import all the patches in an Unix-style mbox::
3655 - import all the patches in an Unix-style mbox::
3663
3656
3664 hg import incoming-patches.mbox
3657 hg import incoming-patches.mbox
3665
3658
3666 - attempt to exactly restore an exported changeset (not always
3659 - attempt to exactly restore an exported changeset (not always
3667 possible)::
3660 possible)::
3668
3661
3669 hg import --exact proposed-fix.patch
3662 hg import --exact proposed-fix.patch
3670
3663
3671 Returns 0 on success.
3664 Returns 0 on success.
3672 """
3665 """
3673
3666
3674 if not patch1:
3667 if not patch1:
3675 raise util.Abort(_('need at least one patch to import'))
3668 raise util.Abort(_('need at least one patch to import'))
3676
3669
3677 patches = (patch1,) + patches
3670 patches = (patch1,) + patches
3678
3671
3679 date = opts.get('date')
3672 date = opts.get('date')
3680 if date:
3673 if date:
3681 opts['date'] = util.parsedate(date)
3674 opts['date'] = util.parsedate(date)
3682
3675
3683 editor = cmdutil.commiteditor
3676 editor = cmdutil.commiteditor
3684 if opts.get('edit'):
3677 if opts.get('edit'):
3685 editor = cmdutil.commitforceeditor
3678 editor = cmdutil.commitforceeditor
3686
3679
3687 update = not opts.get('bypass')
3680 update = not opts.get('bypass')
3688 if not update and opts.get('no_commit'):
3681 if not update and opts.get('no_commit'):
3689 raise util.Abort(_('cannot use --no-commit with --bypass'))
3682 raise util.Abort(_('cannot use --no-commit with --bypass'))
3690 try:
3683 try:
3691 sim = float(opts.get('similarity') or 0)
3684 sim = float(opts.get('similarity') or 0)
3692 except ValueError:
3685 except ValueError:
3693 raise util.Abort(_('similarity must be a number'))
3686 raise util.Abort(_('similarity must be a number'))
3694 if sim < 0 or sim > 100:
3687 if sim < 0 or sim > 100:
3695 raise util.Abort(_('similarity must be between 0 and 100'))
3688 raise util.Abort(_('similarity must be between 0 and 100'))
3696 if sim and not update:
3689 if sim and not update:
3697 raise util.Abort(_('cannot use --similarity with --bypass'))
3690 raise util.Abort(_('cannot use --similarity with --bypass'))
3698
3691
3699 if update:
3692 if update:
3700 cmdutil.checkunfinished(repo)
3693 cmdutil.checkunfinished(repo)
3701 if (opts.get('exact') or not opts.get('force')) and update:
3694 if (opts.get('exact') or not opts.get('force')) and update:
3702 cmdutil.bailifchanged(repo)
3695 cmdutil.bailifchanged(repo)
3703
3696
3704 base = opts["base"]
3697 base = opts["base"]
3705 strip = opts["strip"]
3698 strip = opts["strip"]
3706 wlock = lock = tr = None
3699 wlock = lock = tr = None
3707 msgs = []
3700 msgs = []
3708
3701
3709 def tryone(ui, hunk, parents):
3702 def tryone(ui, hunk, parents):
3710 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3703 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3711 patch.extract(ui, hunk)
3704 patch.extract(ui, hunk)
3712
3705
3713 if not tmpname:
3706 if not tmpname:
3714 return (None, None)
3707 return (None, None)
3715 msg = _('applied to working directory')
3708 msg = _('applied to working directory')
3716
3709
3717 try:
3710 try:
3718 cmdline_message = cmdutil.logmessage(ui, opts)
3711 cmdline_message = cmdutil.logmessage(ui, opts)
3719 if cmdline_message:
3712 if cmdline_message:
3720 # pickup the cmdline msg
3713 # pickup the cmdline msg
3721 message = cmdline_message
3714 message = cmdline_message
3722 elif message:
3715 elif message:
3723 # pickup the patch msg
3716 # pickup the patch msg
3724 message = message.strip()
3717 message = message.strip()
3725 else:
3718 else:
3726 # launch the editor
3719 # launch the editor
3727 message = None
3720 message = None
3728 ui.debug('message:\n%s\n' % message)
3721 ui.debug('message:\n%s\n' % message)
3729
3722
3730 if len(parents) == 1:
3723 if len(parents) == 1:
3731 parents.append(repo[nullid])
3724 parents.append(repo[nullid])
3732 if opts.get('exact'):
3725 if opts.get('exact'):
3733 if not nodeid or not p1:
3726 if not nodeid or not p1:
3734 raise util.Abort(_('not a Mercurial patch'))
3727 raise util.Abort(_('not a Mercurial patch'))
3735 p1 = repo[p1]
3728 p1 = repo[p1]
3736 p2 = repo[p2 or nullid]
3729 p2 = repo[p2 or nullid]
3737 elif p2:
3730 elif p2:
3738 try:
3731 try:
3739 p1 = repo[p1]
3732 p1 = repo[p1]
3740 p2 = repo[p2]
3733 p2 = repo[p2]
3741 # Without any options, consider p2 only if the
3734 # Without any options, consider p2 only if the
3742 # patch is being applied on top of the recorded
3735 # patch is being applied on top of the recorded
3743 # first parent.
3736 # first parent.
3744 if p1 != parents[0]:
3737 if p1 != parents[0]:
3745 p1 = parents[0]
3738 p1 = parents[0]
3746 p2 = repo[nullid]
3739 p2 = repo[nullid]
3747 except error.RepoError:
3740 except error.RepoError:
3748 p1, p2 = parents
3741 p1, p2 = parents
3749 else:
3742 else:
3750 p1, p2 = parents
3743 p1, p2 = parents
3751
3744
3752 n = None
3745 n = None
3753 if update:
3746 if update:
3754 if p1 != parents[0]:
3747 if p1 != parents[0]:
3755 hg.clean(repo, p1.node())
3748 hg.clean(repo, p1.node())
3756 if p2 != parents[1]:
3749 if p2 != parents[1]:
3757 repo.setparents(p1.node(), p2.node())
3750 repo.setparents(p1.node(), p2.node())
3758
3751
3759 if opts.get('exact') or opts.get('import_branch'):
3752 if opts.get('exact') or opts.get('import_branch'):
3760 repo.dirstate.setbranch(branch or 'default')
3753 repo.dirstate.setbranch(branch or 'default')
3761
3754
3762 files = set()
3755 files = set()
3763 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3756 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3764 eolmode=None, similarity=sim / 100.0)
3757 eolmode=None, similarity=sim / 100.0)
3765 files = list(files)
3758 files = list(files)
3766 if opts.get('no_commit'):
3759 if opts.get('no_commit'):
3767 if message:
3760 if message:
3768 msgs.append(message)
3761 msgs.append(message)
3769 else:
3762 else:
3770 if opts.get('exact') or p2:
3763 if opts.get('exact') or p2:
3771 # If you got here, you either use --force and know what
3764 # If you got here, you either use --force and know what
3772 # you are doing or used --exact or a merge patch while
3765 # you are doing or used --exact or a merge patch while
3773 # being updated to its first parent.
3766 # being updated to its first parent.
3774 m = None
3767 m = None
3775 else:
3768 else:
3776 m = scmutil.matchfiles(repo, files or [])
3769 m = scmutil.matchfiles(repo, files or [])
3777 n = repo.commit(message, opts.get('user') or user,
3770 n = repo.commit(message, opts.get('user') or user,
3778 opts.get('date') or date, match=m,
3771 opts.get('date') or date, match=m,
3779 editor=editor)
3772 editor=editor)
3780 else:
3773 else:
3781 if opts.get('exact') or opts.get('import_branch'):
3774 if opts.get('exact') or opts.get('import_branch'):
3782 branch = branch or 'default'
3775 branch = branch or 'default'
3783 else:
3776 else:
3784 branch = p1.branch()
3777 branch = p1.branch()
3785 store = patch.filestore()
3778 store = patch.filestore()
3786 try:
3779 try:
3787 files = set()
3780 files = set()
3788 try:
3781 try:
3789 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3782 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3790 files, eolmode=None)
3783 files, eolmode=None)
3791 except patch.PatchError, e:
3784 except patch.PatchError, e:
3792 raise util.Abort(str(e))
3785 raise util.Abort(str(e))
3793 memctx = context.makememctx(repo, (p1.node(), p2.node()),
3786 memctx = context.makememctx(repo, (p1.node(), p2.node()),
3794 message,
3787 message,
3795 opts.get('user') or user,
3788 opts.get('user') or user,
3796 opts.get('date') or date,
3789 opts.get('date') or date,
3797 branch, files, store,
3790 branch, files, store,
3798 editor=cmdutil.commiteditor)
3791 editor=cmdutil.commiteditor)
3799 repo.savecommitmessage(memctx.description())
3792 repo.savecommitmessage(memctx.description())
3800 n = memctx.commit()
3793 n = memctx.commit()
3801 finally:
3794 finally:
3802 store.close()
3795 store.close()
3803 if opts.get('exact') and hex(n) != nodeid:
3796 if opts.get('exact') and hex(n) != nodeid:
3804 raise util.Abort(_('patch is damaged or loses information'))
3797 raise util.Abort(_('patch is damaged or loses information'))
3805 if n:
3798 if n:
3806 # i18n: refers to a short changeset id
3799 # i18n: refers to a short changeset id
3807 msg = _('created %s') % short(n)
3800 msg = _('created %s') % short(n)
3808 return (msg, n)
3801 return (msg, n)
3809 finally:
3802 finally:
3810 os.unlink(tmpname)
3803 os.unlink(tmpname)
3811
3804
3812 try:
3805 try:
3813 try:
3806 try:
3814 wlock = repo.wlock()
3807 wlock = repo.wlock()
3815 if not opts.get('no_commit'):
3808 if not opts.get('no_commit'):
3816 lock = repo.lock()
3809 lock = repo.lock()
3817 tr = repo.transaction('import')
3810 tr = repo.transaction('import')
3818 parents = repo.parents()
3811 parents = repo.parents()
3819 for patchurl in patches:
3812 for patchurl in patches:
3820 if patchurl == '-':
3813 if patchurl == '-':
3821 ui.status(_('applying patch from stdin\n'))
3814 ui.status(_('applying patch from stdin\n'))
3822 patchfile = ui.fin
3815 patchfile = ui.fin
3823 patchurl = 'stdin' # for error message
3816 patchurl = 'stdin' # for error message
3824 else:
3817 else:
3825 patchurl = os.path.join(base, patchurl)
3818 patchurl = os.path.join(base, patchurl)
3826 ui.status(_('applying %s\n') % patchurl)
3819 ui.status(_('applying %s\n') % patchurl)
3827 patchfile = hg.openpath(ui, patchurl)
3820 patchfile = hg.openpath(ui, patchurl)
3828
3821
3829 haspatch = False
3822 haspatch = False
3830 for hunk in patch.split(patchfile):
3823 for hunk in patch.split(patchfile):
3831 (msg, node) = tryone(ui, hunk, parents)
3824 (msg, node) = tryone(ui, hunk, parents)
3832 if msg:
3825 if msg:
3833 haspatch = True
3826 haspatch = True
3834 ui.note(msg + '\n')
3827 ui.note(msg + '\n')
3835 if update or opts.get('exact'):
3828 if update or opts.get('exact'):
3836 parents = repo.parents()
3829 parents = repo.parents()
3837 else:
3830 else:
3838 parents = [repo[node]]
3831 parents = [repo[node]]
3839
3832
3840 if not haspatch:
3833 if not haspatch:
3841 raise util.Abort(_('%s: no diffs found') % patchurl)
3834 raise util.Abort(_('%s: no diffs found') % patchurl)
3842
3835
3843 if tr:
3836 if tr:
3844 tr.close()
3837 tr.close()
3845 if msgs:
3838 if msgs:
3846 repo.savecommitmessage('\n* * *\n'.join(msgs))
3839 repo.savecommitmessage('\n* * *\n'.join(msgs))
3847 except: # re-raises
3840 except: # re-raises
3848 # wlock.release() indirectly calls dirstate.write(): since
3841 # wlock.release() indirectly calls dirstate.write(): since
3849 # we're crashing, we do not want to change the working dir
3842 # we're crashing, we do not want to change the working dir
3850 # parent after all, so make sure it writes nothing
3843 # parent after all, so make sure it writes nothing
3851 repo.dirstate.invalidate()
3844 repo.dirstate.invalidate()
3852 raise
3845 raise
3853 finally:
3846 finally:
3854 if tr:
3847 if tr:
3855 tr.release()
3848 tr.release()
3856 release(lock, wlock)
3849 release(lock, wlock)
3857
3850
3858 @command('incoming|in',
3851 @command('incoming|in',
3859 [('f', 'force', None,
3852 [('f', 'force', None,
3860 _('run even if remote repository is unrelated')),
3853 _('run even if remote repository is unrelated')),
3861 ('n', 'newest-first', None, _('show newest record first')),
3854 ('n', 'newest-first', None, _('show newest record first')),
3862 ('', 'bundle', '',
3855 ('', 'bundle', '',
3863 _('file to store the bundles into'), _('FILE')),
3856 _('file to store the bundles into'), _('FILE')),
3864 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3857 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3865 ('B', 'bookmarks', False, _("compare bookmarks")),
3858 ('B', 'bookmarks', False, _("compare bookmarks")),
3866 ('b', 'branch', [],
3859 ('b', 'branch', [],
3867 _('a specific branch you would like to pull'), _('BRANCH')),
3860 _('a specific branch you would like to pull'), _('BRANCH')),
3868 ] + logopts + remoteopts + subrepoopts,
3861 ] + logopts + remoteopts + subrepoopts,
3869 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3862 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3870 def incoming(ui, repo, source="default", **opts):
3863 def incoming(ui, repo, source="default", **opts):
3871 """show new changesets found in source
3864 """show new changesets found in source
3872
3865
3873 Show new changesets found in the specified path/URL or the default
3866 Show new changesets found in the specified path/URL or the default
3874 pull location. These are the changesets that would have been pulled
3867 pull location. These are the changesets that would have been pulled
3875 if a pull at the time you issued this command.
3868 if a pull at the time you issued this command.
3876
3869
3877 For remote repository, using --bundle avoids downloading the
3870 For remote repository, using --bundle avoids downloading the
3878 changesets twice if the incoming is followed by a pull.
3871 changesets twice if the incoming is followed by a pull.
3879
3872
3880 See pull for valid source format details.
3873 See pull for valid source format details.
3881
3874
3882 Returns 0 if there are incoming changes, 1 otherwise.
3875 Returns 0 if there are incoming changes, 1 otherwise.
3883 """
3876 """
3884 if opts.get('graph'):
3877 if opts.get('graph'):
3885 cmdutil.checkunsupportedgraphflags([], opts)
3878 cmdutil.checkunsupportedgraphflags([], opts)
3886 def display(other, chlist, displayer):
3879 def display(other, chlist, displayer):
3887 revdag = cmdutil.graphrevs(other, chlist, opts)
3880 revdag = cmdutil.graphrevs(other, chlist, opts)
3888 showparents = [ctx.node() for ctx in repo[None].parents()]
3881 showparents = [ctx.node() for ctx in repo[None].parents()]
3889 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3882 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3890 graphmod.asciiedges)
3883 graphmod.asciiedges)
3891
3884
3892 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3885 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3893 return 0
3886 return 0
3894
3887
3895 if opts.get('bundle') and opts.get('subrepos'):
3888 if opts.get('bundle') and opts.get('subrepos'):
3896 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3889 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3897
3890
3898 if opts.get('bookmarks'):
3891 if opts.get('bookmarks'):
3899 source, branches = hg.parseurl(ui.expandpath(source),
3892 source, branches = hg.parseurl(ui.expandpath(source),
3900 opts.get('branch'))
3893 opts.get('branch'))
3901 other = hg.peer(repo, opts, source)
3894 other = hg.peer(repo, opts, source)
3902 if 'bookmarks' not in other.listkeys('namespaces'):
3895 if 'bookmarks' not in other.listkeys('namespaces'):
3903 ui.warn(_("remote doesn't support bookmarks\n"))
3896 ui.warn(_("remote doesn't support bookmarks\n"))
3904 return 0
3897 return 0
3905 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3898 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3906 return bookmarks.diff(ui, repo, other)
3899 return bookmarks.diff(ui, repo, other)
3907
3900
3908 repo._subtoppath = ui.expandpath(source)
3901 repo._subtoppath = ui.expandpath(source)
3909 try:
3902 try:
3910 return hg.incoming(ui, repo, source, opts)
3903 return hg.incoming(ui, repo, source, opts)
3911 finally:
3904 finally:
3912 del repo._subtoppath
3905 del repo._subtoppath
3913
3906
3914
3907
3915 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3908 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3916 def init(ui, dest=".", **opts):
3909 def init(ui, dest=".", **opts):
3917 """create a new repository in the given directory
3910 """create a new repository in the given directory
3918
3911
3919 Initialize a new repository in the given directory. If the given
3912 Initialize a new repository in the given directory. If the given
3920 directory does not exist, it will be created.
3913 directory does not exist, it will be created.
3921
3914
3922 If no directory is given, the current directory is used.
3915 If no directory is given, the current directory is used.
3923
3916
3924 It is possible to specify an ``ssh://`` URL as the destination.
3917 It is possible to specify an ``ssh://`` URL as the destination.
3925 See :hg:`help urls` for more information.
3918 See :hg:`help urls` for more information.
3926
3919
3927 Returns 0 on success.
3920 Returns 0 on success.
3928 """
3921 """
3929 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3922 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3930
3923
3931 @command('locate',
3924 @command('locate',
3932 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3925 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3933 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3926 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3934 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3927 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3935 ] + walkopts,
3928 ] + walkopts,
3936 _('[OPTION]... [PATTERN]...'))
3929 _('[OPTION]... [PATTERN]...'))
3937 def locate(ui, repo, *pats, **opts):
3930 def locate(ui, repo, *pats, **opts):
3938 """locate files matching specific patterns
3931 """locate files matching specific patterns
3939
3932
3940 Print files under Mercurial control in the working directory whose
3933 Print files under Mercurial control in the working directory whose
3941 names match the given patterns.
3934 names match the given patterns.
3942
3935
3943 By default, this command searches all directories in the working
3936 By default, this command searches all directories in the working
3944 directory. To search just the current directory and its
3937 directory. To search just the current directory and its
3945 subdirectories, use "--include .".
3938 subdirectories, use "--include .".
3946
3939
3947 If no patterns are given to match, this command prints the names
3940 If no patterns are given to match, this command prints the names
3948 of all files under Mercurial control in the working directory.
3941 of all files under Mercurial control in the working directory.
3949
3942
3950 If you want to feed the output of this command into the "xargs"
3943 If you want to feed the output of this command into the "xargs"
3951 command, use the -0 option to both this command and "xargs". This
3944 command, use the -0 option to both this command and "xargs". This
3952 will avoid the problem of "xargs" treating single filenames that
3945 will avoid the problem of "xargs" treating single filenames that
3953 contain whitespace as multiple filenames.
3946 contain whitespace as multiple filenames.
3954
3947
3955 Returns 0 if a match is found, 1 otherwise.
3948 Returns 0 if a match is found, 1 otherwise.
3956 """
3949 """
3957 end = opts.get('print0') and '\0' or '\n'
3950 end = opts.get('print0') and '\0' or '\n'
3958 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3951 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3959
3952
3960 ret = 1
3953 ret = 1
3961 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3954 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3962 m.bad = lambda x, y: False
3955 m.bad = lambda x, y: False
3963 for abs in repo[rev].walk(m):
3956 for abs in repo[rev].walk(m):
3964 if not rev and abs not in repo.dirstate:
3957 if not rev and abs not in repo.dirstate:
3965 continue
3958 continue
3966 if opts.get('fullpath'):
3959 if opts.get('fullpath'):
3967 ui.write(repo.wjoin(abs), end)
3960 ui.write(repo.wjoin(abs), end)
3968 else:
3961 else:
3969 ui.write(((pats and m.rel(abs)) or abs), end)
3962 ui.write(((pats and m.rel(abs)) or abs), end)
3970 ret = 0
3963 ret = 0
3971
3964
3972 return ret
3965 return ret
3973
3966
3974 @command('^log|history',
3967 @command('^log|history',
3975 [('f', 'follow', None,
3968 [('f', 'follow', None,
3976 _('follow changeset history, or file history across copies and renames')),
3969 _('follow changeset history, or file history across copies and renames')),
3977 ('', 'follow-first', None,
3970 ('', 'follow-first', None,
3978 _('only follow the first parent of merge changesets (DEPRECATED)')),
3971 _('only follow the first parent of merge changesets (DEPRECATED)')),
3979 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3972 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3980 ('C', 'copies', None, _('show copied files')),
3973 ('C', 'copies', None, _('show copied files')),
3981 ('k', 'keyword', [],
3974 ('k', 'keyword', [],
3982 _('do case-insensitive search for a given text'), _('TEXT')),
3975 _('do case-insensitive search for a given text'), _('TEXT')),
3983 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3976 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3984 ('', 'removed', None, _('include revisions where files were removed')),
3977 ('', 'removed', None, _('include revisions where files were removed')),
3985 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3978 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3986 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3979 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3987 ('', 'only-branch', [],
3980 ('', 'only-branch', [],
3988 _('show only changesets within the given named branch (DEPRECATED)'),
3981 _('show only changesets within the given named branch (DEPRECATED)'),
3989 _('BRANCH')),
3982 _('BRANCH')),
3990 ('b', 'branch', [],
3983 ('b', 'branch', [],
3991 _('show changesets within the given named branch'), _('BRANCH')),
3984 _('show changesets within the given named branch'), _('BRANCH')),
3992 ('P', 'prune', [],
3985 ('P', 'prune', [],
3993 _('do not display revision or any of its ancestors'), _('REV')),
3986 _('do not display revision or any of its ancestors'), _('REV')),
3994 ] + logopts + walkopts,
3987 ] + logopts + walkopts,
3995 _('[OPTION]... [FILE]'))
3988 _('[OPTION]... [FILE]'))
3996 def log(ui, repo, *pats, **opts):
3989 def log(ui, repo, *pats, **opts):
3997 """show revision history of entire repository or files
3990 """show revision history of entire repository or files
3998
3991
3999 Print the revision history of the specified files or the entire
3992 Print the revision history of the specified files or the entire
4000 project.
3993 project.
4001
3994
4002 If no revision range is specified, the default is ``tip:0`` unless
3995 If no revision range is specified, the default is ``tip:0`` unless
4003 --follow is set, in which case the working directory parent is
3996 --follow is set, in which case the working directory parent is
4004 used as the starting revision.
3997 used as the starting revision.
4005
3998
4006 File history is shown without following rename or copy history of
3999 File history is shown without following rename or copy history of
4007 files. Use -f/--follow with a filename to follow history across
4000 files. Use -f/--follow with a filename to follow history across
4008 renames and copies. --follow without a filename will only show
4001 renames and copies. --follow without a filename will only show
4009 ancestors or descendants of the starting revision.
4002 ancestors or descendants of the starting revision.
4010
4003
4011 By default this command prints revision number and changeset id,
4004 By default this command prints revision number and changeset id,
4012 tags, non-trivial parents, user, date and time, and a summary for
4005 tags, non-trivial parents, user, date and time, and a summary for
4013 each commit. When the -v/--verbose switch is used, the list of
4006 each commit. When the -v/--verbose switch is used, the list of
4014 changed files and full commit message are shown.
4007 changed files and full commit message are shown.
4015
4008
4016 .. note::
4009 .. note::
4017
4010
4018 log -p/--patch may generate unexpected diff output for merge
4011 log -p/--patch may generate unexpected diff output for merge
4019 changesets, as it will only compare the merge changeset against
4012 changesets, as it will only compare the merge changeset against
4020 its first parent. Also, only files different from BOTH parents
4013 its first parent. Also, only files different from BOTH parents
4021 will appear in files:.
4014 will appear in files:.
4022
4015
4023 .. note::
4016 .. note::
4024
4017
4025 for performance reasons, log FILE may omit duplicate changes
4018 for performance reasons, log FILE may omit duplicate changes
4026 made on branches and will not show deletions. To see all
4019 made on branches and will not show deletions. To see all
4027 changes including duplicates and deletions, use the --removed
4020 changes including duplicates and deletions, use the --removed
4028 switch.
4021 switch.
4029
4022
4030 .. container:: verbose
4023 .. container:: verbose
4031
4024
4032 Some examples:
4025 Some examples:
4033
4026
4034 - changesets with full descriptions and file lists::
4027 - changesets with full descriptions and file lists::
4035
4028
4036 hg log -v
4029 hg log -v
4037
4030
4038 - changesets ancestral to the working directory::
4031 - changesets ancestral to the working directory::
4039
4032
4040 hg log -f
4033 hg log -f
4041
4034
4042 - last 10 commits on the current branch::
4035 - last 10 commits on the current branch::
4043
4036
4044 hg log -l 10 -b .
4037 hg log -l 10 -b .
4045
4038
4046 - changesets showing all modifications of a file, including removals::
4039 - changesets showing all modifications of a file, including removals::
4047
4040
4048 hg log --removed file.c
4041 hg log --removed file.c
4049
4042
4050 - all changesets that touch a directory, with diffs, excluding merges::
4043 - all changesets that touch a directory, with diffs, excluding merges::
4051
4044
4052 hg log -Mp lib/
4045 hg log -Mp lib/
4053
4046
4054 - all revision numbers that match a keyword::
4047 - all revision numbers that match a keyword::
4055
4048
4056 hg log -k bug --template "{rev}\\n"
4049 hg log -k bug --template "{rev}\\n"
4057
4050
4058 - check if a given changeset is included is a tagged release::
4051 - check if a given changeset is included is a tagged release::
4059
4052
4060 hg log -r "a21ccf and ancestor(1.9)"
4053 hg log -r "a21ccf and ancestor(1.9)"
4061
4054
4062 - find all changesets by some user in a date range::
4055 - find all changesets by some user in a date range::
4063
4056
4064 hg log -k alice -d "may 2008 to jul 2008"
4057 hg log -k alice -d "may 2008 to jul 2008"
4065
4058
4066 - summary of all changesets after the last tag::
4059 - summary of all changesets after the last tag::
4067
4060
4068 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4061 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4069
4062
4070 See :hg:`help dates` for a list of formats valid for -d/--date.
4063 See :hg:`help dates` for a list of formats valid for -d/--date.
4071
4064
4072 See :hg:`help revisions` and :hg:`help revsets` for more about
4065 See :hg:`help revisions` and :hg:`help revsets` for more about
4073 specifying revisions.
4066 specifying revisions.
4074
4067
4075 See :hg:`help templates` for more about pre-packaged styles and
4068 See :hg:`help templates` for more about pre-packaged styles and
4076 specifying custom templates.
4069 specifying custom templates.
4077
4070
4078 Returns 0 on success.
4071 Returns 0 on success.
4079 """
4072 """
4080 if opts.get('graph'):
4073 if opts.get('graph'):
4081 return cmdutil.graphlog(ui, repo, *pats, **opts)
4074 return cmdutil.graphlog(ui, repo, *pats, **opts)
4082
4075
4083 matchfn = scmutil.match(repo[None], pats, opts)
4076 matchfn = scmutil.match(repo[None], pats, opts)
4084 limit = cmdutil.loglimit(opts)
4077 limit = cmdutil.loglimit(opts)
4085 count = 0
4078 count = 0
4086
4079
4087 getrenamed, endrev = None, None
4080 getrenamed, endrev = None, None
4088 if opts.get('copies'):
4081 if opts.get('copies'):
4089 if opts.get('rev'):
4082 if opts.get('rev'):
4090 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4083 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4091 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4084 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4092
4085
4093 df = False
4086 df = False
4094 if opts.get("date"):
4087 if opts.get("date"):
4095 df = util.matchdate(opts["date"])
4088 df = util.matchdate(opts["date"])
4096
4089
4097 branches = opts.get('branch', []) + opts.get('only_branch', [])
4090 branches = opts.get('branch', []) + opts.get('only_branch', [])
4098 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4091 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4099
4092
4100 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4093 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4101 def prep(ctx, fns):
4094 def prep(ctx, fns):
4102 rev = ctx.rev()
4095 rev = ctx.rev()
4103 parents = [p for p in repo.changelog.parentrevs(rev)
4096 parents = [p for p in repo.changelog.parentrevs(rev)
4104 if p != nullrev]
4097 if p != nullrev]
4105 if opts.get('no_merges') and len(parents) == 2:
4098 if opts.get('no_merges') and len(parents) == 2:
4106 return
4099 return
4107 if opts.get('only_merges') and len(parents) != 2:
4100 if opts.get('only_merges') and len(parents) != 2:
4108 return
4101 return
4109 if opts.get('branch') and ctx.branch() not in opts['branch']:
4102 if opts.get('branch') and ctx.branch() not in opts['branch']:
4110 return
4103 return
4111 if df and not df(ctx.date()[0]):
4104 if df and not df(ctx.date()[0]):
4112 return
4105 return
4113
4106
4114 lower = encoding.lower
4107 lower = encoding.lower
4115 if opts.get('user'):
4108 if opts.get('user'):
4116 luser = lower(ctx.user())
4109 luser = lower(ctx.user())
4117 for k in [lower(x) for x in opts['user']]:
4110 for k in [lower(x) for x in opts['user']]:
4118 if (k in luser):
4111 if (k in luser):
4119 break
4112 break
4120 else:
4113 else:
4121 return
4114 return
4122 if opts.get('keyword'):
4115 if opts.get('keyword'):
4123 luser = lower(ctx.user())
4116 luser = lower(ctx.user())
4124 ldesc = lower(ctx.description())
4117 ldesc = lower(ctx.description())
4125 lfiles = lower(" ".join(ctx.files()))
4118 lfiles = lower(" ".join(ctx.files()))
4126 for k in [lower(x) for x in opts['keyword']]:
4119 for k in [lower(x) for x in opts['keyword']]:
4127 if (k in luser or k in ldesc or k in lfiles):
4120 if (k in luser or k in ldesc or k in lfiles):
4128 break
4121 break
4129 else:
4122 else:
4130 return
4123 return
4131
4124
4132 copies = None
4125 copies = None
4133 if getrenamed is not None and rev:
4126 if getrenamed is not None and rev:
4134 copies = []
4127 copies = []
4135 for fn in ctx.files():
4128 for fn in ctx.files():
4136 rename = getrenamed(fn, rev)
4129 rename = getrenamed(fn, rev)
4137 if rename:
4130 if rename:
4138 copies.append((fn, rename[0]))
4131 copies.append((fn, rename[0]))
4139
4132
4140 revmatchfn = None
4133 revmatchfn = None
4141 if opts.get('patch') or opts.get('stat'):
4134 if opts.get('patch') or opts.get('stat'):
4142 if opts.get('follow') or opts.get('follow_first'):
4135 if opts.get('follow') or opts.get('follow_first'):
4143 # note: this might be wrong when following through merges
4136 # note: this might be wrong when following through merges
4144 revmatchfn = scmutil.match(repo[None], fns, default='path')
4137 revmatchfn = scmutil.match(repo[None], fns, default='path')
4145 else:
4138 else:
4146 revmatchfn = matchfn
4139 revmatchfn = matchfn
4147
4140
4148 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4141 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4149
4142
4150 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4143 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4151 if displayer.flush(ctx.rev()):
4144 if displayer.flush(ctx.rev()):
4152 count += 1
4145 count += 1
4153 if count == limit:
4146 if count == limit:
4154 break
4147 break
4155 displayer.close()
4148 displayer.close()
4156
4149
4157 @command('manifest',
4150 @command('manifest',
4158 [('r', 'rev', '', _('revision to display'), _('REV')),
4151 [('r', 'rev', '', _('revision to display'), _('REV')),
4159 ('', 'all', False, _("list files from all revisions"))],
4152 ('', 'all', False, _("list files from all revisions"))],
4160 _('[-r REV]'))
4153 _('[-r REV]'))
4161 def manifest(ui, repo, node=None, rev=None, **opts):
4154 def manifest(ui, repo, node=None, rev=None, **opts):
4162 """output the current or given revision of the project manifest
4155 """output the current or given revision of the project manifest
4163
4156
4164 Print a list of version controlled files for the given revision.
4157 Print a list of version controlled files for the given revision.
4165 If no revision is given, the first parent of the working directory
4158 If no revision is given, the first parent of the working directory
4166 is used, or the null revision if no revision is checked out.
4159 is used, or the null revision if no revision is checked out.
4167
4160
4168 With -v, print file permissions, symlink and executable bits.
4161 With -v, print file permissions, symlink and executable bits.
4169 With --debug, print file revision hashes.
4162 With --debug, print file revision hashes.
4170
4163
4171 If option --all is specified, the list of all files from all revisions
4164 If option --all is specified, the list of all files from all revisions
4172 is printed. This includes deleted and renamed files.
4165 is printed. This includes deleted and renamed files.
4173
4166
4174 Returns 0 on success.
4167 Returns 0 on success.
4175 """
4168 """
4176
4169
4177 fm = ui.formatter('manifest', opts)
4170 fm = ui.formatter('manifest', opts)
4178
4171
4179 if opts.get('all'):
4172 if opts.get('all'):
4180 if rev or node:
4173 if rev or node:
4181 raise util.Abort(_("can't specify a revision with --all"))
4174 raise util.Abort(_("can't specify a revision with --all"))
4182
4175
4183 res = []
4176 res = []
4184 prefix = "data/"
4177 prefix = "data/"
4185 suffix = ".i"
4178 suffix = ".i"
4186 plen = len(prefix)
4179 plen = len(prefix)
4187 slen = len(suffix)
4180 slen = len(suffix)
4188 lock = repo.lock()
4181 lock = repo.lock()
4189 try:
4182 try:
4190 for fn, b, size in repo.store.datafiles():
4183 for fn, b, size in repo.store.datafiles():
4191 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4184 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4192 res.append(fn[plen:-slen])
4185 res.append(fn[plen:-slen])
4193 finally:
4186 finally:
4194 lock.release()
4187 lock.release()
4195 for f in res:
4188 for f in res:
4196 fm.startitem()
4189 fm.startitem()
4197 fm.write("path", '%s\n', f)
4190 fm.write("path", '%s\n', f)
4198 fm.end()
4191 fm.end()
4199 return
4192 return
4200
4193
4201 if rev and node:
4194 if rev and node:
4202 raise util.Abort(_("please specify just one revision"))
4195 raise util.Abort(_("please specify just one revision"))
4203
4196
4204 if not node:
4197 if not node:
4205 node = rev
4198 node = rev
4206
4199
4207 char = {'l': '@', 'x': '*', '': ''}
4200 char = {'l': '@', 'x': '*', '': ''}
4208 mode = {'l': '644', 'x': '755', '': '644'}
4201 mode = {'l': '644', 'x': '755', '': '644'}
4209 ctx = scmutil.revsingle(repo, node)
4202 ctx = scmutil.revsingle(repo, node)
4210 mf = ctx.manifest()
4203 mf = ctx.manifest()
4211 for f in ctx:
4204 for f in ctx:
4212 fm.startitem()
4205 fm.startitem()
4213 fl = ctx[f].flags()
4206 fl = ctx[f].flags()
4214 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4207 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4215 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4208 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4216 fm.write('path', '%s\n', f)
4209 fm.write('path', '%s\n', f)
4217 fm.end()
4210 fm.end()
4218
4211
4219 @command('^merge',
4212 @command('^merge',
4220 [('f', 'force', None,
4213 [('f', 'force', None,
4221 _('force a merge including outstanding changes (DEPRECATED)')),
4214 _('force a merge including outstanding changes (DEPRECATED)')),
4222 ('r', 'rev', '', _('revision to merge'), _('REV')),
4215 ('r', 'rev', '', _('revision to merge'), _('REV')),
4223 ('P', 'preview', None,
4216 ('P', 'preview', None,
4224 _('review revisions to merge (no merge is performed)'))
4217 _('review revisions to merge (no merge is performed)'))
4225 ] + mergetoolopts,
4218 ] + mergetoolopts,
4226 _('[-P] [-f] [[-r] REV]'))
4219 _('[-P] [-f] [[-r] REV]'))
4227 def merge(ui, repo, node=None, **opts):
4220 def merge(ui, repo, node=None, **opts):
4228 """merge working directory with another revision
4221 """merge working directory with another revision
4229
4222
4230 The current working directory is updated with all changes made in
4223 The current working directory is updated with all changes made in
4231 the requested revision since the last common predecessor revision.
4224 the requested revision since the last common predecessor revision.
4232
4225
4233 Files that changed between either parent are marked as changed for
4226 Files that changed between either parent are marked as changed for
4234 the next commit and a commit must be performed before any further
4227 the next commit and a commit must be performed before any further
4235 updates to the repository are allowed. The next commit will have
4228 updates to the repository are allowed. The next commit will have
4236 two parents.
4229 two parents.
4237
4230
4238 ``--tool`` can be used to specify the merge tool used for file
4231 ``--tool`` can be used to specify the merge tool used for file
4239 merges. It overrides the HGMERGE environment variable and your
4232 merges. It overrides the HGMERGE environment variable and your
4240 configuration files. See :hg:`help merge-tools` for options.
4233 configuration files. See :hg:`help merge-tools` for options.
4241
4234
4242 If no revision is specified, the working directory's parent is a
4235 If no revision is specified, the working directory's parent is a
4243 head revision, and the current branch contains exactly one other
4236 head revision, and the current branch contains exactly one other
4244 head, the other head is merged with by default. Otherwise, an
4237 head, the other head is merged with by default. Otherwise, an
4245 explicit revision with which to merge with must be provided.
4238 explicit revision with which to merge with must be provided.
4246
4239
4247 :hg:`resolve` must be used to resolve unresolved files.
4240 :hg:`resolve` must be used to resolve unresolved files.
4248
4241
4249 To undo an uncommitted merge, use :hg:`update --clean .` which
4242 To undo an uncommitted merge, use :hg:`update --clean .` which
4250 will check out a clean copy of the original merge parent, losing
4243 will check out a clean copy of the original merge parent, losing
4251 all changes.
4244 all changes.
4252
4245
4253 Returns 0 on success, 1 if there are unresolved files.
4246 Returns 0 on success, 1 if there are unresolved files.
4254 """
4247 """
4255
4248
4256 if opts.get('rev') and node:
4249 if opts.get('rev') and node:
4257 raise util.Abort(_("please specify just one revision"))
4250 raise util.Abort(_("please specify just one revision"))
4258 if not node:
4251 if not node:
4259 node = opts.get('rev')
4252 node = opts.get('rev')
4260
4253
4261 if node:
4254 if node:
4262 node = scmutil.revsingle(repo, node).node()
4255 node = scmutil.revsingle(repo, node).node()
4263
4256
4264 if not node and repo._bookmarkcurrent:
4257 if not node and repo._bookmarkcurrent:
4265 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4258 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4266 curhead = repo[repo._bookmarkcurrent].node()
4259 curhead = repo[repo._bookmarkcurrent].node()
4267 if len(bmheads) == 2:
4260 if len(bmheads) == 2:
4268 if curhead == bmheads[0]:
4261 if curhead == bmheads[0]:
4269 node = bmheads[1]
4262 node = bmheads[1]
4270 else:
4263 else:
4271 node = bmheads[0]
4264 node = bmheads[0]
4272 elif len(bmheads) > 2:
4265 elif len(bmheads) > 2:
4273 raise util.Abort(_("multiple matching bookmarks to merge - "
4266 raise util.Abort(_("multiple matching bookmarks to merge - "
4274 "please merge with an explicit rev or bookmark"),
4267 "please merge with an explicit rev or bookmark"),
4275 hint=_("run 'hg heads' to see all heads"))
4268 hint=_("run 'hg heads' to see all heads"))
4276 elif len(bmheads) <= 1:
4269 elif len(bmheads) <= 1:
4277 raise util.Abort(_("no matching bookmark to merge - "
4270 raise util.Abort(_("no matching bookmark to merge - "
4278 "please merge with an explicit rev or bookmark"),
4271 "please merge with an explicit rev or bookmark"),
4279 hint=_("run 'hg heads' to see all heads"))
4272 hint=_("run 'hg heads' to see all heads"))
4280
4273
4281 if not node and not repo._bookmarkcurrent:
4274 if not node and not repo._bookmarkcurrent:
4282 branch = repo[None].branch()
4275 branch = repo[None].branch()
4283 bheads = repo.branchheads(branch)
4276 bheads = repo.branchheads(branch)
4284 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4277 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4285
4278
4286 if len(nbhs) > 2:
4279 if len(nbhs) > 2:
4287 raise util.Abort(_("branch '%s' has %d heads - "
4280 raise util.Abort(_("branch '%s' has %d heads - "
4288 "please merge with an explicit rev")
4281 "please merge with an explicit rev")
4289 % (branch, len(bheads)),
4282 % (branch, len(bheads)),
4290 hint=_("run 'hg heads .' to see heads"))
4283 hint=_("run 'hg heads .' to see heads"))
4291
4284
4292 parent = repo.dirstate.p1()
4285 parent = repo.dirstate.p1()
4293 if len(nbhs) <= 1:
4286 if len(nbhs) <= 1:
4294 if len(bheads) > 1:
4287 if len(bheads) > 1:
4295 raise util.Abort(_("heads are bookmarked - "
4288 raise util.Abort(_("heads are bookmarked - "
4296 "please merge with an explicit rev"),
4289 "please merge with an explicit rev"),
4297 hint=_("run 'hg heads' to see all heads"))
4290 hint=_("run 'hg heads' to see all heads"))
4298 if len(repo.heads()) > 1:
4291 if len(repo.heads()) > 1:
4299 raise util.Abort(_("branch '%s' has one head - "
4292 raise util.Abort(_("branch '%s' has one head - "
4300 "please merge with an explicit rev")
4293 "please merge with an explicit rev")
4301 % branch,
4294 % branch,
4302 hint=_("run 'hg heads' to see all heads"))
4295 hint=_("run 'hg heads' to see all heads"))
4303 msg, hint = _('nothing to merge'), None
4296 msg, hint = _('nothing to merge'), None
4304 if parent != repo.lookup(branch):
4297 if parent != repo.lookup(branch):
4305 hint = _("use 'hg update' instead")
4298 hint = _("use 'hg update' instead")
4306 raise util.Abort(msg, hint=hint)
4299 raise util.Abort(msg, hint=hint)
4307
4300
4308 if parent not in bheads:
4301 if parent not in bheads:
4309 raise util.Abort(_('working directory not at a head revision'),
4302 raise util.Abort(_('working directory not at a head revision'),
4310 hint=_("use 'hg update' or merge with an "
4303 hint=_("use 'hg update' or merge with an "
4311 "explicit revision"))
4304 "explicit revision"))
4312 if parent == nbhs[0]:
4305 if parent == nbhs[0]:
4313 node = nbhs[-1]
4306 node = nbhs[-1]
4314 else:
4307 else:
4315 node = nbhs[0]
4308 node = nbhs[0]
4316
4309
4317 if opts.get('preview'):
4310 if opts.get('preview'):
4318 # find nodes that are ancestors of p2 but not of p1
4311 # find nodes that are ancestors of p2 but not of p1
4319 p1 = repo.lookup('.')
4312 p1 = repo.lookup('.')
4320 p2 = repo.lookup(node)
4313 p2 = repo.lookup(node)
4321 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4314 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4322
4315
4323 displayer = cmdutil.show_changeset(ui, repo, opts)
4316 displayer = cmdutil.show_changeset(ui, repo, opts)
4324 for node in nodes:
4317 for node in nodes:
4325 displayer.show(repo[node])
4318 displayer.show(repo[node])
4326 displayer.close()
4319 displayer.close()
4327 return 0
4320 return 0
4328
4321
4329 try:
4322 try:
4330 # ui.forcemerge is an internal variable, do not document
4323 # ui.forcemerge is an internal variable, do not document
4331 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4324 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4332 return hg.merge(repo, node, force=opts.get('force'))
4325 return hg.merge(repo, node, force=opts.get('force'))
4333 finally:
4326 finally:
4334 ui.setconfig('ui', 'forcemerge', '')
4327 ui.setconfig('ui', 'forcemerge', '')
4335
4328
4336 @command('outgoing|out',
4329 @command('outgoing|out',
4337 [('f', 'force', None, _('run even when the destination is unrelated')),
4330 [('f', 'force', None, _('run even when the destination is unrelated')),
4338 ('r', 'rev', [],
4331 ('r', 'rev', [],
4339 _('a changeset intended to be included in the destination'), _('REV')),
4332 _('a changeset intended to be included in the destination'), _('REV')),
4340 ('n', 'newest-first', None, _('show newest record first')),
4333 ('n', 'newest-first', None, _('show newest record first')),
4341 ('B', 'bookmarks', False, _('compare bookmarks')),
4334 ('B', 'bookmarks', False, _('compare bookmarks')),
4342 ('b', 'branch', [], _('a specific branch you would like to push'),
4335 ('b', 'branch', [], _('a specific branch you would like to push'),
4343 _('BRANCH')),
4336 _('BRANCH')),
4344 ] + logopts + remoteopts + subrepoopts,
4337 ] + logopts + remoteopts + subrepoopts,
4345 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4338 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4346 def outgoing(ui, repo, dest=None, **opts):
4339 def outgoing(ui, repo, dest=None, **opts):
4347 """show changesets not found in the destination
4340 """show changesets not found in the destination
4348
4341
4349 Show changesets not found in the specified destination repository
4342 Show changesets not found in the specified destination repository
4350 or the default push location. These are the changesets that would
4343 or the default push location. These are the changesets that would
4351 be pushed if a push was requested.
4344 be pushed if a push was requested.
4352
4345
4353 See pull for details of valid destination formats.
4346 See pull for details of valid destination formats.
4354
4347
4355 Returns 0 if there are outgoing changes, 1 otherwise.
4348 Returns 0 if there are outgoing changes, 1 otherwise.
4356 """
4349 """
4357 if opts.get('graph'):
4350 if opts.get('graph'):
4358 cmdutil.checkunsupportedgraphflags([], opts)
4351 cmdutil.checkunsupportedgraphflags([], opts)
4359 o = hg._outgoing(ui, repo, dest, opts)
4352 o = hg._outgoing(ui, repo, dest, opts)
4360 if o is None:
4353 if o is None:
4361 return
4354 return
4362
4355
4363 revdag = cmdutil.graphrevs(repo, o, opts)
4356 revdag = cmdutil.graphrevs(repo, o, opts)
4364 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4357 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4365 showparents = [ctx.node() for ctx in repo[None].parents()]
4358 showparents = [ctx.node() for ctx in repo[None].parents()]
4366 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4359 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4367 graphmod.asciiedges)
4360 graphmod.asciiedges)
4368 return 0
4361 return 0
4369
4362
4370 if opts.get('bookmarks'):
4363 if opts.get('bookmarks'):
4371 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4364 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4372 dest, branches = hg.parseurl(dest, opts.get('branch'))
4365 dest, branches = hg.parseurl(dest, opts.get('branch'))
4373 other = hg.peer(repo, opts, dest)
4366 other = hg.peer(repo, opts, dest)
4374 if 'bookmarks' not in other.listkeys('namespaces'):
4367 if 'bookmarks' not in other.listkeys('namespaces'):
4375 ui.warn(_("remote doesn't support bookmarks\n"))
4368 ui.warn(_("remote doesn't support bookmarks\n"))
4376 return 0
4369 return 0
4377 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4370 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4378 return bookmarks.diff(ui, other, repo)
4371 return bookmarks.diff(ui, other, repo)
4379
4372
4380 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4373 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4381 try:
4374 try:
4382 return hg.outgoing(ui, repo, dest, opts)
4375 return hg.outgoing(ui, repo, dest, opts)
4383 finally:
4376 finally:
4384 del repo._subtoppath
4377 del repo._subtoppath
4385
4378
4386 @command('parents',
4379 @command('parents',
4387 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4380 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4388 ] + templateopts,
4381 ] + templateopts,
4389 _('[-r REV] [FILE]'))
4382 _('[-r REV] [FILE]'))
4390 def parents(ui, repo, file_=None, **opts):
4383 def parents(ui, repo, file_=None, **opts):
4391 """show the parents of the working directory or revision
4384 """show the parents of the working directory or revision
4392
4385
4393 Print the working directory's parent revisions. If a revision is
4386 Print the working directory's parent revisions. If a revision is
4394 given via -r/--rev, the parent of that revision will be printed.
4387 given via -r/--rev, the parent of that revision will be printed.
4395 If a file argument is given, the revision in which the file was
4388 If a file argument is given, the revision in which the file was
4396 last changed (before the working directory revision or the
4389 last changed (before the working directory revision or the
4397 argument to --rev if given) is printed.
4390 argument to --rev if given) is printed.
4398
4391
4399 Returns 0 on success.
4392 Returns 0 on success.
4400 """
4393 """
4401
4394
4402 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4395 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4403
4396
4404 if file_:
4397 if file_:
4405 m = scmutil.match(ctx, (file_,), opts)
4398 m = scmutil.match(ctx, (file_,), opts)
4406 if m.anypats() or len(m.files()) != 1:
4399 if m.anypats() or len(m.files()) != 1:
4407 raise util.Abort(_('can only specify an explicit filename'))
4400 raise util.Abort(_('can only specify an explicit filename'))
4408 file_ = m.files()[0]
4401 file_ = m.files()[0]
4409 filenodes = []
4402 filenodes = []
4410 for cp in ctx.parents():
4403 for cp in ctx.parents():
4411 if not cp:
4404 if not cp:
4412 continue
4405 continue
4413 try:
4406 try:
4414 filenodes.append(cp.filenode(file_))
4407 filenodes.append(cp.filenode(file_))
4415 except error.LookupError:
4408 except error.LookupError:
4416 pass
4409 pass
4417 if not filenodes:
4410 if not filenodes:
4418 raise util.Abort(_("'%s' not found in manifest!") % file_)
4411 raise util.Abort(_("'%s' not found in manifest!") % file_)
4419 p = []
4412 p = []
4420 for fn in filenodes:
4413 for fn in filenodes:
4421 fctx = repo.filectx(file_, fileid=fn)
4414 fctx = repo.filectx(file_, fileid=fn)
4422 p.append(fctx.node())
4415 p.append(fctx.node())
4423 else:
4416 else:
4424 p = [cp.node() for cp in ctx.parents()]
4417 p = [cp.node() for cp in ctx.parents()]
4425
4418
4426 displayer = cmdutil.show_changeset(ui, repo, opts)
4419 displayer = cmdutil.show_changeset(ui, repo, opts)
4427 for n in p:
4420 for n in p:
4428 if n != nullid:
4421 if n != nullid:
4429 displayer.show(repo[n])
4422 displayer.show(repo[n])
4430 displayer.close()
4423 displayer.close()
4431
4424
4432 @command('paths', [], _('[NAME]'))
4425 @command('paths', [], _('[NAME]'))
4433 def paths(ui, repo, search=None):
4426 def paths(ui, repo, search=None):
4434 """show aliases for remote repositories
4427 """show aliases for remote repositories
4435
4428
4436 Show definition of symbolic path name NAME. If no name is given,
4429 Show definition of symbolic path name NAME. If no name is given,
4437 show definition of all available names.
4430 show definition of all available names.
4438
4431
4439 Option -q/--quiet suppresses all output when searching for NAME
4432 Option -q/--quiet suppresses all output when searching for NAME
4440 and shows only the path names when listing all definitions.
4433 and shows only the path names when listing all definitions.
4441
4434
4442 Path names are defined in the [paths] section of your
4435 Path names are defined in the [paths] section of your
4443 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4436 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4444 repository, ``.hg/hgrc`` is used, too.
4437 repository, ``.hg/hgrc`` is used, too.
4445
4438
4446 The path names ``default`` and ``default-push`` have a special
4439 The path names ``default`` and ``default-push`` have a special
4447 meaning. When performing a push or pull operation, they are used
4440 meaning. When performing a push or pull operation, they are used
4448 as fallbacks if no location is specified on the command-line.
4441 as fallbacks if no location is specified on the command-line.
4449 When ``default-push`` is set, it will be used for push and
4442 When ``default-push`` is set, it will be used for push and
4450 ``default`` will be used for pull; otherwise ``default`` is used
4443 ``default`` will be used for pull; otherwise ``default`` is used
4451 as the fallback for both. When cloning a repository, the clone
4444 as the fallback for both. When cloning a repository, the clone
4452 source is written as ``default`` in ``.hg/hgrc``. Note that
4445 source is written as ``default`` in ``.hg/hgrc``. Note that
4453 ``default`` and ``default-push`` apply to all inbound (e.g.
4446 ``default`` and ``default-push`` apply to all inbound (e.g.
4454 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4447 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4455 :hg:`bundle`) operations.
4448 :hg:`bundle`) operations.
4456
4449
4457 See :hg:`help urls` for more information.
4450 See :hg:`help urls` for more information.
4458
4451
4459 Returns 0 on success.
4452 Returns 0 on success.
4460 """
4453 """
4461 if search:
4454 if search:
4462 for name, path in ui.configitems("paths"):
4455 for name, path in ui.configitems("paths"):
4463 if name == search:
4456 if name == search:
4464 ui.status("%s\n" % util.hidepassword(path))
4457 ui.status("%s\n" % util.hidepassword(path))
4465 return
4458 return
4466 if not ui.quiet:
4459 if not ui.quiet:
4467 ui.warn(_("not found!\n"))
4460 ui.warn(_("not found!\n"))
4468 return 1
4461 return 1
4469 else:
4462 else:
4470 for name, path in ui.configitems("paths"):
4463 for name, path in ui.configitems("paths"):
4471 if ui.quiet:
4464 if ui.quiet:
4472 ui.write("%s\n" % name)
4465 ui.write("%s\n" % name)
4473 else:
4466 else:
4474 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4467 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4475
4468
4476 @command('phase',
4469 @command('phase',
4477 [('p', 'public', False, _('set changeset phase to public')),
4470 [('p', 'public', False, _('set changeset phase to public')),
4478 ('d', 'draft', False, _('set changeset phase to draft')),
4471 ('d', 'draft', False, _('set changeset phase to draft')),
4479 ('s', 'secret', False, _('set changeset phase to secret')),
4472 ('s', 'secret', False, _('set changeset phase to secret')),
4480 ('f', 'force', False, _('allow to move boundary backward')),
4473 ('f', 'force', False, _('allow to move boundary backward')),
4481 ('r', 'rev', [], _('target revision'), _('REV')),
4474 ('r', 'rev', [], _('target revision'), _('REV')),
4482 ],
4475 ],
4483 _('[-p|-d|-s] [-f] [-r] REV...'))
4476 _('[-p|-d|-s] [-f] [-r] REV...'))
4484 def phase(ui, repo, *revs, **opts):
4477 def phase(ui, repo, *revs, **opts):
4485 """set or show the current phase name
4478 """set or show the current phase name
4486
4479
4487 With no argument, show the phase name of specified revisions.
4480 With no argument, show the phase name of specified revisions.
4488
4481
4489 With one of -p/--public, -d/--draft or -s/--secret, change the
4482 With one of -p/--public, -d/--draft or -s/--secret, change the
4490 phase value of the specified revisions.
4483 phase value of the specified revisions.
4491
4484
4492 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4485 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4493 lower phase to an higher phase. Phases are ordered as follows::
4486 lower phase to an higher phase. Phases are ordered as follows::
4494
4487
4495 public < draft < secret
4488 public < draft < secret
4496
4489
4497 Return 0 on success, 1 if no phases were changed or some could not
4490 Return 0 on success, 1 if no phases were changed or some could not
4498 be changed.
4491 be changed.
4499 """
4492 """
4500 # search for a unique phase argument
4493 # search for a unique phase argument
4501 targetphase = None
4494 targetphase = None
4502 for idx, name in enumerate(phases.phasenames):
4495 for idx, name in enumerate(phases.phasenames):
4503 if opts[name]:
4496 if opts[name]:
4504 if targetphase is not None:
4497 if targetphase is not None:
4505 raise util.Abort(_('only one phase can be specified'))
4498 raise util.Abort(_('only one phase can be specified'))
4506 targetphase = idx
4499 targetphase = idx
4507
4500
4508 # look for specified revision
4501 # look for specified revision
4509 revs = list(revs)
4502 revs = list(revs)
4510 revs.extend(opts['rev'])
4503 revs.extend(opts['rev'])
4511 if not revs:
4504 if not revs:
4512 raise util.Abort(_('no revisions specified'))
4505 raise util.Abort(_('no revisions specified'))
4513
4506
4514 revs = scmutil.revrange(repo, revs)
4507 revs = scmutil.revrange(repo, revs)
4515
4508
4516 lock = None
4509 lock = None
4517 ret = 0
4510 ret = 0
4518 if targetphase is None:
4511 if targetphase is None:
4519 # display
4512 # display
4520 for r in revs:
4513 for r in revs:
4521 ctx = repo[r]
4514 ctx = repo[r]
4522 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4515 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4523 else:
4516 else:
4524 lock = repo.lock()
4517 lock = repo.lock()
4525 try:
4518 try:
4526 # set phase
4519 # set phase
4527 if not revs:
4520 if not revs:
4528 raise util.Abort(_('empty revision set'))
4521 raise util.Abort(_('empty revision set'))
4529 nodes = [repo[r].node() for r in revs]
4522 nodes = [repo[r].node() for r in revs]
4530 olddata = repo._phasecache.getphaserevs(repo)[:]
4523 olddata = repo._phasecache.getphaserevs(repo)[:]
4531 phases.advanceboundary(repo, targetphase, nodes)
4524 phases.advanceboundary(repo, targetphase, nodes)
4532 if opts['force']:
4525 if opts['force']:
4533 phases.retractboundary(repo, targetphase, nodes)
4526 phases.retractboundary(repo, targetphase, nodes)
4534 finally:
4527 finally:
4535 lock.release()
4528 lock.release()
4536 # moving revision from public to draft may hide them
4529 # moving revision from public to draft may hide them
4537 # We have to check result on an unfiltered repository
4530 # We have to check result on an unfiltered repository
4538 unfi = repo.unfiltered()
4531 unfi = repo.unfiltered()
4539 newdata = repo._phasecache.getphaserevs(unfi)
4532 newdata = repo._phasecache.getphaserevs(unfi)
4540 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4533 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4541 cl = unfi.changelog
4534 cl = unfi.changelog
4542 rejected = [n for n in nodes
4535 rejected = [n for n in nodes
4543 if newdata[cl.rev(n)] < targetphase]
4536 if newdata[cl.rev(n)] < targetphase]
4544 if rejected:
4537 if rejected:
4545 ui.warn(_('cannot move %i changesets to a higher '
4538 ui.warn(_('cannot move %i changesets to a higher '
4546 'phase, use --force\n') % len(rejected))
4539 'phase, use --force\n') % len(rejected))
4547 ret = 1
4540 ret = 1
4548 if changes:
4541 if changes:
4549 msg = _('phase changed for %i changesets\n') % changes
4542 msg = _('phase changed for %i changesets\n') % changes
4550 if ret:
4543 if ret:
4551 ui.status(msg)
4544 ui.status(msg)
4552 else:
4545 else:
4553 ui.note(msg)
4546 ui.note(msg)
4554 else:
4547 else:
4555 ui.warn(_('no phases changed\n'))
4548 ui.warn(_('no phases changed\n'))
4556 ret = 1
4549 ret = 1
4557 return ret
4550 return ret
4558
4551
4559 def postincoming(ui, repo, modheads, optupdate, checkout):
4552 def postincoming(ui, repo, modheads, optupdate, checkout):
4560 if modheads == 0:
4553 if modheads == 0:
4561 return
4554 return
4562 if optupdate:
4555 if optupdate:
4563 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4556 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4564 try:
4557 try:
4565 ret = hg.update(repo, checkout)
4558 ret = hg.update(repo, checkout)
4566 except util.Abort, inst:
4559 except util.Abort, inst:
4567 ui.warn(_("not updating: %s\n") % str(inst))
4560 ui.warn(_("not updating: %s\n") % str(inst))
4568 if inst.hint:
4561 if inst.hint:
4569 ui.warn(_("(%s)\n") % inst.hint)
4562 ui.warn(_("(%s)\n") % inst.hint)
4570 return 0
4563 return 0
4571 if not ret and not checkout:
4564 if not ret and not checkout:
4572 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4565 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4573 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4566 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4574 return ret
4567 return ret
4575 if modheads > 1:
4568 if modheads > 1:
4576 currentbranchheads = len(repo.branchheads())
4569 currentbranchheads = len(repo.branchheads())
4577 if currentbranchheads == modheads:
4570 if currentbranchheads == modheads:
4578 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4571 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4579 elif currentbranchheads > 1:
4572 elif currentbranchheads > 1:
4580 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4573 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4581 "merge)\n"))
4574 "merge)\n"))
4582 else:
4575 else:
4583 ui.status(_("(run 'hg heads' to see heads)\n"))
4576 ui.status(_("(run 'hg heads' to see heads)\n"))
4584 else:
4577 else:
4585 ui.status(_("(run 'hg update' to get a working copy)\n"))
4578 ui.status(_("(run 'hg update' to get a working copy)\n"))
4586
4579
4587 @command('^pull',
4580 @command('^pull',
4588 [('u', 'update', None,
4581 [('u', 'update', None,
4589 _('update to new branch head if changesets were pulled')),
4582 _('update to new branch head if changesets were pulled')),
4590 ('f', 'force', None, _('run even when remote repository is unrelated')),
4583 ('f', 'force', None, _('run even when remote repository is unrelated')),
4591 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4584 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4592 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4585 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4593 ('b', 'branch', [], _('a specific branch you would like to pull'),
4586 ('b', 'branch', [], _('a specific branch you would like to pull'),
4594 _('BRANCH')),
4587 _('BRANCH')),
4595 ] + remoteopts,
4588 ] + remoteopts,
4596 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4589 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4597 def pull(ui, repo, source="default", **opts):
4590 def pull(ui, repo, source="default", **opts):
4598 """pull changes from the specified source
4591 """pull changes from the specified source
4599
4592
4600 Pull changes from a remote repository to a local one.
4593 Pull changes from a remote repository to a local one.
4601
4594
4602 This finds all changes from the repository at the specified path
4595 This finds all changes from the repository at the specified path
4603 or URL and adds them to a local repository (the current one unless
4596 or URL and adds them to a local repository (the current one unless
4604 -R is specified). By default, this does not update the copy of the
4597 -R is specified). By default, this does not update the copy of the
4605 project in the working directory.
4598 project in the working directory.
4606
4599
4607 Use :hg:`incoming` if you want to see what would have been added
4600 Use :hg:`incoming` if you want to see what would have been added
4608 by a pull at the time you issued this command. If you then decide
4601 by a pull at the time you issued this command. If you then decide
4609 to add those changes to the repository, you should use :hg:`pull
4602 to add those changes to the repository, you should use :hg:`pull
4610 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4603 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4611
4604
4612 If SOURCE is omitted, the 'default' path will be used.
4605 If SOURCE is omitted, the 'default' path will be used.
4613 See :hg:`help urls` for more information.
4606 See :hg:`help urls` for more information.
4614
4607
4615 Returns 0 on success, 1 if an update had unresolved files.
4608 Returns 0 on success, 1 if an update had unresolved files.
4616 """
4609 """
4617 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4610 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4618 other = hg.peer(repo, opts, source)
4611 other = hg.peer(repo, opts, source)
4619 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4612 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4620 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4613 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4621
4614
4622 remotebookmarks = other.listkeys('bookmarks')
4615 remotebookmarks = other.listkeys('bookmarks')
4623
4616
4624 if opts.get('bookmark'):
4617 if opts.get('bookmark'):
4625 if not revs:
4618 if not revs:
4626 revs = []
4619 revs = []
4627 for b in opts['bookmark']:
4620 for b in opts['bookmark']:
4628 if b not in remotebookmarks:
4621 if b not in remotebookmarks:
4629 raise util.Abort(_('remote bookmark %s not found!') % b)
4622 raise util.Abort(_('remote bookmark %s not found!') % b)
4630 revs.append(remotebookmarks[b])
4623 revs.append(remotebookmarks[b])
4631
4624
4632 if revs:
4625 if revs:
4633 try:
4626 try:
4634 revs = [other.lookup(rev) for rev in revs]
4627 revs = [other.lookup(rev) for rev in revs]
4635 except error.CapabilityError:
4628 except error.CapabilityError:
4636 err = _("other repository doesn't support revision lookup, "
4629 err = _("other repository doesn't support revision lookup, "
4637 "so a rev cannot be specified.")
4630 "so a rev cannot be specified.")
4638 raise util.Abort(err)
4631 raise util.Abort(err)
4639
4632
4640 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4633 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4641 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4634 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4642 if checkout:
4635 if checkout:
4643 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4636 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4644 repo._subtoppath = source
4637 repo._subtoppath = source
4645 try:
4638 try:
4646 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4639 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4647
4640
4648 finally:
4641 finally:
4649 del repo._subtoppath
4642 del repo._subtoppath
4650
4643
4651 # update specified bookmarks
4644 # update specified bookmarks
4652 if opts.get('bookmark'):
4645 if opts.get('bookmark'):
4653 marks = repo._bookmarks
4646 marks = repo._bookmarks
4654 for b in opts['bookmark']:
4647 for b in opts['bookmark']:
4655 # explicit pull overrides local bookmark if any
4648 # explicit pull overrides local bookmark if any
4656 ui.status(_("importing bookmark %s\n") % b)
4649 ui.status(_("importing bookmark %s\n") % b)
4657 marks[b] = repo[remotebookmarks[b]].node()
4650 marks[b] = repo[remotebookmarks[b]].node()
4658 marks.write()
4651 marks.write()
4659
4652
4660 return ret
4653 return ret
4661
4654
4662 @command('^push',
4655 @command('^push',
4663 [('f', 'force', None, _('force push')),
4656 [('f', 'force', None, _('force push')),
4664 ('r', 'rev', [],
4657 ('r', 'rev', [],
4665 _('a changeset intended to be included in the destination'),
4658 _('a changeset intended to be included in the destination'),
4666 _('REV')),
4659 _('REV')),
4667 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4660 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4668 ('b', 'branch', [],
4661 ('b', 'branch', [],
4669 _('a specific branch you would like to push'), _('BRANCH')),
4662 _('a specific branch you would like to push'), _('BRANCH')),
4670 ('', 'new-branch', False, _('allow pushing a new branch')),
4663 ('', 'new-branch', False, _('allow pushing a new branch')),
4671 ] + remoteopts,
4664 ] + remoteopts,
4672 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4665 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4673 def push(ui, repo, dest=None, **opts):
4666 def push(ui, repo, dest=None, **opts):
4674 """push changes to the specified destination
4667 """push changes to the specified destination
4675
4668
4676 Push changesets from the local repository to the specified
4669 Push changesets from the local repository to the specified
4677 destination.
4670 destination.
4678
4671
4679 This operation is symmetrical to pull: it is identical to a pull
4672 This operation is symmetrical to pull: it is identical to a pull
4680 in the destination repository from the current one.
4673 in the destination repository from the current one.
4681
4674
4682 By default, push will not allow creation of new heads at the
4675 By default, push will not allow creation of new heads at the
4683 destination, since multiple heads would make it unclear which head
4676 destination, since multiple heads would make it unclear which head
4684 to use. In this situation, it is recommended to pull and merge
4677 to use. In this situation, it is recommended to pull and merge
4685 before pushing.
4678 before pushing.
4686
4679
4687 Use --new-branch if you want to allow push to create a new named
4680 Use --new-branch if you want to allow push to create a new named
4688 branch that is not present at the destination. This allows you to
4681 branch that is not present at the destination. This allows you to
4689 only create a new branch without forcing other changes.
4682 only create a new branch without forcing other changes.
4690
4683
4691 .. note::
4684 .. note::
4692
4685
4693 Extra care should be taken with the -f/--force option,
4686 Extra care should be taken with the -f/--force option,
4694 which will push all new heads on all branches, an action which will
4687 which will push all new heads on all branches, an action which will
4695 almost always cause confusion for collaborators.
4688 almost always cause confusion for collaborators.
4696
4689
4697 If -r/--rev is used, the specified revision and all its ancestors
4690 If -r/--rev is used, the specified revision and all its ancestors
4698 will be pushed to the remote repository.
4691 will be pushed to the remote repository.
4699
4692
4700 If -B/--bookmark is used, the specified bookmarked revision, its
4693 If -B/--bookmark is used, the specified bookmarked revision, its
4701 ancestors, and the bookmark will be pushed to the remote
4694 ancestors, and the bookmark will be pushed to the remote
4702 repository.
4695 repository.
4703
4696
4704 Please see :hg:`help urls` for important details about ``ssh://``
4697 Please see :hg:`help urls` for important details about ``ssh://``
4705 URLs. If DESTINATION is omitted, a default path will be used.
4698 URLs. If DESTINATION is omitted, a default path will be used.
4706
4699
4707 Returns 0 if push was successful, 1 if nothing to push.
4700 Returns 0 if push was successful, 1 if nothing to push.
4708 """
4701 """
4709
4702
4710 if opts.get('bookmark'):
4703 if opts.get('bookmark'):
4711 ui.setconfig('bookmarks', 'pushing', opts['bookmark'])
4704 ui.setconfig('bookmarks', 'pushing', opts['bookmark'])
4712 for b in opts['bookmark']:
4705 for b in opts['bookmark']:
4713 # translate -B options to -r so changesets get pushed
4706 # translate -B options to -r so changesets get pushed
4714 if b in repo._bookmarks:
4707 if b in repo._bookmarks:
4715 opts.setdefault('rev', []).append(b)
4708 opts.setdefault('rev', []).append(b)
4716 else:
4709 else:
4717 # if we try to push a deleted bookmark, translate it to null
4710 # if we try to push a deleted bookmark, translate it to null
4718 # this lets simultaneous -r, -b options continue working
4711 # this lets simultaneous -r, -b options continue working
4719 opts.setdefault('rev', []).append("null")
4712 opts.setdefault('rev', []).append("null")
4720
4713
4721 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4714 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4722 dest, branches = hg.parseurl(dest, opts.get('branch'))
4715 dest, branches = hg.parseurl(dest, opts.get('branch'))
4723 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4716 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4724 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4717 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4725 other = hg.peer(repo, opts, dest)
4718 other = hg.peer(repo, opts, dest)
4726 if revs:
4719 if revs:
4727 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4720 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4728
4721
4729 repo._subtoppath = dest
4722 repo._subtoppath = dest
4730 try:
4723 try:
4731 # push subrepos depth-first for coherent ordering
4724 # push subrepos depth-first for coherent ordering
4732 c = repo['']
4725 c = repo['']
4733 subs = c.substate # only repos that are committed
4726 subs = c.substate # only repos that are committed
4734 for s in sorted(subs):
4727 for s in sorted(subs):
4735 if c.sub(s).push(opts) == 0:
4728 if c.sub(s).push(opts) == 0:
4736 return False
4729 return False
4737 finally:
4730 finally:
4738 del repo._subtoppath
4731 del repo._subtoppath
4739 result = repo.push(other, opts.get('force'), revs=revs,
4732 result = repo.push(other, opts.get('force'), revs=revs,
4740 newbranch=opts.get('new_branch'))
4733 newbranch=opts.get('new_branch'))
4741
4734
4742 result = not result
4735 result = not result
4743
4736
4744 if opts.get('bookmark'):
4737 if opts.get('bookmark'):
4745 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4738 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4746 if bresult == 2:
4739 if bresult == 2:
4747 return 2
4740 return 2
4748 if not result and bresult:
4741 if not result and bresult:
4749 result = 2
4742 result = 2
4750
4743
4751 return result
4744 return result
4752
4745
4753 @command('recover', [])
4746 @command('recover', [])
4754 def recover(ui, repo):
4747 def recover(ui, repo):
4755 """roll back an interrupted transaction
4748 """roll back an interrupted transaction
4756
4749
4757 Recover from an interrupted commit or pull.
4750 Recover from an interrupted commit or pull.
4758
4751
4759 This command tries to fix the repository status after an
4752 This command tries to fix the repository status after an
4760 interrupted operation. It should only be necessary when Mercurial
4753 interrupted operation. It should only be necessary when Mercurial
4761 suggests it.
4754 suggests it.
4762
4755
4763 Returns 0 if successful, 1 if nothing to recover or verify fails.
4756 Returns 0 if successful, 1 if nothing to recover or verify fails.
4764 """
4757 """
4765 if repo.recover():
4758 if repo.recover():
4766 return hg.verify(repo)
4759 return hg.verify(repo)
4767 return 1
4760 return 1
4768
4761
4769 @command('^remove|rm',
4762 @command('^remove|rm',
4770 [('A', 'after', None, _('record delete for missing files')),
4763 [('A', 'after', None, _('record delete for missing files')),
4771 ('f', 'force', None,
4764 ('f', 'force', None,
4772 _('remove (and delete) file even if added or modified')),
4765 _('remove (and delete) file even if added or modified')),
4773 ] + walkopts,
4766 ] + walkopts,
4774 _('[OPTION]... FILE...'))
4767 _('[OPTION]... FILE...'))
4775 def remove(ui, repo, *pats, **opts):
4768 def remove(ui, repo, *pats, **opts):
4776 """remove the specified files on the next commit
4769 """remove the specified files on the next commit
4777
4770
4778 Schedule the indicated files for removal from the current branch.
4771 Schedule the indicated files for removal from the current branch.
4779
4772
4780 This command schedules the files to be removed at the next commit.
4773 This command schedules the files to be removed at the next commit.
4781 To undo a remove before that, see :hg:`revert`. To undo added
4774 To undo a remove before that, see :hg:`revert`. To undo added
4782 files, see :hg:`forget`.
4775 files, see :hg:`forget`.
4783
4776
4784 .. container:: verbose
4777 .. container:: verbose
4785
4778
4786 -A/--after can be used to remove only files that have already
4779 -A/--after can be used to remove only files that have already
4787 been deleted, -f/--force can be used to force deletion, and -Af
4780 been deleted, -f/--force can be used to force deletion, and -Af
4788 can be used to remove files from the next revision without
4781 can be used to remove files from the next revision without
4789 deleting them from the working directory.
4782 deleting them from the working directory.
4790
4783
4791 The following table details the behavior of remove for different
4784 The following table details the behavior of remove for different
4792 file states (columns) and option combinations (rows). The file
4785 file states (columns) and option combinations (rows). The file
4793 states are Added [A], Clean [C], Modified [M] and Missing [!]
4786 states are Added [A], Clean [C], Modified [M] and Missing [!]
4794 (as reported by :hg:`status`). The actions are Warn, Remove
4787 (as reported by :hg:`status`). The actions are Warn, Remove
4795 (from branch) and Delete (from disk):
4788 (from branch) and Delete (from disk):
4796
4789
4797 ========= == == == ==
4790 ========= == == == ==
4798 opt/state A C M !
4791 opt/state A C M !
4799 ========= == == == ==
4792 ========= == == == ==
4800 none W RD W R
4793 none W RD W R
4801 -f R RD RD R
4794 -f R RD RD R
4802 -A W W W R
4795 -A W W W R
4803 -Af R R R R
4796 -Af R R R R
4804 ========= == == == ==
4797 ========= == == == ==
4805
4798
4806 Note that remove never deletes files in Added [A] state from the
4799 Note that remove never deletes files in Added [A] state from the
4807 working directory, not even if option --force is specified.
4800 working directory, not even if option --force is specified.
4808
4801
4809 Returns 0 on success, 1 if any warnings encountered.
4802 Returns 0 on success, 1 if any warnings encountered.
4810 """
4803 """
4811
4804
4812 ret = 0
4805 ret = 0
4813 after, force = opts.get('after'), opts.get('force')
4806 after, force = opts.get('after'), opts.get('force')
4814 if not pats and not after:
4807 if not pats and not after:
4815 raise util.Abort(_('no files specified'))
4808 raise util.Abort(_('no files specified'))
4816
4809
4817 m = scmutil.match(repo[None], pats, opts)
4810 m = scmutil.match(repo[None], pats, opts)
4818 s = repo.status(match=m, clean=True)
4811 s = repo.status(match=m, clean=True)
4819 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4812 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4820
4813
4821 # warn about failure to delete explicit files/dirs
4814 # warn about failure to delete explicit files/dirs
4822 wctx = repo[None]
4815 wctx = repo[None]
4823 for f in m.files():
4816 for f in m.files():
4824 if f in repo.dirstate or f in wctx.dirs():
4817 if f in repo.dirstate or f in wctx.dirs():
4825 continue
4818 continue
4826 if os.path.exists(m.rel(f)):
4819 if os.path.exists(m.rel(f)):
4827 if os.path.isdir(m.rel(f)):
4820 if os.path.isdir(m.rel(f)):
4828 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4821 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4829 else:
4822 else:
4830 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4823 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4831 # missing files will generate a warning elsewhere
4824 # missing files will generate a warning elsewhere
4832 ret = 1
4825 ret = 1
4833
4826
4834 if force:
4827 if force:
4835 list = modified + deleted + clean + added
4828 list = modified + deleted + clean + added
4836 elif after:
4829 elif after:
4837 list = deleted
4830 list = deleted
4838 for f in modified + added + clean:
4831 for f in modified + added + clean:
4839 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4832 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4840 ret = 1
4833 ret = 1
4841 else:
4834 else:
4842 list = deleted + clean
4835 list = deleted + clean
4843 for f in modified:
4836 for f in modified:
4844 ui.warn(_('not removing %s: file is modified (use -f'
4837 ui.warn(_('not removing %s: file is modified (use -f'
4845 ' to force removal)\n') % m.rel(f))
4838 ' to force removal)\n') % m.rel(f))
4846 ret = 1
4839 ret = 1
4847 for f in added:
4840 for f in added:
4848 ui.warn(_('not removing %s: file has been marked for add'
4841 ui.warn(_('not removing %s: file has been marked for add'
4849 ' (use forget to undo)\n') % m.rel(f))
4842 ' (use forget to undo)\n') % m.rel(f))
4850 ret = 1
4843 ret = 1
4851
4844
4852 for f in sorted(list):
4845 for f in sorted(list):
4853 if ui.verbose or not m.exact(f):
4846 if ui.verbose or not m.exact(f):
4854 ui.status(_('removing %s\n') % m.rel(f))
4847 ui.status(_('removing %s\n') % m.rel(f))
4855
4848
4856 wlock = repo.wlock()
4849 wlock = repo.wlock()
4857 try:
4850 try:
4858 if not after:
4851 if not after:
4859 for f in list:
4852 for f in list:
4860 if f in added:
4853 if f in added:
4861 continue # we never unlink added files on remove
4854 continue # we never unlink added files on remove
4862 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4855 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4863 repo[None].forget(list)
4856 repo[None].forget(list)
4864 finally:
4857 finally:
4865 wlock.release()
4858 wlock.release()
4866
4859
4867 return ret
4860 return ret
4868
4861
4869 @command('rename|move|mv',
4862 @command('rename|move|mv',
4870 [('A', 'after', None, _('record a rename that has already occurred')),
4863 [('A', 'after', None, _('record a rename that has already occurred')),
4871 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4864 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4872 ] + walkopts + dryrunopts,
4865 ] + walkopts + dryrunopts,
4873 _('[OPTION]... SOURCE... DEST'))
4866 _('[OPTION]... SOURCE... DEST'))
4874 def rename(ui, repo, *pats, **opts):
4867 def rename(ui, repo, *pats, **opts):
4875 """rename files; equivalent of copy + remove
4868 """rename files; equivalent of copy + remove
4876
4869
4877 Mark dest as copies of sources; mark sources for deletion. If dest
4870 Mark dest as copies of sources; mark sources for deletion. If dest
4878 is a directory, copies are put in that directory. If dest is a
4871 is a directory, copies are put in that directory. If dest is a
4879 file, there can only be one source.
4872 file, there can only be one source.
4880
4873
4881 By default, this command copies the contents of files as they
4874 By default, this command copies the contents of files as they
4882 exist in the working directory. If invoked with -A/--after, the
4875 exist in the working directory. If invoked with -A/--after, the
4883 operation is recorded, but no copying is performed.
4876 operation is recorded, but no copying is performed.
4884
4877
4885 This command takes effect at the next commit. To undo a rename
4878 This command takes effect at the next commit. To undo a rename
4886 before that, see :hg:`revert`.
4879 before that, see :hg:`revert`.
4887
4880
4888 Returns 0 on success, 1 if errors are encountered.
4881 Returns 0 on success, 1 if errors are encountered.
4889 """
4882 """
4890 wlock = repo.wlock(False)
4883 wlock = repo.wlock(False)
4891 try:
4884 try:
4892 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4885 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4893 finally:
4886 finally:
4894 wlock.release()
4887 wlock.release()
4895
4888
4896 @command('resolve',
4889 @command('resolve',
4897 [('a', 'all', None, _('select all unresolved files')),
4890 [('a', 'all', None, _('select all unresolved files')),
4898 ('l', 'list', None, _('list state of files needing merge')),
4891 ('l', 'list', None, _('list state of files needing merge')),
4899 ('m', 'mark', None, _('mark files as resolved')),
4892 ('m', 'mark', None, _('mark files as resolved')),
4900 ('u', 'unmark', None, _('mark files as unresolved')),
4893 ('u', 'unmark', None, _('mark files as unresolved')),
4901 ('n', 'no-status', None, _('hide status prefix'))]
4894 ('n', 'no-status', None, _('hide status prefix'))]
4902 + mergetoolopts + walkopts,
4895 + mergetoolopts + walkopts,
4903 _('[OPTION]... [FILE]...'))
4896 _('[OPTION]... [FILE]...'))
4904 def resolve(ui, repo, *pats, **opts):
4897 def resolve(ui, repo, *pats, **opts):
4905 """redo merges or set/view the merge status of files
4898 """redo merges or set/view the merge status of files
4906
4899
4907 Merges with unresolved conflicts are often the result of
4900 Merges with unresolved conflicts are often the result of
4908 non-interactive merging using the ``internal:merge`` configuration
4901 non-interactive merging using the ``internal:merge`` configuration
4909 setting, or a command-line merge tool like ``diff3``. The resolve
4902 setting, or a command-line merge tool like ``diff3``. The resolve
4910 command is used to manage the files involved in a merge, after
4903 command is used to manage the files involved in a merge, after
4911 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4904 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4912 working directory must have two parents). See :hg:`help
4905 working directory must have two parents). See :hg:`help
4913 merge-tools` for information on configuring merge tools.
4906 merge-tools` for information on configuring merge tools.
4914
4907
4915 The resolve command can be used in the following ways:
4908 The resolve command can be used in the following ways:
4916
4909
4917 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4910 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4918 files, discarding any previous merge attempts. Re-merging is not
4911 files, discarding any previous merge attempts. Re-merging is not
4919 performed for files already marked as resolved. Use ``--all/-a``
4912 performed for files already marked as resolved. Use ``--all/-a``
4920 to select all unresolved files. ``--tool`` can be used to specify
4913 to select all unresolved files. ``--tool`` can be used to specify
4921 the merge tool used for the given files. It overrides the HGMERGE
4914 the merge tool used for the given files. It overrides the HGMERGE
4922 environment variable and your configuration files. Previous file
4915 environment variable and your configuration files. Previous file
4923 contents are saved with a ``.orig`` suffix.
4916 contents are saved with a ``.orig`` suffix.
4924
4917
4925 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4918 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4926 (e.g. after having manually fixed-up the files). The default is
4919 (e.g. after having manually fixed-up the files). The default is
4927 to mark all unresolved files.
4920 to mark all unresolved files.
4928
4921
4929 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4922 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4930 default is to mark all resolved files.
4923 default is to mark all resolved files.
4931
4924
4932 - :hg:`resolve -l`: list files which had or still have conflicts.
4925 - :hg:`resolve -l`: list files which had or still have conflicts.
4933 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4926 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4934
4927
4935 Note that Mercurial will not let you commit files with unresolved
4928 Note that Mercurial will not let you commit files with unresolved
4936 merge conflicts. You must use :hg:`resolve -m ...` before you can
4929 merge conflicts. You must use :hg:`resolve -m ...` before you can
4937 commit after a conflicting merge.
4930 commit after a conflicting merge.
4938
4931
4939 Returns 0 on success, 1 if any files fail a resolve attempt.
4932 Returns 0 on success, 1 if any files fail a resolve attempt.
4940 """
4933 """
4941
4934
4942 all, mark, unmark, show, nostatus = \
4935 all, mark, unmark, show, nostatus = \
4943 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4936 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4944
4937
4945 if (show and (mark or unmark)) or (mark and unmark):
4938 if (show and (mark or unmark)) or (mark and unmark):
4946 raise util.Abort(_("too many options specified"))
4939 raise util.Abort(_("too many options specified"))
4947 if pats and all:
4940 if pats and all:
4948 raise util.Abort(_("can't specify --all and patterns"))
4941 raise util.Abort(_("can't specify --all and patterns"))
4949 if not (all or pats or show or mark or unmark):
4942 if not (all or pats or show or mark or unmark):
4950 raise util.Abort(_('no files or directories specified; '
4943 raise util.Abort(_('no files or directories specified; '
4951 'use --all to remerge all files'))
4944 'use --all to remerge all files'))
4952
4945
4953 ms = mergemod.mergestate(repo)
4946 ms = mergemod.mergestate(repo)
4954 m = scmutil.match(repo[None], pats, opts)
4947 m = scmutil.match(repo[None], pats, opts)
4955 ret = 0
4948 ret = 0
4956
4949
4957 for f in ms:
4950 for f in ms:
4958 if m(f):
4951 if m(f):
4959 if show:
4952 if show:
4960 if nostatus:
4953 if nostatus:
4961 ui.write("%s\n" % f)
4954 ui.write("%s\n" % f)
4962 else:
4955 else:
4963 ui.write("%s %s\n" % (ms[f].upper(), f),
4956 ui.write("%s %s\n" % (ms[f].upper(), f),
4964 label='resolve.' +
4957 label='resolve.' +
4965 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4958 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4966 elif mark:
4959 elif mark:
4967 ms.mark(f, "r")
4960 ms.mark(f, "r")
4968 elif unmark:
4961 elif unmark:
4969 ms.mark(f, "u")
4962 ms.mark(f, "u")
4970 else:
4963 else:
4971 wctx = repo[None]
4964 wctx = repo[None]
4972 mctx = wctx.parents()[-1]
4965 mctx = wctx.parents()[-1]
4973
4966
4974 # backup pre-resolve (merge uses .orig for its own purposes)
4967 # backup pre-resolve (merge uses .orig for its own purposes)
4975 a = repo.wjoin(f)
4968 a = repo.wjoin(f)
4976 util.copyfile(a, a + ".resolve")
4969 util.copyfile(a, a + ".resolve")
4977
4970
4978 try:
4971 try:
4979 # resolve file
4972 # resolve file
4980 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4973 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4981 if ms.resolve(f, wctx, mctx):
4974 if ms.resolve(f, wctx, mctx):
4982 ret = 1
4975 ret = 1
4983 finally:
4976 finally:
4984 ui.setconfig('ui', 'forcemerge', '')
4977 ui.setconfig('ui', 'forcemerge', '')
4985 ms.commit()
4978 ms.commit()
4986
4979
4987 # replace filemerge's .orig file with our resolve file
4980 # replace filemerge's .orig file with our resolve file
4988 util.rename(a + ".resolve", a + ".orig")
4981 util.rename(a + ".resolve", a + ".orig")
4989
4982
4990 ms.commit()
4983 ms.commit()
4991 return ret
4984 return ret
4992
4985
4993 @command('revert',
4986 @command('revert',
4994 [('a', 'all', None, _('revert all changes when no arguments given')),
4987 [('a', 'all', None, _('revert all changes when no arguments given')),
4995 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4988 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4996 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4989 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4997 ('C', 'no-backup', None, _('do not save backup copies of files')),
4990 ('C', 'no-backup', None, _('do not save backup copies of files')),
4998 ] + walkopts + dryrunopts,
4991 ] + walkopts + dryrunopts,
4999 _('[OPTION]... [-r REV] [NAME]...'))
4992 _('[OPTION]... [-r REV] [NAME]...'))
5000 def revert(ui, repo, *pats, **opts):
4993 def revert(ui, repo, *pats, **opts):
5001 """restore files to their checkout state
4994 """restore files to their checkout state
5002
4995
5003 .. note::
4996 .. note::
5004
4997
5005 To check out earlier revisions, you should use :hg:`update REV`.
4998 To check out earlier revisions, you should use :hg:`update REV`.
5006 To cancel an uncommitted merge (and lose your changes),
4999 To cancel an uncommitted merge (and lose your changes),
5007 use :hg:`update --clean .`.
5000 use :hg:`update --clean .`.
5008
5001
5009 With no revision specified, revert the specified files or directories
5002 With no revision specified, revert the specified files or directories
5010 to the contents they had in the parent of the working directory.
5003 to the contents they had in the parent of the working directory.
5011 This restores the contents of files to an unmodified
5004 This restores the contents of files to an unmodified
5012 state and unschedules adds, removes, copies, and renames. If the
5005 state and unschedules adds, removes, copies, and renames. If the
5013 working directory has two parents, you must explicitly specify a
5006 working directory has two parents, you must explicitly specify a
5014 revision.
5007 revision.
5015
5008
5016 Using the -r/--rev or -d/--date options, revert the given files or
5009 Using the -r/--rev or -d/--date options, revert the given files or
5017 directories to their states as of a specific revision. Because
5010 directories to their states as of a specific revision. Because
5018 revert does not change the working directory parents, this will
5011 revert does not change the working directory parents, this will
5019 cause these files to appear modified. This can be helpful to "back
5012 cause these files to appear modified. This can be helpful to "back
5020 out" some or all of an earlier change. See :hg:`backout` for a
5013 out" some or all of an earlier change. See :hg:`backout` for a
5021 related method.
5014 related method.
5022
5015
5023 Modified files are saved with a .orig suffix before reverting.
5016 Modified files are saved with a .orig suffix before reverting.
5024 To disable these backups, use --no-backup.
5017 To disable these backups, use --no-backup.
5025
5018
5026 See :hg:`help dates` for a list of formats valid for -d/--date.
5019 See :hg:`help dates` for a list of formats valid for -d/--date.
5027
5020
5028 Returns 0 on success.
5021 Returns 0 on success.
5029 """
5022 """
5030
5023
5031 if opts.get("date"):
5024 if opts.get("date"):
5032 if opts.get("rev"):
5025 if opts.get("rev"):
5033 raise util.Abort(_("you can't specify a revision and a date"))
5026 raise util.Abort(_("you can't specify a revision and a date"))
5034 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5027 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5035
5028
5036 parent, p2 = repo.dirstate.parents()
5029 parent, p2 = repo.dirstate.parents()
5037 if not opts.get('rev') and p2 != nullid:
5030 if not opts.get('rev') and p2 != nullid:
5038 # revert after merge is a trap for new users (issue2915)
5031 # revert after merge is a trap for new users (issue2915)
5039 raise util.Abort(_('uncommitted merge with no revision specified'),
5032 raise util.Abort(_('uncommitted merge with no revision specified'),
5040 hint=_('use "hg update" or see "hg help revert"'))
5033 hint=_('use "hg update" or see "hg help revert"'))
5041
5034
5042 ctx = scmutil.revsingle(repo, opts.get('rev'))
5035 ctx = scmutil.revsingle(repo, opts.get('rev'))
5043
5036
5044 if not pats and not opts.get('all'):
5037 if not pats and not opts.get('all'):
5045 msg = _("no files or directories specified")
5038 msg = _("no files or directories specified")
5046 if p2 != nullid:
5039 if p2 != nullid:
5047 hint = _("uncommitted merge, use --all to discard all changes,"
5040 hint = _("uncommitted merge, use --all to discard all changes,"
5048 " or 'hg update -C .' to abort the merge")
5041 " or 'hg update -C .' to abort the merge")
5049 raise util.Abort(msg, hint=hint)
5042 raise util.Abort(msg, hint=hint)
5050 dirty = util.any(repo.status())
5043 dirty = util.any(repo.status())
5051 node = ctx.node()
5044 node = ctx.node()
5052 if node != parent:
5045 if node != parent:
5053 if dirty:
5046 if dirty:
5054 hint = _("uncommitted changes, use --all to discard all"
5047 hint = _("uncommitted changes, use --all to discard all"
5055 " changes, or 'hg update %s' to update") % ctx.rev()
5048 " changes, or 'hg update %s' to update") % ctx.rev()
5056 else:
5049 else:
5057 hint = _("use --all to revert all files,"
5050 hint = _("use --all to revert all files,"
5058 " or 'hg update %s' to update") % ctx.rev()
5051 " or 'hg update %s' to update") % ctx.rev()
5059 elif dirty:
5052 elif dirty:
5060 hint = _("uncommitted changes, use --all to discard all changes")
5053 hint = _("uncommitted changes, use --all to discard all changes")
5061 else:
5054 else:
5062 hint = _("use --all to revert all files")
5055 hint = _("use --all to revert all files")
5063 raise util.Abort(msg, hint=hint)
5056 raise util.Abort(msg, hint=hint)
5064
5057
5065 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5058 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5066
5059
5067 @command('rollback', dryrunopts +
5060 @command('rollback', dryrunopts +
5068 [('f', 'force', False, _('ignore safety measures'))])
5061 [('f', 'force', False, _('ignore safety measures'))])
5069 def rollback(ui, repo, **opts):
5062 def rollback(ui, repo, **opts):
5070 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5063 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5071
5064
5072 Please use :hg:`commit --amend` instead of rollback to correct
5065 Please use :hg:`commit --amend` instead of rollback to correct
5073 mistakes in the last commit.
5066 mistakes in the last commit.
5074
5067
5075 This command should be used with care. There is only one level of
5068 This command should be used with care. There is only one level of
5076 rollback, and there is no way to undo a rollback. It will also
5069 rollback, and there is no way to undo a rollback. It will also
5077 restore the dirstate at the time of the last transaction, losing
5070 restore the dirstate at the time of the last transaction, losing
5078 any dirstate changes since that time. This command does not alter
5071 any dirstate changes since that time. This command does not alter
5079 the working directory.
5072 the working directory.
5080
5073
5081 Transactions are used to encapsulate the effects of all commands
5074 Transactions are used to encapsulate the effects of all commands
5082 that create new changesets or propagate existing changesets into a
5075 that create new changesets or propagate existing changesets into a
5083 repository.
5076 repository.
5084
5077
5085 .. container:: verbose
5078 .. container:: verbose
5086
5079
5087 For example, the following commands are transactional, and their
5080 For example, the following commands are transactional, and their
5088 effects can be rolled back:
5081 effects can be rolled back:
5089
5082
5090 - commit
5083 - commit
5091 - import
5084 - import
5092 - pull
5085 - pull
5093 - push (with this repository as the destination)
5086 - push (with this repository as the destination)
5094 - unbundle
5087 - unbundle
5095
5088
5096 To avoid permanent data loss, rollback will refuse to rollback a
5089 To avoid permanent data loss, rollback will refuse to rollback a
5097 commit transaction if it isn't checked out. Use --force to
5090 commit transaction if it isn't checked out. Use --force to
5098 override this protection.
5091 override this protection.
5099
5092
5100 This command is not intended for use on public repositories. Once
5093 This command is not intended for use on public repositories. Once
5101 changes are visible for pull by other users, rolling a transaction
5094 changes are visible for pull by other users, rolling a transaction
5102 back locally is ineffective (someone else may already have pulled
5095 back locally is ineffective (someone else may already have pulled
5103 the changes). Furthermore, a race is possible with readers of the
5096 the changes). Furthermore, a race is possible with readers of the
5104 repository; for example an in-progress pull from the repository
5097 repository; for example an in-progress pull from the repository
5105 may fail if a rollback is performed.
5098 may fail if a rollback is performed.
5106
5099
5107 Returns 0 on success, 1 if no rollback data is available.
5100 Returns 0 on success, 1 if no rollback data is available.
5108 """
5101 """
5109 return repo.rollback(dryrun=opts.get('dry_run'),
5102 return repo.rollback(dryrun=opts.get('dry_run'),
5110 force=opts.get('force'))
5103 force=opts.get('force'))
5111
5104
5112 @command('root', [])
5105 @command('root', [])
5113 def root(ui, repo):
5106 def root(ui, repo):
5114 """print the root (top) of the current working directory
5107 """print the root (top) of the current working directory
5115
5108
5116 Print the root directory of the current repository.
5109 Print the root directory of the current repository.
5117
5110
5118 Returns 0 on success.
5111 Returns 0 on success.
5119 """
5112 """
5120 ui.write(repo.root + "\n")
5113 ui.write(repo.root + "\n")
5121
5114
5122 @command('^serve',
5115 @command('^serve',
5123 [('A', 'accesslog', '', _('name of access log file to write to'),
5116 [('A', 'accesslog', '', _('name of access log file to write to'),
5124 _('FILE')),
5117 _('FILE')),
5125 ('d', 'daemon', None, _('run server in background')),
5118 ('d', 'daemon', None, _('run server in background')),
5126 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5119 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5127 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5120 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5128 # use string type, then we can check if something was passed
5121 # use string type, then we can check if something was passed
5129 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5122 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5130 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5123 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5131 _('ADDR')),
5124 _('ADDR')),
5132 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5125 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5133 _('PREFIX')),
5126 _('PREFIX')),
5134 ('n', 'name', '',
5127 ('n', 'name', '',
5135 _('name to show in web pages (default: working directory)'), _('NAME')),
5128 _('name to show in web pages (default: working directory)'), _('NAME')),
5136 ('', 'web-conf', '',
5129 ('', 'web-conf', '',
5137 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5130 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5138 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5131 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5139 _('FILE')),
5132 _('FILE')),
5140 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5133 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5141 ('', 'stdio', None, _('for remote clients')),
5134 ('', 'stdio', None, _('for remote clients')),
5142 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5135 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5143 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5136 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5144 ('', 'style', '', _('template style to use'), _('STYLE')),
5137 ('', 'style', '', _('template style to use'), _('STYLE')),
5145 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5138 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5146 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5139 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5147 _('[OPTION]...'))
5140 _('[OPTION]...'))
5148 def serve(ui, repo, **opts):
5141 def serve(ui, repo, **opts):
5149 """start stand-alone webserver
5142 """start stand-alone webserver
5150
5143
5151 Start a local HTTP repository browser and pull server. You can use
5144 Start a local HTTP repository browser and pull server. You can use
5152 this for ad-hoc sharing and browsing of repositories. It is
5145 this for ad-hoc sharing and browsing of repositories. It is
5153 recommended to use a real web server to serve a repository for
5146 recommended to use a real web server to serve a repository for
5154 longer periods of time.
5147 longer periods of time.
5155
5148
5156 Please note that the server does not implement access control.
5149 Please note that the server does not implement access control.
5157 This means that, by default, anybody can read from the server and
5150 This means that, by default, anybody can read from the server and
5158 nobody can write to it by default. Set the ``web.allow_push``
5151 nobody can write to it by default. Set the ``web.allow_push``
5159 option to ``*`` to allow everybody to push to the server. You
5152 option to ``*`` to allow everybody to push to the server. You
5160 should use a real web server if you need to authenticate users.
5153 should use a real web server if you need to authenticate users.
5161
5154
5162 By default, the server logs accesses to stdout and errors to
5155 By default, the server logs accesses to stdout and errors to
5163 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5156 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5164 files.
5157 files.
5165
5158
5166 To have the server choose a free port number to listen on, specify
5159 To have the server choose a free port number to listen on, specify
5167 a port number of 0; in this case, the server will print the port
5160 a port number of 0; in this case, the server will print the port
5168 number it uses.
5161 number it uses.
5169
5162
5170 Returns 0 on success.
5163 Returns 0 on success.
5171 """
5164 """
5172
5165
5173 if opts["stdio"] and opts["cmdserver"]:
5166 if opts["stdio"] and opts["cmdserver"]:
5174 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5167 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5175
5168
5176 def checkrepo():
5169 def checkrepo():
5177 if repo is None:
5170 if repo is None:
5178 raise error.RepoError(_("there is no Mercurial repository here"
5171 raise error.RepoError(_("there is no Mercurial repository here"
5179 " (.hg not found)"))
5172 " (.hg not found)"))
5180
5173
5181 if opts["stdio"]:
5174 if opts["stdio"]:
5182 checkrepo()
5175 checkrepo()
5183 s = sshserver.sshserver(ui, repo)
5176 s = sshserver.sshserver(ui, repo)
5184 s.serve_forever()
5177 s.serve_forever()
5185
5178
5186 if opts["cmdserver"]:
5179 if opts["cmdserver"]:
5187 checkrepo()
5180 checkrepo()
5188 s = commandserver.server(ui, repo, opts["cmdserver"])
5181 s = commandserver.server(ui, repo, opts["cmdserver"])
5189 return s.serve()
5182 return s.serve()
5190
5183
5191 # this way we can check if something was given in the command-line
5184 # this way we can check if something was given in the command-line
5192 if opts.get('port'):
5185 if opts.get('port'):
5193 opts['port'] = util.getport(opts.get('port'))
5186 opts['port'] = util.getport(opts.get('port'))
5194
5187
5195 baseui = repo and repo.baseui or ui
5188 baseui = repo and repo.baseui or ui
5196 optlist = ("name templates style address port prefix ipv6"
5189 optlist = ("name templates style address port prefix ipv6"
5197 " accesslog errorlog certificate encoding")
5190 " accesslog errorlog certificate encoding")
5198 for o in optlist.split():
5191 for o in optlist.split():
5199 val = opts.get(o, '')
5192 val = opts.get(o, '')
5200 if val in (None, ''): # should check against default options instead
5193 if val in (None, ''): # should check against default options instead
5201 continue
5194 continue
5202 baseui.setconfig("web", o, val)
5195 baseui.setconfig("web", o, val)
5203 if repo and repo.ui != baseui:
5196 if repo and repo.ui != baseui:
5204 repo.ui.setconfig("web", o, val)
5197 repo.ui.setconfig("web", o, val)
5205
5198
5206 o = opts.get('web_conf') or opts.get('webdir_conf')
5199 o = opts.get('web_conf') or opts.get('webdir_conf')
5207 if not o:
5200 if not o:
5208 if not repo:
5201 if not repo:
5209 raise error.RepoError(_("there is no Mercurial repository"
5202 raise error.RepoError(_("there is no Mercurial repository"
5210 " here (.hg not found)"))
5203 " here (.hg not found)"))
5211 o = repo
5204 o = repo
5212
5205
5213 app = hgweb.hgweb(o, baseui=baseui)
5206 app = hgweb.hgweb(o, baseui=baseui)
5214 service = httpservice(ui, app, opts)
5207 service = httpservice(ui, app, opts)
5215 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5208 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5216
5209
5217 class httpservice(object):
5210 class httpservice(object):
5218 def __init__(self, ui, app, opts):
5211 def __init__(self, ui, app, opts):
5219 self.ui = ui
5212 self.ui = ui
5220 self.app = app
5213 self.app = app
5221 self.opts = opts
5214 self.opts = opts
5222
5215
5223 def init(self):
5216 def init(self):
5224 util.setsignalhandler()
5217 util.setsignalhandler()
5225 self.httpd = hgweb_server.create_server(self.ui, self.app)
5218 self.httpd = hgweb_server.create_server(self.ui, self.app)
5226
5219
5227 if self.opts['port'] and not self.ui.verbose:
5220 if self.opts['port'] and not self.ui.verbose:
5228 return
5221 return
5229
5222
5230 if self.httpd.prefix:
5223 if self.httpd.prefix:
5231 prefix = self.httpd.prefix.strip('/') + '/'
5224 prefix = self.httpd.prefix.strip('/') + '/'
5232 else:
5225 else:
5233 prefix = ''
5226 prefix = ''
5234
5227
5235 port = ':%d' % self.httpd.port
5228 port = ':%d' % self.httpd.port
5236 if port == ':80':
5229 if port == ':80':
5237 port = ''
5230 port = ''
5238
5231
5239 bindaddr = self.httpd.addr
5232 bindaddr = self.httpd.addr
5240 if bindaddr == '0.0.0.0':
5233 if bindaddr == '0.0.0.0':
5241 bindaddr = '*'
5234 bindaddr = '*'
5242 elif ':' in bindaddr: # IPv6
5235 elif ':' in bindaddr: # IPv6
5243 bindaddr = '[%s]' % bindaddr
5236 bindaddr = '[%s]' % bindaddr
5244
5237
5245 fqaddr = self.httpd.fqaddr
5238 fqaddr = self.httpd.fqaddr
5246 if ':' in fqaddr:
5239 if ':' in fqaddr:
5247 fqaddr = '[%s]' % fqaddr
5240 fqaddr = '[%s]' % fqaddr
5248 if self.opts['port']:
5241 if self.opts['port']:
5249 write = self.ui.status
5242 write = self.ui.status
5250 else:
5243 else:
5251 write = self.ui.write
5244 write = self.ui.write
5252 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5245 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5253 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5246 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5254
5247
5255 def run(self):
5248 def run(self):
5256 self.httpd.serve_forever()
5249 self.httpd.serve_forever()
5257
5250
5258
5251
5259 @command('showconfig|debugconfig',
5252 @command('showconfig|debugconfig',
5260 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5253 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5261 _('[-u] [NAME]...'))
5254 _('[-u] [NAME]...'))
5262 def showconfig(ui, repo, *values, **opts):
5255 def showconfig(ui, repo, *values, **opts):
5263 """show combined config settings from all hgrc files
5256 """show combined config settings from all hgrc files
5264
5257
5265 With no arguments, print names and values of all config items.
5258 With no arguments, print names and values of all config items.
5266
5259
5267 With one argument of the form section.name, print just the value
5260 With one argument of the form section.name, print just the value
5268 of that config item.
5261 of that config item.
5269
5262
5270 With multiple arguments, print names and values of all config
5263 With multiple arguments, print names and values of all config
5271 items with matching section names.
5264 items with matching section names.
5272
5265
5273 With --debug, the source (filename and line number) is printed
5266 With --debug, the source (filename and line number) is printed
5274 for each config item.
5267 for each config item.
5275
5268
5276 Returns 0 on success.
5269 Returns 0 on success.
5277 """
5270 """
5278
5271
5279 for f in scmutil.rcpath():
5272 for f in scmutil.rcpath():
5280 ui.debug('read config from: %s\n' % f)
5273 ui.debug('read config from: %s\n' % f)
5281 untrusted = bool(opts.get('untrusted'))
5274 untrusted = bool(opts.get('untrusted'))
5282 if values:
5275 if values:
5283 sections = [v for v in values if '.' not in v]
5276 sections = [v for v in values if '.' not in v]
5284 items = [v for v in values if '.' in v]
5277 items = [v for v in values if '.' in v]
5285 if len(items) > 1 or items and sections:
5278 if len(items) > 1 or items and sections:
5286 raise util.Abort(_('only one config item permitted'))
5279 raise util.Abort(_('only one config item permitted'))
5287 for section, name, value in ui.walkconfig(untrusted=untrusted):
5280 for section, name, value in ui.walkconfig(untrusted=untrusted):
5288 value = str(value).replace('\n', '\\n')
5281 value = str(value).replace('\n', '\\n')
5289 sectname = section + '.' + name
5282 sectname = section + '.' + name
5290 if values:
5283 if values:
5291 for v in values:
5284 for v in values:
5292 if v == section:
5285 if v == section:
5293 ui.debug('%s: ' %
5286 ui.debug('%s: ' %
5294 ui.configsource(section, name, untrusted))
5287 ui.configsource(section, name, untrusted))
5295 ui.write('%s=%s\n' % (sectname, value))
5288 ui.write('%s=%s\n' % (sectname, value))
5296 elif v == sectname:
5289 elif v == sectname:
5297 ui.debug('%s: ' %
5290 ui.debug('%s: ' %
5298 ui.configsource(section, name, untrusted))
5291 ui.configsource(section, name, untrusted))
5299 ui.write(value, '\n')
5292 ui.write(value, '\n')
5300 else:
5293 else:
5301 ui.debug('%s: ' %
5294 ui.debug('%s: ' %
5302 ui.configsource(section, name, untrusted))
5295 ui.configsource(section, name, untrusted))
5303 ui.write('%s=%s\n' % (sectname, value))
5296 ui.write('%s=%s\n' % (sectname, value))
5304
5297
5305 @command('^status|st',
5298 @command('^status|st',
5306 [('A', 'all', None, _('show status of all files')),
5299 [('A', 'all', None, _('show status of all files')),
5307 ('m', 'modified', None, _('show only modified files')),
5300 ('m', 'modified', None, _('show only modified files')),
5308 ('a', 'added', None, _('show only added files')),
5301 ('a', 'added', None, _('show only added files')),
5309 ('r', 'removed', None, _('show only removed files')),
5302 ('r', 'removed', None, _('show only removed files')),
5310 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5303 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5311 ('c', 'clean', None, _('show only files without changes')),
5304 ('c', 'clean', None, _('show only files without changes')),
5312 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5305 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5313 ('i', 'ignored', None, _('show only ignored files')),
5306 ('i', 'ignored', None, _('show only ignored files')),
5314 ('n', 'no-status', None, _('hide status prefix')),
5307 ('n', 'no-status', None, _('hide status prefix')),
5315 ('C', 'copies', None, _('show source of copied files')),
5308 ('C', 'copies', None, _('show source of copied files')),
5316 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5309 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5317 ('', 'rev', [], _('show difference from revision'), _('REV')),
5310 ('', 'rev', [], _('show difference from revision'), _('REV')),
5318 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5311 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5319 ] + walkopts + subrepoopts,
5312 ] + walkopts + subrepoopts,
5320 _('[OPTION]... [FILE]...'))
5313 _('[OPTION]... [FILE]...'))
5321 def status(ui, repo, *pats, **opts):
5314 def status(ui, repo, *pats, **opts):
5322 """show changed files in the working directory
5315 """show changed files in the working directory
5323
5316
5324 Show status of files in the repository. If names are given, only
5317 Show status of files in the repository. If names are given, only
5325 files that match are shown. Files that are clean or ignored or
5318 files that match are shown. Files that are clean or ignored or
5326 the source of a copy/move operation, are not listed unless
5319 the source of a copy/move operation, are not listed unless
5327 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5320 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5328 Unless options described with "show only ..." are given, the
5321 Unless options described with "show only ..." are given, the
5329 options -mardu are used.
5322 options -mardu are used.
5330
5323
5331 Option -q/--quiet hides untracked (unknown and ignored) files
5324 Option -q/--quiet hides untracked (unknown and ignored) files
5332 unless explicitly requested with -u/--unknown or -i/--ignored.
5325 unless explicitly requested with -u/--unknown or -i/--ignored.
5333
5326
5334 .. note::
5327 .. note::
5335
5328
5336 status may appear to disagree with diff if permissions have
5329 status may appear to disagree with diff if permissions have
5337 changed or a merge has occurred. The standard diff format does
5330 changed or a merge has occurred. The standard diff format does
5338 not report permission changes and diff only reports changes
5331 not report permission changes and diff only reports changes
5339 relative to one merge parent.
5332 relative to one merge parent.
5340
5333
5341 If one revision is given, it is used as the base revision.
5334 If one revision is given, it is used as the base revision.
5342 If two revisions are given, the differences between them are
5335 If two revisions are given, the differences between them are
5343 shown. The --change option can also be used as a shortcut to list
5336 shown. The --change option can also be used as a shortcut to list
5344 the changed files of a revision from its first parent.
5337 the changed files of a revision from its first parent.
5345
5338
5346 The codes used to show the status of files are::
5339 The codes used to show the status of files are::
5347
5340
5348 M = modified
5341 M = modified
5349 A = added
5342 A = added
5350 R = removed
5343 R = removed
5351 C = clean
5344 C = clean
5352 ! = missing (deleted by non-hg command, but still tracked)
5345 ! = missing (deleted by non-hg command, but still tracked)
5353 ? = not tracked
5346 ? = not tracked
5354 I = ignored
5347 I = ignored
5355 = origin of the previous file listed as A (added)
5348 = origin of the previous file listed as A (added)
5356
5349
5357 .. container:: verbose
5350 .. container:: verbose
5358
5351
5359 Examples:
5352 Examples:
5360
5353
5361 - show changes in the working directory relative to a
5354 - show changes in the working directory relative to a
5362 changeset::
5355 changeset::
5363
5356
5364 hg status --rev 9353
5357 hg status --rev 9353
5365
5358
5366 - show all changes including copies in an existing changeset::
5359 - show all changes including copies in an existing changeset::
5367
5360
5368 hg status --copies --change 9353
5361 hg status --copies --change 9353
5369
5362
5370 - get a NUL separated list of added files, suitable for xargs::
5363 - get a NUL separated list of added files, suitable for xargs::
5371
5364
5372 hg status -an0
5365 hg status -an0
5373
5366
5374 Returns 0 on success.
5367 Returns 0 on success.
5375 """
5368 """
5376
5369
5377 revs = opts.get('rev')
5370 revs = opts.get('rev')
5378 change = opts.get('change')
5371 change = opts.get('change')
5379
5372
5380 if revs and change:
5373 if revs and change:
5381 msg = _('cannot specify --rev and --change at the same time')
5374 msg = _('cannot specify --rev and --change at the same time')
5382 raise util.Abort(msg)
5375 raise util.Abort(msg)
5383 elif change:
5376 elif change:
5384 node2 = scmutil.revsingle(repo, change, None).node()
5377 node2 = scmutil.revsingle(repo, change, None).node()
5385 node1 = repo[node2].p1().node()
5378 node1 = repo[node2].p1().node()
5386 else:
5379 else:
5387 node1, node2 = scmutil.revpair(repo, revs)
5380 node1, node2 = scmutil.revpair(repo, revs)
5388
5381
5389 cwd = (pats and repo.getcwd()) or ''
5382 cwd = (pats and repo.getcwd()) or ''
5390 end = opts.get('print0') and '\0' or '\n'
5383 end = opts.get('print0') and '\0' or '\n'
5391 copy = {}
5384 copy = {}
5392 states = 'modified added removed deleted unknown ignored clean'.split()
5385 states = 'modified added removed deleted unknown ignored clean'.split()
5393 show = [k for k in states if opts.get(k)]
5386 show = [k for k in states if opts.get(k)]
5394 if opts.get('all'):
5387 if opts.get('all'):
5395 show += ui.quiet and (states[:4] + ['clean']) or states
5388 show += ui.quiet and (states[:4] + ['clean']) or states
5396 if not show:
5389 if not show:
5397 show = ui.quiet and states[:4] or states[:5]
5390 show = ui.quiet and states[:4] or states[:5]
5398
5391
5399 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5392 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5400 'ignored' in show, 'clean' in show, 'unknown' in show,
5393 'ignored' in show, 'clean' in show, 'unknown' in show,
5401 opts.get('subrepos'))
5394 opts.get('subrepos'))
5402 changestates = zip(states, 'MAR!?IC', stat)
5395 changestates = zip(states, 'MAR!?IC', stat)
5403
5396
5404 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5397 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5405 copy = copies.pathcopies(repo[node1], repo[node2])
5398 copy = copies.pathcopies(repo[node1], repo[node2])
5406
5399
5407 fm = ui.formatter('status', opts)
5400 fm = ui.formatter('status', opts)
5408 fmt = '%s' + end
5401 fmt = '%s' + end
5409 showchar = not opts.get('no_status')
5402 showchar = not opts.get('no_status')
5410
5403
5411 for state, char, files in changestates:
5404 for state, char, files in changestates:
5412 if state in show:
5405 if state in show:
5413 label = 'status.' + state
5406 label = 'status.' + state
5414 for f in files:
5407 for f in files:
5415 fm.startitem()
5408 fm.startitem()
5416 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5409 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5417 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5410 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5418 if f in copy:
5411 if f in copy:
5419 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5412 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5420 label='status.copied')
5413 label='status.copied')
5421 fm.end()
5414 fm.end()
5422
5415
5423 @command('^summary|sum',
5416 @command('^summary|sum',
5424 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5417 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5425 def summary(ui, repo, **opts):
5418 def summary(ui, repo, **opts):
5426 """summarize working directory state
5419 """summarize working directory state
5427
5420
5428 This generates a brief summary of the working directory state,
5421 This generates a brief summary of the working directory state,
5429 including parents, branch, commit status, and available updates.
5422 including parents, branch, commit status, and available updates.
5430
5423
5431 With the --remote option, this will check the default paths for
5424 With the --remote option, this will check the default paths for
5432 incoming and outgoing changes. This can be time-consuming.
5425 incoming and outgoing changes. This can be time-consuming.
5433
5426
5434 Returns 0 on success.
5427 Returns 0 on success.
5435 """
5428 """
5436
5429
5437 ctx = repo[None]
5430 ctx = repo[None]
5438 parents = ctx.parents()
5431 parents = ctx.parents()
5439 pnode = parents[0].node()
5432 pnode = parents[0].node()
5440 marks = []
5433 marks = []
5441
5434
5442 for p in parents:
5435 for p in parents:
5443 # label with log.changeset (instead of log.parent) since this
5436 # label with log.changeset (instead of log.parent) since this
5444 # shows a working directory parent *changeset*:
5437 # shows a working directory parent *changeset*:
5445 # i18n: column positioning for "hg summary"
5438 # i18n: column positioning for "hg summary"
5446 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5439 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5447 label='log.changeset changeset.%s' % p.phasestr())
5440 label='log.changeset changeset.%s' % p.phasestr())
5448 ui.write(' '.join(p.tags()), label='log.tag')
5441 ui.write(' '.join(p.tags()), label='log.tag')
5449 if p.bookmarks():
5442 if p.bookmarks():
5450 marks.extend(p.bookmarks())
5443 marks.extend(p.bookmarks())
5451 if p.rev() == -1:
5444 if p.rev() == -1:
5452 if not len(repo):
5445 if not len(repo):
5453 ui.write(_(' (empty repository)'))
5446 ui.write(_(' (empty repository)'))
5454 else:
5447 else:
5455 ui.write(_(' (no revision checked out)'))
5448 ui.write(_(' (no revision checked out)'))
5456 ui.write('\n')
5449 ui.write('\n')
5457 if p.description():
5450 if p.description():
5458 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5451 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5459 label='log.summary')
5452 label='log.summary')
5460
5453
5461 branch = ctx.branch()
5454 branch = ctx.branch()
5462 bheads = repo.branchheads(branch)
5455 bheads = repo.branchheads(branch)
5463 # i18n: column positioning for "hg summary"
5456 # i18n: column positioning for "hg summary"
5464 m = _('branch: %s\n') % branch
5457 m = _('branch: %s\n') % branch
5465 if branch != 'default':
5458 if branch != 'default':
5466 ui.write(m, label='log.branch')
5459 ui.write(m, label='log.branch')
5467 else:
5460 else:
5468 ui.status(m, label='log.branch')
5461 ui.status(m, label='log.branch')
5469
5462
5470 if marks:
5463 if marks:
5471 current = repo._bookmarkcurrent
5464 current = repo._bookmarkcurrent
5472 # i18n: column positioning for "hg summary"
5465 # i18n: column positioning for "hg summary"
5473 ui.write(_('bookmarks:'), label='log.bookmark')
5466 ui.write(_('bookmarks:'), label='log.bookmark')
5474 if current is not None:
5467 if current is not None:
5475 if current in marks:
5468 if current in marks:
5476 ui.write(' *' + current, label='bookmarks.current')
5469 ui.write(' *' + current, label='bookmarks.current')
5477 marks.remove(current)
5470 marks.remove(current)
5478 else:
5471 else:
5479 ui.write(' [%s]' % current, label='bookmarks.current')
5472 ui.write(' [%s]' % current, label='bookmarks.current')
5480 for m in marks:
5473 for m in marks:
5481 ui.write(' ' + m, label='log.bookmark')
5474 ui.write(' ' + m, label='log.bookmark')
5482 ui.write('\n', label='log.bookmark')
5475 ui.write('\n', label='log.bookmark')
5483
5476
5484 st = list(repo.status(unknown=True))[:6]
5477 st = list(repo.status(unknown=True))[:6]
5485
5478
5486 c = repo.dirstate.copies()
5479 c = repo.dirstate.copies()
5487 copied, renamed = [], []
5480 copied, renamed = [], []
5488 for d, s in c.iteritems():
5481 for d, s in c.iteritems():
5489 if s in st[2]:
5482 if s in st[2]:
5490 st[2].remove(s)
5483 st[2].remove(s)
5491 renamed.append(d)
5484 renamed.append(d)
5492 else:
5485 else:
5493 copied.append(d)
5486 copied.append(d)
5494 if d in st[1]:
5487 if d in st[1]:
5495 st[1].remove(d)
5488 st[1].remove(d)
5496 st.insert(3, renamed)
5489 st.insert(3, renamed)
5497 st.insert(4, copied)
5490 st.insert(4, copied)
5498
5491
5499 ms = mergemod.mergestate(repo)
5492 ms = mergemod.mergestate(repo)
5500 st.append([f for f in ms if ms[f] == 'u'])
5493 st.append([f for f in ms if ms[f] == 'u'])
5501
5494
5502 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5495 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5503 st.append(subs)
5496 st.append(subs)
5504
5497
5505 labels = [ui.label(_('%d modified'), 'status.modified'),
5498 labels = [ui.label(_('%d modified'), 'status.modified'),
5506 ui.label(_('%d added'), 'status.added'),
5499 ui.label(_('%d added'), 'status.added'),
5507 ui.label(_('%d removed'), 'status.removed'),
5500 ui.label(_('%d removed'), 'status.removed'),
5508 ui.label(_('%d renamed'), 'status.copied'),
5501 ui.label(_('%d renamed'), 'status.copied'),
5509 ui.label(_('%d copied'), 'status.copied'),
5502 ui.label(_('%d copied'), 'status.copied'),
5510 ui.label(_('%d deleted'), 'status.deleted'),
5503 ui.label(_('%d deleted'), 'status.deleted'),
5511 ui.label(_('%d unknown'), 'status.unknown'),
5504 ui.label(_('%d unknown'), 'status.unknown'),
5512 ui.label(_('%d ignored'), 'status.ignored'),
5505 ui.label(_('%d ignored'), 'status.ignored'),
5513 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5506 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5514 ui.label(_('%d subrepos'), 'status.modified')]
5507 ui.label(_('%d subrepos'), 'status.modified')]
5515 t = []
5508 t = []
5516 for s, l in zip(st, labels):
5509 for s, l in zip(st, labels):
5517 if s:
5510 if s:
5518 t.append(l % len(s))
5511 t.append(l % len(s))
5519
5512
5520 t = ', '.join(t)
5513 t = ', '.join(t)
5521 cleanworkdir = False
5514 cleanworkdir = False
5522
5515
5523 if repo.vfs.exists('updatestate'):
5516 if repo.vfs.exists('updatestate'):
5524 t += _(' (interrupted update)')
5517 t += _(' (interrupted update)')
5525 elif len(parents) > 1:
5518 elif len(parents) > 1:
5526 t += _(' (merge)')
5519 t += _(' (merge)')
5527 elif branch != parents[0].branch():
5520 elif branch != parents[0].branch():
5528 t += _(' (new branch)')
5521 t += _(' (new branch)')
5529 elif (parents[0].closesbranch() and
5522 elif (parents[0].closesbranch() and
5530 pnode in repo.branchheads(branch, closed=True)):
5523 pnode in repo.branchheads(branch, closed=True)):
5531 t += _(' (head closed)')
5524 t += _(' (head closed)')
5532 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5525 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5533 t += _(' (clean)')
5526 t += _(' (clean)')
5534 cleanworkdir = True
5527 cleanworkdir = True
5535 elif pnode not in bheads:
5528 elif pnode not in bheads:
5536 t += _(' (new branch head)')
5529 t += _(' (new branch head)')
5537
5530
5538 if cleanworkdir:
5531 if cleanworkdir:
5539 # i18n: column positioning for "hg summary"
5532 # i18n: column positioning for "hg summary"
5540 ui.status(_('commit: %s\n') % t.strip())
5533 ui.status(_('commit: %s\n') % t.strip())
5541 else:
5534 else:
5542 # i18n: column positioning for "hg summary"
5535 # i18n: column positioning for "hg summary"
5543 ui.write(_('commit: %s\n') % t.strip())
5536 ui.write(_('commit: %s\n') % t.strip())
5544
5537
5545 # all ancestors of branch heads - all ancestors of parent = new csets
5538 # all ancestors of branch heads - all ancestors of parent = new csets
5546 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5539 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5547 bheads))
5540 bheads))
5548
5541
5549 if new == 0:
5542 if new == 0:
5550 # i18n: column positioning for "hg summary"
5543 # i18n: column positioning for "hg summary"
5551 ui.status(_('update: (current)\n'))
5544 ui.status(_('update: (current)\n'))
5552 elif pnode not in bheads:
5545 elif pnode not in bheads:
5553 # i18n: column positioning for "hg summary"
5546 # i18n: column positioning for "hg summary"
5554 ui.write(_('update: %d new changesets (update)\n') % new)
5547 ui.write(_('update: %d new changesets (update)\n') % new)
5555 else:
5548 else:
5556 # i18n: column positioning for "hg summary"
5549 # i18n: column positioning for "hg summary"
5557 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5550 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5558 (new, len(bheads)))
5551 (new, len(bheads)))
5559
5552
5560 cmdutil.summaryhooks(ui, repo)
5553 cmdutil.summaryhooks(ui, repo)
5561
5554
5562 if opts.get('remote'):
5555 if opts.get('remote'):
5563 t = []
5556 t = []
5564 source, branches = hg.parseurl(ui.expandpath('default'))
5557 source, branches = hg.parseurl(ui.expandpath('default'))
5565 sbranch = branches[0]
5558 sbranch = branches[0]
5566 other = hg.peer(repo, {}, source)
5559 other = hg.peer(repo, {}, source)
5567 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5560 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5568 if revs:
5561 if revs:
5569 revs = [other.lookup(rev) for rev in revs]
5562 revs = [other.lookup(rev) for rev in revs]
5570 ui.debug('comparing with %s\n' % util.hidepassword(source))
5563 ui.debug('comparing with %s\n' % util.hidepassword(source))
5571 repo.ui.pushbuffer()
5564 repo.ui.pushbuffer()
5572 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5565 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5573 _common, incoming, _rheads = commoninc
5566 _common, incoming, _rheads = commoninc
5574 repo.ui.popbuffer()
5567 repo.ui.popbuffer()
5575 if incoming:
5568 if incoming:
5576 t.append(_('1 or more incoming'))
5569 t.append(_('1 or more incoming'))
5577
5570
5578 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5571 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5579 dbranch = branches[0]
5572 dbranch = branches[0]
5580 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5573 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5581 if source != dest:
5574 if source != dest:
5582 other = hg.peer(repo, {}, dest)
5575 other = hg.peer(repo, {}, dest)
5583 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5576 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5584 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5577 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5585 commoninc = None
5578 commoninc = None
5586 if revs:
5579 if revs:
5587 revs = [repo.lookup(rev) for rev in revs]
5580 revs = [repo.lookup(rev) for rev in revs]
5588 repo.ui.pushbuffer()
5581 repo.ui.pushbuffer()
5589 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5582 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5590 commoninc=commoninc)
5583 commoninc=commoninc)
5591 repo.ui.popbuffer()
5584 repo.ui.popbuffer()
5592 o = outgoing.missing
5585 o = outgoing.missing
5593 if o:
5586 if o:
5594 t.append(_('%d outgoing') % len(o))
5587 t.append(_('%d outgoing') % len(o))
5595 if 'bookmarks' in other.listkeys('namespaces'):
5588 if 'bookmarks' in other.listkeys('namespaces'):
5596 lmarks = repo.listkeys('bookmarks')
5589 lmarks = repo.listkeys('bookmarks')
5597 rmarks = other.listkeys('bookmarks')
5590 rmarks = other.listkeys('bookmarks')
5598 diff = set(rmarks) - set(lmarks)
5591 diff = set(rmarks) - set(lmarks)
5599 if len(diff) > 0:
5592 if len(diff) > 0:
5600 t.append(_('%d incoming bookmarks') % len(diff))
5593 t.append(_('%d incoming bookmarks') % len(diff))
5601 diff = set(lmarks) - set(rmarks)
5594 diff = set(lmarks) - set(rmarks)
5602 if len(diff) > 0:
5595 if len(diff) > 0:
5603 t.append(_('%d outgoing bookmarks') % len(diff))
5596 t.append(_('%d outgoing bookmarks') % len(diff))
5604
5597
5605 if t:
5598 if t:
5606 # i18n: column positioning for "hg summary"
5599 # i18n: column positioning for "hg summary"
5607 ui.write(_('remote: %s\n') % (', '.join(t)))
5600 ui.write(_('remote: %s\n') % (', '.join(t)))
5608 else:
5601 else:
5609 # i18n: column positioning for "hg summary"
5602 # i18n: column positioning for "hg summary"
5610 ui.status(_('remote: (synced)\n'))
5603 ui.status(_('remote: (synced)\n'))
5611
5604
5612 @command('tag',
5605 @command('tag',
5613 [('f', 'force', None, _('force tag')),
5606 [('f', 'force', None, _('force tag')),
5614 ('l', 'local', None, _('make the tag local')),
5607 ('l', 'local', None, _('make the tag local')),
5615 ('r', 'rev', '', _('revision to tag'), _('REV')),
5608 ('r', 'rev', '', _('revision to tag'), _('REV')),
5616 ('', 'remove', None, _('remove a tag')),
5609 ('', 'remove', None, _('remove a tag')),
5617 # -l/--local is already there, commitopts cannot be used
5610 # -l/--local is already there, commitopts cannot be used
5618 ('e', 'edit', None, _('edit commit message')),
5611 ('e', 'edit', None, _('edit commit message')),
5619 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5612 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5620 ] + commitopts2,
5613 ] + commitopts2,
5621 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5614 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5622 def tag(ui, repo, name1, *names, **opts):
5615 def tag(ui, repo, name1, *names, **opts):
5623 """add one or more tags for the current or given revision
5616 """add one or more tags for the current or given revision
5624
5617
5625 Name a particular revision using <name>.
5618 Name a particular revision using <name>.
5626
5619
5627 Tags are used to name particular revisions of the repository and are
5620 Tags are used to name particular revisions of the repository and are
5628 very useful to compare different revisions, to go back to significant
5621 very useful to compare different revisions, to go back to significant
5629 earlier versions or to mark branch points as releases, etc. Changing
5622 earlier versions or to mark branch points as releases, etc. Changing
5630 an existing tag is normally disallowed; use -f/--force to override.
5623 an existing tag is normally disallowed; use -f/--force to override.
5631
5624
5632 If no revision is given, the parent of the working directory is
5625 If no revision is given, the parent of the working directory is
5633 used.
5626 used.
5634
5627
5635 To facilitate version control, distribution, and merging of tags,
5628 To facilitate version control, distribution, and merging of tags,
5636 they are stored as a file named ".hgtags" which is managed similarly
5629 they are stored as a file named ".hgtags" which is managed similarly
5637 to other project files and can be hand-edited if necessary. This
5630 to other project files and can be hand-edited if necessary. This
5638 also means that tagging creates a new commit. The file
5631 also means that tagging creates a new commit. The file
5639 ".hg/localtags" is used for local tags (not shared among
5632 ".hg/localtags" is used for local tags (not shared among
5640 repositories).
5633 repositories).
5641
5634
5642 Tag commits are usually made at the head of a branch. If the parent
5635 Tag commits are usually made at the head of a branch. If the parent
5643 of the working directory is not a branch head, :hg:`tag` aborts; use
5636 of the working directory is not a branch head, :hg:`tag` aborts; use
5644 -f/--force to force the tag commit to be based on a non-head
5637 -f/--force to force the tag commit to be based on a non-head
5645 changeset.
5638 changeset.
5646
5639
5647 See :hg:`help dates` for a list of formats valid for -d/--date.
5640 See :hg:`help dates` for a list of formats valid for -d/--date.
5648
5641
5649 Since tag names have priority over branch names during revision
5642 Since tag names have priority over branch names during revision
5650 lookup, using an existing branch name as a tag name is discouraged.
5643 lookup, using an existing branch name as a tag name is discouraged.
5651
5644
5652 Returns 0 on success.
5645 Returns 0 on success.
5653 """
5646 """
5654 wlock = lock = None
5647 wlock = lock = None
5655 try:
5648 try:
5656 wlock = repo.wlock()
5649 wlock = repo.wlock()
5657 lock = repo.lock()
5650 lock = repo.lock()
5658 rev_ = "."
5651 rev_ = "."
5659 names = [t.strip() for t in (name1,) + names]
5652 names = [t.strip() for t in (name1,) + names]
5660 if len(names) != len(set(names)):
5653 if len(names) != len(set(names)):
5661 raise util.Abort(_('tag names must be unique'))
5654 raise util.Abort(_('tag names must be unique'))
5662 for n in names:
5655 for n in names:
5663 scmutil.checknewlabel(repo, n, 'tag')
5656 scmutil.checknewlabel(repo, n, 'tag')
5664 if not n:
5657 if not n:
5665 raise util.Abort(_('tag names cannot consist entirely of '
5658 raise util.Abort(_('tag names cannot consist entirely of '
5666 'whitespace'))
5659 'whitespace'))
5667 if opts.get('rev') and opts.get('remove'):
5660 if opts.get('rev') and opts.get('remove'):
5668 raise util.Abort(_("--rev and --remove are incompatible"))
5661 raise util.Abort(_("--rev and --remove are incompatible"))
5669 if opts.get('rev'):
5662 if opts.get('rev'):
5670 rev_ = opts['rev']
5663 rev_ = opts['rev']
5671 message = opts.get('message')
5664 message = opts.get('message')
5672 if opts.get('remove'):
5665 if opts.get('remove'):
5673 expectedtype = opts.get('local') and 'local' or 'global'
5666 expectedtype = opts.get('local') and 'local' or 'global'
5674 for n in names:
5667 for n in names:
5675 if not repo.tagtype(n):
5668 if not repo.tagtype(n):
5676 raise util.Abort(_("tag '%s' does not exist") % n)
5669 raise util.Abort(_("tag '%s' does not exist") % n)
5677 if repo.tagtype(n) != expectedtype:
5670 if repo.tagtype(n) != expectedtype:
5678 if expectedtype == 'global':
5671 if expectedtype == 'global':
5679 raise util.Abort(_("tag '%s' is not a global tag") % n)
5672 raise util.Abort(_("tag '%s' is not a global tag") % n)
5680 else:
5673 else:
5681 raise util.Abort(_("tag '%s' is not a local tag") % n)
5674 raise util.Abort(_("tag '%s' is not a local tag") % n)
5682 rev_ = nullid
5675 rev_ = nullid
5683 if not message:
5676 if not message:
5684 # we don't translate commit messages
5677 # we don't translate commit messages
5685 message = 'Removed tag %s' % ', '.join(names)
5678 message = 'Removed tag %s' % ', '.join(names)
5686 elif not opts.get('force'):
5679 elif not opts.get('force'):
5687 for n in names:
5680 for n in names:
5688 if n in repo.tags():
5681 if n in repo.tags():
5689 raise util.Abort(_("tag '%s' already exists "
5682 raise util.Abort(_("tag '%s' already exists "
5690 "(use -f to force)") % n)
5683 "(use -f to force)") % n)
5691 if not opts.get('local'):
5684 if not opts.get('local'):
5692 p1, p2 = repo.dirstate.parents()
5685 p1, p2 = repo.dirstate.parents()
5693 if p2 != nullid:
5686 if p2 != nullid:
5694 raise util.Abort(_('uncommitted merge'))
5687 raise util.Abort(_('uncommitted merge'))
5695 bheads = repo.branchheads()
5688 bheads = repo.branchheads()
5696 if not opts.get('force') and bheads and p1 not in bheads:
5689 if not opts.get('force') and bheads and p1 not in bheads:
5697 raise util.Abort(_('not at a branch head (use -f to force)'))
5690 raise util.Abort(_('not at a branch head (use -f to force)'))
5698 r = scmutil.revsingle(repo, rev_).node()
5691 r = scmutil.revsingle(repo, rev_).node()
5699
5692
5700 if not message:
5693 if not message:
5701 # we don't translate commit messages
5694 # we don't translate commit messages
5702 message = ('Added tag %s for changeset %s' %
5695 message = ('Added tag %s for changeset %s' %
5703 (', '.join(names), short(r)))
5696 (', '.join(names), short(r)))
5704
5697
5705 date = opts.get('date')
5698 date = opts.get('date')
5706 if date:
5699 if date:
5707 date = util.parsedate(date)
5700 date = util.parsedate(date)
5708
5701
5709 if opts.get('edit'):
5702 if opts.get('edit'):
5710 message = ui.edit(message, ui.username())
5703 message = ui.edit(message, ui.username())
5711
5704
5712 # don't allow tagging the null rev
5705 # don't allow tagging the null rev
5713 if (not opts.get('remove') and
5706 if (not opts.get('remove') and
5714 scmutil.revsingle(repo, rev_).rev() == nullrev):
5707 scmutil.revsingle(repo, rev_).rev() == nullrev):
5715 raise util.Abort(_("cannot tag null revision"))
5708 raise util.Abort(_("cannot tag null revision"))
5716
5709
5717 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5710 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5718 finally:
5711 finally:
5719 release(lock, wlock)
5712 release(lock, wlock)
5720
5713
5721 @command('tags', [], '')
5714 @command('tags', [], '')
5722 def tags(ui, repo, **opts):
5715 def tags(ui, repo, **opts):
5723 """list repository tags
5716 """list repository tags
5724
5717
5725 This lists both regular and local tags. When the -v/--verbose
5718 This lists both regular and local tags. When the -v/--verbose
5726 switch is used, a third column "local" is printed for local tags.
5719 switch is used, a third column "local" is printed for local tags.
5727
5720
5728 Returns 0 on success.
5721 Returns 0 on success.
5729 """
5722 """
5730
5723
5731 fm = ui.formatter('tags', opts)
5724 fm = ui.formatter('tags', opts)
5732 hexfunc = ui.debugflag and hex or short
5725 hexfunc = ui.debugflag and hex or short
5733 tagtype = ""
5726 tagtype = ""
5734
5727
5735 for t, n in reversed(repo.tagslist()):
5728 for t, n in reversed(repo.tagslist()):
5736 hn = hexfunc(n)
5729 hn = hexfunc(n)
5737 label = 'tags.normal'
5730 label = 'tags.normal'
5738 tagtype = ''
5731 tagtype = ''
5739 if repo.tagtype(t) == 'local':
5732 if repo.tagtype(t) == 'local':
5740 label = 'tags.local'
5733 label = 'tags.local'
5741 tagtype = 'local'
5734 tagtype = 'local'
5742
5735
5743 fm.startitem()
5736 fm.startitem()
5744 fm.write('tag', '%s', t, label=label)
5737 fm.write('tag', '%s', t, label=label)
5745 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5738 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5746 fm.condwrite(not ui.quiet, 'rev id', fmt,
5739 fm.condwrite(not ui.quiet, 'rev id', fmt,
5747 repo.changelog.rev(n), hn, label=label)
5740 repo.changelog.rev(n), hn, label=label)
5748 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5741 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5749 tagtype, label=label)
5742 tagtype, label=label)
5750 fm.plain('\n')
5743 fm.plain('\n')
5751 fm.end()
5744 fm.end()
5752
5745
5753 @command('tip',
5746 @command('tip',
5754 [('p', 'patch', None, _('show patch')),
5747 [('p', 'patch', None, _('show patch')),
5755 ('g', 'git', None, _('use git extended diff format')),
5748 ('g', 'git', None, _('use git extended diff format')),
5756 ] + templateopts,
5749 ] + templateopts,
5757 _('[-p] [-g]'))
5750 _('[-p] [-g]'))
5758 def tip(ui, repo, **opts):
5751 def tip(ui, repo, **opts):
5759 """show the tip revision (DEPRECATED)
5752 """show the tip revision (DEPRECATED)
5760
5753
5761 The tip revision (usually just called the tip) is the changeset
5754 The tip revision (usually just called the tip) is the changeset
5762 most recently added to the repository (and therefore the most
5755 most recently added to the repository (and therefore the most
5763 recently changed head).
5756 recently changed head).
5764
5757
5765 If you have just made a commit, that commit will be the tip. If
5758 If you have just made a commit, that commit will be the tip. If
5766 you have just pulled changes from another repository, the tip of
5759 you have just pulled changes from another repository, the tip of
5767 that repository becomes the current tip. The "tip" tag is special
5760 that repository becomes the current tip. The "tip" tag is special
5768 and cannot be renamed or assigned to a different changeset.
5761 and cannot be renamed or assigned to a different changeset.
5769
5762
5770 This command is deprecated, please use :hg:`heads` instead.
5763 This command is deprecated, please use :hg:`heads` instead.
5771
5764
5772 Returns 0 on success.
5765 Returns 0 on success.
5773 """
5766 """
5774 displayer = cmdutil.show_changeset(ui, repo, opts)
5767 displayer = cmdutil.show_changeset(ui, repo, opts)
5775 displayer.show(repo['tip'])
5768 displayer.show(repo['tip'])
5776 displayer.close()
5769 displayer.close()
5777
5770
5778 @command('unbundle',
5771 @command('unbundle',
5779 [('u', 'update', None,
5772 [('u', 'update', None,
5780 _('update to new branch head if changesets were unbundled'))],
5773 _('update to new branch head if changesets were unbundled'))],
5781 _('[-u] FILE...'))
5774 _('[-u] FILE...'))
5782 def unbundle(ui, repo, fname1, *fnames, **opts):
5775 def unbundle(ui, repo, fname1, *fnames, **opts):
5783 """apply one or more changegroup files
5776 """apply one or more changegroup files
5784
5777
5785 Apply one or more compressed changegroup files generated by the
5778 Apply one or more compressed changegroup files generated by the
5786 bundle command.
5779 bundle command.
5787
5780
5788 Returns 0 on success, 1 if an update has unresolved files.
5781 Returns 0 on success, 1 if an update has unresolved files.
5789 """
5782 """
5790 fnames = (fname1,) + fnames
5783 fnames = (fname1,) + fnames
5791
5784
5792 lock = repo.lock()
5785 lock = repo.lock()
5793 wc = repo['.']
5786 wc = repo['.']
5794 try:
5787 try:
5795 for fname in fnames:
5788 for fname in fnames:
5796 f = hg.openpath(ui, fname)
5789 f = hg.openpath(ui, fname)
5797 gen = changegroup.readbundle(f, fname)
5790 gen = changegroup.readbundle(f, fname)
5798 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5791 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5799 finally:
5792 finally:
5800 lock.release()
5793 lock.release()
5801 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5794 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5802 return postincoming(ui, repo, modheads, opts.get('update'), None)
5795 return postincoming(ui, repo, modheads, opts.get('update'), None)
5803
5796
5804 @command('^update|up|checkout|co',
5797 @command('^update|up|checkout|co',
5805 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5798 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5806 ('c', 'check', None,
5799 ('c', 'check', None,
5807 _('update across branches if no uncommitted changes')),
5800 _('update across branches if no uncommitted changes')),
5808 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5801 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5809 ('r', 'rev', '', _('revision'), _('REV'))],
5802 ('r', 'rev', '', _('revision'), _('REV'))],
5810 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5803 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5811 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5804 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5812 """update working directory (or switch revisions)
5805 """update working directory (or switch revisions)
5813
5806
5814 Update the repository's working directory to the specified
5807 Update the repository's working directory to the specified
5815 changeset. If no changeset is specified, update to the tip of the
5808 changeset. If no changeset is specified, update to the tip of the
5816 current named branch and move the current bookmark (see :hg:`help
5809 current named branch and move the current bookmark (see :hg:`help
5817 bookmarks`).
5810 bookmarks`).
5818
5811
5819 Update sets the working directory's parent revision to the specified
5812 Update sets the working directory's parent revision to the specified
5820 changeset (see :hg:`help parents`).
5813 changeset (see :hg:`help parents`).
5821
5814
5822 If the changeset is not a descendant or ancestor of the working
5815 If the changeset is not a descendant or ancestor of the working
5823 directory's parent, the update is aborted. With the -c/--check
5816 directory's parent, the update is aborted. With the -c/--check
5824 option, the working directory is checked for uncommitted changes; if
5817 option, the working directory is checked for uncommitted changes; if
5825 none are found, the working directory is updated to the specified
5818 none are found, the working directory is updated to the specified
5826 changeset.
5819 changeset.
5827
5820
5828 .. container:: verbose
5821 .. container:: verbose
5829
5822
5830 The following rules apply when the working directory contains
5823 The following rules apply when the working directory contains
5831 uncommitted changes:
5824 uncommitted changes:
5832
5825
5833 1. If neither -c/--check nor -C/--clean is specified, and if
5826 1. If neither -c/--check nor -C/--clean is specified, and if
5834 the requested changeset is an ancestor or descendant of
5827 the requested changeset is an ancestor or descendant of
5835 the working directory's parent, the uncommitted changes
5828 the working directory's parent, the uncommitted changes
5836 are merged into the requested changeset and the merged
5829 are merged into the requested changeset and the merged
5837 result is left uncommitted. If the requested changeset is
5830 result is left uncommitted. If the requested changeset is
5838 not an ancestor or descendant (that is, it is on another
5831 not an ancestor or descendant (that is, it is on another
5839 branch), the update is aborted and the uncommitted changes
5832 branch), the update is aborted and the uncommitted changes
5840 are preserved.
5833 are preserved.
5841
5834
5842 2. With the -c/--check option, the update is aborted and the
5835 2. With the -c/--check option, the update is aborted and the
5843 uncommitted changes are preserved.
5836 uncommitted changes are preserved.
5844
5837
5845 3. With the -C/--clean option, uncommitted changes are discarded and
5838 3. With the -C/--clean option, uncommitted changes are discarded and
5846 the working directory is updated to the requested changeset.
5839 the working directory is updated to the requested changeset.
5847
5840
5848 To cancel an uncommitted merge (and lose your changes), use
5841 To cancel an uncommitted merge (and lose your changes), use
5849 :hg:`update --clean .`.
5842 :hg:`update --clean .`.
5850
5843
5851 Use null as the changeset to remove the working directory (like
5844 Use null as the changeset to remove the working directory (like
5852 :hg:`clone -U`).
5845 :hg:`clone -U`).
5853
5846
5854 If you want to revert just one file to an older revision, use
5847 If you want to revert just one file to an older revision, use
5855 :hg:`revert [-r REV] NAME`.
5848 :hg:`revert [-r REV] NAME`.
5856
5849
5857 See :hg:`help dates` for a list of formats valid for -d/--date.
5850 See :hg:`help dates` for a list of formats valid for -d/--date.
5858
5851
5859 Returns 0 on success, 1 if there are unresolved files.
5852 Returns 0 on success, 1 if there are unresolved files.
5860 """
5853 """
5861 if rev and node:
5854 if rev and node:
5862 raise util.Abort(_("please specify just one revision"))
5855 raise util.Abort(_("please specify just one revision"))
5863
5856
5864 if rev is None or rev == '':
5857 if rev is None or rev == '':
5865 rev = node
5858 rev = node
5866
5859
5867 cmdutil.clearunfinished(repo)
5860 cmdutil.clearunfinished(repo)
5868
5861
5869 # with no argument, we also move the current bookmark, if any
5862 # with no argument, we also move the current bookmark, if any
5870 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5863 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5871
5864
5872 # if we defined a bookmark, we have to remember the original bookmark name
5865 # if we defined a bookmark, we have to remember the original bookmark name
5873 brev = rev
5866 brev = rev
5874 rev = scmutil.revsingle(repo, rev, rev).rev()
5867 rev = scmutil.revsingle(repo, rev, rev).rev()
5875
5868
5876 if check and clean:
5869 if check and clean:
5877 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5870 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5878
5871
5879 if date:
5872 if date:
5880 if rev is not None:
5873 if rev is not None:
5881 raise util.Abort(_("you can't specify a revision and a date"))
5874 raise util.Abort(_("you can't specify a revision and a date"))
5882 rev = cmdutil.finddate(ui, repo, date)
5875 rev = cmdutil.finddate(ui, repo, date)
5883
5876
5884 if check:
5877 if check:
5885 c = repo[None]
5878 c = repo[None]
5886 if c.dirty(merge=False, branch=False, missing=True):
5879 if c.dirty(merge=False, branch=False, missing=True):
5887 raise util.Abort(_("uncommitted changes"))
5880 raise util.Abort(_("uncommitted changes"))
5888 if rev is None:
5881 if rev is None:
5889 rev = repo[repo[None].branch()].rev()
5882 rev = repo[repo[None].branch()].rev()
5890 mergemod._checkunknown(repo, repo[None], repo[rev])
5883 mergemod._checkunknown(repo, repo[None], repo[rev])
5891
5884
5892 if clean:
5885 if clean:
5893 ret = hg.clean(repo, rev)
5886 ret = hg.clean(repo, rev)
5894 else:
5887 else:
5895 ret = hg.update(repo, rev)
5888 ret = hg.update(repo, rev)
5896
5889
5897 if not ret and movemarkfrom:
5890 if not ret and movemarkfrom:
5898 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5891 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5899 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5892 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5900 elif brev in repo._bookmarks:
5893 elif brev in repo._bookmarks:
5901 bookmarks.setcurrent(repo, brev)
5894 bookmarks.setcurrent(repo, brev)
5902 elif brev:
5895 elif brev:
5903 bookmarks.unsetcurrent(repo)
5896 bookmarks.unsetcurrent(repo)
5904
5897
5905 return ret
5898 return ret
5906
5899
5907 @command('verify', [])
5900 @command('verify', [])
5908 def verify(ui, repo):
5901 def verify(ui, repo):
5909 """verify the integrity of the repository
5902 """verify the integrity of the repository
5910
5903
5911 Verify the integrity of the current repository.
5904 Verify the integrity of the current repository.
5912
5905
5913 This will perform an extensive check of the repository's
5906 This will perform an extensive check of the repository's
5914 integrity, validating the hashes and checksums of each entry in
5907 integrity, validating the hashes and checksums of each entry in
5915 the changelog, manifest, and tracked files, as well as the
5908 the changelog, manifest, and tracked files, as well as the
5916 integrity of their crosslinks and indices.
5909 integrity of their crosslinks and indices.
5917
5910
5918 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5911 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5919 for more information about recovery from corruption of the
5912 for more information about recovery from corruption of the
5920 repository.
5913 repository.
5921
5914
5922 Returns 0 on success, 1 if errors are encountered.
5915 Returns 0 on success, 1 if errors are encountered.
5923 """
5916 """
5924 return hg.verify(repo)
5917 return hg.verify(repo)
5925
5918
5926 @command('version', [])
5919 @command('version', [])
5927 def version_(ui):
5920 def version_(ui):
5928 """output version and copyright information"""
5921 """output version and copyright information"""
5929 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5922 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5930 % util.version())
5923 % util.version())
5931 ui.status(_(
5924 ui.status(_(
5932 "(see http://mercurial.selenic.com for more information)\n"
5925 "(see http://mercurial.selenic.com for more information)\n"
5933 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
5926 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
5934 "This is free software; see the source for copying conditions. "
5927 "This is free software; see the source for copying conditions. "
5935 "There is NO\nwarranty; "
5928 "There is NO\nwarranty; "
5936 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5929 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5937 ))
5930 ))
5938
5931
5939 norepo = ("clone init version help debugcommands debugcomplete"
5932 norepo = ("clone init version help debugcommands debugcomplete"
5940 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5933 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5941 " debugknown debuggetbundle debugbundle")
5934 " debugknown debuggetbundle debugbundle")
5942 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5935 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5943 " debugdata debugindex debugindexdot debugrevlog")
5936 " debugdata debugindex debugindexdot debugrevlog")
5944 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5937 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5945 " remove resolve status debugwalk")
5938 " remove resolve status debugwalk")
General Comments 0
You need to be logged in to leave comments. Login now