##// END OF EJS Templates
import: move tryone closure in cmdutil...
Pierre-Yves David -
r20500:ce3f3082 default
parent child Browse files
Show More
@@ -1,2180 +1,2305
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 tryimportone(ui, repo, hunk, parents, opts, msgs, updatefunc):
546 """Utility function used by commands.import to import a single patch
547
548 This function is explicitly defined here to help the evolve extension to
549 wrap this part of the import logic.
550
551 The API is currently a bit ugly because it a simple code translation from
552 the import command. Feel free to make it better.
553
554 :hunk: a patch (as a binary string)
555 :parents: nodes that will be parent of the created commit
556 :opts: the full dict of option passed to the import command
557 :msgs: list to save commit message to.
558 (used in case we need to save it when failing)
559 :updatefunc: a function that update a repo to a given node
560 updatefunc(<repo>, <node>)
561 """
562 tmpname, message, user, date, branch, nodeid, p1, p2 = \
563 patch.extract(ui, hunk)
564
565 editor = commiteditor
566 if opts.get('edit'):
567 editor = commitforceeditor
568 update = not opts.get('bypass')
569 strip = opts["strip"]
570 sim = float(opts.get('similarity') or 0)
571 if not tmpname:
572 return (None, None)
573 msg = _('applied to working directory')
574
575 try:
576 cmdline_message = logmessage(ui, opts)
577 if cmdline_message:
578 # pickup the cmdline msg
579 message = cmdline_message
580 elif message:
581 # pickup the patch msg
582 message = message.strip()
583 else:
584 # launch the editor
585 message = None
586 ui.debug('message:\n%s\n' % message)
587
588 if len(parents) == 1:
589 parents.append(repo[nullid])
590 if opts.get('exact'):
591 if not nodeid or not p1:
592 raise util.Abort(_('not a Mercurial patch'))
593 p1 = repo[p1]
594 p2 = repo[p2 or nullid]
595 elif p2:
596 try:
597 p1 = repo[p1]
598 p2 = repo[p2]
599 # Without any options, consider p2 only if the
600 # patch is being applied on top of the recorded
601 # first parent.
602 if p1 != parents[0]:
603 p1 = parents[0]
604 p2 = repo[nullid]
605 except error.RepoError:
606 p1, p2 = parents
607 else:
608 p1, p2 = parents
609
610 n = None
611 if update:
612 if p1 != parents[0]:
613 updatefunc(repo, p1.node())
614 if p2 != parents[1]:
615 repo.setparents(p1.node(), p2.node())
616
617 if opts.get('exact') or opts.get('import_branch'):
618 repo.dirstate.setbranch(branch or 'default')
619
620 files = set()
621 patch.patch(ui, repo, tmpname, strip=strip, files=files,
622 eolmode=None, similarity=sim / 100.0)
623 files = list(files)
624 if opts.get('no_commit'):
625 if message:
626 msgs.append(message)
627 else:
628 if opts.get('exact') or p2:
629 # If you got here, you either use --force and know what
630 # you are doing or used --exact or a merge patch while
631 # being updated to its first parent.
632 m = None
633 else:
634 m = scmutil.matchfiles(repo, files or [])
635 n = repo.commit(message, opts.get('user') or user,
636 opts.get('date') or date, match=m,
637 editor=editor)
638 else:
639 if opts.get('exact') or opts.get('import_branch'):
640 branch = branch or 'default'
641 else:
642 branch = p1.branch()
643 store = patch.filestore()
644 try:
645 files = set()
646 try:
647 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
648 files, eolmode=None)
649 except patch.PatchError, e:
650 raise util.Abort(str(e))
651 memctx = context.makememctx(repo, (p1.node(), p2.node()),
652 message,
653 opts.get('user') or user,
654 opts.get('date') or date,
655 branch, files, store,
656 editor=commiteditor)
657 repo.savecommitmessage(memctx.description())
658 n = memctx.commit()
659 finally:
660 store.close()
661 if opts.get('exact') and hex(n) != nodeid:
662 raise util.Abort(_('patch is damaged or loses information'))
663 if n:
664 # i18n: refers to a short changeset id
665 msg = _('created %s') % short(n)
666 return (msg, n)
667 finally:
668 os.unlink(tmpname)
669
545 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
670 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
546 opts=None):
671 opts=None):
547 '''export changesets as hg patches.'''
672 '''export changesets as hg patches.'''
548
673
549 total = len(revs)
674 total = len(revs)
550 revwidth = max([len(str(rev)) for rev in revs])
675 revwidth = max([len(str(rev)) for rev in revs])
551 filemode = {}
676 filemode = {}
552
677
553 def single(rev, seqno, fp):
678 def single(rev, seqno, fp):
554 ctx = repo[rev]
679 ctx = repo[rev]
555 node = ctx.node()
680 node = ctx.node()
556 parents = [p.node() for p in ctx.parents() if p]
681 parents = [p.node() for p in ctx.parents() if p]
557 branch = ctx.branch()
682 branch = ctx.branch()
558 if switch_parent:
683 if switch_parent:
559 parents.reverse()
684 parents.reverse()
560 prev = (parents and parents[0]) or nullid
685 prev = (parents and parents[0]) or nullid
561
686
562 shouldclose = False
687 shouldclose = False
563 if not fp and len(template) > 0:
688 if not fp and len(template) > 0:
564 desc_lines = ctx.description().rstrip().split('\n')
689 desc_lines = ctx.description().rstrip().split('\n')
565 desc = desc_lines[0] #Commit always has a first line.
690 desc = desc_lines[0] #Commit always has a first line.
566 fp = makefileobj(repo, template, node, desc=desc, total=total,
691 fp = makefileobj(repo, template, node, desc=desc, total=total,
567 seqno=seqno, revwidth=revwidth, mode='wb',
692 seqno=seqno, revwidth=revwidth, mode='wb',
568 modemap=filemode)
693 modemap=filemode)
569 if fp != template:
694 if fp != template:
570 shouldclose = True
695 shouldclose = True
571 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
696 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
572 repo.ui.note("%s\n" % fp.name)
697 repo.ui.note("%s\n" % fp.name)
573
698
574 if not fp:
699 if not fp:
575 write = repo.ui.write
700 write = repo.ui.write
576 else:
701 else:
577 def write(s, **kw):
702 def write(s, **kw):
578 fp.write(s)
703 fp.write(s)
579
704
580
705
581 write("# HG changeset patch\n")
706 write("# HG changeset patch\n")
582 write("# User %s\n" % ctx.user())
707 write("# User %s\n" % ctx.user())
583 write("# Date %d %d\n" % ctx.date())
708 write("# Date %d %d\n" % ctx.date())
584 write("# %s\n" % util.datestr(ctx.date()))
709 write("# %s\n" % util.datestr(ctx.date()))
585 if branch and branch != 'default':
710 if branch and branch != 'default':
586 write("# Branch %s\n" % branch)
711 write("# Branch %s\n" % branch)
587 write("# Node ID %s\n" % hex(node))
712 write("# Node ID %s\n" % hex(node))
588 write("# Parent %s\n" % hex(prev))
713 write("# Parent %s\n" % hex(prev))
589 if len(parents) > 1:
714 if len(parents) > 1:
590 write("# Parent %s\n" % hex(parents[1]))
715 write("# Parent %s\n" % hex(parents[1]))
591 write(ctx.description().rstrip())
716 write(ctx.description().rstrip())
592 write("\n\n")
717 write("\n\n")
593
718
594 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
719 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
595 write(chunk, label=label)
720 write(chunk, label=label)
596
721
597 if shouldclose:
722 if shouldclose:
598 fp.close()
723 fp.close()
599
724
600 for seqno, rev in enumerate(revs):
725 for seqno, rev in enumerate(revs):
601 single(rev, seqno + 1, fp)
726 single(rev, seqno + 1, fp)
602
727
603 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
728 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
604 changes=None, stat=False, fp=None, prefix='',
729 changes=None, stat=False, fp=None, prefix='',
605 listsubrepos=False):
730 listsubrepos=False):
606 '''show diff or diffstat.'''
731 '''show diff or diffstat.'''
607 if fp is None:
732 if fp is None:
608 write = ui.write
733 write = ui.write
609 else:
734 else:
610 def write(s, **kw):
735 def write(s, **kw):
611 fp.write(s)
736 fp.write(s)
612
737
613 if stat:
738 if stat:
614 diffopts = diffopts.copy(context=0)
739 diffopts = diffopts.copy(context=0)
615 width = 80
740 width = 80
616 if not ui.plain():
741 if not ui.plain():
617 width = ui.termwidth()
742 width = ui.termwidth()
618 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
743 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
619 prefix=prefix)
744 prefix=prefix)
620 for chunk, label in patch.diffstatui(util.iterlines(chunks),
745 for chunk, label in patch.diffstatui(util.iterlines(chunks),
621 width=width,
746 width=width,
622 git=diffopts.git):
747 git=diffopts.git):
623 write(chunk, label=label)
748 write(chunk, label=label)
624 else:
749 else:
625 for chunk, label in patch.diffui(repo, node1, node2, match,
750 for chunk, label in patch.diffui(repo, node1, node2, match,
626 changes, diffopts, prefix=prefix):
751 changes, diffopts, prefix=prefix):
627 write(chunk, label=label)
752 write(chunk, label=label)
628
753
629 if listsubrepos:
754 if listsubrepos:
630 ctx1 = repo[node1]
755 ctx1 = repo[node1]
631 ctx2 = repo[node2]
756 ctx2 = repo[node2]
632 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
757 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
633 tempnode2 = node2
758 tempnode2 = node2
634 try:
759 try:
635 if node2 is not None:
760 if node2 is not None:
636 tempnode2 = ctx2.substate[subpath][1]
761 tempnode2 = ctx2.substate[subpath][1]
637 except KeyError:
762 except KeyError:
638 # A subrepo that existed in node1 was deleted between node1 and
763 # A subrepo that existed in node1 was deleted between node1 and
639 # node2 (inclusive). Thus, ctx2's substate won't contain that
764 # node2 (inclusive). Thus, ctx2's substate won't contain that
640 # subpath. The best we can do is to ignore it.
765 # subpath. The best we can do is to ignore it.
641 tempnode2 = None
766 tempnode2 = None
642 submatch = matchmod.narrowmatcher(subpath, match)
767 submatch = matchmod.narrowmatcher(subpath, match)
643 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
768 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
644 stat=stat, fp=fp, prefix=prefix)
769 stat=stat, fp=fp, prefix=prefix)
645
770
646 class changeset_printer(object):
771 class changeset_printer(object):
647 '''show changeset information when templating not requested.'''
772 '''show changeset information when templating not requested.'''
648
773
649 def __init__(self, ui, repo, patch, diffopts, buffered):
774 def __init__(self, ui, repo, patch, diffopts, buffered):
650 self.ui = ui
775 self.ui = ui
651 self.repo = repo
776 self.repo = repo
652 self.buffered = buffered
777 self.buffered = buffered
653 self.patch = patch
778 self.patch = patch
654 self.diffopts = diffopts
779 self.diffopts = diffopts
655 self.header = {}
780 self.header = {}
656 self.hunk = {}
781 self.hunk = {}
657 self.lastheader = None
782 self.lastheader = None
658 self.footer = None
783 self.footer = None
659
784
660 def flush(self, rev):
785 def flush(self, rev):
661 if rev in self.header:
786 if rev in self.header:
662 h = self.header[rev]
787 h = self.header[rev]
663 if h != self.lastheader:
788 if h != self.lastheader:
664 self.lastheader = h
789 self.lastheader = h
665 self.ui.write(h)
790 self.ui.write(h)
666 del self.header[rev]
791 del self.header[rev]
667 if rev in self.hunk:
792 if rev in self.hunk:
668 self.ui.write(self.hunk[rev])
793 self.ui.write(self.hunk[rev])
669 del self.hunk[rev]
794 del self.hunk[rev]
670 return 1
795 return 1
671 return 0
796 return 0
672
797
673 def close(self):
798 def close(self):
674 if self.footer:
799 if self.footer:
675 self.ui.write(self.footer)
800 self.ui.write(self.footer)
676
801
677 def show(self, ctx, copies=None, matchfn=None, **props):
802 def show(self, ctx, copies=None, matchfn=None, **props):
678 if self.buffered:
803 if self.buffered:
679 self.ui.pushbuffer()
804 self.ui.pushbuffer()
680 self._show(ctx, copies, matchfn, props)
805 self._show(ctx, copies, matchfn, props)
681 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
806 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
682 else:
807 else:
683 self._show(ctx, copies, matchfn, props)
808 self._show(ctx, copies, matchfn, props)
684
809
685 def _show(self, ctx, copies, matchfn, props):
810 def _show(self, ctx, copies, matchfn, props):
686 '''show a single changeset or file revision'''
811 '''show a single changeset or file revision'''
687 changenode = ctx.node()
812 changenode = ctx.node()
688 rev = ctx.rev()
813 rev = ctx.rev()
689
814
690 if self.ui.quiet:
815 if self.ui.quiet:
691 self.ui.write("%d:%s\n" % (rev, short(changenode)),
816 self.ui.write("%d:%s\n" % (rev, short(changenode)),
692 label='log.node')
817 label='log.node')
693 return
818 return
694
819
695 log = self.repo.changelog
820 log = self.repo.changelog
696 date = util.datestr(ctx.date())
821 date = util.datestr(ctx.date())
697
822
698 hexfunc = self.ui.debugflag and hex or short
823 hexfunc = self.ui.debugflag and hex or short
699
824
700 parents = [(p, hexfunc(log.node(p)))
825 parents = [(p, hexfunc(log.node(p)))
701 for p in self._meaningful_parentrevs(log, rev)]
826 for p in self._meaningful_parentrevs(log, rev)]
702
827
703 # i18n: column positioning for "hg log"
828 # i18n: column positioning for "hg log"
704 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
829 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
705 label='log.changeset changeset.%s' % ctx.phasestr())
830 label='log.changeset changeset.%s' % ctx.phasestr())
706
831
707 branch = ctx.branch()
832 branch = ctx.branch()
708 # don't show the default branch name
833 # don't show the default branch name
709 if branch != 'default':
834 if branch != 'default':
710 # i18n: column positioning for "hg log"
835 # i18n: column positioning for "hg log"
711 self.ui.write(_("branch: %s\n") % branch,
836 self.ui.write(_("branch: %s\n") % branch,
712 label='log.branch')
837 label='log.branch')
713 for bookmark in self.repo.nodebookmarks(changenode):
838 for bookmark in self.repo.nodebookmarks(changenode):
714 # i18n: column positioning for "hg log"
839 # i18n: column positioning for "hg log"
715 self.ui.write(_("bookmark: %s\n") % bookmark,
840 self.ui.write(_("bookmark: %s\n") % bookmark,
716 label='log.bookmark')
841 label='log.bookmark')
717 for tag in self.repo.nodetags(changenode):
842 for tag in self.repo.nodetags(changenode):
718 # i18n: column positioning for "hg log"
843 # i18n: column positioning for "hg log"
719 self.ui.write(_("tag: %s\n") % tag,
844 self.ui.write(_("tag: %s\n") % tag,
720 label='log.tag')
845 label='log.tag')
721 if self.ui.debugflag and ctx.phase():
846 if self.ui.debugflag and ctx.phase():
722 # i18n: column positioning for "hg log"
847 # i18n: column positioning for "hg log"
723 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
848 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
724 label='log.phase')
849 label='log.phase')
725 for parent in parents:
850 for parent in parents:
726 # i18n: column positioning for "hg log"
851 # i18n: column positioning for "hg log"
727 self.ui.write(_("parent: %d:%s\n") % parent,
852 self.ui.write(_("parent: %d:%s\n") % parent,
728 label='log.parent changeset.%s' % ctx.phasestr())
853 label='log.parent changeset.%s' % ctx.phasestr())
729
854
730 if self.ui.debugflag:
855 if self.ui.debugflag:
731 mnode = ctx.manifestnode()
856 mnode = ctx.manifestnode()
732 # i18n: column positioning for "hg log"
857 # i18n: column positioning for "hg log"
733 self.ui.write(_("manifest: %d:%s\n") %
858 self.ui.write(_("manifest: %d:%s\n") %
734 (self.repo.manifest.rev(mnode), hex(mnode)),
859 (self.repo.manifest.rev(mnode), hex(mnode)),
735 label='ui.debug log.manifest')
860 label='ui.debug log.manifest')
736 # i18n: column positioning for "hg log"
861 # i18n: column positioning for "hg log"
737 self.ui.write(_("user: %s\n") % ctx.user(),
862 self.ui.write(_("user: %s\n") % ctx.user(),
738 label='log.user')
863 label='log.user')
739 # i18n: column positioning for "hg log"
864 # i18n: column positioning for "hg log"
740 self.ui.write(_("date: %s\n") % date,
865 self.ui.write(_("date: %s\n") % date,
741 label='log.date')
866 label='log.date')
742
867
743 if self.ui.debugflag:
868 if self.ui.debugflag:
744 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
869 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
745 for key, value in zip([# i18n: column positioning for "hg log"
870 for key, value in zip([# i18n: column positioning for "hg log"
746 _("files:"),
871 _("files:"),
747 # i18n: column positioning for "hg log"
872 # i18n: column positioning for "hg log"
748 _("files+:"),
873 _("files+:"),
749 # i18n: column positioning for "hg log"
874 # i18n: column positioning for "hg log"
750 _("files-:")], files):
875 _("files-:")], files):
751 if value:
876 if value:
752 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
877 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
753 label='ui.debug log.files')
878 label='ui.debug log.files')
754 elif ctx.files() and self.ui.verbose:
879 elif ctx.files() and self.ui.verbose:
755 # i18n: column positioning for "hg log"
880 # i18n: column positioning for "hg log"
756 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
881 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
757 label='ui.note log.files')
882 label='ui.note log.files')
758 if copies and self.ui.verbose:
883 if copies and self.ui.verbose:
759 copies = ['%s (%s)' % c for c in copies]
884 copies = ['%s (%s)' % c for c in copies]
760 # i18n: column positioning for "hg log"
885 # i18n: column positioning for "hg log"
761 self.ui.write(_("copies: %s\n") % ' '.join(copies),
886 self.ui.write(_("copies: %s\n") % ' '.join(copies),
762 label='ui.note log.copies')
887 label='ui.note log.copies')
763
888
764 extra = ctx.extra()
889 extra = ctx.extra()
765 if extra and self.ui.debugflag:
890 if extra and self.ui.debugflag:
766 for key, value in sorted(extra.items()):
891 for key, value in sorted(extra.items()):
767 # i18n: column positioning for "hg log"
892 # i18n: column positioning for "hg log"
768 self.ui.write(_("extra: %s=%s\n")
893 self.ui.write(_("extra: %s=%s\n")
769 % (key, value.encode('string_escape')),
894 % (key, value.encode('string_escape')),
770 label='ui.debug log.extra')
895 label='ui.debug log.extra')
771
896
772 description = ctx.description().strip()
897 description = ctx.description().strip()
773 if description:
898 if description:
774 if self.ui.verbose:
899 if self.ui.verbose:
775 self.ui.write(_("description:\n"),
900 self.ui.write(_("description:\n"),
776 label='ui.note log.description')
901 label='ui.note log.description')
777 self.ui.write(description,
902 self.ui.write(description,
778 label='ui.note log.description')
903 label='ui.note log.description')
779 self.ui.write("\n\n")
904 self.ui.write("\n\n")
780 else:
905 else:
781 # i18n: column positioning for "hg log"
906 # i18n: column positioning for "hg log"
782 self.ui.write(_("summary: %s\n") %
907 self.ui.write(_("summary: %s\n") %
783 description.splitlines()[0],
908 description.splitlines()[0],
784 label='log.summary')
909 label='log.summary')
785 self.ui.write("\n")
910 self.ui.write("\n")
786
911
787 self.showpatch(changenode, matchfn)
912 self.showpatch(changenode, matchfn)
788
913
789 def showpatch(self, node, matchfn):
914 def showpatch(self, node, matchfn):
790 if not matchfn:
915 if not matchfn:
791 matchfn = self.patch
916 matchfn = self.patch
792 if matchfn:
917 if matchfn:
793 stat = self.diffopts.get('stat')
918 stat = self.diffopts.get('stat')
794 diff = self.diffopts.get('patch')
919 diff = self.diffopts.get('patch')
795 diffopts = patch.diffopts(self.ui, self.diffopts)
920 diffopts = patch.diffopts(self.ui, self.diffopts)
796 prev = self.repo.changelog.parents(node)[0]
921 prev = self.repo.changelog.parents(node)[0]
797 if stat:
922 if stat:
798 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
923 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
799 match=matchfn, stat=True)
924 match=matchfn, stat=True)
800 if diff:
925 if diff:
801 if stat:
926 if stat:
802 self.ui.write("\n")
927 self.ui.write("\n")
803 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
928 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
804 match=matchfn, stat=False)
929 match=matchfn, stat=False)
805 self.ui.write("\n")
930 self.ui.write("\n")
806
931
807 def _meaningful_parentrevs(self, log, rev):
932 def _meaningful_parentrevs(self, log, rev):
808 """Return list of meaningful (or all if debug) parentrevs for rev.
933 """Return list of meaningful (or all if debug) parentrevs for rev.
809
934
810 For merges (two non-nullrev revisions) both parents are meaningful.
935 For merges (two non-nullrev revisions) both parents are meaningful.
811 Otherwise the first parent revision is considered meaningful if it
936 Otherwise the first parent revision is considered meaningful if it
812 is not the preceding revision.
937 is not the preceding revision.
813 """
938 """
814 parents = log.parentrevs(rev)
939 parents = log.parentrevs(rev)
815 if not self.ui.debugflag and parents[1] == nullrev:
940 if not self.ui.debugflag and parents[1] == nullrev:
816 if parents[0] >= rev - 1:
941 if parents[0] >= rev - 1:
817 parents = []
942 parents = []
818 else:
943 else:
819 parents = [parents[0]]
944 parents = [parents[0]]
820 return parents
945 return parents
821
946
822
947
823 class changeset_templater(changeset_printer):
948 class changeset_templater(changeset_printer):
824 '''format changeset information.'''
949 '''format changeset information.'''
825
950
826 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
951 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
827 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
952 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
828 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
953 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
829 defaulttempl = {
954 defaulttempl = {
830 'parent': '{rev}:{node|formatnode} ',
955 'parent': '{rev}:{node|formatnode} ',
831 'manifest': '{rev}:{node|formatnode}',
956 'manifest': '{rev}:{node|formatnode}',
832 'file_copy': '{name} ({source})',
957 'file_copy': '{name} ({source})',
833 'extra': '{key}={value|stringescape}'
958 'extra': '{key}={value|stringescape}'
834 }
959 }
835 # filecopy is preserved for compatibility reasons
960 # filecopy is preserved for compatibility reasons
836 defaulttempl['filecopy'] = defaulttempl['file_copy']
961 defaulttempl['filecopy'] = defaulttempl['file_copy']
837 self.t = templater.templater(mapfile, {'formatnode': formatnode},
962 self.t = templater.templater(mapfile, {'formatnode': formatnode},
838 cache=defaulttempl)
963 cache=defaulttempl)
839 self.cache = {}
964 self.cache = {}
840
965
841 def use_template(self, t):
966 def use_template(self, t):
842 '''set template string to use'''
967 '''set template string to use'''
843 self.t.cache['changeset'] = t
968 self.t.cache['changeset'] = t
844
969
845 def _meaningful_parentrevs(self, ctx):
970 def _meaningful_parentrevs(self, ctx):
846 """Return list of meaningful (or all if debug) parentrevs for rev.
971 """Return list of meaningful (or all if debug) parentrevs for rev.
847 """
972 """
848 parents = ctx.parents()
973 parents = ctx.parents()
849 if len(parents) > 1:
974 if len(parents) > 1:
850 return parents
975 return parents
851 if self.ui.debugflag:
976 if self.ui.debugflag:
852 return [parents[0], self.repo['null']]
977 return [parents[0], self.repo['null']]
853 if parents[0].rev() >= ctx.rev() - 1:
978 if parents[0].rev() >= ctx.rev() - 1:
854 return []
979 return []
855 return parents
980 return parents
856
981
857 def _show(self, ctx, copies, matchfn, props):
982 def _show(self, ctx, copies, matchfn, props):
858 '''show a single changeset or file revision'''
983 '''show a single changeset or file revision'''
859
984
860 showlist = templatekw.showlist
985 showlist = templatekw.showlist
861
986
862 # showparents() behaviour depends on ui trace level which
987 # showparents() behaviour depends on ui trace level which
863 # causes unexpected behaviours at templating level and makes
988 # causes unexpected behaviours at templating level and makes
864 # it harder to extract it in a standalone function. Its
989 # it harder to extract it in a standalone function. Its
865 # behaviour cannot be changed so leave it here for now.
990 # behaviour cannot be changed so leave it here for now.
866 def showparents(**args):
991 def showparents(**args):
867 ctx = args['ctx']
992 ctx = args['ctx']
868 parents = [[('rev', p.rev()), ('node', p.hex())]
993 parents = [[('rev', p.rev()), ('node', p.hex())]
869 for p in self._meaningful_parentrevs(ctx)]
994 for p in self._meaningful_parentrevs(ctx)]
870 return showlist('parent', parents, **args)
995 return showlist('parent', parents, **args)
871
996
872 props = props.copy()
997 props = props.copy()
873 props.update(templatekw.keywords)
998 props.update(templatekw.keywords)
874 props['parents'] = showparents
999 props['parents'] = showparents
875 props['templ'] = self.t
1000 props['templ'] = self.t
876 props['ctx'] = ctx
1001 props['ctx'] = ctx
877 props['repo'] = self.repo
1002 props['repo'] = self.repo
878 props['revcache'] = {'copies': copies}
1003 props['revcache'] = {'copies': copies}
879 props['cache'] = self.cache
1004 props['cache'] = self.cache
880
1005
881 # find correct templates for current mode
1006 # find correct templates for current mode
882
1007
883 tmplmodes = [
1008 tmplmodes = [
884 (True, None),
1009 (True, None),
885 (self.ui.verbose, 'verbose'),
1010 (self.ui.verbose, 'verbose'),
886 (self.ui.quiet, 'quiet'),
1011 (self.ui.quiet, 'quiet'),
887 (self.ui.debugflag, 'debug'),
1012 (self.ui.debugflag, 'debug'),
888 ]
1013 ]
889
1014
890 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
1015 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
891 for mode, postfix in tmplmodes:
1016 for mode, postfix in tmplmodes:
892 for type in types:
1017 for type in types:
893 cur = postfix and ('%s_%s' % (type, postfix)) or type
1018 cur = postfix and ('%s_%s' % (type, postfix)) or type
894 if mode and cur in self.t:
1019 if mode and cur in self.t:
895 types[type] = cur
1020 types[type] = cur
896
1021
897 try:
1022 try:
898
1023
899 # write header
1024 # write header
900 if types['header']:
1025 if types['header']:
901 h = templater.stringify(self.t(types['header'], **props))
1026 h = templater.stringify(self.t(types['header'], **props))
902 if self.buffered:
1027 if self.buffered:
903 self.header[ctx.rev()] = h
1028 self.header[ctx.rev()] = h
904 else:
1029 else:
905 if self.lastheader != h:
1030 if self.lastheader != h:
906 self.lastheader = h
1031 self.lastheader = h
907 self.ui.write(h)
1032 self.ui.write(h)
908
1033
909 # write changeset metadata, then patch if requested
1034 # write changeset metadata, then patch if requested
910 key = types['changeset']
1035 key = types['changeset']
911 self.ui.write(templater.stringify(self.t(key, **props)))
1036 self.ui.write(templater.stringify(self.t(key, **props)))
912 self.showpatch(ctx.node(), matchfn)
1037 self.showpatch(ctx.node(), matchfn)
913
1038
914 if types['footer']:
1039 if types['footer']:
915 if not self.footer:
1040 if not self.footer:
916 self.footer = templater.stringify(self.t(types['footer'],
1041 self.footer = templater.stringify(self.t(types['footer'],
917 **props))
1042 **props))
918
1043
919 except KeyError, inst:
1044 except KeyError, inst:
920 msg = _("%s: no key named '%s'")
1045 msg = _("%s: no key named '%s'")
921 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
1046 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
922 except SyntaxError, inst:
1047 except SyntaxError, inst:
923 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
1048 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
924
1049
925 def show_changeset(ui, repo, opts, buffered=False):
1050 def show_changeset(ui, repo, opts, buffered=False):
926 """show one changeset using template or regular display.
1051 """show one changeset using template or regular display.
927
1052
928 Display format will be the first non-empty hit of:
1053 Display format will be the first non-empty hit of:
929 1. option 'template'
1054 1. option 'template'
930 2. option 'style'
1055 2. option 'style'
931 3. [ui] setting 'logtemplate'
1056 3. [ui] setting 'logtemplate'
932 4. [ui] setting 'style'
1057 4. [ui] setting 'style'
933 If all of these values are either the unset or the empty string,
1058 If all of these values are either the unset or the empty string,
934 regular display via changeset_printer() is done.
1059 regular display via changeset_printer() is done.
935 """
1060 """
936 # options
1061 # options
937 patch = None
1062 patch = None
938 if opts.get('patch') or opts.get('stat'):
1063 if opts.get('patch') or opts.get('stat'):
939 patch = scmutil.matchall(repo)
1064 patch = scmutil.matchall(repo)
940
1065
941 tmpl = opts.get('template')
1066 tmpl = opts.get('template')
942 style = None
1067 style = None
943 if not tmpl:
1068 if not tmpl:
944 style = opts.get('style')
1069 style = opts.get('style')
945
1070
946 # ui settings
1071 # ui settings
947 if not (tmpl or style):
1072 if not (tmpl or style):
948 tmpl = ui.config('ui', 'logtemplate')
1073 tmpl = ui.config('ui', 'logtemplate')
949 if tmpl:
1074 if tmpl:
950 try:
1075 try:
951 tmpl = templater.parsestring(tmpl)
1076 tmpl = templater.parsestring(tmpl)
952 except SyntaxError:
1077 except SyntaxError:
953 tmpl = templater.parsestring(tmpl, quoted=False)
1078 tmpl = templater.parsestring(tmpl, quoted=False)
954 else:
1079 else:
955 style = util.expandpath(ui.config('ui', 'style', ''))
1080 style = util.expandpath(ui.config('ui', 'style', ''))
956
1081
957 if not (tmpl or style):
1082 if not (tmpl or style):
958 return changeset_printer(ui, repo, patch, opts, buffered)
1083 return changeset_printer(ui, repo, patch, opts, buffered)
959
1084
960 mapfile = None
1085 mapfile = None
961 if style and not tmpl:
1086 if style and not tmpl:
962 mapfile = style
1087 mapfile = style
963 if not os.path.split(mapfile)[0]:
1088 if not os.path.split(mapfile)[0]:
964 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1089 mapname = (templater.templatepath('map-cmdline.' + mapfile)
965 or templater.templatepath(mapfile))
1090 or templater.templatepath(mapfile))
966 if mapname:
1091 if mapname:
967 mapfile = mapname
1092 mapfile = mapname
968
1093
969 try:
1094 try:
970 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
1095 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
971 except SyntaxError, inst:
1096 except SyntaxError, inst:
972 raise util.Abort(inst.args[0])
1097 raise util.Abort(inst.args[0])
973 if tmpl:
1098 if tmpl:
974 t.use_template(tmpl)
1099 t.use_template(tmpl)
975 return t
1100 return t
976
1101
977 def showmarker(ui, marker):
1102 def showmarker(ui, marker):
978 """utility function to display obsolescence marker in a readable way
1103 """utility function to display obsolescence marker in a readable way
979
1104
980 To be used by debug function."""
1105 To be used by debug function."""
981 ui.write(hex(marker.precnode()))
1106 ui.write(hex(marker.precnode()))
982 for repl in marker.succnodes():
1107 for repl in marker.succnodes():
983 ui.write(' ')
1108 ui.write(' ')
984 ui.write(hex(repl))
1109 ui.write(hex(repl))
985 ui.write(' %X ' % marker._data[2])
1110 ui.write(' %X ' % marker._data[2])
986 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
1111 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
987 sorted(marker.metadata().items()))))
1112 sorted(marker.metadata().items()))))
988 ui.write('\n')
1113 ui.write('\n')
989
1114
990 def finddate(ui, repo, date):
1115 def finddate(ui, repo, date):
991 """Find the tipmost changeset that matches the given date spec"""
1116 """Find the tipmost changeset that matches the given date spec"""
992
1117
993 df = util.matchdate(date)
1118 df = util.matchdate(date)
994 m = scmutil.matchall(repo)
1119 m = scmutil.matchall(repo)
995 results = {}
1120 results = {}
996
1121
997 def prep(ctx, fns):
1122 def prep(ctx, fns):
998 d = ctx.date()
1123 d = ctx.date()
999 if df(d[0]):
1124 if df(d[0]):
1000 results[ctx.rev()] = d
1125 results[ctx.rev()] = d
1001
1126
1002 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1127 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1003 rev = ctx.rev()
1128 rev = ctx.rev()
1004 if rev in results:
1129 if rev in results:
1005 ui.status(_("found revision %s from %s\n") %
1130 ui.status(_("found revision %s from %s\n") %
1006 (rev, util.datestr(results[rev])))
1131 (rev, util.datestr(results[rev])))
1007 return str(rev)
1132 return str(rev)
1008
1133
1009 raise util.Abort(_("revision matching date not found"))
1134 raise util.Abort(_("revision matching date not found"))
1010
1135
1011 def increasingwindows(start, end, windowsize=8, sizelimit=512):
1136 def increasingwindows(start, end, windowsize=8, sizelimit=512):
1012 if start < end:
1137 if start < end:
1013 while start < end:
1138 while start < end:
1014 yield start, min(windowsize, end - start)
1139 yield start, min(windowsize, end - start)
1015 start += windowsize
1140 start += windowsize
1016 if windowsize < sizelimit:
1141 if windowsize < sizelimit:
1017 windowsize *= 2
1142 windowsize *= 2
1018 else:
1143 else:
1019 while start > end:
1144 while start > end:
1020 yield start, min(windowsize, start - end - 1)
1145 yield start, min(windowsize, start - end - 1)
1021 start -= windowsize
1146 start -= windowsize
1022 if windowsize < sizelimit:
1147 if windowsize < sizelimit:
1023 windowsize *= 2
1148 windowsize *= 2
1024
1149
1025 class FileWalkError(Exception):
1150 class FileWalkError(Exception):
1026 pass
1151 pass
1027
1152
1028 def walkfilerevs(repo, match, follow, revs, fncache):
1153 def walkfilerevs(repo, match, follow, revs, fncache):
1029 '''Walks the file history for the matched files.
1154 '''Walks the file history for the matched files.
1030
1155
1031 Returns the changeset revs that are involved in the file history.
1156 Returns the changeset revs that are involved in the file history.
1032
1157
1033 Throws FileWalkError if the file history can't be walked using
1158 Throws FileWalkError if the file history can't be walked using
1034 filelogs alone.
1159 filelogs alone.
1035 '''
1160 '''
1036 wanted = set()
1161 wanted = set()
1037 copies = []
1162 copies = []
1038 minrev, maxrev = min(revs), max(revs)
1163 minrev, maxrev = min(revs), max(revs)
1039 def filerevgen(filelog, last):
1164 def filerevgen(filelog, last):
1040 """
1165 """
1041 Only files, no patterns. Check the history of each file.
1166 Only files, no patterns. Check the history of each file.
1042
1167
1043 Examines filelog entries within minrev, maxrev linkrev range
1168 Examines filelog entries within minrev, maxrev linkrev range
1044 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1169 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1045 tuples in backwards order
1170 tuples in backwards order
1046 """
1171 """
1047 cl_count = len(repo)
1172 cl_count = len(repo)
1048 revs = []
1173 revs = []
1049 for j in xrange(0, last + 1):
1174 for j in xrange(0, last + 1):
1050 linkrev = filelog.linkrev(j)
1175 linkrev = filelog.linkrev(j)
1051 if linkrev < minrev:
1176 if linkrev < minrev:
1052 continue
1177 continue
1053 # only yield rev for which we have the changelog, it can
1178 # only yield rev for which we have the changelog, it can
1054 # happen while doing "hg log" during a pull or commit
1179 # happen while doing "hg log" during a pull or commit
1055 if linkrev >= cl_count:
1180 if linkrev >= cl_count:
1056 break
1181 break
1057
1182
1058 parentlinkrevs = []
1183 parentlinkrevs = []
1059 for p in filelog.parentrevs(j):
1184 for p in filelog.parentrevs(j):
1060 if p != nullrev:
1185 if p != nullrev:
1061 parentlinkrevs.append(filelog.linkrev(p))
1186 parentlinkrevs.append(filelog.linkrev(p))
1062 n = filelog.node(j)
1187 n = filelog.node(j)
1063 revs.append((linkrev, parentlinkrevs,
1188 revs.append((linkrev, parentlinkrevs,
1064 follow and filelog.renamed(n)))
1189 follow and filelog.renamed(n)))
1065
1190
1066 return reversed(revs)
1191 return reversed(revs)
1067 def iterfiles():
1192 def iterfiles():
1068 pctx = repo['.']
1193 pctx = repo['.']
1069 for filename in match.files():
1194 for filename in match.files():
1070 if follow:
1195 if follow:
1071 if filename not in pctx:
1196 if filename not in pctx:
1072 raise util.Abort(_('cannot follow file not in parent '
1197 raise util.Abort(_('cannot follow file not in parent '
1073 'revision: "%s"') % filename)
1198 'revision: "%s"') % filename)
1074 yield filename, pctx[filename].filenode()
1199 yield filename, pctx[filename].filenode()
1075 else:
1200 else:
1076 yield filename, None
1201 yield filename, None
1077 for filename_node in copies:
1202 for filename_node in copies:
1078 yield filename_node
1203 yield filename_node
1079
1204
1080 for file_, node in iterfiles():
1205 for file_, node in iterfiles():
1081 filelog = repo.file(file_)
1206 filelog = repo.file(file_)
1082 if not len(filelog):
1207 if not len(filelog):
1083 if node is None:
1208 if node is None:
1084 # A zero count may be a directory or deleted file, so
1209 # A zero count may be a directory or deleted file, so
1085 # try to find matching entries on the slow path.
1210 # try to find matching entries on the slow path.
1086 if follow:
1211 if follow:
1087 raise util.Abort(
1212 raise util.Abort(
1088 _('cannot follow nonexistent file: "%s"') % file_)
1213 _('cannot follow nonexistent file: "%s"') % file_)
1089 raise FileWalkError("Cannot walk via filelog")
1214 raise FileWalkError("Cannot walk via filelog")
1090 else:
1215 else:
1091 continue
1216 continue
1092
1217
1093 if node is None:
1218 if node is None:
1094 last = len(filelog) - 1
1219 last = len(filelog) - 1
1095 else:
1220 else:
1096 last = filelog.rev(node)
1221 last = filelog.rev(node)
1097
1222
1098
1223
1099 # keep track of all ancestors of the file
1224 # keep track of all ancestors of the file
1100 ancestors = set([filelog.linkrev(last)])
1225 ancestors = set([filelog.linkrev(last)])
1101
1226
1102 # iterate from latest to oldest revision
1227 # iterate from latest to oldest revision
1103 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1228 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1104 if not follow:
1229 if not follow:
1105 if rev > maxrev:
1230 if rev > maxrev:
1106 continue
1231 continue
1107 else:
1232 else:
1108 # Note that last might not be the first interesting
1233 # Note that last might not be the first interesting
1109 # rev to us:
1234 # rev to us:
1110 # if the file has been changed after maxrev, we'll
1235 # if the file has been changed after maxrev, we'll
1111 # have linkrev(last) > maxrev, and we still need
1236 # have linkrev(last) > maxrev, and we still need
1112 # to explore the file graph
1237 # to explore the file graph
1113 if rev not in ancestors:
1238 if rev not in ancestors:
1114 continue
1239 continue
1115 # XXX insert 1327 fix here
1240 # XXX insert 1327 fix here
1116 if flparentlinkrevs:
1241 if flparentlinkrevs:
1117 ancestors.update(flparentlinkrevs)
1242 ancestors.update(flparentlinkrevs)
1118
1243
1119 fncache.setdefault(rev, []).append(file_)
1244 fncache.setdefault(rev, []).append(file_)
1120 wanted.add(rev)
1245 wanted.add(rev)
1121 if copied:
1246 if copied:
1122 copies.append(copied)
1247 copies.append(copied)
1123
1248
1124 return wanted
1249 return wanted
1125
1250
1126 def walkchangerevs(repo, match, opts, prepare):
1251 def walkchangerevs(repo, match, opts, prepare):
1127 '''Iterate over files and the revs in which they changed.
1252 '''Iterate over files and the revs in which they changed.
1128
1253
1129 Callers most commonly need to iterate backwards over the history
1254 Callers most commonly need to iterate backwards over the history
1130 in which they are interested. Doing so has awful (quadratic-looking)
1255 in which they are interested. Doing so has awful (quadratic-looking)
1131 performance, so we use iterators in a "windowed" way.
1256 performance, so we use iterators in a "windowed" way.
1132
1257
1133 We walk a window of revisions in the desired order. Within the
1258 We walk a window of revisions in the desired order. Within the
1134 window, we first walk forwards to gather data, then in the desired
1259 window, we first walk forwards to gather data, then in the desired
1135 order (usually backwards) to display it.
1260 order (usually backwards) to display it.
1136
1261
1137 This function returns an iterator yielding contexts. Before
1262 This function returns an iterator yielding contexts. Before
1138 yielding each context, the iterator will first call the prepare
1263 yielding each context, the iterator will first call the prepare
1139 function on each context in the window in forward order.'''
1264 function on each context in the window in forward order.'''
1140
1265
1141 follow = opts.get('follow') or opts.get('follow_first')
1266 follow = opts.get('follow') or opts.get('follow_first')
1142
1267
1143 if opts.get('rev'):
1268 if opts.get('rev'):
1144 revs = scmutil.revrange(repo, opts.get('rev'))
1269 revs = scmutil.revrange(repo, opts.get('rev'))
1145 elif follow:
1270 elif follow:
1146 revs = repo.revs('reverse(:.)')
1271 revs = repo.revs('reverse(:.)')
1147 else:
1272 else:
1148 revs = revset.baseset(repo)
1273 revs = revset.baseset(repo)
1149 revs.reverse()
1274 revs.reverse()
1150 if not revs:
1275 if not revs:
1151 return []
1276 return []
1152 wanted = set()
1277 wanted = set()
1153 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1278 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1154 fncache = {}
1279 fncache = {}
1155 change = repo.changectx
1280 change = repo.changectx
1156 revs = revset.baseset(revs)
1281 revs = revset.baseset(revs)
1157
1282
1158 # First step is to fill wanted, the set of revisions that we want to yield.
1283 # First step is to fill wanted, the set of revisions that we want to yield.
1159 # When it does not induce extra cost, we also fill fncache for revisions in
1284 # When it does not induce extra cost, we also fill fncache for revisions in
1160 # wanted: a cache of filenames that were changed (ctx.files()) and that
1285 # wanted: a cache of filenames that were changed (ctx.files()) and that
1161 # match the file filtering conditions.
1286 # match the file filtering conditions.
1162
1287
1163 if not slowpath and not match.files():
1288 if not slowpath and not match.files():
1164 # No files, no patterns. Display all revs.
1289 # No files, no patterns. Display all revs.
1165 wanted = set(revs)
1290 wanted = set(revs)
1166
1291
1167 if not slowpath and match.files():
1292 if not slowpath and match.files():
1168 # We only have to read through the filelog to find wanted revisions
1293 # We only have to read through the filelog to find wanted revisions
1169
1294
1170 try:
1295 try:
1171 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1296 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1172 except FileWalkError:
1297 except FileWalkError:
1173 slowpath = True
1298 slowpath = True
1174
1299
1175 # We decided to fall back to the slowpath because at least one
1300 # We decided to fall back to the slowpath because at least one
1176 # of the paths was not a file. Check to see if at least one of them
1301 # of the paths was not a file. Check to see if at least one of them
1177 # existed in history, otherwise simply return
1302 # existed in history, otherwise simply return
1178 for path in match.files():
1303 for path in match.files():
1179 if path == '.' or path in repo.store:
1304 if path == '.' or path in repo.store:
1180 break
1305 break
1181 else:
1306 else:
1182 return []
1307 return []
1183
1308
1184 if slowpath:
1309 if slowpath:
1185 # We have to read the changelog to match filenames against
1310 # We have to read the changelog to match filenames against
1186 # changed files
1311 # changed files
1187
1312
1188 if follow:
1313 if follow:
1189 raise util.Abort(_('can only follow copies/renames for explicit '
1314 raise util.Abort(_('can only follow copies/renames for explicit '
1190 'filenames'))
1315 'filenames'))
1191
1316
1192 # The slow path checks files modified in every changeset.
1317 # The slow path checks files modified in every changeset.
1193 # This is really slow on large repos, so compute the set lazily.
1318 # This is really slow on large repos, so compute the set lazily.
1194 class lazywantedset(object):
1319 class lazywantedset(object):
1195 def __init__(self):
1320 def __init__(self):
1196 self.set = set()
1321 self.set = set()
1197 self.revs = set(revs)
1322 self.revs = set(revs)
1198
1323
1199 # No need to worry about locality here because it will be accessed
1324 # No need to worry about locality here because it will be accessed
1200 # in the same order as the increasing window below.
1325 # in the same order as the increasing window below.
1201 def __contains__(self, value):
1326 def __contains__(self, value):
1202 if value in self.set:
1327 if value in self.set:
1203 return True
1328 return True
1204 elif not value in self.revs:
1329 elif not value in self.revs:
1205 return False
1330 return False
1206 else:
1331 else:
1207 self.revs.discard(value)
1332 self.revs.discard(value)
1208 ctx = change(value)
1333 ctx = change(value)
1209 matches = filter(match, ctx.files())
1334 matches = filter(match, ctx.files())
1210 if matches:
1335 if matches:
1211 fncache[value] = matches
1336 fncache[value] = matches
1212 self.set.add(value)
1337 self.set.add(value)
1213 return True
1338 return True
1214 return False
1339 return False
1215
1340
1216 def discard(self, value):
1341 def discard(self, value):
1217 self.revs.discard(value)
1342 self.revs.discard(value)
1218 self.set.discard(value)
1343 self.set.discard(value)
1219
1344
1220 wanted = lazywantedset()
1345 wanted = lazywantedset()
1221
1346
1222 class followfilter(object):
1347 class followfilter(object):
1223 def __init__(self, onlyfirst=False):
1348 def __init__(self, onlyfirst=False):
1224 self.startrev = nullrev
1349 self.startrev = nullrev
1225 self.roots = set()
1350 self.roots = set()
1226 self.onlyfirst = onlyfirst
1351 self.onlyfirst = onlyfirst
1227
1352
1228 def match(self, rev):
1353 def match(self, rev):
1229 def realparents(rev):
1354 def realparents(rev):
1230 if self.onlyfirst:
1355 if self.onlyfirst:
1231 return repo.changelog.parentrevs(rev)[0:1]
1356 return repo.changelog.parentrevs(rev)[0:1]
1232 else:
1357 else:
1233 return filter(lambda x: x != nullrev,
1358 return filter(lambda x: x != nullrev,
1234 repo.changelog.parentrevs(rev))
1359 repo.changelog.parentrevs(rev))
1235
1360
1236 if self.startrev == nullrev:
1361 if self.startrev == nullrev:
1237 self.startrev = rev
1362 self.startrev = rev
1238 return True
1363 return True
1239
1364
1240 if rev > self.startrev:
1365 if rev > self.startrev:
1241 # forward: all descendants
1366 # forward: all descendants
1242 if not self.roots:
1367 if not self.roots:
1243 self.roots.add(self.startrev)
1368 self.roots.add(self.startrev)
1244 for parent in realparents(rev):
1369 for parent in realparents(rev):
1245 if parent in self.roots:
1370 if parent in self.roots:
1246 self.roots.add(rev)
1371 self.roots.add(rev)
1247 return True
1372 return True
1248 else:
1373 else:
1249 # backwards: all parents
1374 # backwards: all parents
1250 if not self.roots:
1375 if not self.roots:
1251 self.roots.update(realparents(self.startrev))
1376 self.roots.update(realparents(self.startrev))
1252 if rev in self.roots:
1377 if rev in self.roots:
1253 self.roots.remove(rev)
1378 self.roots.remove(rev)
1254 self.roots.update(realparents(rev))
1379 self.roots.update(realparents(rev))
1255 return True
1380 return True
1256
1381
1257 return False
1382 return False
1258
1383
1259 # it might be worthwhile to do this in the iterator if the rev range
1384 # it might be worthwhile to do this in the iterator if the rev range
1260 # is descending and the prune args are all within that range
1385 # is descending and the prune args are all within that range
1261 for rev in opts.get('prune', ()):
1386 for rev in opts.get('prune', ()):
1262 rev = repo[rev].rev()
1387 rev = repo[rev].rev()
1263 ff = followfilter()
1388 ff = followfilter()
1264 stop = min(revs[0], revs[-1])
1389 stop = min(revs[0], revs[-1])
1265 for x in xrange(rev, stop - 1, -1):
1390 for x in xrange(rev, stop - 1, -1):
1266 if ff.match(x):
1391 if ff.match(x):
1267 wanted.discard(x)
1392 wanted.discard(x)
1268
1393
1269 # Choose a small initial window if we will probably only visit a
1394 # Choose a small initial window if we will probably only visit a
1270 # few commits.
1395 # few commits.
1271 limit = loglimit(opts)
1396 limit = loglimit(opts)
1272 windowsize = 8
1397 windowsize = 8
1273 if limit:
1398 if limit:
1274 windowsize = min(limit, windowsize)
1399 windowsize = min(limit, windowsize)
1275
1400
1276 # Now that wanted is correctly initialized, we can iterate over the
1401 # Now that wanted is correctly initialized, we can iterate over the
1277 # revision range, yielding only revisions in wanted.
1402 # revision range, yielding only revisions in wanted.
1278 def iterate():
1403 def iterate():
1279 if follow and not match.files():
1404 if follow and not match.files():
1280 ff = followfilter(onlyfirst=opts.get('follow_first'))
1405 ff = followfilter(onlyfirst=opts.get('follow_first'))
1281 def want(rev):
1406 def want(rev):
1282 return ff.match(rev) and rev in wanted
1407 return ff.match(rev) and rev in wanted
1283 else:
1408 else:
1284 def want(rev):
1409 def want(rev):
1285 return rev in wanted
1410 return rev in wanted
1286
1411
1287 for i, window in increasingwindows(0, len(revs), windowsize):
1412 for i, window in increasingwindows(0, len(revs), windowsize):
1288 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1413 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1289 for rev in sorted(nrevs):
1414 for rev in sorted(nrevs):
1290 fns = fncache.get(rev)
1415 fns = fncache.get(rev)
1291 ctx = change(rev)
1416 ctx = change(rev)
1292 if not fns:
1417 if not fns:
1293 def fns_generator():
1418 def fns_generator():
1294 for f in ctx.files():
1419 for f in ctx.files():
1295 if match(f):
1420 if match(f):
1296 yield f
1421 yield f
1297 fns = fns_generator()
1422 fns = fns_generator()
1298 prepare(ctx, fns)
1423 prepare(ctx, fns)
1299 for rev in nrevs:
1424 for rev in nrevs:
1300 yield change(rev)
1425 yield change(rev)
1301 return iterate()
1426 return iterate()
1302
1427
1303 def _makegraphfilematcher(repo, pats, followfirst):
1428 def _makegraphfilematcher(repo, pats, followfirst):
1304 # When displaying a revision with --patch --follow FILE, we have
1429 # When displaying a revision with --patch --follow FILE, we have
1305 # to know which file of the revision must be diffed. With
1430 # to know which file of the revision must be diffed. With
1306 # --follow, we want the names of the ancestors of FILE in the
1431 # --follow, we want the names of the ancestors of FILE in the
1307 # revision, stored in "fcache". "fcache" is populated by
1432 # revision, stored in "fcache". "fcache" is populated by
1308 # reproducing the graph traversal already done by --follow revset
1433 # reproducing the graph traversal already done by --follow revset
1309 # and relating linkrevs to file names (which is not "correct" but
1434 # and relating linkrevs to file names (which is not "correct" but
1310 # good enough).
1435 # good enough).
1311 fcache = {}
1436 fcache = {}
1312 fcacheready = [False]
1437 fcacheready = [False]
1313 pctx = repo['.']
1438 pctx = repo['.']
1314 wctx = repo[None]
1439 wctx = repo[None]
1315
1440
1316 def populate():
1441 def populate():
1317 for fn in pats:
1442 for fn in pats:
1318 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1443 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1319 for c in i:
1444 for c in i:
1320 fcache.setdefault(c.linkrev(), set()).add(c.path())
1445 fcache.setdefault(c.linkrev(), set()).add(c.path())
1321
1446
1322 def filematcher(rev):
1447 def filematcher(rev):
1323 if not fcacheready[0]:
1448 if not fcacheready[0]:
1324 # Lazy initialization
1449 # Lazy initialization
1325 fcacheready[0] = True
1450 fcacheready[0] = True
1326 populate()
1451 populate()
1327 return scmutil.match(wctx, fcache.get(rev, []), default='path')
1452 return scmutil.match(wctx, fcache.get(rev, []), default='path')
1328
1453
1329 return filematcher
1454 return filematcher
1330
1455
1331 def _makegraphlogrevset(repo, pats, opts, revs):
1456 def _makegraphlogrevset(repo, pats, opts, revs):
1332 """Return (expr, filematcher) where expr is a revset string built
1457 """Return (expr, filematcher) where expr is a revset string built
1333 from log options and file patterns or None. If --stat or --patch
1458 from log options and file patterns or None. If --stat or --patch
1334 are not passed filematcher is None. Otherwise it is a callable
1459 are not passed filematcher is None. Otherwise it is a callable
1335 taking a revision number and returning a match objects filtering
1460 taking a revision number and returning a match objects filtering
1336 the files to be detailed when displaying the revision.
1461 the files to be detailed when displaying the revision.
1337 """
1462 """
1338 opt2revset = {
1463 opt2revset = {
1339 'no_merges': ('not merge()', None),
1464 'no_merges': ('not merge()', None),
1340 'only_merges': ('merge()', None),
1465 'only_merges': ('merge()', None),
1341 '_ancestors': ('ancestors(%(val)s)', None),
1466 '_ancestors': ('ancestors(%(val)s)', None),
1342 '_fancestors': ('_firstancestors(%(val)s)', None),
1467 '_fancestors': ('_firstancestors(%(val)s)', None),
1343 '_descendants': ('descendants(%(val)s)', None),
1468 '_descendants': ('descendants(%(val)s)', None),
1344 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1469 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1345 '_matchfiles': ('_matchfiles(%(val)s)', None),
1470 '_matchfiles': ('_matchfiles(%(val)s)', None),
1346 'date': ('date(%(val)r)', None),
1471 'date': ('date(%(val)r)', None),
1347 'branch': ('branch(%(val)r)', ' or '),
1472 'branch': ('branch(%(val)r)', ' or '),
1348 '_patslog': ('filelog(%(val)r)', ' or '),
1473 '_patslog': ('filelog(%(val)r)', ' or '),
1349 '_patsfollow': ('follow(%(val)r)', ' or '),
1474 '_patsfollow': ('follow(%(val)r)', ' or '),
1350 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1475 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1351 'keyword': ('keyword(%(val)r)', ' or '),
1476 'keyword': ('keyword(%(val)r)', ' or '),
1352 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1477 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1353 'user': ('user(%(val)r)', ' or '),
1478 'user': ('user(%(val)r)', ' or '),
1354 }
1479 }
1355
1480
1356 opts = dict(opts)
1481 opts = dict(opts)
1357 # follow or not follow?
1482 # follow or not follow?
1358 follow = opts.get('follow') or opts.get('follow_first')
1483 follow = opts.get('follow') or opts.get('follow_first')
1359 followfirst = opts.get('follow_first') and 1 or 0
1484 followfirst = opts.get('follow_first') and 1 or 0
1360 # --follow with FILE behaviour depends on revs...
1485 # --follow with FILE behaviour depends on revs...
1361 startrev = revs[0]
1486 startrev = revs[0]
1362 followdescendants = (len(revs) > 1 and revs[0] < revs[1]) and 1 or 0
1487 followdescendants = (len(revs) > 1 and revs[0] < revs[1]) and 1 or 0
1363
1488
1364 # branch and only_branch are really aliases and must be handled at
1489 # branch and only_branch are really aliases and must be handled at
1365 # the same time
1490 # the same time
1366 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1491 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1367 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1492 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1368 # pats/include/exclude are passed to match.match() directly in
1493 # pats/include/exclude are passed to match.match() directly in
1369 # _matchfiles() revset but walkchangerevs() builds its matcher with
1494 # _matchfiles() revset but walkchangerevs() builds its matcher with
1370 # scmutil.match(). The difference is input pats are globbed on
1495 # scmutil.match(). The difference is input pats are globbed on
1371 # platforms without shell expansion (windows).
1496 # platforms without shell expansion (windows).
1372 pctx = repo[None]
1497 pctx = repo[None]
1373 match, pats = scmutil.matchandpats(pctx, pats, opts)
1498 match, pats = scmutil.matchandpats(pctx, pats, opts)
1374 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1499 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1375 if not slowpath:
1500 if not slowpath:
1376 for f in match.files():
1501 for f in match.files():
1377 if follow and f not in pctx:
1502 if follow and f not in pctx:
1378 raise util.Abort(_('cannot follow file not in parent '
1503 raise util.Abort(_('cannot follow file not in parent '
1379 'revision: "%s"') % f)
1504 'revision: "%s"') % f)
1380 filelog = repo.file(f)
1505 filelog = repo.file(f)
1381 if not filelog:
1506 if not filelog:
1382 # A zero count may be a directory or deleted file, so
1507 # A zero count may be a directory or deleted file, so
1383 # try to find matching entries on the slow path.
1508 # try to find matching entries on the slow path.
1384 if follow:
1509 if follow:
1385 raise util.Abort(
1510 raise util.Abort(
1386 _('cannot follow nonexistent file: "%s"') % f)
1511 _('cannot follow nonexistent file: "%s"') % f)
1387 slowpath = True
1512 slowpath = True
1388
1513
1389 # We decided to fall back to the slowpath because at least one
1514 # We decided to fall back to the slowpath because at least one
1390 # of the paths was not a file. Check to see if at least one of them
1515 # of the paths was not a file. Check to see if at least one of them
1391 # existed in history - in that case, we'll continue down the
1516 # existed in history - in that case, we'll continue down the
1392 # slowpath; otherwise, we can turn off the slowpath
1517 # slowpath; otherwise, we can turn off the slowpath
1393 if slowpath:
1518 if slowpath:
1394 for path in match.files():
1519 for path in match.files():
1395 if path == '.' or path in repo.store:
1520 if path == '.' or path in repo.store:
1396 break
1521 break
1397 else:
1522 else:
1398 slowpath = False
1523 slowpath = False
1399
1524
1400 if slowpath:
1525 if slowpath:
1401 # See walkchangerevs() slow path.
1526 # See walkchangerevs() slow path.
1402 #
1527 #
1403 if follow:
1528 if follow:
1404 raise util.Abort(_('can only follow copies/renames for explicit '
1529 raise util.Abort(_('can only follow copies/renames for explicit '
1405 'filenames'))
1530 'filenames'))
1406 # pats/include/exclude cannot be represented as separate
1531 # pats/include/exclude cannot be represented as separate
1407 # revset expressions as their filtering logic applies at file
1532 # revset expressions as their filtering logic applies at file
1408 # level. For instance "-I a -X a" matches a revision touching
1533 # level. For instance "-I a -X a" matches a revision touching
1409 # "a" and "b" while "file(a) and not file(b)" does
1534 # "a" and "b" while "file(a) and not file(b)" does
1410 # not. Besides, filesets are evaluated against the working
1535 # not. Besides, filesets are evaluated against the working
1411 # directory.
1536 # directory.
1412 matchargs = ['r:', 'd:relpath']
1537 matchargs = ['r:', 'd:relpath']
1413 for p in pats:
1538 for p in pats:
1414 matchargs.append('p:' + p)
1539 matchargs.append('p:' + p)
1415 for p in opts.get('include', []):
1540 for p in opts.get('include', []):
1416 matchargs.append('i:' + p)
1541 matchargs.append('i:' + p)
1417 for p in opts.get('exclude', []):
1542 for p in opts.get('exclude', []):
1418 matchargs.append('x:' + p)
1543 matchargs.append('x:' + p)
1419 matchargs = ','.join(('%r' % p) for p in matchargs)
1544 matchargs = ','.join(('%r' % p) for p in matchargs)
1420 opts['_matchfiles'] = matchargs
1545 opts['_matchfiles'] = matchargs
1421 else:
1546 else:
1422 if follow:
1547 if follow:
1423 fpats = ('_patsfollow', '_patsfollowfirst')
1548 fpats = ('_patsfollow', '_patsfollowfirst')
1424 fnopats = (('_ancestors', '_fancestors'),
1549 fnopats = (('_ancestors', '_fancestors'),
1425 ('_descendants', '_fdescendants'))
1550 ('_descendants', '_fdescendants'))
1426 if pats:
1551 if pats:
1427 # follow() revset interprets its file argument as a
1552 # follow() revset interprets its file argument as a
1428 # manifest entry, so use match.files(), not pats.
1553 # manifest entry, so use match.files(), not pats.
1429 opts[fpats[followfirst]] = list(match.files())
1554 opts[fpats[followfirst]] = list(match.files())
1430 else:
1555 else:
1431 opts[fnopats[followdescendants][followfirst]] = str(startrev)
1556 opts[fnopats[followdescendants][followfirst]] = str(startrev)
1432 else:
1557 else:
1433 opts['_patslog'] = list(pats)
1558 opts['_patslog'] = list(pats)
1434
1559
1435 filematcher = None
1560 filematcher = None
1436 if opts.get('patch') or opts.get('stat'):
1561 if opts.get('patch') or opts.get('stat'):
1437 if follow:
1562 if follow:
1438 filematcher = _makegraphfilematcher(repo, pats, followfirst)
1563 filematcher = _makegraphfilematcher(repo, pats, followfirst)
1439 else:
1564 else:
1440 filematcher = lambda rev: match
1565 filematcher = lambda rev: match
1441
1566
1442 expr = []
1567 expr = []
1443 for op, val in opts.iteritems():
1568 for op, val in opts.iteritems():
1444 if not val:
1569 if not val:
1445 continue
1570 continue
1446 if op not in opt2revset:
1571 if op not in opt2revset:
1447 continue
1572 continue
1448 revop, andor = opt2revset[op]
1573 revop, andor = opt2revset[op]
1449 if '%(val)' not in revop:
1574 if '%(val)' not in revop:
1450 expr.append(revop)
1575 expr.append(revop)
1451 else:
1576 else:
1452 if not isinstance(val, list):
1577 if not isinstance(val, list):
1453 e = revop % {'val': val}
1578 e = revop % {'val': val}
1454 else:
1579 else:
1455 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1580 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1456 expr.append(e)
1581 expr.append(e)
1457
1582
1458 if expr:
1583 if expr:
1459 expr = '(' + ' and '.join(expr) + ')'
1584 expr = '(' + ' and '.join(expr) + ')'
1460 else:
1585 else:
1461 expr = None
1586 expr = None
1462 return expr, filematcher
1587 return expr, filematcher
1463
1588
1464 def getgraphlogrevs(repo, pats, opts):
1589 def getgraphlogrevs(repo, pats, opts):
1465 """Return (revs, expr, filematcher) where revs is an iterable of
1590 """Return (revs, expr, filematcher) where revs is an iterable of
1466 revision numbers, expr is a revset string built from log options
1591 revision numbers, expr is a revset string built from log options
1467 and file patterns or None, and used to filter 'revs'. If --stat or
1592 and file patterns or None, and used to filter 'revs'. If --stat or
1468 --patch are not passed filematcher is None. Otherwise it is a
1593 --patch are not passed filematcher is None. Otherwise it is a
1469 callable taking a revision number and returning a match objects
1594 callable taking a revision number and returning a match objects
1470 filtering the files to be detailed when displaying the revision.
1595 filtering the files to be detailed when displaying the revision.
1471 """
1596 """
1472 if not len(repo):
1597 if not len(repo):
1473 return [], None, None
1598 return [], None, None
1474 limit = loglimit(opts)
1599 limit = loglimit(opts)
1475 # Default --rev value depends on --follow but --follow behaviour
1600 # Default --rev value depends on --follow but --follow behaviour
1476 # depends on revisions resolved from --rev...
1601 # depends on revisions resolved from --rev...
1477 follow = opts.get('follow') or opts.get('follow_first')
1602 follow = opts.get('follow') or opts.get('follow_first')
1478 possiblyunsorted = False # whether revs might need sorting
1603 possiblyunsorted = False # whether revs might need sorting
1479 if opts.get('rev'):
1604 if opts.get('rev'):
1480 revs = scmutil.revrange(repo, opts['rev'])
1605 revs = scmutil.revrange(repo, opts['rev'])
1481 # Don't sort here because _makegraphlogrevset might depend on the
1606 # Don't sort here because _makegraphlogrevset might depend on the
1482 # order of revs
1607 # order of revs
1483 possiblyunsorted = True
1608 possiblyunsorted = True
1484 else:
1609 else:
1485 if follow and len(repo) > 0:
1610 if follow and len(repo) > 0:
1486 revs = repo.revs('reverse(:.)')
1611 revs = repo.revs('reverse(:.)')
1487 else:
1612 else:
1488 revs = revset.baseset(repo.changelog)
1613 revs = revset.baseset(repo.changelog)
1489 revs.reverse()
1614 revs.reverse()
1490 if not revs:
1615 if not revs:
1491 return [], None, None
1616 return [], None, None
1492 revs = revset.baseset(revs)
1617 revs = revset.baseset(revs)
1493 expr, filematcher = _makegraphlogrevset(repo, pats, opts, revs)
1618 expr, filematcher = _makegraphlogrevset(repo, pats, opts, revs)
1494 if possiblyunsorted:
1619 if possiblyunsorted:
1495 revs.sort(reverse=True)
1620 revs.sort(reverse=True)
1496 if expr:
1621 if expr:
1497 # Revset matchers often operate faster on revisions in changelog
1622 # Revset matchers often operate faster on revisions in changelog
1498 # order, because most filters deal with the changelog.
1623 # order, because most filters deal with the changelog.
1499 revs.reverse()
1624 revs.reverse()
1500 matcher = revset.match(repo.ui, expr)
1625 matcher = revset.match(repo.ui, expr)
1501 # Revset matches can reorder revisions. "A or B" typically returns
1626 # Revset matches can reorder revisions. "A or B" typically returns
1502 # returns the revision matching A then the revision matching B. Sort
1627 # returns the revision matching A then the revision matching B. Sort
1503 # again to fix that.
1628 # again to fix that.
1504 revs = matcher(repo, revs)
1629 revs = matcher(repo, revs)
1505 revs.sort(reverse=True)
1630 revs.sort(reverse=True)
1506 if limit is not None:
1631 if limit is not None:
1507 revs = revs[:limit]
1632 revs = revs[:limit]
1508
1633
1509 return revs, expr, filematcher
1634 return revs, expr, filematcher
1510
1635
1511 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
1636 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
1512 filematcher=None):
1637 filematcher=None):
1513 seen, state = [], graphmod.asciistate()
1638 seen, state = [], graphmod.asciistate()
1514 for rev, type, ctx, parents in dag:
1639 for rev, type, ctx, parents in dag:
1515 char = 'o'
1640 char = 'o'
1516 if ctx.node() in showparents:
1641 if ctx.node() in showparents:
1517 char = '@'
1642 char = '@'
1518 elif ctx.obsolete():
1643 elif ctx.obsolete():
1519 char = 'x'
1644 char = 'x'
1520 copies = None
1645 copies = None
1521 if getrenamed and ctx.rev():
1646 if getrenamed and ctx.rev():
1522 copies = []
1647 copies = []
1523 for fn in ctx.files():
1648 for fn in ctx.files():
1524 rename = getrenamed(fn, ctx.rev())
1649 rename = getrenamed(fn, ctx.rev())
1525 if rename:
1650 if rename:
1526 copies.append((fn, rename[0]))
1651 copies.append((fn, rename[0]))
1527 revmatchfn = None
1652 revmatchfn = None
1528 if filematcher is not None:
1653 if filematcher is not None:
1529 revmatchfn = filematcher(ctx.rev())
1654 revmatchfn = filematcher(ctx.rev())
1530 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
1655 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
1531 lines = displayer.hunk.pop(rev).split('\n')
1656 lines = displayer.hunk.pop(rev).split('\n')
1532 if not lines[-1]:
1657 if not lines[-1]:
1533 del lines[-1]
1658 del lines[-1]
1534 displayer.flush(rev)
1659 displayer.flush(rev)
1535 edges = edgefn(type, char, lines, seen, rev, parents)
1660 edges = edgefn(type, char, lines, seen, rev, parents)
1536 for type, char, lines, coldata in edges:
1661 for type, char, lines, coldata in edges:
1537 graphmod.ascii(ui, state, type, char, lines, coldata)
1662 graphmod.ascii(ui, state, type, char, lines, coldata)
1538 displayer.close()
1663 displayer.close()
1539
1664
1540 def graphlog(ui, repo, *pats, **opts):
1665 def graphlog(ui, repo, *pats, **opts):
1541 # Parameters are identical to log command ones
1666 # Parameters are identical to log command ones
1542 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
1667 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
1543 revdag = graphmod.dagwalker(repo, revs)
1668 revdag = graphmod.dagwalker(repo, revs)
1544
1669
1545 getrenamed = None
1670 getrenamed = None
1546 if opts.get('copies'):
1671 if opts.get('copies'):
1547 endrev = None
1672 endrev = None
1548 if opts.get('rev'):
1673 if opts.get('rev'):
1549 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
1674 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
1550 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
1675 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
1551 displayer = show_changeset(ui, repo, opts, buffered=True)
1676 displayer = show_changeset(ui, repo, opts, buffered=True)
1552 showparents = [ctx.node() for ctx in repo[None].parents()]
1677 showparents = [ctx.node() for ctx in repo[None].parents()]
1553 displaygraph(ui, revdag, displayer, showparents,
1678 displaygraph(ui, revdag, displayer, showparents,
1554 graphmod.asciiedges, getrenamed, filematcher)
1679 graphmod.asciiedges, getrenamed, filematcher)
1555
1680
1556 def checkunsupportedgraphflags(pats, opts):
1681 def checkunsupportedgraphflags(pats, opts):
1557 for op in ["newest_first"]:
1682 for op in ["newest_first"]:
1558 if op in opts and opts[op]:
1683 if op in opts and opts[op]:
1559 raise util.Abort(_("-G/--graph option is incompatible with --%s")
1684 raise util.Abort(_("-G/--graph option is incompatible with --%s")
1560 % op.replace("_", "-"))
1685 % op.replace("_", "-"))
1561
1686
1562 def graphrevs(repo, nodes, opts):
1687 def graphrevs(repo, nodes, opts):
1563 limit = loglimit(opts)
1688 limit = loglimit(opts)
1564 nodes.reverse()
1689 nodes.reverse()
1565 if limit is not None:
1690 if limit is not None:
1566 nodes = nodes[:limit]
1691 nodes = nodes[:limit]
1567 return graphmod.nodes(repo, nodes)
1692 return graphmod.nodes(repo, nodes)
1568
1693
1569 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1694 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1570 join = lambda f: os.path.join(prefix, f)
1695 join = lambda f: os.path.join(prefix, f)
1571 bad = []
1696 bad = []
1572 oldbad = match.bad
1697 oldbad = match.bad
1573 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1698 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1574 names = []
1699 names = []
1575 wctx = repo[None]
1700 wctx = repo[None]
1576 cca = None
1701 cca = None
1577 abort, warn = scmutil.checkportabilityalert(ui)
1702 abort, warn = scmutil.checkportabilityalert(ui)
1578 if abort or warn:
1703 if abort or warn:
1579 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
1704 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
1580 for f in repo.walk(match):
1705 for f in repo.walk(match):
1581 exact = match.exact(f)
1706 exact = match.exact(f)
1582 if exact or not explicitonly and f not in repo.dirstate:
1707 if exact or not explicitonly and f not in repo.dirstate:
1583 if cca:
1708 if cca:
1584 cca(f)
1709 cca(f)
1585 names.append(f)
1710 names.append(f)
1586 if ui.verbose or not exact:
1711 if ui.verbose or not exact:
1587 ui.status(_('adding %s\n') % match.rel(join(f)))
1712 ui.status(_('adding %s\n') % match.rel(join(f)))
1588
1713
1589 for subpath in sorted(wctx.substate):
1714 for subpath in sorted(wctx.substate):
1590 sub = wctx.sub(subpath)
1715 sub = wctx.sub(subpath)
1591 try:
1716 try:
1592 submatch = matchmod.narrowmatcher(subpath, match)
1717 submatch = matchmod.narrowmatcher(subpath, match)
1593 if listsubrepos:
1718 if listsubrepos:
1594 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1719 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1595 False))
1720 False))
1596 else:
1721 else:
1597 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1722 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1598 True))
1723 True))
1599 except error.LookupError:
1724 except error.LookupError:
1600 ui.status(_("skipping missing subrepository: %s\n")
1725 ui.status(_("skipping missing subrepository: %s\n")
1601 % join(subpath))
1726 % join(subpath))
1602
1727
1603 if not dryrun:
1728 if not dryrun:
1604 rejected = wctx.add(names, prefix)
1729 rejected = wctx.add(names, prefix)
1605 bad.extend(f for f in rejected if f in match.files())
1730 bad.extend(f for f in rejected if f in match.files())
1606 return bad
1731 return bad
1607
1732
1608 def forget(ui, repo, match, prefix, explicitonly):
1733 def forget(ui, repo, match, prefix, explicitonly):
1609 join = lambda f: os.path.join(prefix, f)
1734 join = lambda f: os.path.join(prefix, f)
1610 bad = []
1735 bad = []
1611 oldbad = match.bad
1736 oldbad = match.bad
1612 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1737 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1613 wctx = repo[None]
1738 wctx = repo[None]
1614 forgot = []
1739 forgot = []
1615 s = repo.status(match=match, clean=True)
1740 s = repo.status(match=match, clean=True)
1616 forget = sorted(s[0] + s[1] + s[3] + s[6])
1741 forget = sorted(s[0] + s[1] + s[3] + s[6])
1617 if explicitonly:
1742 if explicitonly:
1618 forget = [f for f in forget if match.exact(f)]
1743 forget = [f for f in forget if match.exact(f)]
1619
1744
1620 for subpath in sorted(wctx.substate):
1745 for subpath in sorted(wctx.substate):
1621 sub = wctx.sub(subpath)
1746 sub = wctx.sub(subpath)
1622 try:
1747 try:
1623 submatch = matchmod.narrowmatcher(subpath, match)
1748 submatch = matchmod.narrowmatcher(subpath, match)
1624 subbad, subforgot = sub.forget(ui, submatch, prefix)
1749 subbad, subforgot = sub.forget(ui, submatch, prefix)
1625 bad.extend([subpath + '/' + f for f in subbad])
1750 bad.extend([subpath + '/' + f for f in subbad])
1626 forgot.extend([subpath + '/' + f for f in subforgot])
1751 forgot.extend([subpath + '/' + f for f in subforgot])
1627 except error.LookupError:
1752 except error.LookupError:
1628 ui.status(_("skipping missing subrepository: %s\n")
1753 ui.status(_("skipping missing subrepository: %s\n")
1629 % join(subpath))
1754 % join(subpath))
1630
1755
1631 if not explicitonly:
1756 if not explicitonly:
1632 for f in match.files():
1757 for f in match.files():
1633 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
1758 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
1634 if f not in forgot:
1759 if f not in forgot:
1635 if os.path.exists(match.rel(join(f))):
1760 if os.path.exists(match.rel(join(f))):
1636 ui.warn(_('not removing %s: '
1761 ui.warn(_('not removing %s: '
1637 'file is already untracked\n')
1762 'file is already untracked\n')
1638 % match.rel(join(f)))
1763 % match.rel(join(f)))
1639 bad.append(f)
1764 bad.append(f)
1640
1765
1641 for f in forget:
1766 for f in forget:
1642 if ui.verbose or not match.exact(f):
1767 if ui.verbose or not match.exact(f):
1643 ui.status(_('removing %s\n') % match.rel(join(f)))
1768 ui.status(_('removing %s\n') % match.rel(join(f)))
1644
1769
1645 rejected = wctx.forget(forget, prefix)
1770 rejected = wctx.forget(forget, prefix)
1646 bad.extend(f for f in rejected if f in match.files())
1771 bad.extend(f for f in rejected if f in match.files())
1647 forgot.extend(forget)
1772 forgot.extend(forget)
1648 return bad, forgot
1773 return bad, forgot
1649
1774
1650 def duplicatecopies(repo, rev, fromrev):
1775 def duplicatecopies(repo, rev, fromrev):
1651 '''reproduce copies from fromrev to rev in the dirstate'''
1776 '''reproduce copies from fromrev to rev in the dirstate'''
1652 for dst, src in copies.pathcopies(repo[fromrev], repo[rev]).iteritems():
1777 for dst, src in copies.pathcopies(repo[fromrev], repo[rev]).iteritems():
1653 # copies.pathcopies returns backward renames, so dst might not
1778 # copies.pathcopies returns backward renames, so dst might not
1654 # actually be in the dirstate
1779 # actually be in the dirstate
1655 if repo.dirstate[dst] in "nma":
1780 if repo.dirstate[dst] in "nma":
1656 repo.dirstate.copy(src, dst)
1781 repo.dirstate.copy(src, dst)
1657
1782
1658 def commit(ui, repo, commitfunc, pats, opts):
1783 def commit(ui, repo, commitfunc, pats, opts):
1659 '''commit the specified files or all outstanding changes'''
1784 '''commit the specified files or all outstanding changes'''
1660 date = opts.get('date')
1785 date = opts.get('date')
1661 if date:
1786 if date:
1662 opts['date'] = util.parsedate(date)
1787 opts['date'] = util.parsedate(date)
1663 message = logmessage(ui, opts)
1788 message = logmessage(ui, opts)
1664
1789
1665 # extract addremove carefully -- this function can be called from a command
1790 # extract addremove carefully -- this function can be called from a command
1666 # that doesn't support addremove
1791 # that doesn't support addremove
1667 if opts.get('addremove'):
1792 if opts.get('addremove'):
1668 scmutil.addremove(repo, pats, opts)
1793 scmutil.addremove(repo, pats, opts)
1669
1794
1670 return commitfunc(ui, repo, message,
1795 return commitfunc(ui, repo, message,
1671 scmutil.match(repo[None], pats, opts), opts)
1796 scmutil.match(repo[None], pats, opts), opts)
1672
1797
1673 def amend(ui, repo, commitfunc, old, extra, pats, opts):
1798 def amend(ui, repo, commitfunc, old, extra, pats, opts):
1674 ui.note(_('amending changeset %s\n') % old)
1799 ui.note(_('amending changeset %s\n') % old)
1675 base = old.p1()
1800 base = old.p1()
1676
1801
1677 wlock = lock = newid = None
1802 wlock = lock = newid = None
1678 try:
1803 try:
1679 wlock = repo.wlock()
1804 wlock = repo.wlock()
1680 lock = repo.lock()
1805 lock = repo.lock()
1681 tr = repo.transaction('amend')
1806 tr = repo.transaction('amend')
1682 try:
1807 try:
1683 # See if we got a message from -m or -l, if not, open the editor
1808 # See if we got a message from -m or -l, if not, open the editor
1684 # with the message of the changeset to amend
1809 # with the message of the changeset to amend
1685 message = logmessage(ui, opts)
1810 message = logmessage(ui, opts)
1686 # ensure logfile does not conflict with later enforcement of the
1811 # ensure logfile does not conflict with later enforcement of the
1687 # message. potential logfile content has been processed by
1812 # message. potential logfile content has been processed by
1688 # `logmessage` anyway.
1813 # `logmessage` anyway.
1689 opts.pop('logfile')
1814 opts.pop('logfile')
1690 # First, do a regular commit to record all changes in the working
1815 # First, do a regular commit to record all changes in the working
1691 # directory (if there are any)
1816 # directory (if there are any)
1692 ui.callhooks = False
1817 ui.callhooks = False
1693 currentbookmark = repo._bookmarkcurrent
1818 currentbookmark = repo._bookmarkcurrent
1694 try:
1819 try:
1695 repo._bookmarkcurrent = None
1820 repo._bookmarkcurrent = None
1696 opts['message'] = 'temporary amend commit for %s' % old
1821 opts['message'] = 'temporary amend commit for %s' % old
1697 node = commit(ui, repo, commitfunc, pats, opts)
1822 node = commit(ui, repo, commitfunc, pats, opts)
1698 finally:
1823 finally:
1699 repo._bookmarkcurrent = currentbookmark
1824 repo._bookmarkcurrent = currentbookmark
1700 ui.callhooks = True
1825 ui.callhooks = True
1701 ctx = repo[node]
1826 ctx = repo[node]
1702
1827
1703 # Participating changesets:
1828 # Participating changesets:
1704 #
1829 #
1705 # node/ctx o - new (intermediate) commit that contains changes
1830 # node/ctx o - new (intermediate) commit that contains changes
1706 # | from working dir to go into amending commit
1831 # | from working dir to go into amending commit
1707 # | (or a workingctx if there were no changes)
1832 # | (or a workingctx if there were no changes)
1708 # |
1833 # |
1709 # old o - changeset to amend
1834 # old o - changeset to amend
1710 # |
1835 # |
1711 # base o - parent of amending changeset
1836 # base o - parent of amending changeset
1712
1837
1713 # Update extra dict from amended commit (e.g. to preserve graft
1838 # Update extra dict from amended commit (e.g. to preserve graft
1714 # source)
1839 # source)
1715 extra.update(old.extra())
1840 extra.update(old.extra())
1716
1841
1717 # Also update it from the intermediate commit or from the wctx
1842 # Also update it from the intermediate commit or from the wctx
1718 extra.update(ctx.extra())
1843 extra.update(ctx.extra())
1719
1844
1720 if len(old.parents()) > 1:
1845 if len(old.parents()) > 1:
1721 # ctx.files() isn't reliable for merges, so fall back to the
1846 # ctx.files() isn't reliable for merges, so fall back to the
1722 # slower repo.status() method
1847 # slower repo.status() method
1723 files = set([fn for st in repo.status(base, old)[:3]
1848 files = set([fn for st in repo.status(base, old)[:3]
1724 for fn in st])
1849 for fn in st])
1725 else:
1850 else:
1726 files = set(old.files())
1851 files = set(old.files())
1727
1852
1728 # Second, we use either the commit we just did, or if there were no
1853 # Second, we use either the commit we just did, or if there were no
1729 # changes the parent of the working directory as the version of the
1854 # changes the parent of the working directory as the version of the
1730 # files in the final amend commit
1855 # files in the final amend commit
1731 if node:
1856 if node:
1732 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
1857 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
1733
1858
1734 user = ctx.user()
1859 user = ctx.user()
1735 date = ctx.date()
1860 date = ctx.date()
1736 # Recompute copies (avoid recording a -> b -> a)
1861 # Recompute copies (avoid recording a -> b -> a)
1737 copied = copies.pathcopies(base, ctx)
1862 copied = copies.pathcopies(base, ctx)
1738
1863
1739 # Prune files which were reverted by the updates: if old
1864 # Prune files which were reverted by the updates: if old
1740 # introduced file X and our intermediate commit, node,
1865 # introduced file X and our intermediate commit, node,
1741 # renamed that file, then those two files are the same and
1866 # renamed that file, then those two files are the same and
1742 # we can discard X from our list of files. Likewise if X
1867 # we can discard X from our list of files. Likewise if X
1743 # was deleted, it's no longer relevant
1868 # was deleted, it's no longer relevant
1744 files.update(ctx.files())
1869 files.update(ctx.files())
1745
1870
1746 def samefile(f):
1871 def samefile(f):
1747 if f in ctx.manifest():
1872 if f in ctx.manifest():
1748 a = ctx.filectx(f)
1873 a = ctx.filectx(f)
1749 if f in base.manifest():
1874 if f in base.manifest():
1750 b = base.filectx(f)
1875 b = base.filectx(f)
1751 return (not a.cmp(b)
1876 return (not a.cmp(b)
1752 and a.flags() == b.flags())
1877 and a.flags() == b.flags())
1753 else:
1878 else:
1754 return False
1879 return False
1755 else:
1880 else:
1756 return f not in base.manifest()
1881 return f not in base.manifest()
1757 files = [f for f in files if not samefile(f)]
1882 files = [f for f in files if not samefile(f)]
1758
1883
1759 def filectxfn(repo, ctx_, path):
1884 def filectxfn(repo, ctx_, path):
1760 try:
1885 try:
1761 fctx = ctx[path]
1886 fctx = ctx[path]
1762 flags = fctx.flags()
1887 flags = fctx.flags()
1763 mctx = context.memfilectx(fctx.path(), fctx.data(),
1888 mctx = context.memfilectx(fctx.path(), fctx.data(),
1764 islink='l' in flags,
1889 islink='l' in flags,
1765 isexec='x' in flags,
1890 isexec='x' in flags,
1766 copied=copied.get(path))
1891 copied=copied.get(path))
1767 return mctx
1892 return mctx
1768 except KeyError:
1893 except KeyError:
1769 raise IOError
1894 raise IOError
1770 else:
1895 else:
1771 ui.note(_('copying changeset %s to %s\n') % (old, base))
1896 ui.note(_('copying changeset %s to %s\n') % (old, base))
1772
1897
1773 # Use version of files as in the old cset
1898 # Use version of files as in the old cset
1774 def filectxfn(repo, ctx_, path):
1899 def filectxfn(repo, ctx_, path):
1775 try:
1900 try:
1776 return old.filectx(path)
1901 return old.filectx(path)
1777 except KeyError:
1902 except KeyError:
1778 raise IOError
1903 raise IOError
1779
1904
1780 user = opts.get('user') or old.user()
1905 user = opts.get('user') or old.user()
1781 date = opts.get('date') or old.date()
1906 date = opts.get('date') or old.date()
1782 editmsg = False
1907 editmsg = False
1783 if not message:
1908 if not message:
1784 editmsg = True
1909 editmsg = True
1785 message = old.description()
1910 message = old.description()
1786
1911
1787 pureextra = extra.copy()
1912 pureextra = extra.copy()
1788 extra['amend_source'] = old.hex()
1913 extra['amend_source'] = old.hex()
1789
1914
1790 new = context.memctx(repo,
1915 new = context.memctx(repo,
1791 parents=[base.node(), old.p2().node()],
1916 parents=[base.node(), old.p2().node()],
1792 text=message,
1917 text=message,
1793 files=files,
1918 files=files,
1794 filectxfn=filectxfn,
1919 filectxfn=filectxfn,
1795 user=user,
1920 user=user,
1796 date=date,
1921 date=date,
1797 extra=extra)
1922 extra=extra)
1798 if editmsg:
1923 if editmsg:
1799 new._text = commitforceeditor(repo, new, [])
1924 new._text = commitforceeditor(repo, new, [])
1800
1925
1801 newdesc = changelog.stripdesc(new.description())
1926 newdesc = changelog.stripdesc(new.description())
1802 if ((not node)
1927 if ((not node)
1803 and newdesc == old.description()
1928 and newdesc == old.description()
1804 and user == old.user()
1929 and user == old.user()
1805 and date == old.date()
1930 and date == old.date()
1806 and pureextra == old.extra()):
1931 and pureextra == old.extra()):
1807 # nothing changed. continuing here would create a new node
1932 # nothing changed. continuing here would create a new node
1808 # anyway because of the amend_source noise.
1933 # anyway because of the amend_source noise.
1809 #
1934 #
1810 # This not what we expect from amend.
1935 # This not what we expect from amend.
1811 return old.node()
1936 return old.node()
1812
1937
1813 ph = repo.ui.config('phases', 'new-commit', phases.draft)
1938 ph = repo.ui.config('phases', 'new-commit', phases.draft)
1814 try:
1939 try:
1815 repo.ui.setconfig('phases', 'new-commit', old.phase())
1940 repo.ui.setconfig('phases', 'new-commit', old.phase())
1816 newid = repo.commitctx(new)
1941 newid = repo.commitctx(new)
1817 finally:
1942 finally:
1818 repo.ui.setconfig('phases', 'new-commit', ph)
1943 repo.ui.setconfig('phases', 'new-commit', ph)
1819 if newid != old.node():
1944 if newid != old.node():
1820 # Reroute the working copy parent to the new changeset
1945 # Reroute the working copy parent to the new changeset
1821 repo.setparents(newid, nullid)
1946 repo.setparents(newid, nullid)
1822
1947
1823 # Move bookmarks from old parent to amend commit
1948 # Move bookmarks from old parent to amend commit
1824 bms = repo.nodebookmarks(old.node())
1949 bms = repo.nodebookmarks(old.node())
1825 if bms:
1950 if bms:
1826 marks = repo._bookmarks
1951 marks = repo._bookmarks
1827 for bm in bms:
1952 for bm in bms:
1828 marks[bm] = newid
1953 marks[bm] = newid
1829 marks.write()
1954 marks.write()
1830 #commit the whole amend process
1955 #commit the whole amend process
1831 if obsolete._enabled and newid != old.node():
1956 if obsolete._enabled and newid != old.node():
1832 # mark the new changeset as successor of the rewritten one
1957 # mark the new changeset as successor of the rewritten one
1833 new = repo[newid]
1958 new = repo[newid]
1834 obs = [(old, (new,))]
1959 obs = [(old, (new,))]
1835 if node:
1960 if node:
1836 obs.append((ctx, ()))
1961 obs.append((ctx, ()))
1837
1962
1838 obsolete.createmarkers(repo, obs)
1963 obsolete.createmarkers(repo, obs)
1839 tr.close()
1964 tr.close()
1840 finally:
1965 finally:
1841 tr.release()
1966 tr.release()
1842 if (not obsolete._enabled) and newid != old.node():
1967 if (not obsolete._enabled) and newid != old.node():
1843 # Strip the intermediate commit (if there was one) and the amended
1968 # Strip the intermediate commit (if there was one) and the amended
1844 # commit
1969 # commit
1845 if node:
1970 if node:
1846 ui.note(_('stripping intermediate changeset %s\n') % ctx)
1971 ui.note(_('stripping intermediate changeset %s\n') % ctx)
1847 ui.note(_('stripping amended changeset %s\n') % old)
1972 ui.note(_('stripping amended changeset %s\n') % old)
1848 repair.strip(ui, repo, old.node(), topic='amend-backup')
1973 repair.strip(ui, repo, old.node(), topic='amend-backup')
1849 finally:
1974 finally:
1850 if newid is None:
1975 if newid is None:
1851 repo.dirstate.invalidate()
1976 repo.dirstate.invalidate()
1852 lockmod.release(lock, wlock)
1977 lockmod.release(lock, wlock)
1853 return newid
1978 return newid
1854
1979
1855 def commiteditor(repo, ctx, subs):
1980 def commiteditor(repo, ctx, subs):
1856 if ctx.description():
1981 if ctx.description():
1857 return ctx.description()
1982 return ctx.description()
1858 return commitforceeditor(repo, ctx, subs)
1983 return commitforceeditor(repo, ctx, subs)
1859
1984
1860 def commitforceeditor(repo, ctx, subs):
1985 def commitforceeditor(repo, ctx, subs):
1861 edittext = []
1986 edittext = []
1862 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1987 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1863 if ctx.description():
1988 if ctx.description():
1864 edittext.append(ctx.description())
1989 edittext.append(ctx.description())
1865 edittext.append("")
1990 edittext.append("")
1866 edittext.append("") # Empty line between message and comments.
1991 edittext.append("") # Empty line between message and comments.
1867 edittext.append(_("HG: Enter commit message."
1992 edittext.append(_("HG: Enter commit message."
1868 " Lines beginning with 'HG:' are removed."))
1993 " Lines beginning with 'HG:' are removed."))
1869 edittext.append(_("HG: Leave message empty to abort commit."))
1994 edittext.append(_("HG: Leave message empty to abort commit."))
1870 edittext.append("HG: --")
1995 edittext.append("HG: --")
1871 edittext.append(_("HG: user: %s") % ctx.user())
1996 edittext.append(_("HG: user: %s") % ctx.user())
1872 if ctx.p2():
1997 if ctx.p2():
1873 edittext.append(_("HG: branch merge"))
1998 edittext.append(_("HG: branch merge"))
1874 if ctx.branch():
1999 if ctx.branch():
1875 edittext.append(_("HG: branch '%s'") % ctx.branch())
2000 edittext.append(_("HG: branch '%s'") % ctx.branch())
1876 if bookmarks.iscurrent(repo):
2001 if bookmarks.iscurrent(repo):
1877 edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
2002 edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
1878 edittext.extend([_("HG: subrepo %s") % s for s in subs])
2003 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1879 edittext.extend([_("HG: added %s") % f for f in added])
2004 edittext.extend([_("HG: added %s") % f for f in added])
1880 edittext.extend([_("HG: changed %s") % f for f in modified])
2005 edittext.extend([_("HG: changed %s") % f for f in modified])
1881 edittext.extend([_("HG: removed %s") % f for f in removed])
2006 edittext.extend([_("HG: removed %s") % f for f in removed])
1882 if not added and not modified and not removed:
2007 if not added and not modified and not removed:
1883 edittext.append(_("HG: no files changed"))
2008 edittext.append(_("HG: no files changed"))
1884 edittext.append("")
2009 edittext.append("")
1885 # run editor in the repository root
2010 # run editor in the repository root
1886 olddir = os.getcwd()
2011 olddir = os.getcwd()
1887 os.chdir(repo.root)
2012 os.chdir(repo.root)
1888 text = repo.ui.edit("\n".join(edittext), ctx.user())
2013 text = repo.ui.edit("\n".join(edittext), ctx.user())
1889 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2014 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1890 os.chdir(olddir)
2015 os.chdir(olddir)
1891
2016
1892 if not text.strip():
2017 if not text.strip():
1893 raise util.Abort(_("empty commit message"))
2018 raise util.Abort(_("empty commit message"))
1894
2019
1895 return text
2020 return text
1896
2021
1897 def commitstatus(repo, node, branch, bheads=None, opts={}):
2022 def commitstatus(repo, node, branch, bheads=None, opts={}):
1898 ctx = repo[node]
2023 ctx = repo[node]
1899 parents = ctx.parents()
2024 parents = ctx.parents()
1900
2025
1901 if (not opts.get('amend') and bheads and node not in bheads and not
2026 if (not opts.get('amend') and bheads and node not in bheads and not
1902 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2027 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1903 repo.ui.status(_('created new head\n'))
2028 repo.ui.status(_('created new head\n'))
1904 # The message is not printed for initial roots. For the other
2029 # The message is not printed for initial roots. For the other
1905 # changesets, it is printed in the following situations:
2030 # changesets, it is printed in the following situations:
1906 #
2031 #
1907 # Par column: for the 2 parents with ...
2032 # Par column: for the 2 parents with ...
1908 # N: null or no parent
2033 # N: null or no parent
1909 # B: parent is on another named branch
2034 # B: parent is on another named branch
1910 # C: parent is a regular non head changeset
2035 # C: parent is a regular non head changeset
1911 # H: parent was a branch head of the current branch
2036 # H: parent was a branch head of the current branch
1912 # Msg column: whether we print "created new head" message
2037 # Msg column: whether we print "created new head" message
1913 # In the following, it is assumed that there already exists some
2038 # In the following, it is assumed that there already exists some
1914 # initial branch heads of the current branch, otherwise nothing is
2039 # initial branch heads of the current branch, otherwise nothing is
1915 # printed anyway.
2040 # printed anyway.
1916 #
2041 #
1917 # Par Msg Comment
2042 # Par Msg Comment
1918 # N N y additional topo root
2043 # N N y additional topo root
1919 #
2044 #
1920 # B N y additional branch root
2045 # B N y additional branch root
1921 # C N y additional topo head
2046 # C N y additional topo head
1922 # H N n usual case
2047 # H N n usual case
1923 #
2048 #
1924 # B B y weird additional branch root
2049 # B B y weird additional branch root
1925 # C B y branch merge
2050 # C B y branch merge
1926 # H B n merge with named branch
2051 # H B n merge with named branch
1927 #
2052 #
1928 # C C y additional head from merge
2053 # C C y additional head from merge
1929 # C H n merge with a head
2054 # C H n merge with a head
1930 #
2055 #
1931 # H H n head merge: head count decreases
2056 # H H n head merge: head count decreases
1932
2057
1933 if not opts.get('close_branch'):
2058 if not opts.get('close_branch'):
1934 for r in parents:
2059 for r in parents:
1935 if r.closesbranch() and r.branch() == branch:
2060 if r.closesbranch() and r.branch() == branch:
1936 repo.ui.status(_('reopening closed branch head %d\n') % r)
2061 repo.ui.status(_('reopening closed branch head %d\n') % r)
1937
2062
1938 if repo.ui.debugflag:
2063 if repo.ui.debugflag:
1939 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
2064 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1940 elif repo.ui.verbose:
2065 elif repo.ui.verbose:
1941 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
2066 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1942
2067
1943 def revert(ui, repo, ctx, parents, *pats, **opts):
2068 def revert(ui, repo, ctx, parents, *pats, **opts):
1944 parent, p2 = parents
2069 parent, p2 = parents
1945 node = ctx.node()
2070 node = ctx.node()
1946
2071
1947 mf = ctx.manifest()
2072 mf = ctx.manifest()
1948 if node == parent:
2073 if node == parent:
1949 pmf = mf
2074 pmf = mf
1950 else:
2075 else:
1951 pmf = None
2076 pmf = None
1952
2077
1953 # need all matching names in dirstate and manifest of target rev,
2078 # need all matching names in dirstate and manifest of target rev,
1954 # so have to walk both. do not print errors if files exist in one
2079 # so have to walk both. do not print errors if files exist in one
1955 # but not other.
2080 # but not other.
1956
2081
1957 names = {}
2082 names = {}
1958
2083
1959 wlock = repo.wlock()
2084 wlock = repo.wlock()
1960 try:
2085 try:
1961 # walk dirstate.
2086 # walk dirstate.
1962
2087
1963 m = scmutil.match(repo[None], pats, opts)
2088 m = scmutil.match(repo[None], pats, opts)
1964 m.bad = lambda x, y: False
2089 m.bad = lambda x, y: False
1965 for abs in repo.walk(m):
2090 for abs in repo.walk(m):
1966 names[abs] = m.rel(abs), m.exact(abs)
2091 names[abs] = m.rel(abs), m.exact(abs)
1967
2092
1968 # walk target manifest.
2093 # walk target manifest.
1969
2094
1970 def badfn(path, msg):
2095 def badfn(path, msg):
1971 if path in names:
2096 if path in names:
1972 return
2097 return
1973 if path in ctx.substate:
2098 if path in ctx.substate:
1974 return
2099 return
1975 path_ = path + '/'
2100 path_ = path + '/'
1976 for f in names:
2101 for f in names:
1977 if f.startswith(path_):
2102 if f.startswith(path_):
1978 return
2103 return
1979 ui.warn("%s: %s\n" % (m.rel(path), msg))
2104 ui.warn("%s: %s\n" % (m.rel(path), msg))
1980
2105
1981 m = scmutil.match(ctx, pats, opts)
2106 m = scmutil.match(ctx, pats, opts)
1982 m.bad = badfn
2107 m.bad = badfn
1983 for abs in ctx.walk(m):
2108 for abs in ctx.walk(m):
1984 if abs not in names:
2109 if abs not in names:
1985 names[abs] = m.rel(abs), m.exact(abs)
2110 names[abs] = m.rel(abs), m.exact(abs)
1986
2111
1987 # get the list of subrepos that must be reverted
2112 # get the list of subrepos that must be reverted
1988 targetsubs = sorted(s for s in ctx.substate if m(s))
2113 targetsubs = sorted(s for s in ctx.substate if m(s))
1989 m = scmutil.matchfiles(repo, names)
2114 m = scmutil.matchfiles(repo, names)
1990 changes = repo.status(match=m)[:4]
2115 changes = repo.status(match=m)[:4]
1991 modified, added, removed, deleted = map(set, changes)
2116 modified, added, removed, deleted = map(set, changes)
1992
2117
1993 # if f is a rename, also revert the source
2118 # if f is a rename, also revert the source
1994 cwd = repo.getcwd()
2119 cwd = repo.getcwd()
1995 for f in added:
2120 for f in added:
1996 src = repo.dirstate.copied(f)
2121 src = repo.dirstate.copied(f)
1997 if src and src not in names and repo.dirstate[src] == 'r':
2122 if src and src not in names and repo.dirstate[src] == 'r':
1998 removed.add(src)
2123 removed.add(src)
1999 names[src] = (repo.pathto(src, cwd), True)
2124 names[src] = (repo.pathto(src, cwd), True)
2000
2125
2001 def removeforget(abs):
2126 def removeforget(abs):
2002 if repo.dirstate[abs] == 'a':
2127 if repo.dirstate[abs] == 'a':
2003 return _('forgetting %s\n')
2128 return _('forgetting %s\n')
2004 return _('removing %s\n')
2129 return _('removing %s\n')
2005
2130
2006 revert = ([], _('reverting %s\n'))
2131 revert = ([], _('reverting %s\n'))
2007 add = ([], _('adding %s\n'))
2132 add = ([], _('adding %s\n'))
2008 remove = ([], removeforget)
2133 remove = ([], removeforget)
2009 undelete = ([], _('undeleting %s\n'))
2134 undelete = ([], _('undeleting %s\n'))
2010
2135
2011 disptable = (
2136 disptable = (
2012 # dispatch table:
2137 # dispatch table:
2013 # file state
2138 # file state
2014 # action if in target manifest
2139 # action if in target manifest
2015 # action if not in target manifest
2140 # action if not in target manifest
2016 # make backup if in target manifest
2141 # make backup if in target manifest
2017 # make backup if not in target manifest
2142 # make backup if not in target manifest
2018 (modified, revert, remove, True, True),
2143 (modified, revert, remove, True, True),
2019 (added, revert, remove, True, False),
2144 (added, revert, remove, True, False),
2020 (removed, undelete, None, True, False),
2145 (removed, undelete, None, True, False),
2021 (deleted, revert, remove, False, False),
2146 (deleted, revert, remove, False, False),
2022 )
2147 )
2023
2148
2024 for abs, (rel, exact) in sorted(names.items()):
2149 for abs, (rel, exact) in sorted(names.items()):
2025 mfentry = mf.get(abs)
2150 mfentry = mf.get(abs)
2026 target = repo.wjoin(abs)
2151 target = repo.wjoin(abs)
2027 def handle(xlist, dobackup):
2152 def handle(xlist, dobackup):
2028 xlist[0].append(abs)
2153 xlist[0].append(abs)
2029 if (dobackup and not opts.get('no_backup') and
2154 if (dobackup and not opts.get('no_backup') and
2030 os.path.lexists(target) and
2155 os.path.lexists(target) and
2031 abs in ctx and repo[None][abs].cmp(ctx[abs])):
2156 abs in ctx and repo[None][abs].cmp(ctx[abs])):
2032 bakname = "%s.orig" % rel
2157 bakname = "%s.orig" % rel
2033 ui.note(_('saving current version of %s as %s\n') %
2158 ui.note(_('saving current version of %s as %s\n') %
2034 (rel, bakname))
2159 (rel, bakname))
2035 if not opts.get('dry_run'):
2160 if not opts.get('dry_run'):
2036 util.rename(target, bakname)
2161 util.rename(target, bakname)
2037 if ui.verbose or not exact:
2162 if ui.verbose or not exact:
2038 msg = xlist[1]
2163 msg = xlist[1]
2039 if not isinstance(msg, basestring):
2164 if not isinstance(msg, basestring):
2040 msg = msg(abs)
2165 msg = msg(abs)
2041 ui.status(msg % rel)
2166 ui.status(msg % rel)
2042 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2167 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2043 if abs not in table:
2168 if abs not in table:
2044 continue
2169 continue
2045 # file has changed in dirstate
2170 # file has changed in dirstate
2046 if mfentry:
2171 if mfentry:
2047 handle(hitlist, backuphit)
2172 handle(hitlist, backuphit)
2048 elif misslist is not None:
2173 elif misslist is not None:
2049 handle(misslist, backupmiss)
2174 handle(misslist, backupmiss)
2050 break
2175 break
2051 else:
2176 else:
2052 if abs not in repo.dirstate:
2177 if abs not in repo.dirstate:
2053 if mfentry:
2178 if mfentry:
2054 handle(add, True)
2179 handle(add, True)
2055 elif exact:
2180 elif exact:
2056 ui.warn(_('file not managed: %s\n') % rel)
2181 ui.warn(_('file not managed: %s\n') % rel)
2057 continue
2182 continue
2058 # file has not changed in dirstate
2183 # file has not changed in dirstate
2059 if node == parent:
2184 if node == parent:
2060 if exact:
2185 if exact:
2061 ui.warn(_('no changes needed to %s\n') % rel)
2186 ui.warn(_('no changes needed to %s\n') % rel)
2062 continue
2187 continue
2063 if pmf is None:
2188 if pmf is None:
2064 # only need parent manifest in this unlikely case,
2189 # only need parent manifest in this unlikely case,
2065 # so do not read by default
2190 # so do not read by default
2066 pmf = repo[parent].manifest()
2191 pmf = repo[parent].manifest()
2067 if abs in pmf and mfentry:
2192 if abs in pmf and mfentry:
2068 # if version of file is same in parent and target
2193 # if version of file is same in parent and target
2069 # manifests, do nothing
2194 # manifests, do nothing
2070 if (pmf[abs] != mfentry or
2195 if (pmf[abs] != mfentry or
2071 pmf.flags(abs) != mf.flags(abs)):
2196 pmf.flags(abs) != mf.flags(abs)):
2072 handle(revert, False)
2197 handle(revert, False)
2073 else:
2198 else:
2074 handle(remove, False)
2199 handle(remove, False)
2075
2200
2076 if not opts.get('dry_run'):
2201 if not opts.get('dry_run'):
2077 def checkout(f):
2202 def checkout(f):
2078 fc = ctx[f]
2203 fc = ctx[f]
2079 repo.wwrite(f, fc.data(), fc.flags())
2204 repo.wwrite(f, fc.data(), fc.flags())
2080
2205
2081 audit_path = pathutil.pathauditor(repo.root)
2206 audit_path = pathutil.pathauditor(repo.root)
2082 for f in remove[0]:
2207 for f in remove[0]:
2083 if repo.dirstate[f] == 'a':
2208 if repo.dirstate[f] == 'a':
2084 repo.dirstate.drop(f)
2209 repo.dirstate.drop(f)
2085 continue
2210 continue
2086 audit_path(f)
2211 audit_path(f)
2087 try:
2212 try:
2088 util.unlinkpath(repo.wjoin(f))
2213 util.unlinkpath(repo.wjoin(f))
2089 except OSError:
2214 except OSError:
2090 pass
2215 pass
2091 repo.dirstate.remove(f)
2216 repo.dirstate.remove(f)
2092
2217
2093 normal = None
2218 normal = None
2094 if node == parent:
2219 if node == parent:
2095 # We're reverting to our parent. If possible, we'd like status
2220 # We're reverting to our parent. If possible, we'd like status
2096 # to report the file as clean. We have to use normallookup for
2221 # to report the file as clean. We have to use normallookup for
2097 # merges to avoid losing information about merged/dirty files.
2222 # merges to avoid losing information about merged/dirty files.
2098 if p2 != nullid:
2223 if p2 != nullid:
2099 normal = repo.dirstate.normallookup
2224 normal = repo.dirstate.normallookup
2100 else:
2225 else:
2101 normal = repo.dirstate.normal
2226 normal = repo.dirstate.normal
2102 for f in revert[0]:
2227 for f in revert[0]:
2103 checkout(f)
2228 checkout(f)
2104 if normal:
2229 if normal:
2105 normal(f)
2230 normal(f)
2106
2231
2107 for f in add[0]:
2232 for f in add[0]:
2108 checkout(f)
2233 checkout(f)
2109 repo.dirstate.add(f)
2234 repo.dirstate.add(f)
2110
2235
2111 normal = repo.dirstate.normallookup
2236 normal = repo.dirstate.normallookup
2112 if node == parent and p2 == nullid:
2237 if node == parent and p2 == nullid:
2113 normal = repo.dirstate.normal
2238 normal = repo.dirstate.normal
2114 for f in undelete[0]:
2239 for f in undelete[0]:
2115 checkout(f)
2240 checkout(f)
2116 normal(f)
2241 normal(f)
2117
2242
2118 copied = copies.pathcopies(repo[parent], ctx)
2243 copied = copies.pathcopies(repo[parent], ctx)
2119
2244
2120 for f in add[0] + undelete[0] + revert[0]:
2245 for f in add[0] + undelete[0] + revert[0]:
2121 if f in copied:
2246 if f in copied:
2122 repo.dirstate.copy(copied[f], f)
2247 repo.dirstate.copy(copied[f], f)
2123
2248
2124 if targetsubs:
2249 if targetsubs:
2125 # Revert the subrepos on the revert list
2250 # Revert the subrepos on the revert list
2126 for sub in targetsubs:
2251 for sub in targetsubs:
2127 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
2252 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
2128 finally:
2253 finally:
2129 wlock.release()
2254 wlock.release()
2130
2255
2131 def command(table):
2256 def command(table):
2132 '''returns a function object bound to table which can be used as
2257 '''returns a function object bound to table which can be used as
2133 a decorator for populating table as a command table'''
2258 a decorator for populating table as a command table'''
2134
2259
2135 def cmd(name, options=(), synopsis=None):
2260 def cmd(name, options=(), synopsis=None):
2136 def decorator(func):
2261 def decorator(func):
2137 if synopsis:
2262 if synopsis:
2138 table[name] = func, list(options), synopsis
2263 table[name] = func, list(options), synopsis
2139 else:
2264 else:
2140 table[name] = func, list(options)
2265 table[name] = func, list(options)
2141 return func
2266 return func
2142 return decorator
2267 return decorator
2143
2268
2144 return cmd
2269 return cmd
2145
2270
2146 # a list of (ui, repo) functions called by commands.summary
2271 # a list of (ui, repo) functions called by commands.summary
2147 summaryhooks = util.hooks()
2272 summaryhooks = util.hooks()
2148
2273
2149 # A list of state files kept by multistep operations like graft.
2274 # A list of state files kept by multistep operations like graft.
2150 # Since graft cannot be aborted, it is considered 'clearable' by update.
2275 # Since graft cannot be aborted, it is considered 'clearable' by update.
2151 # note: bisect is intentionally excluded
2276 # note: bisect is intentionally excluded
2152 # (state file, clearable, allowcommit, error, hint)
2277 # (state file, clearable, allowcommit, error, hint)
2153 unfinishedstates = [
2278 unfinishedstates = [
2154 ('graftstate', True, False, _('graft in progress'),
2279 ('graftstate', True, False, _('graft in progress'),
2155 _("use 'hg graft --continue' or 'hg update' to abort")),
2280 _("use 'hg graft --continue' or 'hg update' to abort")),
2156 ('updatestate', True, False, _('last update was interrupted'),
2281 ('updatestate', True, False, _('last update was interrupted'),
2157 _("use 'hg update' to get a consistent checkout"))
2282 _("use 'hg update' to get a consistent checkout"))
2158 ]
2283 ]
2159
2284
2160 def checkunfinished(repo, commit=False):
2285 def checkunfinished(repo, commit=False):
2161 '''Look for an unfinished multistep operation, like graft, and abort
2286 '''Look for an unfinished multistep operation, like graft, and abort
2162 if found. It's probably good to check this right before
2287 if found. It's probably good to check this right before
2163 bailifchanged().
2288 bailifchanged().
2164 '''
2289 '''
2165 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2290 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2166 if commit and allowcommit:
2291 if commit and allowcommit:
2167 continue
2292 continue
2168 if repo.vfs.exists(f):
2293 if repo.vfs.exists(f):
2169 raise util.Abort(msg, hint=hint)
2294 raise util.Abort(msg, hint=hint)
2170
2295
2171 def clearunfinished(repo):
2296 def clearunfinished(repo):
2172 '''Check for unfinished operations (as above), and clear the ones
2297 '''Check for unfinished operations (as above), and clear the ones
2173 that are clearable.
2298 that are clearable.
2174 '''
2299 '''
2175 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2300 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2176 if not clearable and repo.vfs.exists(f):
2301 if not clearable and repo.vfs.exists(f):
2177 raise util.Abort(msg, hint=hint)
2302 raise util.Abort(msg, hint=hint)
2178 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2303 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2179 if clearable and repo.vfs.exists(f):
2304 if clearable and repo.vfs.exists(f):
2180 util.unlink(repo.join(f))
2305 util.unlink(repo.join(f))
@@ -1,5943 +1,5837
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 cmdutil.showmarker(ui, m)
2230 cmdutil.showmarker(ui, m)
2231
2231
2232 @command('debugpathcomplete',
2232 @command('debugpathcomplete',
2233 [('f', 'full', None, _('complete an entire path')),
2233 [('f', 'full', None, _('complete an entire path')),
2234 ('n', 'normal', None, _('show only normal files')),
2234 ('n', 'normal', None, _('show only normal files')),
2235 ('a', 'added', None, _('show only added files')),
2235 ('a', 'added', None, _('show only added files')),
2236 ('r', 'removed', None, _('show only removed files'))],
2236 ('r', 'removed', None, _('show only removed files'))],
2237 _('FILESPEC...'))
2237 _('FILESPEC...'))
2238 def debugpathcomplete(ui, repo, *specs, **opts):
2238 def debugpathcomplete(ui, repo, *specs, **opts):
2239 '''complete part or all of a tracked path
2239 '''complete part or all of a tracked path
2240
2240
2241 This command supports shells that offer path name completion. It
2241 This command supports shells that offer path name completion. It
2242 currently completes only files already known to the dirstate.
2242 currently completes only files already known to the dirstate.
2243
2243
2244 Completion extends only to the next path segment unless
2244 Completion extends only to the next path segment unless
2245 --full is specified, in which case entire paths are used.'''
2245 --full is specified, in which case entire paths are used.'''
2246
2246
2247 def complete(path, acceptable):
2247 def complete(path, acceptable):
2248 dirstate = repo.dirstate
2248 dirstate = repo.dirstate
2249 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2249 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2250 rootdir = repo.root + os.sep
2250 rootdir = repo.root + os.sep
2251 if spec != repo.root and not spec.startswith(rootdir):
2251 if spec != repo.root and not spec.startswith(rootdir):
2252 return [], []
2252 return [], []
2253 if os.path.isdir(spec):
2253 if os.path.isdir(spec):
2254 spec += '/'
2254 spec += '/'
2255 spec = spec[len(rootdir):]
2255 spec = spec[len(rootdir):]
2256 fixpaths = os.sep != '/'
2256 fixpaths = os.sep != '/'
2257 if fixpaths:
2257 if fixpaths:
2258 spec = spec.replace(os.sep, '/')
2258 spec = spec.replace(os.sep, '/')
2259 speclen = len(spec)
2259 speclen = len(spec)
2260 fullpaths = opts['full']
2260 fullpaths = opts['full']
2261 files, dirs = set(), set()
2261 files, dirs = set(), set()
2262 adddir, addfile = dirs.add, files.add
2262 adddir, addfile = dirs.add, files.add
2263 for f, st in dirstate.iteritems():
2263 for f, st in dirstate.iteritems():
2264 if f.startswith(spec) and st[0] in acceptable:
2264 if f.startswith(spec) and st[0] in acceptable:
2265 if fixpaths:
2265 if fixpaths:
2266 f = f.replace('/', os.sep)
2266 f = f.replace('/', os.sep)
2267 if fullpaths:
2267 if fullpaths:
2268 addfile(f)
2268 addfile(f)
2269 continue
2269 continue
2270 s = f.find(os.sep, speclen)
2270 s = f.find(os.sep, speclen)
2271 if s >= 0:
2271 if s >= 0:
2272 adddir(f[:s])
2272 adddir(f[:s])
2273 else:
2273 else:
2274 addfile(f)
2274 addfile(f)
2275 return files, dirs
2275 return files, dirs
2276
2276
2277 acceptable = ''
2277 acceptable = ''
2278 if opts['normal']:
2278 if opts['normal']:
2279 acceptable += 'nm'
2279 acceptable += 'nm'
2280 if opts['added']:
2280 if opts['added']:
2281 acceptable += 'a'
2281 acceptable += 'a'
2282 if opts['removed']:
2282 if opts['removed']:
2283 acceptable += 'r'
2283 acceptable += 'r'
2284 cwd = repo.getcwd()
2284 cwd = repo.getcwd()
2285 if not specs:
2285 if not specs:
2286 specs = ['.']
2286 specs = ['.']
2287
2287
2288 files, dirs = set(), set()
2288 files, dirs = set(), set()
2289 for spec in specs:
2289 for spec in specs:
2290 f, d = complete(spec, acceptable or 'nmar')
2290 f, d = complete(spec, acceptable or 'nmar')
2291 files.update(f)
2291 files.update(f)
2292 dirs.update(d)
2292 dirs.update(d)
2293 files.update(dirs)
2293 files.update(dirs)
2294 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)))
2295 ui.write('\n')
2295 ui.write('\n')
2296
2296
2297 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2297 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2298 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2298 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2299 '''access the pushkey key/value protocol
2299 '''access the pushkey key/value protocol
2300
2300
2301 With two args, list the keys in the given namespace.
2301 With two args, list the keys in the given namespace.
2302
2302
2303 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.
2304 Reports success or failure.
2304 Reports success or failure.
2305 '''
2305 '''
2306
2306
2307 target = hg.peer(ui, {}, repopath)
2307 target = hg.peer(ui, {}, repopath)
2308 if keyinfo:
2308 if keyinfo:
2309 key, old, new = keyinfo
2309 key, old, new = keyinfo
2310 r = target.pushkey(namespace, key, old, new)
2310 r = target.pushkey(namespace, key, old, new)
2311 ui.status(str(r) + '\n')
2311 ui.status(str(r) + '\n')
2312 return not r
2312 return not r
2313 else:
2313 else:
2314 for k, v in sorted(target.listkeys(namespace).iteritems()):
2314 for k, v in sorted(target.listkeys(namespace).iteritems()):
2315 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2315 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2316 v.encode('string-escape')))
2316 v.encode('string-escape')))
2317
2317
2318 @command('debugpvec', [], _('A B'))
2318 @command('debugpvec', [], _('A B'))
2319 def debugpvec(ui, repo, a, b=None):
2319 def debugpvec(ui, repo, a, b=None):
2320 ca = scmutil.revsingle(repo, a)
2320 ca = scmutil.revsingle(repo, a)
2321 cb = scmutil.revsingle(repo, b)
2321 cb = scmutil.revsingle(repo, b)
2322 pa = pvec.ctxpvec(ca)
2322 pa = pvec.ctxpvec(ca)
2323 pb = pvec.ctxpvec(cb)
2323 pb = pvec.ctxpvec(cb)
2324 if pa == pb:
2324 if pa == pb:
2325 rel = "="
2325 rel = "="
2326 elif pa > pb:
2326 elif pa > pb:
2327 rel = ">"
2327 rel = ">"
2328 elif pa < pb:
2328 elif pa < pb:
2329 rel = "<"
2329 rel = "<"
2330 elif pa | pb:
2330 elif pa | pb:
2331 rel = "|"
2331 rel = "|"
2332 ui.write(_("a: %s\n") % pa)
2332 ui.write(_("a: %s\n") % pa)
2333 ui.write(_("b: %s\n") % pb)
2333 ui.write(_("b: %s\n") % pb)
2334 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))
2335 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2335 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2336 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2336 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2337 pa.distance(pb), rel))
2337 pa.distance(pb), rel))
2338
2338
2339 @command('debugrebuilddirstate|debugrebuildstate',
2339 @command('debugrebuilddirstate|debugrebuildstate',
2340 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2340 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2341 _('[-r REV]'))
2341 _('[-r REV]'))
2342 def debugrebuilddirstate(ui, repo, rev):
2342 def debugrebuilddirstate(ui, repo, rev):
2343 """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
2344
2344
2345 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.
2346
2346
2347 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.
2348 The actual working directory content or existing dirstate
2348 The actual working directory content or existing dirstate
2349 information such as adds or removes is not considered.
2349 information such as adds or removes is not considered.
2350
2350
2351 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
2352 check the actual file content.
2352 check the actual file content.
2353 """
2353 """
2354 ctx = scmutil.revsingle(repo, rev)
2354 ctx = scmutil.revsingle(repo, rev)
2355 wlock = repo.wlock()
2355 wlock = repo.wlock()
2356 try:
2356 try:
2357 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2357 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2358 finally:
2358 finally:
2359 wlock.release()
2359 wlock.release()
2360
2360
2361 @command('debugrename',
2361 @command('debugrename',
2362 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2362 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2363 _('[-r REV] FILE'))
2363 _('[-r REV] FILE'))
2364 def debugrename(ui, repo, file1, *pats, **opts):
2364 def debugrename(ui, repo, file1, *pats, **opts):
2365 """dump rename information"""
2365 """dump rename information"""
2366
2366
2367 ctx = scmutil.revsingle(repo, opts.get('rev'))
2367 ctx = scmutil.revsingle(repo, opts.get('rev'))
2368 m = scmutil.match(ctx, (file1,) + pats, opts)
2368 m = scmutil.match(ctx, (file1,) + pats, opts)
2369 for abs in ctx.walk(m):
2369 for abs in ctx.walk(m):
2370 fctx = ctx[abs]
2370 fctx = ctx[abs]
2371 o = fctx.filelog().renamed(fctx.filenode())
2371 o = fctx.filelog().renamed(fctx.filenode())
2372 rel = m.rel(abs)
2372 rel = m.rel(abs)
2373 if o:
2373 if o:
2374 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])))
2375 else:
2375 else:
2376 ui.write(_("%s not renamed\n") % rel)
2376 ui.write(_("%s not renamed\n") % rel)
2377
2377
2378 @command('debugrevlog',
2378 @command('debugrevlog',
2379 [('c', 'changelog', False, _('open changelog')),
2379 [('c', 'changelog', False, _('open changelog')),
2380 ('m', 'manifest', False, _('open manifest')),
2380 ('m', 'manifest', False, _('open manifest')),
2381 ('d', 'dump', False, _('dump index data'))],
2381 ('d', 'dump', False, _('dump index data'))],
2382 _('-c|-m|FILE'))
2382 _('-c|-m|FILE'))
2383 def debugrevlog(ui, repo, file_=None, **opts):
2383 def debugrevlog(ui, repo, file_=None, **opts):
2384 """show data and statistics about a revlog"""
2384 """show data and statistics about a revlog"""
2385 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2385 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2386
2386
2387 if opts.get("dump"):
2387 if opts.get("dump"):
2388 numrevs = len(r)
2388 numrevs = len(r)
2389 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2389 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2390 " rawsize totalsize compression heads\n")
2390 " rawsize totalsize compression heads\n")
2391 ts = 0
2391 ts = 0
2392 heads = set()
2392 heads = set()
2393 for rev in xrange(numrevs):
2393 for rev in xrange(numrevs):
2394 dbase = r.deltaparent(rev)
2394 dbase = r.deltaparent(rev)
2395 if dbase == -1:
2395 if dbase == -1:
2396 dbase = rev
2396 dbase = rev
2397 cbase = r.chainbase(rev)
2397 cbase = r.chainbase(rev)
2398 p1, p2 = r.parentrevs(rev)
2398 p1, p2 = r.parentrevs(rev)
2399 rs = r.rawsize(rev)
2399 rs = r.rawsize(rev)
2400 ts = ts + rs
2400 ts = ts + rs
2401 heads -= set(r.parentrevs(rev))
2401 heads -= set(r.parentrevs(rev))
2402 heads.add(rev)
2402 heads.add(rev)
2403 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" %
2404 (rev, p1, p2, r.start(rev), r.end(rev),
2404 (rev, p1, p2, r.start(rev), r.end(rev),
2405 r.start(dbase), r.start(cbase),
2405 r.start(dbase), r.start(cbase),
2406 r.start(p1), r.start(p2),
2406 r.start(p1), r.start(p2),
2407 rs, ts, ts / r.end(rev), len(heads)))
2407 rs, ts, ts / r.end(rev), len(heads)))
2408 return 0
2408 return 0
2409
2409
2410 v = r.version
2410 v = r.version
2411 format = v & 0xFFFF
2411 format = v & 0xFFFF
2412 flags = []
2412 flags = []
2413 gdelta = False
2413 gdelta = False
2414 if v & revlog.REVLOGNGINLINEDATA:
2414 if v & revlog.REVLOGNGINLINEDATA:
2415 flags.append('inline')
2415 flags.append('inline')
2416 if v & revlog.REVLOGGENERALDELTA:
2416 if v & revlog.REVLOGGENERALDELTA:
2417 gdelta = True
2417 gdelta = True
2418 flags.append('generaldelta')
2418 flags.append('generaldelta')
2419 if not flags:
2419 if not flags:
2420 flags = ['(none)']
2420 flags = ['(none)']
2421
2421
2422 nummerges = 0
2422 nummerges = 0
2423 numfull = 0
2423 numfull = 0
2424 numprev = 0
2424 numprev = 0
2425 nump1 = 0
2425 nump1 = 0
2426 nump2 = 0
2426 nump2 = 0
2427 numother = 0
2427 numother = 0
2428 nump1prev = 0
2428 nump1prev = 0
2429 nump2prev = 0
2429 nump2prev = 0
2430 chainlengths = []
2430 chainlengths = []
2431
2431
2432 datasize = [None, 0, 0L]
2432 datasize = [None, 0, 0L]
2433 fullsize = [None, 0, 0L]
2433 fullsize = [None, 0, 0L]
2434 deltasize = [None, 0, 0L]
2434 deltasize = [None, 0, 0L]
2435
2435
2436 def addsize(size, l):
2436 def addsize(size, l):
2437 if l[0] is None or size < l[0]:
2437 if l[0] is None or size < l[0]:
2438 l[0] = size
2438 l[0] = size
2439 if size > l[1]:
2439 if size > l[1]:
2440 l[1] = size
2440 l[1] = size
2441 l[2] += size
2441 l[2] += size
2442
2442
2443 numrevs = len(r)
2443 numrevs = len(r)
2444 for rev in xrange(numrevs):
2444 for rev in xrange(numrevs):
2445 p1, p2 = r.parentrevs(rev)
2445 p1, p2 = r.parentrevs(rev)
2446 delta = r.deltaparent(rev)
2446 delta = r.deltaparent(rev)
2447 if format > 0:
2447 if format > 0:
2448 addsize(r.rawsize(rev), datasize)
2448 addsize(r.rawsize(rev), datasize)
2449 if p2 != nullrev:
2449 if p2 != nullrev:
2450 nummerges += 1
2450 nummerges += 1
2451 size = r.length(rev)
2451 size = r.length(rev)
2452 if delta == nullrev:
2452 if delta == nullrev:
2453 chainlengths.append(0)
2453 chainlengths.append(0)
2454 numfull += 1
2454 numfull += 1
2455 addsize(size, fullsize)
2455 addsize(size, fullsize)
2456 else:
2456 else:
2457 chainlengths.append(chainlengths[delta] + 1)
2457 chainlengths.append(chainlengths[delta] + 1)
2458 addsize(size, deltasize)
2458 addsize(size, deltasize)
2459 if delta == rev - 1:
2459 if delta == rev - 1:
2460 numprev += 1
2460 numprev += 1
2461 if delta == p1:
2461 if delta == p1:
2462 nump1prev += 1
2462 nump1prev += 1
2463 elif delta == p2:
2463 elif delta == p2:
2464 nump2prev += 1
2464 nump2prev += 1
2465 elif delta == p1:
2465 elif delta == p1:
2466 nump1 += 1
2466 nump1 += 1
2467 elif delta == p2:
2467 elif delta == p2:
2468 nump2 += 1
2468 nump2 += 1
2469 elif delta != nullrev:
2469 elif delta != nullrev:
2470 numother += 1
2470 numother += 1
2471
2471
2472 # Adjust size min value for empty cases
2472 # Adjust size min value for empty cases
2473 for size in (datasize, fullsize, deltasize):
2473 for size in (datasize, fullsize, deltasize):
2474 if size[0] is None:
2474 if size[0] is None:
2475 size[0] = 0
2475 size[0] = 0
2476
2476
2477 numdeltas = numrevs - numfull
2477 numdeltas = numrevs - numfull
2478 numoprev = numprev - nump1prev - nump2prev
2478 numoprev = numprev - nump1prev - nump2prev
2479 totalrawsize = datasize[2]
2479 totalrawsize = datasize[2]
2480 datasize[2] /= numrevs
2480 datasize[2] /= numrevs
2481 fulltotal = fullsize[2]
2481 fulltotal = fullsize[2]
2482 fullsize[2] /= numfull
2482 fullsize[2] /= numfull
2483 deltatotal = deltasize[2]
2483 deltatotal = deltasize[2]
2484 if numrevs - numfull > 0:
2484 if numrevs - numfull > 0:
2485 deltasize[2] /= numrevs - numfull
2485 deltasize[2] /= numrevs - numfull
2486 totalsize = fulltotal + deltatotal
2486 totalsize = fulltotal + deltatotal
2487 avgchainlen = sum(chainlengths) / numrevs
2487 avgchainlen = sum(chainlengths) / numrevs
2488 compratio = totalrawsize / totalsize
2488 compratio = totalrawsize / totalsize
2489
2489
2490 basedfmtstr = '%%%dd\n'
2490 basedfmtstr = '%%%dd\n'
2491 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2491 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2492
2492
2493 def dfmtstr(max):
2493 def dfmtstr(max):
2494 return basedfmtstr % len(str(max))
2494 return basedfmtstr % len(str(max))
2495 def pcfmtstr(max, padding=0):
2495 def pcfmtstr(max, padding=0):
2496 return basepcfmtstr % (len(str(max)), ' ' * padding)
2496 return basepcfmtstr % (len(str(max)), ' ' * padding)
2497
2497
2498 def pcfmt(value, total):
2498 def pcfmt(value, total):
2499 return (value, 100 * float(value) / total)
2499 return (value, 100 * float(value) / total)
2500
2500
2501 ui.write(('format : %d\n') % format)
2501 ui.write(('format : %d\n') % format)
2502 ui.write(('flags : %s\n') % ', '.join(flags))
2502 ui.write(('flags : %s\n') % ', '.join(flags))
2503
2503
2504 ui.write('\n')
2504 ui.write('\n')
2505 fmt = pcfmtstr(totalsize)
2505 fmt = pcfmtstr(totalsize)
2506 fmt2 = dfmtstr(totalsize)
2506 fmt2 = dfmtstr(totalsize)
2507 ui.write(('revisions : ') + fmt2 % numrevs)
2507 ui.write(('revisions : ') + fmt2 % numrevs)
2508 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2508 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2509 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2509 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2510 ui.write(('revisions : ') + fmt2 % numrevs)
2510 ui.write(('revisions : ') + fmt2 % numrevs)
2511 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2511 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2512 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2512 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2513 ui.write(('revision size : ') + fmt2 % totalsize)
2513 ui.write(('revision size : ') + fmt2 % totalsize)
2514 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2514 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2515 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2515 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2516
2516
2517 ui.write('\n')
2517 ui.write('\n')
2518 fmt = dfmtstr(max(avgchainlen, compratio))
2518 fmt = dfmtstr(max(avgchainlen, compratio))
2519 ui.write(('avg chain length : ') + fmt % avgchainlen)
2519 ui.write(('avg chain length : ') + fmt % avgchainlen)
2520 ui.write(('compression ratio : ') + fmt % compratio)
2520 ui.write(('compression ratio : ') + fmt % compratio)
2521
2521
2522 if format > 0:
2522 if format > 0:
2523 ui.write('\n')
2523 ui.write('\n')
2524 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')
2525 % tuple(datasize))
2525 % tuple(datasize))
2526 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')
2527 % tuple(fullsize))
2527 % tuple(fullsize))
2528 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2528 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2529 % tuple(deltasize))
2529 % tuple(deltasize))
2530
2530
2531 if numdeltas > 0:
2531 if numdeltas > 0:
2532 ui.write('\n')
2532 ui.write('\n')
2533 fmt = pcfmtstr(numdeltas)
2533 fmt = pcfmtstr(numdeltas)
2534 fmt2 = pcfmtstr(numdeltas, 4)
2534 fmt2 = pcfmtstr(numdeltas, 4)
2535 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2535 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2536 if numprev > 0:
2536 if numprev > 0:
2537 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2537 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2538 numprev))
2538 numprev))
2539 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2539 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2540 numprev))
2540 numprev))
2541 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2541 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2542 numprev))
2542 numprev))
2543 if gdelta:
2543 if gdelta:
2544 ui.write(('deltas against p1 : ')
2544 ui.write(('deltas against p1 : ')
2545 + fmt % pcfmt(nump1, numdeltas))
2545 + fmt % pcfmt(nump1, numdeltas))
2546 ui.write(('deltas against p2 : ')
2546 ui.write(('deltas against p2 : ')
2547 + fmt % pcfmt(nump2, numdeltas))
2547 + fmt % pcfmt(nump2, numdeltas))
2548 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2548 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2549 numdeltas))
2549 numdeltas))
2550
2550
2551 @command('debugrevspec',
2551 @command('debugrevspec',
2552 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2552 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2553 ('REVSPEC'))
2553 ('REVSPEC'))
2554 def debugrevspec(ui, repo, expr, **opts):
2554 def debugrevspec(ui, repo, expr, **opts):
2555 """parse and apply a revision specification
2555 """parse and apply a revision specification
2556
2556
2557 Use --verbose to print the parsed tree before and after aliases
2557 Use --verbose to print the parsed tree before and after aliases
2558 expansion.
2558 expansion.
2559 """
2559 """
2560 if ui.verbose:
2560 if ui.verbose:
2561 tree = revset.parse(expr)[0]
2561 tree = revset.parse(expr)[0]
2562 ui.note(revset.prettyformat(tree), "\n")
2562 ui.note(revset.prettyformat(tree), "\n")
2563 newtree = revset.findaliases(ui, tree)
2563 newtree = revset.findaliases(ui, tree)
2564 if newtree != tree:
2564 if newtree != tree:
2565 ui.note(revset.prettyformat(newtree), "\n")
2565 ui.note(revset.prettyformat(newtree), "\n")
2566 if opts["optimize"]:
2566 if opts["optimize"]:
2567 weight, optimizedtree = revset.optimize(newtree, True)
2567 weight, optimizedtree = revset.optimize(newtree, True)
2568 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2568 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2569 func = revset.match(ui, expr)
2569 func = revset.match(ui, expr)
2570 for c in func(repo, revset.baseset(range(len(repo)))):
2570 for c in func(repo, revset.baseset(range(len(repo)))):
2571 ui.write("%s\n" % c)
2571 ui.write("%s\n" % c)
2572
2572
2573 @command('debugsetparents', [], _('REV1 [REV2]'))
2573 @command('debugsetparents', [], _('REV1 [REV2]'))
2574 def debugsetparents(ui, repo, rev1, rev2=None):
2574 def debugsetparents(ui, repo, rev1, rev2=None):
2575 """manually set the parents of the current working directory
2575 """manually set the parents of the current working directory
2576
2576
2577 This is useful for writing repository conversion tools, but should
2577 This is useful for writing repository conversion tools, but should
2578 be used with care.
2578 be used with care.
2579
2579
2580 Returns 0 on success.
2580 Returns 0 on success.
2581 """
2581 """
2582
2582
2583 r1 = scmutil.revsingle(repo, rev1).node()
2583 r1 = scmutil.revsingle(repo, rev1).node()
2584 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2584 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2585
2585
2586 wlock = repo.wlock()
2586 wlock = repo.wlock()
2587 try:
2587 try:
2588 repo.setparents(r1, r2)
2588 repo.setparents(r1, r2)
2589 finally:
2589 finally:
2590 wlock.release()
2590 wlock.release()
2591
2591
2592 @command('debugdirstate|debugstate',
2592 @command('debugdirstate|debugstate',
2593 [('', 'nodates', None, _('do not display the saved mtime')),
2593 [('', 'nodates', None, _('do not display the saved mtime')),
2594 ('', 'datesort', None, _('sort by saved mtime'))],
2594 ('', 'datesort', None, _('sort by saved mtime'))],
2595 _('[OPTION]...'))
2595 _('[OPTION]...'))
2596 def debugstate(ui, repo, nodates=None, datesort=None):
2596 def debugstate(ui, repo, nodates=None, datesort=None):
2597 """show the contents of the current dirstate"""
2597 """show the contents of the current dirstate"""
2598 timestr = ""
2598 timestr = ""
2599 showdate = not nodates
2599 showdate = not nodates
2600 if datesort:
2600 if datesort:
2601 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2601 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2602 else:
2602 else:
2603 keyfunc = None # sort by filename
2603 keyfunc = None # sort by filename
2604 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2604 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2605 if showdate:
2605 if showdate:
2606 if ent[3] == -1:
2606 if ent[3] == -1:
2607 # Pad or slice to locale representation
2607 # Pad or slice to locale representation
2608 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2608 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2609 time.localtime(0)))
2609 time.localtime(0)))
2610 timestr = 'unset'
2610 timestr = 'unset'
2611 timestr = (timestr[:locale_len] +
2611 timestr = (timestr[:locale_len] +
2612 ' ' * (locale_len - len(timestr)))
2612 ' ' * (locale_len - len(timestr)))
2613 else:
2613 else:
2614 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2614 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2615 time.localtime(ent[3]))
2615 time.localtime(ent[3]))
2616 if ent[1] & 020000:
2616 if ent[1] & 020000:
2617 mode = 'lnk'
2617 mode = 'lnk'
2618 else:
2618 else:
2619 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2619 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2620 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2620 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2621 for f in repo.dirstate.copies():
2621 for f in repo.dirstate.copies():
2622 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2622 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2623
2623
2624 @command('debugsub',
2624 @command('debugsub',
2625 [('r', 'rev', '',
2625 [('r', 'rev', '',
2626 _('revision to check'), _('REV'))],
2626 _('revision to check'), _('REV'))],
2627 _('[-r REV] [REV]'))
2627 _('[-r REV] [REV]'))
2628 def debugsub(ui, repo, rev=None):
2628 def debugsub(ui, repo, rev=None):
2629 ctx = scmutil.revsingle(repo, rev, None)
2629 ctx = scmutil.revsingle(repo, rev, None)
2630 for k, v in sorted(ctx.substate.items()):
2630 for k, v in sorted(ctx.substate.items()):
2631 ui.write(('path %s\n') % k)
2631 ui.write(('path %s\n') % k)
2632 ui.write((' source %s\n') % v[0])
2632 ui.write((' source %s\n') % v[0])
2633 ui.write((' revision %s\n') % v[1])
2633 ui.write((' revision %s\n') % v[1])
2634
2634
2635 @command('debugsuccessorssets',
2635 @command('debugsuccessorssets',
2636 [],
2636 [],
2637 _('[REV]'))
2637 _('[REV]'))
2638 def debugsuccessorssets(ui, repo, *revs):
2638 def debugsuccessorssets(ui, repo, *revs):
2639 """show set of successors for revision
2639 """show set of successors for revision
2640
2640
2641 A successors set of changeset A is a consistent group of revisions that
2641 A successors set of changeset A is a consistent group of revisions that
2642 succeed A. It contains non-obsolete changesets only.
2642 succeed A. It contains non-obsolete changesets only.
2643
2643
2644 In most cases a changeset A has a single successors set containing a single
2644 In most cases a changeset A has a single successors set containing a single
2645 successor (changeset A replaced by A').
2645 successor (changeset A replaced by A').
2646
2646
2647 A changeset that is made obsolete with no successors are called "pruned".
2647 A changeset that is made obsolete with no successors are called "pruned".
2648 Such changesets have no successors sets at all.
2648 Such changesets have no successors sets at all.
2649
2649
2650 A changeset that has been "split" will have a successors set containing
2650 A changeset that has been "split" will have a successors set containing
2651 more than one successor.
2651 more than one successor.
2652
2652
2653 A changeset that has been rewritten in multiple different ways is called
2653 A changeset that has been rewritten in multiple different ways is called
2654 "divergent". Such changesets have multiple successor sets (each of which
2654 "divergent". Such changesets have multiple successor sets (each of which
2655 may also be split, i.e. have multiple successors).
2655 may also be split, i.e. have multiple successors).
2656
2656
2657 Results are displayed as follows::
2657 Results are displayed as follows::
2658
2658
2659 <rev1>
2659 <rev1>
2660 <successors-1A>
2660 <successors-1A>
2661 <rev2>
2661 <rev2>
2662 <successors-2A>
2662 <successors-2A>
2663 <successors-2B1> <successors-2B2> <successors-2B3>
2663 <successors-2B1> <successors-2B2> <successors-2B3>
2664
2664
2665 Here rev2 has two possible (i.e. divergent) successors sets. The first
2665 Here rev2 has two possible (i.e. divergent) successors sets. The first
2666 holds one element, whereas the second holds three (i.e. the changeset has
2666 holds one element, whereas the second holds three (i.e. the changeset has
2667 been split).
2667 been split).
2668 """
2668 """
2669 # passed to successorssets caching computation from one call to another
2669 # passed to successorssets caching computation from one call to another
2670 cache = {}
2670 cache = {}
2671 ctx2str = str
2671 ctx2str = str
2672 node2str = short
2672 node2str = short
2673 if ui.debug():
2673 if ui.debug():
2674 def ctx2str(ctx):
2674 def ctx2str(ctx):
2675 return ctx.hex()
2675 return ctx.hex()
2676 node2str = hex
2676 node2str = hex
2677 for rev in scmutil.revrange(repo, revs):
2677 for rev in scmutil.revrange(repo, revs):
2678 ctx = repo[rev]
2678 ctx = repo[rev]
2679 ui.write('%s\n'% ctx2str(ctx))
2679 ui.write('%s\n'% ctx2str(ctx))
2680 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2680 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2681 if succsset:
2681 if succsset:
2682 ui.write(' ')
2682 ui.write(' ')
2683 ui.write(node2str(succsset[0]))
2683 ui.write(node2str(succsset[0]))
2684 for node in succsset[1:]:
2684 for node in succsset[1:]:
2685 ui.write(' ')
2685 ui.write(' ')
2686 ui.write(node2str(node))
2686 ui.write(node2str(node))
2687 ui.write('\n')
2687 ui.write('\n')
2688
2688
2689 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2689 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2690 def debugwalk(ui, repo, *pats, **opts):
2690 def debugwalk(ui, repo, *pats, **opts):
2691 """show how files match on given patterns"""
2691 """show how files match on given patterns"""
2692 m = scmutil.match(repo[None], pats, opts)
2692 m = scmutil.match(repo[None], pats, opts)
2693 items = list(repo.walk(m))
2693 items = list(repo.walk(m))
2694 if not items:
2694 if not items:
2695 return
2695 return
2696 f = lambda fn: fn
2696 f = lambda fn: fn
2697 if ui.configbool('ui', 'slash') and os.sep != '/':
2697 if ui.configbool('ui', 'slash') and os.sep != '/':
2698 f = lambda fn: util.normpath(fn)
2698 f = lambda fn: util.normpath(fn)
2699 fmt = 'f %%-%ds %%-%ds %%s' % (
2699 fmt = 'f %%-%ds %%-%ds %%s' % (
2700 max([len(abs) for abs in items]),
2700 max([len(abs) for abs in items]),
2701 max([len(m.rel(abs)) for abs in items]))
2701 max([len(m.rel(abs)) for abs in items]))
2702 for abs in items:
2702 for abs in items:
2703 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2703 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2704 ui.write("%s\n" % line.rstrip())
2704 ui.write("%s\n" % line.rstrip())
2705
2705
2706 @command('debugwireargs',
2706 @command('debugwireargs',
2707 [('', 'three', '', 'three'),
2707 [('', 'three', '', 'three'),
2708 ('', 'four', '', 'four'),
2708 ('', 'four', '', 'four'),
2709 ('', 'five', '', 'five'),
2709 ('', 'five', '', 'five'),
2710 ] + remoteopts,
2710 ] + remoteopts,
2711 _('REPO [OPTIONS]... [ONE [TWO]]'))
2711 _('REPO [OPTIONS]... [ONE [TWO]]'))
2712 def debugwireargs(ui, repopath, *vals, **opts):
2712 def debugwireargs(ui, repopath, *vals, **opts):
2713 repo = hg.peer(ui, opts, repopath)
2713 repo = hg.peer(ui, opts, repopath)
2714 for opt in remoteopts:
2714 for opt in remoteopts:
2715 del opts[opt[1]]
2715 del opts[opt[1]]
2716 args = {}
2716 args = {}
2717 for k, v in opts.iteritems():
2717 for k, v in opts.iteritems():
2718 if v:
2718 if v:
2719 args[k] = v
2719 args[k] = v
2720 # run twice to check that we don't mess up the stream for the next command
2720 # run twice to check that we don't mess up the stream for the next command
2721 res1 = repo.debugwireargs(*vals, **args)
2721 res1 = repo.debugwireargs(*vals, **args)
2722 res2 = repo.debugwireargs(*vals, **args)
2722 res2 = repo.debugwireargs(*vals, **args)
2723 ui.write("%s\n" % res1)
2723 ui.write("%s\n" % res1)
2724 if res1 != res2:
2724 if res1 != res2:
2725 ui.warn("%s\n" % res2)
2725 ui.warn("%s\n" % res2)
2726
2726
2727 @command('^diff',
2727 @command('^diff',
2728 [('r', 'rev', [], _('revision'), _('REV')),
2728 [('r', 'rev', [], _('revision'), _('REV')),
2729 ('c', 'change', '', _('change made by revision'), _('REV'))
2729 ('c', 'change', '', _('change made by revision'), _('REV'))
2730 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2730 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2731 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2731 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2732 def diff(ui, repo, *pats, **opts):
2732 def diff(ui, repo, *pats, **opts):
2733 """diff repository (or selected files)
2733 """diff repository (or selected files)
2734
2734
2735 Show differences between revisions for the specified files.
2735 Show differences between revisions for the specified files.
2736
2736
2737 Differences between files are shown using the unified diff format.
2737 Differences between files are shown using the unified diff format.
2738
2738
2739 .. note::
2739 .. note::
2740
2740
2741 diff may generate unexpected results for merges, as it will
2741 diff may generate unexpected results for merges, as it will
2742 default to comparing against the working directory's first
2742 default to comparing against the working directory's first
2743 parent changeset if no revisions are specified.
2743 parent changeset if no revisions are specified.
2744
2744
2745 When two revision arguments are given, then changes are shown
2745 When two revision arguments are given, then changes are shown
2746 between those revisions. If only one revision is specified then
2746 between those revisions. If only one revision is specified then
2747 that revision is compared to the working directory, and, when no
2747 that revision is compared to the working directory, and, when no
2748 revisions are specified, the working directory files are compared
2748 revisions are specified, the working directory files are compared
2749 to its parent.
2749 to its parent.
2750
2750
2751 Alternatively you can specify -c/--change with a revision to see
2751 Alternatively you can specify -c/--change with a revision to see
2752 the changes in that changeset relative to its first parent.
2752 the changes in that changeset relative to its first parent.
2753
2753
2754 Without the -a/--text option, diff will avoid generating diffs of
2754 Without the -a/--text option, diff will avoid generating diffs of
2755 files it detects as binary. With -a, diff will generate a diff
2755 files it detects as binary. With -a, diff will generate a diff
2756 anyway, probably with undesirable results.
2756 anyway, probably with undesirable results.
2757
2757
2758 Use the -g/--git option to generate diffs in the git extended diff
2758 Use the -g/--git option to generate diffs in the git extended diff
2759 format. For more information, read :hg:`help diffs`.
2759 format. For more information, read :hg:`help diffs`.
2760
2760
2761 .. container:: verbose
2761 .. container:: verbose
2762
2762
2763 Examples:
2763 Examples:
2764
2764
2765 - compare a file in the current working directory to its parent::
2765 - compare a file in the current working directory to its parent::
2766
2766
2767 hg diff foo.c
2767 hg diff foo.c
2768
2768
2769 - compare two historical versions of a directory, with rename info::
2769 - compare two historical versions of a directory, with rename info::
2770
2770
2771 hg diff --git -r 1.0:1.2 lib/
2771 hg diff --git -r 1.0:1.2 lib/
2772
2772
2773 - get change stats relative to the last change on some date::
2773 - get change stats relative to the last change on some date::
2774
2774
2775 hg diff --stat -r "date('may 2')"
2775 hg diff --stat -r "date('may 2')"
2776
2776
2777 - diff all newly-added files that contain a keyword::
2777 - diff all newly-added files that contain a keyword::
2778
2778
2779 hg diff "set:added() and grep(GNU)"
2779 hg diff "set:added() and grep(GNU)"
2780
2780
2781 - compare a revision and its parents::
2781 - compare a revision and its parents::
2782
2782
2783 hg diff -c 9353 # compare against first parent
2783 hg diff -c 9353 # compare against first parent
2784 hg diff -r 9353^:9353 # same using revset syntax
2784 hg diff -r 9353^:9353 # same using revset syntax
2785 hg diff -r 9353^2:9353 # compare against the second parent
2785 hg diff -r 9353^2:9353 # compare against the second parent
2786
2786
2787 Returns 0 on success.
2787 Returns 0 on success.
2788 """
2788 """
2789
2789
2790 revs = opts.get('rev')
2790 revs = opts.get('rev')
2791 change = opts.get('change')
2791 change = opts.get('change')
2792 stat = opts.get('stat')
2792 stat = opts.get('stat')
2793 reverse = opts.get('reverse')
2793 reverse = opts.get('reverse')
2794
2794
2795 if revs and change:
2795 if revs and change:
2796 msg = _('cannot specify --rev and --change at the same time')
2796 msg = _('cannot specify --rev and --change at the same time')
2797 raise util.Abort(msg)
2797 raise util.Abort(msg)
2798 elif change:
2798 elif change:
2799 node2 = scmutil.revsingle(repo, change, None).node()
2799 node2 = scmutil.revsingle(repo, change, None).node()
2800 node1 = repo[node2].p1().node()
2800 node1 = repo[node2].p1().node()
2801 else:
2801 else:
2802 node1, node2 = scmutil.revpair(repo, revs)
2802 node1, node2 = scmutil.revpair(repo, revs)
2803
2803
2804 if reverse:
2804 if reverse:
2805 node1, node2 = node2, node1
2805 node1, node2 = node2, node1
2806
2806
2807 diffopts = patch.diffopts(ui, opts)
2807 diffopts = patch.diffopts(ui, opts)
2808 m = scmutil.match(repo[node2], pats, opts)
2808 m = scmutil.match(repo[node2], pats, opts)
2809 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2809 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2810 listsubrepos=opts.get('subrepos'))
2810 listsubrepos=opts.get('subrepos'))
2811
2811
2812 @command('^export',
2812 @command('^export',
2813 [('o', 'output', '',
2813 [('o', 'output', '',
2814 _('print output to file with formatted name'), _('FORMAT')),
2814 _('print output to file with formatted name'), _('FORMAT')),
2815 ('', 'switch-parent', None, _('diff against the second parent')),
2815 ('', 'switch-parent', None, _('diff against the second parent')),
2816 ('r', 'rev', [], _('revisions to export'), _('REV')),
2816 ('r', 'rev', [], _('revisions to export'), _('REV')),
2817 ] + diffopts,
2817 ] + diffopts,
2818 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2818 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2819 def export(ui, repo, *changesets, **opts):
2819 def export(ui, repo, *changesets, **opts):
2820 """dump the header and diffs for one or more changesets
2820 """dump the header and diffs for one or more changesets
2821
2821
2822 Print the changeset header and diffs for one or more revisions.
2822 Print the changeset header and diffs for one or more revisions.
2823 If no revision is given, the parent of the working directory is used.
2823 If no revision is given, the parent of the working directory is used.
2824
2824
2825 The information shown in the changeset header is: author, date,
2825 The information shown in the changeset header is: author, date,
2826 branch name (if non-default), changeset hash, parent(s) and commit
2826 branch name (if non-default), changeset hash, parent(s) and commit
2827 comment.
2827 comment.
2828
2828
2829 .. note::
2829 .. note::
2830
2830
2831 export may generate unexpected diff output for merge
2831 export may generate unexpected diff output for merge
2832 changesets, as it will compare the merge changeset against its
2832 changesets, as it will compare the merge changeset against its
2833 first parent only.
2833 first parent only.
2834
2834
2835 Output may be to a file, in which case the name of the file is
2835 Output may be to a file, in which case the name of the file is
2836 given using a format string. The formatting rules are as follows:
2836 given using a format string. The formatting rules are as follows:
2837
2837
2838 :``%%``: literal "%" character
2838 :``%%``: literal "%" character
2839 :``%H``: changeset hash (40 hexadecimal digits)
2839 :``%H``: changeset hash (40 hexadecimal digits)
2840 :``%N``: number of patches being generated
2840 :``%N``: number of patches being generated
2841 :``%R``: changeset revision number
2841 :``%R``: changeset revision number
2842 :``%b``: basename of the exporting repository
2842 :``%b``: basename of the exporting repository
2843 :``%h``: short-form changeset hash (12 hexadecimal digits)
2843 :``%h``: short-form changeset hash (12 hexadecimal digits)
2844 :``%m``: first line of the commit message (only alphanumeric characters)
2844 :``%m``: first line of the commit message (only alphanumeric characters)
2845 :``%n``: zero-padded sequence number, starting at 1
2845 :``%n``: zero-padded sequence number, starting at 1
2846 :``%r``: zero-padded changeset revision number
2846 :``%r``: zero-padded changeset revision number
2847
2847
2848 Without the -a/--text option, export will avoid generating diffs
2848 Without the -a/--text option, export will avoid generating diffs
2849 of files it detects as binary. With -a, export will generate a
2849 of files it detects as binary. With -a, export will generate a
2850 diff anyway, probably with undesirable results.
2850 diff anyway, probably with undesirable results.
2851
2851
2852 Use the -g/--git option to generate diffs in the git extended diff
2852 Use the -g/--git option to generate diffs in the git extended diff
2853 format. See :hg:`help diffs` for more information.
2853 format. See :hg:`help diffs` for more information.
2854
2854
2855 With the --switch-parent option, the diff will be against the
2855 With the --switch-parent option, the diff will be against the
2856 second parent. It can be useful to review a merge.
2856 second parent. It can be useful to review a merge.
2857
2857
2858 .. container:: verbose
2858 .. container:: verbose
2859
2859
2860 Examples:
2860 Examples:
2861
2861
2862 - use export and import to transplant a bugfix to the current
2862 - use export and import to transplant a bugfix to the current
2863 branch::
2863 branch::
2864
2864
2865 hg export -r 9353 | hg import -
2865 hg export -r 9353 | hg import -
2866
2866
2867 - export all the changesets between two revisions to a file with
2867 - export all the changesets between two revisions to a file with
2868 rename information::
2868 rename information::
2869
2869
2870 hg export --git -r 123:150 > changes.txt
2870 hg export --git -r 123:150 > changes.txt
2871
2871
2872 - split outgoing changes into a series of patches with
2872 - split outgoing changes into a series of patches with
2873 descriptive names::
2873 descriptive names::
2874
2874
2875 hg export -r "outgoing()" -o "%n-%m.patch"
2875 hg export -r "outgoing()" -o "%n-%m.patch"
2876
2876
2877 Returns 0 on success.
2877 Returns 0 on success.
2878 """
2878 """
2879 changesets += tuple(opts.get('rev', []))
2879 changesets += tuple(opts.get('rev', []))
2880 if not changesets:
2880 if not changesets:
2881 changesets = ['.']
2881 changesets = ['.']
2882 revs = scmutil.revrange(repo, changesets)
2882 revs = scmutil.revrange(repo, changesets)
2883 if not revs:
2883 if not revs:
2884 raise util.Abort(_("export requires at least one changeset"))
2884 raise util.Abort(_("export requires at least one changeset"))
2885 if len(revs) > 1:
2885 if len(revs) > 1:
2886 ui.note(_('exporting patches:\n'))
2886 ui.note(_('exporting patches:\n'))
2887 else:
2887 else:
2888 ui.note(_('exporting patch:\n'))
2888 ui.note(_('exporting patch:\n'))
2889 cmdutil.export(repo, revs, template=opts.get('output'),
2889 cmdutil.export(repo, revs, template=opts.get('output'),
2890 switch_parent=opts.get('switch_parent'),
2890 switch_parent=opts.get('switch_parent'),
2891 opts=patch.diffopts(ui, opts))
2891 opts=patch.diffopts(ui, opts))
2892
2892
2893 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2893 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2894 def forget(ui, repo, *pats, **opts):
2894 def forget(ui, repo, *pats, **opts):
2895 """forget the specified files on the next commit
2895 """forget the specified files on the next commit
2896
2896
2897 Mark the specified files so they will no longer be tracked
2897 Mark the specified files so they will no longer be tracked
2898 after the next commit.
2898 after the next commit.
2899
2899
2900 This only removes files from the current branch, not from the
2900 This only removes files from the current branch, not from the
2901 entire project history, and it does not delete them from the
2901 entire project history, and it does not delete them from the
2902 working directory.
2902 working directory.
2903
2903
2904 To undo a forget before the next commit, see :hg:`add`.
2904 To undo a forget before the next commit, see :hg:`add`.
2905
2905
2906 .. container:: verbose
2906 .. container:: verbose
2907
2907
2908 Examples:
2908 Examples:
2909
2909
2910 - forget newly-added binary files::
2910 - forget newly-added binary files::
2911
2911
2912 hg forget "set:added() and binary()"
2912 hg forget "set:added() and binary()"
2913
2913
2914 - forget files that would be excluded by .hgignore::
2914 - forget files that would be excluded by .hgignore::
2915
2915
2916 hg forget "set:hgignore()"
2916 hg forget "set:hgignore()"
2917
2917
2918 Returns 0 on success.
2918 Returns 0 on success.
2919 """
2919 """
2920
2920
2921 if not pats:
2921 if not pats:
2922 raise util.Abort(_('no files specified'))
2922 raise util.Abort(_('no files specified'))
2923
2923
2924 m = scmutil.match(repo[None], pats, opts)
2924 m = scmutil.match(repo[None], pats, opts)
2925 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2925 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2926 return rejected and 1 or 0
2926 return rejected and 1 or 0
2927
2927
2928 @command(
2928 @command(
2929 'graft',
2929 'graft',
2930 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2930 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2931 ('c', 'continue', False, _('resume interrupted graft')),
2931 ('c', 'continue', False, _('resume interrupted graft')),
2932 ('e', 'edit', False, _('invoke editor on commit messages')),
2932 ('e', 'edit', False, _('invoke editor on commit messages')),
2933 ('', 'log', None, _('append graft info to log message')),
2933 ('', 'log', None, _('append graft info to log message')),
2934 ('D', 'currentdate', False,
2934 ('D', 'currentdate', False,
2935 _('record the current date as commit date')),
2935 _('record the current date as commit date')),
2936 ('U', 'currentuser', False,
2936 ('U', 'currentuser', False,
2937 _('record the current user as committer'), _('DATE'))]
2937 _('record the current user as committer'), _('DATE'))]
2938 + commitopts2 + mergetoolopts + dryrunopts,
2938 + commitopts2 + mergetoolopts + dryrunopts,
2939 _('[OPTION]... [-r] REV...'))
2939 _('[OPTION]... [-r] REV...'))
2940 def graft(ui, repo, *revs, **opts):
2940 def graft(ui, repo, *revs, **opts):
2941 '''copy changes from other branches onto the current branch
2941 '''copy changes from other branches onto the current branch
2942
2942
2943 This command uses Mercurial's merge logic to copy individual
2943 This command uses Mercurial's merge logic to copy individual
2944 changes from other branches without merging branches in the
2944 changes from other branches without merging branches in the
2945 history graph. This is sometimes known as 'backporting' or
2945 history graph. This is sometimes known as 'backporting' or
2946 'cherry-picking'. By default, graft will copy user, date, and
2946 'cherry-picking'. By default, graft will copy user, date, and
2947 description from the source changesets.
2947 description from the source changesets.
2948
2948
2949 Changesets that are ancestors of the current revision, that have
2949 Changesets that are ancestors of the current revision, that have
2950 already been grafted, or that are merges will be skipped.
2950 already been grafted, or that are merges will be skipped.
2951
2951
2952 If --log is specified, log messages will have a comment appended
2952 If --log is specified, log messages will have a comment appended
2953 of the form::
2953 of the form::
2954
2954
2955 (grafted from CHANGESETHASH)
2955 (grafted from CHANGESETHASH)
2956
2956
2957 If a graft merge results in conflicts, the graft process is
2957 If a graft merge results in conflicts, the graft process is
2958 interrupted so that the current merge can be manually resolved.
2958 interrupted so that the current merge can be manually resolved.
2959 Once all conflicts are addressed, the graft process can be
2959 Once all conflicts are addressed, the graft process can be
2960 continued with the -c/--continue option.
2960 continued with the -c/--continue option.
2961
2961
2962 .. note::
2962 .. note::
2963
2963
2964 The -c/--continue option does not reapply earlier options.
2964 The -c/--continue option does not reapply earlier options.
2965
2965
2966 .. container:: verbose
2966 .. container:: verbose
2967
2967
2968 Examples:
2968 Examples:
2969
2969
2970 - copy a single change to the stable branch and edit its description::
2970 - copy a single change to the stable branch and edit its description::
2971
2971
2972 hg update stable
2972 hg update stable
2973 hg graft --edit 9393
2973 hg graft --edit 9393
2974
2974
2975 - graft a range of changesets with one exception, updating dates::
2975 - graft a range of changesets with one exception, updating dates::
2976
2976
2977 hg graft -D "2085::2093 and not 2091"
2977 hg graft -D "2085::2093 and not 2091"
2978
2978
2979 - continue a graft after resolving conflicts::
2979 - continue a graft after resolving conflicts::
2980
2980
2981 hg graft -c
2981 hg graft -c
2982
2982
2983 - show the source of a grafted changeset::
2983 - show the source of a grafted changeset::
2984
2984
2985 hg log --debug -r .
2985 hg log --debug -r .
2986
2986
2987 Returns 0 on successful completion.
2987 Returns 0 on successful completion.
2988 '''
2988 '''
2989
2989
2990 revs = list(revs)
2990 revs = list(revs)
2991 revs.extend(opts['rev'])
2991 revs.extend(opts['rev'])
2992
2992
2993 if not opts.get('user') and opts.get('currentuser'):
2993 if not opts.get('user') and opts.get('currentuser'):
2994 opts['user'] = ui.username()
2994 opts['user'] = ui.username()
2995 if not opts.get('date') and opts.get('currentdate'):
2995 if not opts.get('date') and opts.get('currentdate'):
2996 opts['date'] = "%d %d" % util.makedate()
2996 opts['date'] = "%d %d" % util.makedate()
2997
2997
2998 editor = None
2998 editor = None
2999 if opts.get('edit'):
2999 if opts.get('edit'):
3000 editor = cmdutil.commitforceeditor
3000 editor = cmdutil.commitforceeditor
3001
3001
3002 cont = False
3002 cont = False
3003 if opts['continue']:
3003 if opts['continue']:
3004 cont = True
3004 cont = True
3005 if revs:
3005 if revs:
3006 raise util.Abort(_("can't specify --continue and revisions"))
3006 raise util.Abort(_("can't specify --continue and revisions"))
3007 # read in unfinished revisions
3007 # read in unfinished revisions
3008 try:
3008 try:
3009 nodes = repo.opener.read('graftstate').splitlines()
3009 nodes = repo.opener.read('graftstate').splitlines()
3010 revs = [repo[node].rev() for node in nodes]
3010 revs = [repo[node].rev() for node in nodes]
3011 except IOError, inst:
3011 except IOError, inst:
3012 if inst.errno != errno.ENOENT:
3012 if inst.errno != errno.ENOENT:
3013 raise
3013 raise
3014 raise util.Abort(_("no graft state found, can't continue"))
3014 raise util.Abort(_("no graft state found, can't continue"))
3015 else:
3015 else:
3016 cmdutil.checkunfinished(repo)
3016 cmdutil.checkunfinished(repo)
3017 cmdutil.bailifchanged(repo)
3017 cmdutil.bailifchanged(repo)
3018 if not revs:
3018 if not revs:
3019 raise util.Abort(_('no revisions specified'))
3019 raise util.Abort(_('no revisions specified'))
3020 revs = scmutil.revrange(repo, revs)
3020 revs = scmutil.revrange(repo, revs)
3021
3021
3022 # check for merges
3022 # check for merges
3023 for rev in repo.revs('%ld and merge()', revs):
3023 for rev in repo.revs('%ld and merge()', revs):
3024 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3024 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3025 revs.remove(rev)
3025 revs.remove(rev)
3026 if not revs:
3026 if not revs:
3027 return -1
3027 return -1
3028
3028
3029 # check for ancestors of dest branch
3029 # check for ancestors of dest branch
3030 crev = repo['.'].rev()
3030 crev = repo['.'].rev()
3031 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3031 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3032 # don't mutate while iterating, create a copy
3032 # don't mutate while iterating, create a copy
3033 for rev in list(revs):
3033 for rev in list(revs):
3034 if rev in ancestors:
3034 if rev in ancestors:
3035 ui.warn(_('skipping ancestor revision %s\n') % rev)
3035 ui.warn(_('skipping ancestor revision %s\n') % rev)
3036 revs.remove(rev)
3036 revs.remove(rev)
3037 if not revs:
3037 if not revs:
3038 return -1
3038 return -1
3039
3039
3040 # analyze revs for earlier grafts
3040 # analyze revs for earlier grafts
3041 ids = {}
3041 ids = {}
3042 for ctx in repo.set("%ld", revs):
3042 for ctx in repo.set("%ld", revs):
3043 ids[ctx.hex()] = ctx.rev()
3043 ids[ctx.hex()] = ctx.rev()
3044 n = ctx.extra().get('source')
3044 n = ctx.extra().get('source')
3045 if n:
3045 if n:
3046 ids[n] = ctx.rev()
3046 ids[n] = ctx.rev()
3047
3047
3048 # check ancestors for earlier grafts
3048 # check ancestors for earlier grafts
3049 ui.debug('scanning for duplicate grafts\n')
3049 ui.debug('scanning for duplicate grafts\n')
3050
3050
3051 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3051 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3052 ctx = repo[rev]
3052 ctx = repo[rev]
3053 n = ctx.extra().get('source')
3053 n = ctx.extra().get('source')
3054 if n in ids:
3054 if n in ids:
3055 r = repo[n].rev()
3055 r = repo[n].rev()
3056 if r in revs:
3056 if r in revs:
3057 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3057 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3058 % (r, rev))
3058 % (r, rev))
3059 revs.remove(r)
3059 revs.remove(r)
3060 elif ids[n] in revs:
3060 elif ids[n] in revs:
3061 ui.warn(_('skipping already grafted revision %s '
3061 ui.warn(_('skipping already grafted revision %s '
3062 '(%s also has origin %d)\n') % (ids[n], rev, r))
3062 '(%s also has origin %d)\n') % (ids[n], rev, r))
3063 revs.remove(ids[n])
3063 revs.remove(ids[n])
3064 elif ctx.hex() in ids:
3064 elif ctx.hex() in ids:
3065 r = ids[ctx.hex()]
3065 r = ids[ctx.hex()]
3066 ui.warn(_('skipping already grafted revision %s '
3066 ui.warn(_('skipping already grafted revision %s '
3067 '(was grafted from %d)\n') % (r, rev))
3067 '(was grafted from %d)\n') % (r, rev))
3068 revs.remove(r)
3068 revs.remove(r)
3069 if not revs:
3069 if not revs:
3070 return -1
3070 return -1
3071
3071
3072 wlock = repo.wlock()
3072 wlock = repo.wlock()
3073 try:
3073 try:
3074 current = repo['.']
3074 current = repo['.']
3075 for pos, ctx in enumerate(repo.set("%ld", revs)):
3075 for pos, ctx in enumerate(repo.set("%ld", revs)):
3076
3076
3077 ui.status(_('grafting revision %s\n') % ctx.rev())
3077 ui.status(_('grafting revision %s\n') % ctx.rev())
3078 if opts.get('dry_run'):
3078 if opts.get('dry_run'):
3079 continue
3079 continue
3080
3080
3081 source = ctx.extra().get('source')
3081 source = ctx.extra().get('source')
3082 if not source:
3082 if not source:
3083 source = ctx.hex()
3083 source = ctx.hex()
3084 extra = {'source': source}
3084 extra = {'source': source}
3085 user = ctx.user()
3085 user = ctx.user()
3086 if opts.get('user'):
3086 if opts.get('user'):
3087 user = opts['user']
3087 user = opts['user']
3088 date = ctx.date()
3088 date = ctx.date()
3089 if opts.get('date'):
3089 if opts.get('date'):
3090 date = opts['date']
3090 date = opts['date']
3091 message = ctx.description()
3091 message = ctx.description()
3092 if opts.get('log'):
3092 if opts.get('log'):
3093 message += '\n(grafted from %s)' % ctx.hex()
3093 message += '\n(grafted from %s)' % ctx.hex()
3094
3094
3095 # we don't merge the first commit when continuing
3095 # we don't merge the first commit when continuing
3096 if not cont:
3096 if not cont:
3097 # perform the graft merge with p1(rev) as 'ancestor'
3097 # perform the graft merge with p1(rev) as 'ancestor'
3098 try:
3098 try:
3099 # ui.forcemerge is an internal variable, do not document
3099 # ui.forcemerge is an internal variable, do not document
3100 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3100 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3101 stats = mergemod.update(repo, ctx.node(), True, True, False,
3101 stats = mergemod.update(repo, ctx.node(), True, True, False,
3102 ctx.p1().node())
3102 ctx.p1().node())
3103 finally:
3103 finally:
3104 repo.ui.setconfig('ui', 'forcemerge', '')
3104 repo.ui.setconfig('ui', 'forcemerge', '')
3105 # report any conflicts
3105 # report any conflicts
3106 if stats and stats[3] > 0:
3106 if stats and stats[3] > 0:
3107 # write out state for --continue
3107 # write out state for --continue
3108 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3108 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3109 repo.opener.write('graftstate', ''.join(nodelines))
3109 repo.opener.write('graftstate', ''.join(nodelines))
3110 raise util.Abort(
3110 raise util.Abort(
3111 _("unresolved conflicts, can't continue"),
3111 _("unresolved conflicts, can't continue"),
3112 hint=_('use hg resolve and hg graft --continue'))
3112 hint=_('use hg resolve and hg graft --continue'))
3113 else:
3113 else:
3114 cont = False
3114 cont = False
3115
3115
3116 # drop the second merge parent
3116 # drop the second merge parent
3117 repo.setparents(current.node(), nullid)
3117 repo.setparents(current.node(), nullid)
3118 repo.dirstate.write()
3118 repo.dirstate.write()
3119 # fix up dirstate for copies and renames
3119 # fix up dirstate for copies and renames
3120 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3120 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3121
3121
3122 # commit
3122 # commit
3123 node = repo.commit(text=message, user=user,
3123 node = repo.commit(text=message, user=user,
3124 date=date, extra=extra, editor=editor)
3124 date=date, extra=extra, editor=editor)
3125 if node is None:
3125 if node is None:
3126 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3126 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3127 else:
3127 else:
3128 current = repo[node]
3128 current = repo[node]
3129 finally:
3129 finally:
3130 wlock.release()
3130 wlock.release()
3131
3131
3132 # remove state when we complete successfully
3132 # remove state when we complete successfully
3133 if not opts.get('dry_run'):
3133 if not opts.get('dry_run'):
3134 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3134 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3135
3135
3136 return 0
3136 return 0
3137
3137
3138 @command('grep',
3138 @command('grep',
3139 [('0', 'print0', None, _('end fields with NUL')),
3139 [('0', 'print0', None, _('end fields with NUL')),
3140 ('', 'all', None, _('print all revisions that match')),
3140 ('', 'all', None, _('print all revisions that match')),
3141 ('a', 'text', None, _('treat all files as text')),
3141 ('a', 'text', None, _('treat all files as text')),
3142 ('f', 'follow', None,
3142 ('f', 'follow', None,
3143 _('follow changeset history,'
3143 _('follow changeset history,'
3144 ' or file history across copies and renames')),
3144 ' or file history across copies and renames')),
3145 ('i', 'ignore-case', None, _('ignore case when matching')),
3145 ('i', 'ignore-case', None, _('ignore case when matching')),
3146 ('l', 'files-with-matches', None,
3146 ('l', 'files-with-matches', None,
3147 _('print only filenames and revisions that match')),
3147 _('print only filenames and revisions that match')),
3148 ('n', 'line-number', None, _('print matching line numbers')),
3148 ('n', 'line-number', None, _('print matching line numbers')),
3149 ('r', 'rev', [],
3149 ('r', 'rev', [],
3150 _('only search files changed within revision range'), _('REV')),
3150 _('only search files changed within revision range'), _('REV')),
3151 ('u', 'user', None, _('list the author (long with -v)')),
3151 ('u', 'user', None, _('list the author (long with -v)')),
3152 ('d', 'date', None, _('list the date (short with -q)')),
3152 ('d', 'date', None, _('list the date (short with -q)')),
3153 ] + walkopts,
3153 ] + walkopts,
3154 _('[OPTION]... PATTERN [FILE]...'))
3154 _('[OPTION]... PATTERN [FILE]...'))
3155 def grep(ui, repo, pattern, *pats, **opts):
3155 def grep(ui, repo, pattern, *pats, **opts):
3156 """search for a pattern in specified files and revisions
3156 """search for a pattern in specified files and revisions
3157
3157
3158 Search revisions of files for a regular expression.
3158 Search revisions of files for a regular expression.
3159
3159
3160 This command behaves differently than Unix grep. It only accepts
3160 This command behaves differently than Unix grep. It only accepts
3161 Python/Perl regexps. It searches repository history, not the
3161 Python/Perl regexps. It searches repository history, not the
3162 working directory. It always prints the revision number in which a
3162 working directory. It always prints the revision number in which a
3163 match appears.
3163 match appears.
3164
3164
3165 By default, grep only prints output for the first revision of a
3165 By default, grep only prints output for the first revision of a
3166 file in which it finds a match. To get it to print every revision
3166 file in which it finds a match. To get it to print every revision
3167 that contains a change in match status ("-" for a match that
3167 that contains a change in match status ("-" for a match that
3168 becomes a non-match, or "+" for a non-match that becomes a match),
3168 becomes a non-match, or "+" for a non-match that becomes a match),
3169 use the --all flag.
3169 use the --all flag.
3170
3170
3171 Returns 0 if a match is found, 1 otherwise.
3171 Returns 0 if a match is found, 1 otherwise.
3172 """
3172 """
3173 reflags = re.M
3173 reflags = re.M
3174 if opts.get('ignore_case'):
3174 if opts.get('ignore_case'):
3175 reflags |= re.I
3175 reflags |= re.I
3176 try:
3176 try:
3177 regexp = util.compilere(pattern, reflags)
3177 regexp = util.compilere(pattern, reflags)
3178 except re.error, inst:
3178 except re.error, inst:
3179 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3179 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3180 return 1
3180 return 1
3181 sep, eol = ':', '\n'
3181 sep, eol = ':', '\n'
3182 if opts.get('print0'):
3182 if opts.get('print0'):
3183 sep = eol = '\0'
3183 sep = eol = '\0'
3184
3184
3185 getfile = util.lrucachefunc(repo.file)
3185 getfile = util.lrucachefunc(repo.file)
3186
3186
3187 def matchlines(body):
3187 def matchlines(body):
3188 begin = 0
3188 begin = 0
3189 linenum = 0
3189 linenum = 0
3190 while begin < len(body):
3190 while begin < len(body):
3191 match = regexp.search(body, begin)
3191 match = regexp.search(body, begin)
3192 if not match:
3192 if not match:
3193 break
3193 break
3194 mstart, mend = match.span()
3194 mstart, mend = match.span()
3195 linenum += body.count('\n', begin, mstart) + 1
3195 linenum += body.count('\n', begin, mstart) + 1
3196 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3196 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3197 begin = body.find('\n', mend) + 1 or len(body) + 1
3197 begin = body.find('\n', mend) + 1 or len(body) + 1
3198 lend = begin - 1
3198 lend = begin - 1
3199 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3199 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3200
3200
3201 class linestate(object):
3201 class linestate(object):
3202 def __init__(self, line, linenum, colstart, colend):
3202 def __init__(self, line, linenum, colstart, colend):
3203 self.line = line
3203 self.line = line
3204 self.linenum = linenum
3204 self.linenum = linenum
3205 self.colstart = colstart
3205 self.colstart = colstart
3206 self.colend = colend
3206 self.colend = colend
3207
3207
3208 def __hash__(self):
3208 def __hash__(self):
3209 return hash((self.linenum, self.line))
3209 return hash((self.linenum, self.line))
3210
3210
3211 def __eq__(self, other):
3211 def __eq__(self, other):
3212 return self.line == other.line
3212 return self.line == other.line
3213
3213
3214 matches = {}
3214 matches = {}
3215 copies = {}
3215 copies = {}
3216 def grepbody(fn, rev, body):
3216 def grepbody(fn, rev, body):
3217 matches[rev].setdefault(fn, [])
3217 matches[rev].setdefault(fn, [])
3218 m = matches[rev][fn]
3218 m = matches[rev][fn]
3219 for lnum, cstart, cend, line in matchlines(body):
3219 for lnum, cstart, cend, line in matchlines(body):
3220 s = linestate(line, lnum, cstart, cend)
3220 s = linestate(line, lnum, cstart, cend)
3221 m.append(s)
3221 m.append(s)
3222
3222
3223 def difflinestates(a, b):
3223 def difflinestates(a, b):
3224 sm = difflib.SequenceMatcher(None, a, b)
3224 sm = difflib.SequenceMatcher(None, a, b)
3225 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3225 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3226 if tag == 'insert':
3226 if tag == 'insert':
3227 for i in xrange(blo, bhi):
3227 for i in xrange(blo, bhi):
3228 yield ('+', b[i])
3228 yield ('+', b[i])
3229 elif tag == 'delete':
3229 elif tag == 'delete':
3230 for i in xrange(alo, ahi):
3230 for i in xrange(alo, ahi):
3231 yield ('-', a[i])
3231 yield ('-', a[i])
3232 elif tag == 'replace':
3232 elif tag == 'replace':
3233 for i in xrange(alo, ahi):
3233 for i in xrange(alo, ahi):
3234 yield ('-', a[i])
3234 yield ('-', a[i])
3235 for i in xrange(blo, bhi):
3235 for i in xrange(blo, bhi):
3236 yield ('+', b[i])
3236 yield ('+', b[i])
3237
3237
3238 def display(fn, ctx, pstates, states):
3238 def display(fn, ctx, pstates, states):
3239 rev = ctx.rev()
3239 rev = ctx.rev()
3240 datefunc = ui.quiet and util.shortdate or util.datestr
3240 datefunc = ui.quiet and util.shortdate or util.datestr
3241 found = False
3241 found = False
3242 filerevmatches = {}
3242 filerevmatches = {}
3243 def binary():
3243 def binary():
3244 flog = getfile(fn)
3244 flog = getfile(fn)
3245 return util.binary(flog.read(ctx.filenode(fn)))
3245 return util.binary(flog.read(ctx.filenode(fn)))
3246
3246
3247 if opts.get('all'):
3247 if opts.get('all'):
3248 iter = difflinestates(pstates, states)
3248 iter = difflinestates(pstates, states)
3249 else:
3249 else:
3250 iter = [('', l) for l in states]
3250 iter = [('', l) for l in states]
3251 for change, l in iter:
3251 for change, l in iter:
3252 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3252 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3253 before, match, after = None, None, None
3253 before, match, after = None, None, None
3254
3254
3255 if opts.get('line_number'):
3255 if opts.get('line_number'):
3256 cols.append((str(l.linenum), 'grep.linenumber'))
3256 cols.append((str(l.linenum), 'grep.linenumber'))
3257 if opts.get('all'):
3257 if opts.get('all'):
3258 cols.append((change, 'grep.change'))
3258 cols.append((change, 'grep.change'))
3259 if opts.get('user'):
3259 if opts.get('user'):
3260 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3260 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3261 if opts.get('date'):
3261 if opts.get('date'):
3262 cols.append((datefunc(ctx.date()), 'grep.date'))
3262 cols.append((datefunc(ctx.date()), 'grep.date'))
3263 if opts.get('files_with_matches'):
3263 if opts.get('files_with_matches'):
3264 c = (fn, rev)
3264 c = (fn, rev)
3265 if c in filerevmatches:
3265 if c in filerevmatches:
3266 continue
3266 continue
3267 filerevmatches[c] = 1
3267 filerevmatches[c] = 1
3268 else:
3268 else:
3269 before = l.line[:l.colstart]
3269 before = l.line[:l.colstart]
3270 match = l.line[l.colstart:l.colend]
3270 match = l.line[l.colstart:l.colend]
3271 after = l.line[l.colend:]
3271 after = l.line[l.colend:]
3272 for col, label in cols[:-1]:
3272 for col, label in cols[:-1]:
3273 ui.write(col, label=label)
3273 ui.write(col, label=label)
3274 ui.write(sep, label='grep.sep')
3274 ui.write(sep, label='grep.sep')
3275 ui.write(cols[-1][0], label=cols[-1][1])
3275 ui.write(cols[-1][0], label=cols[-1][1])
3276 if before is not None:
3276 if before is not None:
3277 ui.write(sep, label='grep.sep')
3277 ui.write(sep, label='grep.sep')
3278 if not opts.get('text') and binary():
3278 if not opts.get('text') and binary():
3279 ui.write(" Binary file matches")
3279 ui.write(" Binary file matches")
3280 else:
3280 else:
3281 ui.write(before)
3281 ui.write(before)
3282 ui.write(match, label='grep.match')
3282 ui.write(match, label='grep.match')
3283 ui.write(after)
3283 ui.write(after)
3284 ui.write(eol)
3284 ui.write(eol)
3285 found = True
3285 found = True
3286 return found
3286 return found
3287
3287
3288 skip = {}
3288 skip = {}
3289 revfiles = {}
3289 revfiles = {}
3290 matchfn = scmutil.match(repo[None], pats, opts)
3290 matchfn = scmutil.match(repo[None], pats, opts)
3291 found = False
3291 found = False
3292 follow = opts.get('follow')
3292 follow = opts.get('follow')
3293
3293
3294 def prep(ctx, fns):
3294 def prep(ctx, fns):
3295 rev = ctx.rev()
3295 rev = ctx.rev()
3296 pctx = ctx.p1()
3296 pctx = ctx.p1()
3297 parent = pctx.rev()
3297 parent = pctx.rev()
3298 matches.setdefault(rev, {})
3298 matches.setdefault(rev, {})
3299 matches.setdefault(parent, {})
3299 matches.setdefault(parent, {})
3300 files = revfiles.setdefault(rev, [])
3300 files = revfiles.setdefault(rev, [])
3301 for fn in fns:
3301 for fn in fns:
3302 flog = getfile(fn)
3302 flog = getfile(fn)
3303 try:
3303 try:
3304 fnode = ctx.filenode(fn)
3304 fnode = ctx.filenode(fn)
3305 except error.LookupError:
3305 except error.LookupError:
3306 continue
3306 continue
3307
3307
3308 copied = flog.renamed(fnode)
3308 copied = flog.renamed(fnode)
3309 copy = follow and copied and copied[0]
3309 copy = follow and copied and copied[0]
3310 if copy:
3310 if copy:
3311 copies.setdefault(rev, {})[fn] = copy
3311 copies.setdefault(rev, {})[fn] = copy
3312 if fn in skip:
3312 if fn in skip:
3313 if copy:
3313 if copy:
3314 skip[copy] = True
3314 skip[copy] = True
3315 continue
3315 continue
3316 files.append(fn)
3316 files.append(fn)
3317
3317
3318 if fn not in matches[rev]:
3318 if fn not in matches[rev]:
3319 grepbody(fn, rev, flog.read(fnode))
3319 grepbody(fn, rev, flog.read(fnode))
3320
3320
3321 pfn = copy or fn
3321 pfn = copy or fn
3322 if pfn not in matches[parent]:
3322 if pfn not in matches[parent]:
3323 try:
3323 try:
3324 fnode = pctx.filenode(pfn)
3324 fnode = pctx.filenode(pfn)
3325 grepbody(pfn, parent, flog.read(fnode))
3325 grepbody(pfn, parent, flog.read(fnode))
3326 except error.LookupError:
3326 except error.LookupError:
3327 pass
3327 pass
3328
3328
3329 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3329 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3330 rev = ctx.rev()
3330 rev = ctx.rev()
3331 parent = ctx.p1().rev()
3331 parent = ctx.p1().rev()
3332 for fn in sorted(revfiles.get(rev, [])):
3332 for fn in sorted(revfiles.get(rev, [])):
3333 states = matches[rev][fn]
3333 states = matches[rev][fn]
3334 copy = copies.get(rev, {}).get(fn)
3334 copy = copies.get(rev, {}).get(fn)
3335 if fn in skip:
3335 if fn in skip:
3336 if copy:
3336 if copy:
3337 skip[copy] = True
3337 skip[copy] = True
3338 continue
3338 continue
3339 pstates = matches.get(parent, {}).get(copy or fn, [])
3339 pstates = matches.get(parent, {}).get(copy or fn, [])
3340 if pstates or states:
3340 if pstates or states:
3341 r = display(fn, ctx, pstates, states)
3341 r = display(fn, ctx, pstates, states)
3342 found = found or r
3342 found = found or r
3343 if r and not opts.get('all'):
3343 if r and not opts.get('all'):
3344 skip[fn] = True
3344 skip[fn] = True
3345 if copy:
3345 if copy:
3346 skip[copy] = True
3346 skip[copy] = True
3347 del matches[rev]
3347 del matches[rev]
3348 del revfiles[rev]
3348 del revfiles[rev]
3349
3349
3350 return not found
3350 return not found
3351
3351
3352 @command('heads',
3352 @command('heads',
3353 [('r', 'rev', '',
3353 [('r', 'rev', '',
3354 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3354 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3355 ('t', 'topo', False, _('show topological heads only')),
3355 ('t', 'topo', False, _('show topological heads only')),
3356 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3356 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3357 ('c', 'closed', False, _('show normal and closed branch heads')),
3357 ('c', 'closed', False, _('show normal and closed branch heads')),
3358 ] + templateopts,
3358 ] + templateopts,
3359 _('[-ct] [-r STARTREV] [REV]...'))
3359 _('[-ct] [-r STARTREV] [REV]...'))
3360 def heads(ui, repo, *branchrevs, **opts):
3360 def heads(ui, repo, *branchrevs, **opts):
3361 """show branch heads
3361 """show branch heads
3362
3362
3363 With no arguments, show all open branch heads in the repository.
3363 With no arguments, show all open branch heads in the repository.
3364 Branch heads are changesets that have no descendants on the
3364 Branch heads are changesets that have no descendants on the
3365 same branch. They are where development generally takes place and
3365 same branch. They are where development generally takes place and
3366 are the usual targets for update and merge operations.
3366 are the usual targets for update and merge operations.
3367
3367
3368 If one or more REVs are given, only open branch heads on the
3368 If one or more REVs are given, only open branch heads on the
3369 branches associated with the specified changesets are shown. This
3369 branches associated with the specified changesets are shown. This
3370 means that you can use :hg:`heads .` to see the heads on the
3370 means that you can use :hg:`heads .` to see the heads on the
3371 currently checked-out branch.
3371 currently checked-out branch.
3372
3372
3373 If -c/--closed is specified, also show branch heads marked closed
3373 If -c/--closed is specified, also show branch heads marked closed
3374 (see :hg:`commit --close-branch`).
3374 (see :hg:`commit --close-branch`).
3375
3375
3376 If STARTREV is specified, only those heads that are descendants of
3376 If STARTREV is specified, only those heads that are descendants of
3377 STARTREV will be displayed.
3377 STARTREV will be displayed.
3378
3378
3379 If -t/--topo is specified, named branch mechanics will be ignored and only
3379 If -t/--topo is specified, named branch mechanics will be ignored and only
3380 topological heads (changesets with no children) will be shown.
3380 topological heads (changesets with no children) will be shown.
3381
3381
3382 Returns 0 if matching heads are found, 1 if not.
3382 Returns 0 if matching heads are found, 1 if not.
3383 """
3383 """
3384
3384
3385 start = None
3385 start = None
3386 if 'rev' in opts:
3386 if 'rev' in opts:
3387 start = scmutil.revsingle(repo, opts['rev'], None).node()
3387 start = scmutil.revsingle(repo, opts['rev'], None).node()
3388
3388
3389 if opts.get('topo'):
3389 if opts.get('topo'):
3390 heads = [repo[h] for h in repo.heads(start)]
3390 heads = [repo[h] for h in repo.heads(start)]
3391 else:
3391 else:
3392 heads = []
3392 heads = []
3393 for branch in repo.branchmap():
3393 for branch in repo.branchmap():
3394 heads += repo.branchheads(branch, start, opts.get('closed'))
3394 heads += repo.branchheads(branch, start, opts.get('closed'))
3395 heads = [repo[h] for h in heads]
3395 heads = [repo[h] for h in heads]
3396
3396
3397 if branchrevs:
3397 if branchrevs:
3398 branches = set(repo[br].branch() for br in branchrevs)
3398 branches = set(repo[br].branch() for br in branchrevs)
3399 heads = [h for h in heads if h.branch() in branches]
3399 heads = [h for h in heads if h.branch() in branches]
3400
3400
3401 if opts.get('active') and branchrevs:
3401 if opts.get('active') and branchrevs:
3402 dagheads = repo.heads(start)
3402 dagheads = repo.heads(start)
3403 heads = [h for h in heads if h.node() in dagheads]
3403 heads = [h for h in heads if h.node() in dagheads]
3404
3404
3405 if branchrevs:
3405 if branchrevs:
3406 haveheads = set(h.branch() for h in heads)
3406 haveheads = set(h.branch() for h in heads)
3407 if branches - haveheads:
3407 if branches - haveheads:
3408 headless = ', '.join(b for b in branches - haveheads)
3408 headless = ', '.join(b for b in branches - haveheads)
3409 msg = _('no open branch heads found on branches %s')
3409 msg = _('no open branch heads found on branches %s')
3410 if opts.get('rev'):
3410 if opts.get('rev'):
3411 msg += _(' (started at %s)') % opts['rev']
3411 msg += _(' (started at %s)') % opts['rev']
3412 ui.warn((msg + '\n') % headless)
3412 ui.warn((msg + '\n') % headless)
3413
3413
3414 if not heads:
3414 if not heads:
3415 return 1
3415 return 1
3416
3416
3417 heads = sorted(heads, key=lambda x: -x.rev())
3417 heads = sorted(heads, key=lambda x: -x.rev())
3418 displayer = cmdutil.show_changeset(ui, repo, opts)
3418 displayer = cmdutil.show_changeset(ui, repo, opts)
3419 for ctx in heads:
3419 for ctx in heads:
3420 displayer.show(ctx)
3420 displayer.show(ctx)
3421 displayer.close()
3421 displayer.close()
3422
3422
3423 @command('help',
3423 @command('help',
3424 [('e', 'extension', None, _('show only help for extensions')),
3424 [('e', 'extension', None, _('show only help for extensions')),
3425 ('c', 'command', None, _('show only help for commands')),
3425 ('c', 'command', None, _('show only help for commands')),
3426 ('k', 'keyword', '', _('show topics matching keyword')),
3426 ('k', 'keyword', '', _('show topics matching keyword')),
3427 ],
3427 ],
3428 _('[-ec] [TOPIC]'))
3428 _('[-ec] [TOPIC]'))
3429 def help_(ui, name=None, **opts):
3429 def help_(ui, name=None, **opts):
3430 """show help for a given topic or a help overview
3430 """show help for a given topic or a help overview
3431
3431
3432 With no arguments, print a list of commands with short help messages.
3432 With no arguments, print a list of commands with short help messages.
3433
3433
3434 Given a topic, extension, or command name, print help for that
3434 Given a topic, extension, or command name, print help for that
3435 topic.
3435 topic.
3436
3436
3437 Returns 0 if successful.
3437 Returns 0 if successful.
3438 """
3438 """
3439
3439
3440 textwidth = min(ui.termwidth(), 80) - 2
3440 textwidth = min(ui.termwidth(), 80) - 2
3441
3441
3442 keep = ui.verbose and ['verbose'] or []
3442 keep = ui.verbose and ['verbose'] or []
3443 text = help.help_(ui, name, **opts)
3443 text = help.help_(ui, name, **opts)
3444
3444
3445 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3445 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3446 if 'verbose' in pruned:
3446 if 'verbose' in pruned:
3447 keep.append('omitted')
3447 keep.append('omitted')
3448 else:
3448 else:
3449 keep.append('notomitted')
3449 keep.append('notomitted')
3450 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3450 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3451 ui.write(formatted)
3451 ui.write(formatted)
3452
3452
3453
3453
3454 @command('identify|id',
3454 @command('identify|id',
3455 [('r', 'rev', '',
3455 [('r', 'rev', '',
3456 _('identify the specified revision'), _('REV')),
3456 _('identify the specified revision'), _('REV')),
3457 ('n', 'num', None, _('show local revision number')),
3457 ('n', 'num', None, _('show local revision number')),
3458 ('i', 'id', None, _('show global revision id')),
3458 ('i', 'id', None, _('show global revision id')),
3459 ('b', 'branch', None, _('show branch')),
3459 ('b', 'branch', None, _('show branch')),
3460 ('t', 'tags', None, _('show tags')),
3460 ('t', 'tags', None, _('show tags')),
3461 ('B', 'bookmarks', None, _('show bookmarks')),
3461 ('B', 'bookmarks', None, _('show bookmarks')),
3462 ] + remoteopts,
3462 ] + remoteopts,
3463 _('[-nibtB] [-r REV] [SOURCE]'))
3463 _('[-nibtB] [-r REV] [SOURCE]'))
3464 def identify(ui, repo, source=None, rev=None,
3464 def identify(ui, repo, source=None, rev=None,
3465 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3465 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3466 """identify the working copy or specified revision
3466 """identify the working copy or specified revision
3467
3467
3468 Print a summary identifying the repository state at REV using one or
3468 Print a summary identifying the repository state at REV using one or
3469 two parent hash identifiers, followed by a "+" if the working
3469 two parent hash identifiers, followed by a "+" if the working
3470 directory has uncommitted changes, the branch name (if not default),
3470 directory has uncommitted changes, the branch name (if not default),
3471 a list of tags, and a list of bookmarks.
3471 a list of tags, and a list of bookmarks.
3472
3472
3473 When REV is not given, print a summary of the current state of the
3473 When REV is not given, print a summary of the current state of the
3474 repository.
3474 repository.
3475
3475
3476 Specifying a path to a repository root or Mercurial bundle will
3476 Specifying a path to a repository root or Mercurial bundle will
3477 cause lookup to operate on that repository/bundle.
3477 cause lookup to operate on that repository/bundle.
3478
3478
3479 .. container:: verbose
3479 .. container:: verbose
3480
3480
3481 Examples:
3481 Examples:
3482
3482
3483 - generate a build identifier for the working directory::
3483 - generate a build identifier for the working directory::
3484
3484
3485 hg id --id > build-id.dat
3485 hg id --id > build-id.dat
3486
3486
3487 - find the revision corresponding to a tag::
3487 - find the revision corresponding to a tag::
3488
3488
3489 hg id -n -r 1.3
3489 hg id -n -r 1.3
3490
3490
3491 - check the most recent revision of a remote repository::
3491 - check the most recent revision of a remote repository::
3492
3492
3493 hg id -r tip http://selenic.com/hg/
3493 hg id -r tip http://selenic.com/hg/
3494
3494
3495 Returns 0 if successful.
3495 Returns 0 if successful.
3496 """
3496 """
3497
3497
3498 if not repo and not source:
3498 if not repo and not source:
3499 raise util.Abort(_("there is no Mercurial repository here "
3499 raise util.Abort(_("there is no Mercurial repository here "
3500 "(.hg not found)"))
3500 "(.hg not found)"))
3501
3501
3502 hexfunc = ui.debugflag and hex or short
3502 hexfunc = ui.debugflag and hex or short
3503 default = not (num or id or branch or tags or bookmarks)
3503 default = not (num or id or branch or tags or bookmarks)
3504 output = []
3504 output = []
3505 revs = []
3505 revs = []
3506
3506
3507 if source:
3507 if source:
3508 source, branches = hg.parseurl(ui.expandpath(source))
3508 source, branches = hg.parseurl(ui.expandpath(source))
3509 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3509 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3510 repo = peer.local()
3510 repo = peer.local()
3511 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3511 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3512
3512
3513 if not repo:
3513 if not repo:
3514 if num or branch or tags:
3514 if num or branch or tags:
3515 raise util.Abort(
3515 raise util.Abort(
3516 _("can't query remote revision number, branch, or tags"))
3516 _("can't query remote revision number, branch, or tags"))
3517 if not rev and revs:
3517 if not rev and revs:
3518 rev = revs[0]
3518 rev = revs[0]
3519 if not rev:
3519 if not rev:
3520 rev = "tip"
3520 rev = "tip"
3521
3521
3522 remoterev = peer.lookup(rev)
3522 remoterev = peer.lookup(rev)
3523 if default or id:
3523 if default or id:
3524 output = [hexfunc(remoterev)]
3524 output = [hexfunc(remoterev)]
3525
3525
3526 def getbms():
3526 def getbms():
3527 bms = []
3527 bms = []
3528
3528
3529 if 'bookmarks' in peer.listkeys('namespaces'):
3529 if 'bookmarks' in peer.listkeys('namespaces'):
3530 hexremoterev = hex(remoterev)
3530 hexremoterev = hex(remoterev)
3531 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3531 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3532 if bmr == hexremoterev]
3532 if bmr == hexremoterev]
3533
3533
3534 return sorted(bms)
3534 return sorted(bms)
3535
3535
3536 if bookmarks:
3536 if bookmarks:
3537 output.extend(getbms())
3537 output.extend(getbms())
3538 elif default and not ui.quiet:
3538 elif default and not ui.quiet:
3539 # multiple bookmarks for a single parent separated by '/'
3539 # multiple bookmarks for a single parent separated by '/'
3540 bm = '/'.join(getbms())
3540 bm = '/'.join(getbms())
3541 if bm:
3541 if bm:
3542 output.append(bm)
3542 output.append(bm)
3543 else:
3543 else:
3544 if not rev:
3544 if not rev:
3545 ctx = repo[None]
3545 ctx = repo[None]
3546 parents = ctx.parents()
3546 parents = ctx.parents()
3547 changed = ""
3547 changed = ""
3548 if default or id or num:
3548 if default or id or num:
3549 if (util.any(repo.status())
3549 if (util.any(repo.status())
3550 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3550 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3551 changed = '+'
3551 changed = '+'
3552 if default or id:
3552 if default or id:
3553 output = ["%s%s" %
3553 output = ["%s%s" %
3554 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3554 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3555 if num:
3555 if num:
3556 output.append("%s%s" %
3556 output.append("%s%s" %
3557 ('+'.join([str(p.rev()) for p in parents]), changed))
3557 ('+'.join([str(p.rev()) for p in parents]), changed))
3558 else:
3558 else:
3559 ctx = scmutil.revsingle(repo, rev)
3559 ctx = scmutil.revsingle(repo, rev)
3560 if default or id:
3560 if default or id:
3561 output = [hexfunc(ctx.node())]
3561 output = [hexfunc(ctx.node())]
3562 if num:
3562 if num:
3563 output.append(str(ctx.rev()))
3563 output.append(str(ctx.rev()))
3564
3564
3565 if default and not ui.quiet:
3565 if default and not ui.quiet:
3566 b = ctx.branch()
3566 b = ctx.branch()
3567 if b != 'default':
3567 if b != 'default':
3568 output.append("(%s)" % b)
3568 output.append("(%s)" % b)
3569
3569
3570 # multiple tags for a single parent separated by '/'
3570 # multiple tags for a single parent separated by '/'
3571 t = '/'.join(ctx.tags())
3571 t = '/'.join(ctx.tags())
3572 if t:
3572 if t:
3573 output.append(t)
3573 output.append(t)
3574
3574
3575 # multiple bookmarks for a single parent separated by '/'
3575 # multiple bookmarks for a single parent separated by '/'
3576 bm = '/'.join(ctx.bookmarks())
3576 bm = '/'.join(ctx.bookmarks())
3577 if bm:
3577 if bm:
3578 output.append(bm)
3578 output.append(bm)
3579 else:
3579 else:
3580 if branch:
3580 if branch:
3581 output.append(ctx.branch())
3581 output.append(ctx.branch())
3582
3582
3583 if tags:
3583 if tags:
3584 output.extend(ctx.tags())
3584 output.extend(ctx.tags())
3585
3585
3586 if bookmarks:
3586 if bookmarks:
3587 output.extend(ctx.bookmarks())
3587 output.extend(ctx.bookmarks())
3588
3588
3589 ui.write("%s\n" % ' '.join(output))
3589 ui.write("%s\n" % ' '.join(output))
3590
3590
3591 @command('import|patch',
3591 @command('import|patch',
3592 [('p', 'strip', 1,
3592 [('p', 'strip', 1,
3593 _('directory strip option for patch. This has the same '
3593 _('directory strip option for patch. This has the same '
3594 'meaning as the corresponding patch option'), _('NUM')),
3594 'meaning as the corresponding patch option'), _('NUM')),
3595 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3595 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3596 ('e', 'edit', False, _('invoke editor on commit messages')),
3596 ('e', 'edit', False, _('invoke editor on commit messages')),
3597 ('f', 'force', None,
3597 ('f', 'force', None,
3598 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3598 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3599 ('', 'no-commit', None,
3599 ('', 'no-commit', None,
3600 _("don't commit, just update the working directory")),
3600 _("don't commit, just update the working directory")),
3601 ('', 'bypass', None,
3601 ('', 'bypass', None,
3602 _("apply patch without touching the working directory")),
3602 _("apply patch without touching the working directory")),
3603 ('', 'exact', None,
3603 ('', 'exact', None,
3604 _('apply patch to the nodes from which it was generated')),
3604 _('apply patch to the nodes from which it was generated')),
3605 ('', 'import-branch', None,
3605 ('', 'import-branch', None,
3606 _('use any branch information in patch (implied by --exact)'))] +
3606 _('use any branch information in patch (implied by --exact)'))] +
3607 commitopts + commitopts2 + similarityopts,
3607 commitopts + commitopts2 + similarityopts,
3608 _('[OPTION]... PATCH...'))
3608 _('[OPTION]... PATCH...'))
3609 def import_(ui, repo, patch1=None, *patches, **opts):
3609 def import_(ui, repo, patch1=None, *patches, **opts):
3610 """import an ordered set of patches
3610 """import an ordered set of patches
3611
3611
3612 Import a list of patches and commit them individually (unless
3612 Import a list of patches and commit them individually (unless
3613 --no-commit is specified).
3613 --no-commit is specified).
3614
3614
3615 Because import first applies changes to the working directory,
3615 Because import first applies changes to the working directory,
3616 import will abort if there are outstanding changes.
3616 import will abort if there are outstanding changes.
3617
3617
3618 You can import a patch straight from a mail message. Even patches
3618 You can import a patch straight from a mail message. Even patches
3619 as attachments work (to use the body part, it must have type
3619 as attachments work (to use the body part, it must have type
3620 text/plain or text/x-patch). From and Subject headers of email
3620 text/plain or text/x-patch). From and Subject headers of email
3621 message are used as default committer and commit message. All
3621 message are used as default committer and commit message. All
3622 text/plain body parts before first diff are added to commit
3622 text/plain body parts before first diff are added to commit
3623 message.
3623 message.
3624
3624
3625 If the imported patch was generated by :hg:`export`, user and
3625 If the imported patch was generated by :hg:`export`, user and
3626 description from patch override values from message headers and
3626 description from patch override values from message headers and
3627 body. Values given on command line with -m/--message and -u/--user
3627 body. Values given on command line with -m/--message and -u/--user
3628 override these.
3628 override these.
3629
3629
3630 If --exact is specified, import will set the working directory to
3630 If --exact is specified, import will set the working directory to
3631 the parent of each patch before applying it, and will abort if the
3631 the parent of each patch before applying it, and will abort if the
3632 resulting changeset has a different ID than the one recorded in
3632 resulting changeset has a different ID than the one recorded in
3633 the patch. This may happen due to character set problems or other
3633 the patch. This may happen due to character set problems or other
3634 deficiencies in the text patch format.
3634 deficiencies in the text patch format.
3635
3635
3636 Use --bypass to apply and commit patches directly to the
3636 Use --bypass to apply and commit patches directly to the
3637 repository, not touching the working directory. Without --exact,
3637 repository, not touching the working directory. Without --exact,
3638 patches will be applied on top of the working directory parent
3638 patches will be applied on top of the working directory parent
3639 revision.
3639 revision.
3640
3640
3641 With -s/--similarity, hg will attempt to discover renames and
3641 With -s/--similarity, hg will attempt to discover renames and
3642 copies in the patch in the same way as :hg:`addremove`.
3642 copies in the patch in the same way as :hg:`addremove`.
3643
3643
3644 To read a patch from standard input, use "-" as the patch name. If
3644 To read a patch from standard input, use "-" as the patch name. If
3645 a URL is specified, the patch will be downloaded from it.
3645 a URL is specified, the patch will be downloaded from it.
3646 See :hg:`help dates` for a list of formats valid for -d/--date.
3646 See :hg:`help dates` for a list of formats valid for -d/--date.
3647
3647
3648 .. container:: verbose
3648 .. container:: verbose
3649
3649
3650 Examples:
3650 Examples:
3651
3651
3652 - import a traditional patch from a website and detect renames::
3652 - import a traditional patch from a website and detect renames::
3653
3653
3654 hg import -s 80 http://example.com/bugfix.patch
3654 hg import -s 80 http://example.com/bugfix.patch
3655
3655
3656 - import a changeset from an hgweb server::
3656 - import a changeset from an hgweb server::
3657
3657
3658 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3658 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3659
3659
3660 - import all the patches in an Unix-style mbox::
3660 - import all the patches in an Unix-style mbox::
3661
3661
3662 hg import incoming-patches.mbox
3662 hg import incoming-patches.mbox
3663
3663
3664 - attempt to exactly restore an exported changeset (not always
3664 - attempt to exactly restore an exported changeset (not always
3665 possible)::
3665 possible)::
3666
3666
3667 hg import --exact proposed-fix.patch
3667 hg import --exact proposed-fix.patch
3668
3668
3669 Returns 0 on success.
3669 Returns 0 on success.
3670 """
3670 """
3671
3671
3672 if not patch1:
3672 if not patch1:
3673 raise util.Abort(_('need at least one patch to import'))
3673 raise util.Abort(_('need at least one patch to import'))
3674
3674
3675 patches = (patch1,) + patches
3675 patches = (patch1,) + patches
3676
3676
3677 date = opts.get('date')
3677 date = opts.get('date')
3678 if date:
3678 if date:
3679 opts['date'] = util.parsedate(date)
3679 opts['date'] = util.parsedate(date)
3680
3680
3681 editor = cmdutil.commiteditor
3682 if opts.get('edit'):
3683 editor = cmdutil.commitforceeditor
3684
3685 update = not opts.get('bypass')
3681 update = not opts.get('bypass')
3686 if not update and opts.get('no_commit'):
3682 if not update and opts.get('no_commit'):
3687 raise util.Abort(_('cannot use --no-commit with --bypass'))
3683 raise util.Abort(_('cannot use --no-commit with --bypass'))
3688 try:
3684 try:
3689 sim = float(opts.get('similarity') or 0)
3685 sim = float(opts.get('similarity') or 0)
3690 except ValueError:
3686 except ValueError:
3691 raise util.Abort(_('similarity must be a number'))
3687 raise util.Abort(_('similarity must be a number'))
3692 if sim < 0 or sim > 100:
3688 if sim < 0 or sim > 100:
3693 raise util.Abort(_('similarity must be between 0 and 100'))
3689 raise util.Abort(_('similarity must be between 0 and 100'))
3694 if sim and not update:
3690 if sim and not update:
3695 raise util.Abort(_('cannot use --similarity with --bypass'))
3691 raise util.Abort(_('cannot use --similarity with --bypass'))
3696
3692
3697 if update:
3693 if update:
3698 cmdutil.checkunfinished(repo)
3694 cmdutil.checkunfinished(repo)
3699 if (opts.get('exact') or not opts.get('force')) and update:
3695 if (opts.get('exact') or not opts.get('force')) and update:
3700 cmdutil.bailifchanged(repo)
3696 cmdutil.bailifchanged(repo)
3701
3697
3702 base = opts["base"]
3698 base = opts["base"]
3703 strip = opts["strip"]
3704 wlock = lock = tr = None
3699 wlock = lock = tr = None
3705 msgs = []
3700 msgs = []
3706
3701
3707 def tryone(ui, hunk, parents):
3708 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3709 patch.extract(ui, hunk)
3710
3711 if not tmpname:
3712 return (None, None)
3713 msg = _('applied to working directory')
3714
3715 try:
3716 cmdline_message = cmdutil.logmessage(ui, opts)
3717 if cmdline_message:
3718 # pickup the cmdline msg
3719 message = cmdline_message
3720 elif message:
3721 # pickup the patch msg
3722 message = message.strip()
3723 else:
3724 # launch the editor
3725 message = None
3726 ui.debug('message:\n%s\n' % message)
3727
3728 if len(parents) == 1:
3729 parents.append(repo[nullid])
3730 if opts.get('exact'):
3731 if not nodeid or not p1:
3732 raise util.Abort(_('not a Mercurial patch'))
3733 p1 = repo[p1]
3734 p2 = repo[p2 or nullid]
3735 elif p2:
3736 try:
3737 p1 = repo[p1]
3738 p2 = repo[p2]
3739 # Without any options, consider p2 only if the
3740 # patch is being applied on top of the recorded
3741 # first parent.
3742 if p1 != parents[0]:
3743 p1 = parents[0]
3744 p2 = repo[nullid]
3745 except error.RepoError:
3746 p1, p2 = parents
3747 else:
3748 p1, p2 = parents
3749
3750 n = None
3751 if update:
3752 if p1 != parents[0]:
3753 hg.clean(repo, p1.node())
3754 if p2 != parents[1]:
3755 repo.setparents(p1.node(), p2.node())
3756
3757 if opts.get('exact') or opts.get('import_branch'):
3758 repo.dirstate.setbranch(branch or 'default')
3759
3760 files = set()
3761 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3762 eolmode=None, similarity=sim / 100.0)
3763 files = list(files)
3764 if opts.get('no_commit'):
3765 if message:
3766 msgs.append(message)
3767 else:
3768 if opts.get('exact') or p2:
3769 # If you got here, you either use --force and know what
3770 # you are doing or used --exact or a merge patch while
3771 # being updated to its first parent.
3772 m = None
3773 else:
3774 m = scmutil.matchfiles(repo, files or [])
3775 n = repo.commit(message, opts.get('user') or user,
3776 opts.get('date') or date, match=m,
3777 editor=editor)
3778 else:
3779 if opts.get('exact') or opts.get('import_branch'):
3780 branch = branch or 'default'
3781 else:
3782 branch = p1.branch()
3783 store = patch.filestore()
3784 try:
3785 files = set()
3786 try:
3787 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3788 files, eolmode=None)
3789 except patch.PatchError, e:
3790 raise util.Abort(str(e))
3791 memctx = context.makememctx(repo, (p1.node(), p2.node()),
3792 message,
3793 opts.get('user') or user,
3794 opts.get('date') or date,
3795 branch, files, store,
3796 editor=cmdutil.commiteditor)
3797 repo.savecommitmessage(memctx.description())
3798 n = memctx.commit()
3799 finally:
3800 store.close()
3801 if opts.get('exact') and hex(n) != nodeid:
3802 raise util.Abort(_('patch is damaged or loses information'))
3803 if n:
3804 # i18n: refers to a short changeset id
3805 msg = _('created %s') % short(n)
3806 return (msg, n)
3807 finally:
3808 os.unlink(tmpname)
3809
3702
3810 try:
3703 try:
3811 try:
3704 try:
3812 wlock = repo.wlock()
3705 wlock = repo.wlock()
3813 if not opts.get('no_commit'):
3706 if not opts.get('no_commit'):
3814 lock = repo.lock()
3707 lock = repo.lock()
3815 tr = repo.transaction('import')
3708 tr = repo.transaction('import')
3816 parents = repo.parents()
3709 parents = repo.parents()
3817 for patchurl in patches:
3710 for patchurl in patches:
3818 if patchurl == '-':
3711 if patchurl == '-':
3819 ui.status(_('applying patch from stdin\n'))
3712 ui.status(_('applying patch from stdin\n'))
3820 patchfile = ui.fin
3713 patchfile = ui.fin
3821 patchurl = 'stdin' # for error message
3714 patchurl = 'stdin' # for error message
3822 else:
3715 else:
3823 patchurl = os.path.join(base, patchurl)
3716 patchurl = os.path.join(base, patchurl)
3824 ui.status(_('applying %s\n') % patchurl)
3717 ui.status(_('applying %s\n') % patchurl)
3825 patchfile = hg.openpath(ui, patchurl)
3718 patchfile = hg.openpath(ui, patchurl)
3826
3719
3827 haspatch = False
3720 haspatch = False
3828 for hunk in patch.split(patchfile):
3721 for hunk in patch.split(patchfile):
3829 (msg, node) = tryone(ui, hunk, parents)
3722 (msg, node) = cmdutil.tryimportone(ui, repo, hunk, parents,
3723 opts, msgs, hg.clean)
3830 if msg:
3724 if msg:
3831 haspatch = True
3725 haspatch = True
3832 ui.note(msg + '\n')
3726 ui.note(msg + '\n')
3833 if update or opts.get('exact'):
3727 if update or opts.get('exact'):
3834 parents = repo.parents()
3728 parents = repo.parents()
3835 else:
3729 else:
3836 parents = [repo[node]]
3730 parents = [repo[node]]
3837
3731
3838 if not haspatch:
3732 if not haspatch:
3839 raise util.Abort(_('%s: no diffs found') % patchurl)
3733 raise util.Abort(_('%s: no diffs found') % patchurl)
3840
3734
3841 if tr:
3735 if tr:
3842 tr.close()
3736 tr.close()
3843 if msgs:
3737 if msgs:
3844 repo.savecommitmessage('\n* * *\n'.join(msgs))
3738 repo.savecommitmessage('\n* * *\n'.join(msgs))
3845 except: # re-raises
3739 except: # re-raises
3846 # wlock.release() indirectly calls dirstate.write(): since
3740 # wlock.release() indirectly calls dirstate.write(): since
3847 # we're crashing, we do not want to change the working dir
3741 # we're crashing, we do not want to change the working dir
3848 # parent after all, so make sure it writes nothing
3742 # parent after all, so make sure it writes nothing
3849 repo.dirstate.invalidate()
3743 repo.dirstate.invalidate()
3850 raise
3744 raise
3851 finally:
3745 finally:
3852 if tr:
3746 if tr:
3853 tr.release()
3747 tr.release()
3854 release(lock, wlock)
3748 release(lock, wlock)
3855
3749
3856 @command('incoming|in',
3750 @command('incoming|in',
3857 [('f', 'force', None,
3751 [('f', 'force', None,
3858 _('run even if remote repository is unrelated')),
3752 _('run even if remote repository is unrelated')),
3859 ('n', 'newest-first', None, _('show newest record first')),
3753 ('n', 'newest-first', None, _('show newest record first')),
3860 ('', 'bundle', '',
3754 ('', 'bundle', '',
3861 _('file to store the bundles into'), _('FILE')),
3755 _('file to store the bundles into'), _('FILE')),
3862 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3756 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3863 ('B', 'bookmarks', False, _("compare bookmarks")),
3757 ('B', 'bookmarks', False, _("compare bookmarks")),
3864 ('b', 'branch', [],
3758 ('b', 'branch', [],
3865 _('a specific branch you would like to pull'), _('BRANCH')),
3759 _('a specific branch you would like to pull'), _('BRANCH')),
3866 ] + logopts + remoteopts + subrepoopts,
3760 ] + logopts + remoteopts + subrepoopts,
3867 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3761 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3868 def incoming(ui, repo, source="default", **opts):
3762 def incoming(ui, repo, source="default", **opts):
3869 """show new changesets found in source
3763 """show new changesets found in source
3870
3764
3871 Show new changesets found in the specified path/URL or the default
3765 Show new changesets found in the specified path/URL or the default
3872 pull location. These are the changesets that would have been pulled
3766 pull location. These are the changesets that would have been pulled
3873 if a pull at the time you issued this command.
3767 if a pull at the time you issued this command.
3874
3768
3875 For remote repository, using --bundle avoids downloading the
3769 For remote repository, using --bundle avoids downloading the
3876 changesets twice if the incoming is followed by a pull.
3770 changesets twice if the incoming is followed by a pull.
3877
3771
3878 See pull for valid source format details.
3772 See pull for valid source format details.
3879
3773
3880 Returns 0 if there are incoming changes, 1 otherwise.
3774 Returns 0 if there are incoming changes, 1 otherwise.
3881 """
3775 """
3882 if opts.get('graph'):
3776 if opts.get('graph'):
3883 cmdutil.checkunsupportedgraphflags([], opts)
3777 cmdutil.checkunsupportedgraphflags([], opts)
3884 def display(other, chlist, displayer):
3778 def display(other, chlist, displayer):
3885 revdag = cmdutil.graphrevs(other, chlist, opts)
3779 revdag = cmdutil.graphrevs(other, chlist, opts)
3886 showparents = [ctx.node() for ctx in repo[None].parents()]
3780 showparents = [ctx.node() for ctx in repo[None].parents()]
3887 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3781 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3888 graphmod.asciiedges)
3782 graphmod.asciiedges)
3889
3783
3890 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3784 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3891 return 0
3785 return 0
3892
3786
3893 if opts.get('bundle') and opts.get('subrepos'):
3787 if opts.get('bundle') and opts.get('subrepos'):
3894 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3788 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3895
3789
3896 if opts.get('bookmarks'):
3790 if opts.get('bookmarks'):
3897 source, branches = hg.parseurl(ui.expandpath(source),
3791 source, branches = hg.parseurl(ui.expandpath(source),
3898 opts.get('branch'))
3792 opts.get('branch'))
3899 other = hg.peer(repo, opts, source)
3793 other = hg.peer(repo, opts, source)
3900 if 'bookmarks' not in other.listkeys('namespaces'):
3794 if 'bookmarks' not in other.listkeys('namespaces'):
3901 ui.warn(_("remote doesn't support bookmarks\n"))
3795 ui.warn(_("remote doesn't support bookmarks\n"))
3902 return 0
3796 return 0
3903 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3797 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3904 return bookmarks.diff(ui, repo, other)
3798 return bookmarks.diff(ui, repo, other)
3905
3799
3906 repo._subtoppath = ui.expandpath(source)
3800 repo._subtoppath = ui.expandpath(source)
3907 try:
3801 try:
3908 return hg.incoming(ui, repo, source, opts)
3802 return hg.incoming(ui, repo, source, opts)
3909 finally:
3803 finally:
3910 del repo._subtoppath
3804 del repo._subtoppath
3911
3805
3912
3806
3913 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3807 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3914 def init(ui, dest=".", **opts):
3808 def init(ui, dest=".", **opts):
3915 """create a new repository in the given directory
3809 """create a new repository in the given directory
3916
3810
3917 Initialize a new repository in the given directory. If the given
3811 Initialize a new repository in the given directory. If the given
3918 directory does not exist, it will be created.
3812 directory does not exist, it will be created.
3919
3813
3920 If no directory is given, the current directory is used.
3814 If no directory is given, the current directory is used.
3921
3815
3922 It is possible to specify an ``ssh://`` URL as the destination.
3816 It is possible to specify an ``ssh://`` URL as the destination.
3923 See :hg:`help urls` for more information.
3817 See :hg:`help urls` for more information.
3924
3818
3925 Returns 0 on success.
3819 Returns 0 on success.
3926 """
3820 """
3927 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3821 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3928
3822
3929 @command('locate',
3823 @command('locate',
3930 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3824 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3931 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3825 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3932 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3826 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3933 ] + walkopts,
3827 ] + walkopts,
3934 _('[OPTION]... [PATTERN]...'))
3828 _('[OPTION]... [PATTERN]...'))
3935 def locate(ui, repo, *pats, **opts):
3829 def locate(ui, repo, *pats, **opts):
3936 """locate files matching specific patterns
3830 """locate files matching specific patterns
3937
3831
3938 Print files under Mercurial control in the working directory whose
3832 Print files under Mercurial control in the working directory whose
3939 names match the given patterns.
3833 names match the given patterns.
3940
3834
3941 By default, this command searches all directories in the working
3835 By default, this command searches all directories in the working
3942 directory. To search just the current directory and its
3836 directory. To search just the current directory and its
3943 subdirectories, use "--include .".
3837 subdirectories, use "--include .".
3944
3838
3945 If no patterns are given to match, this command prints the names
3839 If no patterns are given to match, this command prints the names
3946 of all files under Mercurial control in the working directory.
3840 of all files under Mercurial control in the working directory.
3947
3841
3948 If you want to feed the output of this command into the "xargs"
3842 If you want to feed the output of this command into the "xargs"
3949 command, use the -0 option to both this command and "xargs". This
3843 command, use the -0 option to both this command and "xargs". This
3950 will avoid the problem of "xargs" treating single filenames that
3844 will avoid the problem of "xargs" treating single filenames that
3951 contain whitespace as multiple filenames.
3845 contain whitespace as multiple filenames.
3952
3846
3953 Returns 0 if a match is found, 1 otherwise.
3847 Returns 0 if a match is found, 1 otherwise.
3954 """
3848 """
3955 end = opts.get('print0') and '\0' or '\n'
3849 end = opts.get('print0') and '\0' or '\n'
3956 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3850 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3957
3851
3958 ret = 1
3852 ret = 1
3959 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3853 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3960 m.bad = lambda x, y: False
3854 m.bad = lambda x, y: False
3961 for abs in repo[rev].walk(m):
3855 for abs in repo[rev].walk(m):
3962 if not rev and abs not in repo.dirstate:
3856 if not rev and abs not in repo.dirstate:
3963 continue
3857 continue
3964 if opts.get('fullpath'):
3858 if opts.get('fullpath'):
3965 ui.write(repo.wjoin(abs), end)
3859 ui.write(repo.wjoin(abs), end)
3966 else:
3860 else:
3967 ui.write(((pats and m.rel(abs)) or abs), end)
3861 ui.write(((pats and m.rel(abs)) or abs), end)
3968 ret = 0
3862 ret = 0
3969
3863
3970 return ret
3864 return ret
3971
3865
3972 @command('^log|history',
3866 @command('^log|history',
3973 [('f', 'follow', None,
3867 [('f', 'follow', None,
3974 _('follow changeset history, or file history across copies and renames')),
3868 _('follow changeset history, or file history across copies and renames')),
3975 ('', 'follow-first', None,
3869 ('', 'follow-first', None,
3976 _('only follow the first parent of merge changesets (DEPRECATED)')),
3870 _('only follow the first parent of merge changesets (DEPRECATED)')),
3977 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3871 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3978 ('C', 'copies', None, _('show copied files')),
3872 ('C', 'copies', None, _('show copied files')),
3979 ('k', 'keyword', [],
3873 ('k', 'keyword', [],
3980 _('do case-insensitive search for a given text'), _('TEXT')),
3874 _('do case-insensitive search for a given text'), _('TEXT')),
3981 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3875 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3982 ('', 'removed', None, _('include revisions where files were removed')),
3876 ('', 'removed', None, _('include revisions where files were removed')),
3983 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3877 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3984 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3878 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3985 ('', 'only-branch', [],
3879 ('', 'only-branch', [],
3986 _('show only changesets within the given named branch (DEPRECATED)'),
3880 _('show only changesets within the given named branch (DEPRECATED)'),
3987 _('BRANCH')),
3881 _('BRANCH')),
3988 ('b', 'branch', [],
3882 ('b', 'branch', [],
3989 _('show changesets within the given named branch'), _('BRANCH')),
3883 _('show changesets within the given named branch'), _('BRANCH')),
3990 ('P', 'prune', [],
3884 ('P', 'prune', [],
3991 _('do not display revision or any of its ancestors'), _('REV')),
3885 _('do not display revision or any of its ancestors'), _('REV')),
3992 ] + logopts + walkopts,
3886 ] + logopts + walkopts,
3993 _('[OPTION]... [FILE]'))
3887 _('[OPTION]... [FILE]'))
3994 def log(ui, repo, *pats, **opts):
3888 def log(ui, repo, *pats, **opts):
3995 """show revision history of entire repository or files
3889 """show revision history of entire repository or files
3996
3890
3997 Print the revision history of the specified files or the entire
3891 Print the revision history of the specified files or the entire
3998 project.
3892 project.
3999
3893
4000 If no revision range is specified, the default is ``tip:0`` unless
3894 If no revision range is specified, the default is ``tip:0`` unless
4001 --follow is set, in which case the working directory parent is
3895 --follow is set, in which case the working directory parent is
4002 used as the starting revision.
3896 used as the starting revision.
4003
3897
4004 File history is shown without following rename or copy history of
3898 File history is shown without following rename or copy history of
4005 files. Use -f/--follow with a filename to follow history across
3899 files. Use -f/--follow with a filename to follow history across
4006 renames and copies. --follow without a filename will only show
3900 renames and copies. --follow without a filename will only show
4007 ancestors or descendants of the starting revision.
3901 ancestors or descendants of the starting revision.
4008
3902
4009 By default this command prints revision number and changeset id,
3903 By default this command prints revision number and changeset id,
4010 tags, non-trivial parents, user, date and time, and a summary for
3904 tags, non-trivial parents, user, date and time, and a summary for
4011 each commit. When the -v/--verbose switch is used, the list of
3905 each commit. When the -v/--verbose switch is used, the list of
4012 changed files and full commit message are shown.
3906 changed files and full commit message are shown.
4013
3907
4014 .. note::
3908 .. note::
4015
3909
4016 log -p/--patch may generate unexpected diff output for merge
3910 log -p/--patch may generate unexpected diff output for merge
4017 changesets, as it will only compare the merge changeset against
3911 changesets, as it will only compare the merge changeset against
4018 its first parent. Also, only files different from BOTH parents
3912 its first parent. Also, only files different from BOTH parents
4019 will appear in files:.
3913 will appear in files:.
4020
3914
4021 .. note::
3915 .. note::
4022
3916
4023 for performance reasons, log FILE may omit duplicate changes
3917 for performance reasons, log FILE may omit duplicate changes
4024 made on branches and will not show deletions. To see all
3918 made on branches and will not show deletions. To see all
4025 changes including duplicates and deletions, use the --removed
3919 changes including duplicates and deletions, use the --removed
4026 switch.
3920 switch.
4027
3921
4028 .. container:: verbose
3922 .. container:: verbose
4029
3923
4030 Some examples:
3924 Some examples:
4031
3925
4032 - changesets with full descriptions and file lists::
3926 - changesets with full descriptions and file lists::
4033
3927
4034 hg log -v
3928 hg log -v
4035
3929
4036 - changesets ancestral to the working directory::
3930 - changesets ancestral to the working directory::
4037
3931
4038 hg log -f
3932 hg log -f
4039
3933
4040 - last 10 commits on the current branch::
3934 - last 10 commits on the current branch::
4041
3935
4042 hg log -l 10 -b .
3936 hg log -l 10 -b .
4043
3937
4044 - changesets showing all modifications of a file, including removals::
3938 - changesets showing all modifications of a file, including removals::
4045
3939
4046 hg log --removed file.c
3940 hg log --removed file.c
4047
3941
4048 - all changesets that touch a directory, with diffs, excluding merges::
3942 - all changesets that touch a directory, with diffs, excluding merges::
4049
3943
4050 hg log -Mp lib/
3944 hg log -Mp lib/
4051
3945
4052 - all revision numbers that match a keyword::
3946 - all revision numbers that match a keyword::
4053
3947
4054 hg log -k bug --template "{rev}\\n"
3948 hg log -k bug --template "{rev}\\n"
4055
3949
4056 - check if a given changeset is included is a tagged release::
3950 - check if a given changeset is included is a tagged release::
4057
3951
4058 hg log -r "a21ccf and ancestor(1.9)"
3952 hg log -r "a21ccf and ancestor(1.9)"
4059
3953
4060 - find all changesets by some user in a date range::
3954 - find all changesets by some user in a date range::
4061
3955
4062 hg log -k alice -d "may 2008 to jul 2008"
3956 hg log -k alice -d "may 2008 to jul 2008"
4063
3957
4064 - summary of all changesets after the last tag::
3958 - summary of all changesets after the last tag::
4065
3959
4066 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3960 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4067
3961
4068 See :hg:`help dates` for a list of formats valid for -d/--date.
3962 See :hg:`help dates` for a list of formats valid for -d/--date.
4069
3963
4070 See :hg:`help revisions` and :hg:`help revsets` for more about
3964 See :hg:`help revisions` and :hg:`help revsets` for more about
4071 specifying revisions.
3965 specifying revisions.
4072
3966
4073 See :hg:`help templates` for more about pre-packaged styles and
3967 See :hg:`help templates` for more about pre-packaged styles and
4074 specifying custom templates.
3968 specifying custom templates.
4075
3969
4076 Returns 0 on success.
3970 Returns 0 on success.
4077 """
3971 """
4078 if opts.get('graph'):
3972 if opts.get('graph'):
4079 return cmdutil.graphlog(ui, repo, *pats, **opts)
3973 return cmdutil.graphlog(ui, repo, *pats, **opts)
4080
3974
4081 matchfn = scmutil.match(repo[None], pats, opts)
3975 matchfn = scmutil.match(repo[None], pats, opts)
4082 limit = cmdutil.loglimit(opts)
3976 limit = cmdutil.loglimit(opts)
4083 count = 0
3977 count = 0
4084
3978
4085 getrenamed, endrev = None, None
3979 getrenamed, endrev = None, None
4086 if opts.get('copies'):
3980 if opts.get('copies'):
4087 if opts.get('rev'):
3981 if opts.get('rev'):
4088 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3982 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4089 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3983 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4090
3984
4091 df = False
3985 df = False
4092 if opts.get("date"):
3986 if opts.get("date"):
4093 df = util.matchdate(opts["date"])
3987 df = util.matchdate(opts["date"])
4094
3988
4095 branches = opts.get('branch', []) + opts.get('only_branch', [])
3989 branches = opts.get('branch', []) + opts.get('only_branch', [])
4096 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3990 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4097
3991
4098 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3992 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4099 def prep(ctx, fns):
3993 def prep(ctx, fns):
4100 rev = ctx.rev()
3994 rev = ctx.rev()
4101 parents = [p for p in repo.changelog.parentrevs(rev)
3995 parents = [p for p in repo.changelog.parentrevs(rev)
4102 if p != nullrev]
3996 if p != nullrev]
4103 if opts.get('no_merges') and len(parents) == 2:
3997 if opts.get('no_merges') and len(parents) == 2:
4104 return
3998 return
4105 if opts.get('only_merges') and len(parents) != 2:
3999 if opts.get('only_merges') and len(parents) != 2:
4106 return
4000 return
4107 if opts.get('branch') and ctx.branch() not in opts['branch']:
4001 if opts.get('branch') and ctx.branch() not in opts['branch']:
4108 return
4002 return
4109 if df and not df(ctx.date()[0]):
4003 if df and not df(ctx.date()[0]):
4110 return
4004 return
4111
4005
4112 lower = encoding.lower
4006 lower = encoding.lower
4113 if opts.get('user'):
4007 if opts.get('user'):
4114 luser = lower(ctx.user())
4008 luser = lower(ctx.user())
4115 for k in [lower(x) for x in opts['user']]:
4009 for k in [lower(x) for x in opts['user']]:
4116 if (k in luser):
4010 if (k in luser):
4117 break
4011 break
4118 else:
4012 else:
4119 return
4013 return
4120 if opts.get('keyword'):
4014 if opts.get('keyword'):
4121 luser = lower(ctx.user())
4015 luser = lower(ctx.user())
4122 ldesc = lower(ctx.description())
4016 ldesc = lower(ctx.description())
4123 lfiles = lower(" ".join(ctx.files()))
4017 lfiles = lower(" ".join(ctx.files()))
4124 for k in [lower(x) for x in opts['keyword']]:
4018 for k in [lower(x) for x in opts['keyword']]:
4125 if (k in luser or k in ldesc or k in lfiles):
4019 if (k in luser or k in ldesc or k in lfiles):
4126 break
4020 break
4127 else:
4021 else:
4128 return
4022 return
4129
4023
4130 copies = None
4024 copies = None
4131 if getrenamed is not None and rev:
4025 if getrenamed is not None and rev:
4132 copies = []
4026 copies = []
4133 for fn in ctx.files():
4027 for fn in ctx.files():
4134 rename = getrenamed(fn, rev)
4028 rename = getrenamed(fn, rev)
4135 if rename:
4029 if rename:
4136 copies.append((fn, rename[0]))
4030 copies.append((fn, rename[0]))
4137
4031
4138 revmatchfn = None
4032 revmatchfn = None
4139 if opts.get('patch') or opts.get('stat'):
4033 if opts.get('patch') or opts.get('stat'):
4140 if opts.get('follow') or opts.get('follow_first'):
4034 if opts.get('follow') or opts.get('follow_first'):
4141 # note: this might be wrong when following through merges
4035 # note: this might be wrong when following through merges
4142 revmatchfn = scmutil.match(repo[None], fns, default='path')
4036 revmatchfn = scmutil.match(repo[None], fns, default='path')
4143 else:
4037 else:
4144 revmatchfn = matchfn
4038 revmatchfn = matchfn
4145
4039
4146 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4040 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4147
4041
4148 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4042 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4149 if displayer.flush(ctx.rev()):
4043 if displayer.flush(ctx.rev()):
4150 count += 1
4044 count += 1
4151 if count == limit:
4045 if count == limit:
4152 break
4046 break
4153 displayer.close()
4047 displayer.close()
4154
4048
4155 @command('manifest',
4049 @command('manifest',
4156 [('r', 'rev', '', _('revision to display'), _('REV')),
4050 [('r', 'rev', '', _('revision to display'), _('REV')),
4157 ('', 'all', False, _("list files from all revisions"))],
4051 ('', 'all', False, _("list files from all revisions"))],
4158 _('[-r REV]'))
4052 _('[-r REV]'))
4159 def manifest(ui, repo, node=None, rev=None, **opts):
4053 def manifest(ui, repo, node=None, rev=None, **opts):
4160 """output the current or given revision of the project manifest
4054 """output the current or given revision of the project manifest
4161
4055
4162 Print a list of version controlled files for the given revision.
4056 Print a list of version controlled files for the given revision.
4163 If no revision is given, the first parent of the working directory
4057 If no revision is given, the first parent of the working directory
4164 is used, or the null revision if no revision is checked out.
4058 is used, or the null revision if no revision is checked out.
4165
4059
4166 With -v, print file permissions, symlink and executable bits.
4060 With -v, print file permissions, symlink and executable bits.
4167 With --debug, print file revision hashes.
4061 With --debug, print file revision hashes.
4168
4062
4169 If option --all is specified, the list of all files from all revisions
4063 If option --all is specified, the list of all files from all revisions
4170 is printed. This includes deleted and renamed files.
4064 is printed. This includes deleted and renamed files.
4171
4065
4172 Returns 0 on success.
4066 Returns 0 on success.
4173 """
4067 """
4174
4068
4175 fm = ui.formatter('manifest', opts)
4069 fm = ui.formatter('manifest', opts)
4176
4070
4177 if opts.get('all'):
4071 if opts.get('all'):
4178 if rev or node:
4072 if rev or node:
4179 raise util.Abort(_("can't specify a revision with --all"))
4073 raise util.Abort(_("can't specify a revision with --all"))
4180
4074
4181 res = []
4075 res = []
4182 prefix = "data/"
4076 prefix = "data/"
4183 suffix = ".i"
4077 suffix = ".i"
4184 plen = len(prefix)
4078 plen = len(prefix)
4185 slen = len(suffix)
4079 slen = len(suffix)
4186 lock = repo.lock()
4080 lock = repo.lock()
4187 try:
4081 try:
4188 for fn, b, size in repo.store.datafiles():
4082 for fn, b, size in repo.store.datafiles():
4189 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4083 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4190 res.append(fn[plen:-slen])
4084 res.append(fn[plen:-slen])
4191 finally:
4085 finally:
4192 lock.release()
4086 lock.release()
4193 for f in res:
4087 for f in res:
4194 fm.startitem()
4088 fm.startitem()
4195 fm.write("path", '%s\n', f)
4089 fm.write("path", '%s\n', f)
4196 fm.end()
4090 fm.end()
4197 return
4091 return
4198
4092
4199 if rev and node:
4093 if rev and node:
4200 raise util.Abort(_("please specify just one revision"))
4094 raise util.Abort(_("please specify just one revision"))
4201
4095
4202 if not node:
4096 if not node:
4203 node = rev
4097 node = rev
4204
4098
4205 char = {'l': '@', 'x': '*', '': ''}
4099 char = {'l': '@', 'x': '*', '': ''}
4206 mode = {'l': '644', 'x': '755', '': '644'}
4100 mode = {'l': '644', 'x': '755', '': '644'}
4207 ctx = scmutil.revsingle(repo, node)
4101 ctx = scmutil.revsingle(repo, node)
4208 mf = ctx.manifest()
4102 mf = ctx.manifest()
4209 for f in ctx:
4103 for f in ctx:
4210 fm.startitem()
4104 fm.startitem()
4211 fl = ctx[f].flags()
4105 fl = ctx[f].flags()
4212 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4106 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4213 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4107 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4214 fm.write('path', '%s\n', f)
4108 fm.write('path', '%s\n', f)
4215 fm.end()
4109 fm.end()
4216
4110
4217 @command('^merge',
4111 @command('^merge',
4218 [('f', 'force', None,
4112 [('f', 'force', None,
4219 _('force a merge including outstanding changes (DEPRECATED)')),
4113 _('force a merge including outstanding changes (DEPRECATED)')),
4220 ('r', 'rev', '', _('revision to merge'), _('REV')),
4114 ('r', 'rev', '', _('revision to merge'), _('REV')),
4221 ('P', 'preview', None,
4115 ('P', 'preview', None,
4222 _('review revisions to merge (no merge is performed)'))
4116 _('review revisions to merge (no merge is performed)'))
4223 ] + mergetoolopts,
4117 ] + mergetoolopts,
4224 _('[-P] [-f] [[-r] REV]'))
4118 _('[-P] [-f] [[-r] REV]'))
4225 def merge(ui, repo, node=None, **opts):
4119 def merge(ui, repo, node=None, **opts):
4226 """merge working directory with another revision
4120 """merge working directory with another revision
4227
4121
4228 The current working directory is updated with all changes made in
4122 The current working directory is updated with all changes made in
4229 the requested revision since the last common predecessor revision.
4123 the requested revision since the last common predecessor revision.
4230
4124
4231 Files that changed between either parent are marked as changed for
4125 Files that changed between either parent are marked as changed for
4232 the next commit and a commit must be performed before any further
4126 the next commit and a commit must be performed before any further
4233 updates to the repository are allowed. The next commit will have
4127 updates to the repository are allowed. The next commit will have
4234 two parents.
4128 two parents.
4235
4129
4236 ``--tool`` can be used to specify the merge tool used for file
4130 ``--tool`` can be used to specify the merge tool used for file
4237 merges. It overrides the HGMERGE environment variable and your
4131 merges. It overrides the HGMERGE environment variable and your
4238 configuration files. See :hg:`help merge-tools` for options.
4132 configuration files. See :hg:`help merge-tools` for options.
4239
4133
4240 If no revision is specified, the working directory's parent is a
4134 If no revision is specified, the working directory's parent is a
4241 head revision, and the current branch contains exactly one other
4135 head revision, and the current branch contains exactly one other
4242 head, the other head is merged with by default. Otherwise, an
4136 head, the other head is merged with by default. Otherwise, an
4243 explicit revision with which to merge with must be provided.
4137 explicit revision with which to merge with must be provided.
4244
4138
4245 :hg:`resolve` must be used to resolve unresolved files.
4139 :hg:`resolve` must be used to resolve unresolved files.
4246
4140
4247 To undo an uncommitted merge, use :hg:`update --clean .` which
4141 To undo an uncommitted merge, use :hg:`update --clean .` which
4248 will check out a clean copy of the original merge parent, losing
4142 will check out a clean copy of the original merge parent, losing
4249 all changes.
4143 all changes.
4250
4144
4251 Returns 0 on success, 1 if there are unresolved files.
4145 Returns 0 on success, 1 if there are unresolved files.
4252 """
4146 """
4253
4147
4254 if opts.get('rev') and node:
4148 if opts.get('rev') and node:
4255 raise util.Abort(_("please specify just one revision"))
4149 raise util.Abort(_("please specify just one revision"))
4256 if not node:
4150 if not node:
4257 node = opts.get('rev')
4151 node = opts.get('rev')
4258
4152
4259 if node:
4153 if node:
4260 node = scmutil.revsingle(repo, node).node()
4154 node = scmutil.revsingle(repo, node).node()
4261
4155
4262 if not node and repo._bookmarkcurrent:
4156 if not node and repo._bookmarkcurrent:
4263 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4157 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4264 curhead = repo[repo._bookmarkcurrent].node()
4158 curhead = repo[repo._bookmarkcurrent].node()
4265 if len(bmheads) == 2:
4159 if len(bmheads) == 2:
4266 if curhead == bmheads[0]:
4160 if curhead == bmheads[0]:
4267 node = bmheads[1]
4161 node = bmheads[1]
4268 else:
4162 else:
4269 node = bmheads[0]
4163 node = bmheads[0]
4270 elif len(bmheads) > 2:
4164 elif len(bmheads) > 2:
4271 raise util.Abort(_("multiple matching bookmarks to merge - "
4165 raise util.Abort(_("multiple matching bookmarks to merge - "
4272 "please merge with an explicit rev or bookmark"),
4166 "please merge with an explicit rev or bookmark"),
4273 hint=_("run 'hg heads' to see all heads"))
4167 hint=_("run 'hg heads' to see all heads"))
4274 elif len(bmheads) <= 1:
4168 elif len(bmheads) <= 1:
4275 raise util.Abort(_("no matching bookmark to merge - "
4169 raise util.Abort(_("no matching bookmark to merge - "
4276 "please merge with an explicit rev or bookmark"),
4170 "please merge with an explicit rev or bookmark"),
4277 hint=_("run 'hg heads' to see all heads"))
4171 hint=_("run 'hg heads' to see all heads"))
4278
4172
4279 if not node and not repo._bookmarkcurrent:
4173 if not node and not repo._bookmarkcurrent:
4280 branch = repo[None].branch()
4174 branch = repo[None].branch()
4281 bheads = repo.branchheads(branch)
4175 bheads = repo.branchheads(branch)
4282 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4176 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4283
4177
4284 if len(nbhs) > 2:
4178 if len(nbhs) > 2:
4285 raise util.Abort(_("branch '%s' has %d heads - "
4179 raise util.Abort(_("branch '%s' has %d heads - "
4286 "please merge with an explicit rev")
4180 "please merge with an explicit rev")
4287 % (branch, len(bheads)),
4181 % (branch, len(bheads)),
4288 hint=_("run 'hg heads .' to see heads"))
4182 hint=_("run 'hg heads .' to see heads"))
4289
4183
4290 parent = repo.dirstate.p1()
4184 parent = repo.dirstate.p1()
4291 if len(nbhs) <= 1:
4185 if len(nbhs) <= 1:
4292 if len(bheads) > 1:
4186 if len(bheads) > 1:
4293 raise util.Abort(_("heads are bookmarked - "
4187 raise util.Abort(_("heads are bookmarked - "
4294 "please merge with an explicit rev"),
4188 "please merge with an explicit rev"),
4295 hint=_("run 'hg heads' to see all heads"))
4189 hint=_("run 'hg heads' to see all heads"))
4296 if len(repo.heads()) > 1:
4190 if len(repo.heads()) > 1:
4297 raise util.Abort(_("branch '%s' has one head - "
4191 raise util.Abort(_("branch '%s' has one head - "
4298 "please merge with an explicit rev")
4192 "please merge with an explicit rev")
4299 % branch,
4193 % branch,
4300 hint=_("run 'hg heads' to see all heads"))
4194 hint=_("run 'hg heads' to see all heads"))
4301 msg, hint = _('nothing to merge'), None
4195 msg, hint = _('nothing to merge'), None
4302 if parent != repo.lookup(branch):
4196 if parent != repo.lookup(branch):
4303 hint = _("use 'hg update' instead")
4197 hint = _("use 'hg update' instead")
4304 raise util.Abort(msg, hint=hint)
4198 raise util.Abort(msg, hint=hint)
4305
4199
4306 if parent not in bheads:
4200 if parent not in bheads:
4307 raise util.Abort(_('working directory not at a head revision'),
4201 raise util.Abort(_('working directory not at a head revision'),
4308 hint=_("use 'hg update' or merge with an "
4202 hint=_("use 'hg update' or merge with an "
4309 "explicit revision"))
4203 "explicit revision"))
4310 if parent == nbhs[0]:
4204 if parent == nbhs[0]:
4311 node = nbhs[-1]
4205 node = nbhs[-1]
4312 else:
4206 else:
4313 node = nbhs[0]
4207 node = nbhs[0]
4314
4208
4315 if opts.get('preview'):
4209 if opts.get('preview'):
4316 # find nodes that are ancestors of p2 but not of p1
4210 # find nodes that are ancestors of p2 but not of p1
4317 p1 = repo.lookup('.')
4211 p1 = repo.lookup('.')
4318 p2 = repo.lookup(node)
4212 p2 = repo.lookup(node)
4319 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4213 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4320
4214
4321 displayer = cmdutil.show_changeset(ui, repo, opts)
4215 displayer = cmdutil.show_changeset(ui, repo, opts)
4322 for node in nodes:
4216 for node in nodes:
4323 displayer.show(repo[node])
4217 displayer.show(repo[node])
4324 displayer.close()
4218 displayer.close()
4325 return 0
4219 return 0
4326
4220
4327 try:
4221 try:
4328 # ui.forcemerge is an internal variable, do not document
4222 # ui.forcemerge is an internal variable, do not document
4329 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4223 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4330 return hg.merge(repo, node, force=opts.get('force'))
4224 return hg.merge(repo, node, force=opts.get('force'))
4331 finally:
4225 finally:
4332 ui.setconfig('ui', 'forcemerge', '')
4226 ui.setconfig('ui', 'forcemerge', '')
4333
4227
4334 @command('outgoing|out',
4228 @command('outgoing|out',
4335 [('f', 'force', None, _('run even when the destination is unrelated')),
4229 [('f', 'force', None, _('run even when the destination is unrelated')),
4336 ('r', 'rev', [],
4230 ('r', 'rev', [],
4337 _('a changeset intended to be included in the destination'), _('REV')),
4231 _('a changeset intended to be included in the destination'), _('REV')),
4338 ('n', 'newest-first', None, _('show newest record first')),
4232 ('n', 'newest-first', None, _('show newest record first')),
4339 ('B', 'bookmarks', False, _('compare bookmarks')),
4233 ('B', 'bookmarks', False, _('compare bookmarks')),
4340 ('b', 'branch', [], _('a specific branch you would like to push'),
4234 ('b', 'branch', [], _('a specific branch you would like to push'),
4341 _('BRANCH')),
4235 _('BRANCH')),
4342 ] + logopts + remoteopts + subrepoopts,
4236 ] + logopts + remoteopts + subrepoopts,
4343 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4237 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4344 def outgoing(ui, repo, dest=None, **opts):
4238 def outgoing(ui, repo, dest=None, **opts):
4345 """show changesets not found in the destination
4239 """show changesets not found in the destination
4346
4240
4347 Show changesets not found in the specified destination repository
4241 Show changesets not found in the specified destination repository
4348 or the default push location. These are the changesets that would
4242 or the default push location. These are the changesets that would
4349 be pushed if a push was requested.
4243 be pushed if a push was requested.
4350
4244
4351 See pull for details of valid destination formats.
4245 See pull for details of valid destination formats.
4352
4246
4353 Returns 0 if there are outgoing changes, 1 otherwise.
4247 Returns 0 if there are outgoing changes, 1 otherwise.
4354 """
4248 """
4355 if opts.get('graph'):
4249 if opts.get('graph'):
4356 cmdutil.checkunsupportedgraphflags([], opts)
4250 cmdutil.checkunsupportedgraphflags([], opts)
4357 o = hg._outgoing(ui, repo, dest, opts)
4251 o = hg._outgoing(ui, repo, dest, opts)
4358 if o is None:
4252 if o is None:
4359 return
4253 return
4360
4254
4361 revdag = cmdutil.graphrevs(repo, o, opts)
4255 revdag = cmdutil.graphrevs(repo, o, opts)
4362 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4256 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4363 showparents = [ctx.node() for ctx in repo[None].parents()]
4257 showparents = [ctx.node() for ctx in repo[None].parents()]
4364 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4258 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4365 graphmod.asciiedges)
4259 graphmod.asciiedges)
4366 return 0
4260 return 0
4367
4261
4368 if opts.get('bookmarks'):
4262 if opts.get('bookmarks'):
4369 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4263 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4370 dest, branches = hg.parseurl(dest, opts.get('branch'))
4264 dest, branches = hg.parseurl(dest, opts.get('branch'))
4371 other = hg.peer(repo, opts, dest)
4265 other = hg.peer(repo, opts, dest)
4372 if 'bookmarks' not in other.listkeys('namespaces'):
4266 if 'bookmarks' not in other.listkeys('namespaces'):
4373 ui.warn(_("remote doesn't support bookmarks\n"))
4267 ui.warn(_("remote doesn't support bookmarks\n"))
4374 return 0
4268 return 0
4375 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4269 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4376 return bookmarks.diff(ui, other, repo)
4270 return bookmarks.diff(ui, other, repo)
4377
4271
4378 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4272 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4379 try:
4273 try:
4380 return hg.outgoing(ui, repo, dest, opts)
4274 return hg.outgoing(ui, repo, dest, opts)
4381 finally:
4275 finally:
4382 del repo._subtoppath
4276 del repo._subtoppath
4383
4277
4384 @command('parents',
4278 @command('parents',
4385 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4279 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4386 ] + templateopts,
4280 ] + templateopts,
4387 _('[-r REV] [FILE]'))
4281 _('[-r REV] [FILE]'))
4388 def parents(ui, repo, file_=None, **opts):
4282 def parents(ui, repo, file_=None, **opts):
4389 """show the parents of the working directory or revision
4283 """show the parents of the working directory or revision
4390
4284
4391 Print the working directory's parent revisions. If a revision is
4285 Print the working directory's parent revisions. If a revision is
4392 given via -r/--rev, the parent of that revision will be printed.
4286 given via -r/--rev, the parent of that revision will be printed.
4393 If a file argument is given, the revision in which the file was
4287 If a file argument is given, the revision in which the file was
4394 last changed (before the working directory revision or the
4288 last changed (before the working directory revision or the
4395 argument to --rev if given) is printed.
4289 argument to --rev if given) is printed.
4396
4290
4397 Returns 0 on success.
4291 Returns 0 on success.
4398 """
4292 """
4399
4293
4400 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4294 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4401
4295
4402 if file_:
4296 if file_:
4403 m = scmutil.match(ctx, (file_,), opts)
4297 m = scmutil.match(ctx, (file_,), opts)
4404 if m.anypats() or len(m.files()) != 1:
4298 if m.anypats() or len(m.files()) != 1:
4405 raise util.Abort(_('can only specify an explicit filename'))
4299 raise util.Abort(_('can only specify an explicit filename'))
4406 file_ = m.files()[0]
4300 file_ = m.files()[0]
4407 filenodes = []
4301 filenodes = []
4408 for cp in ctx.parents():
4302 for cp in ctx.parents():
4409 if not cp:
4303 if not cp:
4410 continue
4304 continue
4411 try:
4305 try:
4412 filenodes.append(cp.filenode(file_))
4306 filenodes.append(cp.filenode(file_))
4413 except error.LookupError:
4307 except error.LookupError:
4414 pass
4308 pass
4415 if not filenodes:
4309 if not filenodes:
4416 raise util.Abort(_("'%s' not found in manifest!") % file_)
4310 raise util.Abort(_("'%s' not found in manifest!") % file_)
4417 p = []
4311 p = []
4418 for fn in filenodes:
4312 for fn in filenodes:
4419 fctx = repo.filectx(file_, fileid=fn)
4313 fctx = repo.filectx(file_, fileid=fn)
4420 p.append(fctx.node())
4314 p.append(fctx.node())
4421 else:
4315 else:
4422 p = [cp.node() for cp in ctx.parents()]
4316 p = [cp.node() for cp in ctx.parents()]
4423
4317
4424 displayer = cmdutil.show_changeset(ui, repo, opts)
4318 displayer = cmdutil.show_changeset(ui, repo, opts)
4425 for n in p:
4319 for n in p:
4426 if n != nullid:
4320 if n != nullid:
4427 displayer.show(repo[n])
4321 displayer.show(repo[n])
4428 displayer.close()
4322 displayer.close()
4429
4323
4430 @command('paths', [], _('[NAME]'))
4324 @command('paths', [], _('[NAME]'))
4431 def paths(ui, repo, search=None):
4325 def paths(ui, repo, search=None):
4432 """show aliases for remote repositories
4326 """show aliases for remote repositories
4433
4327
4434 Show definition of symbolic path name NAME. If no name is given,
4328 Show definition of symbolic path name NAME. If no name is given,
4435 show definition of all available names.
4329 show definition of all available names.
4436
4330
4437 Option -q/--quiet suppresses all output when searching for NAME
4331 Option -q/--quiet suppresses all output when searching for NAME
4438 and shows only the path names when listing all definitions.
4332 and shows only the path names when listing all definitions.
4439
4333
4440 Path names are defined in the [paths] section of your
4334 Path names are defined in the [paths] section of your
4441 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4335 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4442 repository, ``.hg/hgrc`` is used, too.
4336 repository, ``.hg/hgrc`` is used, too.
4443
4337
4444 The path names ``default`` and ``default-push`` have a special
4338 The path names ``default`` and ``default-push`` have a special
4445 meaning. When performing a push or pull operation, they are used
4339 meaning. When performing a push or pull operation, they are used
4446 as fallbacks if no location is specified on the command-line.
4340 as fallbacks if no location is specified on the command-line.
4447 When ``default-push`` is set, it will be used for push and
4341 When ``default-push`` is set, it will be used for push and
4448 ``default`` will be used for pull; otherwise ``default`` is used
4342 ``default`` will be used for pull; otherwise ``default`` is used
4449 as the fallback for both. When cloning a repository, the clone
4343 as the fallback for both. When cloning a repository, the clone
4450 source is written as ``default`` in ``.hg/hgrc``. Note that
4344 source is written as ``default`` in ``.hg/hgrc``. Note that
4451 ``default`` and ``default-push`` apply to all inbound (e.g.
4345 ``default`` and ``default-push`` apply to all inbound (e.g.
4452 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4346 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4453 :hg:`bundle`) operations.
4347 :hg:`bundle`) operations.
4454
4348
4455 See :hg:`help urls` for more information.
4349 See :hg:`help urls` for more information.
4456
4350
4457 Returns 0 on success.
4351 Returns 0 on success.
4458 """
4352 """
4459 if search:
4353 if search:
4460 for name, path in ui.configitems("paths"):
4354 for name, path in ui.configitems("paths"):
4461 if name == search:
4355 if name == search:
4462 ui.status("%s\n" % util.hidepassword(path))
4356 ui.status("%s\n" % util.hidepassword(path))
4463 return
4357 return
4464 if not ui.quiet:
4358 if not ui.quiet:
4465 ui.warn(_("not found!\n"))
4359 ui.warn(_("not found!\n"))
4466 return 1
4360 return 1
4467 else:
4361 else:
4468 for name, path in ui.configitems("paths"):
4362 for name, path in ui.configitems("paths"):
4469 if ui.quiet:
4363 if ui.quiet:
4470 ui.write("%s\n" % name)
4364 ui.write("%s\n" % name)
4471 else:
4365 else:
4472 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4366 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4473
4367
4474 @command('phase',
4368 @command('phase',
4475 [('p', 'public', False, _('set changeset phase to public')),
4369 [('p', 'public', False, _('set changeset phase to public')),
4476 ('d', 'draft', False, _('set changeset phase to draft')),
4370 ('d', 'draft', False, _('set changeset phase to draft')),
4477 ('s', 'secret', False, _('set changeset phase to secret')),
4371 ('s', 'secret', False, _('set changeset phase to secret')),
4478 ('f', 'force', False, _('allow to move boundary backward')),
4372 ('f', 'force', False, _('allow to move boundary backward')),
4479 ('r', 'rev', [], _('target revision'), _('REV')),
4373 ('r', 'rev', [], _('target revision'), _('REV')),
4480 ],
4374 ],
4481 _('[-p|-d|-s] [-f] [-r] REV...'))
4375 _('[-p|-d|-s] [-f] [-r] REV...'))
4482 def phase(ui, repo, *revs, **opts):
4376 def phase(ui, repo, *revs, **opts):
4483 """set or show the current phase name
4377 """set or show the current phase name
4484
4378
4485 With no argument, show the phase name of specified revisions.
4379 With no argument, show the phase name of specified revisions.
4486
4380
4487 With one of -p/--public, -d/--draft or -s/--secret, change the
4381 With one of -p/--public, -d/--draft or -s/--secret, change the
4488 phase value of the specified revisions.
4382 phase value of the specified revisions.
4489
4383
4490 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4384 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4491 lower phase to an higher phase. Phases are ordered as follows::
4385 lower phase to an higher phase. Phases are ordered as follows::
4492
4386
4493 public < draft < secret
4387 public < draft < secret
4494
4388
4495 Return 0 on success, 1 if no phases were changed or some could not
4389 Return 0 on success, 1 if no phases were changed or some could not
4496 be changed.
4390 be changed.
4497 """
4391 """
4498 # search for a unique phase argument
4392 # search for a unique phase argument
4499 targetphase = None
4393 targetphase = None
4500 for idx, name in enumerate(phases.phasenames):
4394 for idx, name in enumerate(phases.phasenames):
4501 if opts[name]:
4395 if opts[name]:
4502 if targetphase is not None:
4396 if targetphase is not None:
4503 raise util.Abort(_('only one phase can be specified'))
4397 raise util.Abort(_('only one phase can be specified'))
4504 targetphase = idx
4398 targetphase = idx
4505
4399
4506 # look for specified revision
4400 # look for specified revision
4507 revs = list(revs)
4401 revs = list(revs)
4508 revs.extend(opts['rev'])
4402 revs.extend(opts['rev'])
4509 if not revs:
4403 if not revs:
4510 raise util.Abort(_('no revisions specified'))
4404 raise util.Abort(_('no revisions specified'))
4511
4405
4512 revs = scmutil.revrange(repo, revs)
4406 revs = scmutil.revrange(repo, revs)
4513
4407
4514 lock = None
4408 lock = None
4515 ret = 0
4409 ret = 0
4516 if targetphase is None:
4410 if targetphase is None:
4517 # display
4411 # display
4518 for r in revs:
4412 for r in revs:
4519 ctx = repo[r]
4413 ctx = repo[r]
4520 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4414 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4521 else:
4415 else:
4522 lock = repo.lock()
4416 lock = repo.lock()
4523 try:
4417 try:
4524 # set phase
4418 # set phase
4525 if not revs:
4419 if not revs:
4526 raise util.Abort(_('empty revision set'))
4420 raise util.Abort(_('empty revision set'))
4527 nodes = [repo[r].node() for r in revs]
4421 nodes = [repo[r].node() for r in revs]
4528 olddata = repo._phasecache.getphaserevs(repo)[:]
4422 olddata = repo._phasecache.getphaserevs(repo)[:]
4529 phases.advanceboundary(repo, targetphase, nodes)
4423 phases.advanceboundary(repo, targetphase, nodes)
4530 if opts['force']:
4424 if opts['force']:
4531 phases.retractboundary(repo, targetphase, nodes)
4425 phases.retractboundary(repo, targetphase, nodes)
4532 finally:
4426 finally:
4533 lock.release()
4427 lock.release()
4534 # moving revision from public to draft may hide them
4428 # moving revision from public to draft may hide them
4535 # We have to check result on an unfiltered repository
4429 # We have to check result on an unfiltered repository
4536 unfi = repo.unfiltered()
4430 unfi = repo.unfiltered()
4537 newdata = repo._phasecache.getphaserevs(unfi)
4431 newdata = repo._phasecache.getphaserevs(unfi)
4538 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4432 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4539 cl = unfi.changelog
4433 cl = unfi.changelog
4540 rejected = [n for n in nodes
4434 rejected = [n for n in nodes
4541 if newdata[cl.rev(n)] < targetphase]
4435 if newdata[cl.rev(n)] < targetphase]
4542 if rejected:
4436 if rejected:
4543 ui.warn(_('cannot move %i changesets to a higher '
4437 ui.warn(_('cannot move %i changesets to a higher '
4544 'phase, use --force\n') % len(rejected))
4438 'phase, use --force\n') % len(rejected))
4545 ret = 1
4439 ret = 1
4546 if changes:
4440 if changes:
4547 msg = _('phase changed for %i changesets\n') % changes
4441 msg = _('phase changed for %i changesets\n') % changes
4548 if ret:
4442 if ret:
4549 ui.status(msg)
4443 ui.status(msg)
4550 else:
4444 else:
4551 ui.note(msg)
4445 ui.note(msg)
4552 else:
4446 else:
4553 ui.warn(_('no phases changed\n'))
4447 ui.warn(_('no phases changed\n'))
4554 ret = 1
4448 ret = 1
4555 return ret
4449 return ret
4556
4450
4557 def postincoming(ui, repo, modheads, optupdate, checkout):
4451 def postincoming(ui, repo, modheads, optupdate, checkout):
4558 if modheads == 0:
4452 if modheads == 0:
4559 return
4453 return
4560 if optupdate:
4454 if optupdate:
4561 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4455 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4562 try:
4456 try:
4563 ret = hg.update(repo, checkout)
4457 ret = hg.update(repo, checkout)
4564 except util.Abort, inst:
4458 except util.Abort, inst:
4565 ui.warn(_("not updating: %s\n") % str(inst))
4459 ui.warn(_("not updating: %s\n") % str(inst))
4566 if inst.hint:
4460 if inst.hint:
4567 ui.warn(_("(%s)\n") % inst.hint)
4461 ui.warn(_("(%s)\n") % inst.hint)
4568 return 0
4462 return 0
4569 if not ret and not checkout:
4463 if not ret and not checkout:
4570 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4464 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4571 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4465 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4572 return ret
4466 return ret
4573 if modheads > 1:
4467 if modheads > 1:
4574 currentbranchheads = len(repo.branchheads())
4468 currentbranchheads = len(repo.branchheads())
4575 if currentbranchheads == modheads:
4469 if currentbranchheads == modheads:
4576 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4470 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4577 elif currentbranchheads > 1:
4471 elif currentbranchheads > 1:
4578 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4472 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4579 "merge)\n"))
4473 "merge)\n"))
4580 else:
4474 else:
4581 ui.status(_("(run 'hg heads' to see heads)\n"))
4475 ui.status(_("(run 'hg heads' to see heads)\n"))
4582 else:
4476 else:
4583 ui.status(_("(run 'hg update' to get a working copy)\n"))
4477 ui.status(_("(run 'hg update' to get a working copy)\n"))
4584
4478
4585 @command('^pull',
4479 @command('^pull',
4586 [('u', 'update', None,
4480 [('u', 'update', None,
4587 _('update to new branch head if changesets were pulled')),
4481 _('update to new branch head if changesets were pulled')),
4588 ('f', 'force', None, _('run even when remote repository is unrelated')),
4482 ('f', 'force', None, _('run even when remote repository is unrelated')),
4589 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4483 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4590 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4484 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4591 ('b', 'branch', [], _('a specific branch you would like to pull'),
4485 ('b', 'branch', [], _('a specific branch you would like to pull'),
4592 _('BRANCH')),
4486 _('BRANCH')),
4593 ] + remoteopts,
4487 ] + remoteopts,
4594 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4488 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4595 def pull(ui, repo, source="default", **opts):
4489 def pull(ui, repo, source="default", **opts):
4596 """pull changes from the specified source
4490 """pull changes from the specified source
4597
4491
4598 Pull changes from a remote repository to a local one.
4492 Pull changes from a remote repository to a local one.
4599
4493
4600 This finds all changes from the repository at the specified path
4494 This finds all changes from the repository at the specified path
4601 or URL and adds them to a local repository (the current one unless
4495 or URL and adds them to a local repository (the current one unless
4602 -R is specified). By default, this does not update the copy of the
4496 -R is specified). By default, this does not update the copy of the
4603 project in the working directory.
4497 project in the working directory.
4604
4498
4605 Use :hg:`incoming` if you want to see what would have been added
4499 Use :hg:`incoming` if you want to see what would have been added
4606 by a pull at the time you issued this command. If you then decide
4500 by a pull at the time you issued this command. If you then decide
4607 to add those changes to the repository, you should use :hg:`pull
4501 to add those changes to the repository, you should use :hg:`pull
4608 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4502 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4609
4503
4610 If SOURCE is omitted, the 'default' path will be used.
4504 If SOURCE is omitted, the 'default' path will be used.
4611 See :hg:`help urls` for more information.
4505 See :hg:`help urls` for more information.
4612
4506
4613 Returns 0 on success, 1 if an update had unresolved files.
4507 Returns 0 on success, 1 if an update had unresolved files.
4614 """
4508 """
4615 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4509 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4616 other = hg.peer(repo, opts, source)
4510 other = hg.peer(repo, opts, source)
4617 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4511 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4618 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4512 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4619
4513
4620 remotebookmarks = other.listkeys('bookmarks')
4514 remotebookmarks = other.listkeys('bookmarks')
4621
4515
4622 if opts.get('bookmark'):
4516 if opts.get('bookmark'):
4623 if not revs:
4517 if not revs:
4624 revs = []
4518 revs = []
4625 for b in opts['bookmark']:
4519 for b in opts['bookmark']:
4626 if b not in remotebookmarks:
4520 if b not in remotebookmarks:
4627 raise util.Abort(_('remote bookmark %s not found!') % b)
4521 raise util.Abort(_('remote bookmark %s not found!') % b)
4628 revs.append(remotebookmarks[b])
4522 revs.append(remotebookmarks[b])
4629
4523
4630 if revs:
4524 if revs:
4631 try:
4525 try:
4632 revs = [other.lookup(rev) for rev in revs]
4526 revs = [other.lookup(rev) for rev in revs]
4633 except error.CapabilityError:
4527 except error.CapabilityError:
4634 err = _("other repository doesn't support revision lookup, "
4528 err = _("other repository doesn't support revision lookup, "
4635 "so a rev cannot be specified.")
4529 "so a rev cannot be specified.")
4636 raise util.Abort(err)
4530 raise util.Abort(err)
4637
4531
4638 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4532 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4639 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4533 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4640 if checkout:
4534 if checkout:
4641 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4535 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4642 repo._subtoppath = source
4536 repo._subtoppath = source
4643 try:
4537 try:
4644 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4538 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4645
4539
4646 finally:
4540 finally:
4647 del repo._subtoppath
4541 del repo._subtoppath
4648
4542
4649 # update specified bookmarks
4543 # update specified bookmarks
4650 if opts.get('bookmark'):
4544 if opts.get('bookmark'):
4651 marks = repo._bookmarks
4545 marks = repo._bookmarks
4652 for b in opts['bookmark']:
4546 for b in opts['bookmark']:
4653 # explicit pull overrides local bookmark if any
4547 # explicit pull overrides local bookmark if any
4654 ui.status(_("importing bookmark %s\n") % b)
4548 ui.status(_("importing bookmark %s\n") % b)
4655 marks[b] = repo[remotebookmarks[b]].node()
4549 marks[b] = repo[remotebookmarks[b]].node()
4656 marks.write()
4550 marks.write()
4657
4551
4658 return ret
4552 return ret
4659
4553
4660 @command('^push',
4554 @command('^push',
4661 [('f', 'force', None, _('force push')),
4555 [('f', 'force', None, _('force push')),
4662 ('r', 'rev', [],
4556 ('r', 'rev', [],
4663 _('a changeset intended to be included in the destination'),
4557 _('a changeset intended to be included in the destination'),
4664 _('REV')),
4558 _('REV')),
4665 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4559 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4666 ('b', 'branch', [],
4560 ('b', 'branch', [],
4667 _('a specific branch you would like to push'), _('BRANCH')),
4561 _('a specific branch you would like to push'), _('BRANCH')),
4668 ('', 'new-branch', False, _('allow pushing a new branch')),
4562 ('', 'new-branch', False, _('allow pushing a new branch')),
4669 ] + remoteopts,
4563 ] + remoteopts,
4670 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4564 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4671 def push(ui, repo, dest=None, **opts):
4565 def push(ui, repo, dest=None, **opts):
4672 """push changes to the specified destination
4566 """push changes to the specified destination
4673
4567
4674 Push changesets from the local repository to the specified
4568 Push changesets from the local repository to the specified
4675 destination.
4569 destination.
4676
4570
4677 This operation is symmetrical to pull: it is identical to a pull
4571 This operation is symmetrical to pull: it is identical to a pull
4678 in the destination repository from the current one.
4572 in the destination repository from the current one.
4679
4573
4680 By default, push will not allow creation of new heads at the
4574 By default, push will not allow creation of new heads at the
4681 destination, since multiple heads would make it unclear which head
4575 destination, since multiple heads would make it unclear which head
4682 to use. In this situation, it is recommended to pull and merge
4576 to use. In this situation, it is recommended to pull and merge
4683 before pushing.
4577 before pushing.
4684
4578
4685 Use --new-branch if you want to allow push to create a new named
4579 Use --new-branch if you want to allow push to create a new named
4686 branch that is not present at the destination. This allows you to
4580 branch that is not present at the destination. This allows you to
4687 only create a new branch without forcing other changes.
4581 only create a new branch without forcing other changes.
4688
4582
4689 .. note::
4583 .. note::
4690
4584
4691 Extra care should be taken with the -f/--force option,
4585 Extra care should be taken with the -f/--force option,
4692 which will push all new heads on all branches, an action which will
4586 which will push all new heads on all branches, an action which will
4693 almost always cause confusion for collaborators.
4587 almost always cause confusion for collaborators.
4694
4588
4695 If -r/--rev is used, the specified revision and all its ancestors
4589 If -r/--rev is used, the specified revision and all its ancestors
4696 will be pushed to the remote repository.
4590 will be pushed to the remote repository.
4697
4591
4698 If -B/--bookmark is used, the specified bookmarked revision, its
4592 If -B/--bookmark is used, the specified bookmarked revision, its
4699 ancestors, and the bookmark will be pushed to the remote
4593 ancestors, and the bookmark will be pushed to the remote
4700 repository.
4594 repository.
4701
4595
4702 Please see :hg:`help urls` for important details about ``ssh://``
4596 Please see :hg:`help urls` for important details about ``ssh://``
4703 URLs. If DESTINATION is omitted, a default path will be used.
4597 URLs. If DESTINATION is omitted, a default path will be used.
4704
4598
4705 Returns 0 if push was successful, 1 if nothing to push.
4599 Returns 0 if push was successful, 1 if nothing to push.
4706 """
4600 """
4707
4601
4708 if opts.get('bookmark'):
4602 if opts.get('bookmark'):
4709 ui.setconfig('bookmarks', 'pushing', opts['bookmark'])
4603 ui.setconfig('bookmarks', 'pushing', opts['bookmark'])
4710 for b in opts['bookmark']:
4604 for b in opts['bookmark']:
4711 # translate -B options to -r so changesets get pushed
4605 # translate -B options to -r so changesets get pushed
4712 if b in repo._bookmarks:
4606 if b in repo._bookmarks:
4713 opts.setdefault('rev', []).append(b)
4607 opts.setdefault('rev', []).append(b)
4714 else:
4608 else:
4715 # if we try to push a deleted bookmark, translate it to null
4609 # if we try to push a deleted bookmark, translate it to null
4716 # this lets simultaneous -r, -b options continue working
4610 # this lets simultaneous -r, -b options continue working
4717 opts.setdefault('rev', []).append("null")
4611 opts.setdefault('rev', []).append("null")
4718
4612
4719 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4613 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4720 dest, branches = hg.parseurl(dest, opts.get('branch'))
4614 dest, branches = hg.parseurl(dest, opts.get('branch'))
4721 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4615 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4722 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4616 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4723 other = hg.peer(repo, opts, dest)
4617 other = hg.peer(repo, opts, dest)
4724 if revs:
4618 if revs:
4725 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4619 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4726
4620
4727 repo._subtoppath = dest
4621 repo._subtoppath = dest
4728 try:
4622 try:
4729 # push subrepos depth-first for coherent ordering
4623 # push subrepos depth-first for coherent ordering
4730 c = repo['']
4624 c = repo['']
4731 subs = c.substate # only repos that are committed
4625 subs = c.substate # only repos that are committed
4732 for s in sorted(subs):
4626 for s in sorted(subs):
4733 if c.sub(s).push(opts) == 0:
4627 if c.sub(s).push(opts) == 0:
4734 return False
4628 return False
4735 finally:
4629 finally:
4736 del repo._subtoppath
4630 del repo._subtoppath
4737 result = repo.push(other, opts.get('force'), revs=revs,
4631 result = repo.push(other, opts.get('force'), revs=revs,
4738 newbranch=opts.get('new_branch'))
4632 newbranch=opts.get('new_branch'))
4739
4633
4740 result = not result
4634 result = not result
4741
4635
4742 if opts.get('bookmark'):
4636 if opts.get('bookmark'):
4743 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4637 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4744 if bresult == 2:
4638 if bresult == 2:
4745 return 2
4639 return 2
4746 if not result and bresult:
4640 if not result and bresult:
4747 result = 2
4641 result = 2
4748
4642
4749 return result
4643 return result
4750
4644
4751 @command('recover', [])
4645 @command('recover', [])
4752 def recover(ui, repo):
4646 def recover(ui, repo):
4753 """roll back an interrupted transaction
4647 """roll back an interrupted transaction
4754
4648
4755 Recover from an interrupted commit or pull.
4649 Recover from an interrupted commit or pull.
4756
4650
4757 This command tries to fix the repository status after an
4651 This command tries to fix the repository status after an
4758 interrupted operation. It should only be necessary when Mercurial
4652 interrupted operation. It should only be necessary when Mercurial
4759 suggests it.
4653 suggests it.
4760
4654
4761 Returns 0 if successful, 1 if nothing to recover or verify fails.
4655 Returns 0 if successful, 1 if nothing to recover or verify fails.
4762 """
4656 """
4763 if repo.recover():
4657 if repo.recover():
4764 return hg.verify(repo)
4658 return hg.verify(repo)
4765 return 1
4659 return 1
4766
4660
4767 @command('^remove|rm',
4661 @command('^remove|rm',
4768 [('A', 'after', None, _('record delete for missing files')),
4662 [('A', 'after', None, _('record delete for missing files')),
4769 ('f', 'force', None,
4663 ('f', 'force', None,
4770 _('remove (and delete) file even if added or modified')),
4664 _('remove (and delete) file even if added or modified')),
4771 ] + walkopts,
4665 ] + walkopts,
4772 _('[OPTION]... FILE...'))
4666 _('[OPTION]... FILE...'))
4773 def remove(ui, repo, *pats, **opts):
4667 def remove(ui, repo, *pats, **opts):
4774 """remove the specified files on the next commit
4668 """remove the specified files on the next commit
4775
4669
4776 Schedule the indicated files for removal from the current branch.
4670 Schedule the indicated files for removal from the current branch.
4777
4671
4778 This command schedules the files to be removed at the next commit.
4672 This command schedules the files to be removed at the next commit.
4779 To undo a remove before that, see :hg:`revert`. To undo added
4673 To undo a remove before that, see :hg:`revert`. To undo added
4780 files, see :hg:`forget`.
4674 files, see :hg:`forget`.
4781
4675
4782 .. container:: verbose
4676 .. container:: verbose
4783
4677
4784 -A/--after can be used to remove only files that have already
4678 -A/--after can be used to remove only files that have already
4785 been deleted, -f/--force can be used to force deletion, and -Af
4679 been deleted, -f/--force can be used to force deletion, and -Af
4786 can be used to remove files from the next revision without
4680 can be used to remove files from the next revision without
4787 deleting them from the working directory.
4681 deleting them from the working directory.
4788
4682
4789 The following table details the behavior of remove for different
4683 The following table details the behavior of remove for different
4790 file states (columns) and option combinations (rows). The file
4684 file states (columns) and option combinations (rows). The file
4791 states are Added [A], Clean [C], Modified [M] and Missing [!]
4685 states are Added [A], Clean [C], Modified [M] and Missing [!]
4792 (as reported by :hg:`status`). The actions are Warn, Remove
4686 (as reported by :hg:`status`). The actions are Warn, Remove
4793 (from branch) and Delete (from disk):
4687 (from branch) and Delete (from disk):
4794
4688
4795 ========= == == == ==
4689 ========= == == == ==
4796 opt/state A C M !
4690 opt/state A C M !
4797 ========= == == == ==
4691 ========= == == == ==
4798 none W RD W R
4692 none W RD W R
4799 -f R RD RD R
4693 -f R RD RD R
4800 -A W W W R
4694 -A W W W R
4801 -Af R R R R
4695 -Af R R R R
4802 ========= == == == ==
4696 ========= == == == ==
4803
4697
4804 Note that remove never deletes files in Added [A] state from the
4698 Note that remove never deletes files in Added [A] state from the
4805 working directory, not even if option --force is specified.
4699 working directory, not even if option --force is specified.
4806
4700
4807 Returns 0 on success, 1 if any warnings encountered.
4701 Returns 0 on success, 1 if any warnings encountered.
4808 """
4702 """
4809
4703
4810 ret = 0
4704 ret = 0
4811 after, force = opts.get('after'), opts.get('force')
4705 after, force = opts.get('after'), opts.get('force')
4812 if not pats and not after:
4706 if not pats and not after:
4813 raise util.Abort(_('no files specified'))
4707 raise util.Abort(_('no files specified'))
4814
4708
4815 m = scmutil.match(repo[None], pats, opts)
4709 m = scmutil.match(repo[None], pats, opts)
4816 s = repo.status(match=m, clean=True)
4710 s = repo.status(match=m, clean=True)
4817 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4711 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4818
4712
4819 # warn about failure to delete explicit files/dirs
4713 # warn about failure to delete explicit files/dirs
4820 wctx = repo[None]
4714 wctx = repo[None]
4821 for f in m.files():
4715 for f in m.files():
4822 if f in repo.dirstate or f in wctx.dirs():
4716 if f in repo.dirstate or f in wctx.dirs():
4823 continue
4717 continue
4824 if os.path.exists(m.rel(f)):
4718 if os.path.exists(m.rel(f)):
4825 if os.path.isdir(m.rel(f)):
4719 if os.path.isdir(m.rel(f)):
4826 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4720 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4827 else:
4721 else:
4828 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4722 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4829 # missing files will generate a warning elsewhere
4723 # missing files will generate a warning elsewhere
4830 ret = 1
4724 ret = 1
4831
4725
4832 if force:
4726 if force:
4833 list = modified + deleted + clean + added
4727 list = modified + deleted + clean + added
4834 elif after:
4728 elif after:
4835 list = deleted
4729 list = deleted
4836 for f in modified + added + clean:
4730 for f in modified + added + clean:
4837 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4731 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4838 ret = 1
4732 ret = 1
4839 else:
4733 else:
4840 list = deleted + clean
4734 list = deleted + clean
4841 for f in modified:
4735 for f in modified:
4842 ui.warn(_('not removing %s: file is modified (use -f'
4736 ui.warn(_('not removing %s: file is modified (use -f'
4843 ' to force removal)\n') % m.rel(f))
4737 ' to force removal)\n') % m.rel(f))
4844 ret = 1
4738 ret = 1
4845 for f in added:
4739 for f in added:
4846 ui.warn(_('not removing %s: file has been marked for add'
4740 ui.warn(_('not removing %s: file has been marked for add'
4847 ' (use forget to undo)\n') % m.rel(f))
4741 ' (use forget to undo)\n') % m.rel(f))
4848 ret = 1
4742 ret = 1
4849
4743
4850 for f in sorted(list):
4744 for f in sorted(list):
4851 if ui.verbose or not m.exact(f):
4745 if ui.verbose or not m.exact(f):
4852 ui.status(_('removing %s\n') % m.rel(f))
4746 ui.status(_('removing %s\n') % m.rel(f))
4853
4747
4854 wlock = repo.wlock()
4748 wlock = repo.wlock()
4855 try:
4749 try:
4856 if not after:
4750 if not after:
4857 for f in list:
4751 for f in list:
4858 if f in added:
4752 if f in added:
4859 continue # we never unlink added files on remove
4753 continue # we never unlink added files on remove
4860 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4754 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4861 repo[None].forget(list)
4755 repo[None].forget(list)
4862 finally:
4756 finally:
4863 wlock.release()
4757 wlock.release()
4864
4758
4865 return ret
4759 return ret
4866
4760
4867 @command('rename|move|mv',
4761 @command('rename|move|mv',
4868 [('A', 'after', None, _('record a rename that has already occurred')),
4762 [('A', 'after', None, _('record a rename that has already occurred')),
4869 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4763 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4870 ] + walkopts + dryrunopts,
4764 ] + walkopts + dryrunopts,
4871 _('[OPTION]... SOURCE... DEST'))
4765 _('[OPTION]... SOURCE... DEST'))
4872 def rename(ui, repo, *pats, **opts):
4766 def rename(ui, repo, *pats, **opts):
4873 """rename files; equivalent of copy + remove
4767 """rename files; equivalent of copy + remove
4874
4768
4875 Mark dest as copies of sources; mark sources for deletion. If dest
4769 Mark dest as copies of sources; mark sources for deletion. If dest
4876 is a directory, copies are put in that directory. If dest is a
4770 is a directory, copies are put in that directory. If dest is a
4877 file, there can only be one source.
4771 file, there can only be one source.
4878
4772
4879 By default, this command copies the contents of files as they
4773 By default, this command copies the contents of files as they
4880 exist in the working directory. If invoked with -A/--after, the
4774 exist in the working directory. If invoked with -A/--after, the
4881 operation is recorded, but no copying is performed.
4775 operation is recorded, but no copying is performed.
4882
4776
4883 This command takes effect at the next commit. To undo a rename
4777 This command takes effect at the next commit. To undo a rename
4884 before that, see :hg:`revert`.
4778 before that, see :hg:`revert`.
4885
4779
4886 Returns 0 on success, 1 if errors are encountered.
4780 Returns 0 on success, 1 if errors are encountered.
4887 """
4781 """
4888 wlock = repo.wlock(False)
4782 wlock = repo.wlock(False)
4889 try:
4783 try:
4890 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4784 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4891 finally:
4785 finally:
4892 wlock.release()
4786 wlock.release()
4893
4787
4894 @command('resolve',
4788 @command('resolve',
4895 [('a', 'all', None, _('select all unresolved files')),
4789 [('a', 'all', None, _('select all unresolved files')),
4896 ('l', 'list', None, _('list state of files needing merge')),
4790 ('l', 'list', None, _('list state of files needing merge')),
4897 ('m', 'mark', None, _('mark files as resolved')),
4791 ('m', 'mark', None, _('mark files as resolved')),
4898 ('u', 'unmark', None, _('mark files as unresolved')),
4792 ('u', 'unmark', None, _('mark files as unresolved')),
4899 ('n', 'no-status', None, _('hide status prefix'))]
4793 ('n', 'no-status', None, _('hide status prefix'))]
4900 + mergetoolopts + walkopts,
4794 + mergetoolopts + walkopts,
4901 _('[OPTION]... [FILE]...'))
4795 _('[OPTION]... [FILE]...'))
4902 def resolve(ui, repo, *pats, **opts):
4796 def resolve(ui, repo, *pats, **opts):
4903 """redo merges or set/view the merge status of files
4797 """redo merges or set/view the merge status of files
4904
4798
4905 Merges with unresolved conflicts are often the result of
4799 Merges with unresolved conflicts are often the result of
4906 non-interactive merging using the ``internal:merge`` configuration
4800 non-interactive merging using the ``internal:merge`` configuration
4907 setting, or a command-line merge tool like ``diff3``. The resolve
4801 setting, or a command-line merge tool like ``diff3``. The resolve
4908 command is used to manage the files involved in a merge, after
4802 command is used to manage the files involved in a merge, after
4909 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4803 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4910 working directory must have two parents). See :hg:`help
4804 working directory must have two parents). See :hg:`help
4911 merge-tools` for information on configuring merge tools.
4805 merge-tools` for information on configuring merge tools.
4912
4806
4913 The resolve command can be used in the following ways:
4807 The resolve command can be used in the following ways:
4914
4808
4915 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4809 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4916 files, discarding any previous merge attempts. Re-merging is not
4810 files, discarding any previous merge attempts. Re-merging is not
4917 performed for files already marked as resolved. Use ``--all/-a``
4811 performed for files already marked as resolved. Use ``--all/-a``
4918 to select all unresolved files. ``--tool`` can be used to specify
4812 to select all unresolved files. ``--tool`` can be used to specify
4919 the merge tool used for the given files. It overrides the HGMERGE
4813 the merge tool used for the given files. It overrides the HGMERGE
4920 environment variable and your configuration files. Previous file
4814 environment variable and your configuration files. Previous file
4921 contents are saved with a ``.orig`` suffix.
4815 contents are saved with a ``.orig`` suffix.
4922
4816
4923 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4817 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4924 (e.g. after having manually fixed-up the files). The default is
4818 (e.g. after having manually fixed-up the files). The default is
4925 to mark all unresolved files.
4819 to mark all unresolved files.
4926
4820
4927 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4821 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4928 default is to mark all resolved files.
4822 default is to mark all resolved files.
4929
4823
4930 - :hg:`resolve -l`: list files which had or still have conflicts.
4824 - :hg:`resolve -l`: list files which had or still have conflicts.
4931 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4825 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4932
4826
4933 Note that Mercurial will not let you commit files with unresolved
4827 Note that Mercurial will not let you commit files with unresolved
4934 merge conflicts. You must use :hg:`resolve -m ...` before you can
4828 merge conflicts. You must use :hg:`resolve -m ...` before you can
4935 commit after a conflicting merge.
4829 commit after a conflicting merge.
4936
4830
4937 Returns 0 on success, 1 if any files fail a resolve attempt.
4831 Returns 0 on success, 1 if any files fail a resolve attempt.
4938 """
4832 """
4939
4833
4940 all, mark, unmark, show, nostatus = \
4834 all, mark, unmark, show, nostatus = \
4941 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4835 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4942
4836
4943 if (show and (mark or unmark)) or (mark and unmark):
4837 if (show and (mark or unmark)) or (mark and unmark):
4944 raise util.Abort(_("too many options specified"))
4838 raise util.Abort(_("too many options specified"))
4945 if pats and all:
4839 if pats and all:
4946 raise util.Abort(_("can't specify --all and patterns"))
4840 raise util.Abort(_("can't specify --all and patterns"))
4947 if not (all or pats or show or mark or unmark):
4841 if not (all or pats or show or mark or unmark):
4948 raise util.Abort(_('no files or directories specified; '
4842 raise util.Abort(_('no files or directories specified; '
4949 'use --all to remerge all files'))
4843 'use --all to remerge all files'))
4950
4844
4951 ms = mergemod.mergestate(repo)
4845 ms = mergemod.mergestate(repo)
4952 m = scmutil.match(repo[None], pats, opts)
4846 m = scmutil.match(repo[None], pats, opts)
4953 ret = 0
4847 ret = 0
4954
4848
4955 for f in ms:
4849 for f in ms:
4956 if m(f):
4850 if m(f):
4957 if show:
4851 if show:
4958 if nostatus:
4852 if nostatus:
4959 ui.write("%s\n" % f)
4853 ui.write("%s\n" % f)
4960 else:
4854 else:
4961 ui.write("%s %s\n" % (ms[f].upper(), f),
4855 ui.write("%s %s\n" % (ms[f].upper(), f),
4962 label='resolve.' +
4856 label='resolve.' +
4963 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4857 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4964 elif mark:
4858 elif mark:
4965 ms.mark(f, "r")
4859 ms.mark(f, "r")
4966 elif unmark:
4860 elif unmark:
4967 ms.mark(f, "u")
4861 ms.mark(f, "u")
4968 else:
4862 else:
4969 wctx = repo[None]
4863 wctx = repo[None]
4970 mctx = wctx.parents()[-1]
4864 mctx = wctx.parents()[-1]
4971
4865
4972 # backup pre-resolve (merge uses .orig for its own purposes)
4866 # backup pre-resolve (merge uses .orig for its own purposes)
4973 a = repo.wjoin(f)
4867 a = repo.wjoin(f)
4974 util.copyfile(a, a + ".resolve")
4868 util.copyfile(a, a + ".resolve")
4975
4869
4976 try:
4870 try:
4977 # resolve file
4871 # resolve file
4978 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4872 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4979 if ms.resolve(f, wctx, mctx):
4873 if ms.resolve(f, wctx, mctx):
4980 ret = 1
4874 ret = 1
4981 finally:
4875 finally:
4982 ui.setconfig('ui', 'forcemerge', '')
4876 ui.setconfig('ui', 'forcemerge', '')
4983 ms.commit()
4877 ms.commit()
4984
4878
4985 # replace filemerge's .orig file with our resolve file
4879 # replace filemerge's .orig file with our resolve file
4986 util.rename(a + ".resolve", a + ".orig")
4880 util.rename(a + ".resolve", a + ".orig")
4987
4881
4988 ms.commit()
4882 ms.commit()
4989 return ret
4883 return ret
4990
4884
4991 @command('revert',
4885 @command('revert',
4992 [('a', 'all', None, _('revert all changes when no arguments given')),
4886 [('a', 'all', None, _('revert all changes when no arguments given')),
4993 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4887 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4994 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4888 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4995 ('C', 'no-backup', None, _('do not save backup copies of files')),
4889 ('C', 'no-backup', None, _('do not save backup copies of files')),
4996 ] + walkopts + dryrunopts,
4890 ] + walkopts + dryrunopts,
4997 _('[OPTION]... [-r REV] [NAME]...'))
4891 _('[OPTION]... [-r REV] [NAME]...'))
4998 def revert(ui, repo, *pats, **opts):
4892 def revert(ui, repo, *pats, **opts):
4999 """restore files to their checkout state
4893 """restore files to their checkout state
5000
4894
5001 .. note::
4895 .. note::
5002
4896
5003 To check out earlier revisions, you should use :hg:`update REV`.
4897 To check out earlier revisions, you should use :hg:`update REV`.
5004 To cancel an uncommitted merge (and lose your changes),
4898 To cancel an uncommitted merge (and lose your changes),
5005 use :hg:`update --clean .`.
4899 use :hg:`update --clean .`.
5006
4900
5007 With no revision specified, revert the specified files or directories
4901 With no revision specified, revert the specified files or directories
5008 to the contents they had in the parent of the working directory.
4902 to the contents they had in the parent of the working directory.
5009 This restores the contents of files to an unmodified
4903 This restores the contents of files to an unmodified
5010 state and unschedules adds, removes, copies, and renames. If the
4904 state and unschedules adds, removes, copies, and renames. If the
5011 working directory has two parents, you must explicitly specify a
4905 working directory has two parents, you must explicitly specify a
5012 revision.
4906 revision.
5013
4907
5014 Using the -r/--rev or -d/--date options, revert the given files or
4908 Using the -r/--rev or -d/--date options, revert the given files or
5015 directories to their states as of a specific revision. Because
4909 directories to their states as of a specific revision. Because
5016 revert does not change the working directory parents, this will
4910 revert does not change the working directory parents, this will
5017 cause these files to appear modified. This can be helpful to "back
4911 cause these files to appear modified. This can be helpful to "back
5018 out" some or all of an earlier change. See :hg:`backout` for a
4912 out" some or all of an earlier change. See :hg:`backout` for a
5019 related method.
4913 related method.
5020
4914
5021 Modified files are saved with a .orig suffix before reverting.
4915 Modified files are saved with a .orig suffix before reverting.
5022 To disable these backups, use --no-backup.
4916 To disable these backups, use --no-backup.
5023
4917
5024 See :hg:`help dates` for a list of formats valid for -d/--date.
4918 See :hg:`help dates` for a list of formats valid for -d/--date.
5025
4919
5026 Returns 0 on success.
4920 Returns 0 on success.
5027 """
4921 """
5028
4922
5029 if opts.get("date"):
4923 if opts.get("date"):
5030 if opts.get("rev"):
4924 if opts.get("rev"):
5031 raise util.Abort(_("you can't specify a revision and a date"))
4925 raise util.Abort(_("you can't specify a revision and a date"))
5032 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4926 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5033
4927
5034 parent, p2 = repo.dirstate.parents()
4928 parent, p2 = repo.dirstate.parents()
5035 if not opts.get('rev') and p2 != nullid:
4929 if not opts.get('rev') and p2 != nullid:
5036 # revert after merge is a trap for new users (issue2915)
4930 # revert after merge is a trap for new users (issue2915)
5037 raise util.Abort(_('uncommitted merge with no revision specified'),
4931 raise util.Abort(_('uncommitted merge with no revision specified'),
5038 hint=_('use "hg update" or see "hg help revert"'))
4932 hint=_('use "hg update" or see "hg help revert"'))
5039
4933
5040 ctx = scmutil.revsingle(repo, opts.get('rev'))
4934 ctx = scmutil.revsingle(repo, opts.get('rev'))
5041
4935
5042 if not pats and not opts.get('all'):
4936 if not pats and not opts.get('all'):
5043 msg = _("no files or directories specified")
4937 msg = _("no files or directories specified")
5044 if p2 != nullid:
4938 if p2 != nullid:
5045 hint = _("uncommitted merge, use --all to discard all changes,"
4939 hint = _("uncommitted merge, use --all to discard all changes,"
5046 " or 'hg update -C .' to abort the merge")
4940 " or 'hg update -C .' to abort the merge")
5047 raise util.Abort(msg, hint=hint)
4941 raise util.Abort(msg, hint=hint)
5048 dirty = util.any(repo.status())
4942 dirty = util.any(repo.status())
5049 node = ctx.node()
4943 node = ctx.node()
5050 if node != parent:
4944 if node != parent:
5051 if dirty:
4945 if dirty:
5052 hint = _("uncommitted changes, use --all to discard all"
4946 hint = _("uncommitted changes, use --all to discard all"
5053 " changes, or 'hg update %s' to update") % ctx.rev()
4947 " changes, or 'hg update %s' to update") % ctx.rev()
5054 else:
4948 else:
5055 hint = _("use --all to revert all files,"
4949 hint = _("use --all to revert all files,"
5056 " or 'hg update %s' to update") % ctx.rev()
4950 " or 'hg update %s' to update") % ctx.rev()
5057 elif dirty:
4951 elif dirty:
5058 hint = _("uncommitted changes, use --all to discard all changes")
4952 hint = _("uncommitted changes, use --all to discard all changes")
5059 else:
4953 else:
5060 hint = _("use --all to revert all files")
4954 hint = _("use --all to revert all files")
5061 raise util.Abort(msg, hint=hint)
4955 raise util.Abort(msg, hint=hint)
5062
4956
5063 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4957 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5064
4958
5065 @command('rollback', dryrunopts +
4959 @command('rollback', dryrunopts +
5066 [('f', 'force', False, _('ignore safety measures'))])
4960 [('f', 'force', False, _('ignore safety measures'))])
5067 def rollback(ui, repo, **opts):
4961 def rollback(ui, repo, **opts):
5068 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4962 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5069
4963
5070 Please use :hg:`commit --amend` instead of rollback to correct
4964 Please use :hg:`commit --amend` instead of rollback to correct
5071 mistakes in the last commit.
4965 mistakes in the last commit.
5072
4966
5073 This command should be used with care. There is only one level of
4967 This command should be used with care. There is only one level of
5074 rollback, and there is no way to undo a rollback. It will also
4968 rollback, and there is no way to undo a rollback. It will also
5075 restore the dirstate at the time of the last transaction, losing
4969 restore the dirstate at the time of the last transaction, losing
5076 any dirstate changes since that time. This command does not alter
4970 any dirstate changes since that time. This command does not alter
5077 the working directory.
4971 the working directory.
5078
4972
5079 Transactions are used to encapsulate the effects of all commands
4973 Transactions are used to encapsulate the effects of all commands
5080 that create new changesets or propagate existing changesets into a
4974 that create new changesets or propagate existing changesets into a
5081 repository.
4975 repository.
5082
4976
5083 .. container:: verbose
4977 .. container:: verbose
5084
4978
5085 For example, the following commands are transactional, and their
4979 For example, the following commands are transactional, and their
5086 effects can be rolled back:
4980 effects can be rolled back:
5087
4981
5088 - commit
4982 - commit
5089 - import
4983 - import
5090 - pull
4984 - pull
5091 - push (with this repository as the destination)
4985 - push (with this repository as the destination)
5092 - unbundle
4986 - unbundle
5093
4987
5094 To avoid permanent data loss, rollback will refuse to rollback a
4988 To avoid permanent data loss, rollback will refuse to rollback a
5095 commit transaction if it isn't checked out. Use --force to
4989 commit transaction if it isn't checked out. Use --force to
5096 override this protection.
4990 override this protection.
5097
4991
5098 This command is not intended for use on public repositories. Once
4992 This command is not intended for use on public repositories. Once
5099 changes are visible for pull by other users, rolling a transaction
4993 changes are visible for pull by other users, rolling a transaction
5100 back locally is ineffective (someone else may already have pulled
4994 back locally is ineffective (someone else may already have pulled
5101 the changes). Furthermore, a race is possible with readers of the
4995 the changes). Furthermore, a race is possible with readers of the
5102 repository; for example an in-progress pull from the repository
4996 repository; for example an in-progress pull from the repository
5103 may fail if a rollback is performed.
4997 may fail if a rollback is performed.
5104
4998
5105 Returns 0 on success, 1 if no rollback data is available.
4999 Returns 0 on success, 1 if no rollback data is available.
5106 """
5000 """
5107 return repo.rollback(dryrun=opts.get('dry_run'),
5001 return repo.rollback(dryrun=opts.get('dry_run'),
5108 force=opts.get('force'))
5002 force=opts.get('force'))
5109
5003
5110 @command('root', [])
5004 @command('root', [])
5111 def root(ui, repo):
5005 def root(ui, repo):
5112 """print the root (top) of the current working directory
5006 """print the root (top) of the current working directory
5113
5007
5114 Print the root directory of the current repository.
5008 Print the root directory of the current repository.
5115
5009
5116 Returns 0 on success.
5010 Returns 0 on success.
5117 """
5011 """
5118 ui.write(repo.root + "\n")
5012 ui.write(repo.root + "\n")
5119
5013
5120 @command('^serve',
5014 @command('^serve',
5121 [('A', 'accesslog', '', _('name of access log file to write to'),
5015 [('A', 'accesslog', '', _('name of access log file to write to'),
5122 _('FILE')),
5016 _('FILE')),
5123 ('d', 'daemon', None, _('run server in background')),
5017 ('d', 'daemon', None, _('run server in background')),
5124 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5018 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5125 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5019 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5126 # use string type, then we can check if something was passed
5020 # use string type, then we can check if something was passed
5127 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5021 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5128 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5022 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5129 _('ADDR')),
5023 _('ADDR')),
5130 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5024 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5131 _('PREFIX')),
5025 _('PREFIX')),
5132 ('n', 'name', '',
5026 ('n', 'name', '',
5133 _('name to show in web pages (default: working directory)'), _('NAME')),
5027 _('name to show in web pages (default: working directory)'), _('NAME')),
5134 ('', 'web-conf', '',
5028 ('', 'web-conf', '',
5135 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5029 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5136 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5030 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5137 _('FILE')),
5031 _('FILE')),
5138 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5032 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5139 ('', 'stdio', None, _('for remote clients')),
5033 ('', 'stdio', None, _('for remote clients')),
5140 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5034 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5141 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5035 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5142 ('', 'style', '', _('template style to use'), _('STYLE')),
5036 ('', 'style', '', _('template style to use'), _('STYLE')),
5143 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5037 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5144 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5038 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5145 _('[OPTION]...'))
5039 _('[OPTION]...'))
5146 def serve(ui, repo, **opts):
5040 def serve(ui, repo, **opts):
5147 """start stand-alone webserver
5041 """start stand-alone webserver
5148
5042
5149 Start a local HTTP repository browser and pull server. You can use
5043 Start a local HTTP repository browser and pull server. You can use
5150 this for ad-hoc sharing and browsing of repositories. It is
5044 this for ad-hoc sharing and browsing of repositories. It is
5151 recommended to use a real web server to serve a repository for
5045 recommended to use a real web server to serve a repository for
5152 longer periods of time.
5046 longer periods of time.
5153
5047
5154 Please note that the server does not implement access control.
5048 Please note that the server does not implement access control.
5155 This means that, by default, anybody can read from the server and
5049 This means that, by default, anybody can read from the server and
5156 nobody can write to it by default. Set the ``web.allow_push``
5050 nobody can write to it by default. Set the ``web.allow_push``
5157 option to ``*`` to allow everybody to push to the server. You
5051 option to ``*`` to allow everybody to push to the server. You
5158 should use a real web server if you need to authenticate users.
5052 should use a real web server if you need to authenticate users.
5159
5053
5160 By default, the server logs accesses to stdout and errors to
5054 By default, the server logs accesses to stdout and errors to
5161 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5055 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5162 files.
5056 files.
5163
5057
5164 To have the server choose a free port number to listen on, specify
5058 To have the server choose a free port number to listen on, specify
5165 a port number of 0; in this case, the server will print the port
5059 a port number of 0; in this case, the server will print the port
5166 number it uses.
5060 number it uses.
5167
5061
5168 Returns 0 on success.
5062 Returns 0 on success.
5169 """
5063 """
5170
5064
5171 if opts["stdio"] and opts["cmdserver"]:
5065 if opts["stdio"] and opts["cmdserver"]:
5172 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5066 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5173
5067
5174 def checkrepo():
5068 def checkrepo():
5175 if repo is None:
5069 if repo is None:
5176 raise error.RepoError(_("there is no Mercurial repository here"
5070 raise error.RepoError(_("there is no Mercurial repository here"
5177 " (.hg not found)"))
5071 " (.hg not found)"))
5178
5072
5179 if opts["stdio"]:
5073 if opts["stdio"]:
5180 checkrepo()
5074 checkrepo()
5181 s = sshserver.sshserver(ui, repo)
5075 s = sshserver.sshserver(ui, repo)
5182 s.serve_forever()
5076 s.serve_forever()
5183
5077
5184 if opts["cmdserver"]:
5078 if opts["cmdserver"]:
5185 checkrepo()
5079 checkrepo()
5186 s = commandserver.server(ui, repo, opts["cmdserver"])
5080 s = commandserver.server(ui, repo, opts["cmdserver"])
5187 return s.serve()
5081 return s.serve()
5188
5082
5189 # this way we can check if something was given in the command-line
5083 # this way we can check if something was given in the command-line
5190 if opts.get('port'):
5084 if opts.get('port'):
5191 opts['port'] = util.getport(opts.get('port'))
5085 opts['port'] = util.getport(opts.get('port'))
5192
5086
5193 baseui = repo and repo.baseui or ui
5087 baseui = repo and repo.baseui or ui
5194 optlist = ("name templates style address port prefix ipv6"
5088 optlist = ("name templates style address port prefix ipv6"
5195 " accesslog errorlog certificate encoding")
5089 " accesslog errorlog certificate encoding")
5196 for o in optlist.split():
5090 for o in optlist.split():
5197 val = opts.get(o, '')
5091 val = opts.get(o, '')
5198 if val in (None, ''): # should check against default options instead
5092 if val in (None, ''): # should check against default options instead
5199 continue
5093 continue
5200 baseui.setconfig("web", o, val)
5094 baseui.setconfig("web", o, val)
5201 if repo and repo.ui != baseui:
5095 if repo and repo.ui != baseui:
5202 repo.ui.setconfig("web", o, val)
5096 repo.ui.setconfig("web", o, val)
5203
5097
5204 o = opts.get('web_conf') or opts.get('webdir_conf')
5098 o = opts.get('web_conf') or opts.get('webdir_conf')
5205 if not o:
5099 if not o:
5206 if not repo:
5100 if not repo:
5207 raise error.RepoError(_("there is no Mercurial repository"
5101 raise error.RepoError(_("there is no Mercurial repository"
5208 " here (.hg not found)"))
5102 " here (.hg not found)"))
5209 o = repo
5103 o = repo
5210
5104
5211 app = hgweb.hgweb(o, baseui=baseui)
5105 app = hgweb.hgweb(o, baseui=baseui)
5212 service = httpservice(ui, app, opts)
5106 service = httpservice(ui, app, opts)
5213 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5107 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5214
5108
5215 class httpservice(object):
5109 class httpservice(object):
5216 def __init__(self, ui, app, opts):
5110 def __init__(self, ui, app, opts):
5217 self.ui = ui
5111 self.ui = ui
5218 self.app = app
5112 self.app = app
5219 self.opts = opts
5113 self.opts = opts
5220
5114
5221 def init(self):
5115 def init(self):
5222 util.setsignalhandler()
5116 util.setsignalhandler()
5223 self.httpd = hgweb_server.create_server(self.ui, self.app)
5117 self.httpd = hgweb_server.create_server(self.ui, self.app)
5224
5118
5225 if self.opts['port'] and not self.ui.verbose:
5119 if self.opts['port'] and not self.ui.verbose:
5226 return
5120 return
5227
5121
5228 if self.httpd.prefix:
5122 if self.httpd.prefix:
5229 prefix = self.httpd.prefix.strip('/') + '/'
5123 prefix = self.httpd.prefix.strip('/') + '/'
5230 else:
5124 else:
5231 prefix = ''
5125 prefix = ''
5232
5126
5233 port = ':%d' % self.httpd.port
5127 port = ':%d' % self.httpd.port
5234 if port == ':80':
5128 if port == ':80':
5235 port = ''
5129 port = ''
5236
5130
5237 bindaddr = self.httpd.addr
5131 bindaddr = self.httpd.addr
5238 if bindaddr == '0.0.0.0':
5132 if bindaddr == '0.0.0.0':
5239 bindaddr = '*'
5133 bindaddr = '*'
5240 elif ':' in bindaddr: # IPv6
5134 elif ':' in bindaddr: # IPv6
5241 bindaddr = '[%s]' % bindaddr
5135 bindaddr = '[%s]' % bindaddr
5242
5136
5243 fqaddr = self.httpd.fqaddr
5137 fqaddr = self.httpd.fqaddr
5244 if ':' in fqaddr:
5138 if ':' in fqaddr:
5245 fqaddr = '[%s]' % fqaddr
5139 fqaddr = '[%s]' % fqaddr
5246 if self.opts['port']:
5140 if self.opts['port']:
5247 write = self.ui.status
5141 write = self.ui.status
5248 else:
5142 else:
5249 write = self.ui.write
5143 write = self.ui.write
5250 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5144 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5251 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5145 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5252
5146
5253 def run(self):
5147 def run(self):
5254 self.httpd.serve_forever()
5148 self.httpd.serve_forever()
5255
5149
5256
5150
5257 @command('showconfig|debugconfig',
5151 @command('showconfig|debugconfig',
5258 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5152 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5259 _('[-u] [NAME]...'))
5153 _('[-u] [NAME]...'))
5260 def showconfig(ui, repo, *values, **opts):
5154 def showconfig(ui, repo, *values, **opts):
5261 """show combined config settings from all hgrc files
5155 """show combined config settings from all hgrc files
5262
5156
5263 With no arguments, print names and values of all config items.
5157 With no arguments, print names and values of all config items.
5264
5158
5265 With one argument of the form section.name, print just the value
5159 With one argument of the form section.name, print just the value
5266 of that config item.
5160 of that config item.
5267
5161
5268 With multiple arguments, print names and values of all config
5162 With multiple arguments, print names and values of all config
5269 items with matching section names.
5163 items with matching section names.
5270
5164
5271 With --debug, the source (filename and line number) is printed
5165 With --debug, the source (filename and line number) is printed
5272 for each config item.
5166 for each config item.
5273
5167
5274 Returns 0 on success.
5168 Returns 0 on success.
5275 """
5169 """
5276
5170
5277 for f in scmutil.rcpath():
5171 for f in scmutil.rcpath():
5278 ui.debug('read config from: %s\n' % f)
5172 ui.debug('read config from: %s\n' % f)
5279 untrusted = bool(opts.get('untrusted'))
5173 untrusted = bool(opts.get('untrusted'))
5280 if values:
5174 if values:
5281 sections = [v for v in values if '.' not in v]
5175 sections = [v for v in values if '.' not in v]
5282 items = [v for v in values if '.' in v]
5176 items = [v for v in values if '.' in v]
5283 if len(items) > 1 or items and sections:
5177 if len(items) > 1 or items and sections:
5284 raise util.Abort(_('only one config item permitted'))
5178 raise util.Abort(_('only one config item permitted'))
5285 for section, name, value in ui.walkconfig(untrusted=untrusted):
5179 for section, name, value in ui.walkconfig(untrusted=untrusted):
5286 value = str(value).replace('\n', '\\n')
5180 value = str(value).replace('\n', '\\n')
5287 sectname = section + '.' + name
5181 sectname = section + '.' + name
5288 if values:
5182 if values:
5289 for v in values:
5183 for v in values:
5290 if v == section:
5184 if v == section:
5291 ui.debug('%s: ' %
5185 ui.debug('%s: ' %
5292 ui.configsource(section, name, untrusted))
5186 ui.configsource(section, name, untrusted))
5293 ui.write('%s=%s\n' % (sectname, value))
5187 ui.write('%s=%s\n' % (sectname, value))
5294 elif v == sectname:
5188 elif v == sectname:
5295 ui.debug('%s: ' %
5189 ui.debug('%s: ' %
5296 ui.configsource(section, name, untrusted))
5190 ui.configsource(section, name, untrusted))
5297 ui.write(value, '\n')
5191 ui.write(value, '\n')
5298 else:
5192 else:
5299 ui.debug('%s: ' %
5193 ui.debug('%s: ' %
5300 ui.configsource(section, name, untrusted))
5194 ui.configsource(section, name, untrusted))
5301 ui.write('%s=%s\n' % (sectname, value))
5195 ui.write('%s=%s\n' % (sectname, value))
5302
5196
5303 @command('^status|st',
5197 @command('^status|st',
5304 [('A', 'all', None, _('show status of all files')),
5198 [('A', 'all', None, _('show status of all files')),
5305 ('m', 'modified', None, _('show only modified files')),
5199 ('m', 'modified', None, _('show only modified files')),
5306 ('a', 'added', None, _('show only added files')),
5200 ('a', 'added', None, _('show only added files')),
5307 ('r', 'removed', None, _('show only removed files')),
5201 ('r', 'removed', None, _('show only removed files')),
5308 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5202 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5309 ('c', 'clean', None, _('show only files without changes')),
5203 ('c', 'clean', None, _('show only files without changes')),
5310 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5204 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5311 ('i', 'ignored', None, _('show only ignored files')),
5205 ('i', 'ignored', None, _('show only ignored files')),
5312 ('n', 'no-status', None, _('hide status prefix')),
5206 ('n', 'no-status', None, _('hide status prefix')),
5313 ('C', 'copies', None, _('show source of copied files')),
5207 ('C', 'copies', None, _('show source of copied files')),
5314 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5208 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5315 ('', 'rev', [], _('show difference from revision'), _('REV')),
5209 ('', 'rev', [], _('show difference from revision'), _('REV')),
5316 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5210 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5317 ] + walkopts + subrepoopts,
5211 ] + walkopts + subrepoopts,
5318 _('[OPTION]... [FILE]...'))
5212 _('[OPTION]... [FILE]...'))
5319 def status(ui, repo, *pats, **opts):
5213 def status(ui, repo, *pats, **opts):
5320 """show changed files in the working directory
5214 """show changed files in the working directory
5321
5215
5322 Show status of files in the repository. If names are given, only
5216 Show status of files in the repository. If names are given, only
5323 files that match are shown. Files that are clean or ignored or
5217 files that match are shown. Files that are clean or ignored or
5324 the source of a copy/move operation, are not listed unless
5218 the source of a copy/move operation, are not listed unless
5325 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5219 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5326 Unless options described with "show only ..." are given, the
5220 Unless options described with "show only ..." are given, the
5327 options -mardu are used.
5221 options -mardu are used.
5328
5222
5329 Option -q/--quiet hides untracked (unknown and ignored) files
5223 Option -q/--quiet hides untracked (unknown and ignored) files
5330 unless explicitly requested with -u/--unknown or -i/--ignored.
5224 unless explicitly requested with -u/--unknown or -i/--ignored.
5331
5225
5332 .. note::
5226 .. note::
5333
5227
5334 status may appear to disagree with diff if permissions have
5228 status may appear to disagree with diff if permissions have
5335 changed or a merge has occurred. The standard diff format does
5229 changed or a merge has occurred. The standard diff format does
5336 not report permission changes and diff only reports changes
5230 not report permission changes and diff only reports changes
5337 relative to one merge parent.
5231 relative to one merge parent.
5338
5232
5339 If one revision is given, it is used as the base revision.
5233 If one revision is given, it is used as the base revision.
5340 If two revisions are given, the differences between them are
5234 If two revisions are given, the differences between them are
5341 shown. The --change option can also be used as a shortcut to list
5235 shown. The --change option can also be used as a shortcut to list
5342 the changed files of a revision from its first parent.
5236 the changed files of a revision from its first parent.
5343
5237
5344 The codes used to show the status of files are::
5238 The codes used to show the status of files are::
5345
5239
5346 M = modified
5240 M = modified
5347 A = added
5241 A = added
5348 R = removed
5242 R = removed
5349 C = clean
5243 C = clean
5350 ! = missing (deleted by non-hg command, but still tracked)
5244 ! = missing (deleted by non-hg command, but still tracked)
5351 ? = not tracked
5245 ? = not tracked
5352 I = ignored
5246 I = ignored
5353 = origin of the previous file listed as A (added)
5247 = origin of the previous file listed as A (added)
5354
5248
5355 .. container:: verbose
5249 .. container:: verbose
5356
5250
5357 Examples:
5251 Examples:
5358
5252
5359 - show changes in the working directory relative to a
5253 - show changes in the working directory relative to a
5360 changeset::
5254 changeset::
5361
5255
5362 hg status --rev 9353
5256 hg status --rev 9353
5363
5257
5364 - show all changes including copies in an existing changeset::
5258 - show all changes including copies in an existing changeset::
5365
5259
5366 hg status --copies --change 9353
5260 hg status --copies --change 9353
5367
5261
5368 - get a NUL separated list of added files, suitable for xargs::
5262 - get a NUL separated list of added files, suitable for xargs::
5369
5263
5370 hg status -an0
5264 hg status -an0
5371
5265
5372 Returns 0 on success.
5266 Returns 0 on success.
5373 """
5267 """
5374
5268
5375 revs = opts.get('rev')
5269 revs = opts.get('rev')
5376 change = opts.get('change')
5270 change = opts.get('change')
5377
5271
5378 if revs and change:
5272 if revs and change:
5379 msg = _('cannot specify --rev and --change at the same time')
5273 msg = _('cannot specify --rev and --change at the same time')
5380 raise util.Abort(msg)
5274 raise util.Abort(msg)
5381 elif change:
5275 elif change:
5382 node2 = scmutil.revsingle(repo, change, None).node()
5276 node2 = scmutil.revsingle(repo, change, None).node()
5383 node1 = repo[node2].p1().node()
5277 node1 = repo[node2].p1().node()
5384 else:
5278 else:
5385 node1, node2 = scmutil.revpair(repo, revs)
5279 node1, node2 = scmutil.revpair(repo, revs)
5386
5280
5387 cwd = (pats and repo.getcwd()) or ''
5281 cwd = (pats and repo.getcwd()) or ''
5388 end = opts.get('print0') and '\0' or '\n'
5282 end = opts.get('print0') and '\0' or '\n'
5389 copy = {}
5283 copy = {}
5390 states = 'modified added removed deleted unknown ignored clean'.split()
5284 states = 'modified added removed deleted unknown ignored clean'.split()
5391 show = [k for k in states if opts.get(k)]
5285 show = [k for k in states if opts.get(k)]
5392 if opts.get('all'):
5286 if opts.get('all'):
5393 show += ui.quiet and (states[:4] + ['clean']) or states
5287 show += ui.quiet and (states[:4] + ['clean']) or states
5394 if not show:
5288 if not show:
5395 show = ui.quiet and states[:4] or states[:5]
5289 show = ui.quiet and states[:4] or states[:5]
5396
5290
5397 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5291 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5398 'ignored' in show, 'clean' in show, 'unknown' in show,
5292 'ignored' in show, 'clean' in show, 'unknown' in show,
5399 opts.get('subrepos'))
5293 opts.get('subrepos'))
5400 changestates = zip(states, 'MAR!?IC', stat)
5294 changestates = zip(states, 'MAR!?IC', stat)
5401
5295
5402 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5296 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5403 copy = copies.pathcopies(repo[node1], repo[node2])
5297 copy = copies.pathcopies(repo[node1], repo[node2])
5404
5298
5405 fm = ui.formatter('status', opts)
5299 fm = ui.formatter('status', opts)
5406 fmt = '%s' + end
5300 fmt = '%s' + end
5407 showchar = not opts.get('no_status')
5301 showchar = not opts.get('no_status')
5408
5302
5409 for state, char, files in changestates:
5303 for state, char, files in changestates:
5410 if state in show:
5304 if state in show:
5411 label = 'status.' + state
5305 label = 'status.' + state
5412 for f in files:
5306 for f in files:
5413 fm.startitem()
5307 fm.startitem()
5414 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5308 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5415 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5309 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5416 if f in copy:
5310 if f in copy:
5417 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5311 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5418 label='status.copied')
5312 label='status.copied')
5419 fm.end()
5313 fm.end()
5420
5314
5421 @command('^summary|sum',
5315 @command('^summary|sum',
5422 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5316 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5423 def summary(ui, repo, **opts):
5317 def summary(ui, repo, **opts):
5424 """summarize working directory state
5318 """summarize working directory state
5425
5319
5426 This generates a brief summary of the working directory state,
5320 This generates a brief summary of the working directory state,
5427 including parents, branch, commit status, and available updates.
5321 including parents, branch, commit status, and available updates.
5428
5322
5429 With the --remote option, this will check the default paths for
5323 With the --remote option, this will check the default paths for
5430 incoming and outgoing changes. This can be time-consuming.
5324 incoming and outgoing changes. This can be time-consuming.
5431
5325
5432 Returns 0 on success.
5326 Returns 0 on success.
5433 """
5327 """
5434
5328
5435 ctx = repo[None]
5329 ctx = repo[None]
5436 parents = ctx.parents()
5330 parents = ctx.parents()
5437 pnode = parents[0].node()
5331 pnode = parents[0].node()
5438 marks = []
5332 marks = []
5439
5333
5440 for p in parents:
5334 for p in parents:
5441 # label with log.changeset (instead of log.parent) since this
5335 # label with log.changeset (instead of log.parent) since this
5442 # shows a working directory parent *changeset*:
5336 # shows a working directory parent *changeset*:
5443 # i18n: column positioning for "hg summary"
5337 # i18n: column positioning for "hg summary"
5444 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5338 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5445 label='log.changeset changeset.%s' % p.phasestr())
5339 label='log.changeset changeset.%s' % p.phasestr())
5446 ui.write(' '.join(p.tags()), label='log.tag')
5340 ui.write(' '.join(p.tags()), label='log.tag')
5447 if p.bookmarks():
5341 if p.bookmarks():
5448 marks.extend(p.bookmarks())
5342 marks.extend(p.bookmarks())
5449 if p.rev() == -1:
5343 if p.rev() == -1:
5450 if not len(repo):
5344 if not len(repo):
5451 ui.write(_(' (empty repository)'))
5345 ui.write(_(' (empty repository)'))
5452 else:
5346 else:
5453 ui.write(_(' (no revision checked out)'))
5347 ui.write(_(' (no revision checked out)'))
5454 ui.write('\n')
5348 ui.write('\n')
5455 if p.description():
5349 if p.description():
5456 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5350 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5457 label='log.summary')
5351 label='log.summary')
5458
5352
5459 branch = ctx.branch()
5353 branch = ctx.branch()
5460 bheads = repo.branchheads(branch)
5354 bheads = repo.branchheads(branch)
5461 # i18n: column positioning for "hg summary"
5355 # i18n: column positioning for "hg summary"
5462 m = _('branch: %s\n') % branch
5356 m = _('branch: %s\n') % branch
5463 if branch != 'default':
5357 if branch != 'default':
5464 ui.write(m, label='log.branch')
5358 ui.write(m, label='log.branch')
5465 else:
5359 else:
5466 ui.status(m, label='log.branch')
5360 ui.status(m, label='log.branch')
5467
5361
5468 if marks:
5362 if marks:
5469 current = repo._bookmarkcurrent
5363 current = repo._bookmarkcurrent
5470 # i18n: column positioning for "hg summary"
5364 # i18n: column positioning for "hg summary"
5471 ui.write(_('bookmarks:'), label='log.bookmark')
5365 ui.write(_('bookmarks:'), label='log.bookmark')
5472 if current is not None:
5366 if current is not None:
5473 if current in marks:
5367 if current in marks:
5474 ui.write(' *' + current, label='bookmarks.current')
5368 ui.write(' *' + current, label='bookmarks.current')
5475 marks.remove(current)
5369 marks.remove(current)
5476 else:
5370 else:
5477 ui.write(' [%s]' % current, label='bookmarks.current')
5371 ui.write(' [%s]' % current, label='bookmarks.current')
5478 for m in marks:
5372 for m in marks:
5479 ui.write(' ' + m, label='log.bookmark')
5373 ui.write(' ' + m, label='log.bookmark')
5480 ui.write('\n', label='log.bookmark')
5374 ui.write('\n', label='log.bookmark')
5481
5375
5482 st = list(repo.status(unknown=True))[:6]
5376 st = list(repo.status(unknown=True))[:6]
5483
5377
5484 c = repo.dirstate.copies()
5378 c = repo.dirstate.copies()
5485 copied, renamed = [], []
5379 copied, renamed = [], []
5486 for d, s in c.iteritems():
5380 for d, s in c.iteritems():
5487 if s in st[2]:
5381 if s in st[2]:
5488 st[2].remove(s)
5382 st[2].remove(s)
5489 renamed.append(d)
5383 renamed.append(d)
5490 else:
5384 else:
5491 copied.append(d)
5385 copied.append(d)
5492 if d in st[1]:
5386 if d in st[1]:
5493 st[1].remove(d)
5387 st[1].remove(d)
5494 st.insert(3, renamed)
5388 st.insert(3, renamed)
5495 st.insert(4, copied)
5389 st.insert(4, copied)
5496
5390
5497 ms = mergemod.mergestate(repo)
5391 ms = mergemod.mergestate(repo)
5498 st.append([f for f in ms if ms[f] == 'u'])
5392 st.append([f for f in ms if ms[f] == 'u'])
5499
5393
5500 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5394 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5501 st.append(subs)
5395 st.append(subs)
5502
5396
5503 labels = [ui.label(_('%d modified'), 'status.modified'),
5397 labels = [ui.label(_('%d modified'), 'status.modified'),
5504 ui.label(_('%d added'), 'status.added'),
5398 ui.label(_('%d added'), 'status.added'),
5505 ui.label(_('%d removed'), 'status.removed'),
5399 ui.label(_('%d removed'), 'status.removed'),
5506 ui.label(_('%d renamed'), 'status.copied'),
5400 ui.label(_('%d renamed'), 'status.copied'),
5507 ui.label(_('%d copied'), 'status.copied'),
5401 ui.label(_('%d copied'), 'status.copied'),
5508 ui.label(_('%d deleted'), 'status.deleted'),
5402 ui.label(_('%d deleted'), 'status.deleted'),
5509 ui.label(_('%d unknown'), 'status.unknown'),
5403 ui.label(_('%d unknown'), 'status.unknown'),
5510 ui.label(_('%d ignored'), 'status.ignored'),
5404 ui.label(_('%d ignored'), 'status.ignored'),
5511 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5405 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5512 ui.label(_('%d subrepos'), 'status.modified')]
5406 ui.label(_('%d subrepos'), 'status.modified')]
5513 t = []
5407 t = []
5514 for s, l in zip(st, labels):
5408 for s, l in zip(st, labels):
5515 if s:
5409 if s:
5516 t.append(l % len(s))
5410 t.append(l % len(s))
5517
5411
5518 t = ', '.join(t)
5412 t = ', '.join(t)
5519 cleanworkdir = False
5413 cleanworkdir = False
5520
5414
5521 if repo.vfs.exists('updatestate'):
5415 if repo.vfs.exists('updatestate'):
5522 t += _(' (interrupted update)')
5416 t += _(' (interrupted update)')
5523 elif len(parents) > 1:
5417 elif len(parents) > 1:
5524 t += _(' (merge)')
5418 t += _(' (merge)')
5525 elif branch != parents[0].branch():
5419 elif branch != parents[0].branch():
5526 t += _(' (new branch)')
5420 t += _(' (new branch)')
5527 elif (parents[0].closesbranch() and
5421 elif (parents[0].closesbranch() and
5528 pnode in repo.branchheads(branch, closed=True)):
5422 pnode in repo.branchheads(branch, closed=True)):
5529 t += _(' (head closed)')
5423 t += _(' (head closed)')
5530 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5424 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5531 t += _(' (clean)')
5425 t += _(' (clean)')
5532 cleanworkdir = True
5426 cleanworkdir = True
5533 elif pnode not in bheads:
5427 elif pnode not in bheads:
5534 t += _(' (new branch head)')
5428 t += _(' (new branch head)')
5535
5429
5536 if cleanworkdir:
5430 if cleanworkdir:
5537 # i18n: column positioning for "hg summary"
5431 # i18n: column positioning for "hg summary"
5538 ui.status(_('commit: %s\n') % t.strip())
5432 ui.status(_('commit: %s\n') % t.strip())
5539 else:
5433 else:
5540 # i18n: column positioning for "hg summary"
5434 # i18n: column positioning for "hg summary"
5541 ui.write(_('commit: %s\n') % t.strip())
5435 ui.write(_('commit: %s\n') % t.strip())
5542
5436
5543 # all ancestors of branch heads - all ancestors of parent = new csets
5437 # all ancestors of branch heads - all ancestors of parent = new csets
5544 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5438 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5545 bheads))
5439 bheads))
5546
5440
5547 if new == 0:
5441 if new == 0:
5548 # i18n: column positioning for "hg summary"
5442 # i18n: column positioning for "hg summary"
5549 ui.status(_('update: (current)\n'))
5443 ui.status(_('update: (current)\n'))
5550 elif pnode not in bheads:
5444 elif pnode not in bheads:
5551 # i18n: column positioning for "hg summary"
5445 # i18n: column positioning for "hg summary"
5552 ui.write(_('update: %d new changesets (update)\n') % new)
5446 ui.write(_('update: %d new changesets (update)\n') % new)
5553 else:
5447 else:
5554 # i18n: column positioning for "hg summary"
5448 # i18n: column positioning for "hg summary"
5555 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5449 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5556 (new, len(bheads)))
5450 (new, len(bheads)))
5557
5451
5558 cmdutil.summaryhooks(ui, repo)
5452 cmdutil.summaryhooks(ui, repo)
5559
5453
5560 if opts.get('remote'):
5454 if opts.get('remote'):
5561 t = []
5455 t = []
5562 source, branches = hg.parseurl(ui.expandpath('default'))
5456 source, branches = hg.parseurl(ui.expandpath('default'))
5563 sbranch = branches[0]
5457 sbranch = branches[0]
5564 other = hg.peer(repo, {}, source)
5458 other = hg.peer(repo, {}, source)
5565 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5459 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5566 if revs:
5460 if revs:
5567 revs = [other.lookup(rev) for rev in revs]
5461 revs = [other.lookup(rev) for rev in revs]
5568 ui.debug('comparing with %s\n' % util.hidepassword(source))
5462 ui.debug('comparing with %s\n' % util.hidepassword(source))
5569 repo.ui.pushbuffer()
5463 repo.ui.pushbuffer()
5570 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5464 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5571 _common, incoming, _rheads = commoninc
5465 _common, incoming, _rheads = commoninc
5572 repo.ui.popbuffer()
5466 repo.ui.popbuffer()
5573 if incoming:
5467 if incoming:
5574 t.append(_('1 or more incoming'))
5468 t.append(_('1 or more incoming'))
5575
5469
5576 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5470 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5577 dbranch = branches[0]
5471 dbranch = branches[0]
5578 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5472 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5579 if source != dest:
5473 if source != dest:
5580 other = hg.peer(repo, {}, dest)
5474 other = hg.peer(repo, {}, dest)
5581 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5475 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5582 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5476 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5583 commoninc = None
5477 commoninc = None
5584 if revs:
5478 if revs:
5585 revs = [repo.lookup(rev) for rev in revs]
5479 revs = [repo.lookup(rev) for rev in revs]
5586 repo.ui.pushbuffer()
5480 repo.ui.pushbuffer()
5587 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5481 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5588 commoninc=commoninc)
5482 commoninc=commoninc)
5589 repo.ui.popbuffer()
5483 repo.ui.popbuffer()
5590 o = outgoing.missing
5484 o = outgoing.missing
5591 if o:
5485 if o:
5592 t.append(_('%d outgoing') % len(o))
5486 t.append(_('%d outgoing') % len(o))
5593 if 'bookmarks' in other.listkeys('namespaces'):
5487 if 'bookmarks' in other.listkeys('namespaces'):
5594 lmarks = repo.listkeys('bookmarks')
5488 lmarks = repo.listkeys('bookmarks')
5595 rmarks = other.listkeys('bookmarks')
5489 rmarks = other.listkeys('bookmarks')
5596 diff = set(rmarks) - set(lmarks)
5490 diff = set(rmarks) - set(lmarks)
5597 if len(diff) > 0:
5491 if len(diff) > 0:
5598 t.append(_('%d incoming bookmarks') % len(diff))
5492 t.append(_('%d incoming bookmarks') % len(diff))
5599 diff = set(lmarks) - set(rmarks)
5493 diff = set(lmarks) - set(rmarks)
5600 if len(diff) > 0:
5494 if len(diff) > 0:
5601 t.append(_('%d outgoing bookmarks') % len(diff))
5495 t.append(_('%d outgoing bookmarks') % len(diff))
5602
5496
5603 if t:
5497 if t:
5604 # i18n: column positioning for "hg summary"
5498 # i18n: column positioning for "hg summary"
5605 ui.write(_('remote: %s\n') % (', '.join(t)))
5499 ui.write(_('remote: %s\n') % (', '.join(t)))
5606 else:
5500 else:
5607 # i18n: column positioning for "hg summary"
5501 # i18n: column positioning for "hg summary"
5608 ui.status(_('remote: (synced)\n'))
5502 ui.status(_('remote: (synced)\n'))
5609
5503
5610 @command('tag',
5504 @command('tag',
5611 [('f', 'force', None, _('force tag')),
5505 [('f', 'force', None, _('force tag')),
5612 ('l', 'local', None, _('make the tag local')),
5506 ('l', 'local', None, _('make the tag local')),
5613 ('r', 'rev', '', _('revision to tag'), _('REV')),
5507 ('r', 'rev', '', _('revision to tag'), _('REV')),
5614 ('', 'remove', None, _('remove a tag')),
5508 ('', 'remove', None, _('remove a tag')),
5615 # -l/--local is already there, commitopts cannot be used
5509 # -l/--local is already there, commitopts cannot be used
5616 ('e', 'edit', None, _('edit commit message')),
5510 ('e', 'edit', None, _('edit commit message')),
5617 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5511 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5618 ] + commitopts2,
5512 ] + commitopts2,
5619 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5513 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5620 def tag(ui, repo, name1, *names, **opts):
5514 def tag(ui, repo, name1, *names, **opts):
5621 """add one or more tags for the current or given revision
5515 """add one or more tags for the current or given revision
5622
5516
5623 Name a particular revision using <name>.
5517 Name a particular revision using <name>.
5624
5518
5625 Tags are used to name particular revisions of the repository and are
5519 Tags are used to name particular revisions of the repository and are
5626 very useful to compare different revisions, to go back to significant
5520 very useful to compare different revisions, to go back to significant
5627 earlier versions or to mark branch points as releases, etc. Changing
5521 earlier versions or to mark branch points as releases, etc. Changing
5628 an existing tag is normally disallowed; use -f/--force to override.
5522 an existing tag is normally disallowed; use -f/--force to override.
5629
5523
5630 If no revision is given, the parent of the working directory is
5524 If no revision is given, the parent of the working directory is
5631 used.
5525 used.
5632
5526
5633 To facilitate version control, distribution, and merging of tags,
5527 To facilitate version control, distribution, and merging of tags,
5634 they are stored as a file named ".hgtags" which is managed similarly
5528 they are stored as a file named ".hgtags" which is managed similarly
5635 to other project files and can be hand-edited if necessary. This
5529 to other project files and can be hand-edited if necessary. This
5636 also means that tagging creates a new commit. The file
5530 also means that tagging creates a new commit. The file
5637 ".hg/localtags" is used for local tags (not shared among
5531 ".hg/localtags" is used for local tags (not shared among
5638 repositories).
5532 repositories).
5639
5533
5640 Tag commits are usually made at the head of a branch. If the parent
5534 Tag commits are usually made at the head of a branch. If the parent
5641 of the working directory is not a branch head, :hg:`tag` aborts; use
5535 of the working directory is not a branch head, :hg:`tag` aborts; use
5642 -f/--force to force the tag commit to be based on a non-head
5536 -f/--force to force the tag commit to be based on a non-head
5643 changeset.
5537 changeset.
5644
5538
5645 See :hg:`help dates` for a list of formats valid for -d/--date.
5539 See :hg:`help dates` for a list of formats valid for -d/--date.
5646
5540
5647 Since tag names have priority over branch names during revision
5541 Since tag names have priority over branch names during revision
5648 lookup, using an existing branch name as a tag name is discouraged.
5542 lookup, using an existing branch name as a tag name is discouraged.
5649
5543
5650 Returns 0 on success.
5544 Returns 0 on success.
5651 """
5545 """
5652 wlock = lock = None
5546 wlock = lock = None
5653 try:
5547 try:
5654 wlock = repo.wlock()
5548 wlock = repo.wlock()
5655 lock = repo.lock()
5549 lock = repo.lock()
5656 rev_ = "."
5550 rev_ = "."
5657 names = [t.strip() for t in (name1,) + names]
5551 names = [t.strip() for t in (name1,) + names]
5658 if len(names) != len(set(names)):
5552 if len(names) != len(set(names)):
5659 raise util.Abort(_('tag names must be unique'))
5553 raise util.Abort(_('tag names must be unique'))
5660 for n in names:
5554 for n in names:
5661 scmutil.checknewlabel(repo, n, 'tag')
5555 scmutil.checknewlabel(repo, n, 'tag')
5662 if not n:
5556 if not n:
5663 raise util.Abort(_('tag names cannot consist entirely of '
5557 raise util.Abort(_('tag names cannot consist entirely of '
5664 'whitespace'))
5558 'whitespace'))
5665 if opts.get('rev') and opts.get('remove'):
5559 if opts.get('rev') and opts.get('remove'):
5666 raise util.Abort(_("--rev and --remove are incompatible"))
5560 raise util.Abort(_("--rev and --remove are incompatible"))
5667 if opts.get('rev'):
5561 if opts.get('rev'):
5668 rev_ = opts['rev']
5562 rev_ = opts['rev']
5669 message = opts.get('message')
5563 message = opts.get('message')
5670 if opts.get('remove'):
5564 if opts.get('remove'):
5671 expectedtype = opts.get('local') and 'local' or 'global'
5565 expectedtype = opts.get('local') and 'local' or 'global'
5672 for n in names:
5566 for n in names:
5673 if not repo.tagtype(n):
5567 if not repo.tagtype(n):
5674 raise util.Abort(_("tag '%s' does not exist") % n)
5568 raise util.Abort(_("tag '%s' does not exist") % n)
5675 if repo.tagtype(n) != expectedtype:
5569 if repo.tagtype(n) != expectedtype:
5676 if expectedtype == 'global':
5570 if expectedtype == 'global':
5677 raise util.Abort(_("tag '%s' is not a global tag") % n)
5571 raise util.Abort(_("tag '%s' is not a global tag") % n)
5678 else:
5572 else:
5679 raise util.Abort(_("tag '%s' is not a local tag") % n)
5573 raise util.Abort(_("tag '%s' is not a local tag") % n)
5680 rev_ = nullid
5574 rev_ = nullid
5681 if not message:
5575 if not message:
5682 # we don't translate commit messages
5576 # we don't translate commit messages
5683 message = 'Removed tag %s' % ', '.join(names)
5577 message = 'Removed tag %s' % ', '.join(names)
5684 elif not opts.get('force'):
5578 elif not opts.get('force'):
5685 for n in names:
5579 for n in names:
5686 if n in repo.tags():
5580 if n in repo.tags():
5687 raise util.Abort(_("tag '%s' already exists "
5581 raise util.Abort(_("tag '%s' already exists "
5688 "(use -f to force)") % n)
5582 "(use -f to force)") % n)
5689 if not opts.get('local'):
5583 if not opts.get('local'):
5690 p1, p2 = repo.dirstate.parents()
5584 p1, p2 = repo.dirstate.parents()
5691 if p2 != nullid:
5585 if p2 != nullid:
5692 raise util.Abort(_('uncommitted merge'))
5586 raise util.Abort(_('uncommitted merge'))
5693 bheads = repo.branchheads()
5587 bheads = repo.branchheads()
5694 if not opts.get('force') and bheads and p1 not in bheads:
5588 if not opts.get('force') and bheads and p1 not in bheads:
5695 raise util.Abort(_('not at a branch head (use -f to force)'))
5589 raise util.Abort(_('not at a branch head (use -f to force)'))
5696 r = scmutil.revsingle(repo, rev_).node()
5590 r = scmutil.revsingle(repo, rev_).node()
5697
5591
5698 if not message:
5592 if not message:
5699 # we don't translate commit messages
5593 # we don't translate commit messages
5700 message = ('Added tag %s for changeset %s' %
5594 message = ('Added tag %s for changeset %s' %
5701 (', '.join(names), short(r)))
5595 (', '.join(names), short(r)))
5702
5596
5703 date = opts.get('date')
5597 date = opts.get('date')
5704 if date:
5598 if date:
5705 date = util.parsedate(date)
5599 date = util.parsedate(date)
5706
5600
5707 if opts.get('edit'):
5601 if opts.get('edit'):
5708 message = ui.edit(message, ui.username())
5602 message = ui.edit(message, ui.username())
5709
5603
5710 # don't allow tagging the null rev
5604 # don't allow tagging the null rev
5711 if (not opts.get('remove') and
5605 if (not opts.get('remove') and
5712 scmutil.revsingle(repo, rev_).rev() == nullrev):
5606 scmutil.revsingle(repo, rev_).rev() == nullrev):
5713 raise util.Abort(_("cannot tag null revision"))
5607 raise util.Abort(_("cannot tag null revision"))
5714
5608
5715 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5609 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5716 finally:
5610 finally:
5717 release(lock, wlock)
5611 release(lock, wlock)
5718
5612
5719 @command('tags', [], '')
5613 @command('tags', [], '')
5720 def tags(ui, repo, **opts):
5614 def tags(ui, repo, **opts):
5721 """list repository tags
5615 """list repository tags
5722
5616
5723 This lists both regular and local tags. When the -v/--verbose
5617 This lists both regular and local tags. When the -v/--verbose
5724 switch is used, a third column "local" is printed for local tags.
5618 switch is used, a third column "local" is printed for local tags.
5725
5619
5726 Returns 0 on success.
5620 Returns 0 on success.
5727 """
5621 """
5728
5622
5729 fm = ui.formatter('tags', opts)
5623 fm = ui.formatter('tags', opts)
5730 hexfunc = ui.debugflag and hex or short
5624 hexfunc = ui.debugflag and hex or short
5731 tagtype = ""
5625 tagtype = ""
5732
5626
5733 for t, n in reversed(repo.tagslist()):
5627 for t, n in reversed(repo.tagslist()):
5734 hn = hexfunc(n)
5628 hn = hexfunc(n)
5735 label = 'tags.normal'
5629 label = 'tags.normal'
5736 tagtype = ''
5630 tagtype = ''
5737 if repo.tagtype(t) == 'local':
5631 if repo.tagtype(t) == 'local':
5738 label = 'tags.local'
5632 label = 'tags.local'
5739 tagtype = 'local'
5633 tagtype = 'local'
5740
5634
5741 fm.startitem()
5635 fm.startitem()
5742 fm.write('tag', '%s', t, label=label)
5636 fm.write('tag', '%s', t, label=label)
5743 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5637 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5744 fm.condwrite(not ui.quiet, 'rev id', fmt,
5638 fm.condwrite(not ui.quiet, 'rev id', fmt,
5745 repo.changelog.rev(n), hn, label=label)
5639 repo.changelog.rev(n), hn, label=label)
5746 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5640 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5747 tagtype, label=label)
5641 tagtype, label=label)
5748 fm.plain('\n')
5642 fm.plain('\n')
5749 fm.end()
5643 fm.end()
5750
5644
5751 @command('tip',
5645 @command('tip',
5752 [('p', 'patch', None, _('show patch')),
5646 [('p', 'patch', None, _('show patch')),
5753 ('g', 'git', None, _('use git extended diff format')),
5647 ('g', 'git', None, _('use git extended diff format')),
5754 ] + templateopts,
5648 ] + templateopts,
5755 _('[-p] [-g]'))
5649 _('[-p] [-g]'))
5756 def tip(ui, repo, **opts):
5650 def tip(ui, repo, **opts):
5757 """show the tip revision (DEPRECATED)
5651 """show the tip revision (DEPRECATED)
5758
5652
5759 The tip revision (usually just called the tip) is the changeset
5653 The tip revision (usually just called the tip) is the changeset
5760 most recently added to the repository (and therefore the most
5654 most recently added to the repository (and therefore the most
5761 recently changed head).
5655 recently changed head).
5762
5656
5763 If you have just made a commit, that commit will be the tip. If
5657 If you have just made a commit, that commit will be the tip. If
5764 you have just pulled changes from another repository, the tip of
5658 you have just pulled changes from another repository, the tip of
5765 that repository becomes the current tip. The "tip" tag is special
5659 that repository becomes the current tip. The "tip" tag is special
5766 and cannot be renamed or assigned to a different changeset.
5660 and cannot be renamed or assigned to a different changeset.
5767
5661
5768 This command is deprecated, please use :hg:`heads` instead.
5662 This command is deprecated, please use :hg:`heads` instead.
5769
5663
5770 Returns 0 on success.
5664 Returns 0 on success.
5771 """
5665 """
5772 displayer = cmdutil.show_changeset(ui, repo, opts)
5666 displayer = cmdutil.show_changeset(ui, repo, opts)
5773 displayer.show(repo['tip'])
5667 displayer.show(repo['tip'])
5774 displayer.close()
5668 displayer.close()
5775
5669
5776 @command('unbundle',
5670 @command('unbundle',
5777 [('u', 'update', None,
5671 [('u', 'update', None,
5778 _('update to new branch head if changesets were unbundled'))],
5672 _('update to new branch head if changesets were unbundled'))],
5779 _('[-u] FILE...'))
5673 _('[-u] FILE...'))
5780 def unbundle(ui, repo, fname1, *fnames, **opts):
5674 def unbundle(ui, repo, fname1, *fnames, **opts):
5781 """apply one or more changegroup files
5675 """apply one or more changegroup files
5782
5676
5783 Apply one or more compressed changegroup files generated by the
5677 Apply one or more compressed changegroup files generated by the
5784 bundle command.
5678 bundle command.
5785
5679
5786 Returns 0 on success, 1 if an update has unresolved files.
5680 Returns 0 on success, 1 if an update has unresolved files.
5787 """
5681 """
5788 fnames = (fname1,) + fnames
5682 fnames = (fname1,) + fnames
5789
5683
5790 lock = repo.lock()
5684 lock = repo.lock()
5791 wc = repo['.']
5685 wc = repo['.']
5792 try:
5686 try:
5793 for fname in fnames:
5687 for fname in fnames:
5794 f = hg.openpath(ui, fname)
5688 f = hg.openpath(ui, fname)
5795 gen = changegroup.readbundle(f, fname)
5689 gen = changegroup.readbundle(f, fname)
5796 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5690 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5797 finally:
5691 finally:
5798 lock.release()
5692 lock.release()
5799 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5693 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5800 return postincoming(ui, repo, modheads, opts.get('update'), None)
5694 return postincoming(ui, repo, modheads, opts.get('update'), None)
5801
5695
5802 @command('^update|up|checkout|co',
5696 @command('^update|up|checkout|co',
5803 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5697 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5804 ('c', 'check', None,
5698 ('c', 'check', None,
5805 _('update across branches if no uncommitted changes')),
5699 _('update across branches if no uncommitted changes')),
5806 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5700 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5807 ('r', 'rev', '', _('revision'), _('REV'))],
5701 ('r', 'rev', '', _('revision'), _('REV'))],
5808 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5702 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5809 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5703 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5810 """update working directory (or switch revisions)
5704 """update working directory (or switch revisions)
5811
5705
5812 Update the repository's working directory to the specified
5706 Update the repository's working directory to the specified
5813 changeset. If no changeset is specified, update to the tip of the
5707 changeset. If no changeset is specified, update to the tip of the
5814 current named branch and move the current bookmark (see :hg:`help
5708 current named branch and move the current bookmark (see :hg:`help
5815 bookmarks`).
5709 bookmarks`).
5816
5710
5817 Update sets the working directory's parent revision to the specified
5711 Update sets the working directory's parent revision to the specified
5818 changeset (see :hg:`help parents`).
5712 changeset (see :hg:`help parents`).
5819
5713
5820 If the changeset is not a descendant or ancestor of the working
5714 If the changeset is not a descendant or ancestor of the working
5821 directory's parent, the update is aborted. With the -c/--check
5715 directory's parent, the update is aborted. With the -c/--check
5822 option, the working directory is checked for uncommitted changes; if
5716 option, the working directory is checked for uncommitted changes; if
5823 none are found, the working directory is updated to the specified
5717 none are found, the working directory is updated to the specified
5824 changeset.
5718 changeset.
5825
5719
5826 .. container:: verbose
5720 .. container:: verbose
5827
5721
5828 The following rules apply when the working directory contains
5722 The following rules apply when the working directory contains
5829 uncommitted changes:
5723 uncommitted changes:
5830
5724
5831 1. If neither -c/--check nor -C/--clean is specified, and if
5725 1. If neither -c/--check nor -C/--clean is specified, and if
5832 the requested changeset is an ancestor or descendant of
5726 the requested changeset is an ancestor or descendant of
5833 the working directory's parent, the uncommitted changes
5727 the working directory's parent, the uncommitted changes
5834 are merged into the requested changeset and the merged
5728 are merged into the requested changeset and the merged
5835 result is left uncommitted. If the requested changeset is
5729 result is left uncommitted. If the requested changeset is
5836 not an ancestor or descendant (that is, it is on another
5730 not an ancestor or descendant (that is, it is on another
5837 branch), the update is aborted and the uncommitted changes
5731 branch), the update is aborted and the uncommitted changes
5838 are preserved.
5732 are preserved.
5839
5733
5840 2. With the -c/--check option, the update is aborted and the
5734 2. With the -c/--check option, the update is aborted and the
5841 uncommitted changes are preserved.
5735 uncommitted changes are preserved.
5842
5736
5843 3. With the -C/--clean option, uncommitted changes are discarded and
5737 3. With the -C/--clean option, uncommitted changes are discarded and
5844 the working directory is updated to the requested changeset.
5738 the working directory is updated to the requested changeset.
5845
5739
5846 To cancel an uncommitted merge (and lose your changes), use
5740 To cancel an uncommitted merge (and lose your changes), use
5847 :hg:`update --clean .`.
5741 :hg:`update --clean .`.
5848
5742
5849 Use null as the changeset to remove the working directory (like
5743 Use null as the changeset to remove the working directory (like
5850 :hg:`clone -U`).
5744 :hg:`clone -U`).
5851
5745
5852 If you want to revert just one file to an older revision, use
5746 If you want to revert just one file to an older revision, use
5853 :hg:`revert [-r REV] NAME`.
5747 :hg:`revert [-r REV] NAME`.
5854
5748
5855 See :hg:`help dates` for a list of formats valid for -d/--date.
5749 See :hg:`help dates` for a list of formats valid for -d/--date.
5856
5750
5857 Returns 0 on success, 1 if there are unresolved files.
5751 Returns 0 on success, 1 if there are unresolved files.
5858 """
5752 """
5859 if rev and node:
5753 if rev and node:
5860 raise util.Abort(_("please specify just one revision"))
5754 raise util.Abort(_("please specify just one revision"))
5861
5755
5862 if rev is None or rev == '':
5756 if rev is None or rev == '':
5863 rev = node
5757 rev = node
5864
5758
5865 cmdutil.clearunfinished(repo)
5759 cmdutil.clearunfinished(repo)
5866
5760
5867 # with no argument, we also move the current bookmark, if any
5761 # with no argument, we also move the current bookmark, if any
5868 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5762 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5869
5763
5870 # if we defined a bookmark, we have to remember the original bookmark name
5764 # if we defined a bookmark, we have to remember the original bookmark name
5871 brev = rev
5765 brev = rev
5872 rev = scmutil.revsingle(repo, rev, rev).rev()
5766 rev = scmutil.revsingle(repo, rev, rev).rev()
5873
5767
5874 if check and clean:
5768 if check and clean:
5875 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5769 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5876
5770
5877 if date:
5771 if date:
5878 if rev is not None:
5772 if rev is not None:
5879 raise util.Abort(_("you can't specify a revision and a date"))
5773 raise util.Abort(_("you can't specify a revision and a date"))
5880 rev = cmdutil.finddate(ui, repo, date)
5774 rev = cmdutil.finddate(ui, repo, date)
5881
5775
5882 if check:
5776 if check:
5883 c = repo[None]
5777 c = repo[None]
5884 if c.dirty(merge=False, branch=False, missing=True):
5778 if c.dirty(merge=False, branch=False, missing=True):
5885 raise util.Abort(_("uncommitted changes"))
5779 raise util.Abort(_("uncommitted changes"))
5886 if rev is None:
5780 if rev is None:
5887 rev = repo[repo[None].branch()].rev()
5781 rev = repo[repo[None].branch()].rev()
5888 mergemod._checkunknown(repo, repo[None], repo[rev])
5782 mergemod._checkunknown(repo, repo[None], repo[rev])
5889
5783
5890 if clean:
5784 if clean:
5891 ret = hg.clean(repo, rev)
5785 ret = hg.clean(repo, rev)
5892 else:
5786 else:
5893 ret = hg.update(repo, rev)
5787 ret = hg.update(repo, rev)
5894
5788
5895 if not ret and movemarkfrom:
5789 if not ret and movemarkfrom:
5896 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5790 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5897 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5791 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5898 elif brev in repo._bookmarks:
5792 elif brev in repo._bookmarks:
5899 bookmarks.setcurrent(repo, brev)
5793 bookmarks.setcurrent(repo, brev)
5900 elif brev:
5794 elif brev:
5901 bookmarks.unsetcurrent(repo)
5795 bookmarks.unsetcurrent(repo)
5902
5796
5903 return ret
5797 return ret
5904
5798
5905 @command('verify', [])
5799 @command('verify', [])
5906 def verify(ui, repo):
5800 def verify(ui, repo):
5907 """verify the integrity of the repository
5801 """verify the integrity of the repository
5908
5802
5909 Verify the integrity of the current repository.
5803 Verify the integrity of the current repository.
5910
5804
5911 This will perform an extensive check of the repository's
5805 This will perform an extensive check of the repository's
5912 integrity, validating the hashes and checksums of each entry in
5806 integrity, validating the hashes and checksums of each entry in
5913 the changelog, manifest, and tracked files, as well as the
5807 the changelog, manifest, and tracked files, as well as the
5914 integrity of their crosslinks and indices.
5808 integrity of their crosslinks and indices.
5915
5809
5916 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5810 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5917 for more information about recovery from corruption of the
5811 for more information about recovery from corruption of the
5918 repository.
5812 repository.
5919
5813
5920 Returns 0 on success, 1 if errors are encountered.
5814 Returns 0 on success, 1 if errors are encountered.
5921 """
5815 """
5922 return hg.verify(repo)
5816 return hg.verify(repo)
5923
5817
5924 @command('version', [])
5818 @command('version', [])
5925 def version_(ui):
5819 def version_(ui):
5926 """output version and copyright information"""
5820 """output version and copyright information"""
5927 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5821 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5928 % util.version())
5822 % util.version())
5929 ui.status(_(
5823 ui.status(_(
5930 "(see http://mercurial.selenic.com for more information)\n"
5824 "(see http://mercurial.selenic.com for more information)\n"
5931 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
5825 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
5932 "This is free software; see the source for copying conditions. "
5826 "This is free software; see the source for copying conditions. "
5933 "There is NO\nwarranty; "
5827 "There is NO\nwarranty; "
5934 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5828 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5935 ))
5829 ))
5936
5830
5937 norepo = ("clone init version help debugcommands debugcomplete"
5831 norepo = ("clone init version help debugcommands debugcomplete"
5938 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5832 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5939 " debugknown debuggetbundle debugbundle")
5833 " debugknown debuggetbundle debugbundle")
5940 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5834 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5941 " debugdata debugindex debugindexdot debugrevlog")
5835 " debugdata debugindex debugindexdot debugrevlog")
5942 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5836 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5943 " remove resolve status debugwalk")
5837 " remove resolve status debugwalk")
General Comments 0
You need to be logged in to leave comments. Login now