##// END OF EJS Templates
commands: add norepo argument to command decorator...
Gregory Szorc -
r21767:75a96326 default
parent child Browse files
Show More
@@ -1,2554 +1,2563
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 getcommiteditor(edit=False, finishdesc=None, extramsg=None, **opts):
112 def getcommiteditor(edit=False, finishdesc=None, extramsg=None, **opts):
113 """get appropriate commit message editor according to '--edit' option
113 """get appropriate commit message editor according to '--edit' option
114
114
115 'finishdesc' is a function to be called with edited commit message
115 'finishdesc' is a function to be called with edited commit message
116 (= 'description' of the new changeset) just after editing, but
116 (= 'description' of the new changeset) just after editing, but
117 before checking empty-ness. It should return actual text to be
117 before checking empty-ness. It should return actual text to be
118 stored into history. This allows to change description before
118 stored into history. This allows to change description before
119 storing.
119 storing.
120
120
121 'extramsg' is a extra message to be shown in the editor instead of
121 'extramsg' is a extra message to be shown in the editor instead of
122 'Leave message empty to abort commit' line. 'HG: ' prefix and EOL
122 'Leave message empty to abort commit' line. 'HG: ' prefix and EOL
123 is automatically added.
123 is automatically added.
124
124
125 'getcommiteditor' returns 'commitforceeditor' regardless of
125 'getcommiteditor' returns 'commitforceeditor' regardless of
126 'edit', if one of 'finishdesc' or 'extramsg' is specified, because
126 'edit', if one of 'finishdesc' or 'extramsg' is specified, because
127 they are specific for usage in MQ.
127 they are specific for usage in MQ.
128 """
128 """
129 if edit or finishdesc or extramsg:
129 if edit or finishdesc or extramsg:
130 return lambda r, c, s: commitforceeditor(r, c, s,
130 return lambda r, c, s: commitforceeditor(r, c, s,
131 finishdesc=finishdesc,
131 finishdesc=finishdesc,
132 extramsg=extramsg)
132 extramsg=extramsg)
133 else:
133 else:
134 return commiteditor
134 return commiteditor
135
135
136 def loglimit(opts):
136 def loglimit(opts):
137 """get the log limit according to option -l/--limit"""
137 """get the log limit according to option -l/--limit"""
138 limit = opts.get('limit')
138 limit = opts.get('limit')
139 if limit:
139 if limit:
140 try:
140 try:
141 limit = int(limit)
141 limit = int(limit)
142 except ValueError:
142 except ValueError:
143 raise util.Abort(_('limit must be a positive integer'))
143 raise util.Abort(_('limit must be a positive integer'))
144 if limit <= 0:
144 if limit <= 0:
145 raise util.Abort(_('limit must be positive'))
145 raise util.Abort(_('limit must be positive'))
146 else:
146 else:
147 limit = None
147 limit = None
148 return limit
148 return limit
149
149
150 def makefilename(repo, pat, node, desc=None,
150 def makefilename(repo, pat, node, desc=None,
151 total=None, seqno=None, revwidth=None, pathname=None):
151 total=None, seqno=None, revwidth=None, pathname=None):
152 node_expander = {
152 node_expander = {
153 'H': lambda: hex(node),
153 'H': lambda: hex(node),
154 'R': lambda: str(repo.changelog.rev(node)),
154 'R': lambda: str(repo.changelog.rev(node)),
155 'h': lambda: short(node),
155 'h': lambda: short(node),
156 'm': lambda: re.sub('[^\w]', '_', str(desc))
156 'm': lambda: re.sub('[^\w]', '_', str(desc))
157 }
157 }
158 expander = {
158 expander = {
159 '%': lambda: '%',
159 '%': lambda: '%',
160 'b': lambda: os.path.basename(repo.root),
160 'b': lambda: os.path.basename(repo.root),
161 }
161 }
162
162
163 try:
163 try:
164 if node:
164 if node:
165 expander.update(node_expander)
165 expander.update(node_expander)
166 if node:
166 if node:
167 expander['r'] = (lambda:
167 expander['r'] = (lambda:
168 str(repo.changelog.rev(node)).zfill(revwidth or 0))
168 str(repo.changelog.rev(node)).zfill(revwidth or 0))
169 if total is not None:
169 if total is not None:
170 expander['N'] = lambda: str(total)
170 expander['N'] = lambda: str(total)
171 if seqno is not None:
171 if seqno is not None:
172 expander['n'] = lambda: str(seqno)
172 expander['n'] = lambda: str(seqno)
173 if total is not None and seqno is not None:
173 if total is not None and seqno is not None:
174 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
174 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
175 if pathname is not None:
175 if pathname is not None:
176 expander['s'] = lambda: os.path.basename(pathname)
176 expander['s'] = lambda: os.path.basename(pathname)
177 expander['d'] = lambda: os.path.dirname(pathname) or '.'
177 expander['d'] = lambda: os.path.dirname(pathname) or '.'
178 expander['p'] = lambda: pathname
178 expander['p'] = lambda: pathname
179
179
180 newname = []
180 newname = []
181 patlen = len(pat)
181 patlen = len(pat)
182 i = 0
182 i = 0
183 while i < patlen:
183 while i < patlen:
184 c = pat[i]
184 c = pat[i]
185 if c == '%':
185 if c == '%':
186 i += 1
186 i += 1
187 c = pat[i]
187 c = pat[i]
188 c = expander[c]()
188 c = expander[c]()
189 newname.append(c)
189 newname.append(c)
190 i += 1
190 i += 1
191 return ''.join(newname)
191 return ''.join(newname)
192 except KeyError, inst:
192 except KeyError, inst:
193 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
193 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
194 inst.args[0])
194 inst.args[0])
195
195
196 def makefileobj(repo, pat, node=None, desc=None, total=None,
196 def makefileobj(repo, pat, node=None, desc=None, total=None,
197 seqno=None, revwidth=None, mode='wb', modemap=None,
197 seqno=None, revwidth=None, mode='wb', modemap=None,
198 pathname=None):
198 pathname=None):
199
199
200 writable = mode not in ('r', 'rb')
200 writable = mode not in ('r', 'rb')
201
201
202 if not pat or pat == '-':
202 if not pat or pat == '-':
203 fp = writable and repo.ui.fout or repo.ui.fin
203 fp = writable and repo.ui.fout or repo.ui.fin
204 if util.safehasattr(fp, 'fileno'):
204 if util.safehasattr(fp, 'fileno'):
205 return os.fdopen(os.dup(fp.fileno()), mode)
205 return os.fdopen(os.dup(fp.fileno()), mode)
206 else:
206 else:
207 # if this fp can't be duped properly, return
207 # if this fp can't be duped properly, return
208 # a dummy object that can be closed
208 # a dummy object that can be closed
209 class wrappedfileobj(object):
209 class wrappedfileobj(object):
210 noop = lambda x: None
210 noop = lambda x: None
211 def __init__(self, f):
211 def __init__(self, f):
212 self.f = f
212 self.f = f
213 def __getattr__(self, attr):
213 def __getattr__(self, attr):
214 if attr == 'close':
214 if attr == 'close':
215 return self.noop
215 return self.noop
216 else:
216 else:
217 return getattr(self.f, attr)
217 return getattr(self.f, attr)
218
218
219 return wrappedfileobj(fp)
219 return wrappedfileobj(fp)
220 if util.safehasattr(pat, 'write') and writable:
220 if util.safehasattr(pat, 'write') and writable:
221 return pat
221 return pat
222 if util.safehasattr(pat, 'read') and 'r' in mode:
222 if util.safehasattr(pat, 'read') and 'r' in mode:
223 return pat
223 return pat
224 fn = makefilename(repo, pat, node, desc, total, seqno, revwidth, pathname)
224 fn = makefilename(repo, pat, node, desc, total, seqno, revwidth, pathname)
225 if modemap is not None:
225 if modemap is not None:
226 mode = modemap.get(fn, mode)
226 mode = modemap.get(fn, mode)
227 if mode == 'wb':
227 if mode == 'wb':
228 modemap[fn] = 'ab'
228 modemap[fn] = 'ab'
229 return open(fn, mode)
229 return open(fn, mode)
230
230
231 def openrevlog(repo, cmd, file_, opts):
231 def openrevlog(repo, cmd, file_, opts):
232 """opens the changelog, manifest, a filelog or a given revlog"""
232 """opens the changelog, manifest, a filelog or a given revlog"""
233 cl = opts['changelog']
233 cl = opts['changelog']
234 mf = opts['manifest']
234 mf = opts['manifest']
235 msg = None
235 msg = None
236 if cl and mf:
236 if cl and mf:
237 msg = _('cannot specify --changelog and --manifest at the same time')
237 msg = _('cannot specify --changelog and --manifest at the same time')
238 elif cl or mf:
238 elif cl or mf:
239 if file_:
239 if file_:
240 msg = _('cannot specify filename with --changelog or --manifest')
240 msg = _('cannot specify filename with --changelog or --manifest')
241 elif not repo:
241 elif not repo:
242 msg = _('cannot specify --changelog or --manifest '
242 msg = _('cannot specify --changelog or --manifest '
243 'without a repository')
243 'without a repository')
244 if msg:
244 if msg:
245 raise util.Abort(msg)
245 raise util.Abort(msg)
246
246
247 r = None
247 r = None
248 if repo:
248 if repo:
249 if cl:
249 if cl:
250 r = repo.unfiltered().changelog
250 r = repo.unfiltered().changelog
251 elif mf:
251 elif mf:
252 r = repo.manifest
252 r = repo.manifest
253 elif file_:
253 elif file_:
254 filelog = repo.file(file_)
254 filelog = repo.file(file_)
255 if len(filelog):
255 if len(filelog):
256 r = filelog
256 r = filelog
257 if not r:
257 if not r:
258 if not file_:
258 if not file_:
259 raise error.CommandError(cmd, _('invalid arguments'))
259 raise error.CommandError(cmd, _('invalid arguments'))
260 if not os.path.isfile(file_):
260 if not os.path.isfile(file_):
261 raise util.Abort(_("revlog '%s' not found") % file_)
261 raise util.Abort(_("revlog '%s' not found") % file_)
262 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
262 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
263 file_[:-2] + ".i")
263 file_[:-2] + ".i")
264 return r
264 return r
265
265
266 def copy(ui, repo, pats, opts, rename=False):
266 def copy(ui, repo, pats, opts, rename=False):
267 # called with the repo lock held
267 # called with the repo lock held
268 #
268 #
269 # hgsep => pathname that uses "/" to separate directories
269 # hgsep => pathname that uses "/" to separate directories
270 # ossep => pathname that uses os.sep to separate directories
270 # ossep => pathname that uses os.sep to separate directories
271 cwd = repo.getcwd()
271 cwd = repo.getcwd()
272 targets = {}
272 targets = {}
273 after = opts.get("after")
273 after = opts.get("after")
274 dryrun = opts.get("dry_run")
274 dryrun = opts.get("dry_run")
275 wctx = repo[None]
275 wctx = repo[None]
276
276
277 def walkpat(pat):
277 def walkpat(pat):
278 srcs = []
278 srcs = []
279 badstates = after and '?' or '?r'
279 badstates = after and '?' or '?r'
280 m = scmutil.match(repo[None], [pat], opts, globbed=True)
280 m = scmutil.match(repo[None], [pat], opts, globbed=True)
281 for abs in repo.walk(m):
281 for abs in repo.walk(m):
282 state = repo.dirstate[abs]
282 state = repo.dirstate[abs]
283 rel = m.rel(abs)
283 rel = m.rel(abs)
284 exact = m.exact(abs)
284 exact = m.exact(abs)
285 if state in badstates:
285 if state in badstates:
286 if exact and state == '?':
286 if exact and state == '?':
287 ui.warn(_('%s: not copying - file is not managed\n') % rel)
287 ui.warn(_('%s: not copying - file is not managed\n') % rel)
288 if exact and state == 'r':
288 if exact and state == 'r':
289 ui.warn(_('%s: not copying - file has been marked for'
289 ui.warn(_('%s: not copying - file has been marked for'
290 ' remove\n') % rel)
290 ' remove\n') % rel)
291 continue
291 continue
292 # abs: hgsep
292 # abs: hgsep
293 # rel: ossep
293 # rel: ossep
294 srcs.append((abs, rel, exact))
294 srcs.append((abs, rel, exact))
295 return srcs
295 return srcs
296
296
297 # abssrc: hgsep
297 # abssrc: hgsep
298 # relsrc: ossep
298 # relsrc: ossep
299 # otarget: ossep
299 # otarget: ossep
300 def copyfile(abssrc, relsrc, otarget, exact):
300 def copyfile(abssrc, relsrc, otarget, exact):
301 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
301 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
302 if '/' in abstarget:
302 if '/' in abstarget:
303 # We cannot normalize abstarget itself, this would prevent
303 # We cannot normalize abstarget itself, this would prevent
304 # case only renames, like a => A.
304 # case only renames, like a => A.
305 abspath, absname = abstarget.rsplit('/', 1)
305 abspath, absname = abstarget.rsplit('/', 1)
306 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
306 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
307 reltarget = repo.pathto(abstarget, cwd)
307 reltarget = repo.pathto(abstarget, cwd)
308 target = repo.wjoin(abstarget)
308 target = repo.wjoin(abstarget)
309 src = repo.wjoin(abssrc)
309 src = repo.wjoin(abssrc)
310 state = repo.dirstate[abstarget]
310 state = repo.dirstate[abstarget]
311
311
312 scmutil.checkportable(ui, abstarget)
312 scmutil.checkportable(ui, abstarget)
313
313
314 # check for collisions
314 # check for collisions
315 prevsrc = targets.get(abstarget)
315 prevsrc = targets.get(abstarget)
316 if prevsrc is not None:
316 if prevsrc is not None:
317 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
317 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
318 (reltarget, repo.pathto(abssrc, cwd),
318 (reltarget, repo.pathto(abssrc, cwd),
319 repo.pathto(prevsrc, cwd)))
319 repo.pathto(prevsrc, cwd)))
320 return
320 return
321
321
322 # check for overwrites
322 # check for overwrites
323 exists = os.path.lexists(target)
323 exists = os.path.lexists(target)
324 samefile = False
324 samefile = False
325 if exists and abssrc != abstarget:
325 if exists and abssrc != abstarget:
326 if (repo.dirstate.normalize(abssrc) ==
326 if (repo.dirstate.normalize(abssrc) ==
327 repo.dirstate.normalize(abstarget)):
327 repo.dirstate.normalize(abstarget)):
328 if not rename:
328 if not rename:
329 ui.warn(_("%s: can't copy - same file\n") % reltarget)
329 ui.warn(_("%s: can't copy - same file\n") % reltarget)
330 return
330 return
331 exists = False
331 exists = False
332 samefile = True
332 samefile = True
333
333
334 if not after and exists or after and state in 'mn':
334 if not after and exists or after and state in 'mn':
335 if not opts['force']:
335 if not opts['force']:
336 ui.warn(_('%s: not overwriting - file exists\n') %
336 ui.warn(_('%s: not overwriting - file exists\n') %
337 reltarget)
337 reltarget)
338 return
338 return
339
339
340 if after:
340 if after:
341 if not exists:
341 if not exists:
342 if rename:
342 if rename:
343 ui.warn(_('%s: not recording move - %s does not exist\n') %
343 ui.warn(_('%s: not recording move - %s does not exist\n') %
344 (relsrc, reltarget))
344 (relsrc, reltarget))
345 else:
345 else:
346 ui.warn(_('%s: not recording copy - %s does not exist\n') %
346 ui.warn(_('%s: not recording copy - %s does not exist\n') %
347 (relsrc, reltarget))
347 (relsrc, reltarget))
348 return
348 return
349 elif not dryrun:
349 elif not dryrun:
350 try:
350 try:
351 if exists:
351 if exists:
352 os.unlink(target)
352 os.unlink(target)
353 targetdir = os.path.dirname(target) or '.'
353 targetdir = os.path.dirname(target) or '.'
354 if not os.path.isdir(targetdir):
354 if not os.path.isdir(targetdir):
355 os.makedirs(targetdir)
355 os.makedirs(targetdir)
356 if samefile:
356 if samefile:
357 tmp = target + "~hgrename"
357 tmp = target + "~hgrename"
358 os.rename(src, tmp)
358 os.rename(src, tmp)
359 os.rename(tmp, target)
359 os.rename(tmp, target)
360 else:
360 else:
361 util.copyfile(src, target)
361 util.copyfile(src, target)
362 srcexists = True
362 srcexists = True
363 except IOError, inst:
363 except IOError, inst:
364 if inst.errno == errno.ENOENT:
364 if inst.errno == errno.ENOENT:
365 ui.warn(_('%s: deleted in working copy\n') % relsrc)
365 ui.warn(_('%s: deleted in working copy\n') % relsrc)
366 srcexists = False
366 srcexists = False
367 else:
367 else:
368 ui.warn(_('%s: cannot copy - %s\n') %
368 ui.warn(_('%s: cannot copy - %s\n') %
369 (relsrc, inst.strerror))
369 (relsrc, inst.strerror))
370 return True # report a failure
370 return True # report a failure
371
371
372 if ui.verbose or not exact:
372 if ui.verbose or not exact:
373 if rename:
373 if rename:
374 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
374 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
375 else:
375 else:
376 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
376 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
377
377
378 targets[abstarget] = abssrc
378 targets[abstarget] = abssrc
379
379
380 # fix up dirstate
380 # fix up dirstate
381 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
381 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
382 dryrun=dryrun, cwd=cwd)
382 dryrun=dryrun, cwd=cwd)
383 if rename and not dryrun:
383 if rename and not dryrun:
384 if not after and srcexists and not samefile:
384 if not after and srcexists and not samefile:
385 util.unlinkpath(repo.wjoin(abssrc))
385 util.unlinkpath(repo.wjoin(abssrc))
386 wctx.forget([abssrc])
386 wctx.forget([abssrc])
387
387
388 # pat: ossep
388 # pat: ossep
389 # dest ossep
389 # dest ossep
390 # srcs: list of (hgsep, hgsep, ossep, bool)
390 # srcs: list of (hgsep, hgsep, ossep, bool)
391 # return: function that takes hgsep and returns ossep
391 # return: function that takes hgsep and returns ossep
392 def targetpathfn(pat, dest, srcs):
392 def targetpathfn(pat, dest, srcs):
393 if os.path.isdir(pat):
393 if os.path.isdir(pat):
394 abspfx = pathutil.canonpath(repo.root, cwd, pat)
394 abspfx = pathutil.canonpath(repo.root, cwd, pat)
395 abspfx = util.localpath(abspfx)
395 abspfx = util.localpath(abspfx)
396 if destdirexists:
396 if destdirexists:
397 striplen = len(os.path.split(abspfx)[0])
397 striplen = len(os.path.split(abspfx)[0])
398 else:
398 else:
399 striplen = len(abspfx)
399 striplen = len(abspfx)
400 if striplen:
400 if striplen:
401 striplen += len(os.sep)
401 striplen += len(os.sep)
402 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
402 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
403 elif destdirexists:
403 elif destdirexists:
404 res = lambda p: os.path.join(dest,
404 res = lambda p: os.path.join(dest,
405 os.path.basename(util.localpath(p)))
405 os.path.basename(util.localpath(p)))
406 else:
406 else:
407 res = lambda p: dest
407 res = lambda p: dest
408 return res
408 return res
409
409
410 # pat: ossep
410 # pat: ossep
411 # dest ossep
411 # dest ossep
412 # srcs: list of (hgsep, hgsep, ossep, bool)
412 # srcs: list of (hgsep, hgsep, ossep, bool)
413 # return: function that takes hgsep and returns ossep
413 # return: function that takes hgsep and returns ossep
414 def targetpathafterfn(pat, dest, srcs):
414 def targetpathafterfn(pat, dest, srcs):
415 if matchmod.patkind(pat):
415 if matchmod.patkind(pat):
416 # a mercurial pattern
416 # a mercurial pattern
417 res = lambda p: os.path.join(dest,
417 res = lambda p: os.path.join(dest,
418 os.path.basename(util.localpath(p)))
418 os.path.basename(util.localpath(p)))
419 else:
419 else:
420 abspfx = pathutil.canonpath(repo.root, cwd, pat)
420 abspfx = pathutil.canonpath(repo.root, cwd, pat)
421 if len(abspfx) < len(srcs[0][0]):
421 if len(abspfx) < len(srcs[0][0]):
422 # A directory. Either the target path contains the last
422 # A directory. Either the target path contains the last
423 # component of the source path or it does not.
423 # component of the source path or it does not.
424 def evalpath(striplen):
424 def evalpath(striplen):
425 score = 0
425 score = 0
426 for s in srcs:
426 for s in srcs:
427 t = os.path.join(dest, util.localpath(s[0])[striplen:])
427 t = os.path.join(dest, util.localpath(s[0])[striplen:])
428 if os.path.lexists(t):
428 if os.path.lexists(t):
429 score += 1
429 score += 1
430 return score
430 return score
431
431
432 abspfx = util.localpath(abspfx)
432 abspfx = util.localpath(abspfx)
433 striplen = len(abspfx)
433 striplen = len(abspfx)
434 if striplen:
434 if striplen:
435 striplen += len(os.sep)
435 striplen += len(os.sep)
436 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
436 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
437 score = evalpath(striplen)
437 score = evalpath(striplen)
438 striplen1 = len(os.path.split(abspfx)[0])
438 striplen1 = len(os.path.split(abspfx)[0])
439 if striplen1:
439 if striplen1:
440 striplen1 += len(os.sep)
440 striplen1 += len(os.sep)
441 if evalpath(striplen1) > score:
441 if evalpath(striplen1) > score:
442 striplen = striplen1
442 striplen = striplen1
443 res = lambda p: os.path.join(dest,
443 res = lambda p: os.path.join(dest,
444 util.localpath(p)[striplen:])
444 util.localpath(p)[striplen:])
445 else:
445 else:
446 # a file
446 # a file
447 if destdirexists:
447 if destdirexists:
448 res = lambda p: os.path.join(dest,
448 res = lambda p: os.path.join(dest,
449 os.path.basename(util.localpath(p)))
449 os.path.basename(util.localpath(p)))
450 else:
450 else:
451 res = lambda p: dest
451 res = lambda p: dest
452 return res
452 return res
453
453
454
454
455 pats = scmutil.expandpats(pats)
455 pats = scmutil.expandpats(pats)
456 if not pats:
456 if not pats:
457 raise util.Abort(_('no source or destination specified'))
457 raise util.Abort(_('no source or destination specified'))
458 if len(pats) == 1:
458 if len(pats) == 1:
459 raise util.Abort(_('no destination specified'))
459 raise util.Abort(_('no destination specified'))
460 dest = pats.pop()
460 dest = pats.pop()
461 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
461 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
462 if not destdirexists:
462 if not destdirexists:
463 if len(pats) > 1 or matchmod.patkind(pats[0]):
463 if len(pats) > 1 or matchmod.patkind(pats[0]):
464 raise util.Abort(_('with multiple sources, destination must be an '
464 raise util.Abort(_('with multiple sources, destination must be an '
465 'existing directory'))
465 'existing directory'))
466 if util.endswithsep(dest):
466 if util.endswithsep(dest):
467 raise util.Abort(_('destination %s is not a directory') % dest)
467 raise util.Abort(_('destination %s is not a directory') % dest)
468
468
469 tfn = targetpathfn
469 tfn = targetpathfn
470 if after:
470 if after:
471 tfn = targetpathafterfn
471 tfn = targetpathafterfn
472 copylist = []
472 copylist = []
473 for pat in pats:
473 for pat in pats:
474 srcs = walkpat(pat)
474 srcs = walkpat(pat)
475 if not srcs:
475 if not srcs:
476 continue
476 continue
477 copylist.append((tfn(pat, dest, srcs), srcs))
477 copylist.append((tfn(pat, dest, srcs), srcs))
478 if not copylist:
478 if not copylist:
479 raise util.Abort(_('no files to copy'))
479 raise util.Abort(_('no files to copy'))
480
480
481 errors = 0
481 errors = 0
482 for targetpath, srcs in copylist:
482 for targetpath, srcs in copylist:
483 for abssrc, relsrc, exact in srcs:
483 for abssrc, relsrc, exact in srcs:
484 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
484 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
485 errors += 1
485 errors += 1
486
486
487 if errors:
487 if errors:
488 ui.warn(_('(consider using --after)\n'))
488 ui.warn(_('(consider using --after)\n'))
489
489
490 return errors != 0
490 return errors != 0
491
491
492 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
492 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
493 runargs=None, appendpid=False):
493 runargs=None, appendpid=False):
494 '''Run a command as a service.'''
494 '''Run a command as a service.'''
495
495
496 def writepid(pid):
496 def writepid(pid):
497 if opts['pid_file']:
497 if opts['pid_file']:
498 mode = appendpid and 'a' or 'w'
498 mode = appendpid and 'a' or 'w'
499 fp = open(opts['pid_file'], mode)
499 fp = open(opts['pid_file'], mode)
500 fp.write(str(pid) + '\n')
500 fp.write(str(pid) + '\n')
501 fp.close()
501 fp.close()
502
502
503 if opts['daemon'] and not opts['daemon_pipefds']:
503 if opts['daemon'] and not opts['daemon_pipefds']:
504 # Signal child process startup with file removal
504 # Signal child process startup with file removal
505 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
505 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
506 os.close(lockfd)
506 os.close(lockfd)
507 try:
507 try:
508 if not runargs:
508 if not runargs:
509 runargs = util.hgcmd() + sys.argv[1:]
509 runargs = util.hgcmd() + sys.argv[1:]
510 runargs.append('--daemon-pipefds=%s' % lockpath)
510 runargs.append('--daemon-pipefds=%s' % lockpath)
511 # Don't pass --cwd to the child process, because we've already
511 # Don't pass --cwd to the child process, because we've already
512 # changed directory.
512 # changed directory.
513 for i in xrange(1, len(runargs)):
513 for i in xrange(1, len(runargs)):
514 if runargs[i].startswith('--cwd='):
514 if runargs[i].startswith('--cwd='):
515 del runargs[i]
515 del runargs[i]
516 break
516 break
517 elif runargs[i].startswith('--cwd'):
517 elif runargs[i].startswith('--cwd'):
518 del runargs[i:i + 2]
518 del runargs[i:i + 2]
519 break
519 break
520 def condfn():
520 def condfn():
521 return not os.path.exists(lockpath)
521 return not os.path.exists(lockpath)
522 pid = util.rundetached(runargs, condfn)
522 pid = util.rundetached(runargs, condfn)
523 if pid < 0:
523 if pid < 0:
524 raise util.Abort(_('child process failed to start'))
524 raise util.Abort(_('child process failed to start'))
525 writepid(pid)
525 writepid(pid)
526 finally:
526 finally:
527 try:
527 try:
528 os.unlink(lockpath)
528 os.unlink(lockpath)
529 except OSError, e:
529 except OSError, e:
530 if e.errno != errno.ENOENT:
530 if e.errno != errno.ENOENT:
531 raise
531 raise
532 if parentfn:
532 if parentfn:
533 return parentfn(pid)
533 return parentfn(pid)
534 else:
534 else:
535 return
535 return
536
536
537 if initfn:
537 if initfn:
538 initfn()
538 initfn()
539
539
540 if not opts['daemon']:
540 if not opts['daemon']:
541 writepid(os.getpid())
541 writepid(os.getpid())
542
542
543 if opts['daemon_pipefds']:
543 if opts['daemon_pipefds']:
544 lockpath = opts['daemon_pipefds']
544 lockpath = opts['daemon_pipefds']
545 try:
545 try:
546 os.setsid()
546 os.setsid()
547 except AttributeError:
547 except AttributeError:
548 pass
548 pass
549 os.unlink(lockpath)
549 os.unlink(lockpath)
550 util.hidewindow()
550 util.hidewindow()
551 sys.stdout.flush()
551 sys.stdout.flush()
552 sys.stderr.flush()
552 sys.stderr.flush()
553
553
554 nullfd = os.open(os.devnull, os.O_RDWR)
554 nullfd = os.open(os.devnull, os.O_RDWR)
555 logfilefd = nullfd
555 logfilefd = nullfd
556 if logfile:
556 if logfile:
557 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
557 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
558 os.dup2(nullfd, 0)
558 os.dup2(nullfd, 0)
559 os.dup2(logfilefd, 1)
559 os.dup2(logfilefd, 1)
560 os.dup2(logfilefd, 2)
560 os.dup2(logfilefd, 2)
561 if nullfd not in (0, 1, 2):
561 if nullfd not in (0, 1, 2):
562 os.close(nullfd)
562 os.close(nullfd)
563 if logfile and logfilefd not in (0, 1, 2):
563 if logfile and logfilefd not in (0, 1, 2):
564 os.close(logfilefd)
564 os.close(logfilefd)
565
565
566 if runfn:
566 if runfn:
567 return runfn()
567 return runfn()
568
568
569 def tryimportone(ui, repo, hunk, parents, opts, msgs, updatefunc):
569 def tryimportone(ui, repo, hunk, parents, opts, msgs, updatefunc):
570 """Utility function used by commands.import to import a single patch
570 """Utility function used by commands.import to import a single patch
571
571
572 This function is explicitly defined here to help the evolve extension to
572 This function is explicitly defined here to help the evolve extension to
573 wrap this part of the import logic.
573 wrap this part of the import logic.
574
574
575 The API is currently a bit ugly because it a simple code translation from
575 The API is currently a bit ugly because it a simple code translation from
576 the import command. Feel free to make it better.
576 the import command. Feel free to make it better.
577
577
578 :hunk: a patch (as a binary string)
578 :hunk: a patch (as a binary string)
579 :parents: nodes that will be parent of the created commit
579 :parents: nodes that will be parent of the created commit
580 :opts: the full dict of option passed to the import command
580 :opts: the full dict of option passed to the import command
581 :msgs: list to save commit message to.
581 :msgs: list to save commit message to.
582 (used in case we need to save it when failing)
582 (used in case we need to save it when failing)
583 :updatefunc: a function that update a repo to a given node
583 :updatefunc: a function that update a repo to a given node
584 updatefunc(<repo>, <node>)
584 updatefunc(<repo>, <node>)
585 """
585 """
586 tmpname, message, user, date, branch, nodeid, p1, p2 = \
586 tmpname, message, user, date, branch, nodeid, p1, p2 = \
587 patch.extract(ui, hunk)
587 patch.extract(ui, hunk)
588
588
589 editor = getcommiteditor(**opts)
589 editor = getcommiteditor(**opts)
590 update = not opts.get('bypass')
590 update = not opts.get('bypass')
591 strip = opts["strip"]
591 strip = opts["strip"]
592 sim = float(opts.get('similarity') or 0)
592 sim = float(opts.get('similarity') or 0)
593 if not tmpname:
593 if not tmpname:
594 return (None, None, False)
594 return (None, None, False)
595 msg = _('applied to working directory')
595 msg = _('applied to working directory')
596
596
597 rejects = False
597 rejects = False
598
598
599 try:
599 try:
600 cmdline_message = logmessage(ui, opts)
600 cmdline_message = logmessage(ui, opts)
601 if cmdline_message:
601 if cmdline_message:
602 # pickup the cmdline msg
602 # pickup the cmdline msg
603 message = cmdline_message
603 message = cmdline_message
604 elif message:
604 elif message:
605 # pickup the patch msg
605 # pickup the patch msg
606 message = message.strip()
606 message = message.strip()
607 else:
607 else:
608 # launch the editor
608 # launch the editor
609 message = None
609 message = None
610 ui.debug('message:\n%s\n' % message)
610 ui.debug('message:\n%s\n' % message)
611
611
612 if len(parents) == 1:
612 if len(parents) == 1:
613 parents.append(repo[nullid])
613 parents.append(repo[nullid])
614 if opts.get('exact'):
614 if opts.get('exact'):
615 if not nodeid or not p1:
615 if not nodeid or not p1:
616 raise util.Abort(_('not a Mercurial patch'))
616 raise util.Abort(_('not a Mercurial patch'))
617 p1 = repo[p1]
617 p1 = repo[p1]
618 p2 = repo[p2 or nullid]
618 p2 = repo[p2 or nullid]
619 elif p2:
619 elif p2:
620 try:
620 try:
621 p1 = repo[p1]
621 p1 = repo[p1]
622 p2 = repo[p2]
622 p2 = repo[p2]
623 # Without any options, consider p2 only if the
623 # Without any options, consider p2 only if the
624 # patch is being applied on top of the recorded
624 # patch is being applied on top of the recorded
625 # first parent.
625 # first parent.
626 if p1 != parents[0]:
626 if p1 != parents[0]:
627 p1 = parents[0]
627 p1 = parents[0]
628 p2 = repo[nullid]
628 p2 = repo[nullid]
629 except error.RepoError:
629 except error.RepoError:
630 p1, p2 = parents
630 p1, p2 = parents
631 else:
631 else:
632 p1, p2 = parents
632 p1, p2 = parents
633
633
634 n = None
634 n = None
635 if update:
635 if update:
636 if p1 != parents[0]:
636 if p1 != parents[0]:
637 updatefunc(repo, p1.node())
637 updatefunc(repo, p1.node())
638 if p2 != parents[1]:
638 if p2 != parents[1]:
639 repo.setparents(p1.node(), p2.node())
639 repo.setparents(p1.node(), p2.node())
640
640
641 if opts.get('exact') or opts.get('import_branch'):
641 if opts.get('exact') or opts.get('import_branch'):
642 repo.dirstate.setbranch(branch or 'default')
642 repo.dirstate.setbranch(branch or 'default')
643
643
644 partial = opts.get('partial', False)
644 partial = opts.get('partial', False)
645 files = set()
645 files = set()
646 try:
646 try:
647 patch.patch(ui, repo, tmpname, strip=strip, files=files,
647 patch.patch(ui, repo, tmpname, strip=strip, files=files,
648 eolmode=None, similarity=sim / 100.0)
648 eolmode=None, similarity=sim / 100.0)
649 except patch.PatchError, e:
649 except patch.PatchError, e:
650 if not partial:
650 if not partial:
651 raise util.Abort(str(e))
651 raise util.Abort(str(e))
652 if partial:
652 if partial:
653 rejects = True
653 rejects = True
654
654
655 files = list(files)
655 files = list(files)
656 if opts.get('no_commit'):
656 if opts.get('no_commit'):
657 if message:
657 if message:
658 msgs.append(message)
658 msgs.append(message)
659 else:
659 else:
660 if opts.get('exact') or p2:
660 if opts.get('exact') or p2:
661 # If you got here, you either use --force and know what
661 # If you got here, you either use --force and know what
662 # you are doing or used --exact or a merge patch while
662 # you are doing or used --exact or a merge patch while
663 # being updated to its first parent.
663 # being updated to its first parent.
664 m = None
664 m = None
665 else:
665 else:
666 m = scmutil.matchfiles(repo, files or [])
666 m = scmutil.matchfiles(repo, files or [])
667 n = repo.commit(message, opts.get('user') or user,
667 n = repo.commit(message, opts.get('user') or user,
668 opts.get('date') or date, match=m,
668 opts.get('date') or date, match=m,
669 editor=editor, force=partial)
669 editor=editor, force=partial)
670 else:
670 else:
671 if opts.get('exact') or opts.get('import_branch'):
671 if opts.get('exact') or opts.get('import_branch'):
672 branch = branch or 'default'
672 branch = branch or 'default'
673 else:
673 else:
674 branch = p1.branch()
674 branch = p1.branch()
675 store = patch.filestore()
675 store = patch.filestore()
676 try:
676 try:
677 files = set()
677 files = set()
678 try:
678 try:
679 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
679 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
680 files, eolmode=None)
680 files, eolmode=None)
681 except patch.PatchError, e:
681 except patch.PatchError, e:
682 raise util.Abort(str(e))
682 raise util.Abort(str(e))
683 memctx = context.makememctx(repo, (p1.node(), p2.node()),
683 memctx = context.makememctx(repo, (p1.node(), p2.node()),
684 message,
684 message,
685 opts.get('user') or user,
685 opts.get('user') or user,
686 opts.get('date') or date,
686 opts.get('date') or date,
687 branch, files, store,
687 branch, files, store,
688 editor=getcommiteditor())
688 editor=getcommiteditor())
689 n = memctx.commit()
689 n = memctx.commit()
690 finally:
690 finally:
691 store.close()
691 store.close()
692 if opts.get('exact') and hex(n) != nodeid:
692 if opts.get('exact') and hex(n) != nodeid:
693 raise util.Abort(_('patch is damaged or loses information'))
693 raise util.Abort(_('patch is damaged or loses information'))
694 if n:
694 if n:
695 # i18n: refers to a short changeset id
695 # i18n: refers to a short changeset id
696 msg = _('created %s') % short(n)
696 msg = _('created %s') % short(n)
697 return (msg, n, rejects)
697 return (msg, n, rejects)
698 finally:
698 finally:
699 os.unlink(tmpname)
699 os.unlink(tmpname)
700
700
701 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
701 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
702 opts=None):
702 opts=None):
703 '''export changesets as hg patches.'''
703 '''export changesets as hg patches.'''
704
704
705 total = len(revs)
705 total = len(revs)
706 revwidth = max([len(str(rev)) for rev in revs])
706 revwidth = max([len(str(rev)) for rev in revs])
707 filemode = {}
707 filemode = {}
708
708
709 def single(rev, seqno, fp):
709 def single(rev, seqno, fp):
710 ctx = repo[rev]
710 ctx = repo[rev]
711 node = ctx.node()
711 node = ctx.node()
712 parents = [p.node() for p in ctx.parents() if p]
712 parents = [p.node() for p in ctx.parents() if p]
713 branch = ctx.branch()
713 branch = ctx.branch()
714 if switch_parent:
714 if switch_parent:
715 parents.reverse()
715 parents.reverse()
716 prev = (parents and parents[0]) or nullid
716 prev = (parents and parents[0]) or nullid
717
717
718 shouldclose = False
718 shouldclose = False
719 if not fp and len(template) > 0:
719 if not fp and len(template) > 0:
720 desc_lines = ctx.description().rstrip().split('\n')
720 desc_lines = ctx.description().rstrip().split('\n')
721 desc = desc_lines[0] #Commit always has a first line.
721 desc = desc_lines[0] #Commit always has a first line.
722 fp = makefileobj(repo, template, node, desc=desc, total=total,
722 fp = makefileobj(repo, template, node, desc=desc, total=total,
723 seqno=seqno, revwidth=revwidth, mode='wb',
723 seqno=seqno, revwidth=revwidth, mode='wb',
724 modemap=filemode)
724 modemap=filemode)
725 if fp != template:
725 if fp != template:
726 shouldclose = True
726 shouldclose = True
727 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
727 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
728 repo.ui.note("%s\n" % fp.name)
728 repo.ui.note("%s\n" % fp.name)
729
729
730 if not fp:
730 if not fp:
731 write = repo.ui.write
731 write = repo.ui.write
732 else:
732 else:
733 def write(s, **kw):
733 def write(s, **kw):
734 fp.write(s)
734 fp.write(s)
735
735
736
736
737 write("# HG changeset patch\n")
737 write("# HG changeset patch\n")
738 write("# User %s\n" % ctx.user())
738 write("# User %s\n" % ctx.user())
739 write("# Date %d %d\n" % ctx.date())
739 write("# Date %d %d\n" % ctx.date())
740 write("# %s\n" % util.datestr(ctx.date()))
740 write("# %s\n" % util.datestr(ctx.date()))
741 if branch and branch != 'default':
741 if branch and branch != 'default':
742 write("# Branch %s\n" % branch)
742 write("# Branch %s\n" % branch)
743 write("# Node ID %s\n" % hex(node))
743 write("# Node ID %s\n" % hex(node))
744 write("# Parent %s\n" % hex(prev))
744 write("# Parent %s\n" % hex(prev))
745 if len(parents) > 1:
745 if len(parents) > 1:
746 write("# Parent %s\n" % hex(parents[1]))
746 write("# Parent %s\n" % hex(parents[1]))
747 write(ctx.description().rstrip())
747 write(ctx.description().rstrip())
748 write("\n\n")
748 write("\n\n")
749
749
750 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
750 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
751 write(chunk, label=label)
751 write(chunk, label=label)
752
752
753 if shouldclose:
753 if shouldclose:
754 fp.close()
754 fp.close()
755
755
756 for seqno, rev in enumerate(revs):
756 for seqno, rev in enumerate(revs):
757 single(rev, seqno + 1, fp)
757 single(rev, seqno + 1, fp)
758
758
759 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
759 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
760 changes=None, stat=False, fp=None, prefix='',
760 changes=None, stat=False, fp=None, prefix='',
761 listsubrepos=False):
761 listsubrepos=False):
762 '''show diff or diffstat.'''
762 '''show diff or diffstat.'''
763 if fp is None:
763 if fp is None:
764 write = ui.write
764 write = ui.write
765 else:
765 else:
766 def write(s, **kw):
766 def write(s, **kw):
767 fp.write(s)
767 fp.write(s)
768
768
769 if stat:
769 if stat:
770 diffopts = diffopts.copy(context=0)
770 diffopts = diffopts.copy(context=0)
771 width = 80
771 width = 80
772 if not ui.plain():
772 if not ui.plain():
773 width = ui.termwidth()
773 width = ui.termwidth()
774 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
774 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
775 prefix=prefix)
775 prefix=prefix)
776 for chunk, label in patch.diffstatui(util.iterlines(chunks),
776 for chunk, label in patch.diffstatui(util.iterlines(chunks),
777 width=width,
777 width=width,
778 git=diffopts.git):
778 git=diffopts.git):
779 write(chunk, label=label)
779 write(chunk, label=label)
780 else:
780 else:
781 for chunk, label in patch.diffui(repo, node1, node2, match,
781 for chunk, label in patch.diffui(repo, node1, node2, match,
782 changes, diffopts, prefix=prefix):
782 changes, diffopts, prefix=prefix):
783 write(chunk, label=label)
783 write(chunk, label=label)
784
784
785 if listsubrepos:
785 if listsubrepos:
786 ctx1 = repo[node1]
786 ctx1 = repo[node1]
787 ctx2 = repo[node2]
787 ctx2 = repo[node2]
788 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
788 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
789 tempnode2 = node2
789 tempnode2 = node2
790 try:
790 try:
791 if node2 is not None:
791 if node2 is not None:
792 tempnode2 = ctx2.substate[subpath][1]
792 tempnode2 = ctx2.substate[subpath][1]
793 except KeyError:
793 except KeyError:
794 # A subrepo that existed in node1 was deleted between node1 and
794 # A subrepo that existed in node1 was deleted between node1 and
795 # node2 (inclusive). Thus, ctx2's substate won't contain that
795 # node2 (inclusive). Thus, ctx2's substate won't contain that
796 # subpath. The best we can do is to ignore it.
796 # subpath. The best we can do is to ignore it.
797 tempnode2 = None
797 tempnode2 = None
798 submatch = matchmod.narrowmatcher(subpath, match)
798 submatch = matchmod.narrowmatcher(subpath, match)
799 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
799 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
800 stat=stat, fp=fp, prefix=prefix)
800 stat=stat, fp=fp, prefix=prefix)
801
801
802 class changeset_printer(object):
802 class changeset_printer(object):
803 '''show changeset information when templating not requested.'''
803 '''show changeset information when templating not requested.'''
804
804
805 def __init__(self, ui, repo, patch, diffopts, buffered):
805 def __init__(self, ui, repo, patch, diffopts, buffered):
806 self.ui = ui
806 self.ui = ui
807 self.repo = repo
807 self.repo = repo
808 self.buffered = buffered
808 self.buffered = buffered
809 self.patch = patch
809 self.patch = patch
810 self.diffopts = diffopts
810 self.diffopts = diffopts
811 self.header = {}
811 self.header = {}
812 self.hunk = {}
812 self.hunk = {}
813 self.lastheader = None
813 self.lastheader = None
814 self.footer = None
814 self.footer = None
815
815
816 def flush(self, rev):
816 def flush(self, rev):
817 if rev in self.header:
817 if rev in self.header:
818 h = self.header[rev]
818 h = self.header[rev]
819 if h != self.lastheader:
819 if h != self.lastheader:
820 self.lastheader = h
820 self.lastheader = h
821 self.ui.write(h)
821 self.ui.write(h)
822 del self.header[rev]
822 del self.header[rev]
823 if rev in self.hunk:
823 if rev in self.hunk:
824 self.ui.write(self.hunk[rev])
824 self.ui.write(self.hunk[rev])
825 del self.hunk[rev]
825 del self.hunk[rev]
826 return 1
826 return 1
827 return 0
827 return 0
828
828
829 def close(self):
829 def close(self):
830 if self.footer:
830 if self.footer:
831 self.ui.write(self.footer)
831 self.ui.write(self.footer)
832
832
833 def show(self, ctx, copies=None, matchfn=None, **props):
833 def show(self, ctx, copies=None, matchfn=None, **props):
834 if self.buffered:
834 if self.buffered:
835 self.ui.pushbuffer()
835 self.ui.pushbuffer()
836 self._show(ctx, copies, matchfn, props)
836 self._show(ctx, copies, matchfn, props)
837 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
837 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
838 else:
838 else:
839 self._show(ctx, copies, matchfn, props)
839 self._show(ctx, copies, matchfn, props)
840
840
841 def _show(self, ctx, copies, matchfn, props):
841 def _show(self, ctx, copies, matchfn, props):
842 '''show a single changeset or file revision'''
842 '''show a single changeset or file revision'''
843 changenode = ctx.node()
843 changenode = ctx.node()
844 rev = ctx.rev()
844 rev = ctx.rev()
845
845
846 if self.ui.quiet:
846 if self.ui.quiet:
847 self.ui.write("%d:%s\n" % (rev, short(changenode)),
847 self.ui.write("%d:%s\n" % (rev, short(changenode)),
848 label='log.node')
848 label='log.node')
849 return
849 return
850
850
851 log = self.repo.changelog
851 log = self.repo.changelog
852 date = util.datestr(ctx.date())
852 date = util.datestr(ctx.date())
853
853
854 hexfunc = self.ui.debugflag and hex or short
854 hexfunc = self.ui.debugflag and hex or short
855
855
856 parents = [(p, hexfunc(log.node(p)))
856 parents = [(p, hexfunc(log.node(p)))
857 for p in self._meaningful_parentrevs(log, rev)]
857 for p in self._meaningful_parentrevs(log, rev)]
858
858
859 # i18n: column positioning for "hg log"
859 # i18n: column positioning for "hg log"
860 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
860 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
861 label='log.changeset changeset.%s' % ctx.phasestr())
861 label='log.changeset changeset.%s' % ctx.phasestr())
862
862
863 branch = ctx.branch()
863 branch = ctx.branch()
864 # don't show the default branch name
864 # don't show the default branch name
865 if branch != 'default':
865 if branch != 'default':
866 # i18n: column positioning for "hg log"
866 # i18n: column positioning for "hg log"
867 self.ui.write(_("branch: %s\n") % branch,
867 self.ui.write(_("branch: %s\n") % branch,
868 label='log.branch')
868 label='log.branch')
869 for bookmark in self.repo.nodebookmarks(changenode):
869 for bookmark in self.repo.nodebookmarks(changenode):
870 # i18n: column positioning for "hg log"
870 # i18n: column positioning for "hg log"
871 self.ui.write(_("bookmark: %s\n") % bookmark,
871 self.ui.write(_("bookmark: %s\n") % bookmark,
872 label='log.bookmark')
872 label='log.bookmark')
873 for tag in self.repo.nodetags(changenode):
873 for tag in self.repo.nodetags(changenode):
874 # i18n: column positioning for "hg log"
874 # i18n: column positioning for "hg log"
875 self.ui.write(_("tag: %s\n") % tag,
875 self.ui.write(_("tag: %s\n") % tag,
876 label='log.tag')
876 label='log.tag')
877 if self.ui.debugflag and ctx.phase():
877 if self.ui.debugflag and ctx.phase():
878 # i18n: column positioning for "hg log"
878 # i18n: column positioning for "hg log"
879 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
879 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
880 label='log.phase')
880 label='log.phase')
881 for parent in parents:
881 for parent in parents:
882 # i18n: column positioning for "hg log"
882 # i18n: column positioning for "hg log"
883 self.ui.write(_("parent: %d:%s\n") % parent,
883 self.ui.write(_("parent: %d:%s\n") % parent,
884 label='log.parent changeset.%s' % ctx.phasestr())
884 label='log.parent changeset.%s' % ctx.phasestr())
885
885
886 if self.ui.debugflag:
886 if self.ui.debugflag:
887 mnode = ctx.manifestnode()
887 mnode = ctx.manifestnode()
888 # i18n: column positioning for "hg log"
888 # i18n: column positioning for "hg log"
889 self.ui.write(_("manifest: %d:%s\n") %
889 self.ui.write(_("manifest: %d:%s\n") %
890 (self.repo.manifest.rev(mnode), hex(mnode)),
890 (self.repo.manifest.rev(mnode), hex(mnode)),
891 label='ui.debug log.manifest')
891 label='ui.debug log.manifest')
892 # i18n: column positioning for "hg log"
892 # i18n: column positioning for "hg log"
893 self.ui.write(_("user: %s\n") % ctx.user(),
893 self.ui.write(_("user: %s\n") % ctx.user(),
894 label='log.user')
894 label='log.user')
895 # i18n: column positioning for "hg log"
895 # i18n: column positioning for "hg log"
896 self.ui.write(_("date: %s\n") % date,
896 self.ui.write(_("date: %s\n") % date,
897 label='log.date')
897 label='log.date')
898
898
899 if self.ui.debugflag:
899 if self.ui.debugflag:
900 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
900 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
901 for key, value in zip([# i18n: column positioning for "hg log"
901 for key, value in zip([# i18n: column positioning for "hg log"
902 _("files:"),
902 _("files:"),
903 # i18n: column positioning for "hg log"
903 # i18n: column positioning for "hg log"
904 _("files+:"),
904 _("files+:"),
905 # i18n: column positioning for "hg log"
905 # i18n: column positioning for "hg log"
906 _("files-:")], files):
906 _("files-:")], files):
907 if value:
907 if value:
908 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
908 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
909 label='ui.debug log.files')
909 label='ui.debug log.files')
910 elif ctx.files() and self.ui.verbose:
910 elif ctx.files() and self.ui.verbose:
911 # i18n: column positioning for "hg log"
911 # i18n: column positioning for "hg log"
912 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
912 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
913 label='ui.note log.files')
913 label='ui.note log.files')
914 if copies and self.ui.verbose:
914 if copies and self.ui.verbose:
915 copies = ['%s (%s)' % c for c in copies]
915 copies = ['%s (%s)' % c for c in copies]
916 # i18n: column positioning for "hg log"
916 # i18n: column positioning for "hg log"
917 self.ui.write(_("copies: %s\n") % ' '.join(copies),
917 self.ui.write(_("copies: %s\n") % ' '.join(copies),
918 label='ui.note log.copies')
918 label='ui.note log.copies')
919
919
920 extra = ctx.extra()
920 extra = ctx.extra()
921 if extra and self.ui.debugflag:
921 if extra and self.ui.debugflag:
922 for key, value in sorted(extra.items()):
922 for key, value in sorted(extra.items()):
923 # i18n: column positioning for "hg log"
923 # i18n: column positioning for "hg log"
924 self.ui.write(_("extra: %s=%s\n")
924 self.ui.write(_("extra: %s=%s\n")
925 % (key, value.encode('string_escape')),
925 % (key, value.encode('string_escape')),
926 label='ui.debug log.extra')
926 label='ui.debug log.extra')
927
927
928 description = ctx.description().strip()
928 description = ctx.description().strip()
929 if description:
929 if description:
930 if self.ui.verbose:
930 if self.ui.verbose:
931 self.ui.write(_("description:\n"),
931 self.ui.write(_("description:\n"),
932 label='ui.note log.description')
932 label='ui.note log.description')
933 self.ui.write(description,
933 self.ui.write(description,
934 label='ui.note log.description')
934 label='ui.note log.description')
935 self.ui.write("\n\n")
935 self.ui.write("\n\n")
936 else:
936 else:
937 # i18n: column positioning for "hg log"
937 # i18n: column positioning for "hg log"
938 self.ui.write(_("summary: %s\n") %
938 self.ui.write(_("summary: %s\n") %
939 description.splitlines()[0],
939 description.splitlines()[0],
940 label='log.summary')
940 label='log.summary')
941 self.ui.write("\n")
941 self.ui.write("\n")
942
942
943 self.showpatch(changenode, matchfn)
943 self.showpatch(changenode, matchfn)
944
944
945 def showpatch(self, node, matchfn):
945 def showpatch(self, node, matchfn):
946 if not matchfn:
946 if not matchfn:
947 matchfn = self.patch
947 matchfn = self.patch
948 if matchfn:
948 if matchfn:
949 stat = self.diffopts.get('stat')
949 stat = self.diffopts.get('stat')
950 diff = self.diffopts.get('patch')
950 diff = self.diffopts.get('patch')
951 diffopts = patch.diffopts(self.ui, self.diffopts)
951 diffopts = patch.diffopts(self.ui, self.diffopts)
952 prev = self.repo.changelog.parents(node)[0]
952 prev = self.repo.changelog.parents(node)[0]
953 if stat:
953 if stat:
954 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
954 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
955 match=matchfn, stat=True)
955 match=matchfn, stat=True)
956 if diff:
956 if diff:
957 if stat:
957 if stat:
958 self.ui.write("\n")
958 self.ui.write("\n")
959 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
959 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
960 match=matchfn, stat=False)
960 match=matchfn, stat=False)
961 self.ui.write("\n")
961 self.ui.write("\n")
962
962
963 def _meaningful_parentrevs(self, log, rev):
963 def _meaningful_parentrevs(self, log, rev):
964 """Return list of meaningful (or all if debug) parentrevs for rev.
964 """Return list of meaningful (or all if debug) parentrevs for rev.
965
965
966 For merges (two non-nullrev revisions) both parents are meaningful.
966 For merges (two non-nullrev revisions) both parents are meaningful.
967 Otherwise the first parent revision is considered meaningful if it
967 Otherwise the first parent revision is considered meaningful if it
968 is not the preceding revision.
968 is not the preceding revision.
969 """
969 """
970 parents = log.parentrevs(rev)
970 parents = log.parentrevs(rev)
971 if not self.ui.debugflag and parents[1] == nullrev:
971 if not self.ui.debugflag and parents[1] == nullrev:
972 if parents[0] >= rev - 1:
972 if parents[0] >= rev - 1:
973 parents = []
973 parents = []
974 else:
974 else:
975 parents = [parents[0]]
975 parents = [parents[0]]
976 return parents
976 return parents
977
977
978
978
979 class changeset_templater(changeset_printer):
979 class changeset_templater(changeset_printer):
980 '''format changeset information.'''
980 '''format changeset information.'''
981
981
982 def __init__(self, ui, repo, patch, diffopts, tmpl, mapfile, buffered):
982 def __init__(self, ui, repo, patch, diffopts, tmpl, mapfile, buffered):
983 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
983 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
984 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
984 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
985 defaulttempl = {
985 defaulttempl = {
986 'parent': '{rev}:{node|formatnode} ',
986 'parent': '{rev}:{node|formatnode} ',
987 'manifest': '{rev}:{node|formatnode}',
987 'manifest': '{rev}:{node|formatnode}',
988 'file_copy': '{name} ({source})',
988 'file_copy': '{name} ({source})',
989 'extra': '{key}={value|stringescape}'
989 'extra': '{key}={value|stringescape}'
990 }
990 }
991 # filecopy is preserved for compatibility reasons
991 # filecopy is preserved for compatibility reasons
992 defaulttempl['filecopy'] = defaulttempl['file_copy']
992 defaulttempl['filecopy'] = defaulttempl['file_copy']
993 self.t = templater.templater(mapfile, {'formatnode': formatnode},
993 self.t = templater.templater(mapfile, {'formatnode': formatnode},
994 cache=defaulttempl)
994 cache=defaulttempl)
995 if tmpl:
995 if tmpl:
996 self.t.cache['changeset'] = tmpl
996 self.t.cache['changeset'] = tmpl
997
997
998 self.cache = {}
998 self.cache = {}
999
999
1000 def _meaningful_parentrevs(self, ctx):
1000 def _meaningful_parentrevs(self, ctx):
1001 """Return list of meaningful (or all if debug) parentrevs for rev.
1001 """Return list of meaningful (or all if debug) parentrevs for rev.
1002 """
1002 """
1003 parents = ctx.parents()
1003 parents = ctx.parents()
1004 if len(parents) > 1:
1004 if len(parents) > 1:
1005 return parents
1005 return parents
1006 if self.ui.debugflag:
1006 if self.ui.debugflag:
1007 return [parents[0], self.repo['null']]
1007 return [parents[0], self.repo['null']]
1008 if parents[0].rev() >= ctx.rev() - 1:
1008 if parents[0].rev() >= ctx.rev() - 1:
1009 return []
1009 return []
1010 return parents
1010 return parents
1011
1011
1012 def _show(self, ctx, copies, matchfn, props):
1012 def _show(self, ctx, copies, matchfn, props):
1013 '''show a single changeset or file revision'''
1013 '''show a single changeset or file revision'''
1014
1014
1015 showlist = templatekw.showlist
1015 showlist = templatekw.showlist
1016
1016
1017 # showparents() behaviour depends on ui trace level which
1017 # showparents() behaviour depends on ui trace level which
1018 # causes unexpected behaviours at templating level and makes
1018 # causes unexpected behaviours at templating level and makes
1019 # it harder to extract it in a standalone function. Its
1019 # it harder to extract it in a standalone function. Its
1020 # behaviour cannot be changed so leave it here for now.
1020 # behaviour cannot be changed so leave it here for now.
1021 def showparents(**args):
1021 def showparents(**args):
1022 ctx = args['ctx']
1022 ctx = args['ctx']
1023 parents = [[('rev', p.rev()), ('node', p.hex())]
1023 parents = [[('rev', p.rev()), ('node', p.hex())]
1024 for p in self._meaningful_parentrevs(ctx)]
1024 for p in self._meaningful_parentrevs(ctx)]
1025 return showlist('parent', parents, **args)
1025 return showlist('parent', parents, **args)
1026
1026
1027 props = props.copy()
1027 props = props.copy()
1028 props.update(templatekw.keywords)
1028 props.update(templatekw.keywords)
1029 props['parents'] = showparents
1029 props['parents'] = showparents
1030 props['templ'] = self.t
1030 props['templ'] = self.t
1031 props['ctx'] = ctx
1031 props['ctx'] = ctx
1032 props['repo'] = self.repo
1032 props['repo'] = self.repo
1033 props['revcache'] = {'copies': copies}
1033 props['revcache'] = {'copies': copies}
1034 props['cache'] = self.cache
1034 props['cache'] = self.cache
1035
1035
1036 # find correct templates for current mode
1036 # find correct templates for current mode
1037
1037
1038 tmplmodes = [
1038 tmplmodes = [
1039 (True, None),
1039 (True, None),
1040 (self.ui.verbose, 'verbose'),
1040 (self.ui.verbose, 'verbose'),
1041 (self.ui.quiet, 'quiet'),
1041 (self.ui.quiet, 'quiet'),
1042 (self.ui.debugflag, 'debug'),
1042 (self.ui.debugflag, 'debug'),
1043 ]
1043 ]
1044
1044
1045 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
1045 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
1046 for mode, postfix in tmplmodes:
1046 for mode, postfix in tmplmodes:
1047 for type in types:
1047 for type in types:
1048 cur = postfix and ('%s_%s' % (type, postfix)) or type
1048 cur = postfix and ('%s_%s' % (type, postfix)) or type
1049 if mode and cur in self.t:
1049 if mode and cur in self.t:
1050 types[type] = cur
1050 types[type] = cur
1051
1051
1052 try:
1052 try:
1053
1053
1054 # write header
1054 # write header
1055 if types['header']:
1055 if types['header']:
1056 h = templater.stringify(self.t(types['header'], **props))
1056 h = templater.stringify(self.t(types['header'], **props))
1057 if self.buffered:
1057 if self.buffered:
1058 self.header[ctx.rev()] = h
1058 self.header[ctx.rev()] = h
1059 else:
1059 else:
1060 if self.lastheader != h:
1060 if self.lastheader != h:
1061 self.lastheader = h
1061 self.lastheader = h
1062 self.ui.write(h)
1062 self.ui.write(h)
1063
1063
1064 # write changeset metadata, then patch if requested
1064 # write changeset metadata, then patch if requested
1065 key = types['changeset']
1065 key = types['changeset']
1066 self.ui.write(templater.stringify(self.t(key, **props)))
1066 self.ui.write(templater.stringify(self.t(key, **props)))
1067 self.showpatch(ctx.node(), matchfn)
1067 self.showpatch(ctx.node(), matchfn)
1068
1068
1069 if types['footer']:
1069 if types['footer']:
1070 if not self.footer:
1070 if not self.footer:
1071 self.footer = templater.stringify(self.t(types['footer'],
1071 self.footer = templater.stringify(self.t(types['footer'],
1072 **props))
1072 **props))
1073
1073
1074 except KeyError, inst:
1074 except KeyError, inst:
1075 msg = _("%s: no key named '%s'")
1075 msg = _("%s: no key named '%s'")
1076 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
1076 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
1077 except SyntaxError, inst:
1077 except SyntaxError, inst:
1078 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
1078 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
1079
1079
1080 def gettemplate(ui, tmpl, style):
1080 def gettemplate(ui, tmpl, style):
1081 """
1081 """
1082 Find the template matching the given template spec or style.
1082 Find the template matching the given template spec or style.
1083 """
1083 """
1084
1084
1085 # ui settings
1085 # ui settings
1086 if not tmpl and not style:
1086 if not tmpl and not style:
1087 tmpl = ui.config('ui', 'logtemplate')
1087 tmpl = ui.config('ui', 'logtemplate')
1088 if tmpl:
1088 if tmpl:
1089 try:
1089 try:
1090 tmpl = templater.parsestring(tmpl)
1090 tmpl = templater.parsestring(tmpl)
1091 except SyntaxError:
1091 except SyntaxError:
1092 tmpl = templater.parsestring(tmpl, quoted=False)
1092 tmpl = templater.parsestring(tmpl, quoted=False)
1093 return tmpl, None
1093 return tmpl, None
1094 else:
1094 else:
1095 style = util.expandpath(ui.config('ui', 'style', ''))
1095 style = util.expandpath(ui.config('ui', 'style', ''))
1096
1096
1097 if style:
1097 if style:
1098 mapfile = style
1098 mapfile = style
1099 if not os.path.split(mapfile)[0]:
1099 if not os.path.split(mapfile)[0]:
1100 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1100 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1101 or templater.templatepath(mapfile))
1101 or templater.templatepath(mapfile))
1102 if mapname:
1102 if mapname:
1103 mapfile = mapname
1103 mapfile = mapname
1104 return None, mapfile
1104 return None, mapfile
1105
1105
1106 if not tmpl:
1106 if not tmpl:
1107 return None, None
1107 return None, None
1108
1108
1109 # looks like a literal template?
1109 # looks like a literal template?
1110 if '{' in tmpl:
1110 if '{' in tmpl:
1111 return tmpl, None
1111 return tmpl, None
1112
1112
1113 # perhaps a stock style?
1113 # perhaps a stock style?
1114 if not os.path.split(tmpl)[0]:
1114 if not os.path.split(tmpl)[0]:
1115 mapname = (templater.templatepath('map-cmdline.' + tmpl)
1115 mapname = (templater.templatepath('map-cmdline.' + tmpl)
1116 or templater.templatepath(tmpl))
1116 or templater.templatepath(tmpl))
1117 if mapname and os.path.isfile(mapname):
1117 if mapname and os.path.isfile(mapname):
1118 return None, mapname
1118 return None, mapname
1119
1119
1120 # perhaps it's a reference to [templates]
1120 # perhaps it's a reference to [templates]
1121 t = ui.config('templates', tmpl)
1121 t = ui.config('templates', tmpl)
1122 if t:
1122 if t:
1123 try:
1123 try:
1124 tmpl = templater.parsestring(t)
1124 tmpl = templater.parsestring(t)
1125 except SyntaxError:
1125 except SyntaxError:
1126 tmpl = templater.parsestring(t, quoted=False)
1126 tmpl = templater.parsestring(t, quoted=False)
1127 return tmpl, None
1127 return tmpl, None
1128
1128
1129 # perhaps it's a path to a map or a template
1129 # perhaps it's a path to a map or a template
1130 if ('/' in tmpl or '\\' in tmpl) and os.path.isfile(tmpl):
1130 if ('/' in tmpl or '\\' in tmpl) and os.path.isfile(tmpl):
1131 # is it a mapfile for a style?
1131 # is it a mapfile for a style?
1132 if os.path.basename(tmpl).startswith("map-"):
1132 if os.path.basename(tmpl).startswith("map-"):
1133 return None, os.path.realpath(tmpl)
1133 return None, os.path.realpath(tmpl)
1134 tmpl = open(tmpl).read()
1134 tmpl = open(tmpl).read()
1135 return tmpl, None
1135 return tmpl, None
1136
1136
1137 # constant string?
1137 # constant string?
1138 return tmpl, None
1138 return tmpl, None
1139
1139
1140 def show_changeset(ui, repo, opts, buffered=False):
1140 def show_changeset(ui, repo, opts, buffered=False):
1141 """show one changeset using template or regular display.
1141 """show one changeset using template or regular display.
1142
1142
1143 Display format will be the first non-empty hit of:
1143 Display format will be the first non-empty hit of:
1144 1. option 'template'
1144 1. option 'template'
1145 2. option 'style'
1145 2. option 'style'
1146 3. [ui] setting 'logtemplate'
1146 3. [ui] setting 'logtemplate'
1147 4. [ui] setting 'style'
1147 4. [ui] setting 'style'
1148 If all of these values are either the unset or the empty string,
1148 If all of these values are either the unset or the empty string,
1149 regular display via changeset_printer() is done.
1149 regular display via changeset_printer() is done.
1150 """
1150 """
1151 # options
1151 # options
1152 patch = None
1152 patch = None
1153 if opts.get('patch') or opts.get('stat'):
1153 if opts.get('patch') or opts.get('stat'):
1154 patch = scmutil.matchall(repo)
1154 patch = scmutil.matchall(repo)
1155
1155
1156 tmpl, mapfile = gettemplate(ui, opts.get('template'), opts.get('style'))
1156 tmpl, mapfile = gettemplate(ui, opts.get('template'), opts.get('style'))
1157
1157
1158 if not tmpl and not mapfile:
1158 if not tmpl and not mapfile:
1159 return changeset_printer(ui, repo, patch, opts, buffered)
1159 return changeset_printer(ui, repo, patch, opts, buffered)
1160
1160
1161 try:
1161 try:
1162 t = changeset_templater(ui, repo, patch, opts, tmpl, mapfile, buffered)
1162 t = changeset_templater(ui, repo, patch, opts, tmpl, mapfile, buffered)
1163 except SyntaxError, inst:
1163 except SyntaxError, inst:
1164 raise util.Abort(inst.args[0])
1164 raise util.Abort(inst.args[0])
1165 return t
1165 return t
1166
1166
1167 def showmarker(ui, marker):
1167 def showmarker(ui, marker):
1168 """utility function to display obsolescence marker in a readable way
1168 """utility function to display obsolescence marker in a readable way
1169
1169
1170 To be used by debug function."""
1170 To be used by debug function."""
1171 ui.write(hex(marker.precnode()))
1171 ui.write(hex(marker.precnode()))
1172 for repl in marker.succnodes():
1172 for repl in marker.succnodes():
1173 ui.write(' ')
1173 ui.write(' ')
1174 ui.write(hex(repl))
1174 ui.write(hex(repl))
1175 ui.write(' %X ' % marker._data[2])
1175 ui.write(' %X ' % marker._data[2])
1176 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
1176 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
1177 sorted(marker.metadata().items()))))
1177 sorted(marker.metadata().items()))))
1178 ui.write('\n')
1178 ui.write('\n')
1179
1179
1180 def finddate(ui, repo, date):
1180 def finddate(ui, repo, date):
1181 """Find the tipmost changeset that matches the given date spec"""
1181 """Find the tipmost changeset that matches the given date spec"""
1182
1182
1183 df = util.matchdate(date)
1183 df = util.matchdate(date)
1184 m = scmutil.matchall(repo)
1184 m = scmutil.matchall(repo)
1185 results = {}
1185 results = {}
1186
1186
1187 def prep(ctx, fns):
1187 def prep(ctx, fns):
1188 d = ctx.date()
1188 d = ctx.date()
1189 if df(d[0]):
1189 if df(d[0]):
1190 results[ctx.rev()] = d
1190 results[ctx.rev()] = d
1191
1191
1192 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1192 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1193 rev = ctx.rev()
1193 rev = ctx.rev()
1194 if rev in results:
1194 if rev in results:
1195 ui.status(_("found revision %s from %s\n") %
1195 ui.status(_("found revision %s from %s\n") %
1196 (rev, util.datestr(results[rev])))
1196 (rev, util.datestr(results[rev])))
1197 return str(rev)
1197 return str(rev)
1198
1198
1199 raise util.Abort(_("revision matching date not found"))
1199 raise util.Abort(_("revision matching date not found"))
1200
1200
1201 def increasingwindows(windowsize=8, sizelimit=512):
1201 def increasingwindows(windowsize=8, sizelimit=512):
1202 while True:
1202 while True:
1203 yield windowsize
1203 yield windowsize
1204 if windowsize < sizelimit:
1204 if windowsize < sizelimit:
1205 windowsize *= 2
1205 windowsize *= 2
1206
1206
1207 class FileWalkError(Exception):
1207 class FileWalkError(Exception):
1208 pass
1208 pass
1209
1209
1210 def walkfilerevs(repo, match, follow, revs, fncache):
1210 def walkfilerevs(repo, match, follow, revs, fncache):
1211 '''Walks the file history for the matched files.
1211 '''Walks the file history for the matched files.
1212
1212
1213 Returns the changeset revs that are involved in the file history.
1213 Returns the changeset revs that are involved in the file history.
1214
1214
1215 Throws FileWalkError if the file history can't be walked using
1215 Throws FileWalkError if the file history can't be walked using
1216 filelogs alone.
1216 filelogs alone.
1217 '''
1217 '''
1218 wanted = set()
1218 wanted = set()
1219 copies = []
1219 copies = []
1220 minrev, maxrev = min(revs), max(revs)
1220 minrev, maxrev = min(revs), max(revs)
1221 def filerevgen(filelog, last):
1221 def filerevgen(filelog, last):
1222 """
1222 """
1223 Only files, no patterns. Check the history of each file.
1223 Only files, no patterns. Check the history of each file.
1224
1224
1225 Examines filelog entries within minrev, maxrev linkrev range
1225 Examines filelog entries within minrev, maxrev linkrev range
1226 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1226 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1227 tuples in backwards order
1227 tuples in backwards order
1228 """
1228 """
1229 cl_count = len(repo)
1229 cl_count = len(repo)
1230 revs = []
1230 revs = []
1231 for j in xrange(0, last + 1):
1231 for j in xrange(0, last + 1):
1232 linkrev = filelog.linkrev(j)
1232 linkrev = filelog.linkrev(j)
1233 if linkrev < minrev:
1233 if linkrev < minrev:
1234 continue
1234 continue
1235 # only yield rev for which we have the changelog, it can
1235 # only yield rev for which we have the changelog, it can
1236 # happen while doing "hg log" during a pull or commit
1236 # happen while doing "hg log" during a pull or commit
1237 if linkrev >= cl_count:
1237 if linkrev >= cl_count:
1238 break
1238 break
1239
1239
1240 parentlinkrevs = []
1240 parentlinkrevs = []
1241 for p in filelog.parentrevs(j):
1241 for p in filelog.parentrevs(j):
1242 if p != nullrev:
1242 if p != nullrev:
1243 parentlinkrevs.append(filelog.linkrev(p))
1243 parentlinkrevs.append(filelog.linkrev(p))
1244 n = filelog.node(j)
1244 n = filelog.node(j)
1245 revs.append((linkrev, parentlinkrevs,
1245 revs.append((linkrev, parentlinkrevs,
1246 follow and filelog.renamed(n)))
1246 follow and filelog.renamed(n)))
1247
1247
1248 return reversed(revs)
1248 return reversed(revs)
1249 def iterfiles():
1249 def iterfiles():
1250 pctx = repo['.']
1250 pctx = repo['.']
1251 for filename in match.files():
1251 for filename in match.files():
1252 if follow:
1252 if follow:
1253 if filename not in pctx:
1253 if filename not in pctx:
1254 raise util.Abort(_('cannot follow file not in parent '
1254 raise util.Abort(_('cannot follow file not in parent '
1255 'revision: "%s"') % filename)
1255 'revision: "%s"') % filename)
1256 yield filename, pctx[filename].filenode()
1256 yield filename, pctx[filename].filenode()
1257 else:
1257 else:
1258 yield filename, None
1258 yield filename, None
1259 for filename_node in copies:
1259 for filename_node in copies:
1260 yield filename_node
1260 yield filename_node
1261
1261
1262 for file_, node in iterfiles():
1262 for file_, node in iterfiles():
1263 filelog = repo.file(file_)
1263 filelog = repo.file(file_)
1264 if not len(filelog):
1264 if not len(filelog):
1265 if node is None:
1265 if node is None:
1266 # A zero count may be a directory or deleted file, so
1266 # A zero count may be a directory or deleted file, so
1267 # try to find matching entries on the slow path.
1267 # try to find matching entries on the slow path.
1268 if follow:
1268 if follow:
1269 raise util.Abort(
1269 raise util.Abort(
1270 _('cannot follow nonexistent file: "%s"') % file_)
1270 _('cannot follow nonexistent file: "%s"') % file_)
1271 raise FileWalkError("Cannot walk via filelog")
1271 raise FileWalkError("Cannot walk via filelog")
1272 else:
1272 else:
1273 continue
1273 continue
1274
1274
1275 if node is None:
1275 if node is None:
1276 last = len(filelog) - 1
1276 last = len(filelog) - 1
1277 else:
1277 else:
1278 last = filelog.rev(node)
1278 last = filelog.rev(node)
1279
1279
1280
1280
1281 # keep track of all ancestors of the file
1281 # keep track of all ancestors of the file
1282 ancestors = set([filelog.linkrev(last)])
1282 ancestors = set([filelog.linkrev(last)])
1283
1283
1284 # iterate from latest to oldest revision
1284 # iterate from latest to oldest revision
1285 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1285 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1286 if not follow:
1286 if not follow:
1287 if rev > maxrev:
1287 if rev > maxrev:
1288 continue
1288 continue
1289 else:
1289 else:
1290 # Note that last might not be the first interesting
1290 # Note that last might not be the first interesting
1291 # rev to us:
1291 # rev to us:
1292 # if the file has been changed after maxrev, we'll
1292 # if the file has been changed after maxrev, we'll
1293 # have linkrev(last) > maxrev, and we still need
1293 # have linkrev(last) > maxrev, and we still need
1294 # to explore the file graph
1294 # to explore the file graph
1295 if rev not in ancestors:
1295 if rev not in ancestors:
1296 continue
1296 continue
1297 # XXX insert 1327 fix here
1297 # XXX insert 1327 fix here
1298 if flparentlinkrevs:
1298 if flparentlinkrevs:
1299 ancestors.update(flparentlinkrevs)
1299 ancestors.update(flparentlinkrevs)
1300
1300
1301 fncache.setdefault(rev, []).append(file_)
1301 fncache.setdefault(rev, []).append(file_)
1302 wanted.add(rev)
1302 wanted.add(rev)
1303 if copied:
1303 if copied:
1304 copies.append(copied)
1304 copies.append(copied)
1305
1305
1306 return wanted
1306 return wanted
1307
1307
1308 def walkchangerevs(repo, match, opts, prepare):
1308 def walkchangerevs(repo, match, opts, prepare):
1309 '''Iterate over files and the revs in which they changed.
1309 '''Iterate over files and the revs in which they changed.
1310
1310
1311 Callers most commonly need to iterate backwards over the history
1311 Callers most commonly need to iterate backwards over the history
1312 in which they are interested. Doing so has awful (quadratic-looking)
1312 in which they are interested. Doing so has awful (quadratic-looking)
1313 performance, so we use iterators in a "windowed" way.
1313 performance, so we use iterators in a "windowed" way.
1314
1314
1315 We walk a window of revisions in the desired order. Within the
1315 We walk a window of revisions in the desired order. Within the
1316 window, we first walk forwards to gather data, then in the desired
1316 window, we first walk forwards to gather data, then in the desired
1317 order (usually backwards) to display it.
1317 order (usually backwards) to display it.
1318
1318
1319 This function returns an iterator yielding contexts. Before
1319 This function returns an iterator yielding contexts. Before
1320 yielding each context, the iterator will first call the prepare
1320 yielding each context, the iterator will first call the prepare
1321 function on each context in the window in forward order.'''
1321 function on each context in the window in forward order.'''
1322
1322
1323 follow = opts.get('follow') or opts.get('follow_first')
1323 follow = opts.get('follow') or opts.get('follow_first')
1324
1324
1325 if opts.get('rev'):
1325 if opts.get('rev'):
1326 revs = scmutil.revrange(repo, opts.get('rev'))
1326 revs = scmutil.revrange(repo, opts.get('rev'))
1327 elif follow:
1327 elif follow:
1328 revs = repo.revs('reverse(:.)')
1328 revs = repo.revs('reverse(:.)')
1329 else:
1329 else:
1330 revs = revset.spanset(repo)
1330 revs = revset.spanset(repo)
1331 revs.reverse()
1331 revs.reverse()
1332 if not revs:
1332 if not revs:
1333 return []
1333 return []
1334 wanted = set()
1334 wanted = set()
1335 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1335 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1336 fncache = {}
1336 fncache = {}
1337 change = repo.changectx
1337 change = repo.changectx
1338
1338
1339 # First step is to fill wanted, the set of revisions that we want to yield.
1339 # First step is to fill wanted, the set of revisions that we want to yield.
1340 # When it does not induce extra cost, we also fill fncache for revisions in
1340 # When it does not induce extra cost, we also fill fncache for revisions in
1341 # wanted: a cache of filenames that were changed (ctx.files()) and that
1341 # wanted: a cache of filenames that were changed (ctx.files()) and that
1342 # match the file filtering conditions.
1342 # match the file filtering conditions.
1343
1343
1344 if not slowpath and not match.files():
1344 if not slowpath and not match.files():
1345 # No files, no patterns. Display all revs.
1345 # No files, no patterns. Display all revs.
1346 wanted = revs
1346 wanted = revs
1347
1347
1348 if not slowpath and match.files():
1348 if not slowpath and match.files():
1349 # We only have to read through the filelog to find wanted revisions
1349 # We only have to read through the filelog to find wanted revisions
1350
1350
1351 try:
1351 try:
1352 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1352 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1353 except FileWalkError:
1353 except FileWalkError:
1354 slowpath = True
1354 slowpath = True
1355
1355
1356 # We decided to fall back to the slowpath because at least one
1356 # We decided to fall back to the slowpath because at least one
1357 # of the paths was not a file. Check to see if at least one of them
1357 # of the paths was not a file. Check to see if at least one of them
1358 # existed in history, otherwise simply return
1358 # existed in history, otherwise simply return
1359 for path in match.files():
1359 for path in match.files():
1360 if path == '.' or path in repo.store:
1360 if path == '.' or path in repo.store:
1361 break
1361 break
1362 else:
1362 else:
1363 return []
1363 return []
1364
1364
1365 if slowpath:
1365 if slowpath:
1366 # We have to read the changelog to match filenames against
1366 # We have to read the changelog to match filenames against
1367 # changed files
1367 # changed files
1368
1368
1369 if follow:
1369 if follow:
1370 raise util.Abort(_('can only follow copies/renames for explicit '
1370 raise util.Abort(_('can only follow copies/renames for explicit '
1371 'filenames'))
1371 'filenames'))
1372
1372
1373 # The slow path checks files modified in every changeset.
1373 # The slow path checks files modified in every changeset.
1374 # This is really slow on large repos, so compute the set lazily.
1374 # This is really slow on large repos, so compute the set lazily.
1375 class lazywantedset(object):
1375 class lazywantedset(object):
1376 def __init__(self):
1376 def __init__(self):
1377 self.set = set()
1377 self.set = set()
1378 self.revs = set(revs)
1378 self.revs = set(revs)
1379
1379
1380 # No need to worry about locality here because it will be accessed
1380 # No need to worry about locality here because it will be accessed
1381 # in the same order as the increasing window below.
1381 # in the same order as the increasing window below.
1382 def __contains__(self, value):
1382 def __contains__(self, value):
1383 if value in self.set:
1383 if value in self.set:
1384 return True
1384 return True
1385 elif not value in self.revs:
1385 elif not value in self.revs:
1386 return False
1386 return False
1387 else:
1387 else:
1388 self.revs.discard(value)
1388 self.revs.discard(value)
1389 ctx = change(value)
1389 ctx = change(value)
1390 matches = filter(match, ctx.files())
1390 matches = filter(match, ctx.files())
1391 if matches:
1391 if matches:
1392 fncache[value] = matches
1392 fncache[value] = matches
1393 self.set.add(value)
1393 self.set.add(value)
1394 return True
1394 return True
1395 return False
1395 return False
1396
1396
1397 def discard(self, value):
1397 def discard(self, value):
1398 self.revs.discard(value)
1398 self.revs.discard(value)
1399 self.set.discard(value)
1399 self.set.discard(value)
1400
1400
1401 wanted = lazywantedset()
1401 wanted = lazywantedset()
1402
1402
1403 class followfilter(object):
1403 class followfilter(object):
1404 def __init__(self, onlyfirst=False):
1404 def __init__(self, onlyfirst=False):
1405 self.startrev = nullrev
1405 self.startrev = nullrev
1406 self.roots = set()
1406 self.roots = set()
1407 self.onlyfirst = onlyfirst
1407 self.onlyfirst = onlyfirst
1408
1408
1409 def match(self, rev):
1409 def match(self, rev):
1410 def realparents(rev):
1410 def realparents(rev):
1411 if self.onlyfirst:
1411 if self.onlyfirst:
1412 return repo.changelog.parentrevs(rev)[0:1]
1412 return repo.changelog.parentrevs(rev)[0:1]
1413 else:
1413 else:
1414 return filter(lambda x: x != nullrev,
1414 return filter(lambda x: x != nullrev,
1415 repo.changelog.parentrevs(rev))
1415 repo.changelog.parentrevs(rev))
1416
1416
1417 if self.startrev == nullrev:
1417 if self.startrev == nullrev:
1418 self.startrev = rev
1418 self.startrev = rev
1419 return True
1419 return True
1420
1420
1421 if rev > self.startrev:
1421 if rev > self.startrev:
1422 # forward: all descendants
1422 # forward: all descendants
1423 if not self.roots:
1423 if not self.roots:
1424 self.roots.add(self.startrev)
1424 self.roots.add(self.startrev)
1425 for parent in realparents(rev):
1425 for parent in realparents(rev):
1426 if parent in self.roots:
1426 if parent in self.roots:
1427 self.roots.add(rev)
1427 self.roots.add(rev)
1428 return True
1428 return True
1429 else:
1429 else:
1430 # backwards: all parents
1430 # backwards: all parents
1431 if not self.roots:
1431 if not self.roots:
1432 self.roots.update(realparents(self.startrev))
1432 self.roots.update(realparents(self.startrev))
1433 if rev in self.roots:
1433 if rev in self.roots:
1434 self.roots.remove(rev)
1434 self.roots.remove(rev)
1435 self.roots.update(realparents(rev))
1435 self.roots.update(realparents(rev))
1436 return True
1436 return True
1437
1437
1438 return False
1438 return False
1439
1439
1440 # it might be worthwhile to do this in the iterator if the rev range
1440 # it might be worthwhile to do this in the iterator if the rev range
1441 # is descending and the prune args are all within that range
1441 # is descending and the prune args are all within that range
1442 for rev in opts.get('prune', ()):
1442 for rev in opts.get('prune', ()):
1443 rev = repo[rev].rev()
1443 rev = repo[rev].rev()
1444 ff = followfilter()
1444 ff = followfilter()
1445 stop = min(revs[0], revs[-1])
1445 stop = min(revs[0], revs[-1])
1446 for x in xrange(rev, stop - 1, -1):
1446 for x in xrange(rev, stop - 1, -1):
1447 if ff.match(x):
1447 if ff.match(x):
1448 wanted = wanted - [x]
1448 wanted = wanted - [x]
1449
1449
1450 # Now that wanted is correctly initialized, we can iterate over the
1450 # Now that wanted is correctly initialized, we can iterate over the
1451 # revision range, yielding only revisions in wanted.
1451 # revision range, yielding only revisions in wanted.
1452 def iterate():
1452 def iterate():
1453 if follow and not match.files():
1453 if follow and not match.files():
1454 ff = followfilter(onlyfirst=opts.get('follow_first'))
1454 ff = followfilter(onlyfirst=opts.get('follow_first'))
1455 def want(rev):
1455 def want(rev):
1456 return ff.match(rev) and rev in wanted
1456 return ff.match(rev) and rev in wanted
1457 else:
1457 else:
1458 def want(rev):
1458 def want(rev):
1459 return rev in wanted
1459 return rev in wanted
1460
1460
1461 it = iter(revs)
1461 it = iter(revs)
1462 stopiteration = False
1462 stopiteration = False
1463 for windowsize in increasingwindows():
1463 for windowsize in increasingwindows():
1464 nrevs = []
1464 nrevs = []
1465 for i in xrange(windowsize):
1465 for i in xrange(windowsize):
1466 try:
1466 try:
1467 rev = it.next()
1467 rev = it.next()
1468 if want(rev):
1468 if want(rev):
1469 nrevs.append(rev)
1469 nrevs.append(rev)
1470 except (StopIteration):
1470 except (StopIteration):
1471 stopiteration = True
1471 stopiteration = True
1472 break
1472 break
1473 for rev in sorted(nrevs):
1473 for rev in sorted(nrevs):
1474 fns = fncache.get(rev)
1474 fns = fncache.get(rev)
1475 ctx = change(rev)
1475 ctx = change(rev)
1476 if not fns:
1476 if not fns:
1477 def fns_generator():
1477 def fns_generator():
1478 for f in ctx.files():
1478 for f in ctx.files():
1479 if match(f):
1479 if match(f):
1480 yield f
1480 yield f
1481 fns = fns_generator()
1481 fns = fns_generator()
1482 prepare(ctx, fns)
1482 prepare(ctx, fns)
1483 for rev in nrevs:
1483 for rev in nrevs:
1484 yield change(rev)
1484 yield change(rev)
1485
1485
1486 if stopiteration:
1486 if stopiteration:
1487 break
1487 break
1488
1488
1489 return iterate()
1489 return iterate()
1490
1490
1491 def _makelogfilematcher(repo, pats, followfirst):
1491 def _makelogfilematcher(repo, pats, followfirst):
1492 # When displaying a revision with --patch --follow FILE, we have
1492 # When displaying a revision with --patch --follow FILE, we have
1493 # to know which file of the revision must be diffed. With
1493 # to know which file of the revision must be diffed. With
1494 # --follow, we want the names of the ancestors of FILE in the
1494 # --follow, we want the names of the ancestors of FILE in the
1495 # revision, stored in "fcache". "fcache" is populated by
1495 # revision, stored in "fcache". "fcache" is populated by
1496 # reproducing the graph traversal already done by --follow revset
1496 # reproducing the graph traversal already done by --follow revset
1497 # and relating linkrevs to file names (which is not "correct" but
1497 # and relating linkrevs to file names (which is not "correct" but
1498 # good enough).
1498 # good enough).
1499 fcache = {}
1499 fcache = {}
1500 fcacheready = [False]
1500 fcacheready = [False]
1501 pctx = repo['.']
1501 pctx = repo['.']
1502 wctx = repo[None]
1502 wctx = repo[None]
1503
1503
1504 def populate():
1504 def populate():
1505 for fn in pats:
1505 for fn in pats:
1506 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1506 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1507 for c in i:
1507 for c in i:
1508 fcache.setdefault(c.linkrev(), set()).add(c.path())
1508 fcache.setdefault(c.linkrev(), set()).add(c.path())
1509
1509
1510 def filematcher(rev):
1510 def filematcher(rev):
1511 if not fcacheready[0]:
1511 if not fcacheready[0]:
1512 # Lazy initialization
1512 # Lazy initialization
1513 fcacheready[0] = True
1513 fcacheready[0] = True
1514 populate()
1514 populate()
1515 return scmutil.match(wctx, fcache.get(rev, []), default='path')
1515 return scmutil.match(wctx, fcache.get(rev, []), default='path')
1516
1516
1517 return filematcher
1517 return filematcher
1518
1518
1519 def _makelogrevset(repo, pats, opts, revs):
1519 def _makelogrevset(repo, pats, opts, revs):
1520 """Return (expr, filematcher) where expr is a revset string built
1520 """Return (expr, filematcher) where expr is a revset string built
1521 from log options and file patterns or None. If --stat or --patch
1521 from log options and file patterns or None. If --stat or --patch
1522 are not passed filematcher is None. Otherwise it is a callable
1522 are not passed filematcher is None. Otherwise it is a callable
1523 taking a revision number and returning a match objects filtering
1523 taking a revision number and returning a match objects filtering
1524 the files to be detailed when displaying the revision.
1524 the files to be detailed when displaying the revision.
1525 """
1525 """
1526 opt2revset = {
1526 opt2revset = {
1527 'no_merges': ('not merge()', None),
1527 'no_merges': ('not merge()', None),
1528 'only_merges': ('merge()', None),
1528 'only_merges': ('merge()', None),
1529 '_ancestors': ('ancestors(%(val)s)', None),
1529 '_ancestors': ('ancestors(%(val)s)', None),
1530 '_fancestors': ('_firstancestors(%(val)s)', None),
1530 '_fancestors': ('_firstancestors(%(val)s)', None),
1531 '_descendants': ('descendants(%(val)s)', None),
1531 '_descendants': ('descendants(%(val)s)', None),
1532 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1532 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1533 '_matchfiles': ('_matchfiles(%(val)s)', None),
1533 '_matchfiles': ('_matchfiles(%(val)s)', None),
1534 'date': ('date(%(val)r)', None),
1534 'date': ('date(%(val)r)', None),
1535 'branch': ('branch(%(val)r)', ' or '),
1535 'branch': ('branch(%(val)r)', ' or '),
1536 '_patslog': ('filelog(%(val)r)', ' or '),
1536 '_patslog': ('filelog(%(val)r)', ' or '),
1537 '_patsfollow': ('follow(%(val)r)', ' or '),
1537 '_patsfollow': ('follow(%(val)r)', ' or '),
1538 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1538 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1539 'keyword': ('keyword(%(val)r)', ' or '),
1539 'keyword': ('keyword(%(val)r)', ' or '),
1540 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1540 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1541 'user': ('user(%(val)r)', ' or '),
1541 'user': ('user(%(val)r)', ' or '),
1542 }
1542 }
1543
1543
1544 opts = dict(opts)
1544 opts = dict(opts)
1545 # follow or not follow?
1545 # follow or not follow?
1546 follow = opts.get('follow') or opts.get('follow_first')
1546 follow = opts.get('follow') or opts.get('follow_first')
1547 followfirst = opts.get('follow_first') and 1 or 0
1547 followfirst = opts.get('follow_first') and 1 or 0
1548 # --follow with FILE behaviour depends on revs...
1548 # --follow with FILE behaviour depends on revs...
1549 it = iter(revs)
1549 it = iter(revs)
1550 startrev = it.next()
1550 startrev = it.next()
1551 try:
1551 try:
1552 followdescendants = startrev < it.next()
1552 followdescendants = startrev < it.next()
1553 except (StopIteration):
1553 except (StopIteration):
1554 followdescendants = False
1554 followdescendants = False
1555
1555
1556 # branch and only_branch are really aliases and must be handled at
1556 # branch and only_branch are really aliases and must be handled at
1557 # the same time
1557 # the same time
1558 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1558 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1559 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1559 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1560 # pats/include/exclude are passed to match.match() directly in
1560 # pats/include/exclude are passed to match.match() directly in
1561 # _matchfiles() revset but walkchangerevs() builds its matcher with
1561 # _matchfiles() revset but walkchangerevs() builds its matcher with
1562 # scmutil.match(). The difference is input pats are globbed on
1562 # scmutil.match(). The difference is input pats are globbed on
1563 # platforms without shell expansion (windows).
1563 # platforms without shell expansion (windows).
1564 pctx = repo[None]
1564 pctx = repo[None]
1565 match, pats = scmutil.matchandpats(pctx, pats, opts)
1565 match, pats = scmutil.matchandpats(pctx, pats, opts)
1566 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1566 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1567 if not slowpath:
1567 if not slowpath:
1568 for f in match.files():
1568 for f in match.files():
1569 if follow and f not in pctx:
1569 if follow and f not in pctx:
1570 raise util.Abort(_('cannot follow file not in parent '
1570 raise util.Abort(_('cannot follow file not in parent '
1571 'revision: "%s"') % f)
1571 'revision: "%s"') % f)
1572 filelog = repo.file(f)
1572 filelog = repo.file(f)
1573 if not filelog:
1573 if not filelog:
1574 # A zero count may be a directory or deleted file, so
1574 # A zero count may be a directory or deleted file, so
1575 # try to find matching entries on the slow path.
1575 # try to find matching entries on the slow path.
1576 if follow:
1576 if follow:
1577 raise util.Abort(
1577 raise util.Abort(
1578 _('cannot follow nonexistent file: "%s"') % f)
1578 _('cannot follow nonexistent file: "%s"') % f)
1579 slowpath = True
1579 slowpath = True
1580
1580
1581 # We decided to fall back to the slowpath because at least one
1581 # We decided to fall back to the slowpath because at least one
1582 # of the paths was not a file. Check to see if at least one of them
1582 # of the paths was not a file. Check to see if at least one of them
1583 # existed in history - in that case, we'll continue down the
1583 # existed in history - in that case, we'll continue down the
1584 # slowpath; otherwise, we can turn off the slowpath
1584 # slowpath; otherwise, we can turn off the slowpath
1585 if slowpath:
1585 if slowpath:
1586 for path in match.files():
1586 for path in match.files():
1587 if path == '.' or path in repo.store:
1587 if path == '.' or path in repo.store:
1588 break
1588 break
1589 else:
1589 else:
1590 slowpath = False
1590 slowpath = False
1591
1591
1592 if slowpath:
1592 if slowpath:
1593 # See walkchangerevs() slow path.
1593 # See walkchangerevs() slow path.
1594 #
1594 #
1595 if follow:
1595 if follow:
1596 raise util.Abort(_('can only follow copies/renames for explicit '
1596 raise util.Abort(_('can only follow copies/renames for explicit '
1597 'filenames'))
1597 'filenames'))
1598 # pats/include/exclude cannot be represented as separate
1598 # pats/include/exclude cannot be represented as separate
1599 # revset expressions as their filtering logic applies at file
1599 # revset expressions as their filtering logic applies at file
1600 # level. For instance "-I a -X a" matches a revision touching
1600 # level. For instance "-I a -X a" matches a revision touching
1601 # "a" and "b" while "file(a) and not file(b)" does
1601 # "a" and "b" while "file(a) and not file(b)" does
1602 # not. Besides, filesets are evaluated against the working
1602 # not. Besides, filesets are evaluated against the working
1603 # directory.
1603 # directory.
1604 matchargs = ['r:', 'd:relpath']
1604 matchargs = ['r:', 'd:relpath']
1605 for p in pats:
1605 for p in pats:
1606 matchargs.append('p:' + p)
1606 matchargs.append('p:' + p)
1607 for p in opts.get('include', []):
1607 for p in opts.get('include', []):
1608 matchargs.append('i:' + p)
1608 matchargs.append('i:' + p)
1609 for p in opts.get('exclude', []):
1609 for p in opts.get('exclude', []):
1610 matchargs.append('x:' + p)
1610 matchargs.append('x:' + p)
1611 matchargs = ','.join(('%r' % p) for p in matchargs)
1611 matchargs = ','.join(('%r' % p) for p in matchargs)
1612 opts['_matchfiles'] = matchargs
1612 opts['_matchfiles'] = matchargs
1613 else:
1613 else:
1614 if follow:
1614 if follow:
1615 fpats = ('_patsfollow', '_patsfollowfirst')
1615 fpats = ('_patsfollow', '_patsfollowfirst')
1616 fnopats = (('_ancestors', '_fancestors'),
1616 fnopats = (('_ancestors', '_fancestors'),
1617 ('_descendants', '_fdescendants'))
1617 ('_descendants', '_fdescendants'))
1618 if pats:
1618 if pats:
1619 # follow() revset interprets its file argument as a
1619 # follow() revset interprets its file argument as a
1620 # manifest entry, so use match.files(), not pats.
1620 # manifest entry, so use match.files(), not pats.
1621 opts[fpats[followfirst]] = list(match.files())
1621 opts[fpats[followfirst]] = list(match.files())
1622 else:
1622 else:
1623 opts[fnopats[followdescendants][followfirst]] = str(startrev)
1623 opts[fnopats[followdescendants][followfirst]] = str(startrev)
1624 else:
1624 else:
1625 opts['_patslog'] = list(pats)
1625 opts['_patslog'] = list(pats)
1626
1626
1627 filematcher = None
1627 filematcher = None
1628 if opts.get('patch') or opts.get('stat'):
1628 if opts.get('patch') or opts.get('stat'):
1629 if follow:
1629 if follow:
1630 filematcher = _makelogfilematcher(repo, pats, followfirst)
1630 filematcher = _makelogfilematcher(repo, pats, followfirst)
1631 else:
1631 else:
1632 filematcher = lambda rev: match
1632 filematcher = lambda rev: match
1633
1633
1634 expr = []
1634 expr = []
1635 for op, val in opts.iteritems():
1635 for op, val in opts.iteritems():
1636 if not val:
1636 if not val:
1637 continue
1637 continue
1638 if op not in opt2revset:
1638 if op not in opt2revset:
1639 continue
1639 continue
1640 revop, andor = opt2revset[op]
1640 revop, andor = opt2revset[op]
1641 if '%(val)' not in revop:
1641 if '%(val)' not in revop:
1642 expr.append(revop)
1642 expr.append(revop)
1643 else:
1643 else:
1644 if not isinstance(val, list):
1644 if not isinstance(val, list):
1645 e = revop % {'val': val}
1645 e = revop % {'val': val}
1646 else:
1646 else:
1647 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1647 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1648 expr.append(e)
1648 expr.append(e)
1649
1649
1650 if expr:
1650 if expr:
1651 expr = '(' + ' and '.join(expr) + ')'
1651 expr = '(' + ' and '.join(expr) + ')'
1652 else:
1652 else:
1653 expr = None
1653 expr = None
1654 return expr, filematcher
1654 return expr, filematcher
1655
1655
1656 def getgraphlogrevs(repo, pats, opts):
1656 def getgraphlogrevs(repo, pats, opts):
1657 """Return (revs, expr, filematcher) where revs is an iterable of
1657 """Return (revs, expr, filematcher) where revs is an iterable of
1658 revision numbers, expr is a revset string built from log options
1658 revision numbers, expr is a revset string built from log options
1659 and file patterns or None, and used to filter 'revs'. If --stat or
1659 and file patterns or None, and used to filter 'revs'. If --stat or
1660 --patch are not passed filematcher is None. Otherwise it is a
1660 --patch are not passed filematcher is None. Otherwise it is a
1661 callable taking a revision number and returning a match objects
1661 callable taking a revision number and returning a match objects
1662 filtering the files to be detailed when displaying the revision.
1662 filtering the files to be detailed when displaying the revision.
1663 """
1663 """
1664 if not len(repo):
1664 if not len(repo):
1665 return [], None, None
1665 return [], None, None
1666 limit = loglimit(opts)
1666 limit = loglimit(opts)
1667 # Default --rev value depends on --follow but --follow behaviour
1667 # Default --rev value depends on --follow but --follow behaviour
1668 # depends on revisions resolved from --rev...
1668 # depends on revisions resolved from --rev...
1669 follow = opts.get('follow') or opts.get('follow_first')
1669 follow = opts.get('follow') or opts.get('follow_first')
1670 possiblyunsorted = False # whether revs might need sorting
1670 possiblyunsorted = False # whether revs might need sorting
1671 if opts.get('rev'):
1671 if opts.get('rev'):
1672 revs = scmutil.revrange(repo, opts['rev'])
1672 revs = scmutil.revrange(repo, opts['rev'])
1673 # Don't sort here because _makelogrevset might depend on the
1673 # Don't sort here because _makelogrevset might depend on the
1674 # order of revs
1674 # order of revs
1675 possiblyunsorted = True
1675 possiblyunsorted = True
1676 else:
1676 else:
1677 if follow and len(repo) > 0:
1677 if follow and len(repo) > 0:
1678 revs = repo.revs('reverse(:.)')
1678 revs = repo.revs('reverse(:.)')
1679 else:
1679 else:
1680 revs = revset.spanset(repo)
1680 revs = revset.spanset(repo)
1681 revs.reverse()
1681 revs.reverse()
1682 if not revs:
1682 if not revs:
1683 return revset.baseset(), None, None
1683 return revset.baseset(), None, None
1684 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
1684 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
1685 if possiblyunsorted:
1685 if possiblyunsorted:
1686 revs.sort(reverse=True)
1686 revs.sort(reverse=True)
1687 if expr:
1687 if expr:
1688 # Revset matchers often operate faster on revisions in changelog
1688 # Revset matchers often operate faster on revisions in changelog
1689 # order, because most filters deal with the changelog.
1689 # order, because most filters deal with the changelog.
1690 revs.reverse()
1690 revs.reverse()
1691 matcher = revset.match(repo.ui, expr)
1691 matcher = revset.match(repo.ui, expr)
1692 # Revset matches can reorder revisions. "A or B" typically returns
1692 # Revset matches can reorder revisions. "A or B" typically returns
1693 # returns the revision matching A then the revision matching B. Sort
1693 # returns the revision matching A then the revision matching B. Sort
1694 # again to fix that.
1694 # again to fix that.
1695 revs = matcher(repo, revs)
1695 revs = matcher(repo, revs)
1696 revs.sort(reverse=True)
1696 revs.sort(reverse=True)
1697 if limit is not None:
1697 if limit is not None:
1698 limitedrevs = revset.baseset()
1698 limitedrevs = revset.baseset()
1699 for idx, rev in enumerate(revs):
1699 for idx, rev in enumerate(revs):
1700 if idx >= limit:
1700 if idx >= limit:
1701 break
1701 break
1702 limitedrevs.append(rev)
1702 limitedrevs.append(rev)
1703 revs = limitedrevs
1703 revs = limitedrevs
1704
1704
1705 return revs, expr, filematcher
1705 return revs, expr, filematcher
1706
1706
1707 def getlogrevs(repo, pats, opts):
1707 def getlogrevs(repo, pats, opts):
1708 """Return (revs, expr, filematcher) where revs is an iterable of
1708 """Return (revs, expr, filematcher) where revs is an iterable of
1709 revision numbers, expr is a revset string built from log options
1709 revision numbers, expr is a revset string built from log options
1710 and file patterns or None, and used to filter 'revs'. If --stat or
1710 and file patterns or None, and used to filter 'revs'. If --stat or
1711 --patch are not passed filematcher is None. Otherwise it is a
1711 --patch are not passed filematcher is None. Otherwise it is a
1712 callable taking a revision number and returning a match objects
1712 callable taking a revision number and returning a match objects
1713 filtering the files to be detailed when displaying the revision.
1713 filtering the files to be detailed when displaying the revision.
1714 """
1714 """
1715 limit = loglimit(opts)
1715 limit = loglimit(opts)
1716 # Default --rev value depends on --follow but --follow behaviour
1716 # Default --rev value depends on --follow but --follow behaviour
1717 # depends on revisions resolved from --rev...
1717 # depends on revisions resolved from --rev...
1718 follow = opts.get('follow') or opts.get('follow_first')
1718 follow = opts.get('follow') or opts.get('follow_first')
1719 if opts.get('rev'):
1719 if opts.get('rev'):
1720 revs = scmutil.revrange(repo, opts['rev'])
1720 revs = scmutil.revrange(repo, opts['rev'])
1721 elif follow:
1721 elif follow:
1722 revs = revset.baseset(repo.revs('reverse(:.)'))
1722 revs = revset.baseset(repo.revs('reverse(:.)'))
1723 else:
1723 else:
1724 revs = revset.spanset(repo)
1724 revs = revset.spanset(repo)
1725 revs.reverse()
1725 revs.reverse()
1726 if not revs:
1726 if not revs:
1727 return revset.baseset([]), None, None
1727 return revset.baseset([]), None, None
1728 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
1728 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
1729 if expr:
1729 if expr:
1730 # Revset matchers often operate faster on revisions in changelog
1730 # Revset matchers often operate faster on revisions in changelog
1731 # order, because most filters deal with the changelog.
1731 # order, because most filters deal with the changelog.
1732 if not opts.get('rev'):
1732 if not opts.get('rev'):
1733 revs.reverse()
1733 revs.reverse()
1734 matcher = revset.match(repo.ui, expr)
1734 matcher = revset.match(repo.ui, expr)
1735 # Revset matches can reorder revisions. "A or B" typically returns
1735 # Revset matches can reorder revisions. "A or B" typically returns
1736 # returns the revision matching A then the revision matching B. Sort
1736 # returns the revision matching A then the revision matching B. Sort
1737 # again to fix that.
1737 # again to fix that.
1738 revs = matcher(repo, revs)
1738 revs = matcher(repo, revs)
1739 if not opts.get('rev'):
1739 if not opts.get('rev'):
1740 revs.sort(reverse=True)
1740 revs.sort(reverse=True)
1741 if limit is not None:
1741 if limit is not None:
1742 count = 0
1742 count = 0
1743 limitedrevs = revset.baseset([])
1743 limitedrevs = revset.baseset([])
1744 it = iter(revs)
1744 it = iter(revs)
1745 while count < limit:
1745 while count < limit:
1746 try:
1746 try:
1747 limitedrevs.append(it.next())
1747 limitedrevs.append(it.next())
1748 except (StopIteration):
1748 except (StopIteration):
1749 break
1749 break
1750 count += 1
1750 count += 1
1751 revs = limitedrevs
1751 revs = limitedrevs
1752
1752
1753 return revs, expr, filematcher
1753 return revs, expr, filematcher
1754
1754
1755 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
1755 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
1756 filematcher=None):
1756 filematcher=None):
1757 seen, state = [], graphmod.asciistate()
1757 seen, state = [], graphmod.asciistate()
1758 for rev, type, ctx, parents in dag:
1758 for rev, type, ctx, parents in dag:
1759 char = 'o'
1759 char = 'o'
1760 if ctx.node() in showparents:
1760 if ctx.node() in showparents:
1761 char = '@'
1761 char = '@'
1762 elif ctx.obsolete():
1762 elif ctx.obsolete():
1763 char = 'x'
1763 char = 'x'
1764 copies = None
1764 copies = None
1765 if getrenamed and ctx.rev():
1765 if getrenamed and ctx.rev():
1766 copies = []
1766 copies = []
1767 for fn in ctx.files():
1767 for fn in ctx.files():
1768 rename = getrenamed(fn, ctx.rev())
1768 rename = getrenamed(fn, ctx.rev())
1769 if rename:
1769 if rename:
1770 copies.append((fn, rename[0]))
1770 copies.append((fn, rename[0]))
1771 revmatchfn = None
1771 revmatchfn = None
1772 if filematcher is not None:
1772 if filematcher is not None:
1773 revmatchfn = filematcher(ctx.rev())
1773 revmatchfn = filematcher(ctx.rev())
1774 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
1774 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
1775 lines = displayer.hunk.pop(rev).split('\n')
1775 lines = displayer.hunk.pop(rev).split('\n')
1776 if not lines[-1]:
1776 if not lines[-1]:
1777 del lines[-1]
1777 del lines[-1]
1778 displayer.flush(rev)
1778 displayer.flush(rev)
1779 edges = edgefn(type, char, lines, seen, rev, parents)
1779 edges = edgefn(type, char, lines, seen, rev, parents)
1780 for type, char, lines, coldata in edges:
1780 for type, char, lines, coldata in edges:
1781 graphmod.ascii(ui, state, type, char, lines, coldata)
1781 graphmod.ascii(ui, state, type, char, lines, coldata)
1782 displayer.close()
1782 displayer.close()
1783
1783
1784 def graphlog(ui, repo, *pats, **opts):
1784 def graphlog(ui, repo, *pats, **opts):
1785 # Parameters are identical to log command ones
1785 # Parameters are identical to log command ones
1786 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
1786 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
1787 revdag = graphmod.dagwalker(repo, revs)
1787 revdag = graphmod.dagwalker(repo, revs)
1788
1788
1789 getrenamed = None
1789 getrenamed = None
1790 if opts.get('copies'):
1790 if opts.get('copies'):
1791 endrev = None
1791 endrev = None
1792 if opts.get('rev'):
1792 if opts.get('rev'):
1793 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
1793 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
1794 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
1794 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
1795 displayer = show_changeset(ui, repo, opts, buffered=True)
1795 displayer = show_changeset(ui, repo, opts, buffered=True)
1796 showparents = [ctx.node() for ctx in repo[None].parents()]
1796 showparents = [ctx.node() for ctx in repo[None].parents()]
1797 displaygraph(ui, revdag, displayer, showparents,
1797 displaygraph(ui, revdag, displayer, showparents,
1798 graphmod.asciiedges, getrenamed, filematcher)
1798 graphmod.asciiedges, getrenamed, filematcher)
1799
1799
1800 def checkunsupportedgraphflags(pats, opts):
1800 def checkunsupportedgraphflags(pats, opts):
1801 for op in ["newest_first"]:
1801 for op in ["newest_first"]:
1802 if op in opts and opts[op]:
1802 if op in opts and opts[op]:
1803 raise util.Abort(_("-G/--graph option is incompatible with --%s")
1803 raise util.Abort(_("-G/--graph option is incompatible with --%s")
1804 % op.replace("_", "-"))
1804 % op.replace("_", "-"))
1805
1805
1806 def graphrevs(repo, nodes, opts):
1806 def graphrevs(repo, nodes, opts):
1807 limit = loglimit(opts)
1807 limit = loglimit(opts)
1808 nodes.reverse()
1808 nodes.reverse()
1809 if limit is not None:
1809 if limit is not None:
1810 nodes = nodes[:limit]
1810 nodes = nodes[:limit]
1811 return graphmod.nodes(repo, nodes)
1811 return graphmod.nodes(repo, nodes)
1812
1812
1813 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1813 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1814 join = lambda f: os.path.join(prefix, f)
1814 join = lambda f: os.path.join(prefix, f)
1815 bad = []
1815 bad = []
1816 oldbad = match.bad
1816 oldbad = match.bad
1817 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1817 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1818 names = []
1818 names = []
1819 wctx = repo[None]
1819 wctx = repo[None]
1820 cca = None
1820 cca = None
1821 abort, warn = scmutil.checkportabilityalert(ui)
1821 abort, warn = scmutil.checkportabilityalert(ui)
1822 if abort or warn:
1822 if abort or warn:
1823 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
1823 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
1824 for f in repo.walk(match):
1824 for f in repo.walk(match):
1825 exact = match.exact(f)
1825 exact = match.exact(f)
1826 if exact or not explicitonly and f not in repo.dirstate:
1826 if exact or not explicitonly and f not in repo.dirstate:
1827 if cca:
1827 if cca:
1828 cca(f)
1828 cca(f)
1829 names.append(f)
1829 names.append(f)
1830 if ui.verbose or not exact:
1830 if ui.verbose or not exact:
1831 ui.status(_('adding %s\n') % match.rel(join(f)))
1831 ui.status(_('adding %s\n') % match.rel(join(f)))
1832
1832
1833 for subpath in sorted(wctx.substate):
1833 for subpath in sorted(wctx.substate):
1834 sub = wctx.sub(subpath)
1834 sub = wctx.sub(subpath)
1835 try:
1835 try:
1836 submatch = matchmod.narrowmatcher(subpath, match)
1836 submatch = matchmod.narrowmatcher(subpath, match)
1837 if listsubrepos:
1837 if listsubrepos:
1838 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1838 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1839 False))
1839 False))
1840 else:
1840 else:
1841 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1841 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1842 True))
1842 True))
1843 except error.LookupError:
1843 except error.LookupError:
1844 ui.status(_("skipping missing subrepository: %s\n")
1844 ui.status(_("skipping missing subrepository: %s\n")
1845 % join(subpath))
1845 % join(subpath))
1846
1846
1847 if not dryrun:
1847 if not dryrun:
1848 rejected = wctx.add(names, prefix)
1848 rejected = wctx.add(names, prefix)
1849 bad.extend(f for f in rejected if f in match.files())
1849 bad.extend(f for f in rejected if f in match.files())
1850 return bad
1850 return bad
1851
1851
1852 def forget(ui, repo, match, prefix, explicitonly):
1852 def forget(ui, repo, match, prefix, explicitonly):
1853 join = lambda f: os.path.join(prefix, f)
1853 join = lambda f: os.path.join(prefix, f)
1854 bad = []
1854 bad = []
1855 oldbad = match.bad
1855 oldbad = match.bad
1856 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1856 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1857 wctx = repo[None]
1857 wctx = repo[None]
1858 forgot = []
1858 forgot = []
1859 s = repo.status(match=match, clean=True)
1859 s = repo.status(match=match, clean=True)
1860 forget = sorted(s[0] + s[1] + s[3] + s[6])
1860 forget = sorted(s[0] + s[1] + s[3] + s[6])
1861 if explicitonly:
1861 if explicitonly:
1862 forget = [f for f in forget if match.exact(f)]
1862 forget = [f for f in forget if match.exact(f)]
1863
1863
1864 for subpath in sorted(wctx.substate):
1864 for subpath in sorted(wctx.substate):
1865 sub = wctx.sub(subpath)
1865 sub = wctx.sub(subpath)
1866 try:
1866 try:
1867 submatch = matchmod.narrowmatcher(subpath, match)
1867 submatch = matchmod.narrowmatcher(subpath, match)
1868 subbad, subforgot = sub.forget(ui, submatch, prefix)
1868 subbad, subforgot = sub.forget(ui, submatch, prefix)
1869 bad.extend([subpath + '/' + f for f in subbad])
1869 bad.extend([subpath + '/' + f for f in subbad])
1870 forgot.extend([subpath + '/' + f for f in subforgot])
1870 forgot.extend([subpath + '/' + f for f in subforgot])
1871 except error.LookupError:
1871 except error.LookupError:
1872 ui.status(_("skipping missing subrepository: %s\n")
1872 ui.status(_("skipping missing subrepository: %s\n")
1873 % join(subpath))
1873 % join(subpath))
1874
1874
1875 if not explicitonly:
1875 if not explicitonly:
1876 for f in match.files():
1876 for f in match.files():
1877 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
1877 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
1878 if f not in forgot:
1878 if f not in forgot:
1879 if os.path.exists(match.rel(join(f))):
1879 if os.path.exists(match.rel(join(f))):
1880 ui.warn(_('not removing %s: '
1880 ui.warn(_('not removing %s: '
1881 'file is already untracked\n')
1881 'file is already untracked\n')
1882 % match.rel(join(f)))
1882 % match.rel(join(f)))
1883 bad.append(f)
1883 bad.append(f)
1884
1884
1885 for f in forget:
1885 for f in forget:
1886 if ui.verbose or not match.exact(f):
1886 if ui.verbose or not match.exact(f):
1887 ui.status(_('removing %s\n') % match.rel(join(f)))
1887 ui.status(_('removing %s\n') % match.rel(join(f)))
1888
1888
1889 rejected = wctx.forget(forget, prefix)
1889 rejected = wctx.forget(forget, prefix)
1890 bad.extend(f for f in rejected if f in match.files())
1890 bad.extend(f for f in rejected if f in match.files())
1891 forgot.extend(forget)
1891 forgot.extend(forget)
1892 return bad, forgot
1892 return bad, forgot
1893
1893
1894 def cat(ui, repo, ctx, matcher, prefix, **opts):
1894 def cat(ui, repo, ctx, matcher, prefix, **opts):
1895 err = 1
1895 err = 1
1896
1896
1897 def write(path):
1897 def write(path):
1898 fp = makefileobj(repo, opts.get('output'), ctx.node(),
1898 fp = makefileobj(repo, opts.get('output'), ctx.node(),
1899 pathname=os.path.join(prefix, path))
1899 pathname=os.path.join(prefix, path))
1900 data = ctx[path].data()
1900 data = ctx[path].data()
1901 if opts.get('decode'):
1901 if opts.get('decode'):
1902 data = repo.wwritedata(path, data)
1902 data = repo.wwritedata(path, data)
1903 fp.write(data)
1903 fp.write(data)
1904 fp.close()
1904 fp.close()
1905
1905
1906 # Automation often uses hg cat on single files, so special case it
1906 # Automation often uses hg cat on single files, so special case it
1907 # for performance to avoid the cost of parsing the manifest.
1907 # for performance to avoid the cost of parsing the manifest.
1908 if len(matcher.files()) == 1 and not matcher.anypats():
1908 if len(matcher.files()) == 1 and not matcher.anypats():
1909 file = matcher.files()[0]
1909 file = matcher.files()[0]
1910 mf = repo.manifest
1910 mf = repo.manifest
1911 mfnode = ctx._changeset[0]
1911 mfnode = ctx._changeset[0]
1912 if mf.find(mfnode, file)[0]:
1912 if mf.find(mfnode, file)[0]:
1913 write(file)
1913 write(file)
1914 return 0
1914 return 0
1915
1915
1916 # Don't warn about "missing" files that are really in subrepos
1916 # Don't warn about "missing" files that are really in subrepos
1917 bad = matcher.bad
1917 bad = matcher.bad
1918
1918
1919 def badfn(path, msg):
1919 def badfn(path, msg):
1920 for subpath in ctx.substate:
1920 for subpath in ctx.substate:
1921 if path.startswith(subpath):
1921 if path.startswith(subpath):
1922 return
1922 return
1923 bad(path, msg)
1923 bad(path, msg)
1924
1924
1925 matcher.bad = badfn
1925 matcher.bad = badfn
1926
1926
1927 for abs in ctx.walk(matcher):
1927 for abs in ctx.walk(matcher):
1928 write(abs)
1928 write(abs)
1929 err = 0
1929 err = 0
1930
1930
1931 matcher.bad = bad
1931 matcher.bad = bad
1932
1932
1933 for subpath in sorted(ctx.substate):
1933 for subpath in sorted(ctx.substate):
1934 sub = ctx.sub(subpath)
1934 sub = ctx.sub(subpath)
1935 try:
1935 try:
1936 submatch = matchmod.narrowmatcher(subpath, matcher)
1936 submatch = matchmod.narrowmatcher(subpath, matcher)
1937
1937
1938 if not sub.cat(ui, submatch, os.path.join(prefix, sub._path),
1938 if not sub.cat(ui, submatch, os.path.join(prefix, sub._path),
1939 **opts):
1939 **opts):
1940 err = 0
1940 err = 0
1941 except error.RepoLookupError:
1941 except error.RepoLookupError:
1942 ui.status(_("skipping missing subrepository: %s\n")
1942 ui.status(_("skipping missing subrepository: %s\n")
1943 % os.path.join(prefix, subpath))
1943 % os.path.join(prefix, subpath))
1944
1944
1945 return err
1945 return err
1946
1946
1947 def duplicatecopies(repo, rev, fromrev):
1947 def duplicatecopies(repo, rev, fromrev):
1948 '''reproduce copies from fromrev to rev in the dirstate'''
1948 '''reproduce copies from fromrev to rev in the dirstate'''
1949 for dst, src in copies.pathcopies(repo[fromrev], repo[rev]).iteritems():
1949 for dst, src in copies.pathcopies(repo[fromrev], repo[rev]).iteritems():
1950 # copies.pathcopies returns backward renames, so dst might not
1950 # copies.pathcopies returns backward renames, so dst might not
1951 # actually be in the dirstate
1951 # actually be in the dirstate
1952 if repo.dirstate[dst] in "nma":
1952 if repo.dirstate[dst] in "nma":
1953 repo.dirstate.copy(src, dst)
1953 repo.dirstate.copy(src, dst)
1954
1954
1955 def commit(ui, repo, commitfunc, pats, opts):
1955 def commit(ui, repo, commitfunc, pats, opts):
1956 '''commit the specified files or all outstanding changes'''
1956 '''commit the specified files or all outstanding changes'''
1957 date = opts.get('date')
1957 date = opts.get('date')
1958 if date:
1958 if date:
1959 opts['date'] = util.parsedate(date)
1959 opts['date'] = util.parsedate(date)
1960 message = logmessage(ui, opts)
1960 message = logmessage(ui, opts)
1961
1961
1962 # extract addremove carefully -- this function can be called from a command
1962 # extract addremove carefully -- this function can be called from a command
1963 # that doesn't support addremove
1963 # that doesn't support addremove
1964 if opts.get('addremove'):
1964 if opts.get('addremove'):
1965 scmutil.addremove(repo, pats, opts)
1965 scmutil.addremove(repo, pats, opts)
1966
1966
1967 return commitfunc(ui, repo, message,
1967 return commitfunc(ui, repo, message,
1968 scmutil.match(repo[None], pats, opts), opts)
1968 scmutil.match(repo[None], pats, opts), opts)
1969
1969
1970 def amend(ui, repo, commitfunc, old, extra, pats, opts):
1970 def amend(ui, repo, commitfunc, old, extra, pats, opts):
1971 ui.note(_('amending changeset %s\n') % old)
1971 ui.note(_('amending changeset %s\n') % old)
1972 base = old.p1()
1972 base = old.p1()
1973
1973
1974 wlock = lock = newid = None
1974 wlock = lock = newid = None
1975 try:
1975 try:
1976 wlock = repo.wlock()
1976 wlock = repo.wlock()
1977 lock = repo.lock()
1977 lock = repo.lock()
1978 tr = repo.transaction('amend')
1978 tr = repo.transaction('amend')
1979 try:
1979 try:
1980 # See if we got a message from -m or -l, if not, open the editor
1980 # See if we got a message from -m or -l, if not, open the editor
1981 # with the message of the changeset to amend
1981 # with the message of the changeset to amend
1982 message = logmessage(ui, opts)
1982 message = logmessage(ui, opts)
1983 # ensure logfile does not conflict with later enforcement of the
1983 # ensure logfile does not conflict with later enforcement of the
1984 # message. potential logfile content has been processed by
1984 # message. potential logfile content has been processed by
1985 # `logmessage` anyway.
1985 # `logmessage` anyway.
1986 opts.pop('logfile')
1986 opts.pop('logfile')
1987 # First, do a regular commit to record all changes in the working
1987 # First, do a regular commit to record all changes in the working
1988 # directory (if there are any)
1988 # directory (if there are any)
1989 ui.callhooks = False
1989 ui.callhooks = False
1990 currentbookmark = repo._bookmarkcurrent
1990 currentbookmark = repo._bookmarkcurrent
1991 try:
1991 try:
1992 repo._bookmarkcurrent = None
1992 repo._bookmarkcurrent = None
1993 opts['message'] = 'temporary amend commit for %s' % old
1993 opts['message'] = 'temporary amend commit for %s' % old
1994 node = commit(ui, repo, commitfunc, pats, opts)
1994 node = commit(ui, repo, commitfunc, pats, opts)
1995 finally:
1995 finally:
1996 repo._bookmarkcurrent = currentbookmark
1996 repo._bookmarkcurrent = currentbookmark
1997 ui.callhooks = True
1997 ui.callhooks = True
1998 ctx = repo[node]
1998 ctx = repo[node]
1999
1999
2000 # Participating changesets:
2000 # Participating changesets:
2001 #
2001 #
2002 # node/ctx o - new (intermediate) commit that contains changes
2002 # node/ctx o - new (intermediate) commit that contains changes
2003 # | from working dir to go into amending commit
2003 # | from working dir to go into amending commit
2004 # | (or a workingctx if there were no changes)
2004 # | (or a workingctx if there were no changes)
2005 # |
2005 # |
2006 # old o - changeset to amend
2006 # old o - changeset to amend
2007 # |
2007 # |
2008 # base o - parent of amending changeset
2008 # base o - parent of amending changeset
2009
2009
2010 # Update extra dict from amended commit (e.g. to preserve graft
2010 # Update extra dict from amended commit (e.g. to preserve graft
2011 # source)
2011 # source)
2012 extra.update(old.extra())
2012 extra.update(old.extra())
2013
2013
2014 # Also update it from the intermediate commit or from the wctx
2014 # Also update it from the intermediate commit or from the wctx
2015 extra.update(ctx.extra())
2015 extra.update(ctx.extra())
2016
2016
2017 if len(old.parents()) > 1:
2017 if len(old.parents()) > 1:
2018 # ctx.files() isn't reliable for merges, so fall back to the
2018 # ctx.files() isn't reliable for merges, so fall back to the
2019 # slower repo.status() method
2019 # slower repo.status() method
2020 files = set([fn for st in repo.status(base, old)[:3]
2020 files = set([fn for st in repo.status(base, old)[:3]
2021 for fn in st])
2021 for fn in st])
2022 else:
2022 else:
2023 files = set(old.files())
2023 files = set(old.files())
2024
2024
2025 # Second, we use either the commit we just did, or if there were no
2025 # Second, we use either the commit we just did, or if there were no
2026 # changes the parent of the working directory as the version of the
2026 # changes the parent of the working directory as the version of the
2027 # files in the final amend commit
2027 # files in the final amend commit
2028 if node:
2028 if node:
2029 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
2029 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
2030
2030
2031 user = ctx.user()
2031 user = ctx.user()
2032 date = ctx.date()
2032 date = ctx.date()
2033 # Recompute copies (avoid recording a -> b -> a)
2033 # Recompute copies (avoid recording a -> b -> a)
2034 copied = copies.pathcopies(base, ctx)
2034 copied = copies.pathcopies(base, ctx)
2035
2035
2036 # Prune files which were reverted by the updates: if old
2036 # Prune files which were reverted by the updates: if old
2037 # introduced file X and our intermediate commit, node,
2037 # introduced file X and our intermediate commit, node,
2038 # renamed that file, then those two files are the same and
2038 # renamed that file, then those two files are the same and
2039 # we can discard X from our list of files. Likewise if X
2039 # we can discard X from our list of files. Likewise if X
2040 # was deleted, it's no longer relevant
2040 # was deleted, it's no longer relevant
2041 files.update(ctx.files())
2041 files.update(ctx.files())
2042
2042
2043 def samefile(f):
2043 def samefile(f):
2044 if f in ctx.manifest():
2044 if f in ctx.manifest():
2045 a = ctx.filectx(f)
2045 a = ctx.filectx(f)
2046 if f in base.manifest():
2046 if f in base.manifest():
2047 b = base.filectx(f)
2047 b = base.filectx(f)
2048 return (not a.cmp(b)
2048 return (not a.cmp(b)
2049 and a.flags() == b.flags())
2049 and a.flags() == b.flags())
2050 else:
2050 else:
2051 return False
2051 return False
2052 else:
2052 else:
2053 return f not in base.manifest()
2053 return f not in base.manifest()
2054 files = [f for f in files if not samefile(f)]
2054 files = [f for f in files if not samefile(f)]
2055
2055
2056 def filectxfn(repo, ctx_, path):
2056 def filectxfn(repo, ctx_, path):
2057 try:
2057 try:
2058 fctx = ctx[path]
2058 fctx = ctx[path]
2059 flags = fctx.flags()
2059 flags = fctx.flags()
2060 mctx = context.memfilectx(repo,
2060 mctx = context.memfilectx(repo,
2061 fctx.path(), fctx.data(),
2061 fctx.path(), fctx.data(),
2062 islink='l' in flags,
2062 islink='l' in flags,
2063 isexec='x' in flags,
2063 isexec='x' in flags,
2064 copied=copied.get(path))
2064 copied=copied.get(path))
2065 return mctx
2065 return mctx
2066 except KeyError:
2066 except KeyError:
2067 raise IOError
2067 raise IOError
2068 else:
2068 else:
2069 ui.note(_('copying changeset %s to %s\n') % (old, base))
2069 ui.note(_('copying changeset %s to %s\n') % (old, base))
2070
2070
2071 # Use version of files as in the old cset
2071 # Use version of files as in the old cset
2072 def filectxfn(repo, ctx_, path):
2072 def filectxfn(repo, ctx_, path):
2073 try:
2073 try:
2074 return old.filectx(path)
2074 return old.filectx(path)
2075 except KeyError:
2075 except KeyError:
2076 raise IOError
2076 raise IOError
2077
2077
2078 user = opts.get('user') or old.user()
2078 user = opts.get('user') or old.user()
2079 date = opts.get('date') or old.date()
2079 date = opts.get('date') or old.date()
2080 editor = getcommiteditor(**opts)
2080 editor = getcommiteditor(**opts)
2081 if not message:
2081 if not message:
2082 editor = getcommiteditor(edit=True)
2082 editor = getcommiteditor(edit=True)
2083 message = old.description()
2083 message = old.description()
2084
2084
2085 pureextra = extra.copy()
2085 pureextra = extra.copy()
2086 extra['amend_source'] = old.hex()
2086 extra['amend_source'] = old.hex()
2087
2087
2088 new = context.memctx(repo,
2088 new = context.memctx(repo,
2089 parents=[base.node(), old.p2().node()],
2089 parents=[base.node(), old.p2().node()],
2090 text=message,
2090 text=message,
2091 files=files,
2091 files=files,
2092 filectxfn=filectxfn,
2092 filectxfn=filectxfn,
2093 user=user,
2093 user=user,
2094 date=date,
2094 date=date,
2095 extra=extra,
2095 extra=extra,
2096 editor=editor)
2096 editor=editor)
2097
2097
2098 newdesc = changelog.stripdesc(new.description())
2098 newdesc = changelog.stripdesc(new.description())
2099 if ((not node)
2099 if ((not node)
2100 and newdesc == old.description()
2100 and newdesc == old.description()
2101 and user == old.user()
2101 and user == old.user()
2102 and date == old.date()
2102 and date == old.date()
2103 and pureextra == old.extra()):
2103 and pureextra == old.extra()):
2104 # nothing changed. continuing here would create a new node
2104 # nothing changed. continuing here would create a new node
2105 # anyway because of the amend_source noise.
2105 # anyway because of the amend_source noise.
2106 #
2106 #
2107 # This not what we expect from amend.
2107 # This not what we expect from amend.
2108 return old.node()
2108 return old.node()
2109
2109
2110 ph = repo.ui.config('phases', 'new-commit', phases.draft)
2110 ph = repo.ui.config('phases', 'new-commit', phases.draft)
2111 try:
2111 try:
2112 if opts.get('secret'):
2112 if opts.get('secret'):
2113 commitphase = 'secret'
2113 commitphase = 'secret'
2114 else:
2114 else:
2115 commitphase = old.phase()
2115 commitphase = old.phase()
2116 repo.ui.setconfig('phases', 'new-commit', commitphase, 'amend')
2116 repo.ui.setconfig('phases', 'new-commit', commitphase, 'amend')
2117 newid = repo.commitctx(new)
2117 newid = repo.commitctx(new)
2118 finally:
2118 finally:
2119 repo.ui.setconfig('phases', 'new-commit', ph, 'amend')
2119 repo.ui.setconfig('phases', 'new-commit', ph, 'amend')
2120 if newid != old.node():
2120 if newid != old.node():
2121 # Reroute the working copy parent to the new changeset
2121 # Reroute the working copy parent to the new changeset
2122 repo.setparents(newid, nullid)
2122 repo.setparents(newid, nullid)
2123
2123
2124 # Move bookmarks from old parent to amend commit
2124 # Move bookmarks from old parent to amend commit
2125 bms = repo.nodebookmarks(old.node())
2125 bms = repo.nodebookmarks(old.node())
2126 if bms:
2126 if bms:
2127 marks = repo._bookmarks
2127 marks = repo._bookmarks
2128 for bm in bms:
2128 for bm in bms:
2129 marks[bm] = newid
2129 marks[bm] = newid
2130 marks.write()
2130 marks.write()
2131 #commit the whole amend process
2131 #commit the whole amend process
2132 if obsolete._enabled and newid != old.node():
2132 if obsolete._enabled and newid != old.node():
2133 # mark the new changeset as successor of the rewritten one
2133 # mark the new changeset as successor of the rewritten one
2134 new = repo[newid]
2134 new = repo[newid]
2135 obs = [(old, (new,))]
2135 obs = [(old, (new,))]
2136 if node:
2136 if node:
2137 obs.append((ctx, ()))
2137 obs.append((ctx, ()))
2138
2138
2139 obsolete.createmarkers(repo, obs)
2139 obsolete.createmarkers(repo, obs)
2140 tr.close()
2140 tr.close()
2141 finally:
2141 finally:
2142 tr.release()
2142 tr.release()
2143 if (not obsolete._enabled) and newid != old.node():
2143 if (not obsolete._enabled) and newid != old.node():
2144 # Strip the intermediate commit (if there was one) and the amended
2144 # Strip the intermediate commit (if there was one) and the amended
2145 # commit
2145 # commit
2146 if node:
2146 if node:
2147 ui.note(_('stripping intermediate changeset %s\n') % ctx)
2147 ui.note(_('stripping intermediate changeset %s\n') % ctx)
2148 ui.note(_('stripping amended changeset %s\n') % old)
2148 ui.note(_('stripping amended changeset %s\n') % old)
2149 repair.strip(ui, repo, old.node(), topic='amend-backup')
2149 repair.strip(ui, repo, old.node(), topic='amend-backup')
2150 finally:
2150 finally:
2151 if newid is None:
2151 if newid is None:
2152 repo.dirstate.invalidate()
2152 repo.dirstate.invalidate()
2153 lockmod.release(lock, wlock)
2153 lockmod.release(lock, wlock)
2154 return newid
2154 return newid
2155
2155
2156 def commiteditor(repo, ctx, subs):
2156 def commiteditor(repo, ctx, subs):
2157 if ctx.description():
2157 if ctx.description():
2158 return ctx.description()
2158 return ctx.description()
2159 return commitforceeditor(repo, ctx, subs)
2159 return commitforceeditor(repo, ctx, subs)
2160
2160
2161 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None):
2161 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None):
2162 edittext = []
2162 edittext = []
2163 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
2163 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
2164 if ctx.description():
2164 if ctx.description():
2165 edittext.append(ctx.description())
2165 edittext.append(ctx.description())
2166 edittext.append("")
2166 edittext.append("")
2167 edittext.append("") # Empty line between message and comments.
2167 edittext.append("") # Empty line between message and comments.
2168 edittext.append(_("HG: Enter commit message."
2168 edittext.append(_("HG: Enter commit message."
2169 " Lines beginning with 'HG:' are removed."))
2169 " Lines beginning with 'HG:' are removed."))
2170 if extramsg:
2170 if extramsg:
2171 edittext.append("HG: %s" % extramsg)
2171 edittext.append("HG: %s" % extramsg)
2172 else:
2172 else:
2173 edittext.append(_("HG: Leave message empty to abort commit."))
2173 edittext.append(_("HG: Leave message empty to abort commit."))
2174 edittext.append("HG: --")
2174 edittext.append("HG: --")
2175 edittext.append(_("HG: user: %s") % ctx.user())
2175 edittext.append(_("HG: user: %s") % ctx.user())
2176 if ctx.p2():
2176 if ctx.p2():
2177 edittext.append(_("HG: branch merge"))
2177 edittext.append(_("HG: branch merge"))
2178 if ctx.branch():
2178 if ctx.branch():
2179 edittext.append(_("HG: branch '%s'") % ctx.branch())
2179 edittext.append(_("HG: branch '%s'") % ctx.branch())
2180 if bookmarks.iscurrent(repo):
2180 if bookmarks.iscurrent(repo):
2181 edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
2181 edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
2182 edittext.extend([_("HG: subrepo %s") % s for s in subs])
2182 edittext.extend([_("HG: subrepo %s") % s for s in subs])
2183 edittext.extend([_("HG: added %s") % f for f in added])
2183 edittext.extend([_("HG: added %s") % f for f in added])
2184 edittext.extend([_("HG: changed %s") % f for f in modified])
2184 edittext.extend([_("HG: changed %s") % f for f in modified])
2185 edittext.extend([_("HG: removed %s") % f for f in removed])
2185 edittext.extend([_("HG: removed %s") % f for f in removed])
2186 if not added and not modified and not removed:
2186 if not added and not modified and not removed:
2187 edittext.append(_("HG: no files changed"))
2187 edittext.append(_("HG: no files changed"))
2188 edittext.append("")
2188 edittext.append("")
2189 # run editor in the repository root
2189 # run editor in the repository root
2190 olddir = os.getcwd()
2190 olddir = os.getcwd()
2191 os.chdir(repo.root)
2191 os.chdir(repo.root)
2192 text = repo.ui.edit("\n".join(edittext), ctx.user(), ctx.extra())
2192 text = repo.ui.edit("\n".join(edittext), ctx.user(), ctx.extra())
2193 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2193 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2194 os.chdir(olddir)
2194 os.chdir(olddir)
2195
2195
2196 if finishdesc:
2196 if finishdesc:
2197 text = finishdesc(text)
2197 text = finishdesc(text)
2198 if not text.strip():
2198 if not text.strip():
2199 raise util.Abort(_("empty commit message"))
2199 raise util.Abort(_("empty commit message"))
2200
2200
2201 return text
2201 return text
2202
2202
2203 def commitstatus(repo, node, branch, bheads=None, opts={}):
2203 def commitstatus(repo, node, branch, bheads=None, opts={}):
2204 ctx = repo[node]
2204 ctx = repo[node]
2205 parents = ctx.parents()
2205 parents = ctx.parents()
2206
2206
2207 if (not opts.get('amend') and bheads and node not in bheads and not
2207 if (not opts.get('amend') and bheads and node not in bheads and not
2208 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2208 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2209 repo.ui.status(_('created new head\n'))
2209 repo.ui.status(_('created new head\n'))
2210 # The message is not printed for initial roots. For the other
2210 # The message is not printed for initial roots. For the other
2211 # changesets, it is printed in the following situations:
2211 # changesets, it is printed in the following situations:
2212 #
2212 #
2213 # Par column: for the 2 parents with ...
2213 # Par column: for the 2 parents with ...
2214 # N: null or no parent
2214 # N: null or no parent
2215 # B: parent is on another named branch
2215 # B: parent is on another named branch
2216 # C: parent is a regular non head changeset
2216 # C: parent is a regular non head changeset
2217 # H: parent was a branch head of the current branch
2217 # H: parent was a branch head of the current branch
2218 # Msg column: whether we print "created new head" message
2218 # Msg column: whether we print "created new head" message
2219 # In the following, it is assumed that there already exists some
2219 # In the following, it is assumed that there already exists some
2220 # initial branch heads of the current branch, otherwise nothing is
2220 # initial branch heads of the current branch, otherwise nothing is
2221 # printed anyway.
2221 # printed anyway.
2222 #
2222 #
2223 # Par Msg Comment
2223 # Par Msg Comment
2224 # N N y additional topo root
2224 # N N y additional topo root
2225 #
2225 #
2226 # B N y additional branch root
2226 # B N y additional branch root
2227 # C N y additional topo head
2227 # C N y additional topo head
2228 # H N n usual case
2228 # H N n usual case
2229 #
2229 #
2230 # B B y weird additional branch root
2230 # B B y weird additional branch root
2231 # C B y branch merge
2231 # C B y branch merge
2232 # H B n merge with named branch
2232 # H B n merge with named branch
2233 #
2233 #
2234 # C C y additional head from merge
2234 # C C y additional head from merge
2235 # C H n merge with a head
2235 # C H n merge with a head
2236 #
2236 #
2237 # H H n head merge: head count decreases
2237 # H H n head merge: head count decreases
2238
2238
2239 if not opts.get('close_branch'):
2239 if not opts.get('close_branch'):
2240 for r in parents:
2240 for r in parents:
2241 if r.closesbranch() and r.branch() == branch:
2241 if r.closesbranch() and r.branch() == branch:
2242 repo.ui.status(_('reopening closed branch head %d\n') % r)
2242 repo.ui.status(_('reopening closed branch head %d\n') % r)
2243
2243
2244 if repo.ui.debugflag:
2244 if repo.ui.debugflag:
2245 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
2245 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
2246 elif repo.ui.verbose:
2246 elif repo.ui.verbose:
2247 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
2247 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
2248
2248
2249 def revert(ui, repo, ctx, parents, *pats, **opts):
2249 def revert(ui, repo, ctx, parents, *pats, **opts):
2250 parent, p2 = parents
2250 parent, p2 = parents
2251 node = ctx.node()
2251 node = ctx.node()
2252
2252
2253 mf = ctx.manifest()
2253 mf = ctx.manifest()
2254 if node == p2:
2254 if node == p2:
2255 parent = p2
2255 parent = p2
2256 if node == parent:
2256 if node == parent:
2257 pmf = mf
2257 pmf = mf
2258 else:
2258 else:
2259 pmf = None
2259 pmf = None
2260
2260
2261 # need all matching names in dirstate and manifest of target rev,
2261 # need all matching names in dirstate and manifest of target rev,
2262 # so have to walk both. do not print errors if files exist in one
2262 # so have to walk both. do not print errors if files exist in one
2263 # but not other.
2263 # but not other.
2264
2264
2265 # `names` is a mapping for all elements in working copy and target revision
2265 # `names` is a mapping for all elements in working copy and target revision
2266 # The mapping is in the form:
2266 # The mapping is in the form:
2267 # <asb path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
2267 # <asb path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
2268 names = {}
2268 names = {}
2269
2269
2270 wlock = repo.wlock()
2270 wlock = repo.wlock()
2271 try:
2271 try:
2272 ## filling of the `names` mapping
2272 ## filling of the `names` mapping
2273 # walk dirstate to fill `names`
2273 # walk dirstate to fill `names`
2274
2274
2275 m = scmutil.match(repo[None], pats, opts)
2275 m = scmutil.match(repo[None], pats, opts)
2276 m.bad = lambda x, y: False
2276 m.bad = lambda x, y: False
2277 for abs in repo.walk(m):
2277 for abs in repo.walk(m):
2278 names[abs] = m.rel(abs), m.exact(abs)
2278 names[abs] = m.rel(abs), m.exact(abs)
2279
2279
2280 # walk target manifest to fill `names`
2280 # walk target manifest to fill `names`
2281
2281
2282 def badfn(path, msg):
2282 def badfn(path, msg):
2283 if path in names:
2283 if path in names:
2284 return
2284 return
2285 if path in ctx.substate:
2285 if path in ctx.substate:
2286 return
2286 return
2287 path_ = path + '/'
2287 path_ = path + '/'
2288 for f in names:
2288 for f in names:
2289 if f.startswith(path_):
2289 if f.startswith(path_):
2290 return
2290 return
2291 ui.warn("%s: %s\n" % (m.rel(path), msg))
2291 ui.warn("%s: %s\n" % (m.rel(path), msg))
2292
2292
2293 m = scmutil.match(ctx, pats, opts)
2293 m = scmutil.match(ctx, pats, opts)
2294 m.bad = badfn
2294 m.bad = badfn
2295 for abs in ctx.walk(m):
2295 for abs in ctx.walk(m):
2296 if abs not in names:
2296 if abs not in names:
2297 names[abs] = m.rel(abs), m.exact(abs)
2297 names[abs] = m.rel(abs), m.exact(abs)
2298
2298
2299 # get the list of subrepos that must be reverted
2299 # get the list of subrepos that must be reverted
2300 targetsubs = sorted(s for s in ctx.substate if m(s))
2300 targetsubs = sorted(s for s in ctx.substate if m(s))
2301
2301
2302 # Find status of all file in `names`. (Against working directory parent)
2302 # Find status of all file in `names`. (Against working directory parent)
2303 m = scmutil.matchfiles(repo, names)
2303 m = scmutil.matchfiles(repo, names)
2304 changes = repo.status(node1=parent, match=m)[:4]
2304 changes = repo.status(node1=parent, match=m)[:4]
2305 modified, added, removed, deleted = map(set, changes)
2305 modified, added, removed, deleted = map(set, changes)
2306
2306
2307 # if f is a rename, update `names` to also revert the source
2307 # if f is a rename, update `names` to also revert the source
2308 cwd = repo.getcwd()
2308 cwd = repo.getcwd()
2309 for f in added:
2309 for f in added:
2310 src = repo.dirstate.copied(f)
2310 src = repo.dirstate.copied(f)
2311 if src and src not in names and repo.dirstate[src] == 'r':
2311 if src and src not in names and repo.dirstate[src] == 'r':
2312 removed.add(src)
2312 removed.add(src)
2313 names[src] = (repo.pathto(src, cwd), True)
2313 names[src] = (repo.pathto(src, cwd), True)
2314
2314
2315 ## computation of the action to performs on `names` content.
2315 ## computation of the action to performs on `names` content.
2316
2316
2317 def removeforget(abs):
2317 def removeforget(abs):
2318 if repo.dirstate[abs] == 'a':
2318 if repo.dirstate[abs] == 'a':
2319 return _('forgetting %s\n')
2319 return _('forgetting %s\n')
2320 return _('removing %s\n')
2320 return _('removing %s\n')
2321
2321
2322 # action to be actually performed by revert
2322 # action to be actually performed by revert
2323 # (<list of file>, message>) tuple
2323 # (<list of file>, message>) tuple
2324 actions = {'revert': ([], _('reverting %s\n')),
2324 actions = {'revert': ([], _('reverting %s\n')),
2325 'add': ([], _('adding %s\n')),
2325 'add': ([], _('adding %s\n')),
2326 'remove': ([], removeforget),
2326 'remove': ([], removeforget),
2327 'undelete': ([], _('undeleting %s\n'))}
2327 'undelete': ([], _('undeleting %s\n'))}
2328
2328
2329 disptable = (
2329 disptable = (
2330 # dispatch table:
2330 # dispatch table:
2331 # file state
2331 # file state
2332 # action if in target manifest
2332 # action if in target manifest
2333 # action if not in target manifest
2333 # action if not in target manifest
2334 # make backup if in target manifest
2334 # make backup if in target manifest
2335 # make backup if not in target manifest
2335 # make backup if not in target manifest
2336 (modified, (actions['revert'], True),
2336 (modified, (actions['revert'], True),
2337 (actions['remove'], True)),
2337 (actions['remove'], True)),
2338 (added, (actions['revert'], True),
2338 (added, (actions['revert'], True),
2339 (actions['remove'], False)),
2339 (actions['remove'], False)),
2340 (removed, (actions['undelete'], True),
2340 (removed, (actions['undelete'], True),
2341 (None, False)),
2341 (None, False)),
2342 (deleted, (actions['revert'], False),
2342 (deleted, (actions['revert'], False),
2343 (actions['remove'], False)),
2343 (actions['remove'], False)),
2344 )
2344 )
2345
2345
2346 for abs, (rel, exact) in sorted(names.items()):
2346 for abs, (rel, exact) in sorted(names.items()):
2347 # hash on file in target manifest (or None if missing from target)
2347 # hash on file in target manifest (or None if missing from target)
2348 mfentry = mf.get(abs)
2348 mfentry = mf.get(abs)
2349 # target file to be touch on disk (relative to cwd)
2349 # target file to be touch on disk (relative to cwd)
2350 target = repo.wjoin(abs)
2350 target = repo.wjoin(abs)
2351 def handle(xlist, dobackup):
2351 def handle(xlist, dobackup):
2352 xlist[0].append(abs)
2352 xlist[0].append(abs)
2353 if (dobackup and not opts.get('no_backup') and
2353 if (dobackup and not opts.get('no_backup') and
2354 os.path.lexists(target) and
2354 os.path.lexists(target) and
2355 abs in ctx and repo[None][abs].cmp(ctx[abs])):
2355 abs in ctx and repo[None][abs].cmp(ctx[abs])):
2356 bakname = "%s.orig" % rel
2356 bakname = "%s.orig" % rel
2357 ui.note(_('saving current version of %s as %s\n') %
2357 ui.note(_('saving current version of %s as %s\n') %
2358 (rel, bakname))
2358 (rel, bakname))
2359 if not opts.get('dry_run'):
2359 if not opts.get('dry_run'):
2360 util.rename(target, bakname)
2360 util.rename(target, bakname)
2361 if ui.verbose or not exact:
2361 if ui.verbose or not exact:
2362 msg = xlist[1]
2362 msg = xlist[1]
2363 if not isinstance(msg, basestring):
2363 if not isinstance(msg, basestring):
2364 msg = msg(abs)
2364 msg = msg(abs)
2365 ui.status(msg % rel)
2365 ui.status(msg % rel)
2366 # search the entry in the dispatch table.
2366 # search the entry in the dispatch table.
2367 # if the file is in any of this sets, it was touched in the working
2367 # if the file is in any of this sets, it was touched in the working
2368 # directory parent and we are sure it needs to be reverted.
2368 # directory parent and we are sure it needs to be reverted.
2369 for table, hit, miss in disptable:
2369 for table, hit, miss in disptable:
2370 if abs not in table:
2370 if abs not in table:
2371 continue
2371 continue
2372 # file has changed in dirstate
2372 # file has changed in dirstate
2373 if mfentry:
2373 if mfentry:
2374 handle(*hit)
2374 handle(*hit)
2375 elif miss[0] is not None:
2375 elif miss[0] is not None:
2376 handle(*miss)
2376 handle(*miss)
2377 break
2377 break
2378 else:
2378 else:
2379 # Not touched in current dirstate.
2379 # Not touched in current dirstate.
2380
2380
2381 # file is unknown in parent, restore older version or ignore.
2381 # file is unknown in parent, restore older version or ignore.
2382 if abs not in repo.dirstate:
2382 if abs not in repo.dirstate:
2383 if mfentry:
2383 if mfentry:
2384 handle(actions['add'], True)
2384 handle(actions['add'], True)
2385 elif exact:
2385 elif exact:
2386 ui.warn(_('file not managed: %s\n') % rel)
2386 ui.warn(_('file not managed: %s\n') % rel)
2387 continue
2387 continue
2388
2388
2389 # parent is target, no changes mean no changes
2389 # parent is target, no changes mean no changes
2390 if node == parent:
2390 if node == parent:
2391 if exact:
2391 if exact:
2392 ui.warn(_('no changes needed to %s\n') % rel)
2392 ui.warn(_('no changes needed to %s\n') % rel)
2393 continue
2393 continue
2394 # no change in dirstate but parent and target may differ
2394 # no change in dirstate but parent and target may differ
2395 if pmf is None:
2395 if pmf is None:
2396 # only need parent manifest in this unlikely case,
2396 # only need parent manifest in this unlikely case,
2397 # so do not read by default
2397 # so do not read by default
2398 pmf = repo[parent].manifest()
2398 pmf = repo[parent].manifest()
2399 if abs in pmf and mfentry:
2399 if abs in pmf and mfentry:
2400 # if version of file is same in parent and target
2400 # if version of file is same in parent and target
2401 # manifests, do nothing
2401 # manifests, do nothing
2402 if (pmf[abs] != mfentry or
2402 if (pmf[abs] != mfentry or
2403 pmf.flags(abs) != mf.flags(abs)):
2403 pmf.flags(abs) != mf.flags(abs)):
2404 handle(actions['revert'], False)
2404 handle(actions['revert'], False)
2405 else:
2405 else:
2406 handle(actions['remove'], False)
2406 handle(actions['remove'], False)
2407
2407
2408 if not opts.get('dry_run'):
2408 if not opts.get('dry_run'):
2409 _performrevert(repo, parents, ctx, actions)
2409 _performrevert(repo, parents, ctx, actions)
2410
2410
2411 if targetsubs:
2411 if targetsubs:
2412 # Revert the subrepos on the revert list
2412 # Revert the subrepos on the revert list
2413 for sub in targetsubs:
2413 for sub in targetsubs:
2414 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
2414 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
2415 finally:
2415 finally:
2416 wlock.release()
2416 wlock.release()
2417
2417
2418 def _performrevert(repo, parents, ctx, actions):
2418 def _performrevert(repo, parents, ctx, actions):
2419 """function that actually perform all the actions computed for revert
2419 """function that actually perform all the actions computed for revert
2420
2420
2421 This is an independent function to let extension to plug in and react to
2421 This is an independent function to let extension to plug in and react to
2422 the imminent revert.
2422 the imminent revert.
2423
2423
2424 Make sure you have the working directory locked when calling this function.
2424 Make sure you have the working directory locked when calling this function.
2425 """
2425 """
2426 parent, p2 = parents
2426 parent, p2 = parents
2427 node = ctx.node()
2427 node = ctx.node()
2428 def checkout(f):
2428 def checkout(f):
2429 fc = ctx[f]
2429 fc = ctx[f]
2430 repo.wwrite(f, fc.data(), fc.flags())
2430 repo.wwrite(f, fc.data(), fc.flags())
2431
2431
2432 audit_path = pathutil.pathauditor(repo.root)
2432 audit_path = pathutil.pathauditor(repo.root)
2433 for f in actions['remove'][0]:
2433 for f in actions['remove'][0]:
2434 if repo.dirstate[f] == 'a':
2434 if repo.dirstate[f] == 'a':
2435 repo.dirstate.drop(f)
2435 repo.dirstate.drop(f)
2436 continue
2436 continue
2437 audit_path(f)
2437 audit_path(f)
2438 try:
2438 try:
2439 util.unlinkpath(repo.wjoin(f))
2439 util.unlinkpath(repo.wjoin(f))
2440 except OSError:
2440 except OSError:
2441 pass
2441 pass
2442 repo.dirstate.remove(f)
2442 repo.dirstate.remove(f)
2443
2443
2444 normal = None
2444 normal = None
2445 if node == parent:
2445 if node == parent:
2446 # We're reverting to our parent. If possible, we'd like status
2446 # We're reverting to our parent. If possible, we'd like status
2447 # to report the file as clean. We have to use normallookup for
2447 # to report the file as clean. We have to use normallookup for
2448 # merges to avoid losing information about merged/dirty files.
2448 # merges to avoid losing information about merged/dirty files.
2449 if p2 != nullid:
2449 if p2 != nullid:
2450 normal = repo.dirstate.normallookup
2450 normal = repo.dirstate.normallookup
2451 else:
2451 else:
2452 normal = repo.dirstate.normal
2452 normal = repo.dirstate.normal
2453 for f in actions['revert'][0]:
2453 for f in actions['revert'][0]:
2454 checkout(f)
2454 checkout(f)
2455 if normal:
2455 if normal:
2456 normal(f)
2456 normal(f)
2457
2457
2458 for f in actions['add'][0]:
2458 for f in actions['add'][0]:
2459 checkout(f)
2459 checkout(f)
2460 repo.dirstate.add(f)
2460 repo.dirstate.add(f)
2461
2461
2462 normal = repo.dirstate.normallookup
2462 normal = repo.dirstate.normallookup
2463 if node == parent and p2 == nullid:
2463 if node == parent and p2 == nullid:
2464 normal = repo.dirstate.normal
2464 normal = repo.dirstate.normal
2465 for f in actions['undelete'][0]:
2465 for f in actions['undelete'][0]:
2466 checkout(f)
2466 checkout(f)
2467 normal(f)
2467 normal(f)
2468
2468
2469 copied = copies.pathcopies(repo[parent], ctx)
2469 copied = copies.pathcopies(repo[parent], ctx)
2470
2470
2471 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
2471 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
2472 if f in copied:
2472 if f in copied:
2473 repo.dirstate.copy(copied[f], f)
2473 repo.dirstate.copy(copied[f], f)
2474
2474
2475 def command(table):
2475 def command(table):
2476 """Returns a function object to be used as a decorator for making commands.
2476 """Returns a function object to be used as a decorator for making commands.
2477
2477
2478 This function receives a command table as its argument. The table should
2478 This function receives a command table as its argument. The table should
2479 be a dict.
2479 be a dict.
2480
2480
2481 The returned function can be used as a decorator for adding commands
2481 The returned function can be used as a decorator for adding commands
2482 to that command table. This function accepts multiple arguments to define
2482 to that command table. This function accepts multiple arguments to define
2483 a command.
2483 a command.
2484
2484
2485 The first argument is the command name.
2485 The first argument is the command name.
2486
2486
2487 The options argument is an iterable of tuples defining command arguments.
2487 The options argument is an iterable of tuples defining command arguments.
2488 See ``mercurial.fancyopts.fancyopts()`` for the format of each tuple.
2488 See ``mercurial.fancyopts.fancyopts()`` for the format of each tuple.
2489
2489
2490 The synopsis argument defines a short, one line summary of how to use the
2490 The synopsis argument defines a short, one line summary of how to use the
2491 command. This shows up in the help output.
2491 command. This shows up in the help output.
2492
2493 The norepo argument defines whether the command does not require a
2494 local repository. Most commands operate against a repository, thus the
2495 default is False.
2492 """
2496 """
2493
2497 def cmd(name, options=(), synopsis=None, norepo=False):
2494 def cmd(name, options=(), synopsis=None):
2495 def decorator(func):
2498 def decorator(func):
2496 if synopsis:
2499 if synopsis:
2497 table[name] = func, list(options), synopsis
2500 table[name] = func, list(options), synopsis
2498 else:
2501 else:
2499 table[name] = func, list(options)
2502 table[name] = func, list(options)
2503
2504 if norepo:
2505 # Avoid import cycle.
2506 import commands
2507 commands.norepo += ' %s' % ' '.join(parsealiases(name))
2508
2500 return func
2509 return func
2501 return decorator
2510 return decorator
2502
2511
2503 return cmd
2512 return cmd
2504
2513
2505 # a list of (ui, repo, otherpeer, opts, missing) functions called by
2514 # a list of (ui, repo, otherpeer, opts, missing) functions called by
2506 # commands.outgoing. "missing" is "missing" of the result of
2515 # commands.outgoing. "missing" is "missing" of the result of
2507 # "findcommonoutgoing()"
2516 # "findcommonoutgoing()"
2508 outgoinghooks = util.hooks()
2517 outgoinghooks = util.hooks()
2509
2518
2510 # a list of (ui, repo) functions called by commands.summary
2519 # a list of (ui, repo) functions called by commands.summary
2511 summaryhooks = util.hooks()
2520 summaryhooks = util.hooks()
2512
2521
2513 # a list of (ui, repo, opts, changes) functions called by commands.summary.
2522 # a list of (ui, repo, opts, changes) functions called by commands.summary.
2514 #
2523 #
2515 # functions should return tuple of booleans below, if 'changes' is None:
2524 # functions should return tuple of booleans below, if 'changes' is None:
2516 # (whether-incomings-are-needed, whether-outgoings-are-needed)
2525 # (whether-incomings-are-needed, whether-outgoings-are-needed)
2517 #
2526 #
2518 # otherwise, 'changes' is a tuple of tuples below:
2527 # otherwise, 'changes' is a tuple of tuples below:
2519 # - (sourceurl, sourcebranch, sourcepeer, incoming)
2528 # - (sourceurl, sourcebranch, sourcepeer, incoming)
2520 # - (desturl, destbranch, destpeer, outgoing)
2529 # - (desturl, destbranch, destpeer, outgoing)
2521 summaryremotehooks = util.hooks()
2530 summaryremotehooks = util.hooks()
2522
2531
2523 # A list of state files kept by multistep operations like graft.
2532 # A list of state files kept by multistep operations like graft.
2524 # Since graft cannot be aborted, it is considered 'clearable' by update.
2533 # Since graft cannot be aborted, it is considered 'clearable' by update.
2525 # note: bisect is intentionally excluded
2534 # note: bisect is intentionally excluded
2526 # (state file, clearable, allowcommit, error, hint)
2535 # (state file, clearable, allowcommit, error, hint)
2527 unfinishedstates = [
2536 unfinishedstates = [
2528 ('graftstate', True, False, _('graft in progress'),
2537 ('graftstate', True, False, _('graft in progress'),
2529 _("use 'hg graft --continue' or 'hg update' to abort")),
2538 _("use 'hg graft --continue' or 'hg update' to abort")),
2530 ('updatestate', True, False, _('last update was interrupted'),
2539 ('updatestate', True, False, _('last update was interrupted'),
2531 _("use 'hg update' to get a consistent checkout"))
2540 _("use 'hg update' to get a consistent checkout"))
2532 ]
2541 ]
2533
2542
2534 def checkunfinished(repo, commit=False):
2543 def checkunfinished(repo, commit=False):
2535 '''Look for an unfinished multistep operation, like graft, and abort
2544 '''Look for an unfinished multistep operation, like graft, and abort
2536 if found. It's probably good to check this right before
2545 if found. It's probably good to check this right before
2537 bailifchanged().
2546 bailifchanged().
2538 '''
2547 '''
2539 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2548 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2540 if commit and allowcommit:
2549 if commit and allowcommit:
2541 continue
2550 continue
2542 if repo.vfs.exists(f):
2551 if repo.vfs.exists(f):
2543 raise util.Abort(msg, hint=hint)
2552 raise util.Abort(msg, hint=hint)
2544
2553
2545 def clearunfinished(repo):
2554 def clearunfinished(repo):
2546 '''Check for unfinished operations (as above), and clear the ones
2555 '''Check for unfinished operations (as above), and clear the ones
2547 that are clearable.
2556 that are clearable.
2548 '''
2557 '''
2549 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2558 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2550 if not clearable and repo.vfs.exists(f):
2559 if not clearable and repo.vfs.exists(f):
2551 raise util.Abort(msg, hint=hint)
2560 raise util.Abort(msg, hint=hint)
2552 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2561 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2553 if clearable and repo.vfs.exists(f):
2562 if clearable and repo.vfs.exists(f):
2554 util.unlink(repo.join(f))
2563 util.unlink(repo.join(f))
@@ -1,5987 +1,5986
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 sys
12 import sys
13 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import hg, scmutil, util, revlog, copies, error, bookmarks
14 import patch, help, encoding, templatekw, discovery
14 import patch, help, encoding, templatekw, discovery
15 import archival, changegroup, cmdutil, hbisect
15 import archival, changegroup, cmdutil, hbisect
16 import sshserver, hgweb, commandserver
16 import sshserver, hgweb, commandserver
17 from hgweb import server as hgweb_server
17 from hgweb import server as hgweb_server
18 import merge as mergemod
18 import merge as mergemod
19 import minirst, revset, fileset
19 import minirst, revset, fileset
20 import dagparser, context, simplemerge, graphmod
20 import dagparser, context, simplemerge, graphmod
21 import random
21 import random
22 import setdiscovery, treediscovery, dagutil, pvec, localrepo
22 import setdiscovery, treediscovery, dagutil, pvec, localrepo
23 import phases, obsolete, exchange
23 import phases, obsolete, exchange
24
24
25 table = {}
25 table = {}
26
26
27 command = cmdutil.command(table)
27 command = cmdutil.command(table)
28
28
29 norepo = ("clone init version help debugcommands debugcomplete"
30 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
31 " debugknown debuggetbundle debugbundle")
32 optionalrepo = ("identify paths serve config showconfig debugancestor debugdag"
33 " debugdata debugindex debugindexdot debugrevlog")
34 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
35 " remove resolve status debugwalk")
29 # common command options
36 # common command options
30
37
31 globalopts = [
38 globalopts = [
32 ('R', 'repository', '',
39 ('R', 'repository', '',
33 _('repository root directory or name of overlay bundle file'),
40 _('repository root directory or name of overlay bundle file'),
34 _('REPO')),
41 _('REPO')),
35 ('', 'cwd', '',
42 ('', 'cwd', '',
36 _('change working directory'), _('DIR')),
43 _('change working directory'), _('DIR')),
37 ('y', 'noninteractive', None,
44 ('y', 'noninteractive', None,
38 _('do not prompt, automatically pick the first choice for all prompts')),
45 _('do not prompt, automatically pick the first choice for all prompts')),
39 ('q', 'quiet', None, _('suppress output')),
46 ('q', 'quiet', None, _('suppress output')),
40 ('v', 'verbose', None, _('enable additional output')),
47 ('v', 'verbose', None, _('enable additional output')),
41 ('', 'config', [],
48 ('', 'config', [],
42 _('set/override config option (use \'section.name=value\')'),
49 _('set/override config option (use \'section.name=value\')'),
43 _('CONFIG')),
50 _('CONFIG')),
44 ('', 'debug', None, _('enable debugging output')),
51 ('', 'debug', None, _('enable debugging output')),
45 ('', 'debugger', None, _('start debugger')),
52 ('', 'debugger', None, _('start debugger')),
46 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
53 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
47 _('ENCODE')),
54 _('ENCODE')),
48 ('', 'encodingmode', encoding.encodingmode,
55 ('', 'encodingmode', encoding.encodingmode,
49 _('set the charset encoding mode'), _('MODE')),
56 _('set the charset encoding mode'), _('MODE')),
50 ('', 'traceback', None, _('always print a traceback on exception')),
57 ('', 'traceback', None, _('always print a traceback on exception')),
51 ('', 'time', None, _('time how long the command takes')),
58 ('', 'time', None, _('time how long the command takes')),
52 ('', 'profile', None, _('print command execution profile')),
59 ('', 'profile', None, _('print command execution profile')),
53 ('', 'version', None, _('output version information and exit')),
60 ('', 'version', None, _('output version information and exit')),
54 ('h', 'help', None, _('display help and exit')),
61 ('h', 'help', None, _('display help and exit')),
55 ('', 'hidden', False, _('consider hidden changesets')),
62 ('', 'hidden', False, _('consider hidden changesets')),
56 ]
63 ]
57
64
58 dryrunopts = [('n', 'dry-run', None,
65 dryrunopts = [('n', 'dry-run', None,
59 _('do not perform actions, just print output'))]
66 _('do not perform actions, just print output'))]
60
67
61 remoteopts = [
68 remoteopts = [
62 ('e', 'ssh', '',
69 ('e', 'ssh', '',
63 _('specify ssh command to use'), _('CMD')),
70 _('specify ssh command to use'), _('CMD')),
64 ('', 'remotecmd', '',
71 ('', 'remotecmd', '',
65 _('specify hg command to run on the remote side'), _('CMD')),
72 _('specify hg command to run on the remote side'), _('CMD')),
66 ('', 'insecure', None,
73 ('', 'insecure', None,
67 _('do not verify server certificate (ignoring web.cacerts config)')),
74 _('do not verify server certificate (ignoring web.cacerts config)')),
68 ]
75 ]
69
76
70 walkopts = [
77 walkopts = [
71 ('I', 'include', [],
78 ('I', 'include', [],
72 _('include names matching the given patterns'), _('PATTERN')),
79 _('include names matching the given patterns'), _('PATTERN')),
73 ('X', 'exclude', [],
80 ('X', 'exclude', [],
74 _('exclude names matching the given patterns'), _('PATTERN')),
81 _('exclude names matching the given patterns'), _('PATTERN')),
75 ]
82 ]
76
83
77 commitopts = [
84 commitopts = [
78 ('m', 'message', '',
85 ('m', 'message', '',
79 _('use text as commit message'), _('TEXT')),
86 _('use text as commit message'), _('TEXT')),
80 ('l', 'logfile', '',
87 ('l', 'logfile', '',
81 _('read commit message from file'), _('FILE')),
88 _('read commit message from file'), _('FILE')),
82 ]
89 ]
83
90
84 commitopts2 = [
91 commitopts2 = [
85 ('d', 'date', '',
92 ('d', 'date', '',
86 _('record the specified date as commit date'), _('DATE')),
93 _('record the specified date as commit date'), _('DATE')),
87 ('u', 'user', '',
94 ('u', 'user', '',
88 _('record the specified user as committer'), _('USER')),
95 _('record the specified user as committer'), _('USER')),
89 ]
96 ]
90
97
91 templateopts = [
98 templateopts = [
92 ('', 'style', '',
99 ('', 'style', '',
93 _('display using template map file (DEPRECATED)'), _('STYLE')),
100 _('display using template map file (DEPRECATED)'), _('STYLE')),
94 ('T', 'template', '',
101 ('T', 'template', '',
95 _('display with template'), _('TEMPLATE')),
102 _('display with template'), _('TEMPLATE')),
96 ]
103 ]
97
104
98 logopts = [
105 logopts = [
99 ('p', 'patch', None, _('show patch')),
106 ('p', 'patch', None, _('show patch')),
100 ('g', 'git', None, _('use git extended diff format')),
107 ('g', 'git', None, _('use git extended diff format')),
101 ('l', 'limit', '',
108 ('l', 'limit', '',
102 _('limit number of changes displayed'), _('NUM')),
109 _('limit number of changes displayed'), _('NUM')),
103 ('M', 'no-merges', None, _('do not show merges')),
110 ('M', 'no-merges', None, _('do not show merges')),
104 ('', 'stat', None, _('output diffstat-style summary of changes')),
111 ('', 'stat', None, _('output diffstat-style summary of changes')),
105 ('G', 'graph', None, _("show the revision DAG")),
112 ('G', 'graph', None, _("show the revision DAG")),
106 ] + templateopts
113 ] + templateopts
107
114
108 diffopts = [
115 diffopts = [
109 ('a', 'text', None, _('treat all files as text')),
116 ('a', 'text', None, _('treat all files as text')),
110 ('g', 'git', None, _('use git extended diff format')),
117 ('g', 'git', None, _('use git extended diff format')),
111 ('', 'nodates', None, _('omit dates from diff headers'))
118 ('', 'nodates', None, _('omit dates from diff headers'))
112 ]
119 ]
113
120
114 diffwsopts = [
121 diffwsopts = [
115 ('w', 'ignore-all-space', None,
122 ('w', 'ignore-all-space', None,
116 _('ignore white space when comparing lines')),
123 _('ignore white space when comparing lines')),
117 ('b', 'ignore-space-change', None,
124 ('b', 'ignore-space-change', None,
118 _('ignore changes in the amount of white space')),
125 _('ignore changes in the amount of white space')),
119 ('B', 'ignore-blank-lines', None,
126 ('B', 'ignore-blank-lines', None,
120 _('ignore changes whose lines are all blank')),
127 _('ignore changes whose lines are all blank')),
121 ]
128 ]
122
129
123 diffopts2 = [
130 diffopts2 = [
124 ('p', 'show-function', None, _('show which function each change is in')),
131 ('p', 'show-function', None, _('show which function each change is in')),
125 ('', 'reverse', None, _('produce a diff that undoes the changes')),
132 ('', 'reverse', None, _('produce a diff that undoes the changes')),
126 ] + diffwsopts + [
133 ] + diffwsopts + [
127 ('U', 'unified', '',
134 ('U', 'unified', '',
128 _('number of lines of context to show'), _('NUM')),
135 _('number of lines of context to show'), _('NUM')),
129 ('', 'stat', None, _('output diffstat-style summary of changes')),
136 ('', 'stat', None, _('output diffstat-style summary of changes')),
130 ]
137 ]
131
138
132 mergetoolopts = [
139 mergetoolopts = [
133 ('t', 'tool', '', _('specify merge tool')),
140 ('t', 'tool', '', _('specify merge tool')),
134 ]
141 ]
135
142
136 similarityopts = [
143 similarityopts = [
137 ('s', 'similarity', '',
144 ('s', 'similarity', '',
138 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
145 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
139 ]
146 ]
140
147
141 subrepoopts = [
148 subrepoopts = [
142 ('S', 'subrepos', None,
149 ('S', 'subrepos', None,
143 _('recurse into subrepositories'))
150 _('recurse into subrepositories'))
144 ]
151 ]
145
152
146 # Commands start here, listed alphabetically
153 # Commands start here, listed alphabetically
147
154
148 @command('^add',
155 @command('^add',
149 walkopts + subrepoopts + dryrunopts,
156 walkopts + subrepoopts + dryrunopts,
150 _('[OPTION]... [FILE]...'))
157 _('[OPTION]... [FILE]...'))
151 def add(ui, repo, *pats, **opts):
158 def add(ui, repo, *pats, **opts):
152 """add the specified files on the next commit
159 """add the specified files on the next commit
153
160
154 Schedule files to be version controlled and added to the
161 Schedule files to be version controlled and added to the
155 repository.
162 repository.
156
163
157 The files will be added to the repository at the next commit. To
164 The files will be added to the repository at the next commit. To
158 undo an add before that, see :hg:`forget`.
165 undo an add before that, see :hg:`forget`.
159
166
160 If no names are given, add all files to the repository.
167 If no names are given, add all files to the repository.
161
168
162 .. container:: verbose
169 .. container:: verbose
163
170
164 An example showing how new (unknown) files are added
171 An example showing how new (unknown) files are added
165 automatically by :hg:`add`::
172 automatically by :hg:`add`::
166
173
167 $ ls
174 $ ls
168 foo.c
175 foo.c
169 $ hg status
176 $ hg status
170 ? foo.c
177 ? foo.c
171 $ hg add
178 $ hg add
172 adding foo.c
179 adding foo.c
173 $ hg status
180 $ hg status
174 A foo.c
181 A foo.c
175
182
176 Returns 0 if all files are successfully added.
183 Returns 0 if all files are successfully added.
177 """
184 """
178
185
179 m = scmutil.match(repo[None], pats, opts)
186 m = scmutil.match(repo[None], pats, opts)
180 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
187 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
181 opts.get('subrepos'), prefix="", explicitonly=False)
188 opts.get('subrepos'), prefix="", explicitonly=False)
182 return rejected and 1 or 0
189 return rejected and 1 or 0
183
190
184 @command('addremove',
191 @command('addremove',
185 similarityopts + walkopts + dryrunopts,
192 similarityopts + walkopts + dryrunopts,
186 _('[OPTION]... [FILE]...'))
193 _('[OPTION]... [FILE]...'))
187 def addremove(ui, repo, *pats, **opts):
194 def addremove(ui, repo, *pats, **opts):
188 """add all new files, delete all missing files
195 """add all new files, delete all missing files
189
196
190 Add all new files and remove all missing files from the
197 Add all new files and remove all missing files from the
191 repository.
198 repository.
192
199
193 New files are ignored if they match any of the patterns in
200 New files are ignored if they match any of the patterns in
194 ``.hgignore``. As with add, these changes take effect at the next
201 ``.hgignore``. As with add, these changes take effect at the next
195 commit.
202 commit.
196
203
197 Use the -s/--similarity option to detect renamed files. This
204 Use the -s/--similarity option to detect renamed files. This
198 option takes a percentage between 0 (disabled) and 100 (files must
205 option takes a percentage between 0 (disabled) and 100 (files must
199 be identical) as its parameter. With a parameter greater than 0,
206 be identical) as its parameter. With a parameter greater than 0,
200 this compares every removed file with every added file and records
207 this compares every removed file with every added file and records
201 those similar enough as renames. Detecting renamed files this way
208 those similar enough as renames. Detecting renamed files this way
202 can be expensive. After using this option, :hg:`status -C` can be
209 can be expensive. After using this option, :hg:`status -C` can be
203 used to check which files were identified as moved or renamed. If
210 used to check which files were identified as moved or renamed. If
204 not specified, -s/--similarity defaults to 100 and only renames of
211 not specified, -s/--similarity defaults to 100 and only renames of
205 identical files are detected.
212 identical files are detected.
206
213
207 Returns 0 if all files are successfully added.
214 Returns 0 if all files are successfully added.
208 """
215 """
209 try:
216 try:
210 sim = float(opts.get('similarity') or 100)
217 sim = float(opts.get('similarity') or 100)
211 except ValueError:
218 except ValueError:
212 raise util.Abort(_('similarity must be a number'))
219 raise util.Abort(_('similarity must be a number'))
213 if sim < 0 or sim > 100:
220 if sim < 0 or sim > 100:
214 raise util.Abort(_('similarity must be between 0 and 100'))
221 raise util.Abort(_('similarity must be between 0 and 100'))
215 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
222 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
216
223
217 @command('^annotate|blame',
224 @command('^annotate|blame',
218 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
225 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
219 ('', 'follow', None,
226 ('', 'follow', None,
220 _('follow copies/renames and list the filename (DEPRECATED)')),
227 _('follow copies/renames and list the filename (DEPRECATED)')),
221 ('', 'no-follow', None, _("don't follow copies and renames")),
228 ('', 'no-follow', None, _("don't follow copies and renames")),
222 ('a', 'text', None, _('treat all files as text')),
229 ('a', 'text', None, _('treat all files as text')),
223 ('u', 'user', None, _('list the author (long with -v)')),
230 ('u', 'user', None, _('list the author (long with -v)')),
224 ('f', 'file', None, _('list the filename')),
231 ('f', 'file', None, _('list the filename')),
225 ('d', 'date', None, _('list the date (short with -q)')),
232 ('d', 'date', None, _('list the date (short with -q)')),
226 ('n', 'number', None, _('list the revision number (default)')),
233 ('n', 'number', None, _('list the revision number (default)')),
227 ('c', 'changeset', None, _('list the changeset')),
234 ('c', 'changeset', None, _('list the changeset')),
228 ('l', 'line-number', None, _('show line number at the first appearance'))
235 ('l', 'line-number', None, _('show line number at the first appearance'))
229 ] + diffwsopts + walkopts,
236 ] + diffwsopts + walkopts,
230 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
237 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
231 def annotate(ui, repo, *pats, **opts):
238 def annotate(ui, repo, *pats, **opts):
232 """show changeset information by line for each file
239 """show changeset information by line for each file
233
240
234 List changes in files, showing the revision id responsible for
241 List changes in files, showing the revision id responsible for
235 each line
242 each line
236
243
237 This command is useful for discovering when a change was made and
244 This command is useful for discovering when a change was made and
238 by whom.
245 by whom.
239
246
240 Without the -a/--text option, annotate will avoid processing files
247 Without the -a/--text option, annotate will avoid processing files
241 it detects as binary. With -a, annotate will annotate the file
248 it detects as binary. With -a, annotate will annotate the file
242 anyway, although the results will probably be neither useful
249 anyway, although the results will probably be neither useful
243 nor desirable.
250 nor desirable.
244
251
245 Returns 0 on success.
252 Returns 0 on success.
246 """
253 """
247 if opts.get('follow'):
254 if opts.get('follow'):
248 # --follow is deprecated and now just an alias for -f/--file
255 # --follow is deprecated and now just an alias for -f/--file
249 # to mimic the behavior of Mercurial before version 1.5
256 # to mimic the behavior of Mercurial before version 1.5
250 opts['file'] = True
257 opts['file'] = True
251
258
252 datefunc = ui.quiet and util.shortdate or util.datestr
259 datefunc = ui.quiet and util.shortdate or util.datestr
253 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
260 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
254
261
255 if not pats:
262 if not pats:
256 raise util.Abort(_('at least one filename or pattern is required'))
263 raise util.Abort(_('at least one filename or pattern is required'))
257
264
258 hexfn = ui.debugflag and hex or short
265 hexfn = ui.debugflag and hex or short
259
266
260 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
267 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
261 ('number', ' ', lambda x: str(x[0].rev())),
268 ('number', ' ', lambda x: str(x[0].rev())),
262 ('changeset', ' ', lambda x: hexfn(x[0].node())),
269 ('changeset', ' ', lambda x: hexfn(x[0].node())),
263 ('date', ' ', getdate),
270 ('date', ' ', getdate),
264 ('file', ' ', lambda x: x[0].path()),
271 ('file', ' ', lambda x: x[0].path()),
265 ('line_number', ':', lambda x: str(x[1])),
272 ('line_number', ':', lambda x: str(x[1])),
266 ]
273 ]
267
274
268 if (not opts.get('user') and not opts.get('changeset')
275 if (not opts.get('user') and not opts.get('changeset')
269 and not opts.get('date') and not opts.get('file')):
276 and not opts.get('date') and not opts.get('file')):
270 opts['number'] = True
277 opts['number'] = True
271
278
272 linenumber = opts.get('line_number') is not None
279 linenumber = opts.get('line_number') is not None
273 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
280 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
274 raise util.Abort(_('at least one of -n/-c is required for -l'))
281 raise util.Abort(_('at least one of -n/-c is required for -l'))
275
282
276 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
283 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
277 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
284 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
278
285
279 def bad(x, y):
286 def bad(x, y):
280 raise util.Abort("%s: %s" % (x, y))
287 raise util.Abort("%s: %s" % (x, y))
281
288
282 ctx = scmutil.revsingle(repo, opts.get('rev'))
289 ctx = scmutil.revsingle(repo, opts.get('rev'))
283 m = scmutil.match(ctx, pats, opts)
290 m = scmutil.match(ctx, pats, opts)
284 m.bad = bad
291 m.bad = bad
285 follow = not opts.get('no_follow')
292 follow = not opts.get('no_follow')
286 diffopts = patch.diffopts(ui, opts, section='annotate')
293 diffopts = patch.diffopts(ui, opts, section='annotate')
287 for abs in ctx.walk(m):
294 for abs in ctx.walk(m):
288 fctx = ctx[abs]
295 fctx = ctx[abs]
289 if not opts.get('text') and util.binary(fctx.data()):
296 if not opts.get('text') and util.binary(fctx.data()):
290 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
297 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
291 continue
298 continue
292
299
293 lines = fctx.annotate(follow=follow, linenumber=linenumber,
300 lines = fctx.annotate(follow=follow, linenumber=linenumber,
294 diffopts=diffopts)
301 diffopts=diffopts)
295 pieces = []
302 pieces = []
296
303
297 for f, sep in funcmap:
304 for f, sep in funcmap:
298 l = [f(n) for n, dummy in lines]
305 l = [f(n) for n, dummy in lines]
299 if l:
306 if l:
300 sized = [(x, encoding.colwidth(x)) for x in l]
307 sized = [(x, encoding.colwidth(x)) for x in l]
301 ml = max([w for x, w in sized])
308 ml = max([w for x, w in sized])
302 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
309 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
303 for x, w in sized])
310 for x, w in sized])
304
311
305 if pieces:
312 if pieces:
306 for p, l in zip(zip(*pieces), lines):
313 for p, l in zip(zip(*pieces), lines):
307 ui.write("%s: %s" % ("".join(p), l[1]))
314 ui.write("%s: %s" % ("".join(p), l[1]))
308
315
309 if lines and not lines[-1][1].endswith('\n'):
316 if lines and not lines[-1][1].endswith('\n'):
310 ui.write('\n')
317 ui.write('\n')
311
318
312 @command('archive',
319 @command('archive',
313 [('', 'no-decode', None, _('do not pass files through decoders')),
320 [('', 'no-decode', None, _('do not pass files through decoders')),
314 ('p', 'prefix', '', _('directory prefix for files in archive'),
321 ('p', 'prefix', '', _('directory prefix for files in archive'),
315 _('PREFIX')),
322 _('PREFIX')),
316 ('r', 'rev', '', _('revision to distribute'), _('REV')),
323 ('r', 'rev', '', _('revision to distribute'), _('REV')),
317 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
324 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
318 ] + subrepoopts + walkopts,
325 ] + subrepoopts + walkopts,
319 _('[OPTION]... DEST'))
326 _('[OPTION]... DEST'))
320 def archive(ui, repo, dest, **opts):
327 def archive(ui, repo, dest, **opts):
321 '''create an unversioned archive of a repository revision
328 '''create an unversioned archive of a repository revision
322
329
323 By default, the revision used is the parent of the working
330 By default, the revision used is the parent of the working
324 directory; use -r/--rev to specify a different revision.
331 directory; use -r/--rev to specify a different revision.
325
332
326 The archive type is automatically detected based on file
333 The archive type is automatically detected based on file
327 extension (or override using -t/--type).
334 extension (or override using -t/--type).
328
335
329 .. container:: verbose
336 .. container:: verbose
330
337
331 Examples:
338 Examples:
332
339
333 - create a zip file containing the 1.0 release::
340 - create a zip file containing the 1.0 release::
334
341
335 hg archive -r 1.0 project-1.0.zip
342 hg archive -r 1.0 project-1.0.zip
336
343
337 - create a tarball excluding .hg files::
344 - create a tarball excluding .hg files::
338
345
339 hg archive project.tar.gz -X ".hg*"
346 hg archive project.tar.gz -X ".hg*"
340
347
341 Valid types are:
348 Valid types are:
342
349
343 :``files``: a directory full of files (default)
350 :``files``: a directory full of files (default)
344 :``tar``: tar archive, uncompressed
351 :``tar``: tar archive, uncompressed
345 :``tbz2``: tar archive, compressed using bzip2
352 :``tbz2``: tar archive, compressed using bzip2
346 :``tgz``: tar archive, compressed using gzip
353 :``tgz``: tar archive, compressed using gzip
347 :``uzip``: zip archive, uncompressed
354 :``uzip``: zip archive, uncompressed
348 :``zip``: zip archive, compressed using deflate
355 :``zip``: zip archive, compressed using deflate
349
356
350 The exact name of the destination archive or directory is given
357 The exact name of the destination archive or directory is given
351 using a format string; see :hg:`help export` for details.
358 using a format string; see :hg:`help export` for details.
352
359
353 Each member added to an archive file has a directory prefix
360 Each member added to an archive file has a directory prefix
354 prepended. Use -p/--prefix to specify a format string for the
361 prepended. Use -p/--prefix to specify a format string for the
355 prefix. The default is the basename of the archive, with suffixes
362 prefix. The default is the basename of the archive, with suffixes
356 removed.
363 removed.
357
364
358 Returns 0 on success.
365 Returns 0 on success.
359 '''
366 '''
360
367
361 ctx = scmutil.revsingle(repo, opts.get('rev'))
368 ctx = scmutil.revsingle(repo, opts.get('rev'))
362 if not ctx:
369 if not ctx:
363 raise util.Abort(_('no working directory: please specify a revision'))
370 raise util.Abort(_('no working directory: please specify a revision'))
364 node = ctx.node()
371 node = ctx.node()
365 dest = cmdutil.makefilename(repo, dest, node)
372 dest = cmdutil.makefilename(repo, dest, node)
366 if os.path.realpath(dest) == repo.root:
373 if os.path.realpath(dest) == repo.root:
367 raise util.Abort(_('repository root cannot be destination'))
374 raise util.Abort(_('repository root cannot be destination'))
368
375
369 kind = opts.get('type') or archival.guesskind(dest) or 'files'
376 kind = opts.get('type') or archival.guesskind(dest) or 'files'
370 prefix = opts.get('prefix')
377 prefix = opts.get('prefix')
371
378
372 if dest == '-':
379 if dest == '-':
373 if kind == 'files':
380 if kind == 'files':
374 raise util.Abort(_('cannot archive plain files to stdout'))
381 raise util.Abort(_('cannot archive plain files to stdout'))
375 dest = cmdutil.makefileobj(repo, dest)
382 dest = cmdutil.makefileobj(repo, dest)
376 if not prefix:
383 if not prefix:
377 prefix = os.path.basename(repo.root) + '-%h'
384 prefix = os.path.basename(repo.root) + '-%h'
378
385
379 prefix = cmdutil.makefilename(repo, prefix, node)
386 prefix = cmdutil.makefilename(repo, prefix, node)
380 matchfn = scmutil.match(ctx, [], opts)
387 matchfn = scmutil.match(ctx, [], opts)
381 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
388 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
382 matchfn, prefix, subrepos=opts.get('subrepos'))
389 matchfn, prefix, subrepos=opts.get('subrepos'))
383
390
384 @command('backout',
391 @command('backout',
385 [('', 'merge', None, _('merge with old dirstate parent after backout')),
392 [('', 'merge', None, _('merge with old dirstate parent after backout')),
386 ('', 'parent', '',
393 ('', 'parent', '',
387 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
394 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
388 ('r', 'rev', '', _('revision to backout'), _('REV')),
395 ('r', 'rev', '', _('revision to backout'), _('REV')),
389 ('e', 'edit', False, _('invoke editor on commit messages')),
396 ('e', 'edit', False, _('invoke editor on commit messages')),
390 ] + mergetoolopts + walkopts + commitopts + commitopts2,
397 ] + mergetoolopts + walkopts + commitopts + commitopts2,
391 _('[OPTION]... [-r] REV'))
398 _('[OPTION]... [-r] REV'))
392 def backout(ui, repo, node=None, rev=None, **opts):
399 def backout(ui, repo, node=None, rev=None, **opts):
393 '''reverse effect of earlier changeset
400 '''reverse effect of earlier changeset
394
401
395 Prepare a new changeset with the effect of REV undone in the
402 Prepare a new changeset with the effect of REV undone in the
396 current working directory.
403 current working directory.
397
404
398 If REV is the parent of the working directory, then this new changeset
405 If REV is the parent of the working directory, then this new changeset
399 is committed automatically. Otherwise, hg needs to merge the
406 is committed automatically. Otherwise, hg needs to merge the
400 changes and the merged result is left uncommitted.
407 changes and the merged result is left uncommitted.
401
408
402 .. note::
409 .. note::
403
410
404 backout cannot be used to fix either an unwanted or
411 backout cannot be used to fix either an unwanted or
405 incorrect merge.
412 incorrect merge.
406
413
407 .. container:: verbose
414 .. container:: verbose
408
415
409 By default, the pending changeset will have one parent,
416 By default, the pending changeset will have one parent,
410 maintaining a linear history. With --merge, the pending
417 maintaining a linear history. With --merge, the pending
411 changeset will instead have two parents: the old parent of the
418 changeset will instead have two parents: the old parent of the
412 working directory and a new child of REV that simply undoes REV.
419 working directory and a new child of REV that simply undoes REV.
413
420
414 Before version 1.7, the behavior without --merge was equivalent
421 Before version 1.7, the behavior without --merge was equivalent
415 to specifying --merge followed by :hg:`update --clean .` to
422 to specifying --merge followed by :hg:`update --clean .` to
416 cancel the merge and leave the child of REV as a head to be
423 cancel the merge and leave the child of REV as a head to be
417 merged separately.
424 merged separately.
418
425
419 See :hg:`help dates` for a list of formats valid for -d/--date.
426 See :hg:`help dates` for a list of formats valid for -d/--date.
420
427
421 Returns 0 on success, 1 if nothing to backout or there are unresolved
428 Returns 0 on success, 1 if nothing to backout or there are unresolved
422 files.
429 files.
423 '''
430 '''
424 if rev and node:
431 if rev and node:
425 raise util.Abort(_("please specify just one revision"))
432 raise util.Abort(_("please specify just one revision"))
426
433
427 if not rev:
434 if not rev:
428 rev = node
435 rev = node
429
436
430 if not rev:
437 if not rev:
431 raise util.Abort(_("please specify a revision to backout"))
438 raise util.Abort(_("please specify a revision to backout"))
432
439
433 date = opts.get('date')
440 date = opts.get('date')
434 if date:
441 if date:
435 opts['date'] = util.parsedate(date)
442 opts['date'] = util.parsedate(date)
436
443
437 cmdutil.checkunfinished(repo)
444 cmdutil.checkunfinished(repo)
438 cmdutil.bailifchanged(repo)
445 cmdutil.bailifchanged(repo)
439 node = scmutil.revsingle(repo, rev).node()
446 node = scmutil.revsingle(repo, rev).node()
440
447
441 op1, op2 = repo.dirstate.parents()
448 op1, op2 = repo.dirstate.parents()
442 if node not in repo.changelog.commonancestorsheads(op1, node):
449 if node not in repo.changelog.commonancestorsheads(op1, node):
443 raise util.Abort(_('cannot backout change that is not an ancestor'))
450 raise util.Abort(_('cannot backout change that is not an ancestor'))
444
451
445 p1, p2 = repo.changelog.parents(node)
452 p1, p2 = repo.changelog.parents(node)
446 if p1 == nullid:
453 if p1 == nullid:
447 raise util.Abort(_('cannot backout a change with no parents'))
454 raise util.Abort(_('cannot backout a change with no parents'))
448 if p2 != nullid:
455 if p2 != nullid:
449 if not opts.get('parent'):
456 if not opts.get('parent'):
450 raise util.Abort(_('cannot backout a merge changeset'))
457 raise util.Abort(_('cannot backout a merge changeset'))
451 p = repo.lookup(opts['parent'])
458 p = repo.lookup(opts['parent'])
452 if p not in (p1, p2):
459 if p not in (p1, p2):
453 raise util.Abort(_('%s is not a parent of %s') %
460 raise util.Abort(_('%s is not a parent of %s') %
454 (short(p), short(node)))
461 (short(p), short(node)))
455 parent = p
462 parent = p
456 else:
463 else:
457 if opts.get('parent'):
464 if opts.get('parent'):
458 raise util.Abort(_('cannot use --parent on non-merge changeset'))
465 raise util.Abort(_('cannot use --parent on non-merge changeset'))
459 parent = p1
466 parent = p1
460
467
461 # the backout should appear on the same branch
468 # the backout should appear on the same branch
462 wlock = repo.wlock()
469 wlock = repo.wlock()
463 try:
470 try:
464 branch = repo.dirstate.branch()
471 branch = repo.dirstate.branch()
465 bheads = repo.branchheads(branch)
472 bheads = repo.branchheads(branch)
466 rctx = scmutil.revsingle(repo, hex(parent))
473 rctx = scmutil.revsingle(repo, hex(parent))
467 if not opts.get('merge') and op1 != node:
474 if not opts.get('merge') and op1 != node:
468 try:
475 try:
469 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
476 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
470 'backout')
477 'backout')
471 stats = mergemod.update(repo, parent, True, True, False,
478 stats = mergemod.update(repo, parent, True, True, False,
472 node, False)
479 node, False)
473 repo.setparents(op1, op2)
480 repo.setparents(op1, op2)
474 hg._showstats(repo, stats)
481 hg._showstats(repo, stats)
475 if stats[3]:
482 if stats[3]:
476 repo.ui.status(_("use 'hg resolve' to retry unresolved "
483 repo.ui.status(_("use 'hg resolve' to retry unresolved "
477 "file merges\n"))
484 "file merges\n"))
478 else:
485 else:
479 msg = _("changeset %s backed out, "
486 msg = _("changeset %s backed out, "
480 "don't forget to commit.\n")
487 "don't forget to commit.\n")
481 ui.status(msg % short(node))
488 ui.status(msg % short(node))
482 return stats[3] > 0
489 return stats[3] > 0
483 finally:
490 finally:
484 ui.setconfig('ui', 'forcemerge', '', '')
491 ui.setconfig('ui', 'forcemerge', '', '')
485 else:
492 else:
486 hg.clean(repo, node, show_stats=False)
493 hg.clean(repo, node, show_stats=False)
487 repo.dirstate.setbranch(branch)
494 repo.dirstate.setbranch(branch)
488 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
495 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
489
496
490
497
491 def commitfunc(ui, repo, message, match, opts):
498 def commitfunc(ui, repo, message, match, opts):
492 e = cmdutil.getcommiteditor(**opts)
499 e = cmdutil.getcommiteditor(**opts)
493 if not message:
500 if not message:
494 # we don't translate commit messages
501 # we don't translate commit messages
495 message = "Backed out changeset %s" % short(node)
502 message = "Backed out changeset %s" % short(node)
496 e = cmdutil.getcommiteditor(edit=True)
503 e = cmdutil.getcommiteditor(edit=True)
497 return repo.commit(message, opts.get('user'), opts.get('date'),
504 return repo.commit(message, opts.get('user'), opts.get('date'),
498 match, editor=e)
505 match, editor=e)
499 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
506 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
500 if not newnode:
507 if not newnode:
501 ui.status(_("nothing changed\n"))
508 ui.status(_("nothing changed\n"))
502 return 1
509 return 1
503 cmdutil.commitstatus(repo, newnode, branch, bheads)
510 cmdutil.commitstatus(repo, newnode, branch, bheads)
504
511
505 def nice(node):
512 def nice(node):
506 return '%d:%s' % (repo.changelog.rev(node), short(node))
513 return '%d:%s' % (repo.changelog.rev(node), short(node))
507 ui.status(_('changeset %s backs out changeset %s\n') %
514 ui.status(_('changeset %s backs out changeset %s\n') %
508 (nice(repo.changelog.tip()), nice(node)))
515 (nice(repo.changelog.tip()), nice(node)))
509 if opts.get('merge') and op1 != node:
516 if opts.get('merge') and op1 != node:
510 hg.clean(repo, op1, show_stats=False)
517 hg.clean(repo, op1, show_stats=False)
511 ui.status(_('merging with changeset %s\n')
518 ui.status(_('merging with changeset %s\n')
512 % nice(repo.changelog.tip()))
519 % nice(repo.changelog.tip()))
513 try:
520 try:
514 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
521 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
515 'backout')
522 'backout')
516 return hg.merge(repo, hex(repo.changelog.tip()))
523 return hg.merge(repo, hex(repo.changelog.tip()))
517 finally:
524 finally:
518 ui.setconfig('ui', 'forcemerge', '', '')
525 ui.setconfig('ui', 'forcemerge', '', '')
519 finally:
526 finally:
520 wlock.release()
527 wlock.release()
521 return 0
528 return 0
522
529
523 @command('bisect',
530 @command('bisect',
524 [('r', 'reset', False, _('reset bisect state')),
531 [('r', 'reset', False, _('reset bisect state')),
525 ('g', 'good', False, _('mark changeset good')),
532 ('g', 'good', False, _('mark changeset good')),
526 ('b', 'bad', False, _('mark changeset bad')),
533 ('b', 'bad', False, _('mark changeset bad')),
527 ('s', 'skip', False, _('skip testing changeset')),
534 ('s', 'skip', False, _('skip testing changeset')),
528 ('e', 'extend', False, _('extend the bisect range')),
535 ('e', 'extend', False, _('extend the bisect range')),
529 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
536 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
530 ('U', 'noupdate', False, _('do not update to target'))],
537 ('U', 'noupdate', False, _('do not update to target'))],
531 _("[-gbsr] [-U] [-c CMD] [REV]"))
538 _("[-gbsr] [-U] [-c CMD] [REV]"))
532 def bisect(ui, repo, rev=None, extra=None, command=None,
539 def bisect(ui, repo, rev=None, extra=None, command=None,
533 reset=None, good=None, bad=None, skip=None, extend=None,
540 reset=None, good=None, bad=None, skip=None, extend=None,
534 noupdate=None):
541 noupdate=None):
535 """subdivision search of changesets
542 """subdivision search of changesets
536
543
537 This command helps to find changesets which introduce problems. To
544 This command helps to find changesets which introduce problems. To
538 use, mark the earliest changeset you know exhibits the problem as
545 use, mark the earliest changeset you know exhibits the problem as
539 bad, then mark the latest changeset which is free from the problem
546 bad, then mark the latest changeset which is free from the problem
540 as good. Bisect will update your working directory to a revision
547 as good. Bisect will update your working directory to a revision
541 for testing (unless the -U/--noupdate option is specified). Once
548 for testing (unless the -U/--noupdate option is specified). Once
542 you have performed tests, mark the working directory as good or
549 you have performed tests, mark the working directory as good or
543 bad, and bisect will either update to another candidate changeset
550 bad, and bisect will either update to another candidate changeset
544 or announce that it has found the bad revision.
551 or announce that it has found the bad revision.
545
552
546 As a shortcut, you can also use the revision argument to mark a
553 As a shortcut, you can also use the revision argument to mark a
547 revision as good or bad without checking it out first.
554 revision as good or bad without checking it out first.
548
555
549 If you supply a command, it will be used for automatic bisection.
556 If you supply a command, it will be used for automatic bisection.
550 The environment variable HG_NODE will contain the ID of the
557 The environment variable HG_NODE will contain the ID of the
551 changeset being tested. The exit status of the command will be
558 changeset being tested. The exit status of the command will be
552 used to mark revisions as good or bad: status 0 means good, 125
559 used to mark revisions as good or bad: status 0 means good, 125
553 means to skip the revision, 127 (command not found) will abort the
560 means to skip the revision, 127 (command not found) will abort the
554 bisection, and any other non-zero exit status means the revision
561 bisection, and any other non-zero exit status means the revision
555 is bad.
562 is bad.
556
563
557 .. container:: verbose
564 .. container:: verbose
558
565
559 Some examples:
566 Some examples:
560
567
561 - start a bisection with known bad revision 34, and good revision 12::
568 - start a bisection with known bad revision 34, and good revision 12::
562
569
563 hg bisect --bad 34
570 hg bisect --bad 34
564 hg bisect --good 12
571 hg bisect --good 12
565
572
566 - advance the current bisection by marking current revision as good or
573 - advance the current bisection by marking current revision as good or
567 bad::
574 bad::
568
575
569 hg bisect --good
576 hg bisect --good
570 hg bisect --bad
577 hg bisect --bad
571
578
572 - mark the current revision, or a known revision, to be skipped (e.g. if
579 - mark the current revision, or a known revision, to be skipped (e.g. if
573 that revision is not usable because of another issue)::
580 that revision is not usable because of another issue)::
574
581
575 hg bisect --skip
582 hg bisect --skip
576 hg bisect --skip 23
583 hg bisect --skip 23
577
584
578 - skip all revisions that do not touch directories ``foo`` or ``bar``::
585 - skip all revisions that do not touch directories ``foo`` or ``bar``::
579
586
580 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
587 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
581
588
582 - forget the current bisection::
589 - forget the current bisection::
583
590
584 hg bisect --reset
591 hg bisect --reset
585
592
586 - use 'make && make tests' to automatically find the first broken
593 - use 'make && make tests' to automatically find the first broken
587 revision::
594 revision::
588
595
589 hg bisect --reset
596 hg bisect --reset
590 hg bisect --bad 34
597 hg bisect --bad 34
591 hg bisect --good 12
598 hg bisect --good 12
592 hg bisect --command "make && make tests"
599 hg bisect --command "make && make tests"
593
600
594 - see all changesets whose states are already known in the current
601 - see all changesets whose states are already known in the current
595 bisection::
602 bisection::
596
603
597 hg log -r "bisect(pruned)"
604 hg log -r "bisect(pruned)"
598
605
599 - see the changeset currently being bisected (especially useful
606 - see the changeset currently being bisected (especially useful
600 if running with -U/--noupdate)::
607 if running with -U/--noupdate)::
601
608
602 hg log -r "bisect(current)"
609 hg log -r "bisect(current)"
603
610
604 - see all changesets that took part in the current bisection::
611 - see all changesets that took part in the current bisection::
605
612
606 hg log -r "bisect(range)"
613 hg log -r "bisect(range)"
607
614
608 - you can even get a nice graph::
615 - you can even get a nice graph::
609
616
610 hg log --graph -r "bisect(range)"
617 hg log --graph -r "bisect(range)"
611
618
612 See :hg:`help revsets` for more about the `bisect()` keyword.
619 See :hg:`help revsets` for more about the `bisect()` keyword.
613
620
614 Returns 0 on success.
621 Returns 0 on success.
615 """
622 """
616 def extendbisectrange(nodes, good):
623 def extendbisectrange(nodes, good):
617 # bisect is incomplete when it ends on a merge node and
624 # bisect is incomplete when it ends on a merge node and
618 # one of the parent was not checked.
625 # one of the parent was not checked.
619 parents = repo[nodes[0]].parents()
626 parents = repo[nodes[0]].parents()
620 if len(parents) > 1:
627 if len(parents) > 1:
621 side = good and state['bad'] or state['good']
628 side = good and state['bad'] or state['good']
622 num = len(set(i.node() for i in parents) & set(side))
629 num = len(set(i.node() for i in parents) & set(side))
623 if num == 1:
630 if num == 1:
624 return parents[0].ancestor(parents[1])
631 return parents[0].ancestor(parents[1])
625 return None
632 return None
626
633
627 def print_result(nodes, good):
634 def print_result(nodes, good):
628 displayer = cmdutil.show_changeset(ui, repo, {})
635 displayer = cmdutil.show_changeset(ui, repo, {})
629 if len(nodes) == 1:
636 if len(nodes) == 1:
630 # narrowed it down to a single revision
637 # narrowed it down to a single revision
631 if good:
638 if good:
632 ui.write(_("The first good revision is:\n"))
639 ui.write(_("The first good revision is:\n"))
633 else:
640 else:
634 ui.write(_("The first bad revision is:\n"))
641 ui.write(_("The first bad revision is:\n"))
635 displayer.show(repo[nodes[0]])
642 displayer.show(repo[nodes[0]])
636 extendnode = extendbisectrange(nodes, good)
643 extendnode = extendbisectrange(nodes, good)
637 if extendnode is not None:
644 if extendnode is not None:
638 ui.write(_('Not all ancestors of this changeset have been'
645 ui.write(_('Not all ancestors of this changeset have been'
639 ' checked.\nUse bisect --extend to continue the '
646 ' checked.\nUse bisect --extend to continue the '
640 'bisection from\nthe common ancestor, %s.\n')
647 'bisection from\nthe common ancestor, %s.\n')
641 % extendnode)
648 % extendnode)
642 else:
649 else:
643 # multiple possible revisions
650 # multiple possible revisions
644 if good:
651 if good:
645 ui.write(_("Due to skipped revisions, the first "
652 ui.write(_("Due to skipped revisions, the first "
646 "good revision could be any of:\n"))
653 "good revision could be any of:\n"))
647 else:
654 else:
648 ui.write(_("Due to skipped revisions, the first "
655 ui.write(_("Due to skipped revisions, the first "
649 "bad revision could be any of:\n"))
656 "bad revision could be any of:\n"))
650 for n in nodes:
657 for n in nodes:
651 displayer.show(repo[n])
658 displayer.show(repo[n])
652 displayer.close()
659 displayer.close()
653
660
654 def check_state(state, interactive=True):
661 def check_state(state, interactive=True):
655 if not state['good'] or not state['bad']:
662 if not state['good'] or not state['bad']:
656 if (good or bad or skip or reset) and interactive:
663 if (good or bad or skip or reset) and interactive:
657 return
664 return
658 if not state['good']:
665 if not state['good']:
659 raise util.Abort(_('cannot bisect (no known good revisions)'))
666 raise util.Abort(_('cannot bisect (no known good revisions)'))
660 else:
667 else:
661 raise util.Abort(_('cannot bisect (no known bad revisions)'))
668 raise util.Abort(_('cannot bisect (no known bad revisions)'))
662 return True
669 return True
663
670
664 # backward compatibility
671 # backward compatibility
665 if rev in "good bad reset init".split():
672 if rev in "good bad reset init".split():
666 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
673 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
667 cmd, rev, extra = rev, extra, None
674 cmd, rev, extra = rev, extra, None
668 if cmd == "good":
675 if cmd == "good":
669 good = True
676 good = True
670 elif cmd == "bad":
677 elif cmd == "bad":
671 bad = True
678 bad = True
672 else:
679 else:
673 reset = True
680 reset = True
674 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
681 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
675 raise util.Abort(_('incompatible arguments'))
682 raise util.Abort(_('incompatible arguments'))
676
683
677 cmdutil.checkunfinished(repo)
684 cmdutil.checkunfinished(repo)
678
685
679 if reset:
686 if reset:
680 p = repo.join("bisect.state")
687 p = repo.join("bisect.state")
681 if os.path.exists(p):
688 if os.path.exists(p):
682 os.unlink(p)
689 os.unlink(p)
683 return
690 return
684
691
685 state = hbisect.load_state(repo)
692 state = hbisect.load_state(repo)
686
693
687 if command:
694 if command:
688 changesets = 1
695 changesets = 1
689 if noupdate:
696 if noupdate:
690 try:
697 try:
691 node = state['current'][0]
698 node = state['current'][0]
692 except LookupError:
699 except LookupError:
693 raise util.Abort(_('current bisect revision is unknown - '
700 raise util.Abort(_('current bisect revision is unknown - '
694 'start a new bisect to fix'))
701 'start a new bisect to fix'))
695 else:
702 else:
696 node, p2 = repo.dirstate.parents()
703 node, p2 = repo.dirstate.parents()
697 if p2 != nullid:
704 if p2 != nullid:
698 raise util.Abort(_('current bisect revision is a merge'))
705 raise util.Abort(_('current bisect revision is a merge'))
699 try:
706 try:
700 while changesets:
707 while changesets:
701 # update state
708 # update state
702 state['current'] = [node]
709 state['current'] = [node]
703 hbisect.save_state(repo, state)
710 hbisect.save_state(repo, state)
704 status = util.system(command,
711 status = util.system(command,
705 environ={'HG_NODE': hex(node)},
712 environ={'HG_NODE': hex(node)},
706 out=ui.fout)
713 out=ui.fout)
707 if status == 125:
714 if status == 125:
708 transition = "skip"
715 transition = "skip"
709 elif status == 0:
716 elif status == 0:
710 transition = "good"
717 transition = "good"
711 # status < 0 means process was killed
718 # status < 0 means process was killed
712 elif status == 127:
719 elif status == 127:
713 raise util.Abort(_("failed to execute %s") % command)
720 raise util.Abort(_("failed to execute %s") % command)
714 elif status < 0:
721 elif status < 0:
715 raise util.Abort(_("%s killed") % command)
722 raise util.Abort(_("%s killed") % command)
716 else:
723 else:
717 transition = "bad"
724 transition = "bad"
718 ctx = scmutil.revsingle(repo, rev, node)
725 ctx = scmutil.revsingle(repo, rev, node)
719 rev = None # clear for future iterations
726 rev = None # clear for future iterations
720 state[transition].append(ctx.node())
727 state[transition].append(ctx.node())
721 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
728 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
722 check_state(state, interactive=False)
729 check_state(state, interactive=False)
723 # bisect
730 # bisect
724 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
731 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
725 # update to next check
732 # update to next check
726 node = nodes[0]
733 node = nodes[0]
727 if not noupdate:
734 if not noupdate:
728 cmdutil.bailifchanged(repo)
735 cmdutil.bailifchanged(repo)
729 hg.clean(repo, node, show_stats=False)
736 hg.clean(repo, node, show_stats=False)
730 finally:
737 finally:
731 state['current'] = [node]
738 state['current'] = [node]
732 hbisect.save_state(repo, state)
739 hbisect.save_state(repo, state)
733 print_result(nodes, bgood)
740 print_result(nodes, bgood)
734 return
741 return
735
742
736 # update state
743 # update state
737
744
738 if rev:
745 if rev:
739 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
746 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
740 else:
747 else:
741 nodes = [repo.lookup('.')]
748 nodes = [repo.lookup('.')]
742
749
743 if good or bad or skip:
750 if good or bad or skip:
744 if good:
751 if good:
745 state['good'] += nodes
752 state['good'] += nodes
746 elif bad:
753 elif bad:
747 state['bad'] += nodes
754 state['bad'] += nodes
748 elif skip:
755 elif skip:
749 state['skip'] += nodes
756 state['skip'] += nodes
750 hbisect.save_state(repo, state)
757 hbisect.save_state(repo, state)
751
758
752 if not check_state(state):
759 if not check_state(state):
753 return
760 return
754
761
755 # actually bisect
762 # actually bisect
756 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
763 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
757 if extend:
764 if extend:
758 if not changesets:
765 if not changesets:
759 extendnode = extendbisectrange(nodes, good)
766 extendnode = extendbisectrange(nodes, good)
760 if extendnode is not None:
767 if extendnode is not None:
761 ui.write(_("Extending search to changeset %d:%s\n")
768 ui.write(_("Extending search to changeset %d:%s\n")
762 % (extendnode.rev(), extendnode))
769 % (extendnode.rev(), extendnode))
763 state['current'] = [extendnode.node()]
770 state['current'] = [extendnode.node()]
764 hbisect.save_state(repo, state)
771 hbisect.save_state(repo, state)
765 if noupdate:
772 if noupdate:
766 return
773 return
767 cmdutil.bailifchanged(repo)
774 cmdutil.bailifchanged(repo)
768 return hg.clean(repo, extendnode.node())
775 return hg.clean(repo, extendnode.node())
769 raise util.Abort(_("nothing to extend"))
776 raise util.Abort(_("nothing to extend"))
770
777
771 if changesets == 0:
778 if changesets == 0:
772 print_result(nodes, good)
779 print_result(nodes, good)
773 else:
780 else:
774 assert len(nodes) == 1 # only a single node can be tested next
781 assert len(nodes) == 1 # only a single node can be tested next
775 node = nodes[0]
782 node = nodes[0]
776 # compute the approximate number of remaining tests
783 # compute the approximate number of remaining tests
777 tests, size = 0, 2
784 tests, size = 0, 2
778 while size <= changesets:
785 while size <= changesets:
779 tests, size = tests + 1, size * 2
786 tests, size = tests + 1, size * 2
780 rev = repo.changelog.rev(node)
787 rev = repo.changelog.rev(node)
781 ui.write(_("Testing changeset %d:%s "
788 ui.write(_("Testing changeset %d:%s "
782 "(%d changesets remaining, ~%d tests)\n")
789 "(%d changesets remaining, ~%d tests)\n")
783 % (rev, short(node), changesets, tests))
790 % (rev, short(node), changesets, tests))
784 state['current'] = [node]
791 state['current'] = [node]
785 hbisect.save_state(repo, state)
792 hbisect.save_state(repo, state)
786 if not noupdate:
793 if not noupdate:
787 cmdutil.bailifchanged(repo)
794 cmdutil.bailifchanged(repo)
788 return hg.clean(repo, node)
795 return hg.clean(repo, node)
789
796
790 @command('bookmarks|bookmark',
797 @command('bookmarks|bookmark',
791 [('f', 'force', False, _('force')),
798 [('f', 'force', False, _('force')),
792 ('r', 'rev', '', _('revision'), _('REV')),
799 ('r', 'rev', '', _('revision'), _('REV')),
793 ('d', 'delete', False, _('delete a given bookmark')),
800 ('d', 'delete', False, _('delete a given bookmark')),
794 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
801 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
795 ('i', 'inactive', False, _('mark a bookmark inactive'))],
802 ('i', 'inactive', False, _('mark a bookmark inactive'))],
796 _('hg bookmarks [OPTIONS]... [NAME]...'))
803 _('hg bookmarks [OPTIONS]... [NAME]...'))
797 def bookmark(ui, repo, *names, **opts):
804 def bookmark(ui, repo, *names, **opts):
798 '''create a new bookmark or list existing bookmarks
805 '''create a new bookmark or list existing bookmarks
799
806
800 Bookmarks are labels on changesets to help track lines of development.
807 Bookmarks are labels on changesets to help track lines of development.
801 Bookmarks are unversioned and can be moved, renamed and deleted.
808 Bookmarks are unversioned and can be moved, renamed and deleted.
802 Deleting or moving a bookmark has no effect on the associated changesets.
809 Deleting or moving a bookmark has no effect on the associated changesets.
803
810
804 Creating or updating to a bookmark causes it to be marked as 'active'.
811 Creating or updating to a bookmark causes it to be marked as 'active'.
805 Active bookmarks are indicated with a '*'.
812 Active bookmarks are indicated with a '*'.
806 When a commit is made, an active bookmark will advance to the new commit.
813 When a commit is made, an active bookmark will advance to the new commit.
807 A plain :hg:`update` will also advance an active bookmark, if possible.
814 A plain :hg:`update` will also advance an active bookmark, if possible.
808 Updating away from a bookmark will cause it to be deactivated.
815 Updating away from a bookmark will cause it to be deactivated.
809
816
810 Bookmarks can be pushed and pulled between repositories (see
817 Bookmarks can be pushed and pulled between repositories (see
811 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
818 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
812 diverged, a new 'divergent bookmark' of the form 'name@path' will
819 diverged, a new 'divergent bookmark' of the form 'name@path' will
813 be created. Using :hg:'merge' will resolve the divergence.
820 be created. Using :hg:'merge' will resolve the divergence.
814
821
815 A bookmark named '@' has the special property that :hg:`clone` will
822 A bookmark named '@' has the special property that :hg:`clone` will
816 check it out by default if it exists.
823 check it out by default if it exists.
817
824
818 .. container:: verbose
825 .. container:: verbose
819
826
820 Examples:
827 Examples:
821
828
822 - create an active bookmark for a new line of development::
829 - create an active bookmark for a new line of development::
823
830
824 hg book new-feature
831 hg book new-feature
825
832
826 - create an inactive bookmark as a place marker::
833 - create an inactive bookmark as a place marker::
827
834
828 hg book -i reviewed
835 hg book -i reviewed
829
836
830 - create an inactive bookmark on another changeset::
837 - create an inactive bookmark on another changeset::
831
838
832 hg book -r .^ tested
839 hg book -r .^ tested
833
840
834 - move the '@' bookmark from another branch::
841 - move the '@' bookmark from another branch::
835
842
836 hg book -f @
843 hg book -f @
837 '''
844 '''
838 force = opts.get('force')
845 force = opts.get('force')
839 rev = opts.get('rev')
846 rev = opts.get('rev')
840 delete = opts.get('delete')
847 delete = opts.get('delete')
841 rename = opts.get('rename')
848 rename = opts.get('rename')
842 inactive = opts.get('inactive')
849 inactive = opts.get('inactive')
843
850
844 def checkformat(mark):
851 def checkformat(mark):
845 mark = mark.strip()
852 mark = mark.strip()
846 if not mark:
853 if not mark:
847 raise util.Abort(_("bookmark names cannot consist entirely of "
854 raise util.Abort(_("bookmark names cannot consist entirely of "
848 "whitespace"))
855 "whitespace"))
849 scmutil.checknewlabel(repo, mark, 'bookmark')
856 scmutil.checknewlabel(repo, mark, 'bookmark')
850 return mark
857 return mark
851
858
852 def checkconflict(repo, mark, cur, force=False, target=None):
859 def checkconflict(repo, mark, cur, force=False, target=None):
853 if mark in marks and not force:
860 if mark in marks and not force:
854 if target:
861 if target:
855 if marks[mark] == target and target == cur:
862 if marks[mark] == target and target == cur:
856 # re-activating a bookmark
863 # re-activating a bookmark
857 return
864 return
858 anc = repo.changelog.ancestors([repo[target].rev()])
865 anc = repo.changelog.ancestors([repo[target].rev()])
859 bmctx = repo[marks[mark]]
866 bmctx = repo[marks[mark]]
860 divs = [repo[b].node() for b in marks
867 divs = [repo[b].node() for b in marks
861 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
868 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
862
869
863 # allow resolving a single divergent bookmark even if moving
870 # allow resolving a single divergent bookmark even if moving
864 # the bookmark across branches when a revision is specified
871 # the bookmark across branches when a revision is specified
865 # that contains a divergent bookmark
872 # that contains a divergent bookmark
866 if bmctx.rev() not in anc and target in divs:
873 if bmctx.rev() not in anc and target in divs:
867 bookmarks.deletedivergent(repo, [target], mark)
874 bookmarks.deletedivergent(repo, [target], mark)
868 return
875 return
869
876
870 deletefrom = [b for b in divs
877 deletefrom = [b for b in divs
871 if repo[b].rev() in anc or b == target]
878 if repo[b].rev() in anc or b == target]
872 bookmarks.deletedivergent(repo, deletefrom, mark)
879 bookmarks.deletedivergent(repo, deletefrom, mark)
873 if bookmarks.validdest(repo, bmctx, repo[target]):
880 if bookmarks.validdest(repo, bmctx, repo[target]):
874 ui.status(_("moving bookmark '%s' forward from %s\n") %
881 ui.status(_("moving bookmark '%s' forward from %s\n") %
875 (mark, short(bmctx.node())))
882 (mark, short(bmctx.node())))
876 return
883 return
877 raise util.Abort(_("bookmark '%s' already exists "
884 raise util.Abort(_("bookmark '%s' already exists "
878 "(use -f to force)") % mark)
885 "(use -f to force)") % mark)
879 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
886 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
880 and not force):
887 and not force):
881 raise util.Abort(
888 raise util.Abort(
882 _("a bookmark cannot have the name of an existing branch"))
889 _("a bookmark cannot have the name of an existing branch"))
883
890
884 if delete and rename:
891 if delete and rename:
885 raise util.Abort(_("--delete and --rename are incompatible"))
892 raise util.Abort(_("--delete and --rename are incompatible"))
886 if delete and rev:
893 if delete and rev:
887 raise util.Abort(_("--rev is incompatible with --delete"))
894 raise util.Abort(_("--rev is incompatible with --delete"))
888 if rename and rev:
895 if rename and rev:
889 raise util.Abort(_("--rev is incompatible with --rename"))
896 raise util.Abort(_("--rev is incompatible with --rename"))
890 if not names and (delete or rev):
897 if not names and (delete or rev):
891 raise util.Abort(_("bookmark name required"))
898 raise util.Abort(_("bookmark name required"))
892
899
893 if delete or rename or names or inactive:
900 if delete or rename or names or inactive:
894 wlock = repo.wlock()
901 wlock = repo.wlock()
895 try:
902 try:
896 cur = repo.changectx('.').node()
903 cur = repo.changectx('.').node()
897 marks = repo._bookmarks
904 marks = repo._bookmarks
898 if delete:
905 if delete:
899 for mark in names:
906 for mark in names:
900 if mark not in marks:
907 if mark not in marks:
901 raise util.Abort(_("bookmark '%s' does not exist") %
908 raise util.Abort(_("bookmark '%s' does not exist") %
902 mark)
909 mark)
903 if mark == repo._bookmarkcurrent:
910 if mark == repo._bookmarkcurrent:
904 bookmarks.unsetcurrent(repo)
911 bookmarks.unsetcurrent(repo)
905 del marks[mark]
912 del marks[mark]
906 marks.write()
913 marks.write()
907
914
908 elif rename:
915 elif rename:
909 if not names:
916 if not names:
910 raise util.Abort(_("new bookmark name required"))
917 raise util.Abort(_("new bookmark name required"))
911 elif len(names) > 1:
918 elif len(names) > 1:
912 raise util.Abort(_("only one new bookmark name allowed"))
919 raise util.Abort(_("only one new bookmark name allowed"))
913 mark = checkformat(names[0])
920 mark = checkformat(names[0])
914 if rename not in marks:
921 if rename not in marks:
915 raise util.Abort(_("bookmark '%s' does not exist") % rename)
922 raise util.Abort(_("bookmark '%s' does not exist") % rename)
916 checkconflict(repo, mark, cur, force)
923 checkconflict(repo, mark, cur, force)
917 marks[mark] = marks[rename]
924 marks[mark] = marks[rename]
918 if repo._bookmarkcurrent == rename and not inactive:
925 if repo._bookmarkcurrent == rename and not inactive:
919 bookmarks.setcurrent(repo, mark)
926 bookmarks.setcurrent(repo, mark)
920 del marks[rename]
927 del marks[rename]
921 marks.write()
928 marks.write()
922
929
923 elif names:
930 elif names:
924 newact = None
931 newact = None
925 for mark in names:
932 for mark in names:
926 mark = checkformat(mark)
933 mark = checkformat(mark)
927 if newact is None:
934 if newact is None:
928 newact = mark
935 newact = mark
929 if inactive and mark == repo._bookmarkcurrent:
936 if inactive and mark == repo._bookmarkcurrent:
930 bookmarks.unsetcurrent(repo)
937 bookmarks.unsetcurrent(repo)
931 return
938 return
932 tgt = cur
939 tgt = cur
933 if rev:
940 if rev:
934 tgt = scmutil.revsingle(repo, rev).node()
941 tgt = scmutil.revsingle(repo, rev).node()
935 checkconflict(repo, mark, cur, force, tgt)
942 checkconflict(repo, mark, cur, force, tgt)
936 marks[mark] = tgt
943 marks[mark] = tgt
937 if not inactive and cur == marks[newact] and not rev:
944 if not inactive and cur == marks[newact] and not rev:
938 bookmarks.setcurrent(repo, newact)
945 bookmarks.setcurrent(repo, newact)
939 elif cur != tgt and newact == repo._bookmarkcurrent:
946 elif cur != tgt and newact == repo._bookmarkcurrent:
940 bookmarks.unsetcurrent(repo)
947 bookmarks.unsetcurrent(repo)
941 marks.write()
948 marks.write()
942
949
943 elif inactive:
950 elif inactive:
944 if len(marks) == 0:
951 if len(marks) == 0:
945 ui.status(_("no bookmarks set\n"))
952 ui.status(_("no bookmarks set\n"))
946 elif not repo._bookmarkcurrent:
953 elif not repo._bookmarkcurrent:
947 ui.status(_("no active bookmark\n"))
954 ui.status(_("no active bookmark\n"))
948 else:
955 else:
949 bookmarks.unsetcurrent(repo)
956 bookmarks.unsetcurrent(repo)
950 finally:
957 finally:
951 wlock.release()
958 wlock.release()
952 else: # show bookmarks
959 else: # show bookmarks
953 hexfn = ui.debugflag and hex or short
960 hexfn = ui.debugflag and hex or short
954 marks = repo._bookmarks
961 marks = repo._bookmarks
955 if len(marks) == 0:
962 if len(marks) == 0:
956 ui.status(_("no bookmarks set\n"))
963 ui.status(_("no bookmarks set\n"))
957 else:
964 else:
958 for bmark, n in sorted(marks.iteritems()):
965 for bmark, n in sorted(marks.iteritems()):
959 current = repo._bookmarkcurrent
966 current = repo._bookmarkcurrent
960 if bmark == current:
967 if bmark == current:
961 prefix, label = '*', 'bookmarks.current'
968 prefix, label = '*', 'bookmarks.current'
962 else:
969 else:
963 prefix, label = ' ', ''
970 prefix, label = ' ', ''
964
971
965 if ui.quiet:
972 if ui.quiet:
966 ui.write("%s\n" % bmark, label=label)
973 ui.write("%s\n" % bmark, label=label)
967 else:
974 else:
968 pad = " " * (25 - encoding.colwidth(bmark))
975 pad = " " * (25 - encoding.colwidth(bmark))
969 ui.write(" %s %s%s %d:%s\n" % (
976 ui.write(" %s %s%s %d:%s\n" % (
970 prefix, bmark, pad, repo.changelog.rev(n), hexfn(n)),
977 prefix, bmark, pad, repo.changelog.rev(n), hexfn(n)),
971 label=label)
978 label=label)
972
979
973 @command('branch',
980 @command('branch',
974 [('f', 'force', None,
981 [('f', 'force', None,
975 _('set branch name even if it shadows an existing branch')),
982 _('set branch name even if it shadows an existing branch')),
976 ('C', 'clean', None, _('reset branch name to parent branch name'))],
983 ('C', 'clean', None, _('reset branch name to parent branch name'))],
977 _('[-fC] [NAME]'))
984 _('[-fC] [NAME]'))
978 def branch(ui, repo, label=None, **opts):
985 def branch(ui, repo, label=None, **opts):
979 """set or show the current branch name
986 """set or show the current branch name
980
987
981 .. note::
988 .. note::
982
989
983 Branch names are permanent and global. Use :hg:`bookmark` to create a
990 Branch names are permanent and global. Use :hg:`bookmark` to create a
984 light-weight bookmark instead. See :hg:`help glossary` for more
991 light-weight bookmark instead. See :hg:`help glossary` for more
985 information about named branches and bookmarks.
992 information about named branches and bookmarks.
986
993
987 With no argument, show the current branch name. With one argument,
994 With no argument, show the current branch name. With one argument,
988 set the working directory branch name (the branch will not exist
995 set the working directory branch name (the branch will not exist
989 in the repository until the next commit). Standard practice
996 in the repository until the next commit). Standard practice
990 recommends that primary development take place on the 'default'
997 recommends that primary development take place on the 'default'
991 branch.
998 branch.
992
999
993 Unless -f/--force is specified, branch will not let you set a
1000 Unless -f/--force is specified, branch will not let you set a
994 branch name that already exists, even if it's inactive.
1001 branch name that already exists, even if it's inactive.
995
1002
996 Use -C/--clean to reset the working directory branch to that of
1003 Use -C/--clean to reset the working directory branch to that of
997 the parent of the working directory, negating a previous branch
1004 the parent of the working directory, negating a previous branch
998 change.
1005 change.
999
1006
1000 Use the command :hg:`update` to switch to an existing branch. Use
1007 Use the command :hg:`update` to switch to an existing branch. Use
1001 :hg:`commit --close-branch` to mark this branch as closed.
1008 :hg:`commit --close-branch` to mark this branch as closed.
1002
1009
1003 Returns 0 on success.
1010 Returns 0 on success.
1004 """
1011 """
1005 if label:
1012 if label:
1006 label = label.strip()
1013 label = label.strip()
1007
1014
1008 if not opts.get('clean') and not label:
1015 if not opts.get('clean') and not label:
1009 ui.write("%s\n" % repo.dirstate.branch())
1016 ui.write("%s\n" % repo.dirstate.branch())
1010 return
1017 return
1011
1018
1012 wlock = repo.wlock()
1019 wlock = repo.wlock()
1013 try:
1020 try:
1014 if opts.get('clean'):
1021 if opts.get('clean'):
1015 label = repo[None].p1().branch()
1022 label = repo[None].p1().branch()
1016 repo.dirstate.setbranch(label)
1023 repo.dirstate.setbranch(label)
1017 ui.status(_('reset working directory to branch %s\n') % label)
1024 ui.status(_('reset working directory to branch %s\n') % label)
1018 elif label:
1025 elif label:
1019 if not opts.get('force') and label in repo.branchmap():
1026 if not opts.get('force') and label in repo.branchmap():
1020 if label not in [p.branch() for p in repo.parents()]:
1027 if label not in [p.branch() for p in repo.parents()]:
1021 raise util.Abort(_('a branch of the same name already'
1028 raise util.Abort(_('a branch of the same name already'
1022 ' exists'),
1029 ' exists'),
1023 # i18n: "it" refers to an existing branch
1030 # i18n: "it" refers to an existing branch
1024 hint=_("use 'hg update' to switch to it"))
1031 hint=_("use 'hg update' to switch to it"))
1025 scmutil.checknewlabel(repo, label, 'branch')
1032 scmutil.checknewlabel(repo, label, 'branch')
1026 repo.dirstate.setbranch(label)
1033 repo.dirstate.setbranch(label)
1027 ui.status(_('marked working directory as branch %s\n') % label)
1034 ui.status(_('marked working directory as branch %s\n') % label)
1028 ui.status(_('(branches are permanent and global, '
1035 ui.status(_('(branches are permanent and global, '
1029 'did you want a bookmark?)\n'))
1036 'did you want a bookmark?)\n'))
1030 finally:
1037 finally:
1031 wlock.release()
1038 wlock.release()
1032
1039
1033 @command('branches',
1040 @command('branches',
1034 [('a', 'active', False, _('show only branches that have unmerged heads')),
1041 [('a', 'active', False, _('show only branches that have unmerged heads')),
1035 ('c', 'closed', False, _('show normal and closed branches'))],
1042 ('c', 'closed', False, _('show normal and closed branches'))],
1036 _('[-ac]'))
1043 _('[-ac]'))
1037 def branches(ui, repo, active=False, closed=False):
1044 def branches(ui, repo, active=False, closed=False):
1038 """list repository named branches
1045 """list repository named branches
1039
1046
1040 List the repository's named branches, indicating which ones are
1047 List the repository's named branches, indicating which ones are
1041 inactive. If -c/--closed is specified, also list branches which have
1048 inactive. If -c/--closed is specified, also list branches which have
1042 been marked closed (see :hg:`commit --close-branch`).
1049 been marked closed (see :hg:`commit --close-branch`).
1043
1050
1044 If -a/--active is specified, only show active branches. A branch
1051 If -a/--active is specified, only show active branches. A branch
1045 is considered active if it contains repository heads.
1052 is considered active if it contains repository heads.
1046
1053
1047 Use the command :hg:`update` to switch to an existing branch.
1054 Use the command :hg:`update` to switch to an existing branch.
1048
1055
1049 Returns 0.
1056 Returns 0.
1050 """
1057 """
1051
1058
1052 hexfunc = ui.debugflag and hex or short
1059 hexfunc = ui.debugflag and hex or short
1053
1060
1054 allheads = set(repo.heads())
1061 allheads = set(repo.heads())
1055 branches = []
1062 branches = []
1056 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1063 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1057 isactive = not isclosed and bool(set(heads) & allheads)
1064 isactive = not isclosed and bool(set(heads) & allheads)
1058 branches.append((tag, repo[tip], isactive, not isclosed))
1065 branches.append((tag, repo[tip], isactive, not isclosed))
1059 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1066 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1060 reverse=True)
1067 reverse=True)
1061
1068
1062 for tag, ctx, isactive, isopen in branches:
1069 for tag, ctx, isactive, isopen in branches:
1063 if (not active) or isactive:
1070 if (not active) or isactive:
1064 if isactive:
1071 if isactive:
1065 label = 'branches.active'
1072 label = 'branches.active'
1066 notice = ''
1073 notice = ''
1067 elif not isopen:
1074 elif not isopen:
1068 if not closed:
1075 if not closed:
1069 continue
1076 continue
1070 label = 'branches.closed'
1077 label = 'branches.closed'
1071 notice = _(' (closed)')
1078 notice = _(' (closed)')
1072 else:
1079 else:
1073 label = 'branches.inactive'
1080 label = 'branches.inactive'
1074 notice = _(' (inactive)')
1081 notice = _(' (inactive)')
1075 if tag == repo.dirstate.branch():
1082 if tag == repo.dirstate.branch():
1076 label = 'branches.current'
1083 label = 'branches.current'
1077 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(tag))
1084 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(tag))
1078 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1085 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1079 'log.changeset changeset.%s' % ctx.phasestr())
1086 'log.changeset changeset.%s' % ctx.phasestr())
1080 labeledtag = ui.label(tag, label)
1087 labeledtag = ui.label(tag, label)
1081 if ui.quiet:
1088 if ui.quiet:
1082 ui.write("%s\n" % labeledtag)
1089 ui.write("%s\n" % labeledtag)
1083 else:
1090 else:
1084 ui.write("%s %s%s\n" % (labeledtag, rev, notice))
1091 ui.write("%s %s%s\n" % (labeledtag, rev, notice))
1085
1092
1086 @command('bundle',
1093 @command('bundle',
1087 [('f', 'force', None, _('run even when the destination is unrelated')),
1094 [('f', 'force', None, _('run even when the destination is unrelated')),
1088 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1095 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1089 _('REV')),
1096 _('REV')),
1090 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1097 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1091 _('BRANCH')),
1098 _('BRANCH')),
1092 ('', 'base', [],
1099 ('', 'base', [],
1093 _('a base changeset assumed to be available at the destination'),
1100 _('a base changeset assumed to be available at the destination'),
1094 _('REV')),
1101 _('REV')),
1095 ('a', 'all', None, _('bundle all changesets in the repository')),
1102 ('a', 'all', None, _('bundle all changesets in the repository')),
1096 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1103 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1097 ] + remoteopts,
1104 ] + remoteopts,
1098 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1105 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1099 def bundle(ui, repo, fname, dest=None, **opts):
1106 def bundle(ui, repo, fname, dest=None, **opts):
1100 """create a changegroup file
1107 """create a changegroup file
1101
1108
1102 Generate a compressed changegroup file collecting changesets not
1109 Generate a compressed changegroup file collecting changesets not
1103 known to be in another repository.
1110 known to be in another repository.
1104
1111
1105 If you omit the destination repository, then hg assumes the
1112 If you omit the destination repository, then hg assumes the
1106 destination will have all the nodes you specify with --base
1113 destination will have all the nodes you specify with --base
1107 parameters. To create a bundle containing all changesets, use
1114 parameters. To create a bundle containing all changesets, use
1108 -a/--all (or --base null).
1115 -a/--all (or --base null).
1109
1116
1110 You can change compression method with the -t/--type option.
1117 You can change compression method with the -t/--type option.
1111 The available compression methods are: none, bzip2, and
1118 The available compression methods are: none, bzip2, and
1112 gzip (by default, bundles are compressed using bzip2).
1119 gzip (by default, bundles are compressed using bzip2).
1113
1120
1114 The bundle file can then be transferred using conventional means
1121 The bundle file can then be transferred using conventional means
1115 and applied to another repository with the unbundle or pull
1122 and applied to another repository with the unbundle or pull
1116 command. This is useful when direct push and pull are not
1123 command. This is useful when direct push and pull are not
1117 available or when exporting an entire repository is undesirable.
1124 available or when exporting an entire repository is undesirable.
1118
1125
1119 Applying bundles preserves all changeset contents including
1126 Applying bundles preserves all changeset contents including
1120 permissions, copy/rename information, and revision history.
1127 permissions, copy/rename information, and revision history.
1121
1128
1122 Returns 0 on success, 1 if no changes found.
1129 Returns 0 on success, 1 if no changes found.
1123 """
1130 """
1124 revs = None
1131 revs = None
1125 if 'rev' in opts:
1132 if 'rev' in opts:
1126 revs = scmutil.revrange(repo, opts['rev'])
1133 revs = scmutil.revrange(repo, opts['rev'])
1127
1134
1128 bundletype = opts.get('type', 'bzip2').lower()
1135 bundletype = opts.get('type', 'bzip2').lower()
1129 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1136 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1130 bundletype = btypes.get(bundletype)
1137 bundletype = btypes.get(bundletype)
1131 if bundletype not in changegroup.bundletypes:
1138 if bundletype not in changegroup.bundletypes:
1132 raise util.Abort(_('unknown bundle type specified with --type'))
1139 raise util.Abort(_('unknown bundle type specified with --type'))
1133
1140
1134 if opts.get('all'):
1141 if opts.get('all'):
1135 base = ['null']
1142 base = ['null']
1136 else:
1143 else:
1137 base = scmutil.revrange(repo, opts.get('base'))
1144 base = scmutil.revrange(repo, opts.get('base'))
1138 # TODO: get desired bundlecaps from command line.
1145 # TODO: get desired bundlecaps from command line.
1139 bundlecaps = None
1146 bundlecaps = None
1140 if base:
1147 if base:
1141 if dest:
1148 if dest:
1142 raise util.Abort(_("--base is incompatible with specifying "
1149 raise util.Abort(_("--base is incompatible with specifying "
1143 "a destination"))
1150 "a destination"))
1144 common = [repo.lookup(rev) for rev in base]
1151 common = [repo.lookup(rev) for rev in base]
1145 heads = revs and map(repo.lookup, revs) or revs
1152 heads = revs and map(repo.lookup, revs) or revs
1146 cg = changegroup.getbundle(repo, 'bundle', heads=heads, common=common,
1153 cg = changegroup.getbundle(repo, 'bundle', heads=heads, common=common,
1147 bundlecaps=bundlecaps)
1154 bundlecaps=bundlecaps)
1148 outgoing = None
1155 outgoing = None
1149 else:
1156 else:
1150 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1157 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1151 dest, branches = hg.parseurl(dest, opts.get('branch'))
1158 dest, branches = hg.parseurl(dest, opts.get('branch'))
1152 other = hg.peer(repo, opts, dest)
1159 other = hg.peer(repo, opts, dest)
1153 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1160 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1154 heads = revs and map(repo.lookup, revs) or revs
1161 heads = revs and map(repo.lookup, revs) or revs
1155 outgoing = discovery.findcommonoutgoing(repo, other,
1162 outgoing = discovery.findcommonoutgoing(repo, other,
1156 onlyheads=heads,
1163 onlyheads=heads,
1157 force=opts.get('force'),
1164 force=opts.get('force'),
1158 portable=True)
1165 portable=True)
1159 cg = changegroup.getlocalbundle(repo, 'bundle', outgoing, bundlecaps)
1166 cg = changegroup.getlocalbundle(repo, 'bundle', outgoing, bundlecaps)
1160 if not cg:
1167 if not cg:
1161 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1168 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1162 return 1
1169 return 1
1163
1170
1164 changegroup.writebundle(cg, fname, bundletype)
1171 changegroup.writebundle(cg, fname, bundletype)
1165
1172
1166 @command('cat',
1173 @command('cat',
1167 [('o', 'output', '',
1174 [('o', 'output', '',
1168 _('print output to file with formatted name'), _('FORMAT')),
1175 _('print output to file with formatted name'), _('FORMAT')),
1169 ('r', 'rev', '', _('print the given revision'), _('REV')),
1176 ('r', 'rev', '', _('print the given revision'), _('REV')),
1170 ('', 'decode', None, _('apply any matching decode filter')),
1177 ('', 'decode', None, _('apply any matching decode filter')),
1171 ] + walkopts,
1178 ] + walkopts,
1172 _('[OPTION]... FILE...'))
1179 _('[OPTION]... FILE...'))
1173 def cat(ui, repo, file1, *pats, **opts):
1180 def cat(ui, repo, file1, *pats, **opts):
1174 """output the current or given revision of files
1181 """output the current or given revision of files
1175
1182
1176 Print the specified files as they were at the given revision. If
1183 Print the specified files as they were at the given revision. If
1177 no revision is given, the parent of the working directory is used.
1184 no revision is given, the parent of the working directory is used.
1178
1185
1179 Output may be to a file, in which case the name of the file is
1186 Output may be to a file, in which case the name of the file is
1180 given using a format string. The formatting rules as follows:
1187 given using a format string. The formatting rules as follows:
1181
1188
1182 :``%%``: literal "%" character
1189 :``%%``: literal "%" character
1183 :``%s``: basename of file being printed
1190 :``%s``: basename of file being printed
1184 :``%d``: dirname of file being printed, or '.' if in repository root
1191 :``%d``: dirname of file being printed, or '.' if in repository root
1185 :``%p``: root-relative path name of file being printed
1192 :``%p``: root-relative path name of file being printed
1186 :``%H``: changeset hash (40 hexadecimal digits)
1193 :``%H``: changeset hash (40 hexadecimal digits)
1187 :``%R``: changeset revision number
1194 :``%R``: changeset revision number
1188 :``%h``: short-form changeset hash (12 hexadecimal digits)
1195 :``%h``: short-form changeset hash (12 hexadecimal digits)
1189 :``%r``: zero-padded changeset revision number
1196 :``%r``: zero-padded changeset revision number
1190 :``%b``: basename of the exporting repository
1197 :``%b``: basename of the exporting repository
1191
1198
1192 Returns 0 on success.
1199 Returns 0 on success.
1193 """
1200 """
1194 ctx = scmutil.revsingle(repo, opts.get('rev'))
1201 ctx = scmutil.revsingle(repo, opts.get('rev'))
1195 m = scmutil.match(ctx, (file1,) + pats, opts)
1202 m = scmutil.match(ctx, (file1,) + pats, opts)
1196
1203
1197 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1204 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1198
1205
1199 @command('^clone',
1206 @command('^clone',
1200 [('U', 'noupdate', None,
1207 [('U', 'noupdate', None,
1201 _('the clone will include an empty working copy (only a repository)')),
1208 _('the clone will include an empty working copy (only a repository)')),
1202 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1209 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1203 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1210 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1204 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1211 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1205 ('', 'pull', None, _('use pull protocol to copy metadata')),
1212 ('', 'pull', None, _('use pull protocol to copy metadata')),
1206 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1213 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1207 ] + remoteopts,
1214 ] + remoteopts,
1208 _('[OPTION]... SOURCE [DEST]'))
1215 _('[OPTION]... SOURCE [DEST]'))
1209 def clone(ui, source, dest=None, **opts):
1216 def clone(ui, source, dest=None, **opts):
1210 """make a copy of an existing repository
1217 """make a copy of an existing repository
1211
1218
1212 Create a copy of an existing repository in a new directory.
1219 Create a copy of an existing repository in a new directory.
1213
1220
1214 If no destination directory name is specified, it defaults to the
1221 If no destination directory name is specified, it defaults to the
1215 basename of the source.
1222 basename of the source.
1216
1223
1217 The location of the source is added to the new repository's
1224 The location of the source is added to the new repository's
1218 ``.hg/hgrc`` file, as the default to be used for future pulls.
1225 ``.hg/hgrc`` file, as the default to be used for future pulls.
1219
1226
1220 Only local paths and ``ssh://`` URLs are supported as
1227 Only local paths and ``ssh://`` URLs are supported as
1221 destinations. For ``ssh://`` destinations, no working directory or
1228 destinations. For ``ssh://`` destinations, no working directory or
1222 ``.hg/hgrc`` will be created on the remote side.
1229 ``.hg/hgrc`` will be created on the remote side.
1223
1230
1224 To pull only a subset of changesets, specify one or more revisions
1231 To pull only a subset of changesets, specify one or more revisions
1225 identifiers with -r/--rev or branches with -b/--branch. The
1232 identifiers with -r/--rev or branches with -b/--branch. The
1226 resulting clone will contain only the specified changesets and
1233 resulting clone will contain only the specified changesets and
1227 their ancestors. These options (or 'clone src#rev dest') imply
1234 their ancestors. These options (or 'clone src#rev dest') imply
1228 --pull, even for local source repositories. Note that specifying a
1235 --pull, even for local source repositories. Note that specifying a
1229 tag will include the tagged changeset but not the changeset
1236 tag will include the tagged changeset but not the changeset
1230 containing the tag.
1237 containing the tag.
1231
1238
1232 If the source repository has a bookmark called '@' set, that
1239 If the source repository has a bookmark called '@' set, that
1233 revision will be checked out in the new repository by default.
1240 revision will be checked out in the new repository by default.
1234
1241
1235 To check out a particular version, use -u/--update, or
1242 To check out a particular version, use -u/--update, or
1236 -U/--noupdate to create a clone with no working directory.
1243 -U/--noupdate to create a clone with no working directory.
1237
1244
1238 .. container:: verbose
1245 .. container:: verbose
1239
1246
1240 For efficiency, hardlinks are used for cloning whenever the
1247 For efficiency, hardlinks are used for cloning whenever the
1241 source and destination are on the same filesystem (note this
1248 source and destination are on the same filesystem (note this
1242 applies only to the repository data, not to the working
1249 applies only to the repository data, not to the working
1243 directory). Some filesystems, such as AFS, implement hardlinking
1250 directory). Some filesystems, such as AFS, implement hardlinking
1244 incorrectly, but do not report errors. In these cases, use the
1251 incorrectly, but do not report errors. In these cases, use the
1245 --pull option to avoid hardlinking.
1252 --pull option to avoid hardlinking.
1246
1253
1247 In some cases, you can clone repositories and the working
1254 In some cases, you can clone repositories and the working
1248 directory using full hardlinks with ::
1255 directory using full hardlinks with ::
1249
1256
1250 $ cp -al REPO REPOCLONE
1257 $ cp -al REPO REPOCLONE
1251
1258
1252 This is the fastest way to clone, but it is not always safe. The
1259 This is the fastest way to clone, but it is not always safe. The
1253 operation is not atomic (making sure REPO is not modified during
1260 operation is not atomic (making sure REPO is not modified during
1254 the operation is up to you) and you have to make sure your
1261 the operation is up to you) and you have to make sure your
1255 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1262 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1256 so). Also, this is not compatible with certain extensions that
1263 so). Also, this is not compatible with certain extensions that
1257 place their metadata under the .hg directory, such as mq.
1264 place their metadata under the .hg directory, such as mq.
1258
1265
1259 Mercurial will update the working directory to the first applicable
1266 Mercurial will update the working directory to the first applicable
1260 revision from this list:
1267 revision from this list:
1261
1268
1262 a) null if -U or the source repository has no changesets
1269 a) null if -U or the source repository has no changesets
1263 b) if -u . and the source repository is local, the first parent of
1270 b) if -u . and the source repository is local, the first parent of
1264 the source repository's working directory
1271 the source repository's working directory
1265 c) the changeset specified with -u (if a branch name, this means the
1272 c) the changeset specified with -u (if a branch name, this means the
1266 latest head of that branch)
1273 latest head of that branch)
1267 d) the changeset specified with -r
1274 d) the changeset specified with -r
1268 e) the tipmost head specified with -b
1275 e) the tipmost head specified with -b
1269 f) the tipmost head specified with the url#branch source syntax
1276 f) the tipmost head specified with the url#branch source syntax
1270 g) the revision marked with the '@' bookmark, if present
1277 g) the revision marked with the '@' bookmark, if present
1271 h) the tipmost head of the default branch
1278 h) the tipmost head of the default branch
1272 i) tip
1279 i) tip
1273
1280
1274 Examples:
1281 Examples:
1275
1282
1276 - clone a remote repository to a new directory named hg/::
1283 - clone a remote repository to a new directory named hg/::
1277
1284
1278 hg clone http://selenic.com/hg
1285 hg clone http://selenic.com/hg
1279
1286
1280 - create a lightweight local clone::
1287 - create a lightweight local clone::
1281
1288
1282 hg clone project/ project-feature/
1289 hg clone project/ project-feature/
1283
1290
1284 - clone from an absolute path on an ssh server (note double-slash)::
1291 - clone from an absolute path on an ssh server (note double-slash)::
1285
1292
1286 hg clone ssh://user@server//home/projects/alpha/
1293 hg clone ssh://user@server//home/projects/alpha/
1287
1294
1288 - do a high-speed clone over a LAN while checking out a
1295 - do a high-speed clone over a LAN while checking out a
1289 specified version::
1296 specified version::
1290
1297
1291 hg clone --uncompressed http://server/repo -u 1.5
1298 hg clone --uncompressed http://server/repo -u 1.5
1292
1299
1293 - create a repository without changesets after a particular revision::
1300 - create a repository without changesets after a particular revision::
1294
1301
1295 hg clone -r 04e544 experimental/ good/
1302 hg clone -r 04e544 experimental/ good/
1296
1303
1297 - clone (and track) a particular named branch::
1304 - clone (and track) a particular named branch::
1298
1305
1299 hg clone http://selenic.com/hg#stable
1306 hg clone http://selenic.com/hg#stable
1300
1307
1301 See :hg:`help urls` for details on specifying URLs.
1308 See :hg:`help urls` for details on specifying URLs.
1302
1309
1303 Returns 0 on success.
1310 Returns 0 on success.
1304 """
1311 """
1305 if opts.get('noupdate') and opts.get('updaterev'):
1312 if opts.get('noupdate') and opts.get('updaterev'):
1306 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1313 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1307
1314
1308 r = hg.clone(ui, opts, source, dest,
1315 r = hg.clone(ui, opts, source, dest,
1309 pull=opts.get('pull'),
1316 pull=opts.get('pull'),
1310 stream=opts.get('uncompressed'),
1317 stream=opts.get('uncompressed'),
1311 rev=opts.get('rev'),
1318 rev=opts.get('rev'),
1312 update=opts.get('updaterev') or not opts.get('noupdate'),
1319 update=opts.get('updaterev') or not opts.get('noupdate'),
1313 branch=opts.get('branch'))
1320 branch=opts.get('branch'))
1314
1321
1315 return r is None
1322 return r is None
1316
1323
1317 @command('^commit|ci',
1324 @command('^commit|ci',
1318 [('A', 'addremove', None,
1325 [('A', 'addremove', None,
1319 _('mark new/missing files as added/removed before committing')),
1326 _('mark new/missing files as added/removed before committing')),
1320 ('', 'close-branch', None,
1327 ('', 'close-branch', None,
1321 _('mark a branch as closed, hiding it from the branch list')),
1328 _('mark a branch as closed, hiding it from the branch list')),
1322 ('', 'amend', None, _('amend the parent of the working dir')),
1329 ('', 'amend', None, _('amend the parent of the working dir')),
1323 ('s', 'secret', None, _('use the secret phase for committing')),
1330 ('s', 'secret', None, _('use the secret phase for committing')),
1324 ('e', 'edit', None,
1331 ('e', 'edit', None,
1325 _('further edit commit message already specified')),
1332 _('further edit commit message already specified')),
1326 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1333 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1327 _('[OPTION]... [FILE]...'))
1334 _('[OPTION]... [FILE]...'))
1328 def commit(ui, repo, *pats, **opts):
1335 def commit(ui, repo, *pats, **opts):
1329 """commit the specified files or all outstanding changes
1336 """commit the specified files or all outstanding changes
1330
1337
1331 Commit changes to the given files into the repository. Unlike a
1338 Commit changes to the given files into the repository. Unlike a
1332 centralized SCM, this operation is a local operation. See
1339 centralized SCM, this operation is a local operation. See
1333 :hg:`push` for a way to actively distribute your changes.
1340 :hg:`push` for a way to actively distribute your changes.
1334
1341
1335 If a list of files is omitted, all changes reported by :hg:`status`
1342 If a list of files is omitted, all changes reported by :hg:`status`
1336 will be committed.
1343 will be committed.
1337
1344
1338 If you are committing the result of a merge, do not provide any
1345 If you are committing the result of a merge, do not provide any
1339 filenames or -I/-X filters.
1346 filenames or -I/-X filters.
1340
1347
1341 If no commit message is specified, Mercurial starts your
1348 If no commit message is specified, Mercurial starts your
1342 configured editor where you can enter a message. In case your
1349 configured editor where you can enter a message. In case your
1343 commit fails, you will find a backup of your message in
1350 commit fails, you will find a backup of your message in
1344 ``.hg/last-message.txt``.
1351 ``.hg/last-message.txt``.
1345
1352
1346 The --amend flag can be used to amend the parent of the
1353 The --amend flag can be used to amend the parent of the
1347 working directory with a new commit that contains the changes
1354 working directory with a new commit that contains the changes
1348 in the parent in addition to those currently reported by :hg:`status`,
1355 in the parent in addition to those currently reported by :hg:`status`,
1349 if there are any. The old commit is stored in a backup bundle in
1356 if there are any. The old commit is stored in a backup bundle in
1350 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1357 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1351 on how to restore it).
1358 on how to restore it).
1352
1359
1353 Message, user and date are taken from the amended commit unless
1360 Message, user and date are taken from the amended commit unless
1354 specified. When a message isn't specified on the command line,
1361 specified. When a message isn't specified on the command line,
1355 the editor will open with the message of the amended commit.
1362 the editor will open with the message of the amended commit.
1356
1363
1357 It is not possible to amend public changesets (see :hg:`help phases`)
1364 It is not possible to amend public changesets (see :hg:`help phases`)
1358 or changesets that have children.
1365 or changesets that have children.
1359
1366
1360 See :hg:`help dates` for a list of formats valid for -d/--date.
1367 See :hg:`help dates` for a list of formats valid for -d/--date.
1361
1368
1362 Returns 0 on success, 1 if nothing changed.
1369 Returns 0 on success, 1 if nothing changed.
1363 """
1370 """
1364 if opts.get('subrepos'):
1371 if opts.get('subrepos'):
1365 if opts.get('amend'):
1372 if opts.get('amend'):
1366 raise util.Abort(_('cannot amend with --subrepos'))
1373 raise util.Abort(_('cannot amend with --subrepos'))
1367 # Let --subrepos on the command line override config setting.
1374 # Let --subrepos on the command line override config setting.
1368 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1375 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1369
1376
1370 # Save this for restoring it later
1377 # Save this for restoring it later
1371 oldcommitphase = ui.config('phases', 'new-commit')
1378 oldcommitphase = ui.config('phases', 'new-commit')
1372
1379
1373 cmdutil.checkunfinished(repo, commit=True)
1380 cmdutil.checkunfinished(repo, commit=True)
1374
1381
1375 branch = repo[None].branch()
1382 branch = repo[None].branch()
1376 bheads = repo.branchheads(branch)
1383 bheads = repo.branchheads(branch)
1377
1384
1378 extra = {}
1385 extra = {}
1379 if opts.get('close_branch'):
1386 if opts.get('close_branch'):
1380 extra['close'] = 1
1387 extra['close'] = 1
1381
1388
1382 if not bheads:
1389 if not bheads:
1383 raise util.Abort(_('can only close branch heads'))
1390 raise util.Abort(_('can only close branch heads'))
1384 elif opts.get('amend'):
1391 elif opts.get('amend'):
1385 if repo.parents()[0].p1().branch() != branch and \
1392 if repo.parents()[0].p1().branch() != branch and \
1386 repo.parents()[0].p2().branch() != branch:
1393 repo.parents()[0].p2().branch() != branch:
1387 raise util.Abort(_('can only close branch heads'))
1394 raise util.Abort(_('can only close branch heads'))
1388
1395
1389 if opts.get('amend'):
1396 if opts.get('amend'):
1390 if ui.configbool('ui', 'commitsubrepos'):
1397 if ui.configbool('ui', 'commitsubrepos'):
1391 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1398 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1392
1399
1393 old = repo['.']
1400 old = repo['.']
1394 if old.phase() == phases.public:
1401 if old.phase() == phases.public:
1395 raise util.Abort(_('cannot amend public changesets'))
1402 raise util.Abort(_('cannot amend public changesets'))
1396 if len(repo[None].parents()) > 1:
1403 if len(repo[None].parents()) > 1:
1397 raise util.Abort(_('cannot amend while merging'))
1404 raise util.Abort(_('cannot amend while merging'))
1398 if (not obsolete._enabled) and old.children():
1405 if (not obsolete._enabled) and old.children():
1399 raise util.Abort(_('cannot amend changeset with children'))
1406 raise util.Abort(_('cannot amend changeset with children'))
1400
1407
1401 # commitfunc is used only for temporary amend commit by cmdutil.amend
1408 # commitfunc is used only for temporary amend commit by cmdutil.amend
1402 def commitfunc(ui, repo, message, match, opts):
1409 def commitfunc(ui, repo, message, match, opts):
1403 return repo.commit(message,
1410 return repo.commit(message,
1404 opts.get('user') or old.user(),
1411 opts.get('user') or old.user(),
1405 opts.get('date') or old.date(),
1412 opts.get('date') or old.date(),
1406 match,
1413 match,
1407 extra=extra)
1414 extra=extra)
1408
1415
1409 current = repo._bookmarkcurrent
1416 current = repo._bookmarkcurrent
1410 marks = old.bookmarks()
1417 marks = old.bookmarks()
1411 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1418 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1412 if node == old.node():
1419 if node == old.node():
1413 ui.status(_("nothing changed\n"))
1420 ui.status(_("nothing changed\n"))
1414 return 1
1421 return 1
1415 elif marks:
1422 elif marks:
1416 ui.debug('moving bookmarks %r from %s to %s\n' %
1423 ui.debug('moving bookmarks %r from %s to %s\n' %
1417 (marks, old.hex(), hex(node)))
1424 (marks, old.hex(), hex(node)))
1418 newmarks = repo._bookmarks
1425 newmarks = repo._bookmarks
1419 for bm in marks:
1426 for bm in marks:
1420 newmarks[bm] = node
1427 newmarks[bm] = node
1421 if bm == current:
1428 if bm == current:
1422 bookmarks.setcurrent(repo, bm)
1429 bookmarks.setcurrent(repo, bm)
1423 newmarks.write()
1430 newmarks.write()
1424 else:
1431 else:
1425 def commitfunc(ui, repo, message, match, opts):
1432 def commitfunc(ui, repo, message, match, opts):
1426 try:
1433 try:
1427 if opts.get('secret'):
1434 if opts.get('secret'):
1428 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1435 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1429 # Propagate to subrepos
1436 # Propagate to subrepos
1430 repo.baseui.setconfig('phases', 'new-commit', 'secret',
1437 repo.baseui.setconfig('phases', 'new-commit', 'secret',
1431 'commit')
1438 'commit')
1432
1439
1433 return repo.commit(message, opts.get('user'), opts.get('date'),
1440 return repo.commit(message, opts.get('user'), opts.get('date'),
1434 match,
1441 match,
1435 editor=cmdutil.getcommiteditor(**opts),
1442 editor=cmdutil.getcommiteditor(**opts),
1436 extra=extra)
1443 extra=extra)
1437 finally:
1444 finally:
1438 ui.setconfig('phases', 'new-commit', oldcommitphase, 'commit')
1445 ui.setconfig('phases', 'new-commit', oldcommitphase, 'commit')
1439 repo.baseui.setconfig('phases', 'new-commit', oldcommitphase,
1446 repo.baseui.setconfig('phases', 'new-commit', oldcommitphase,
1440 'commit')
1447 'commit')
1441
1448
1442
1449
1443 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1450 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1444
1451
1445 if not node:
1452 if not node:
1446 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1453 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1447 if stat[3]:
1454 if stat[3]:
1448 ui.status(_("nothing changed (%d missing files, see "
1455 ui.status(_("nothing changed (%d missing files, see "
1449 "'hg status')\n") % len(stat[3]))
1456 "'hg status')\n") % len(stat[3]))
1450 else:
1457 else:
1451 ui.status(_("nothing changed\n"))
1458 ui.status(_("nothing changed\n"))
1452 return 1
1459 return 1
1453
1460
1454 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1461 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1455
1462
1456 @command('config|showconfig|debugconfig',
1463 @command('config|showconfig|debugconfig',
1457 [('u', 'untrusted', None, _('show untrusted configuration options')),
1464 [('u', 'untrusted', None, _('show untrusted configuration options')),
1458 ('e', 'edit', None, _('edit user config')),
1465 ('e', 'edit', None, _('edit user config')),
1459 ('l', 'local', None, _('edit repository config')),
1466 ('l', 'local', None, _('edit repository config')),
1460 ('g', 'global', None, _('edit global config'))],
1467 ('g', 'global', None, _('edit global config'))],
1461 _('[-u] [NAME]...'))
1468 _('[-u] [NAME]...'))
1462 def config(ui, repo, *values, **opts):
1469 def config(ui, repo, *values, **opts):
1463 """show combined config settings from all hgrc files
1470 """show combined config settings from all hgrc files
1464
1471
1465 With no arguments, print names and values of all config items.
1472 With no arguments, print names and values of all config items.
1466
1473
1467 With one argument of the form section.name, print just the value
1474 With one argument of the form section.name, print just the value
1468 of that config item.
1475 of that config item.
1469
1476
1470 With multiple arguments, print names and values of all config
1477 With multiple arguments, print names and values of all config
1471 items with matching section names.
1478 items with matching section names.
1472
1479
1473 With --edit, start an editor on the user-level config file. With
1480 With --edit, start an editor on the user-level config file. With
1474 --global, edit the system-wide config file. With --local, edit the
1481 --global, edit the system-wide config file. With --local, edit the
1475 repository-level config file.
1482 repository-level config file.
1476
1483
1477 With --debug, the source (filename and line number) is printed
1484 With --debug, the source (filename and line number) is printed
1478 for each config item.
1485 for each config item.
1479
1486
1480 See :hg:`help config` for more information about config files.
1487 See :hg:`help config` for more information about config files.
1481
1488
1482 Returns 0 on success.
1489 Returns 0 on success.
1483
1490
1484 """
1491 """
1485
1492
1486 if opts.get('edit') or opts.get('local') or opts.get('global'):
1493 if opts.get('edit') or opts.get('local') or opts.get('global'):
1487 if opts.get('local') and opts.get('global'):
1494 if opts.get('local') and opts.get('global'):
1488 raise util.Abort(_("can't use --local and --global together"))
1495 raise util.Abort(_("can't use --local and --global together"))
1489
1496
1490 if opts.get('local'):
1497 if opts.get('local'):
1491 if not repo:
1498 if not repo:
1492 raise util.Abort(_("can't use --local outside a repository"))
1499 raise util.Abort(_("can't use --local outside a repository"))
1493 paths = [repo.join('hgrc')]
1500 paths = [repo.join('hgrc')]
1494 elif opts.get('global'):
1501 elif opts.get('global'):
1495 paths = scmutil.systemrcpath()
1502 paths = scmutil.systemrcpath()
1496 else:
1503 else:
1497 paths = scmutil.userrcpath()
1504 paths = scmutil.userrcpath()
1498
1505
1499 for f in paths:
1506 for f in paths:
1500 if os.path.exists(f):
1507 if os.path.exists(f):
1501 break
1508 break
1502 else:
1509 else:
1503 f = paths[0]
1510 f = paths[0]
1504 fp = open(f, "w")
1511 fp = open(f, "w")
1505 fp.write(
1512 fp.write(
1506 '# example config (see "hg help config" for more info)\n'
1513 '# example config (see "hg help config" for more info)\n'
1507 '\n'
1514 '\n'
1508 '[ui]\n'
1515 '[ui]\n'
1509 '# name and email, e.g.\n'
1516 '# name and email, e.g.\n'
1510 '# username = Jane Doe <jdoe@example.com>\n'
1517 '# username = Jane Doe <jdoe@example.com>\n'
1511 'username =\n'
1518 'username =\n'
1512 '\n'
1519 '\n'
1513 '[extensions]\n'
1520 '[extensions]\n'
1514 '# uncomment these lines to enable some popular extensions\n'
1521 '# uncomment these lines to enable some popular extensions\n'
1515 '# (see "hg help extensions" for more info)\n'
1522 '# (see "hg help extensions" for more info)\n'
1516 '# pager =\n'
1523 '# pager =\n'
1517 '# progress =\n'
1524 '# progress =\n'
1518 '# color =\n')
1525 '# color =\n')
1519 fp.close()
1526 fp.close()
1520
1527
1521 editor = ui.geteditor()
1528 editor = ui.geteditor()
1522 util.system("%s \"%s\"" % (editor, f),
1529 util.system("%s \"%s\"" % (editor, f),
1523 onerr=util.Abort, errprefix=_("edit failed"),
1530 onerr=util.Abort, errprefix=_("edit failed"),
1524 out=ui.fout)
1531 out=ui.fout)
1525 return
1532 return
1526
1533
1527 for f in scmutil.rcpath():
1534 for f in scmutil.rcpath():
1528 ui.debug('read config from: %s\n' % f)
1535 ui.debug('read config from: %s\n' % f)
1529 untrusted = bool(opts.get('untrusted'))
1536 untrusted = bool(opts.get('untrusted'))
1530 if values:
1537 if values:
1531 sections = [v for v in values if '.' not in v]
1538 sections = [v for v in values if '.' not in v]
1532 items = [v for v in values if '.' in v]
1539 items = [v for v in values if '.' in v]
1533 if len(items) > 1 or items and sections:
1540 if len(items) > 1 or items and sections:
1534 raise util.Abort(_('only one config item permitted'))
1541 raise util.Abort(_('only one config item permitted'))
1535 for section, name, value in ui.walkconfig(untrusted=untrusted):
1542 for section, name, value in ui.walkconfig(untrusted=untrusted):
1536 value = str(value).replace('\n', '\\n')
1543 value = str(value).replace('\n', '\\n')
1537 sectname = section + '.' + name
1544 sectname = section + '.' + name
1538 if values:
1545 if values:
1539 for v in values:
1546 for v in values:
1540 if v == section:
1547 if v == section:
1541 ui.debug('%s: ' %
1548 ui.debug('%s: ' %
1542 ui.configsource(section, name, untrusted))
1549 ui.configsource(section, name, untrusted))
1543 ui.write('%s=%s\n' % (sectname, value))
1550 ui.write('%s=%s\n' % (sectname, value))
1544 elif v == sectname:
1551 elif v == sectname:
1545 ui.debug('%s: ' %
1552 ui.debug('%s: ' %
1546 ui.configsource(section, name, untrusted))
1553 ui.configsource(section, name, untrusted))
1547 ui.write(value, '\n')
1554 ui.write(value, '\n')
1548 else:
1555 else:
1549 ui.debug('%s: ' %
1556 ui.debug('%s: ' %
1550 ui.configsource(section, name, untrusted))
1557 ui.configsource(section, name, untrusted))
1551 ui.write('%s=%s\n' % (sectname, value))
1558 ui.write('%s=%s\n' % (sectname, value))
1552
1559
1553 @command('copy|cp',
1560 @command('copy|cp',
1554 [('A', 'after', None, _('record a copy that has already occurred')),
1561 [('A', 'after', None, _('record a copy that has already occurred')),
1555 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1562 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1556 ] + walkopts + dryrunopts,
1563 ] + walkopts + dryrunopts,
1557 _('[OPTION]... [SOURCE]... DEST'))
1564 _('[OPTION]... [SOURCE]... DEST'))
1558 def copy(ui, repo, *pats, **opts):
1565 def copy(ui, repo, *pats, **opts):
1559 """mark files as copied for the next commit
1566 """mark files as copied for the next commit
1560
1567
1561 Mark dest as having copies of source files. If dest is a
1568 Mark dest as having copies of source files. If dest is a
1562 directory, copies are put in that directory. If dest is a file,
1569 directory, copies are put in that directory. If dest is a file,
1563 the source must be a single file.
1570 the source must be a single file.
1564
1571
1565 By default, this command copies the contents of files as they
1572 By default, this command copies the contents of files as they
1566 exist in the working directory. If invoked with -A/--after, the
1573 exist in the working directory. If invoked with -A/--after, the
1567 operation is recorded, but no copying is performed.
1574 operation is recorded, but no copying is performed.
1568
1575
1569 This command takes effect with the next commit. To undo a copy
1576 This command takes effect with the next commit. To undo a copy
1570 before that, see :hg:`revert`.
1577 before that, see :hg:`revert`.
1571
1578
1572 Returns 0 on success, 1 if errors are encountered.
1579 Returns 0 on success, 1 if errors are encountered.
1573 """
1580 """
1574 wlock = repo.wlock(False)
1581 wlock = repo.wlock(False)
1575 try:
1582 try:
1576 return cmdutil.copy(ui, repo, pats, opts)
1583 return cmdutil.copy(ui, repo, pats, opts)
1577 finally:
1584 finally:
1578 wlock.release()
1585 wlock.release()
1579
1586
1580 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1587 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1581 def debugancestor(ui, repo, *args):
1588 def debugancestor(ui, repo, *args):
1582 """find the ancestor revision of two revisions in a given index"""
1589 """find the ancestor revision of two revisions in a given index"""
1583 if len(args) == 3:
1590 if len(args) == 3:
1584 index, rev1, rev2 = args
1591 index, rev1, rev2 = args
1585 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1592 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1586 lookup = r.lookup
1593 lookup = r.lookup
1587 elif len(args) == 2:
1594 elif len(args) == 2:
1588 if not repo:
1595 if not repo:
1589 raise util.Abort(_("there is no Mercurial repository here "
1596 raise util.Abort(_("there is no Mercurial repository here "
1590 "(.hg not found)"))
1597 "(.hg not found)"))
1591 rev1, rev2 = args
1598 rev1, rev2 = args
1592 r = repo.changelog
1599 r = repo.changelog
1593 lookup = repo.lookup
1600 lookup = repo.lookup
1594 else:
1601 else:
1595 raise util.Abort(_('either two or three arguments required'))
1602 raise util.Abort(_('either two or three arguments required'))
1596 a = r.ancestor(lookup(rev1), lookup(rev2))
1603 a = r.ancestor(lookup(rev1), lookup(rev2))
1597 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1604 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1598
1605
1599 @command('debugbuilddag',
1606 @command('debugbuilddag',
1600 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1607 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1601 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1608 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1602 ('n', 'new-file', None, _('add new file at each rev'))],
1609 ('n', 'new-file', None, _('add new file at each rev'))],
1603 _('[OPTION]... [TEXT]'))
1610 _('[OPTION]... [TEXT]'))
1604 def debugbuilddag(ui, repo, text=None,
1611 def debugbuilddag(ui, repo, text=None,
1605 mergeable_file=False,
1612 mergeable_file=False,
1606 overwritten_file=False,
1613 overwritten_file=False,
1607 new_file=False):
1614 new_file=False):
1608 """builds a repo with a given DAG from scratch in the current empty repo
1615 """builds a repo with a given DAG from scratch in the current empty repo
1609
1616
1610 The description of the DAG is read from stdin if not given on the
1617 The description of the DAG is read from stdin if not given on the
1611 command line.
1618 command line.
1612
1619
1613 Elements:
1620 Elements:
1614
1621
1615 - "+n" is a linear run of n nodes based on the current default parent
1622 - "+n" is a linear run of n nodes based on the current default parent
1616 - "." is a single node based on the current default parent
1623 - "." is a single node based on the current default parent
1617 - "$" resets the default parent to null (implied at the start);
1624 - "$" resets the default parent to null (implied at the start);
1618 otherwise the default parent is always the last node created
1625 otherwise the default parent is always the last node created
1619 - "<p" sets the default parent to the backref p
1626 - "<p" sets the default parent to the backref p
1620 - "*p" is a fork at parent p, which is a backref
1627 - "*p" is a fork at parent p, which is a backref
1621 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1628 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1622 - "/p2" is a merge of the preceding node and p2
1629 - "/p2" is a merge of the preceding node and p2
1623 - ":tag" defines a local tag for the preceding node
1630 - ":tag" defines a local tag for the preceding node
1624 - "@branch" sets the named branch for subsequent nodes
1631 - "@branch" sets the named branch for subsequent nodes
1625 - "#...\\n" is a comment up to the end of the line
1632 - "#...\\n" is a comment up to the end of the line
1626
1633
1627 Whitespace between the above elements is ignored.
1634 Whitespace between the above elements is ignored.
1628
1635
1629 A backref is either
1636 A backref is either
1630
1637
1631 - a number n, which references the node curr-n, where curr is the current
1638 - a number n, which references the node curr-n, where curr is the current
1632 node, or
1639 node, or
1633 - the name of a local tag you placed earlier using ":tag", or
1640 - the name of a local tag you placed earlier using ":tag", or
1634 - empty to denote the default parent.
1641 - empty to denote the default parent.
1635
1642
1636 All string valued-elements are either strictly alphanumeric, or must
1643 All string valued-elements are either strictly alphanumeric, or must
1637 be enclosed in double quotes ("..."), with "\\" as escape character.
1644 be enclosed in double quotes ("..."), with "\\" as escape character.
1638 """
1645 """
1639
1646
1640 if text is None:
1647 if text is None:
1641 ui.status(_("reading DAG from stdin\n"))
1648 ui.status(_("reading DAG from stdin\n"))
1642 text = ui.fin.read()
1649 text = ui.fin.read()
1643
1650
1644 cl = repo.changelog
1651 cl = repo.changelog
1645 if len(cl) > 0:
1652 if len(cl) > 0:
1646 raise util.Abort(_('repository is not empty'))
1653 raise util.Abort(_('repository is not empty'))
1647
1654
1648 # determine number of revs in DAG
1655 # determine number of revs in DAG
1649 total = 0
1656 total = 0
1650 for type, data in dagparser.parsedag(text):
1657 for type, data in dagparser.parsedag(text):
1651 if type == 'n':
1658 if type == 'n':
1652 total += 1
1659 total += 1
1653
1660
1654 if mergeable_file:
1661 if mergeable_file:
1655 linesperrev = 2
1662 linesperrev = 2
1656 # make a file with k lines per rev
1663 # make a file with k lines per rev
1657 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1664 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1658 initialmergedlines.append("")
1665 initialmergedlines.append("")
1659
1666
1660 tags = []
1667 tags = []
1661
1668
1662 lock = tr = None
1669 lock = tr = None
1663 try:
1670 try:
1664 lock = repo.lock()
1671 lock = repo.lock()
1665 tr = repo.transaction("builddag")
1672 tr = repo.transaction("builddag")
1666
1673
1667 at = -1
1674 at = -1
1668 atbranch = 'default'
1675 atbranch = 'default'
1669 nodeids = []
1676 nodeids = []
1670 id = 0
1677 id = 0
1671 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1678 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1672 for type, data in dagparser.parsedag(text):
1679 for type, data in dagparser.parsedag(text):
1673 if type == 'n':
1680 if type == 'n':
1674 ui.note(('node %s\n' % str(data)))
1681 ui.note(('node %s\n' % str(data)))
1675 id, ps = data
1682 id, ps = data
1676
1683
1677 files = []
1684 files = []
1678 fctxs = {}
1685 fctxs = {}
1679
1686
1680 p2 = None
1687 p2 = None
1681 if mergeable_file:
1688 if mergeable_file:
1682 fn = "mf"
1689 fn = "mf"
1683 p1 = repo[ps[0]]
1690 p1 = repo[ps[0]]
1684 if len(ps) > 1:
1691 if len(ps) > 1:
1685 p2 = repo[ps[1]]
1692 p2 = repo[ps[1]]
1686 pa = p1.ancestor(p2)
1693 pa = p1.ancestor(p2)
1687 base, local, other = [x[fn].data() for x in (pa, p1,
1694 base, local, other = [x[fn].data() for x in (pa, p1,
1688 p2)]
1695 p2)]
1689 m3 = simplemerge.Merge3Text(base, local, other)
1696 m3 = simplemerge.Merge3Text(base, local, other)
1690 ml = [l.strip() for l in m3.merge_lines()]
1697 ml = [l.strip() for l in m3.merge_lines()]
1691 ml.append("")
1698 ml.append("")
1692 elif at > 0:
1699 elif at > 0:
1693 ml = p1[fn].data().split("\n")
1700 ml = p1[fn].data().split("\n")
1694 else:
1701 else:
1695 ml = initialmergedlines
1702 ml = initialmergedlines
1696 ml[id * linesperrev] += " r%i" % id
1703 ml[id * linesperrev] += " r%i" % id
1697 mergedtext = "\n".join(ml)
1704 mergedtext = "\n".join(ml)
1698 files.append(fn)
1705 files.append(fn)
1699 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1706 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1700
1707
1701 if overwritten_file:
1708 if overwritten_file:
1702 fn = "of"
1709 fn = "of"
1703 files.append(fn)
1710 files.append(fn)
1704 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1711 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1705
1712
1706 if new_file:
1713 if new_file:
1707 fn = "nf%i" % id
1714 fn = "nf%i" % id
1708 files.append(fn)
1715 files.append(fn)
1709 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1716 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1710 if len(ps) > 1:
1717 if len(ps) > 1:
1711 if not p2:
1718 if not p2:
1712 p2 = repo[ps[1]]
1719 p2 = repo[ps[1]]
1713 for fn in p2:
1720 for fn in p2:
1714 if fn.startswith("nf"):
1721 if fn.startswith("nf"):
1715 files.append(fn)
1722 files.append(fn)
1716 fctxs[fn] = p2[fn]
1723 fctxs[fn] = p2[fn]
1717
1724
1718 def fctxfn(repo, cx, path):
1725 def fctxfn(repo, cx, path):
1719 return fctxs.get(path)
1726 return fctxs.get(path)
1720
1727
1721 if len(ps) == 0 or ps[0] < 0:
1728 if len(ps) == 0 or ps[0] < 0:
1722 pars = [None, None]
1729 pars = [None, None]
1723 elif len(ps) == 1:
1730 elif len(ps) == 1:
1724 pars = [nodeids[ps[0]], None]
1731 pars = [nodeids[ps[0]], None]
1725 else:
1732 else:
1726 pars = [nodeids[p] for p in ps]
1733 pars = [nodeids[p] for p in ps]
1727 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1734 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1728 date=(id, 0),
1735 date=(id, 0),
1729 user="debugbuilddag",
1736 user="debugbuilddag",
1730 extra={'branch': atbranch})
1737 extra={'branch': atbranch})
1731 nodeid = repo.commitctx(cx)
1738 nodeid = repo.commitctx(cx)
1732 nodeids.append(nodeid)
1739 nodeids.append(nodeid)
1733 at = id
1740 at = id
1734 elif type == 'l':
1741 elif type == 'l':
1735 id, name = data
1742 id, name = data
1736 ui.note(('tag %s\n' % name))
1743 ui.note(('tag %s\n' % name))
1737 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1744 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1738 elif type == 'a':
1745 elif type == 'a':
1739 ui.note(('branch %s\n' % data))
1746 ui.note(('branch %s\n' % data))
1740 atbranch = data
1747 atbranch = data
1741 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1748 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1742 tr.close()
1749 tr.close()
1743
1750
1744 if tags:
1751 if tags:
1745 repo.opener.write("localtags", "".join(tags))
1752 repo.opener.write("localtags", "".join(tags))
1746 finally:
1753 finally:
1747 ui.progress(_('building'), None)
1754 ui.progress(_('building'), None)
1748 release(tr, lock)
1755 release(tr, lock)
1749
1756
1750 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1757 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1751 def debugbundle(ui, bundlepath, all=None, **opts):
1758 def debugbundle(ui, bundlepath, all=None, **opts):
1752 """lists the contents of a bundle"""
1759 """lists the contents of a bundle"""
1753 f = hg.openpath(ui, bundlepath)
1760 f = hg.openpath(ui, bundlepath)
1754 try:
1761 try:
1755 gen = exchange.readbundle(ui, f, bundlepath)
1762 gen = exchange.readbundle(ui, f, bundlepath)
1756 if all:
1763 if all:
1757 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1764 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1758
1765
1759 def showchunks(named):
1766 def showchunks(named):
1760 ui.write("\n%s\n" % named)
1767 ui.write("\n%s\n" % named)
1761 chain = None
1768 chain = None
1762 while True:
1769 while True:
1763 chunkdata = gen.deltachunk(chain)
1770 chunkdata = gen.deltachunk(chain)
1764 if not chunkdata:
1771 if not chunkdata:
1765 break
1772 break
1766 node = chunkdata['node']
1773 node = chunkdata['node']
1767 p1 = chunkdata['p1']
1774 p1 = chunkdata['p1']
1768 p2 = chunkdata['p2']
1775 p2 = chunkdata['p2']
1769 cs = chunkdata['cs']
1776 cs = chunkdata['cs']
1770 deltabase = chunkdata['deltabase']
1777 deltabase = chunkdata['deltabase']
1771 delta = chunkdata['delta']
1778 delta = chunkdata['delta']
1772 ui.write("%s %s %s %s %s %s\n" %
1779 ui.write("%s %s %s %s %s %s\n" %
1773 (hex(node), hex(p1), hex(p2),
1780 (hex(node), hex(p1), hex(p2),
1774 hex(cs), hex(deltabase), len(delta)))
1781 hex(cs), hex(deltabase), len(delta)))
1775 chain = node
1782 chain = node
1776
1783
1777 chunkdata = gen.changelogheader()
1784 chunkdata = gen.changelogheader()
1778 showchunks("changelog")
1785 showchunks("changelog")
1779 chunkdata = gen.manifestheader()
1786 chunkdata = gen.manifestheader()
1780 showchunks("manifest")
1787 showchunks("manifest")
1781 while True:
1788 while True:
1782 chunkdata = gen.filelogheader()
1789 chunkdata = gen.filelogheader()
1783 if not chunkdata:
1790 if not chunkdata:
1784 break
1791 break
1785 fname = chunkdata['filename']
1792 fname = chunkdata['filename']
1786 showchunks(fname)
1793 showchunks(fname)
1787 else:
1794 else:
1788 chunkdata = gen.changelogheader()
1795 chunkdata = gen.changelogheader()
1789 chain = None
1796 chain = None
1790 while True:
1797 while True:
1791 chunkdata = gen.deltachunk(chain)
1798 chunkdata = gen.deltachunk(chain)
1792 if not chunkdata:
1799 if not chunkdata:
1793 break
1800 break
1794 node = chunkdata['node']
1801 node = chunkdata['node']
1795 ui.write("%s\n" % hex(node))
1802 ui.write("%s\n" % hex(node))
1796 chain = node
1803 chain = node
1797 finally:
1804 finally:
1798 f.close()
1805 f.close()
1799
1806
1800 @command('debugcheckstate', [], '')
1807 @command('debugcheckstate', [], '')
1801 def debugcheckstate(ui, repo):
1808 def debugcheckstate(ui, repo):
1802 """validate the correctness of the current dirstate"""
1809 """validate the correctness of the current dirstate"""
1803 parent1, parent2 = repo.dirstate.parents()
1810 parent1, parent2 = repo.dirstate.parents()
1804 m1 = repo[parent1].manifest()
1811 m1 = repo[parent1].manifest()
1805 m2 = repo[parent2].manifest()
1812 m2 = repo[parent2].manifest()
1806 errors = 0
1813 errors = 0
1807 for f in repo.dirstate:
1814 for f in repo.dirstate:
1808 state = repo.dirstate[f]
1815 state = repo.dirstate[f]
1809 if state in "nr" and f not in m1:
1816 if state in "nr" and f not in m1:
1810 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1817 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1811 errors += 1
1818 errors += 1
1812 if state in "a" and f in m1:
1819 if state in "a" and f in m1:
1813 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1820 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1814 errors += 1
1821 errors += 1
1815 if state in "m" and f not in m1 and f not in m2:
1822 if state in "m" and f not in m1 and f not in m2:
1816 ui.warn(_("%s in state %s, but not in either manifest\n") %
1823 ui.warn(_("%s in state %s, but not in either manifest\n") %
1817 (f, state))
1824 (f, state))
1818 errors += 1
1825 errors += 1
1819 for f in m1:
1826 for f in m1:
1820 state = repo.dirstate[f]
1827 state = repo.dirstate[f]
1821 if state not in "nrm":
1828 if state not in "nrm":
1822 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1829 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1823 errors += 1
1830 errors += 1
1824 if errors:
1831 if errors:
1825 error = _(".hg/dirstate inconsistent with current parent's manifest")
1832 error = _(".hg/dirstate inconsistent with current parent's manifest")
1826 raise util.Abort(error)
1833 raise util.Abort(error)
1827
1834
1828 @command('debugcommands', [], _('[COMMAND]'))
1835 @command('debugcommands', [], _('[COMMAND]'))
1829 def debugcommands(ui, cmd='', *args):
1836 def debugcommands(ui, cmd='', *args):
1830 """list all available commands and options"""
1837 """list all available commands and options"""
1831 for cmd, vals in sorted(table.iteritems()):
1838 for cmd, vals in sorted(table.iteritems()):
1832 cmd = cmd.split('|')[0].strip('^')
1839 cmd = cmd.split('|')[0].strip('^')
1833 opts = ', '.join([i[1] for i in vals[1]])
1840 opts = ', '.join([i[1] for i in vals[1]])
1834 ui.write('%s: %s\n' % (cmd, opts))
1841 ui.write('%s: %s\n' % (cmd, opts))
1835
1842
1836 @command('debugcomplete',
1843 @command('debugcomplete',
1837 [('o', 'options', None, _('show the command options'))],
1844 [('o', 'options', None, _('show the command options'))],
1838 _('[-o] CMD'))
1845 _('[-o] CMD'))
1839 def debugcomplete(ui, cmd='', **opts):
1846 def debugcomplete(ui, cmd='', **opts):
1840 """returns the completion list associated with the given command"""
1847 """returns the completion list associated with the given command"""
1841
1848
1842 if opts.get('options'):
1849 if opts.get('options'):
1843 options = []
1850 options = []
1844 otables = [globalopts]
1851 otables = [globalopts]
1845 if cmd:
1852 if cmd:
1846 aliases, entry = cmdutil.findcmd(cmd, table, False)
1853 aliases, entry = cmdutil.findcmd(cmd, table, False)
1847 otables.append(entry[1])
1854 otables.append(entry[1])
1848 for t in otables:
1855 for t in otables:
1849 for o in t:
1856 for o in t:
1850 if "(DEPRECATED)" in o[3]:
1857 if "(DEPRECATED)" in o[3]:
1851 continue
1858 continue
1852 if o[0]:
1859 if o[0]:
1853 options.append('-%s' % o[0])
1860 options.append('-%s' % o[0])
1854 options.append('--%s' % o[1])
1861 options.append('--%s' % o[1])
1855 ui.write("%s\n" % "\n".join(options))
1862 ui.write("%s\n" % "\n".join(options))
1856 return
1863 return
1857
1864
1858 cmdlist = cmdutil.findpossible(cmd, table)
1865 cmdlist = cmdutil.findpossible(cmd, table)
1859 if ui.verbose:
1866 if ui.verbose:
1860 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1867 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1861 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1868 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1862
1869
1863 @command('debugdag',
1870 @command('debugdag',
1864 [('t', 'tags', None, _('use tags as labels')),
1871 [('t', 'tags', None, _('use tags as labels')),
1865 ('b', 'branches', None, _('annotate with branch names')),
1872 ('b', 'branches', None, _('annotate with branch names')),
1866 ('', 'dots', None, _('use dots for runs')),
1873 ('', 'dots', None, _('use dots for runs')),
1867 ('s', 'spaces', None, _('separate elements by spaces'))],
1874 ('s', 'spaces', None, _('separate elements by spaces'))],
1868 _('[OPTION]... [FILE [REV]...]'))
1875 _('[OPTION]... [FILE [REV]...]'))
1869 def debugdag(ui, repo, file_=None, *revs, **opts):
1876 def debugdag(ui, repo, file_=None, *revs, **opts):
1870 """format the changelog or an index DAG as a concise textual description
1877 """format the changelog or an index DAG as a concise textual description
1871
1878
1872 If you pass a revlog index, the revlog's DAG is emitted. If you list
1879 If you pass a revlog index, the revlog's DAG is emitted. If you list
1873 revision numbers, they get labeled in the output as rN.
1880 revision numbers, they get labeled in the output as rN.
1874
1881
1875 Otherwise, the changelog DAG of the current repo is emitted.
1882 Otherwise, the changelog DAG of the current repo is emitted.
1876 """
1883 """
1877 spaces = opts.get('spaces')
1884 spaces = opts.get('spaces')
1878 dots = opts.get('dots')
1885 dots = opts.get('dots')
1879 if file_:
1886 if file_:
1880 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1887 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1881 revs = set((int(r) for r in revs))
1888 revs = set((int(r) for r in revs))
1882 def events():
1889 def events():
1883 for r in rlog:
1890 for r in rlog:
1884 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1891 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1885 if p != -1)))
1892 if p != -1)))
1886 if r in revs:
1893 if r in revs:
1887 yield 'l', (r, "r%i" % r)
1894 yield 'l', (r, "r%i" % r)
1888 elif repo:
1895 elif repo:
1889 cl = repo.changelog
1896 cl = repo.changelog
1890 tags = opts.get('tags')
1897 tags = opts.get('tags')
1891 branches = opts.get('branches')
1898 branches = opts.get('branches')
1892 if tags:
1899 if tags:
1893 labels = {}
1900 labels = {}
1894 for l, n in repo.tags().items():
1901 for l, n in repo.tags().items():
1895 labels.setdefault(cl.rev(n), []).append(l)
1902 labels.setdefault(cl.rev(n), []).append(l)
1896 def events():
1903 def events():
1897 b = "default"
1904 b = "default"
1898 for r in cl:
1905 for r in cl:
1899 if branches:
1906 if branches:
1900 newb = cl.read(cl.node(r))[5]['branch']
1907 newb = cl.read(cl.node(r))[5]['branch']
1901 if newb != b:
1908 if newb != b:
1902 yield 'a', newb
1909 yield 'a', newb
1903 b = newb
1910 b = newb
1904 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1911 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1905 if p != -1)))
1912 if p != -1)))
1906 if tags:
1913 if tags:
1907 ls = labels.get(r)
1914 ls = labels.get(r)
1908 if ls:
1915 if ls:
1909 for l in ls:
1916 for l in ls:
1910 yield 'l', (r, l)
1917 yield 'l', (r, l)
1911 else:
1918 else:
1912 raise util.Abort(_('need repo for changelog dag'))
1919 raise util.Abort(_('need repo for changelog dag'))
1913
1920
1914 for line in dagparser.dagtextlines(events(),
1921 for line in dagparser.dagtextlines(events(),
1915 addspaces=spaces,
1922 addspaces=spaces,
1916 wraplabels=True,
1923 wraplabels=True,
1917 wrapannotations=True,
1924 wrapannotations=True,
1918 wrapnonlinear=dots,
1925 wrapnonlinear=dots,
1919 usedots=dots,
1926 usedots=dots,
1920 maxlinewidth=70):
1927 maxlinewidth=70):
1921 ui.write(line)
1928 ui.write(line)
1922 ui.write("\n")
1929 ui.write("\n")
1923
1930
1924 @command('debugdata',
1931 @command('debugdata',
1925 [('c', 'changelog', False, _('open changelog')),
1932 [('c', 'changelog', False, _('open changelog')),
1926 ('m', 'manifest', False, _('open manifest'))],
1933 ('m', 'manifest', False, _('open manifest'))],
1927 _('-c|-m|FILE REV'))
1934 _('-c|-m|FILE REV'))
1928 def debugdata(ui, repo, file_, rev=None, **opts):
1935 def debugdata(ui, repo, file_, rev=None, **opts):
1929 """dump the contents of a data file revision"""
1936 """dump the contents of a data file revision"""
1930 if opts.get('changelog') or opts.get('manifest'):
1937 if opts.get('changelog') or opts.get('manifest'):
1931 file_, rev = None, file_
1938 file_, rev = None, file_
1932 elif rev is None:
1939 elif rev is None:
1933 raise error.CommandError('debugdata', _('invalid arguments'))
1940 raise error.CommandError('debugdata', _('invalid arguments'))
1934 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1941 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1935 try:
1942 try:
1936 ui.write(r.revision(r.lookup(rev)))
1943 ui.write(r.revision(r.lookup(rev)))
1937 except KeyError:
1944 except KeyError:
1938 raise util.Abort(_('invalid revision identifier %s') % rev)
1945 raise util.Abort(_('invalid revision identifier %s') % rev)
1939
1946
1940 @command('debugdate',
1947 @command('debugdate',
1941 [('e', 'extended', None, _('try extended date formats'))],
1948 [('e', 'extended', None, _('try extended date formats'))],
1942 _('[-e] DATE [RANGE]'))
1949 _('[-e] DATE [RANGE]'))
1943 def debugdate(ui, date, range=None, **opts):
1950 def debugdate(ui, date, range=None, **opts):
1944 """parse and display a date"""
1951 """parse and display a date"""
1945 if opts["extended"]:
1952 if opts["extended"]:
1946 d = util.parsedate(date, util.extendeddateformats)
1953 d = util.parsedate(date, util.extendeddateformats)
1947 else:
1954 else:
1948 d = util.parsedate(date)
1955 d = util.parsedate(date)
1949 ui.write(("internal: %s %s\n") % d)
1956 ui.write(("internal: %s %s\n") % d)
1950 ui.write(("standard: %s\n") % util.datestr(d))
1957 ui.write(("standard: %s\n") % util.datestr(d))
1951 if range:
1958 if range:
1952 m = util.matchdate(range)
1959 m = util.matchdate(range)
1953 ui.write(("match: %s\n") % m(d[0]))
1960 ui.write(("match: %s\n") % m(d[0]))
1954
1961
1955 @command('debugdiscovery',
1962 @command('debugdiscovery',
1956 [('', 'old', None, _('use old-style discovery')),
1963 [('', 'old', None, _('use old-style discovery')),
1957 ('', 'nonheads', None,
1964 ('', 'nonheads', None,
1958 _('use old-style discovery with non-heads included')),
1965 _('use old-style discovery with non-heads included')),
1959 ] + remoteopts,
1966 ] + remoteopts,
1960 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1967 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1961 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1968 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1962 """runs the changeset discovery protocol in isolation"""
1969 """runs the changeset discovery protocol in isolation"""
1963 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1970 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1964 opts.get('branch'))
1971 opts.get('branch'))
1965 remote = hg.peer(repo, opts, remoteurl)
1972 remote = hg.peer(repo, opts, remoteurl)
1966 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1973 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1967
1974
1968 # make sure tests are repeatable
1975 # make sure tests are repeatable
1969 random.seed(12323)
1976 random.seed(12323)
1970
1977
1971 def doit(localheads, remoteheads, remote=remote):
1978 def doit(localheads, remoteheads, remote=remote):
1972 if opts.get('old'):
1979 if opts.get('old'):
1973 if localheads:
1980 if localheads:
1974 raise util.Abort('cannot use localheads with old style '
1981 raise util.Abort('cannot use localheads with old style '
1975 'discovery')
1982 'discovery')
1976 if not util.safehasattr(remote, 'branches'):
1983 if not util.safehasattr(remote, 'branches'):
1977 # enable in-client legacy support
1984 # enable in-client legacy support
1978 remote = localrepo.locallegacypeer(remote.local())
1985 remote = localrepo.locallegacypeer(remote.local())
1979 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1986 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1980 force=True)
1987 force=True)
1981 common = set(common)
1988 common = set(common)
1982 if not opts.get('nonheads'):
1989 if not opts.get('nonheads'):
1983 ui.write(("unpruned common: %s\n") %
1990 ui.write(("unpruned common: %s\n") %
1984 " ".join(sorted(short(n) for n in common)))
1991 " ".join(sorted(short(n) for n in common)))
1985 dag = dagutil.revlogdag(repo.changelog)
1992 dag = dagutil.revlogdag(repo.changelog)
1986 all = dag.ancestorset(dag.internalizeall(common))
1993 all = dag.ancestorset(dag.internalizeall(common))
1987 common = dag.externalizeall(dag.headsetofconnecteds(all))
1994 common = dag.externalizeall(dag.headsetofconnecteds(all))
1988 else:
1995 else:
1989 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1996 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1990 common = set(common)
1997 common = set(common)
1991 rheads = set(hds)
1998 rheads = set(hds)
1992 lheads = set(repo.heads())
1999 lheads = set(repo.heads())
1993 ui.write(("common heads: %s\n") %
2000 ui.write(("common heads: %s\n") %
1994 " ".join(sorted(short(n) for n in common)))
2001 " ".join(sorted(short(n) for n in common)))
1995 if lheads <= common:
2002 if lheads <= common:
1996 ui.write(("local is subset\n"))
2003 ui.write(("local is subset\n"))
1997 elif rheads <= common:
2004 elif rheads <= common:
1998 ui.write(("remote is subset\n"))
2005 ui.write(("remote is subset\n"))
1999
2006
2000 serverlogs = opts.get('serverlog')
2007 serverlogs = opts.get('serverlog')
2001 if serverlogs:
2008 if serverlogs:
2002 for filename in serverlogs:
2009 for filename in serverlogs:
2003 logfile = open(filename, 'r')
2010 logfile = open(filename, 'r')
2004 try:
2011 try:
2005 line = logfile.readline()
2012 line = logfile.readline()
2006 while line:
2013 while line:
2007 parts = line.strip().split(';')
2014 parts = line.strip().split(';')
2008 op = parts[1]
2015 op = parts[1]
2009 if op == 'cg':
2016 if op == 'cg':
2010 pass
2017 pass
2011 elif op == 'cgss':
2018 elif op == 'cgss':
2012 doit(parts[2].split(' '), parts[3].split(' '))
2019 doit(parts[2].split(' '), parts[3].split(' '))
2013 elif op == 'unb':
2020 elif op == 'unb':
2014 doit(parts[3].split(' '), parts[2].split(' '))
2021 doit(parts[3].split(' '), parts[2].split(' '))
2015 line = logfile.readline()
2022 line = logfile.readline()
2016 finally:
2023 finally:
2017 logfile.close()
2024 logfile.close()
2018
2025
2019 else:
2026 else:
2020 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2027 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2021 opts.get('remote_head'))
2028 opts.get('remote_head'))
2022 localrevs = opts.get('local_head')
2029 localrevs = opts.get('local_head')
2023 doit(localrevs, remoterevs)
2030 doit(localrevs, remoterevs)
2024
2031
2025 @command('debugfileset',
2032 @command('debugfileset',
2026 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2033 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2027 _('[-r REV] FILESPEC'))
2034 _('[-r REV] FILESPEC'))
2028 def debugfileset(ui, repo, expr, **opts):
2035 def debugfileset(ui, repo, expr, **opts):
2029 '''parse and apply a fileset specification'''
2036 '''parse and apply a fileset specification'''
2030 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2037 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2031 if ui.verbose:
2038 if ui.verbose:
2032 tree = fileset.parse(expr)[0]
2039 tree = fileset.parse(expr)[0]
2033 ui.note(tree, "\n")
2040 ui.note(tree, "\n")
2034
2041
2035 for f in ctx.getfileset(expr):
2042 for f in ctx.getfileset(expr):
2036 ui.write("%s\n" % f)
2043 ui.write("%s\n" % f)
2037
2044
2038 @command('debugfsinfo', [], _('[PATH]'))
2045 @command('debugfsinfo', [], _('[PATH]'))
2039 def debugfsinfo(ui, path="."):
2046 def debugfsinfo(ui, path="."):
2040 """show information detected about current filesystem"""
2047 """show information detected about current filesystem"""
2041 util.writefile('.debugfsinfo', '')
2048 util.writefile('.debugfsinfo', '')
2042 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2049 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2043 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2050 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2044 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2051 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2045 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2052 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2046 and 'yes' or 'no'))
2053 and 'yes' or 'no'))
2047 os.unlink('.debugfsinfo')
2054 os.unlink('.debugfsinfo')
2048
2055
2049 @command('debuggetbundle',
2056 @command('debuggetbundle',
2050 [('H', 'head', [], _('id of head node'), _('ID')),
2057 [('H', 'head', [], _('id of head node'), _('ID')),
2051 ('C', 'common', [], _('id of common node'), _('ID')),
2058 ('C', 'common', [], _('id of common node'), _('ID')),
2052 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2059 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2053 _('REPO FILE [-H|-C ID]...'))
2060 _('REPO FILE [-H|-C ID]...'))
2054 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2061 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2055 """retrieves a bundle from a repo
2062 """retrieves a bundle from a repo
2056
2063
2057 Every ID must be a full-length hex node id string. Saves the bundle to the
2064 Every ID must be a full-length hex node id string. Saves the bundle to the
2058 given file.
2065 given file.
2059 """
2066 """
2060 repo = hg.peer(ui, opts, repopath)
2067 repo = hg.peer(ui, opts, repopath)
2061 if not repo.capable('getbundle'):
2068 if not repo.capable('getbundle'):
2062 raise util.Abort("getbundle() not supported by target repository")
2069 raise util.Abort("getbundle() not supported by target repository")
2063 args = {}
2070 args = {}
2064 if common:
2071 if common:
2065 args['common'] = [bin(s) for s in common]
2072 args['common'] = [bin(s) for s in common]
2066 if head:
2073 if head:
2067 args['heads'] = [bin(s) for s in head]
2074 args['heads'] = [bin(s) for s in head]
2068 # TODO: get desired bundlecaps from command line.
2075 # TODO: get desired bundlecaps from command line.
2069 args['bundlecaps'] = None
2076 args['bundlecaps'] = None
2070 bundle = repo.getbundle('debug', **args)
2077 bundle = repo.getbundle('debug', **args)
2071
2078
2072 bundletype = opts.get('type', 'bzip2').lower()
2079 bundletype = opts.get('type', 'bzip2').lower()
2073 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2080 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2074 bundletype = btypes.get(bundletype)
2081 bundletype = btypes.get(bundletype)
2075 if bundletype not in changegroup.bundletypes:
2082 if bundletype not in changegroup.bundletypes:
2076 raise util.Abort(_('unknown bundle type specified with --type'))
2083 raise util.Abort(_('unknown bundle type specified with --type'))
2077 changegroup.writebundle(bundle, bundlepath, bundletype)
2084 changegroup.writebundle(bundle, bundlepath, bundletype)
2078
2085
2079 @command('debugignore', [], '')
2086 @command('debugignore', [], '')
2080 def debugignore(ui, repo, *values, **opts):
2087 def debugignore(ui, repo, *values, **opts):
2081 """display the combined ignore pattern"""
2088 """display the combined ignore pattern"""
2082 ignore = repo.dirstate._ignore
2089 ignore = repo.dirstate._ignore
2083 includepat = getattr(ignore, 'includepat', None)
2090 includepat = getattr(ignore, 'includepat', None)
2084 if includepat is not None:
2091 if includepat is not None:
2085 ui.write("%s\n" % includepat)
2092 ui.write("%s\n" % includepat)
2086 else:
2093 else:
2087 raise util.Abort(_("no ignore patterns found"))
2094 raise util.Abort(_("no ignore patterns found"))
2088
2095
2089 @command('debugindex',
2096 @command('debugindex',
2090 [('c', 'changelog', False, _('open changelog')),
2097 [('c', 'changelog', False, _('open changelog')),
2091 ('m', 'manifest', False, _('open manifest')),
2098 ('m', 'manifest', False, _('open manifest')),
2092 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2099 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2093 _('[-f FORMAT] -c|-m|FILE'))
2100 _('[-f FORMAT] -c|-m|FILE'))
2094 def debugindex(ui, repo, file_=None, **opts):
2101 def debugindex(ui, repo, file_=None, **opts):
2095 """dump the contents of an index file"""
2102 """dump the contents of an index file"""
2096 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2103 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2097 format = opts.get('format', 0)
2104 format = opts.get('format', 0)
2098 if format not in (0, 1):
2105 if format not in (0, 1):
2099 raise util.Abort(_("unknown format %d") % format)
2106 raise util.Abort(_("unknown format %d") % format)
2100
2107
2101 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2108 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2102 if generaldelta:
2109 if generaldelta:
2103 basehdr = ' delta'
2110 basehdr = ' delta'
2104 else:
2111 else:
2105 basehdr = ' base'
2112 basehdr = ' base'
2106
2113
2107 if format == 0:
2114 if format == 0:
2108 ui.write(" rev offset length " + basehdr + " linkrev"
2115 ui.write(" rev offset length " + basehdr + " linkrev"
2109 " nodeid p1 p2\n")
2116 " nodeid p1 p2\n")
2110 elif format == 1:
2117 elif format == 1:
2111 ui.write(" rev flag offset length"
2118 ui.write(" rev flag offset length"
2112 " size " + basehdr + " link p1 p2"
2119 " size " + basehdr + " link p1 p2"
2113 " nodeid\n")
2120 " nodeid\n")
2114
2121
2115 for i in r:
2122 for i in r:
2116 node = r.node(i)
2123 node = r.node(i)
2117 if generaldelta:
2124 if generaldelta:
2118 base = r.deltaparent(i)
2125 base = r.deltaparent(i)
2119 else:
2126 else:
2120 base = r.chainbase(i)
2127 base = r.chainbase(i)
2121 if format == 0:
2128 if format == 0:
2122 try:
2129 try:
2123 pp = r.parents(node)
2130 pp = r.parents(node)
2124 except Exception:
2131 except Exception:
2125 pp = [nullid, nullid]
2132 pp = [nullid, nullid]
2126 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2133 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2127 i, r.start(i), r.length(i), base, r.linkrev(i),
2134 i, r.start(i), r.length(i), base, r.linkrev(i),
2128 short(node), short(pp[0]), short(pp[1])))
2135 short(node), short(pp[0]), short(pp[1])))
2129 elif format == 1:
2136 elif format == 1:
2130 pr = r.parentrevs(i)
2137 pr = r.parentrevs(i)
2131 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2138 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2132 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2139 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2133 base, r.linkrev(i), pr[0], pr[1], short(node)))
2140 base, r.linkrev(i), pr[0], pr[1], short(node)))
2134
2141
2135 @command('debugindexdot', [], _('FILE'))
2142 @command('debugindexdot', [], _('FILE'))
2136 def debugindexdot(ui, repo, file_):
2143 def debugindexdot(ui, repo, file_):
2137 """dump an index DAG as a graphviz dot file"""
2144 """dump an index DAG as a graphviz dot file"""
2138 r = None
2145 r = None
2139 if repo:
2146 if repo:
2140 filelog = repo.file(file_)
2147 filelog = repo.file(file_)
2141 if len(filelog):
2148 if len(filelog):
2142 r = filelog
2149 r = filelog
2143 if not r:
2150 if not r:
2144 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2151 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2145 ui.write(("digraph G {\n"))
2152 ui.write(("digraph G {\n"))
2146 for i in r:
2153 for i in r:
2147 node = r.node(i)
2154 node = r.node(i)
2148 pp = r.parents(node)
2155 pp = r.parents(node)
2149 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2156 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2150 if pp[1] != nullid:
2157 if pp[1] != nullid:
2151 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2158 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2152 ui.write("}\n")
2159 ui.write("}\n")
2153
2160
2154 @command('debuginstall', [], '')
2161 @command('debuginstall', [], '')
2155 def debuginstall(ui):
2162 def debuginstall(ui):
2156 '''test Mercurial installation
2163 '''test Mercurial installation
2157
2164
2158 Returns 0 on success.
2165 Returns 0 on success.
2159 '''
2166 '''
2160
2167
2161 def writetemp(contents):
2168 def writetemp(contents):
2162 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2169 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2163 f = os.fdopen(fd, "wb")
2170 f = os.fdopen(fd, "wb")
2164 f.write(contents)
2171 f.write(contents)
2165 f.close()
2172 f.close()
2166 return name
2173 return name
2167
2174
2168 problems = 0
2175 problems = 0
2169
2176
2170 # encoding
2177 # encoding
2171 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2178 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2172 try:
2179 try:
2173 encoding.fromlocal("test")
2180 encoding.fromlocal("test")
2174 except util.Abort, inst:
2181 except util.Abort, inst:
2175 ui.write(" %s\n" % inst)
2182 ui.write(" %s\n" % inst)
2176 ui.write(_(" (check that your locale is properly set)\n"))
2183 ui.write(_(" (check that your locale is properly set)\n"))
2177 problems += 1
2184 problems += 1
2178
2185
2179 # Python
2186 # Python
2180 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2187 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2181 ui.status(_("checking Python version (%s)\n")
2188 ui.status(_("checking Python version (%s)\n")
2182 % ("%s.%s.%s" % sys.version_info[:3]))
2189 % ("%s.%s.%s" % sys.version_info[:3]))
2183 ui.status(_("checking Python lib (%s)...\n")
2190 ui.status(_("checking Python lib (%s)...\n")
2184 % os.path.dirname(os.__file__))
2191 % os.path.dirname(os.__file__))
2185
2192
2186 # compiled modules
2193 # compiled modules
2187 ui.status(_("checking installed modules (%s)...\n")
2194 ui.status(_("checking installed modules (%s)...\n")
2188 % os.path.dirname(__file__))
2195 % os.path.dirname(__file__))
2189 try:
2196 try:
2190 import bdiff, mpatch, base85, osutil
2197 import bdiff, mpatch, base85, osutil
2191 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2198 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2192 except Exception, inst:
2199 except Exception, inst:
2193 ui.write(" %s\n" % inst)
2200 ui.write(" %s\n" % inst)
2194 ui.write(_(" One or more extensions could not be found"))
2201 ui.write(_(" One or more extensions could not be found"))
2195 ui.write(_(" (check that you compiled the extensions)\n"))
2202 ui.write(_(" (check that you compiled the extensions)\n"))
2196 problems += 1
2203 problems += 1
2197
2204
2198 # templates
2205 # templates
2199 import templater
2206 import templater
2200 p = templater.templatepath()
2207 p = templater.templatepath()
2201 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2208 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2202 if p:
2209 if p:
2203 m = templater.templatepath("map-cmdline.default")
2210 m = templater.templatepath("map-cmdline.default")
2204 if m:
2211 if m:
2205 # template found, check if it is working
2212 # template found, check if it is working
2206 try:
2213 try:
2207 templater.templater(m)
2214 templater.templater(m)
2208 except Exception, inst:
2215 except Exception, inst:
2209 ui.write(" %s\n" % inst)
2216 ui.write(" %s\n" % inst)
2210 p = None
2217 p = None
2211 else:
2218 else:
2212 ui.write(_(" template 'default' not found\n"))
2219 ui.write(_(" template 'default' not found\n"))
2213 p = None
2220 p = None
2214 else:
2221 else:
2215 ui.write(_(" no template directories found\n"))
2222 ui.write(_(" no template directories found\n"))
2216 if not p:
2223 if not p:
2217 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2224 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2218 problems += 1
2225 problems += 1
2219
2226
2220 # editor
2227 # editor
2221 ui.status(_("checking commit editor...\n"))
2228 ui.status(_("checking commit editor...\n"))
2222 editor = ui.geteditor()
2229 editor = ui.geteditor()
2223 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2230 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2224 if not cmdpath:
2231 if not cmdpath:
2225 if editor == 'vi':
2232 if editor == 'vi':
2226 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2233 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2227 ui.write(_(" (specify a commit editor in your configuration"
2234 ui.write(_(" (specify a commit editor in your configuration"
2228 " file)\n"))
2235 " file)\n"))
2229 else:
2236 else:
2230 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2237 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2231 ui.write(_(" (specify a commit editor in your configuration"
2238 ui.write(_(" (specify a commit editor in your configuration"
2232 " file)\n"))
2239 " file)\n"))
2233 problems += 1
2240 problems += 1
2234
2241
2235 # check username
2242 # check username
2236 ui.status(_("checking username...\n"))
2243 ui.status(_("checking username...\n"))
2237 try:
2244 try:
2238 ui.username()
2245 ui.username()
2239 except util.Abort, e:
2246 except util.Abort, e:
2240 ui.write(" %s\n" % e)
2247 ui.write(" %s\n" % e)
2241 ui.write(_(" (specify a username in your configuration file)\n"))
2248 ui.write(_(" (specify a username in your configuration file)\n"))
2242 problems += 1
2249 problems += 1
2243
2250
2244 if not problems:
2251 if not problems:
2245 ui.status(_("no problems detected\n"))
2252 ui.status(_("no problems detected\n"))
2246 else:
2253 else:
2247 ui.write(_("%s problems detected,"
2254 ui.write(_("%s problems detected,"
2248 " please check your install!\n") % problems)
2255 " please check your install!\n") % problems)
2249
2256
2250 return problems
2257 return problems
2251
2258
2252 @command('debugknown', [], _('REPO ID...'))
2259 @command('debugknown', [], _('REPO ID...'))
2253 def debugknown(ui, repopath, *ids, **opts):
2260 def debugknown(ui, repopath, *ids, **opts):
2254 """test whether node ids are known to a repo
2261 """test whether node ids are known to a repo
2255
2262
2256 Every ID must be a full-length hex node id string. Returns a list of 0s
2263 Every ID must be a full-length hex node id string. Returns a list of 0s
2257 and 1s indicating unknown/known.
2264 and 1s indicating unknown/known.
2258 """
2265 """
2259 repo = hg.peer(ui, opts, repopath)
2266 repo = hg.peer(ui, opts, repopath)
2260 if not repo.capable('known'):
2267 if not repo.capable('known'):
2261 raise util.Abort("known() not supported by target repository")
2268 raise util.Abort("known() not supported by target repository")
2262 flags = repo.known([bin(s) for s in ids])
2269 flags = repo.known([bin(s) for s in ids])
2263 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2270 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2264
2271
2265 @command('debuglabelcomplete', [], _('LABEL...'))
2272 @command('debuglabelcomplete', [], _('LABEL...'))
2266 def debuglabelcomplete(ui, repo, *args):
2273 def debuglabelcomplete(ui, repo, *args):
2267 '''complete "labels" - tags, open branch names, bookmark names'''
2274 '''complete "labels" - tags, open branch names, bookmark names'''
2268
2275
2269 labels = set()
2276 labels = set()
2270 labels.update(t[0] for t in repo.tagslist())
2277 labels.update(t[0] for t in repo.tagslist())
2271 labels.update(repo._bookmarks.keys())
2278 labels.update(repo._bookmarks.keys())
2272 labels.update(tag for (tag, heads, tip, closed)
2279 labels.update(tag for (tag, heads, tip, closed)
2273 in repo.branchmap().iterbranches() if not closed)
2280 in repo.branchmap().iterbranches() if not closed)
2274 completions = set()
2281 completions = set()
2275 if not args:
2282 if not args:
2276 args = ['']
2283 args = ['']
2277 for a in args:
2284 for a in args:
2278 completions.update(l for l in labels if l.startswith(a))
2285 completions.update(l for l in labels if l.startswith(a))
2279 ui.write('\n'.join(sorted(completions)))
2286 ui.write('\n'.join(sorted(completions)))
2280 ui.write('\n')
2287 ui.write('\n')
2281
2288
2282 @command('debugobsolete',
2289 @command('debugobsolete',
2283 [('', 'flags', 0, _('markers flag')),
2290 [('', 'flags', 0, _('markers flag')),
2284 ] + commitopts2,
2291 ] + commitopts2,
2285 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2292 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2286 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2293 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2287 """create arbitrary obsolete marker
2294 """create arbitrary obsolete marker
2288
2295
2289 With no arguments, displays the list of obsolescence markers."""
2296 With no arguments, displays the list of obsolescence markers."""
2290 def parsenodeid(s):
2297 def parsenodeid(s):
2291 try:
2298 try:
2292 # We do not use revsingle/revrange functions here to accept
2299 # We do not use revsingle/revrange functions here to accept
2293 # arbitrary node identifiers, possibly not present in the
2300 # arbitrary node identifiers, possibly not present in the
2294 # local repository.
2301 # local repository.
2295 n = bin(s)
2302 n = bin(s)
2296 if len(n) != len(nullid):
2303 if len(n) != len(nullid):
2297 raise TypeError()
2304 raise TypeError()
2298 return n
2305 return n
2299 except TypeError:
2306 except TypeError:
2300 raise util.Abort('changeset references must be full hexadecimal '
2307 raise util.Abort('changeset references must be full hexadecimal '
2301 'node identifiers')
2308 'node identifiers')
2302
2309
2303 if precursor is not None:
2310 if precursor is not None:
2304 metadata = {}
2311 metadata = {}
2305 if 'date' in opts:
2312 if 'date' in opts:
2306 metadata['date'] = opts['date']
2313 metadata['date'] = opts['date']
2307 metadata['user'] = opts['user'] or ui.username()
2314 metadata['user'] = opts['user'] or ui.username()
2308 succs = tuple(parsenodeid(succ) for succ in successors)
2315 succs = tuple(parsenodeid(succ) for succ in successors)
2309 l = repo.lock()
2316 l = repo.lock()
2310 try:
2317 try:
2311 tr = repo.transaction('debugobsolete')
2318 tr = repo.transaction('debugobsolete')
2312 try:
2319 try:
2313 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2320 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2314 opts['flags'], metadata)
2321 opts['flags'], metadata)
2315 tr.close()
2322 tr.close()
2316 finally:
2323 finally:
2317 tr.release()
2324 tr.release()
2318 finally:
2325 finally:
2319 l.release()
2326 l.release()
2320 else:
2327 else:
2321 for m in obsolete.allmarkers(repo):
2328 for m in obsolete.allmarkers(repo):
2322 cmdutil.showmarker(ui, m)
2329 cmdutil.showmarker(ui, m)
2323
2330
2324 @command('debugpathcomplete',
2331 @command('debugpathcomplete',
2325 [('f', 'full', None, _('complete an entire path')),
2332 [('f', 'full', None, _('complete an entire path')),
2326 ('n', 'normal', None, _('show only normal files')),
2333 ('n', 'normal', None, _('show only normal files')),
2327 ('a', 'added', None, _('show only added files')),
2334 ('a', 'added', None, _('show only added files')),
2328 ('r', 'removed', None, _('show only removed files'))],
2335 ('r', 'removed', None, _('show only removed files'))],
2329 _('FILESPEC...'))
2336 _('FILESPEC...'))
2330 def debugpathcomplete(ui, repo, *specs, **opts):
2337 def debugpathcomplete(ui, repo, *specs, **opts):
2331 '''complete part or all of a tracked path
2338 '''complete part or all of a tracked path
2332
2339
2333 This command supports shells that offer path name completion. It
2340 This command supports shells that offer path name completion. It
2334 currently completes only files already known to the dirstate.
2341 currently completes only files already known to the dirstate.
2335
2342
2336 Completion extends only to the next path segment unless
2343 Completion extends only to the next path segment unless
2337 --full is specified, in which case entire paths are used.'''
2344 --full is specified, in which case entire paths are used.'''
2338
2345
2339 def complete(path, acceptable):
2346 def complete(path, acceptable):
2340 dirstate = repo.dirstate
2347 dirstate = repo.dirstate
2341 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2348 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2342 rootdir = repo.root + os.sep
2349 rootdir = repo.root + os.sep
2343 if spec != repo.root and not spec.startswith(rootdir):
2350 if spec != repo.root and not spec.startswith(rootdir):
2344 return [], []
2351 return [], []
2345 if os.path.isdir(spec):
2352 if os.path.isdir(spec):
2346 spec += '/'
2353 spec += '/'
2347 spec = spec[len(rootdir):]
2354 spec = spec[len(rootdir):]
2348 fixpaths = os.sep != '/'
2355 fixpaths = os.sep != '/'
2349 if fixpaths:
2356 if fixpaths:
2350 spec = spec.replace(os.sep, '/')
2357 spec = spec.replace(os.sep, '/')
2351 speclen = len(spec)
2358 speclen = len(spec)
2352 fullpaths = opts['full']
2359 fullpaths = opts['full']
2353 files, dirs = set(), set()
2360 files, dirs = set(), set()
2354 adddir, addfile = dirs.add, files.add
2361 adddir, addfile = dirs.add, files.add
2355 for f, st in dirstate.iteritems():
2362 for f, st in dirstate.iteritems():
2356 if f.startswith(spec) and st[0] in acceptable:
2363 if f.startswith(spec) and st[0] in acceptable:
2357 if fixpaths:
2364 if fixpaths:
2358 f = f.replace('/', os.sep)
2365 f = f.replace('/', os.sep)
2359 if fullpaths:
2366 if fullpaths:
2360 addfile(f)
2367 addfile(f)
2361 continue
2368 continue
2362 s = f.find(os.sep, speclen)
2369 s = f.find(os.sep, speclen)
2363 if s >= 0:
2370 if s >= 0:
2364 adddir(f[:s])
2371 adddir(f[:s])
2365 else:
2372 else:
2366 addfile(f)
2373 addfile(f)
2367 return files, dirs
2374 return files, dirs
2368
2375
2369 acceptable = ''
2376 acceptable = ''
2370 if opts['normal']:
2377 if opts['normal']:
2371 acceptable += 'nm'
2378 acceptable += 'nm'
2372 if opts['added']:
2379 if opts['added']:
2373 acceptable += 'a'
2380 acceptable += 'a'
2374 if opts['removed']:
2381 if opts['removed']:
2375 acceptable += 'r'
2382 acceptable += 'r'
2376 cwd = repo.getcwd()
2383 cwd = repo.getcwd()
2377 if not specs:
2384 if not specs:
2378 specs = ['.']
2385 specs = ['.']
2379
2386
2380 files, dirs = set(), set()
2387 files, dirs = set(), set()
2381 for spec in specs:
2388 for spec in specs:
2382 f, d = complete(spec, acceptable or 'nmar')
2389 f, d = complete(spec, acceptable or 'nmar')
2383 files.update(f)
2390 files.update(f)
2384 dirs.update(d)
2391 dirs.update(d)
2385 files.update(dirs)
2392 files.update(dirs)
2386 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2393 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2387 ui.write('\n')
2394 ui.write('\n')
2388
2395
2389 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2396 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2390 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2397 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2391 '''access the pushkey key/value protocol
2398 '''access the pushkey key/value protocol
2392
2399
2393 With two args, list the keys in the given namespace.
2400 With two args, list the keys in the given namespace.
2394
2401
2395 With five args, set a key to new if it currently is set to old.
2402 With five args, set a key to new if it currently is set to old.
2396 Reports success or failure.
2403 Reports success or failure.
2397 '''
2404 '''
2398
2405
2399 target = hg.peer(ui, {}, repopath)
2406 target = hg.peer(ui, {}, repopath)
2400 if keyinfo:
2407 if keyinfo:
2401 key, old, new = keyinfo
2408 key, old, new = keyinfo
2402 r = target.pushkey(namespace, key, old, new)
2409 r = target.pushkey(namespace, key, old, new)
2403 ui.status(str(r) + '\n')
2410 ui.status(str(r) + '\n')
2404 return not r
2411 return not r
2405 else:
2412 else:
2406 for k, v in sorted(target.listkeys(namespace).iteritems()):
2413 for k, v in sorted(target.listkeys(namespace).iteritems()):
2407 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2414 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2408 v.encode('string-escape')))
2415 v.encode('string-escape')))
2409
2416
2410 @command('debugpvec', [], _('A B'))
2417 @command('debugpvec', [], _('A B'))
2411 def debugpvec(ui, repo, a, b=None):
2418 def debugpvec(ui, repo, a, b=None):
2412 ca = scmutil.revsingle(repo, a)
2419 ca = scmutil.revsingle(repo, a)
2413 cb = scmutil.revsingle(repo, b)
2420 cb = scmutil.revsingle(repo, b)
2414 pa = pvec.ctxpvec(ca)
2421 pa = pvec.ctxpvec(ca)
2415 pb = pvec.ctxpvec(cb)
2422 pb = pvec.ctxpvec(cb)
2416 if pa == pb:
2423 if pa == pb:
2417 rel = "="
2424 rel = "="
2418 elif pa > pb:
2425 elif pa > pb:
2419 rel = ">"
2426 rel = ">"
2420 elif pa < pb:
2427 elif pa < pb:
2421 rel = "<"
2428 rel = "<"
2422 elif pa | pb:
2429 elif pa | pb:
2423 rel = "|"
2430 rel = "|"
2424 ui.write(_("a: %s\n") % pa)
2431 ui.write(_("a: %s\n") % pa)
2425 ui.write(_("b: %s\n") % pb)
2432 ui.write(_("b: %s\n") % pb)
2426 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2433 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2427 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2434 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2428 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2435 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2429 pa.distance(pb), rel))
2436 pa.distance(pb), rel))
2430
2437
2431 @command('debugrebuilddirstate|debugrebuildstate',
2438 @command('debugrebuilddirstate|debugrebuildstate',
2432 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2439 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2433 _('[-r REV]'))
2440 _('[-r REV]'))
2434 def debugrebuilddirstate(ui, repo, rev):
2441 def debugrebuilddirstate(ui, repo, rev):
2435 """rebuild the dirstate as it would look like for the given revision
2442 """rebuild the dirstate as it would look like for the given revision
2436
2443
2437 If no revision is specified the first current parent will be used.
2444 If no revision is specified the first current parent will be used.
2438
2445
2439 The dirstate will be set to the files of the given revision.
2446 The dirstate will be set to the files of the given revision.
2440 The actual working directory content or existing dirstate
2447 The actual working directory content or existing dirstate
2441 information such as adds or removes is not considered.
2448 information such as adds or removes is not considered.
2442
2449
2443 One use of this command is to make the next :hg:`status` invocation
2450 One use of this command is to make the next :hg:`status` invocation
2444 check the actual file content.
2451 check the actual file content.
2445 """
2452 """
2446 ctx = scmutil.revsingle(repo, rev)
2453 ctx = scmutil.revsingle(repo, rev)
2447 wlock = repo.wlock()
2454 wlock = repo.wlock()
2448 try:
2455 try:
2449 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2456 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2450 finally:
2457 finally:
2451 wlock.release()
2458 wlock.release()
2452
2459
2453 @command('debugrename',
2460 @command('debugrename',
2454 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2461 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2455 _('[-r REV] FILE'))
2462 _('[-r REV] FILE'))
2456 def debugrename(ui, repo, file1, *pats, **opts):
2463 def debugrename(ui, repo, file1, *pats, **opts):
2457 """dump rename information"""
2464 """dump rename information"""
2458
2465
2459 ctx = scmutil.revsingle(repo, opts.get('rev'))
2466 ctx = scmutil.revsingle(repo, opts.get('rev'))
2460 m = scmutil.match(ctx, (file1,) + pats, opts)
2467 m = scmutil.match(ctx, (file1,) + pats, opts)
2461 for abs in ctx.walk(m):
2468 for abs in ctx.walk(m):
2462 fctx = ctx[abs]
2469 fctx = ctx[abs]
2463 o = fctx.filelog().renamed(fctx.filenode())
2470 o = fctx.filelog().renamed(fctx.filenode())
2464 rel = m.rel(abs)
2471 rel = m.rel(abs)
2465 if o:
2472 if o:
2466 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2473 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2467 else:
2474 else:
2468 ui.write(_("%s not renamed\n") % rel)
2475 ui.write(_("%s not renamed\n") % rel)
2469
2476
2470 @command('debugrevlog',
2477 @command('debugrevlog',
2471 [('c', 'changelog', False, _('open changelog')),
2478 [('c', 'changelog', False, _('open changelog')),
2472 ('m', 'manifest', False, _('open manifest')),
2479 ('m', 'manifest', False, _('open manifest')),
2473 ('d', 'dump', False, _('dump index data'))],
2480 ('d', 'dump', False, _('dump index data'))],
2474 _('-c|-m|FILE'))
2481 _('-c|-m|FILE'))
2475 def debugrevlog(ui, repo, file_=None, **opts):
2482 def debugrevlog(ui, repo, file_=None, **opts):
2476 """show data and statistics about a revlog"""
2483 """show data and statistics about a revlog"""
2477 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2484 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2478
2485
2479 if opts.get("dump"):
2486 if opts.get("dump"):
2480 numrevs = len(r)
2487 numrevs = len(r)
2481 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2488 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2482 " rawsize totalsize compression heads\n")
2489 " rawsize totalsize compression heads\n")
2483 ts = 0
2490 ts = 0
2484 heads = set()
2491 heads = set()
2485 for rev in xrange(numrevs):
2492 for rev in xrange(numrevs):
2486 dbase = r.deltaparent(rev)
2493 dbase = r.deltaparent(rev)
2487 if dbase == -1:
2494 if dbase == -1:
2488 dbase = rev
2495 dbase = rev
2489 cbase = r.chainbase(rev)
2496 cbase = r.chainbase(rev)
2490 p1, p2 = r.parentrevs(rev)
2497 p1, p2 = r.parentrevs(rev)
2491 rs = r.rawsize(rev)
2498 rs = r.rawsize(rev)
2492 ts = ts + rs
2499 ts = ts + rs
2493 heads -= set(r.parentrevs(rev))
2500 heads -= set(r.parentrevs(rev))
2494 heads.add(rev)
2501 heads.add(rev)
2495 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d %11d %5d\n" %
2502 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d %11d %5d\n" %
2496 (rev, p1, p2, r.start(rev), r.end(rev),
2503 (rev, p1, p2, r.start(rev), r.end(rev),
2497 r.start(dbase), r.start(cbase),
2504 r.start(dbase), r.start(cbase),
2498 r.start(p1), r.start(p2),
2505 r.start(p1), r.start(p2),
2499 rs, ts, ts / r.end(rev), len(heads)))
2506 rs, ts, ts / r.end(rev), len(heads)))
2500 return 0
2507 return 0
2501
2508
2502 v = r.version
2509 v = r.version
2503 format = v & 0xFFFF
2510 format = v & 0xFFFF
2504 flags = []
2511 flags = []
2505 gdelta = False
2512 gdelta = False
2506 if v & revlog.REVLOGNGINLINEDATA:
2513 if v & revlog.REVLOGNGINLINEDATA:
2507 flags.append('inline')
2514 flags.append('inline')
2508 if v & revlog.REVLOGGENERALDELTA:
2515 if v & revlog.REVLOGGENERALDELTA:
2509 gdelta = True
2516 gdelta = True
2510 flags.append('generaldelta')
2517 flags.append('generaldelta')
2511 if not flags:
2518 if not flags:
2512 flags = ['(none)']
2519 flags = ['(none)']
2513
2520
2514 nummerges = 0
2521 nummerges = 0
2515 numfull = 0
2522 numfull = 0
2516 numprev = 0
2523 numprev = 0
2517 nump1 = 0
2524 nump1 = 0
2518 nump2 = 0
2525 nump2 = 0
2519 numother = 0
2526 numother = 0
2520 nump1prev = 0
2527 nump1prev = 0
2521 nump2prev = 0
2528 nump2prev = 0
2522 chainlengths = []
2529 chainlengths = []
2523
2530
2524 datasize = [None, 0, 0L]
2531 datasize = [None, 0, 0L]
2525 fullsize = [None, 0, 0L]
2532 fullsize = [None, 0, 0L]
2526 deltasize = [None, 0, 0L]
2533 deltasize = [None, 0, 0L]
2527
2534
2528 def addsize(size, l):
2535 def addsize(size, l):
2529 if l[0] is None or size < l[0]:
2536 if l[0] is None or size < l[0]:
2530 l[0] = size
2537 l[0] = size
2531 if size > l[1]:
2538 if size > l[1]:
2532 l[1] = size
2539 l[1] = size
2533 l[2] += size
2540 l[2] += size
2534
2541
2535 numrevs = len(r)
2542 numrevs = len(r)
2536 for rev in xrange(numrevs):
2543 for rev in xrange(numrevs):
2537 p1, p2 = r.parentrevs(rev)
2544 p1, p2 = r.parentrevs(rev)
2538 delta = r.deltaparent(rev)
2545 delta = r.deltaparent(rev)
2539 if format > 0:
2546 if format > 0:
2540 addsize(r.rawsize(rev), datasize)
2547 addsize(r.rawsize(rev), datasize)
2541 if p2 != nullrev:
2548 if p2 != nullrev:
2542 nummerges += 1
2549 nummerges += 1
2543 size = r.length(rev)
2550 size = r.length(rev)
2544 if delta == nullrev:
2551 if delta == nullrev:
2545 chainlengths.append(0)
2552 chainlengths.append(0)
2546 numfull += 1
2553 numfull += 1
2547 addsize(size, fullsize)
2554 addsize(size, fullsize)
2548 else:
2555 else:
2549 chainlengths.append(chainlengths[delta] + 1)
2556 chainlengths.append(chainlengths[delta] + 1)
2550 addsize(size, deltasize)
2557 addsize(size, deltasize)
2551 if delta == rev - 1:
2558 if delta == rev - 1:
2552 numprev += 1
2559 numprev += 1
2553 if delta == p1:
2560 if delta == p1:
2554 nump1prev += 1
2561 nump1prev += 1
2555 elif delta == p2:
2562 elif delta == p2:
2556 nump2prev += 1
2563 nump2prev += 1
2557 elif delta == p1:
2564 elif delta == p1:
2558 nump1 += 1
2565 nump1 += 1
2559 elif delta == p2:
2566 elif delta == p2:
2560 nump2 += 1
2567 nump2 += 1
2561 elif delta != nullrev:
2568 elif delta != nullrev:
2562 numother += 1
2569 numother += 1
2563
2570
2564 # Adjust size min value for empty cases
2571 # Adjust size min value for empty cases
2565 for size in (datasize, fullsize, deltasize):
2572 for size in (datasize, fullsize, deltasize):
2566 if size[0] is None:
2573 if size[0] is None:
2567 size[0] = 0
2574 size[0] = 0
2568
2575
2569 numdeltas = numrevs - numfull
2576 numdeltas = numrevs - numfull
2570 numoprev = numprev - nump1prev - nump2prev
2577 numoprev = numprev - nump1prev - nump2prev
2571 totalrawsize = datasize[2]
2578 totalrawsize = datasize[2]
2572 datasize[2] /= numrevs
2579 datasize[2] /= numrevs
2573 fulltotal = fullsize[2]
2580 fulltotal = fullsize[2]
2574 fullsize[2] /= numfull
2581 fullsize[2] /= numfull
2575 deltatotal = deltasize[2]
2582 deltatotal = deltasize[2]
2576 if numrevs - numfull > 0:
2583 if numrevs - numfull > 0:
2577 deltasize[2] /= numrevs - numfull
2584 deltasize[2] /= numrevs - numfull
2578 totalsize = fulltotal + deltatotal
2585 totalsize = fulltotal + deltatotal
2579 avgchainlen = sum(chainlengths) / numrevs
2586 avgchainlen = sum(chainlengths) / numrevs
2580 compratio = totalrawsize / totalsize
2587 compratio = totalrawsize / totalsize
2581
2588
2582 basedfmtstr = '%%%dd\n'
2589 basedfmtstr = '%%%dd\n'
2583 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2590 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2584
2591
2585 def dfmtstr(max):
2592 def dfmtstr(max):
2586 return basedfmtstr % len(str(max))
2593 return basedfmtstr % len(str(max))
2587 def pcfmtstr(max, padding=0):
2594 def pcfmtstr(max, padding=0):
2588 return basepcfmtstr % (len(str(max)), ' ' * padding)
2595 return basepcfmtstr % (len(str(max)), ' ' * padding)
2589
2596
2590 def pcfmt(value, total):
2597 def pcfmt(value, total):
2591 return (value, 100 * float(value) / total)
2598 return (value, 100 * float(value) / total)
2592
2599
2593 ui.write(('format : %d\n') % format)
2600 ui.write(('format : %d\n') % format)
2594 ui.write(('flags : %s\n') % ', '.join(flags))
2601 ui.write(('flags : %s\n') % ', '.join(flags))
2595
2602
2596 ui.write('\n')
2603 ui.write('\n')
2597 fmt = pcfmtstr(totalsize)
2604 fmt = pcfmtstr(totalsize)
2598 fmt2 = dfmtstr(totalsize)
2605 fmt2 = dfmtstr(totalsize)
2599 ui.write(('revisions : ') + fmt2 % numrevs)
2606 ui.write(('revisions : ') + fmt2 % numrevs)
2600 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2607 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2601 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2608 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2602 ui.write(('revisions : ') + fmt2 % numrevs)
2609 ui.write(('revisions : ') + fmt2 % numrevs)
2603 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2610 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2604 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2611 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2605 ui.write(('revision size : ') + fmt2 % totalsize)
2612 ui.write(('revision size : ') + fmt2 % totalsize)
2606 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2613 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2607 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2614 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2608
2615
2609 ui.write('\n')
2616 ui.write('\n')
2610 fmt = dfmtstr(max(avgchainlen, compratio))
2617 fmt = dfmtstr(max(avgchainlen, compratio))
2611 ui.write(('avg chain length : ') + fmt % avgchainlen)
2618 ui.write(('avg chain length : ') + fmt % avgchainlen)
2612 ui.write(('compression ratio : ') + fmt % compratio)
2619 ui.write(('compression ratio : ') + fmt % compratio)
2613
2620
2614 if format > 0:
2621 if format > 0:
2615 ui.write('\n')
2622 ui.write('\n')
2616 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2623 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2617 % tuple(datasize))
2624 % tuple(datasize))
2618 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2625 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2619 % tuple(fullsize))
2626 % tuple(fullsize))
2620 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2627 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2621 % tuple(deltasize))
2628 % tuple(deltasize))
2622
2629
2623 if numdeltas > 0:
2630 if numdeltas > 0:
2624 ui.write('\n')
2631 ui.write('\n')
2625 fmt = pcfmtstr(numdeltas)
2632 fmt = pcfmtstr(numdeltas)
2626 fmt2 = pcfmtstr(numdeltas, 4)
2633 fmt2 = pcfmtstr(numdeltas, 4)
2627 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2634 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2628 if numprev > 0:
2635 if numprev > 0:
2629 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2636 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2630 numprev))
2637 numprev))
2631 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2638 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2632 numprev))
2639 numprev))
2633 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2640 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2634 numprev))
2641 numprev))
2635 if gdelta:
2642 if gdelta:
2636 ui.write(('deltas against p1 : ')
2643 ui.write(('deltas against p1 : ')
2637 + fmt % pcfmt(nump1, numdeltas))
2644 + fmt % pcfmt(nump1, numdeltas))
2638 ui.write(('deltas against p2 : ')
2645 ui.write(('deltas against p2 : ')
2639 + fmt % pcfmt(nump2, numdeltas))
2646 + fmt % pcfmt(nump2, numdeltas))
2640 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2647 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2641 numdeltas))
2648 numdeltas))
2642
2649
2643 @command('debugrevspec',
2650 @command('debugrevspec',
2644 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2651 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2645 ('REVSPEC'))
2652 ('REVSPEC'))
2646 def debugrevspec(ui, repo, expr, **opts):
2653 def debugrevspec(ui, repo, expr, **opts):
2647 """parse and apply a revision specification
2654 """parse and apply a revision specification
2648
2655
2649 Use --verbose to print the parsed tree before and after aliases
2656 Use --verbose to print the parsed tree before and after aliases
2650 expansion.
2657 expansion.
2651 """
2658 """
2652 if ui.verbose:
2659 if ui.verbose:
2653 tree = revset.parse(expr)[0]
2660 tree = revset.parse(expr)[0]
2654 ui.note(revset.prettyformat(tree), "\n")
2661 ui.note(revset.prettyformat(tree), "\n")
2655 newtree = revset.findaliases(ui, tree)
2662 newtree = revset.findaliases(ui, tree)
2656 if newtree != tree:
2663 if newtree != tree:
2657 ui.note(revset.prettyformat(newtree), "\n")
2664 ui.note(revset.prettyformat(newtree), "\n")
2658 if opts["optimize"]:
2665 if opts["optimize"]:
2659 weight, optimizedtree = revset.optimize(newtree, True)
2666 weight, optimizedtree = revset.optimize(newtree, True)
2660 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2667 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2661 func = revset.match(ui, expr)
2668 func = revset.match(ui, expr)
2662 for c in func(repo, revset.spanset(repo)):
2669 for c in func(repo, revset.spanset(repo)):
2663 ui.write("%s\n" % c)
2670 ui.write("%s\n" % c)
2664
2671
2665 @command('debugsetparents', [], _('REV1 [REV2]'))
2672 @command('debugsetparents', [], _('REV1 [REV2]'))
2666 def debugsetparents(ui, repo, rev1, rev2=None):
2673 def debugsetparents(ui, repo, rev1, rev2=None):
2667 """manually set the parents of the current working directory
2674 """manually set the parents of the current working directory
2668
2675
2669 This is useful for writing repository conversion tools, but should
2676 This is useful for writing repository conversion tools, but should
2670 be used with care.
2677 be used with care.
2671
2678
2672 Returns 0 on success.
2679 Returns 0 on success.
2673 """
2680 """
2674
2681
2675 r1 = scmutil.revsingle(repo, rev1).node()
2682 r1 = scmutil.revsingle(repo, rev1).node()
2676 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2683 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2677
2684
2678 wlock = repo.wlock()
2685 wlock = repo.wlock()
2679 try:
2686 try:
2680 repo.setparents(r1, r2)
2687 repo.setparents(r1, r2)
2681 finally:
2688 finally:
2682 wlock.release()
2689 wlock.release()
2683
2690
2684 @command('debugdirstate|debugstate',
2691 @command('debugdirstate|debugstate',
2685 [('', 'nodates', None, _('do not display the saved mtime')),
2692 [('', 'nodates', None, _('do not display the saved mtime')),
2686 ('', 'datesort', None, _('sort by saved mtime'))],
2693 ('', 'datesort', None, _('sort by saved mtime'))],
2687 _('[OPTION]...'))
2694 _('[OPTION]...'))
2688 def debugstate(ui, repo, nodates=None, datesort=None):
2695 def debugstate(ui, repo, nodates=None, datesort=None):
2689 """show the contents of the current dirstate"""
2696 """show the contents of the current dirstate"""
2690 timestr = ""
2697 timestr = ""
2691 showdate = not nodates
2698 showdate = not nodates
2692 if datesort:
2699 if datesort:
2693 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2700 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2694 else:
2701 else:
2695 keyfunc = None # sort by filename
2702 keyfunc = None # sort by filename
2696 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2703 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2697 if showdate:
2704 if showdate:
2698 if ent[3] == -1:
2705 if ent[3] == -1:
2699 # Pad or slice to locale representation
2706 # Pad or slice to locale representation
2700 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2707 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2701 time.localtime(0)))
2708 time.localtime(0)))
2702 timestr = 'unset'
2709 timestr = 'unset'
2703 timestr = (timestr[:locale_len] +
2710 timestr = (timestr[:locale_len] +
2704 ' ' * (locale_len - len(timestr)))
2711 ' ' * (locale_len - len(timestr)))
2705 else:
2712 else:
2706 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2713 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2707 time.localtime(ent[3]))
2714 time.localtime(ent[3]))
2708 if ent[1] & 020000:
2715 if ent[1] & 020000:
2709 mode = 'lnk'
2716 mode = 'lnk'
2710 else:
2717 else:
2711 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2718 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2712 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2719 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2713 for f in repo.dirstate.copies():
2720 for f in repo.dirstate.copies():
2714 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2721 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2715
2722
2716 @command('debugsub',
2723 @command('debugsub',
2717 [('r', 'rev', '',
2724 [('r', 'rev', '',
2718 _('revision to check'), _('REV'))],
2725 _('revision to check'), _('REV'))],
2719 _('[-r REV] [REV]'))
2726 _('[-r REV] [REV]'))
2720 def debugsub(ui, repo, rev=None):
2727 def debugsub(ui, repo, rev=None):
2721 ctx = scmutil.revsingle(repo, rev, None)
2728 ctx = scmutil.revsingle(repo, rev, None)
2722 for k, v in sorted(ctx.substate.items()):
2729 for k, v in sorted(ctx.substate.items()):
2723 ui.write(('path %s\n') % k)
2730 ui.write(('path %s\n') % k)
2724 ui.write((' source %s\n') % v[0])
2731 ui.write((' source %s\n') % v[0])
2725 ui.write((' revision %s\n') % v[1])
2732 ui.write((' revision %s\n') % v[1])
2726
2733
2727 @command('debugsuccessorssets',
2734 @command('debugsuccessorssets',
2728 [],
2735 [],
2729 _('[REV]'))
2736 _('[REV]'))
2730 def debugsuccessorssets(ui, repo, *revs):
2737 def debugsuccessorssets(ui, repo, *revs):
2731 """show set of successors for revision
2738 """show set of successors for revision
2732
2739
2733 A successors set of changeset A is a consistent group of revisions that
2740 A successors set of changeset A is a consistent group of revisions that
2734 succeed A. It contains non-obsolete changesets only.
2741 succeed A. It contains non-obsolete changesets only.
2735
2742
2736 In most cases a changeset A has a single successors set containing a single
2743 In most cases a changeset A has a single successors set containing a single
2737 successor (changeset A replaced by A').
2744 successor (changeset A replaced by A').
2738
2745
2739 A changeset that is made obsolete with no successors are called "pruned".
2746 A changeset that is made obsolete with no successors are called "pruned".
2740 Such changesets have no successors sets at all.
2747 Such changesets have no successors sets at all.
2741
2748
2742 A changeset that has been "split" will have a successors set containing
2749 A changeset that has been "split" will have a successors set containing
2743 more than one successor.
2750 more than one successor.
2744
2751
2745 A changeset that has been rewritten in multiple different ways is called
2752 A changeset that has been rewritten in multiple different ways is called
2746 "divergent". Such changesets have multiple successor sets (each of which
2753 "divergent". Such changesets have multiple successor sets (each of which
2747 may also be split, i.e. have multiple successors).
2754 may also be split, i.e. have multiple successors).
2748
2755
2749 Results are displayed as follows::
2756 Results are displayed as follows::
2750
2757
2751 <rev1>
2758 <rev1>
2752 <successors-1A>
2759 <successors-1A>
2753 <rev2>
2760 <rev2>
2754 <successors-2A>
2761 <successors-2A>
2755 <successors-2B1> <successors-2B2> <successors-2B3>
2762 <successors-2B1> <successors-2B2> <successors-2B3>
2756
2763
2757 Here rev2 has two possible (i.e. divergent) successors sets. The first
2764 Here rev2 has two possible (i.e. divergent) successors sets. The first
2758 holds one element, whereas the second holds three (i.e. the changeset has
2765 holds one element, whereas the second holds three (i.e. the changeset has
2759 been split).
2766 been split).
2760 """
2767 """
2761 # passed to successorssets caching computation from one call to another
2768 # passed to successorssets caching computation from one call to another
2762 cache = {}
2769 cache = {}
2763 ctx2str = str
2770 ctx2str = str
2764 node2str = short
2771 node2str = short
2765 if ui.debug():
2772 if ui.debug():
2766 def ctx2str(ctx):
2773 def ctx2str(ctx):
2767 return ctx.hex()
2774 return ctx.hex()
2768 node2str = hex
2775 node2str = hex
2769 for rev in scmutil.revrange(repo, revs):
2776 for rev in scmutil.revrange(repo, revs):
2770 ctx = repo[rev]
2777 ctx = repo[rev]
2771 ui.write('%s\n'% ctx2str(ctx))
2778 ui.write('%s\n'% ctx2str(ctx))
2772 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2779 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2773 if succsset:
2780 if succsset:
2774 ui.write(' ')
2781 ui.write(' ')
2775 ui.write(node2str(succsset[0]))
2782 ui.write(node2str(succsset[0]))
2776 for node in succsset[1:]:
2783 for node in succsset[1:]:
2777 ui.write(' ')
2784 ui.write(' ')
2778 ui.write(node2str(node))
2785 ui.write(node2str(node))
2779 ui.write('\n')
2786 ui.write('\n')
2780
2787
2781 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2788 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2782 def debugwalk(ui, repo, *pats, **opts):
2789 def debugwalk(ui, repo, *pats, **opts):
2783 """show how files match on given patterns"""
2790 """show how files match on given patterns"""
2784 m = scmutil.match(repo[None], pats, opts)
2791 m = scmutil.match(repo[None], pats, opts)
2785 items = list(repo.walk(m))
2792 items = list(repo.walk(m))
2786 if not items:
2793 if not items:
2787 return
2794 return
2788 f = lambda fn: fn
2795 f = lambda fn: fn
2789 if ui.configbool('ui', 'slash') and os.sep != '/':
2796 if ui.configbool('ui', 'slash') and os.sep != '/':
2790 f = lambda fn: util.normpath(fn)
2797 f = lambda fn: util.normpath(fn)
2791 fmt = 'f %%-%ds %%-%ds %%s' % (
2798 fmt = 'f %%-%ds %%-%ds %%s' % (
2792 max([len(abs) for abs in items]),
2799 max([len(abs) for abs in items]),
2793 max([len(m.rel(abs)) for abs in items]))
2800 max([len(m.rel(abs)) for abs in items]))
2794 for abs in items:
2801 for abs in items:
2795 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2802 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2796 ui.write("%s\n" % line.rstrip())
2803 ui.write("%s\n" % line.rstrip())
2797
2804
2798 @command('debugwireargs',
2805 @command('debugwireargs',
2799 [('', 'three', '', 'three'),
2806 [('', 'three', '', 'three'),
2800 ('', 'four', '', 'four'),
2807 ('', 'four', '', 'four'),
2801 ('', 'five', '', 'five'),
2808 ('', 'five', '', 'five'),
2802 ] + remoteopts,
2809 ] + remoteopts,
2803 _('REPO [OPTIONS]... [ONE [TWO]]'))
2810 _('REPO [OPTIONS]... [ONE [TWO]]'))
2804 def debugwireargs(ui, repopath, *vals, **opts):
2811 def debugwireargs(ui, repopath, *vals, **opts):
2805 repo = hg.peer(ui, opts, repopath)
2812 repo = hg.peer(ui, opts, repopath)
2806 for opt in remoteopts:
2813 for opt in remoteopts:
2807 del opts[opt[1]]
2814 del opts[opt[1]]
2808 args = {}
2815 args = {}
2809 for k, v in opts.iteritems():
2816 for k, v in opts.iteritems():
2810 if v:
2817 if v:
2811 args[k] = v
2818 args[k] = v
2812 # run twice to check that we don't mess up the stream for the next command
2819 # run twice to check that we don't mess up the stream for the next command
2813 res1 = repo.debugwireargs(*vals, **args)
2820 res1 = repo.debugwireargs(*vals, **args)
2814 res2 = repo.debugwireargs(*vals, **args)
2821 res2 = repo.debugwireargs(*vals, **args)
2815 ui.write("%s\n" % res1)
2822 ui.write("%s\n" % res1)
2816 if res1 != res2:
2823 if res1 != res2:
2817 ui.warn("%s\n" % res2)
2824 ui.warn("%s\n" % res2)
2818
2825
2819 @command('^diff',
2826 @command('^diff',
2820 [('r', 'rev', [], _('revision'), _('REV')),
2827 [('r', 'rev', [], _('revision'), _('REV')),
2821 ('c', 'change', '', _('change made by revision'), _('REV'))
2828 ('c', 'change', '', _('change made by revision'), _('REV'))
2822 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2829 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2823 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2830 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2824 def diff(ui, repo, *pats, **opts):
2831 def diff(ui, repo, *pats, **opts):
2825 """diff repository (or selected files)
2832 """diff repository (or selected files)
2826
2833
2827 Show differences between revisions for the specified files.
2834 Show differences between revisions for the specified files.
2828
2835
2829 Differences between files are shown using the unified diff format.
2836 Differences between files are shown using the unified diff format.
2830
2837
2831 .. note::
2838 .. note::
2832
2839
2833 diff may generate unexpected results for merges, as it will
2840 diff may generate unexpected results for merges, as it will
2834 default to comparing against the working directory's first
2841 default to comparing against the working directory's first
2835 parent changeset if no revisions are specified.
2842 parent changeset if no revisions are specified.
2836
2843
2837 When two revision arguments are given, then changes are shown
2844 When two revision arguments are given, then changes are shown
2838 between those revisions. If only one revision is specified then
2845 between those revisions. If only one revision is specified then
2839 that revision is compared to the working directory, and, when no
2846 that revision is compared to the working directory, and, when no
2840 revisions are specified, the working directory files are compared
2847 revisions are specified, the working directory files are compared
2841 to its parent.
2848 to its parent.
2842
2849
2843 Alternatively you can specify -c/--change with a revision to see
2850 Alternatively you can specify -c/--change with a revision to see
2844 the changes in that changeset relative to its first parent.
2851 the changes in that changeset relative to its first parent.
2845
2852
2846 Without the -a/--text option, diff will avoid generating diffs of
2853 Without the -a/--text option, diff will avoid generating diffs of
2847 files it detects as binary. With -a, diff will generate a diff
2854 files it detects as binary. With -a, diff will generate a diff
2848 anyway, probably with undesirable results.
2855 anyway, probably with undesirable results.
2849
2856
2850 Use the -g/--git option to generate diffs in the git extended diff
2857 Use the -g/--git option to generate diffs in the git extended diff
2851 format. For more information, read :hg:`help diffs`.
2858 format. For more information, read :hg:`help diffs`.
2852
2859
2853 .. container:: verbose
2860 .. container:: verbose
2854
2861
2855 Examples:
2862 Examples:
2856
2863
2857 - compare a file in the current working directory to its parent::
2864 - compare a file in the current working directory to its parent::
2858
2865
2859 hg diff foo.c
2866 hg diff foo.c
2860
2867
2861 - compare two historical versions of a directory, with rename info::
2868 - compare two historical versions of a directory, with rename info::
2862
2869
2863 hg diff --git -r 1.0:1.2 lib/
2870 hg diff --git -r 1.0:1.2 lib/
2864
2871
2865 - get change stats relative to the last change on some date::
2872 - get change stats relative to the last change on some date::
2866
2873
2867 hg diff --stat -r "date('may 2')"
2874 hg diff --stat -r "date('may 2')"
2868
2875
2869 - diff all newly-added files that contain a keyword::
2876 - diff all newly-added files that contain a keyword::
2870
2877
2871 hg diff "set:added() and grep(GNU)"
2878 hg diff "set:added() and grep(GNU)"
2872
2879
2873 - compare a revision and its parents::
2880 - compare a revision and its parents::
2874
2881
2875 hg diff -c 9353 # compare against first parent
2882 hg diff -c 9353 # compare against first parent
2876 hg diff -r 9353^:9353 # same using revset syntax
2883 hg diff -r 9353^:9353 # same using revset syntax
2877 hg diff -r 9353^2:9353 # compare against the second parent
2884 hg diff -r 9353^2:9353 # compare against the second parent
2878
2885
2879 Returns 0 on success.
2886 Returns 0 on success.
2880 """
2887 """
2881
2888
2882 revs = opts.get('rev')
2889 revs = opts.get('rev')
2883 change = opts.get('change')
2890 change = opts.get('change')
2884 stat = opts.get('stat')
2891 stat = opts.get('stat')
2885 reverse = opts.get('reverse')
2892 reverse = opts.get('reverse')
2886
2893
2887 if revs and change:
2894 if revs and change:
2888 msg = _('cannot specify --rev and --change at the same time')
2895 msg = _('cannot specify --rev and --change at the same time')
2889 raise util.Abort(msg)
2896 raise util.Abort(msg)
2890 elif change:
2897 elif change:
2891 node2 = scmutil.revsingle(repo, change, None).node()
2898 node2 = scmutil.revsingle(repo, change, None).node()
2892 node1 = repo[node2].p1().node()
2899 node1 = repo[node2].p1().node()
2893 else:
2900 else:
2894 node1, node2 = scmutil.revpair(repo, revs)
2901 node1, node2 = scmutil.revpair(repo, revs)
2895
2902
2896 if reverse:
2903 if reverse:
2897 node1, node2 = node2, node1
2904 node1, node2 = node2, node1
2898
2905
2899 diffopts = patch.diffopts(ui, opts)
2906 diffopts = patch.diffopts(ui, opts)
2900 m = scmutil.match(repo[node2], pats, opts)
2907 m = scmutil.match(repo[node2], pats, opts)
2901 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2908 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2902 listsubrepos=opts.get('subrepos'))
2909 listsubrepos=opts.get('subrepos'))
2903
2910
2904 @command('^export',
2911 @command('^export',
2905 [('o', 'output', '',
2912 [('o', 'output', '',
2906 _('print output to file with formatted name'), _('FORMAT')),
2913 _('print output to file with formatted name'), _('FORMAT')),
2907 ('', 'switch-parent', None, _('diff against the second parent')),
2914 ('', 'switch-parent', None, _('diff against the second parent')),
2908 ('r', 'rev', [], _('revisions to export'), _('REV')),
2915 ('r', 'rev', [], _('revisions to export'), _('REV')),
2909 ] + diffopts,
2916 ] + diffopts,
2910 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2917 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2911 def export(ui, repo, *changesets, **opts):
2918 def export(ui, repo, *changesets, **opts):
2912 """dump the header and diffs for one or more changesets
2919 """dump the header and diffs for one or more changesets
2913
2920
2914 Print the changeset header and diffs for one or more revisions.
2921 Print the changeset header and diffs for one or more revisions.
2915 If no revision is given, the parent of the working directory is used.
2922 If no revision is given, the parent of the working directory is used.
2916
2923
2917 The information shown in the changeset header is: author, date,
2924 The information shown in the changeset header is: author, date,
2918 branch name (if non-default), changeset hash, parent(s) and commit
2925 branch name (if non-default), changeset hash, parent(s) and commit
2919 comment.
2926 comment.
2920
2927
2921 .. note::
2928 .. note::
2922
2929
2923 export may generate unexpected diff output for merge
2930 export may generate unexpected diff output for merge
2924 changesets, as it will compare the merge changeset against its
2931 changesets, as it will compare the merge changeset against its
2925 first parent only.
2932 first parent only.
2926
2933
2927 Output may be to a file, in which case the name of the file is
2934 Output may be to a file, in which case the name of the file is
2928 given using a format string. The formatting rules are as follows:
2935 given using a format string. The formatting rules are as follows:
2929
2936
2930 :``%%``: literal "%" character
2937 :``%%``: literal "%" character
2931 :``%H``: changeset hash (40 hexadecimal digits)
2938 :``%H``: changeset hash (40 hexadecimal digits)
2932 :``%N``: number of patches being generated
2939 :``%N``: number of patches being generated
2933 :``%R``: changeset revision number
2940 :``%R``: changeset revision number
2934 :``%b``: basename of the exporting repository
2941 :``%b``: basename of the exporting repository
2935 :``%h``: short-form changeset hash (12 hexadecimal digits)
2942 :``%h``: short-form changeset hash (12 hexadecimal digits)
2936 :``%m``: first line of the commit message (only alphanumeric characters)
2943 :``%m``: first line of the commit message (only alphanumeric characters)
2937 :``%n``: zero-padded sequence number, starting at 1
2944 :``%n``: zero-padded sequence number, starting at 1
2938 :``%r``: zero-padded changeset revision number
2945 :``%r``: zero-padded changeset revision number
2939
2946
2940 Without the -a/--text option, export will avoid generating diffs
2947 Without the -a/--text option, export will avoid generating diffs
2941 of files it detects as binary. With -a, export will generate a
2948 of files it detects as binary. With -a, export will generate a
2942 diff anyway, probably with undesirable results.
2949 diff anyway, probably with undesirable results.
2943
2950
2944 Use the -g/--git option to generate diffs in the git extended diff
2951 Use the -g/--git option to generate diffs in the git extended diff
2945 format. See :hg:`help diffs` for more information.
2952 format. See :hg:`help diffs` for more information.
2946
2953
2947 With the --switch-parent option, the diff will be against the
2954 With the --switch-parent option, the diff will be against the
2948 second parent. It can be useful to review a merge.
2955 second parent. It can be useful to review a merge.
2949
2956
2950 .. container:: verbose
2957 .. container:: verbose
2951
2958
2952 Examples:
2959 Examples:
2953
2960
2954 - use export and import to transplant a bugfix to the current
2961 - use export and import to transplant a bugfix to the current
2955 branch::
2962 branch::
2956
2963
2957 hg export -r 9353 | hg import -
2964 hg export -r 9353 | hg import -
2958
2965
2959 - export all the changesets between two revisions to a file with
2966 - export all the changesets between two revisions to a file with
2960 rename information::
2967 rename information::
2961
2968
2962 hg export --git -r 123:150 > changes.txt
2969 hg export --git -r 123:150 > changes.txt
2963
2970
2964 - split outgoing changes into a series of patches with
2971 - split outgoing changes into a series of patches with
2965 descriptive names::
2972 descriptive names::
2966
2973
2967 hg export -r "outgoing()" -o "%n-%m.patch"
2974 hg export -r "outgoing()" -o "%n-%m.patch"
2968
2975
2969 Returns 0 on success.
2976 Returns 0 on success.
2970 """
2977 """
2971 changesets += tuple(opts.get('rev', []))
2978 changesets += tuple(opts.get('rev', []))
2972 if not changesets:
2979 if not changesets:
2973 changesets = ['.']
2980 changesets = ['.']
2974 revs = scmutil.revrange(repo, changesets)
2981 revs = scmutil.revrange(repo, changesets)
2975 if not revs:
2982 if not revs:
2976 raise util.Abort(_("export requires at least one changeset"))
2983 raise util.Abort(_("export requires at least one changeset"))
2977 if len(revs) > 1:
2984 if len(revs) > 1:
2978 ui.note(_('exporting patches:\n'))
2985 ui.note(_('exporting patches:\n'))
2979 else:
2986 else:
2980 ui.note(_('exporting patch:\n'))
2987 ui.note(_('exporting patch:\n'))
2981 cmdutil.export(repo, revs, template=opts.get('output'),
2988 cmdutil.export(repo, revs, template=opts.get('output'),
2982 switch_parent=opts.get('switch_parent'),
2989 switch_parent=opts.get('switch_parent'),
2983 opts=patch.diffopts(ui, opts))
2990 opts=patch.diffopts(ui, opts))
2984
2991
2985 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2992 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2986 def forget(ui, repo, *pats, **opts):
2993 def forget(ui, repo, *pats, **opts):
2987 """forget the specified files on the next commit
2994 """forget the specified files on the next commit
2988
2995
2989 Mark the specified files so they will no longer be tracked
2996 Mark the specified files so they will no longer be tracked
2990 after the next commit.
2997 after the next commit.
2991
2998
2992 This only removes files from the current branch, not from the
2999 This only removes files from the current branch, not from the
2993 entire project history, and it does not delete them from the
3000 entire project history, and it does not delete them from the
2994 working directory.
3001 working directory.
2995
3002
2996 To undo a forget before the next commit, see :hg:`add`.
3003 To undo a forget before the next commit, see :hg:`add`.
2997
3004
2998 .. container:: verbose
3005 .. container:: verbose
2999
3006
3000 Examples:
3007 Examples:
3001
3008
3002 - forget newly-added binary files::
3009 - forget newly-added binary files::
3003
3010
3004 hg forget "set:added() and binary()"
3011 hg forget "set:added() and binary()"
3005
3012
3006 - forget files that would be excluded by .hgignore::
3013 - forget files that would be excluded by .hgignore::
3007
3014
3008 hg forget "set:hgignore()"
3015 hg forget "set:hgignore()"
3009
3016
3010 Returns 0 on success.
3017 Returns 0 on success.
3011 """
3018 """
3012
3019
3013 if not pats:
3020 if not pats:
3014 raise util.Abort(_('no files specified'))
3021 raise util.Abort(_('no files specified'))
3015
3022
3016 m = scmutil.match(repo[None], pats, opts)
3023 m = scmutil.match(repo[None], pats, opts)
3017 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3024 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3018 return rejected and 1 or 0
3025 return rejected and 1 or 0
3019
3026
3020 @command(
3027 @command(
3021 'graft',
3028 'graft',
3022 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3029 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3023 ('c', 'continue', False, _('resume interrupted graft')),
3030 ('c', 'continue', False, _('resume interrupted graft')),
3024 ('e', 'edit', False, _('invoke editor on commit messages')),
3031 ('e', 'edit', False, _('invoke editor on commit messages')),
3025 ('', 'log', None, _('append graft info to log message')),
3032 ('', 'log', None, _('append graft info to log message')),
3026 ('D', 'currentdate', False,
3033 ('D', 'currentdate', False,
3027 _('record the current date as commit date')),
3034 _('record the current date as commit date')),
3028 ('U', 'currentuser', False,
3035 ('U', 'currentuser', False,
3029 _('record the current user as committer'), _('DATE'))]
3036 _('record the current user as committer'), _('DATE'))]
3030 + commitopts2 + mergetoolopts + dryrunopts,
3037 + commitopts2 + mergetoolopts + dryrunopts,
3031 _('[OPTION]... [-r] REV...'))
3038 _('[OPTION]... [-r] REV...'))
3032 def graft(ui, repo, *revs, **opts):
3039 def graft(ui, repo, *revs, **opts):
3033 '''copy changes from other branches onto the current branch
3040 '''copy changes from other branches onto the current branch
3034
3041
3035 This command uses Mercurial's merge logic to copy individual
3042 This command uses Mercurial's merge logic to copy individual
3036 changes from other branches without merging branches in the
3043 changes from other branches without merging branches in the
3037 history graph. This is sometimes known as 'backporting' or
3044 history graph. This is sometimes known as 'backporting' or
3038 'cherry-picking'. By default, graft will copy user, date, and
3045 'cherry-picking'. By default, graft will copy user, date, and
3039 description from the source changesets.
3046 description from the source changesets.
3040
3047
3041 Changesets that are ancestors of the current revision, that have
3048 Changesets that are ancestors of the current revision, that have
3042 already been grafted, or that are merges will be skipped.
3049 already been grafted, or that are merges will be skipped.
3043
3050
3044 If --log is specified, log messages will have a comment appended
3051 If --log is specified, log messages will have a comment appended
3045 of the form::
3052 of the form::
3046
3053
3047 (grafted from CHANGESETHASH)
3054 (grafted from CHANGESETHASH)
3048
3055
3049 If a graft merge results in conflicts, the graft process is
3056 If a graft merge results in conflicts, the graft process is
3050 interrupted so that the current merge can be manually resolved.
3057 interrupted so that the current merge can be manually resolved.
3051 Once all conflicts are addressed, the graft process can be
3058 Once all conflicts are addressed, the graft process can be
3052 continued with the -c/--continue option.
3059 continued with the -c/--continue option.
3053
3060
3054 .. note::
3061 .. note::
3055
3062
3056 The -c/--continue option does not reapply earlier options.
3063 The -c/--continue option does not reapply earlier options.
3057
3064
3058 .. container:: verbose
3065 .. container:: verbose
3059
3066
3060 Examples:
3067 Examples:
3061
3068
3062 - copy a single change to the stable branch and edit its description::
3069 - copy a single change to the stable branch and edit its description::
3063
3070
3064 hg update stable
3071 hg update stable
3065 hg graft --edit 9393
3072 hg graft --edit 9393
3066
3073
3067 - graft a range of changesets with one exception, updating dates::
3074 - graft a range of changesets with one exception, updating dates::
3068
3075
3069 hg graft -D "2085::2093 and not 2091"
3076 hg graft -D "2085::2093 and not 2091"
3070
3077
3071 - continue a graft after resolving conflicts::
3078 - continue a graft after resolving conflicts::
3072
3079
3073 hg graft -c
3080 hg graft -c
3074
3081
3075 - show the source of a grafted changeset::
3082 - show the source of a grafted changeset::
3076
3083
3077 hg log --debug -r .
3084 hg log --debug -r .
3078
3085
3079 Returns 0 on successful completion.
3086 Returns 0 on successful completion.
3080 '''
3087 '''
3081
3088
3082 revs = list(revs)
3089 revs = list(revs)
3083 revs.extend(opts['rev'])
3090 revs.extend(opts['rev'])
3084
3091
3085 if not opts.get('user') and opts.get('currentuser'):
3092 if not opts.get('user') and opts.get('currentuser'):
3086 opts['user'] = ui.username()
3093 opts['user'] = ui.username()
3087 if not opts.get('date') and opts.get('currentdate'):
3094 if not opts.get('date') and opts.get('currentdate'):
3088 opts['date'] = "%d %d" % util.makedate()
3095 opts['date'] = "%d %d" % util.makedate()
3089
3096
3090 editor = cmdutil.getcommiteditor(**opts)
3097 editor = cmdutil.getcommiteditor(**opts)
3091
3098
3092 cont = False
3099 cont = False
3093 if opts['continue']:
3100 if opts['continue']:
3094 cont = True
3101 cont = True
3095 if revs:
3102 if revs:
3096 raise util.Abort(_("can't specify --continue and revisions"))
3103 raise util.Abort(_("can't specify --continue and revisions"))
3097 # read in unfinished revisions
3104 # read in unfinished revisions
3098 try:
3105 try:
3099 nodes = repo.opener.read('graftstate').splitlines()
3106 nodes = repo.opener.read('graftstate').splitlines()
3100 revs = [repo[node].rev() for node in nodes]
3107 revs = [repo[node].rev() for node in nodes]
3101 except IOError, inst:
3108 except IOError, inst:
3102 if inst.errno != errno.ENOENT:
3109 if inst.errno != errno.ENOENT:
3103 raise
3110 raise
3104 raise util.Abort(_("no graft state found, can't continue"))
3111 raise util.Abort(_("no graft state found, can't continue"))
3105 else:
3112 else:
3106 cmdutil.checkunfinished(repo)
3113 cmdutil.checkunfinished(repo)
3107 cmdutil.bailifchanged(repo)
3114 cmdutil.bailifchanged(repo)
3108 if not revs:
3115 if not revs:
3109 raise util.Abort(_('no revisions specified'))
3116 raise util.Abort(_('no revisions specified'))
3110 revs = scmutil.revrange(repo, revs)
3117 revs = scmutil.revrange(repo, revs)
3111
3118
3112 # check for merges
3119 # check for merges
3113 for rev in repo.revs('%ld and merge()', revs):
3120 for rev in repo.revs('%ld and merge()', revs):
3114 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3121 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3115 revs.remove(rev)
3122 revs.remove(rev)
3116 if not revs:
3123 if not revs:
3117 return -1
3124 return -1
3118
3125
3119 # check for ancestors of dest branch
3126 # check for ancestors of dest branch
3120 crev = repo['.'].rev()
3127 crev = repo['.'].rev()
3121 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3128 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3122 # Cannot use x.remove(y) on smart set, this has to be a list.
3129 # Cannot use x.remove(y) on smart set, this has to be a list.
3123 # XXX make this lazy in the future
3130 # XXX make this lazy in the future
3124 revs = list(revs)
3131 revs = list(revs)
3125 # don't mutate while iterating, create a copy
3132 # don't mutate while iterating, create a copy
3126 for rev in list(revs):
3133 for rev in list(revs):
3127 if rev in ancestors:
3134 if rev in ancestors:
3128 ui.warn(_('skipping ancestor revision %s\n') % rev)
3135 ui.warn(_('skipping ancestor revision %s\n') % rev)
3129 # XXX remove on list is slow
3136 # XXX remove on list is slow
3130 revs.remove(rev)
3137 revs.remove(rev)
3131 if not revs:
3138 if not revs:
3132 return -1
3139 return -1
3133
3140
3134 # analyze revs for earlier grafts
3141 # analyze revs for earlier grafts
3135 ids = {}
3142 ids = {}
3136 for ctx in repo.set("%ld", revs):
3143 for ctx in repo.set("%ld", revs):
3137 ids[ctx.hex()] = ctx.rev()
3144 ids[ctx.hex()] = ctx.rev()
3138 n = ctx.extra().get('source')
3145 n = ctx.extra().get('source')
3139 if n:
3146 if n:
3140 ids[n] = ctx.rev()
3147 ids[n] = ctx.rev()
3141
3148
3142 # check ancestors for earlier grafts
3149 # check ancestors for earlier grafts
3143 ui.debug('scanning for duplicate grafts\n')
3150 ui.debug('scanning for duplicate grafts\n')
3144
3151
3145 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3152 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3146 ctx = repo[rev]
3153 ctx = repo[rev]
3147 n = ctx.extra().get('source')
3154 n = ctx.extra().get('source')
3148 if n in ids:
3155 if n in ids:
3149 r = repo[n].rev()
3156 r = repo[n].rev()
3150 if r in revs:
3157 if r in revs:
3151 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3158 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3152 % (r, rev))
3159 % (r, rev))
3153 revs.remove(r)
3160 revs.remove(r)
3154 elif ids[n] in revs:
3161 elif ids[n] in revs:
3155 ui.warn(_('skipping already grafted revision %s '
3162 ui.warn(_('skipping already grafted revision %s '
3156 '(%s also has origin %d)\n') % (ids[n], rev, r))
3163 '(%s also has origin %d)\n') % (ids[n], rev, r))
3157 revs.remove(ids[n])
3164 revs.remove(ids[n])
3158 elif ctx.hex() in ids:
3165 elif ctx.hex() in ids:
3159 r = ids[ctx.hex()]
3166 r = ids[ctx.hex()]
3160 ui.warn(_('skipping already grafted revision %s '
3167 ui.warn(_('skipping already grafted revision %s '
3161 '(was grafted from %d)\n') % (r, rev))
3168 '(was grafted from %d)\n') % (r, rev))
3162 revs.remove(r)
3169 revs.remove(r)
3163 if not revs:
3170 if not revs:
3164 return -1
3171 return -1
3165
3172
3166 wlock = repo.wlock()
3173 wlock = repo.wlock()
3167 try:
3174 try:
3168 current = repo['.']
3175 current = repo['.']
3169 for pos, ctx in enumerate(repo.set("%ld", revs)):
3176 for pos, ctx in enumerate(repo.set("%ld", revs)):
3170
3177
3171 ui.status(_('grafting revision %s\n') % ctx.rev())
3178 ui.status(_('grafting revision %s\n') % ctx.rev())
3172 if opts.get('dry_run'):
3179 if opts.get('dry_run'):
3173 continue
3180 continue
3174
3181
3175 source = ctx.extra().get('source')
3182 source = ctx.extra().get('source')
3176 if not source:
3183 if not source:
3177 source = ctx.hex()
3184 source = ctx.hex()
3178 extra = {'source': source}
3185 extra = {'source': source}
3179 user = ctx.user()
3186 user = ctx.user()
3180 if opts.get('user'):
3187 if opts.get('user'):
3181 user = opts['user']
3188 user = opts['user']
3182 date = ctx.date()
3189 date = ctx.date()
3183 if opts.get('date'):
3190 if opts.get('date'):
3184 date = opts['date']
3191 date = opts['date']
3185 message = ctx.description()
3192 message = ctx.description()
3186 if opts.get('log'):
3193 if opts.get('log'):
3187 message += '\n(grafted from %s)' % ctx.hex()
3194 message += '\n(grafted from %s)' % ctx.hex()
3188
3195
3189 # we don't merge the first commit when continuing
3196 # we don't merge the first commit when continuing
3190 if not cont:
3197 if not cont:
3191 # perform the graft merge with p1(rev) as 'ancestor'
3198 # perform the graft merge with p1(rev) as 'ancestor'
3192 try:
3199 try:
3193 # ui.forcemerge is an internal variable, do not document
3200 # ui.forcemerge is an internal variable, do not document
3194 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3201 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3195 'graft')
3202 'graft')
3196 stats = mergemod.update(repo, ctx.node(), True, True, False,
3203 stats = mergemod.update(repo, ctx.node(), True, True, False,
3197 ctx.p1().node(),
3204 ctx.p1().node(),
3198 labels=['local', 'graft'])
3205 labels=['local', 'graft'])
3199 finally:
3206 finally:
3200 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3207 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3201 # report any conflicts
3208 # report any conflicts
3202 if stats and stats[3] > 0:
3209 if stats and stats[3] > 0:
3203 # write out state for --continue
3210 # write out state for --continue
3204 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3211 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3205 repo.opener.write('graftstate', ''.join(nodelines))
3212 repo.opener.write('graftstate', ''.join(nodelines))
3206 raise util.Abort(
3213 raise util.Abort(
3207 _("unresolved conflicts, can't continue"),
3214 _("unresolved conflicts, can't continue"),
3208 hint=_('use hg resolve and hg graft --continue'))
3215 hint=_('use hg resolve and hg graft --continue'))
3209 else:
3216 else:
3210 cont = False
3217 cont = False
3211
3218
3212 # drop the second merge parent
3219 # drop the second merge parent
3213 repo.setparents(current.node(), nullid)
3220 repo.setparents(current.node(), nullid)
3214 repo.dirstate.write()
3221 repo.dirstate.write()
3215 # fix up dirstate for copies and renames
3222 # fix up dirstate for copies and renames
3216 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3223 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3217
3224
3218 # commit
3225 # commit
3219 node = repo.commit(text=message, user=user,
3226 node = repo.commit(text=message, user=user,
3220 date=date, extra=extra, editor=editor)
3227 date=date, extra=extra, editor=editor)
3221 if node is None:
3228 if node is None:
3222 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3229 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3223 else:
3230 else:
3224 current = repo[node]
3231 current = repo[node]
3225 finally:
3232 finally:
3226 wlock.release()
3233 wlock.release()
3227
3234
3228 # remove state when we complete successfully
3235 # remove state when we complete successfully
3229 if not opts.get('dry_run'):
3236 if not opts.get('dry_run'):
3230 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3237 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3231
3238
3232 return 0
3239 return 0
3233
3240
3234 @command('grep',
3241 @command('grep',
3235 [('0', 'print0', None, _('end fields with NUL')),
3242 [('0', 'print0', None, _('end fields with NUL')),
3236 ('', 'all', None, _('print all revisions that match')),
3243 ('', 'all', None, _('print all revisions that match')),
3237 ('a', 'text', None, _('treat all files as text')),
3244 ('a', 'text', None, _('treat all files as text')),
3238 ('f', 'follow', None,
3245 ('f', 'follow', None,
3239 _('follow changeset history,'
3246 _('follow changeset history,'
3240 ' or file history across copies and renames')),
3247 ' or file history across copies and renames')),
3241 ('i', 'ignore-case', None, _('ignore case when matching')),
3248 ('i', 'ignore-case', None, _('ignore case when matching')),
3242 ('l', 'files-with-matches', None,
3249 ('l', 'files-with-matches', None,
3243 _('print only filenames and revisions that match')),
3250 _('print only filenames and revisions that match')),
3244 ('n', 'line-number', None, _('print matching line numbers')),
3251 ('n', 'line-number', None, _('print matching line numbers')),
3245 ('r', 'rev', [],
3252 ('r', 'rev', [],
3246 _('only search files changed within revision range'), _('REV')),
3253 _('only search files changed within revision range'), _('REV')),
3247 ('u', 'user', None, _('list the author (long with -v)')),
3254 ('u', 'user', None, _('list the author (long with -v)')),
3248 ('d', 'date', None, _('list the date (short with -q)')),
3255 ('d', 'date', None, _('list the date (short with -q)')),
3249 ] + walkopts,
3256 ] + walkopts,
3250 _('[OPTION]... PATTERN [FILE]...'))
3257 _('[OPTION]... PATTERN [FILE]...'))
3251 def grep(ui, repo, pattern, *pats, **opts):
3258 def grep(ui, repo, pattern, *pats, **opts):
3252 """search for a pattern in specified files and revisions
3259 """search for a pattern in specified files and revisions
3253
3260
3254 Search revisions of files for a regular expression.
3261 Search revisions of files for a regular expression.
3255
3262
3256 This command behaves differently than Unix grep. It only accepts
3263 This command behaves differently than Unix grep. It only accepts
3257 Python/Perl regexps. It searches repository history, not the
3264 Python/Perl regexps. It searches repository history, not the
3258 working directory. It always prints the revision number in which a
3265 working directory. It always prints the revision number in which a
3259 match appears.
3266 match appears.
3260
3267
3261 By default, grep only prints output for the first revision of a
3268 By default, grep only prints output for the first revision of a
3262 file in which it finds a match. To get it to print every revision
3269 file in which it finds a match. To get it to print every revision
3263 that contains a change in match status ("-" for a match that
3270 that contains a change in match status ("-" for a match that
3264 becomes a non-match, or "+" for a non-match that becomes a match),
3271 becomes a non-match, or "+" for a non-match that becomes a match),
3265 use the --all flag.
3272 use the --all flag.
3266
3273
3267 Returns 0 if a match is found, 1 otherwise.
3274 Returns 0 if a match is found, 1 otherwise.
3268 """
3275 """
3269 reflags = re.M
3276 reflags = re.M
3270 if opts.get('ignore_case'):
3277 if opts.get('ignore_case'):
3271 reflags |= re.I
3278 reflags |= re.I
3272 try:
3279 try:
3273 regexp = util.compilere(pattern, reflags)
3280 regexp = util.compilere(pattern, reflags)
3274 except re.error, inst:
3281 except re.error, inst:
3275 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3282 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3276 return 1
3283 return 1
3277 sep, eol = ':', '\n'
3284 sep, eol = ':', '\n'
3278 if opts.get('print0'):
3285 if opts.get('print0'):
3279 sep = eol = '\0'
3286 sep = eol = '\0'
3280
3287
3281 getfile = util.lrucachefunc(repo.file)
3288 getfile = util.lrucachefunc(repo.file)
3282
3289
3283 def matchlines(body):
3290 def matchlines(body):
3284 begin = 0
3291 begin = 0
3285 linenum = 0
3292 linenum = 0
3286 while begin < len(body):
3293 while begin < len(body):
3287 match = regexp.search(body, begin)
3294 match = regexp.search(body, begin)
3288 if not match:
3295 if not match:
3289 break
3296 break
3290 mstart, mend = match.span()
3297 mstart, mend = match.span()
3291 linenum += body.count('\n', begin, mstart) + 1
3298 linenum += body.count('\n', begin, mstart) + 1
3292 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3299 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3293 begin = body.find('\n', mend) + 1 or len(body) + 1
3300 begin = body.find('\n', mend) + 1 or len(body) + 1
3294 lend = begin - 1
3301 lend = begin - 1
3295 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3302 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3296
3303
3297 class linestate(object):
3304 class linestate(object):
3298 def __init__(self, line, linenum, colstart, colend):
3305 def __init__(self, line, linenum, colstart, colend):
3299 self.line = line
3306 self.line = line
3300 self.linenum = linenum
3307 self.linenum = linenum
3301 self.colstart = colstart
3308 self.colstart = colstart
3302 self.colend = colend
3309 self.colend = colend
3303
3310
3304 def __hash__(self):
3311 def __hash__(self):
3305 return hash((self.linenum, self.line))
3312 return hash((self.linenum, self.line))
3306
3313
3307 def __eq__(self, other):
3314 def __eq__(self, other):
3308 return self.line == other.line
3315 return self.line == other.line
3309
3316
3310 def __iter__(self):
3317 def __iter__(self):
3311 yield (self.line[:self.colstart], '')
3318 yield (self.line[:self.colstart], '')
3312 yield (self.line[self.colstart:self.colend], 'grep.match')
3319 yield (self.line[self.colstart:self.colend], 'grep.match')
3313 rest = self.line[self.colend:]
3320 rest = self.line[self.colend:]
3314 while rest != '':
3321 while rest != '':
3315 match = regexp.search(rest)
3322 match = regexp.search(rest)
3316 if not match:
3323 if not match:
3317 yield (rest, '')
3324 yield (rest, '')
3318 break
3325 break
3319 mstart, mend = match.span()
3326 mstart, mend = match.span()
3320 yield (rest[:mstart], '')
3327 yield (rest[:mstart], '')
3321 yield (rest[mstart:mend], 'grep.match')
3328 yield (rest[mstart:mend], 'grep.match')
3322 rest = rest[mend:]
3329 rest = rest[mend:]
3323
3330
3324 matches = {}
3331 matches = {}
3325 copies = {}
3332 copies = {}
3326 def grepbody(fn, rev, body):
3333 def grepbody(fn, rev, body):
3327 matches[rev].setdefault(fn, [])
3334 matches[rev].setdefault(fn, [])
3328 m = matches[rev][fn]
3335 m = matches[rev][fn]
3329 for lnum, cstart, cend, line in matchlines(body):
3336 for lnum, cstart, cend, line in matchlines(body):
3330 s = linestate(line, lnum, cstart, cend)
3337 s = linestate(line, lnum, cstart, cend)
3331 m.append(s)
3338 m.append(s)
3332
3339
3333 def difflinestates(a, b):
3340 def difflinestates(a, b):
3334 sm = difflib.SequenceMatcher(None, a, b)
3341 sm = difflib.SequenceMatcher(None, a, b)
3335 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3342 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3336 if tag == 'insert':
3343 if tag == 'insert':
3337 for i in xrange(blo, bhi):
3344 for i in xrange(blo, bhi):
3338 yield ('+', b[i])
3345 yield ('+', b[i])
3339 elif tag == 'delete':
3346 elif tag == 'delete':
3340 for i in xrange(alo, ahi):
3347 for i in xrange(alo, ahi):
3341 yield ('-', a[i])
3348 yield ('-', a[i])
3342 elif tag == 'replace':
3349 elif tag == 'replace':
3343 for i in xrange(alo, ahi):
3350 for i in xrange(alo, ahi):
3344 yield ('-', a[i])
3351 yield ('-', a[i])
3345 for i in xrange(blo, bhi):
3352 for i in xrange(blo, bhi):
3346 yield ('+', b[i])
3353 yield ('+', b[i])
3347
3354
3348 def display(fn, ctx, pstates, states):
3355 def display(fn, ctx, pstates, states):
3349 rev = ctx.rev()
3356 rev = ctx.rev()
3350 datefunc = ui.quiet and util.shortdate or util.datestr
3357 datefunc = ui.quiet and util.shortdate or util.datestr
3351 found = False
3358 found = False
3352 @util.cachefunc
3359 @util.cachefunc
3353 def binary():
3360 def binary():
3354 flog = getfile(fn)
3361 flog = getfile(fn)
3355 return util.binary(flog.read(ctx.filenode(fn)))
3362 return util.binary(flog.read(ctx.filenode(fn)))
3356
3363
3357 if opts.get('all'):
3364 if opts.get('all'):
3358 iter = difflinestates(pstates, states)
3365 iter = difflinestates(pstates, states)
3359 else:
3366 else:
3360 iter = [('', l) for l in states]
3367 iter = [('', l) for l in states]
3361 for change, l in iter:
3368 for change, l in iter:
3362 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3369 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3363
3370
3364 if opts.get('line_number'):
3371 if opts.get('line_number'):
3365 cols.append((str(l.linenum), 'grep.linenumber'))
3372 cols.append((str(l.linenum), 'grep.linenumber'))
3366 if opts.get('all'):
3373 if opts.get('all'):
3367 cols.append((change, 'grep.change'))
3374 cols.append((change, 'grep.change'))
3368 if opts.get('user'):
3375 if opts.get('user'):
3369 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3376 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3370 if opts.get('date'):
3377 if opts.get('date'):
3371 cols.append((datefunc(ctx.date()), 'grep.date'))
3378 cols.append((datefunc(ctx.date()), 'grep.date'))
3372 for col, label in cols[:-1]:
3379 for col, label in cols[:-1]:
3373 ui.write(col, label=label)
3380 ui.write(col, label=label)
3374 ui.write(sep, label='grep.sep')
3381 ui.write(sep, label='grep.sep')
3375 ui.write(cols[-1][0], label=cols[-1][1])
3382 ui.write(cols[-1][0], label=cols[-1][1])
3376 if not opts.get('files_with_matches'):
3383 if not opts.get('files_with_matches'):
3377 ui.write(sep, label='grep.sep')
3384 ui.write(sep, label='grep.sep')
3378 if not opts.get('text') and binary():
3385 if not opts.get('text') and binary():
3379 ui.write(" Binary file matches")
3386 ui.write(" Binary file matches")
3380 else:
3387 else:
3381 for s, label in l:
3388 for s, label in l:
3382 ui.write(s, label=label)
3389 ui.write(s, label=label)
3383 ui.write(eol)
3390 ui.write(eol)
3384 found = True
3391 found = True
3385 if opts.get('files_with_matches'):
3392 if opts.get('files_with_matches'):
3386 break
3393 break
3387 return found
3394 return found
3388
3395
3389 skip = {}
3396 skip = {}
3390 revfiles = {}
3397 revfiles = {}
3391 matchfn = scmutil.match(repo[None], pats, opts)
3398 matchfn = scmutil.match(repo[None], pats, opts)
3392 found = False
3399 found = False
3393 follow = opts.get('follow')
3400 follow = opts.get('follow')
3394
3401
3395 def prep(ctx, fns):
3402 def prep(ctx, fns):
3396 rev = ctx.rev()
3403 rev = ctx.rev()
3397 pctx = ctx.p1()
3404 pctx = ctx.p1()
3398 parent = pctx.rev()
3405 parent = pctx.rev()
3399 matches.setdefault(rev, {})
3406 matches.setdefault(rev, {})
3400 matches.setdefault(parent, {})
3407 matches.setdefault(parent, {})
3401 files = revfiles.setdefault(rev, [])
3408 files = revfiles.setdefault(rev, [])
3402 for fn in fns:
3409 for fn in fns:
3403 flog = getfile(fn)
3410 flog = getfile(fn)
3404 try:
3411 try:
3405 fnode = ctx.filenode(fn)
3412 fnode = ctx.filenode(fn)
3406 except error.LookupError:
3413 except error.LookupError:
3407 continue
3414 continue
3408
3415
3409 copied = flog.renamed(fnode)
3416 copied = flog.renamed(fnode)
3410 copy = follow and copied and copied[0]
3417 copy = follow and copied and copied[0]
3411 if copy:
3418 if copy:
3412 copies.setdefault(rev, {})[fn] = copy
3419 copies.setdefault(rev, {})[fn] = copy
3413 if fn in skip:
3420 if fn in skip:
3414 if copy:
3421 if copy:
3415 skip[copy] = True
3422 skip[copy] = True
3416 continue
3423 continue
3417 files.append(fn)
3424 files.append(fn)
3418
3425
3419 if fn not in matches[rev]:
3426 if fn not in matches[rev]:
3420 grepbody(fn, rev, flog.read(fnode))
3427 grepbody(fn, rev, flog.read(fnode))
3421
3428
3422 pfn = copy or fn
3429 pfn = copy or fn
3423 if pfn not in matches[parent]:
3430 if pfn not in matches[parent]:
3424 try:
3431 try:
3425 fnode = pctx.filenode(pfn)
3432 fnode = pctx.filenode(pfn)
3426 grepbody(pfn, parent, flog.read(fnode))
3433 grepbody(pfn, parent, flog.read(fnode))
3427 except error.LookupError:
3434 except error.LookupError:
3428 pass
3435 pass
3429
3436
3430 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3437 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3431 rev = ctx.rev()
3438 rev = ctx.rev()
3432 parent = ctx.p1().rev()
3439 parent = ctx.p1().rev()
3433 for fn in sorted(revfiles.get(rev, [])):
3440 for fn in sorted(revfiles.get(rev, [])):
3434 states = matches[rev][fn]
3441 states = matches[rev][fn]
3435 copy = copies.get(rev, {}).get(fn)
3442 copy = copies.get(rev, {}).get(fn)
3436 if fn in skip:
3443 if fn in skip:
3437 if copy:
3444 if copy:
3438 skip[copy] = True
3445 skip[copy] = True
3439 continue
3446 continue
3440 pstates = matches.get(parent, {}).get(copy or fn, [])
3447 pstates = matches.get(parent, {}).get(copy or fn, [])
3441 if pstates or states:
3448 if pstates or states:
3442 r = display(fn, ctx, pstates, states)
3449 r = display(fn, ctx, pstates, states)
3443 found = found or r
3450 found = found or r
3444 if r and not opts.get('all'):
3451 if r and not opts.get('all'):
3445 skip[fn] = True
3452 skip[fn] = True
3446 if copy:
3453 if copy:
3447 skip[copy] = True
3454 skip[copy] = True
3448 del matches[rev]
3455 del matches[rev]
3449 del revfiles[rev]
3456 del revfiles[rev]
3450
3457
3451 return not found
3458 return not found
3452
3459
3453 @command('heads',
3460 @command('heads',
3454 [('r', 'rev', '',
3461 [('r', 'rev', '',
3455 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3462 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3456 ('t', 'topo', False, _('show topological heads only')),
3463 ('t', 'topo', False, _('show topological heads only')),
3457 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3464 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3458 ('c', 'closed', False, _('show normal and closed branch heads')),
3465 ('c', 'closed', False, _('show normal and closed branch heads')),
3459 ] + templateopts,
3466 ] + templateopts,
3460 _('[-ct] [-r STARTREV] [REV]...'))
3467 _('[-ct] [-r STARTREV] [REV]...'))
3461 def heads(ui, repo, *branchrevs, **opts):
3468 def heads(ui, repo, *branchrevs, **opts):
3462 """show branch heads
3469 """show branch heads
3463
3470
3464 With no arguments, show all open branch heads in the repository.
3471 With no arguments, show all open branch heads in the repository.
3465 Branch heads are changesets that have no descendants on the
3472 Branch heads are changesets that have no descendants on the
3466 same branch. They are where development generally takes place and
3473 same branch. They are where development generally takes place and
3467 are the usual targets for update and merge operations.
3474 are the usual targets for update and merge operations.
3468
3475
3469 If one or more REVs are given, only open branch heads on the
3476 If one or more REVs are given, only open branch heads on the
3470 branches associated with the specified changesets are shown. This
3477 branches associated with the specified changesets are shown. This
3471 means that you can use :hg:`heads .` to see the heads on the
3478 means that you can use :hg:`heads .` to see the heads on the
3472 currently checked-out branch.
3479 currently checked-out branch.
3473
3480
3474 If -c/--closed is specified, also show branch heads marked closed
3481 If -c/--closed is specified, also show branch heads marked closed
3475 (see :hg:`commit --close-branch`).
3482 (see :hg:`commit --close-branch`).
3476
3483
3477 If STARTREV is specified, only those heads that are descendants of
3484 If STARTREV is specified, only those heads that are descendants of
3478 STARTREV will be displayed.
3485 STARTREV will be displayed.
3479
3486
3480 If -t/--topo is specified, named branch mechanics will be ignored and only
3487 If -t/--topo is specified, named branch mechanics will be ignored and only
3481 topological heads (changesets with no children) will be shown.
3488 topological heads (changesets with no children) will be shown.
3482
3489
3483 Returns 0 if matching heads are found, 1 if not.
3490 Returns 0 if matching heads are found, 1 if not.
3484 """
3491 """
3485
3492
3486 start = None
3493 start = None
3487 if 'rev' in opts:
3494 if 'rev' in opts:
3488 start = scmutil.revsingle(repo, opts['rev'], None).node()
3495 start = scmutil.revsingle(repo, opts['rev'], None).node()
3489
3496
3490 if opts.get('topo'):
3497 if opts.get('topo'):
3491 heads = [repo[h] for h in repo.heads(start)]
3498 heads = [repo[h] for h in repo.heads(start)]
3492 else:
3499 else:
3493 heads = []
3500 heads = []
3494 for branch in repo.branchmap():
3501 for branch in repo.branchmap():
3495 heads += repo.branchheads(branch, start, opts.get('closed'))
3502 heads += repo.branchheads(branch, start, opts.get('closed'))
3496 heads = [repo[h] for h in heads]
3503 heads = [repo[h] for h in heads]
3497
3504
3498 if branchrevs:
3505 if branchrevs:
3499 branches = set(repo[br].branch() for br in branchrevs)
3506 branches = set(repo[br].branch() for br in branchrevs)
3500 heads = [h for h in heads if h.branch() in branches]
3507 heads = [h for h in heads if h.branch() in branches]
3501
3508
3502 if opts.get('active') and branchrevs:
3509 if opts.get('active') and branchrevs:
3503 dagheads = repo.heads(start)
3510 dagheads = repo.heads(start)
3504 heads = [h for h in heads if h.node() in dagheads]
3511 heads = [h for h in heads if h.node() in dagheads]
3505
3512
3506 if branchrevs:
3513 if branchrevs:
3507 haveheads = set(h.branch() for h in heads)
3514 haveheads = set(h.branch() for h in heads)
3508 if branches - haveheads:
3515 if branches - haveheads:
3509 headless = ', '.join(b for b in branches - haveheads)
3516 headless = ', '.join(b for b in branches - haveheads)
3510 msg = _('no open branch heads found on branches %s')
3517 msg = _('no open branch heads found on branches %s')
3511 if opts.get('rev'):
3518 if opts.get('rev'):
3512 msg += _(' (started at %s)') % opts['rev']
3519 msg += _(' (started at %s)') % opts['rev']
3513 ui.warn((msg + '\n') % headless)
3520 ui.warn((msg + '\n') % headless)
3514
3521
3515 if not heads:
3522 if not heads:
3516 return 1
3523 return 1
3517
3524
3518 heads = sorted(heads, key=lambda x: -x.rev())
3525 heads = sorted(heads, key=lambda x: -x.rev())
3519 displayer = cmdutil.show_changeset(ui, repo, opts)
3526 displayer = cmdutil.show_changeset(ui, repo, opts)
3520 for ctx in heads:
3527 for ctx in heads:
3521 displayer.show(ctx)
3528 displayer.show(ctx)
3522 displayer.close()
3529 displayer.close()
3523
3530
3524 @command('help',
3531 @command('help',
3525 [('e', 'extension', None, _('show only help for extensions')),
3532 [('e', 'extension', None, _('show only help for extensions')),
3526 ('c', 'command', None, _('show only help for commands')),
3533 ('c', 'command', None, _('show only help for commands')),
3527 ('k', 'keyword', '', _('show topics matching keyword')),
3534 ('k', 'keyword', '', _('show topics matching keyword')),
3528 ],
3535 ],
3529 _('[-ec] [TOPIC]'))
3536 _('[-ec] [TOPIC]'))
3530 def help_(ui, name=None, **opts):
3537 def help_(ui, name=None, **opts):
3531 """show help for a given topic or a help overview
3538 """show help for a given topic or a help overview
3532
3539
3533 With no arguments, print a list of commands with short help messages.
3540 With no arguments, print a list of commands with short help messages.
3534
3541
3535 Given a topic, extension, or command name, print help for that
3542 Given a topic, extension, or command name, print help for that
3536 topic.
3543 topic.
3537
3544
3538 Returns 0 if successful.
3545 Returns 0 if successful.
3539 """
3546 """
3540
3547
3541 textwidth = min(ui.termwidth(), 80) - 2
3548 textwidth = min(ui.termwidth(), 80) - 2
3542
3549
3543 keep = ui.verbose and ['verbose'] or []
3550 keep = ui.verbose and ['verbose'] or []
3544 text = help.help_(ui, name, **opts)
3551 text = help.help_(ui, name, **opts)
3545
3552
3546 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3553 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3547 if 'verbose' in pruned:
3554 if 'verbose' in pruned:
3548 keep.append('omitted')
3555 keep.append('omitted')
3549 else:
3556 else:
3550 keep.append('notomitted')
3557 keep.append('notomitted')
3551 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3558 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3552 ui.write(formatted)
3559 ui.write(formatted)
3553
3560
3554
3561
3555 @command('identify|id',
3562 @command('identify|id',
3556 [('r', 'rev', '',
3563 [('r', 'rev', '',
3557 _('identify the specified revision'), _('REV')),
3564 _('identify the specified revision'), _('REV')),
3558 ('n', 'num', None, _('show local revision number')),
3565 ('n', 'num', None, _('show local revision number')),
3559 ('i', 'id', None, _('show global revision id')),
3566 ('i', 'id', None, _('show global revision id')),
3560 ('b', 'branch', None, _('show branch')),
3567 ('b', 'branch', None, _('show branch')),
3561 ('t', 'tags', None, _('show tags')),
3568 ('t', 'tags', None, _('show tags')),
3562 ('B', 'bookmarks', None, _('show bookmarks')),
3569 ('B', 'bookmarks', None, _('show bookmarks')),
3563 ] + remoteopts,
3570 ] + remoteopts,
3564 _('[-nibtB] [-r REV] [SOURCE]'))
3571 _('[-nibtB] [-r REV] [SOURCE]'))
3565 def identify(ui, repo, source=None, rev=None,
3572 def identify(ui, repo, source=None, rev=None,
3566 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3573 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3567 """identify the working copy or specified revision
3574 """identify the working copy or specified revision
3568
3575
3569 Print a summary identifying the repository state at REV using one or
3576 Print a summary identifying the repository state at REV using one or
3570 two parent hash identifiers, followed by a "+" if the working
3577 two parent hash identifiers, followed by a "+" if the working
3571 directory has uncommitted changes, the branch name (if not default),
3578 directory has uncommitted changes, the branch name (if not default),
3572 a list of tags, and a list of bookmarks.
3579 a list of tags, and a list of bookmarks.
3573
3580
3574 When REV is not given, print a summary of the current state of the
3581 When REV is not given, print a summary of the current state of the
3575 repository.
3582 repository.
3576
3583
3577 Specifying a path to a repository root or Mercurial bundle will
3584 Specifying a path to a repository root or Mercurial bundle will
3578 cause lookup to operate on that repository/bundle.
3585 cause lookup to operate on that repository/bundle.
3579
3586
3580 .. container:: verbose
3587 .. container:: verbose
3581
3588
3582 Examples:
3589 Examples:
3583
3590
3584 - generate a build identifier for the working directory::
3591 - generate a build identifier for the working directory::
3585
3592
3586 hg id --id > build-id.dat
3593 hg id --id > build-id.dat
3587
3594
3588 - find the revision corresponding to a tag::
3595 - find the revision corresponding to a tag::
3589
3596
3590 hg id -n -r 1.3
3597 hg id -n -r 1.3
3591
3598
3592 - check the most recent revision of a remote repository::
3599 - check the most recent revision of a remote repository::
3593
3600
3594 hg id -r tip http://selenic.com/hg/
3601 hg id -r tip http://selenic.com/hg/
3595
3602
3596 Returns 0 if successful.
3603 Returns 0 if successful.
3597 """
3604 """
3598
3605
3599 if not repo and not source:
3606 if not repo and not source:
3600 raise util.Abort(_("there is no Mercurial repository here "
3607 raise util.Abort(_("there is no Mercurial repository here "
3601 "(.hg not found)"))
3608 "(.hg not found)"))
3602
3609
3603 hexfunc = ui.debugflag and hex or short
3610 hexfunc = ui.debugflag and hex or short
3604 default = not (num or id or branch or tags or bookmarks)
3611 default = not (num or id or branch or tags or bookmarks)
3605 output = []
3612 output = []
3606 revs = []
3613 revs = []
3607
3614
3608 if source:
3615 if source:
3609 source, branches = hg.parseurl(ui.expandpath(source))
3616 source, branches = hg.parseurl(ui.expandpath(source))
3610 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3617 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3611 repo = peer.local()
3618 repo = peer.local()
3612 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3619 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3613
3620
3614 if not repo:
3621 if not repo:
3615 if num or branch or tags:
3622 if num or branch or tags:
3616 raise util.Abort(
3623 raise util.Abort(
3617 _("can't query remote revision number, branch, or tags"))
3624 _("can't query remote revision number, branch, or tags"))
3618 if not rev and revs:
3625 if not rev and revs:
3619 rev = revs[0]
3626 rev = revs[0]
3620 if not rev:
3627 if not rev:
3621 rev = "tip"
3628 rev = "tip"
3622
3629
3623 remoterev = peer.lookup(rev)
3630 remoterev = peer.lookup(rev)
3624 if default or id:
3631 if default or id:
3625 output = [hexfunc(remoterev)]
3632 output = [hexfunc(remoterev)]
3626
3633
3627 def getbms():
3634 def getbms():
3628 bms = []
3635 bms = []
3629
3636
3630 if 'bookmarks' in peer.listkeys('namespaces'):
3637 if 'bookmarks' in peer.listkeys('namespaces'):
3631 hexremoterev = hex(remoterev)
3638 hexremoterev = hex(remoterev)
3632 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3639 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3633 if bmr == hexremoterev]
3640 if bmr == hexremoterev]
3634
3641
3635 return sorted(bms)
3642 return sorted(bms)
3636
3643
3637 if bookmarks:
3644 if bookmarks:
3638 output.extend(getbms())
3645 output.extend(getbms())
3639 elif default and not ui.quiet:
3646 elif default and not ui.quiet:
3640 # multiple bookmarks for a single parent separated by '/'
3647 # multiple bookmarks for a single parent separated by '/'
3641 bm = '/'.join(getbms())
3648 bm = '/'.join(getbms())
3642 if bm:
3649 if bm:
3643 output.append(bm)
3650 output.append(bm)
3644 else:
3651 else:
3645 if not rev:
3652 if not rev:
3646 ctx = repo[None]
3653 ctx = repo[None]
3647 parents = ctx.parents()
3654 parents = ctx.parents()
3648 changed = ""
3655 changed = ""
3649 if default or id or num:
3656 if default or id or num:
3650 if (util.any(repo.status())
3657 if (util.any(repo.status())
3651 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3658 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3652 changed = '+'
3659 changed = '+'
3653 if default or id:
3660 if default or id:
3654 output = ["%s%s" %
3661 output = ["%s%s" %
3655 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3662 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3656 if num:
3663 if num:
3657 output.append("%s%s" %
3664 output.append("%s%s" %
3658 ('+'.join([str(p.rev()) for p in parents]), changed))
3665 ('+'.join([str(p.rev()) for p in parents]), changed))
3659 else:
3666 else:
3660 ctx = scmutil.revsingle(repo, rev)
3667 ctx = scmutil.revsingle(repo, rev)
3661 if default or id:
3668 if default or id:
3662 output = [hexfunc(ctx.node())]
3669 output = [hexfunc(ctx.node())]
3663 if num:
3670 if num:
3664 output.append(str(ctx.rev()))
3671 output.append(str(ctx.rev()))
3665
3672
3666 if default and not ui.quiet:
3673 if default and not ui.quiet:
3667 b = ctx.branch()
3674 b = ctx.branch()
3668 if b != 'default':
3675 if b != 'default':
3669 output.append("(%s)" % b)
3676 output.append("(%s)" % b)
3670
3677
3671 # multiple tags for a single parent separated by '/'
3678 # multiple tags for a single parent separated by '/'
3672 t = '/'.join(ctx.tags())
3679 t = '/'.join(ctx.tags())
3673 if t:
3680 if t:
3674 output.append(t)
3681 output.append(t)
3675
3682
3676 # multiple bookmarks for a single parent separated by '/'
3683 # multiple bookmarks for a single parent separated by '/'
3677 bm = '/'.join(ctx.bookmarks())
3684 bm = '/'.join(ctx.bookmarks())
3678 if bm:
3685 if bm:
3679 output.append(bm)
3686 output.append(bm)
3680 else:
3687 else:
3681 if branch:
3688 if branch:
3682 output.append(ctx.branch())
3689 output.append(ctx.branch())
3683
3690
3684 if tags:
3691 if tags:
3685 output.extend(ctx.tags())
3692 output.extend(ctx.tags())
3686
3693
3687 if bookmarks:
3694 if bookmarks:
3688 output.extend(ctx.bookmarks())
3695 output.extend(ctx.bookmarks())
3689
3696
3690 ui.write("%s\n" % ' '.join(output))
3697 ui.write("%s\n" % ' '.join(output))
3691
3698
3692 @command('import|patch',
3699 @command('import|patch',
3693 [('p', 'strip', 1,
3700 [('p', 'strip', 1,
3694 _('directory strip option for patch. This has the same '
3701 _('directory strip option for patch. This has the same '
3695 'meaning as the corresponding patch option'), _('NUM')),
3702 'meaning as the corresponding patch option'), _('NUM')),
3696 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3703 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3697 ('e', 'edit', False, _('invoke editor on commit messages')),
3704 ('e', 'edit', False, _('invoke editor on commit messages')),
3698 ('f', 'force', None,
3705 ('f', 'force', None,
3699 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3706 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3700 ('', 'no-commit', None,
3707 ('', 'no-commit', None,
3701 _("don't commit, just update the working directory")),
3708 _("don't commit, just update the working directory")),
3702 ('', 'bypass', None,
3709 ('', 'bypass', None,
3703 _("apply patch without touching the working directory")),
3710 _("apply patch without touching the working directory")),
3704 ('', 'partial', None,
3711 ('', 'partial', None,
3705 _('commit even if some hunks fail')),
3712 _('commit even if some hunks fail')),
3706 ('', 'exact', None,
3713 ('', 'exact', None,
3707 _('apply patch to the nodes from which it was generated')),
3714 _('apply patch to the nodes from which it was generated')),
3708 ('', 'import-branch', None,
3715 ('', 'import-branch', None,
3709 _('use any branch information in patch (implied by --exact)'))] +
3716 _('use any branch information in patch (implied by --exact)'))] +
3710 commitopts + commitopts2 + similarityopts,
3717 commitopts + commitopts2 + similarityopts,
3711 _('[OPTION]... PATCH...'))
3718 _('[OPTION]... PATCH...'))
3712 def import_(ui, repo, patch1=None, *patches, **opts):
3719 def import_(ui, repo, patch1=None, *patches, **opts):
3713 """import an ordered set of patches
3720 """import an ordered set of patches
3714
3721
3715 Import a list of patches and commit them individually (unless
3722 Import a list of patches and commit them individually (unless
3716 --no-commit is specified).
3723 --no-commit is specified).
3717
3724
3718 Because import first applies changes to the working directory,
3725 Because import first applies changes to the working directory,
3719 import will abort if there are outstanding changes.
3726 import will abort if there are outstanding changes.
3720
3727
3721 You can import a patch straight from a mail message. Even patches
3728 You can import a patch straight from a mail message. Even patches
3722 as attachments work (to use the body part, it must have type
3729 as attachments work (to use the body part, it must have type
3723 text/plain or text/x-patch). From and Subject headers of email
3730 text/plain or text/x-patch). From and Subject headers of email
3724 message are used as default committer and commit message. All
3731 message are used as default committer and commit message. All
3725 text/plain body parts before first diff are added to commit
3732 text/plain body parts before first diff are added to commit
3726 message.
3733 message.
3727
3734
3728 If the imported patch was generated by :hg:`export`, user and
3735 If the imported patch was generated by :hg:`export`, user and
3729 description from patch override values from message headers and
3736 description from patch override values from message headers and
3730 body. Values given on command line with -m/--message and -u/--user
3737 body. Values given on command line with -m/--message and -u/--user
3731 override these.
3738 override these.
3732
3739
3733 If --exact is specified, import will set the working directory to
3740 If --exact is specified, import will set the working directory to
3734 the parent of each patch before applying it, and will abort if the
3741 the parent of each patch before applying it, and will abort if the
3735 resulting changeset has a different ID than the one recorded in
3742 resulting changeset has a different ID than the one recorded in
3736 the patch. This may happen due to character set problems or other
3743 the patch. This may happen due to character set problems or other
3737 deficiencies in the text patch format.
3744 deficiencies in the text patch format.
3738
3745
3739 Use --bypass to apply and commit patches directly to the
3746 Use --bypass to apply and commit patches directly to the
3740 repository, not touching the working directory. Without --exact,
3747 repository, not touching the working directory. Without --exact,
3741 patches will be applied on top of the working directory parent
3748 patches will be applied on top of the working directory parent
3742 revision.
3749 revision.
3743
3750
3744 With -s/--similarity, hg will attempt to discover renames and
3751 With -s/--similarity, hg will attempt to discover renames and
3745 copies in the patch in the same way as :hg:`addremove`.
3752 copies in the patch in the same way as :hg:`addremove`.
3746
3753
3747 Use --partial to ensure a changeset will be created from the patch
3754 Use --partial to ensure a changeset will be created from the patch
3748 even if some hunks fail to apply. Hunks that fail to apply will be
3755 even if some hunks fail to apply. Hunks that fail to apply will be
3749 written to a <target-file>.rej file. Conflicts can then be resolved
3756 written to a <target-file>.rej file. Conflicts can then be resolved
3750 by hand before :hg:`commit --amend` is run to update the created
3757 by hand before :hg:`commit --amend` is run to update the created
3751 changeset. This flag exists to let people import patches that
3758 changeset. This flag exists to let people import patches that
3752 partially apply without losing the associated metadata (author,
3759 partially apply without losing the associated metadata (author,
3753 date, description, ...), Note that when none of the hunk applies
3760 date, description, ...), Note that when none of the hunk applies
3754 cleanly, :hg:`import --partial` will create an empty changeset,
3761 cleanly, :hg:`import --partial` will create an empty changeset,
3755 importing only the patch metadata.
3762 importing only the patch metadata.
3756
3763
3757 To read a patch from standard input, use "-" as the patch name. If
3764 To read a patch from standard input, use "-" as the patch name. If
3758 a URL is specified, the patch will be downloaded from it.
3765 a URL is specified, the patch will be downloaded from it.
3759 See :hg:`help dates` for a list of formats valid for -d/--date.
3766 See :hg:`help dates` for a list of formats valid for -d/--date.
3760
3767
3761 .. container:: verbose
3768 .. container:: verbose
3762
3769
3763 Examples:
3770 Examples:
3764
3771
3765 - import a traditional patch from a website and detect renames::
3772 - import a traditional patch from a website and detect renames::
3766
3773
3767 hg import -s 80 http://example.com/bugfix.patch
3774 hg import -s 80 http://example.com/bugfix.patch
3768
3775
3769 - import a changeset from an hgweb server::
3776 - import a changeset from an hgweb server::
3770
3777
3771 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3778 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3772
3779
3773 - import all the patches in an Unix-style mbox::
3780 - import all the patches in an Unix-style mbox::
3774
3781
3775 hg import incoming-patches.mbox
3782 hg import incoming-patches.mbox
3776
3783
3777 - attempt to exactly restore an exported changeset (not always
3784 - attempt to exactly restore an exported changeset (not always
3778 possible)::
3785 possible)::
3779
3786
3780 hg import --exact proposed-fix.patch
3787 hg import --exact proposed-fix.patch
3781
3788
3782 Returns 0 on success, 1 on partial success (see --partial).
3789 Returns 0 on success, 1 on partial success (see --partial).
3783 """
3790 """
3784
3791
3785 if not patch1:
3792 if not patch1:
3786 raise util.Abort(_('need at least one patch to import'))
3793 raise util.Abort(_('need at least one patch to import'))
3787
3794
3788 patches = (patch1,) + patches
3795 patches = (patch1,) + patches
3789
3796
3790 date = opts.get('date')
3797 date = opts.get('date')
3791 if date:
3798 if date:
3792 opts['date'] = util.parsedate(date)
3799 opts['date'] = util.parsedate(date)
3793
3800
3794 update = not opts.get('bypass')
3801 update = not opts.get('bypass')
3795 if not update and opts.get('no_commit'):
3802 if not update and opts.get('no_commit'):
3796 raise util.Abort(_('cannot use --no-commit with --bypass'))
3803 raise util.Abort(_('cannot use --no-commit with --bypass'))
3797 try:
3804 try:
3798 sim = float(opts.get('similarity') or 0)
3805 sim = float(opts.get('similarity') or 0)
3799 except ValueError:
3806 except ValueError:
3800 raise util.Abort(_('similarity must be a number'))
3807 raise util.Abort(_('similarity must be a number'))
3801 if sim < 0 or sim > 100:
3808 if sim < 0 or sim > 100:
3802 raise util.Abort(_('similarity must be between 0 and 100'))
3809 raise util.Abort(_('similarity must be between 0 and 100'))
3803 if sim and not update:
3810 if sim and not update:
3804 raise util.Abort(_('cannot use --similarity with --bypass'))
3811 raise util.Abort(_('cannot use --similarity with --bypass'))
3805
3812
3806 if update:
3813 if update:
3807 cmdutil.checkunfinished(repo)
3814 cmdutil.checkunfinished(repo)
3808 if (opts.get('exact') or not opts.get('force')) and update:
3815 if (opts.get('exact') or not opts.get('force')) and update:
3809 cmdutil.bailifchanged(repo)
3816 cmdutil.bailifchanged(repo)
3810
3817
3811 base = opts["base"]
3818 base = opts["base"]
3812 wlock = lock = tr = None
3819 wlock = lock = tr = None
3813 msgs = []
3820 msgs = []
3814 ret = 0
3821 ret = 0
3815
3822
3816
3823
3817 try:
3824 try:
3818 try:
3825 try:
3819 wlock = repo.wlock()
3826 wlock = repo.wlock()
3820 if not opts.get('no_commit'):
3827 if not opts.get('no_commit'):
3821 lock = repo.lock()
3828 lock = repo.lock()
3822 tr = repo.transaction('import')
3829 tr = repo.transaction('import')
3823 parents = repo.parents()
3830 parents = repo.parents()
3824 for patchurl in patches:
3831 for patchurl in patches:
3825 if patchurl == '-':
3832 if patchurl == '-':
3826 ui.status(_('applying patch from stdin\n'))
3833 ui.status(_('applying patch from stdin\n'))
3827 patchfile = ui.fin
3834 patchfile = ui.fin
3828 patchurl = 'stdin' # for error message
3835 patchurl = 'stdin' # for error message
3829 else:
3836 else:
3830 patchurl = os.path.join(base, patchurl)
3837 patchurl = os.path.join(base, patchurl)
3831 ui.status(_('applying %s\n') % patchurl)
3838 ui.status(_('applying %s\n') % patchurl)
3832 patchfile = hg.openpath(ui, patchurl)
3839 patchfile = hg.openpath(ui, patchurl)
3833
3840
3834 haspatch = False
3841 haspatch = False
3835 for hunk in patch.split(patchfile):
3842 for hunk in patch.split(patchfile):
3836 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3843 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3837 parents, opts,
3844 parents, opts,
3838 msgs, hg.clean)
3845 msgs, hg.clean)
3839 if msg:
3846 if msg:
3840 haspatch = True
3847 haspatch = True
3841 ui.note(msg + '\n')
3848 ui.note(msg + '\n')
3842 if update or opts.get('exact'):
3849 if update or opts.get('exact'):
3843 parents = repo.parents()
3850 parents = repo.parents()
3844 else:
3851 else:
3845 parents = [repo[node]]
3852 parents = [repo[node]]
3846 if rej:
3853 if rej:
3847 ui.write_err(_("patch applied partially\n"))
3854 ui.write_err(_("patch applied partially\n"))
3848 ui.write_err(("(fix the .rej files and run "
3855 ui.write_err(("(fix the .rej files and run "
3849 "`hg commit --amend`)\n"))
3856 "`hg commit --amend`)\n"))
3850 ret = 1
3857 ret = 1
3851 break
3858 break
3852
3859
3853 if not haspatch:
3860 if not haspatch:
3854 raise util.Abort(_('%s: no diffs found') % patchurl)
3861 raise util.Abort(_('%s: no diffs found') % patchurl)
3855
3862
3856 if tr:
3863 if tr:
3857 tr.close()
3864 tr.close()
3858 if msgs:
3865 if msgs:
3859 repo.savecommitmessage('\n* * *\n'.join(msgs))
3866 repo.savecommitmessage('\n* * *\n'.join(msgs))
3860 return ret
3867 return ret
3861 except: # re-raises
3868 except: # re-raises
3862 # wlock.release() indirectly calls dirstate.write(): since
3869 # wlock.release() indirectly calls dirstate.write(): since
3863 # we're crashing, we do not want to change the working dir
3870 # we're crashing, we do not want to change the working dir
3864 # parent after all, so make sure it writes nothing
3871 # parent after all, so make sure it writes nothing
3865 repo.dirstate.invalidate()
3872 repo.dirstate.invalidate()
3866 raise
3873 raise
3867 finally:
3874 finally:
3868 if tr:
3875 if tr:
3869 tr.release()
3876 tr.release()
3870 release(lock, wlock)
3877 release(lock, wlock)
3871
3878
3872 @command('incoming|in',
3879 @command('incoming|in',
3873 [('f', 'force', None,
3880 [('f', 'force', None,
3874 _('run even if remote repository is unrelated')),
3881 _('run even if remote repository is unrelated')),
3875 ('n', 'newest-first', None, _('show newest record first')),
3882 ('n', 'newest-first', None, _('show newest record first')),
3876 ('', 'bundle', '',
3883 ('', 'bundle', '',
3877 _('file to store the bundles into'), _('FILE')),
3884 _('file to store the bundles into'), _('FILE')),
3878 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3885 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3879 ('B', 'bookmarks', False, _("compare bookmarks")),
3886 ('B', 'bookmarks', False, _("compare bookmarks")),
3880 ('b', 'branch', [],
3887 ('b', 'branch', [],
3881 _('a specific branch you would like to pull'), _('BRANCH')),
3888 _('a specific branch you would like to pull'), _('BRANCH')),
3882 ] + logopts + remoteopts + subrepoopts,
3889 ] + logopts + remoteopts + subrepoopts,
3883 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3890 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3884 def incoming(ui, repo, source="default", **opts):
3891 def incoming(ui, repo, source="default", **opts):
3885 """show new changesets found in source
3892 """show new changesets found in source
3886
3893
3887 Show new changesets found in the specified path/URL or the default
3894 Show new changesets found in the specified path/URL or the default
3888 pull location. These are the changesets that would have been pulled
3895 pull location. These are the changesets that would have been pulled
3889 if a pull at the time you issued this command.
3896 if a pull at the time you issued this command.
3890
3897
3891 For remote repository, using --bundle avoids downloading the
3898 For remote repository, using --bundle avoids downloading the
3892 changesets twice if the incoming is followed by a pull.
3899 changesets twice if the incoming is followed by a pull.
3893
3900
3894 See pull for valid source format details.
3901 See pull for valid source format details.
3895
3902
3896 .. container:: verbose
3903 .. container:: verbose
3897
3904
3898 Examples:
3905 Examples:
3899
3906
3900 - show incoming changes with patches and full description::
3907 - show incoming changes with patches and full description::
3901
3908
3902 hg incoming -vp
3909 hg incoming -vp
3903
3910
3904 - show incoming changes excluding merges, store a bundle::
3911 - show incoming changes excluding merges, store a bundle::
3905
3912
3906 hg in -vpM --bundle incoming.hg
3913 hg in -vpM --bundle incoming.hg
3907 hg pull incoming.hg
3914 hg pull incoming.hg
3908
3915
3909 - briefly list changes inside a bundle::
3916 - briefly list changes inside a bundle::
3910
3917
3911 hg in changes.hg -T "{desc|firstline}\\n"
3918 hg in changes.hg -T "{desc|firstline}\\n"
3912
3919
3913 Returns 0 if there are incoming changes, 1 otherwise.
3920 Returns 0 if there are incoming changes, 1 otherwise.
3914 """
3921 """
3915 if opts.get('graph'):
3922 if opts.get('graph'):
3916 cmdutil.checkunsupportedgraphflags([], opts)
3923 cmdutil.checkunsupportedgraphflags([], opts)
3917 def display(other, chlist, displayer):
3924 def display(other, chlist, displayer):
3918 revdag = cmdutil.graphrevs(other, chlist, opts)
3925 revdag = cmdutil.graphrevs(other, chlist, opts)
3919 showparents = [ctx.node() for ctx in repo[None].parents()]
3926 showparents = [ctx.node() for ctx in repo[None].parents()]
3920 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3927 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3921 graphmod.asciiedges)
3928 graphmod.asciiedges)
3922
3929
3923 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3930 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3924 return 0
3931 return 0
3925
3932
3926 if opts.get('bundle') and opts.get('subrepos'):
3933 if opts.get('bundle') and opts.get('subrepos'):
3927 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3934 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3928
3935
3929 if opts.get('bookmarks'):
3936 if opts.get('bookmarks'):
3930 source, branches = hg.parseurl(ui.expandpath(source),
3937 source, branches = hg.parseurl(ui.expandpath(source),
3931 opts.get('branch'))
3938 opts.get('branch'))
3932 other = hg.peer(repo, opts, source)
3939 other = hg.peer(repo, opts, source)
3933 if 'bookmarks' not in other.listkeys('namespaces'):
3940 if 'bookmarks' not in other.listkeys('namespaces'):
3934 ui.warn(_("remote doesn't support bookmarks\n"))
3941 ui.warn(_("remote doesn't support bookmarks\n"))
3935 return 0
3942 return 0
3936 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3943 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3937 return bookmarks.diff(ui, repo, other)
3944 return bookmarks.diff(ui, repo, other)
3938
3945
3939 repo._subtoppath = ui.expandpath(source)
3946 repo._subtoppath = ui.expandpath(source)
3940 try:
3947 try:
3941 return hg.incoming(ui, repo, source, opts)
3948 return hg.incoming(ui, repo, source, opts)
3942 finally:
3949 finally:
3943 del repo._subtoppath
3950 del repo._subtoppath
3944
3951
3945
3952
3946 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3953 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3947 def init(ui, dest=".", **opts):
3954 def init(ui, dest=".", **opts):
3948 """create a new repository in the given directory
3955 """create a new repository in the given directory
3949
3956
3950 Initialize a new repository in the given directory. If the given
3957 Initialize a new repository in the given directory. If the given
3951 directory does not exist, it will be created.
3958 directory does not exist, it will be created.
3952
3959
3953 If no directory is given, the current directory is used.
3960 If no directory is given, the current directory is used.
3954
3961
3955 It is possible to specify an ``ssh://`` URL as the destination.
3962 It is possible to specify an ``ssh://`` URL as the destination.
3956 See :hg:`help urls` for more information.
3963 See :hg:`help urls` for more information.
3957
3964
3958 Returns 0 on success.
3965 Returns 0 on success.
3959 """
3966 """
3960 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3967 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3961
3968
3962 @command('locate',
3969 @command('locate',
3963 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3970 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3964 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3971 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3965 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3972 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3966 ] + walkopts,
3973 ] + walkopts,
3967 _('[OPTION]... [PATTERN]...'))
3974 _('[OPTION]... [PATTERN]...'))
3968 def locate(ui, repo, *pats, **opts):
3975 def locate(ui, repo, *pats, **opts):
3969 """locate files matching specific patterns
3976 """locate files matching specific patterns
3970
3977
3971 Print files under Mercurial control in the working directory whose
3978 Print files under Mercurial control in the working directory whose
3972 names match the given patterns.
3979 names match the given patterns.
3973
3980
3974 By default, this command searches all directories in the working
3981 By default, this command searches all directories in the working
3975 directory. To search just the current directory and its
3982 directory. To search just the current directory and its
3976 subdirectories, use "--include .".
3983 subdirectories, use "--include .".
3977
3984
3978 If no patterns are given to match, this command prints the names
3985 If no patterns are given to match, this command prints the names
3979 of all files under Mercurial control in the working directory.
3986 of all files under Mercurial control in the working directory.
3980
3987
3981 If you want to feed the output of this command into the "xargs"
3988 If you want to feed the output of this command into the "xargs"
3982 command, use the -0 option to both this command and "xargs". This
3989 command, use the -0 option to both this command and "xargs". This
3983 will avoid the problem of "xargs" treating single filenames that
3990 will avoid the problem of "xargs" treating single filenames that
3984 contain whitespace as multiple filenames.
3991 contain whitespace as multiple filenames.
3985
3992
3986 Returns 0 if a match is found, 1 otherwise.
3993 Returns 0 if a match is found, 1 otherwise.
3987 """
3994 """
3988 end = opts.get('print0') and '\0' or '\n'
3995 end = opts.get('print0') and '\0' or '\n'
3989 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3996 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3990
3997
3991 ret = 1
3998 ret = 1
3992 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3999 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3993 m.bad = lambda x, y: False
4000 m.bad = lambda x, y: False
3994 for abs in repo[rev].walk(m):
4001 for abs in repo[rev].walk(m):
3995 if not rev and abs not in repo.dirstate:
4002 if not rev and abs not in repo.dirstate:
3996 continue
4003 continue
3997 if opts.get('fullpath'):
4004 if opts.get('fullpath'):
3998 ui.write(repo.wjoin(abs), end)
4005 ui.write(repo.wjoin(abs), end)
3999 else:
4006 else:
4000 ui.write(((pats and m.rel(abs)) or abs), end)
4007 ui.write(((pats and m.rel(abs)) or abs), end)
4001 ret = 0
4008 ret = 0
4002
4009
4003 return ret
4010 return ret
4004
4011
4005 @command('^log|history',
4012 @command('^log|history',
4006 [('f', 'follow', None,
4013 [('f', 'follow', None,
4007 _('follow changeset history, or file history across copies and renames')),
4014 _('follow changeset history, or file history across copies and renames')),
4008 ('', 'follow-first', None,
4015 ('', 'follow-first', None,
4009 _('only follow the first parent of merge changesets (DEPRECATED)')),
4016 _('only follow the first parent of merge changesets (DEPRECATED)')),
4010 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4017 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4011 ('C', 'copies', None, _('show copied files')),
4018 ('C', 'copies', None, _('show copied files')),
4012 ('k', 'keyword', [],
4019 ('k', 'keyword', [],
4013 _('do case-insensitive search for a given text'), _('TEXT')),
4020 _('do case-insensitive search for a given text'), _('TEXT')),
4014 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4021 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4015 ('', 'removed', None, _('include revisions where files were removed')),
4022 ('', 'removed', None, _('include revisions where files were removed')),
4016 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4023 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4017 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4024 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4018 ('', 'only-branch', [],
4025 ('', 'only-branch', [],
4019 _('show only changesets within the given named branch (DEPRECATED)'),
4026 _('show only changesets within the given named branch (DEPRECATED)'),
4020 _('BRANCH')),
4027 _('BRANCH')),
4021 ('b', 'branch', [],
4028 ('b', 'branch', [],
4022 _('show changesets within the given named branch'), _('BRANCH')),
4029 _('show changesets within the given named branch'), _('BRANCH')),
4023 ('P', 'prune', [],
4030 ('P', 'prune', [],
4024 _('do not display revision or any of its ancestors'), _('REV')),
4031 _('do not display revision or any of its ancestors'), _('REV')),
4025 ] + logopts + walkopts,
4032 ] + logopts + walkopts,
4026 _('[OPTION]... [FILE]'))
4033 _('[OPTION]... [FILE]'))
4027 def log(ui, repo, *pats, **opts):
4034 def log(ui, repo, *pats, **opts):
4028 """show revision history of entire repository or files
4035 """show revision history of entire repository or files
4029
4036
4030 Print the revision history of the specified files or the entire
4037 Print the revision history of the specified files or the entire
4031 project.
4038 project.
4032
4039
4033 If no revision range is specified, the default is ``tip:0`` unless
4040 If no revision range is specified, the default is ``tip:0`` unless
4034 --follow is set, in which case the working directory parent is
4041 --follow is set, in which case the working directory parent is
4035 used as the starting revision.
4042 used as the starting revision.
4036
4043
4037 File history is shown without following rename or copy history of
4044 File history is shown without following rename or copy history of
4038 files. Use -f/--follow with a filename to follow history across
4045 files. Use -f/--follow with a filename to follow history across
4039 renames and copies. --follow without a filename will only show
4046 renames and copies. --follow without a filename will only show
4040 ancestors or descendants of the starting revision.
4047 ancestors or descendants of the starting revision.
4041
4048
4042 By default this command prints revision number and changeset id,
4049 By default this command prints revision number and changeset id,
4043 tags, non-trivial parents, user, date and time, and a summary for
4050 tags, non-trivial parents, user, date and time, and a summary for
4044 each commit. When the -v/--verbose switch is used, the list of
4051 each commit. When the -v/--verbose switch is used, the list of
4045 changed files and full commit message are shown.
4052 changed files and full commit message are shown.
4046
4053
4047 With --graph the revisions are shown as an ASCII art DAG with the most
4054 With --graph the revisions are shown as an ASCII art DAG with the most
4048 recent changeset at the top.
4055 recent changeset at the top.
4049 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4056 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4050 and '+' represents a fork where the changeset from the lines below is a
4057 and '+' represents a fork where the changeset from the lines below is a
4051 parent of the 'o' merge on the same line.
4058 parent of the 'o' merge on the same line.
4052
4059
4053 .. note::
4060 .. note::
4054
4061
4055 log -p/--patch may generate unexpected diff output for merge
4062 log -p/--patch may generate unexpected diff output for merge
4056 changesets, as it will only compare the merge changeset against
4063 changesets, as it will only compare the merge changeset against
4057 its first parent. Also, only files different from BOTH parents
4064 its first parent. Also, only files different from BOTH parents
4058 will appear in files:.
4065 will appear in files:.
4059
4066
4060 .. note::
4067 .. note::
4061
4068
4062 for performance reasons, log FILE may omit duplicate changes
4069 for performance reasons, log FILE may omit duplicate changes
4063 made on branches and will not show deletions. To see all
4070 made on branches and will not show deletions. To see all
4064 changes including duplicates and deletions, use the --removed
4071 changes including duplicates and deletions, use the --removed
4065 switch.
4072 switch.
4066
4073
4067 .. container:: verbose
4074 .. container:: verbose
4068
4075
4069 Some examples:
4076 Some examples:
4070
4077
4071 - changesets with full descriptions and file lists::
4078 - changesets with full descriptions and file lists::
4072
4079
4073 hg log -v
4080 hg log -v
4074
4081
4075 - changesets ancestral to the working directory::
4082 - changesets ancestral to the working directory::
4076
4083
4077 hg log -f
4084 hg log -f
4078
4085
4079 - last 10 commits on the current branch::
4086 - last 10 commits on the current branch::
4080
4087
4081 hg log -l 10 -b .
4088 hg log -l 10 -b .
4082
4089
4083 - changesets showing all modifications of a file, including removals::
4090 - changesets showing all modifications of a file, including removals::
4084
4091
4085 hg log --removed file.c
4092 hg log --removed file.c
4086
4093
4087 - all changesets that touch a directory, with diffs, excluding merges::
4094 - all changesets that touch a directory, with diffs, excluding merges::
4088
4095
4089 hg log -Mp lib/
4096 hg log -Mp lib/
4090
4097
4091 - all revision numbers that match a keyword::
4098 - all revision numbers that match a keyword::
4092
4099
4093 hg log -k bug --template "{rev}\\n"
4100 hg log -k bug --template "{rev}\\n"
4094
4101
4095 - check if a given changeset is included is a tagged release::
4102 - check if a given changeset is included is a tagged release::
4096
4103
4097 hg log -r "a21ccf and ancestor(1.9)"
4104 hg log -r "a21ccf and ancestor(1.9)"
4098
4105
4099 - find all changesets by some user in a date range::
4106 - find all changesets by some user in a date range::
4100
4107
4101 hg log -k alice -d "may 2008 to jul 2008"
4108 hg log -k alice -d "may 2008 to jul 2008"
4102
4109
4103 - summary of all changesets after the last tag::
4110 - summary of all changesets after the last tag::
4104
4111
4105 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4112 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4106
4113
4107 See :hg:`help dates` for a list of formats valid for -d/--date.
4114 See :hg:`help dates` for a list of formats valid for -d/--date.
4108
4115
4109 See :hg:`help revisions` and :hg:`help revsets` for more about
4116 See :hg:`help revisions` and :hg:`help revsets` for more about
4110 specifying revisions.
4117 specifying revisions.
4111
4118
4112 See :hg:`help templates` for more about pre-packaged styles and
4119 See :hg:`help templates` for more about pre-packaged styles and
4113 specifying custom templates.
4120 specifying custom templates.
4114
4121
4115 Returns 0 on success.
4122 Returns 0 on success.
4116 """
4123 """
4117 if opts.get('graph'):
4124 if opts.get('graph'):
4118 return cmdutil.graphlog(ui, repo, *pats, **opts)
4125 return cmdutil.graphlog(ui, repo, *pats, **opts)
4119
4126
4120 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4127 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4121 limit = cmdutil.loglimit(opts)
4128 limit = cmdutil.loglimit(opts)
4122 count = 0
4129 count = 0
4123
4130
4124 getrenamed = None
4131 getrenamed = None
4125 if opts.get('copies'):
4132 if opts.get('copies'):
4126 endrev = None
4133 endrev = None
4127 if opts.get('rev'):
4134 if opts.get('rev'):
4128 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4135 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4129 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4136 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4130
4137
4131 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4138 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4132 for rev in revs:
4139 for rev in revs:
4133 if count == limit:
4140 if count == limit:
4134 break
4141 break
4135 ctx = repo[rev]
4142 ctx = repo[rev]
4136 copies = None
4143 copies = None
4137 if getrenamed is not None and rev:
4144 if getrenamed is not None and rev:
4138 copies = []
4145 copies = []
4139 for fn in ctx.files():
4146 for fn in ctx.files():
4140 rename = getrenamed(fn, rev)
4147 rename = getrenamed(fn, rev)
4141 if rename:
4148 if rename:
4142 copies.append((fn, rename[0]))
4149 copies.append((fn, rename[0]))
4143 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4150 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4144 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4151 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4145 if displayer.flush(rev):
4152 if displayer.flush(rev):
4146 count += 1
4153 count += 1
4147
4154
4148 displayer.close()
4155 displayer.close()
4149
4156
4150 @command('manifest',
4157 @command('manifest',
4151 [('r', 'rev', '', _('revision to display'), _('REV')),
4158 [('r', 'rev', '', _('revision to display'), _('REV')),
4152 ('', 'all', False, _("list files from all revisions"))],
4159 ('', 'all', False, _("list files from all revisions"))],
4153 _('[-r REV]'))
4160 _('[-r REV]'))
4154 def manifest(ui, repo, node=None, rev=None, **opts):
4161 def manifest(ui, repo, node=None, rev=None, **opts):
4155 """output the current or given revision of the project manifest
4162 """output the current or given revision of the project manifest
4156
4163
4157 Print a list of version controlled files for the given revision.
4164 Print a list of version controlled files for the given revision.
4158 If no revision is given, the first parent of the working directory
4165 If no revision is given, the first parent of the working directory
4159 is used, or the null revision if no revision is checked out.
4166 is used, or the null revision if no revision is checked out.
4160
4167
4161 With -v, print file permissions, symlink and executable bits.
4168 With -v, print file permissions, symlink and executable bits.
4162 With --debug, print file revision hashes.
4169 With --debug, print file revision hashes.
4163
4170
4164 If option --all is specified, the list of all files from all revisions
4171 If option --all is specified, the list of all files from all revisions
4165 is printed. This includes deleted and renamed files.
4172 is printed. This includes deleted and renamed files.
4166
4173
4167 Returns 0 on success.
4174 Returns 0 on success.
4168 """
4175 """
4169
4176
4170 fm = ui.formatter('manifest', opts)
4177 fm = ui.formatter('manifest', opts)
4171
4178
4172 if opts.get('all'):
4179 if opts.get('all'):
4173 if rev or node:
4180 if rev or node:
4174 raise util.Abort(_("can't specify a revision with --all"))
4181 raise util.Abort(_("can't specify a revision with --all"))
4175
4182
4176 res = []
4183 res = []
4177 prefix = "data/"
4184 prefix = "data/"
4178 suffix = ".i"
4185 suffix = ".i"
4179 plen = len(prefix)
4186 plen = len(prefix)
4180 slen = len(suffix)
4187 slen = len(suffix)
4181 lock = repo.lock()
4188 lock = repo.lock()
4182 try:
4189 try:
4183 for fn, b, size in repo.store.datafiles():
4190 for fn, b, size in repo.store.datafiles():
4184 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4191 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4185 res.append(fn[plen:-slen])
4192 res.append(fn[plen:-slen])
4186 finally:
4193 finally:
4187 lock.release()
4194 lock.release()
4188 for f in res:
4195 for f in res:
4189 fm.startitem()
4196 fm.startitem()
4190 fm.write("path", '%s\n', f)
4197 fm.write("path", '%s\n', f)
4191 fm.end()
4198 fm.end()
4192 return
4199 return
4193
4200
4194 if rev and node:
4201 if rev and node:
4195 raise util.Abort(_("please specify just one revision"))
4202 raise util.Abort(_("please specify just one revision"))
4196
4203
4197 if not node:
4204 if not node:
4198 node = rev
4205 node = rev
4199
4206
4200 char = {'l': '@', 'x': '*', '': ''}
4207 char = {'l': '@', 'x': '*', '': ''}
4201 mode = {'l': '644', 'x': '755', '': '644'}
4208 mode = {'l': '644', 'x': '755', '': '644'}
4202 ctx = scmutil.revsingle(repo, node)
4209 ctx = scmutil.revsingle(repo, node)
4203 mf = ctx.manifest()
4210 mf = ctx.manifest()
4204 for f in ctx:
4211 for f in ctx:
4205 fm.startitem()
4212 fm.startitem()
4206 fl = ctx[f].flags()
4213 fl = ctx[f].flags()
4207 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4214 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4208 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4215 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4209 fm.write('path', '%s\n', f)
4216 fm.write('path', '%s\n', f)
4210 fm.end()
4217 fm.end()
4211
4218
4212 @command('^merge',
4219 @command('^merge',
4213 [('f', 'force', None,
4220 [('f', 'force', None,
4214 _('force a merge including outstanding changes (DEPRECATED)')),
4221 _('force a merge including outstanding changes (DEPRECATED)')),
4215 ('r', 'rev', '', _('revision to merge'), _('REV')),
4222 ('r', 'rev', '', _('revision to merge'), _('REV')),
4216 ('P', 'preview', None,
4223 ('P', 'preview', None,
4217 _('review revisions to merge (no merge is performed)'))
4224 _('review revisions to merge (no merge is performed)'))
4218 ] + mergetoolopts,
4225 ] + mergetoolopts,
4219 _('[-P] [-f] [[-r] REV]'))
4226 _('[-P] [-f] [[-r] REV]'))
4220 def merge(ui, repo, node=None, **opts):
4227 def merge(ui, repo, node=None, **opts):
4221 """merge working directory with another revision
4228 """merge working directory with another revision
4222
4229
4223 The current working directory is updated with all changes made in
4230 The current working directory is updated with all changes made in
4224 the requested revision since the last common predecessor revision.
4231 the requested revision since the last common predecessor revision.
4225
4232
4226 Files that changed between either parent are marked as changed for
4233 Files that changed between either parent are marked as changed for
4227 the next commit and a commit must be performed before any further
4234 the next commit and a commit must be performed before any further
4228 updates to the repository are allowed. The next commit will have
4235 updates to the repository are allowed. The next commit will have
4229 two parents.
4236 two parents.
4230
4237
4231 ``--tool`` can be used to specify the merge tool used for file
4238 ``--tool`` can be used to specify the merge tool used for file
4232 merges. It overrides the HGMERGE environment variable and your
4239 merges. It overrides the HGMERGE environment variable and your
4233 configuration files. See :hg:`help merge-tools` for options.
4240 configuration files. See :hg:`help merge-tools` for options.
4234
4241
4235 If no revision is specified, the working directory's parent is a
4242 If no revision is specified, the working directory's parent is a
4236 head revision, and the current branch contains exactly one other
4243 head revision, and the current branch contains exactly one other
4237 head, the other head is merged with by default. Otherwise, an
4244 head, the other head is merged with by default. Otherwise, an
4238 explicit revision with which to merge with must be provided.
4245 explicit revision with which to merge with must be provided.
4239
4246
4240 :hg:`resolve` must be used to resolve unresolved files.
4247 :hg:`resolve` must be used to resolve unresolved files.
4241
4248
4242 To undo an uncommitted merge, use :hg:`update --clean .` which
4249 To undo an uncommitted merge, use :hg:`update --clean .` which
4243 will check out a clean copy of the original merge parent, losing
4250 will check out a clean copy of the original merge parent, losing
4244 all changes.
4251 all changes.
4245
4252
4246 Returns 0 on success, 1 if there are unresolved files.
4253 Returns 0 on success, 1 if there are unresolved files.
4247 """
4254 """
4248
4255
4249 if opts.get('rev') and node:
4256 if opts.get('rev') and node:
4250 raise util.Abort(_("please specify just one revision"))
4257 raise util.Abort(_("please specify just one revision"))
4251 if not node:
4258 if not node:
4252 node = opts.get('rev')
4259 node = opts.get('rev')
4253
4260
4254 if node:
4261 if node:
4255 node = scmutil.revsingle(repo, node).node()
4262 node = scmutil.revsingle(repo, node).node()
4256
4263
4257 if not node and repo._bookmarkcurrent:
4264 if not node and repo._bookmarkcurrent:
4258 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4265 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4259 curhead = repo[repo._bookmarkcurrent].node()
4266 curhead = repo[repo._bookmarkcurrent].node()
4260 if len(bmheads) == 2:
4267 if len(bmheads) == 2:
4261 if curhead == bmheads[0]:
4268 if curhead == bmheads[0]:
4262 node = bmheads[1]
4269 node = bmheads[1]
4263 else:
4270 else:
4264 node = bmheads[0]
4271 node = bmheads[0]
4265 elif len(bmheads) > 2:
4272 elif len(bmheads) > 2:
4266 raise util.Abort(_("multiple matching bookmarks to merge - "
4273 raise util.Abort(_("multiple matching bookmarks to merge - "
4267 "please merge with an explicit rev or bookmark"),
4274 "please merge with an explicit rev or bookmark"),
4268 hint=_("run 'hg heads' to see all heads"))
4275 hint=_("run 'hg heads' to see all heads"))
4269 elif len(bmheads) <= 1:
4276 elif len(bmheads) <= 1:
4270 raise util.Abort(_("no matching bookmark to merge - "
4277 raise util.Abort(_("no matching bookmark to merge - "
4271 "please merge with an explicit rev or bookmark"),
4278 "please merge with an explicit rev or bookmark"),
4272 hint=_("run 'hg heads' to see all heads"))
4279 hint=_("run 'hg heads' to see all heads"))
4273
4280
4274 if not node and not repo._bookmarkcurrent:
4281 if not node and not repo._bookmarkcurrent:
4275 branch = repo[None].branch()
4282 branch = repo[None].branch()
4276 bheads = repo.branchheads(branch)
4283 bheads = repo.branchheads(branch)
4277 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4284 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4278
4285
4279 if len(nbhs) > 2:
4286 if len(nbhs) > 2:
4280 raise util.Abort(_("branch '%s' has %d heads - "
4287 raise util.Abort(_("branch '%s' has %d heads - "
4281 "please merge with an explicit rev")
4288 "please merge with an explicit rev")
4282 % (branch, len(bheads)),
4289 % (branch, len(bheads)),
4283 hint=_("run 'hg heads .' to see heads"))
4290 hint=_("run 'hg heads .' to see heads"))
4284
4291
4285 parent = repo.dirstate.p1()
4292 parent = repo.dirstate.p1()
4286 if len(nbhs) <= 1:
4293 if len(nbhs) <= 1:
4287 if len(bheads) > 1:
4294 if len(bheads) > 1:
4288 raise util.Abort(_("heads are bookmarked - "
4295 raise util.Abort(_("heads are bookmarked - "
4289 "please merge with an explicit rev"),
4296 "please merge with an explicit rev"),
4290 hint=_("run 'hg heads' to see all heads"))
4297 hint=_("run 'hg heads' to see all heads"))
4291 if len(repo.heads()) > 1:
4298 if len(repo.heads()) > 1:
4292 raise util.Abort(_("branch '%s' has one head - "
4299 raise util.Abort(_("branch '%s' has one head - "
4293 "please merge with an explicit rev")
4300 "please merge with an explicit rev")
4294 % branch,
4301 % branch,
4295 hint=_("run 'hg heads' to see all heads"))
4302 hint=_("run 'hg heads' to see all heads"))
4296 msg, hint = _('nothing to merge'), None
4303 msg, hint = _('nothing to merge'), None
4297 if parent != repo.lookup(branch):
4304 if parent != repo.lookup(branch):
4298 hint = _("use 'hg update' instead")
4305 hint = _("use 'hg update' instead")
4299 raise util.Abort(msg, hint=hint)
4306 raise util.Abort(msg, hint=hint)
4300
4307
4301 if parent not in bheads:
4308 if parent not in bheads:
4302 raise util.Abort(_('working directory not at a head revision'),
4309 raise util.Abort(_('working directory not at a head revision'),
4303 hint=_("use 'hg update' or merge with an "
4310 hint=_("use 'hg update' or merge with an "
4304 "explicit revision"))
4311 "explicit revision"))
4305 if parent == nbhs[0]:
4312 if parent == nbhs[0]:
4306 node = nbhs[-1]
4313 node = nbhs[-1]
4307 else:
4314 else:
4308 node = nbhs[0]
4315 node = nbhs[0]
4309
4316
4310 if opts.get('preview'):
4317 if opts.get('preview'):
4311 # find nodes that are ancestors of p2 but not of p1
4318 # find nodes that are ancestors of p2 but not of p1
4312 p1 = repo.lookup('.')
4319 p1 = repo.lookup('.')
4313 p2 = repo.lookup(node)
4320 p2 = repo.lookup(node)
4314 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4321 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4315
4322
4316 displayer = cmdutil.show_changeset(ui, repo, opts)
4323 displayer = cmdutil.show_changeset(ui, repo, opts)
4317 for node in nodes:
4324 for node in nodes:
4318 displayer.show(repo[node])
4325 displayer.show(repo[node])
4319 displayer.close()
4326 displayer.close()
4320 return 0
4327 return 0
4321
4328
4322 try:
4329 try:
4323 # ui.forcemerge is an internal variable, do not document
4330 # ui.forcemerge is an internal variable, do not document
4324 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4331 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4325 return hg.merge(repo, node, force=opts.get('force'))
4332 return hg.merge(repo, node, force=opts.get('force'))
4326 finally:
4333 finally:
4327 ui.setconfig('ui', 'forcemerge', '', 'merge')
4334 ui.setconfig('ui', 'forcemerge', '', 'merge')
4328
4335
4329 @command('outgoing|out',
4336 @command('outgoing|out',
4330 [('f', 'force', None, _('run even when the destination is unrelated')),
4337 [('f', 'force', None, _('run even when the destination is unrelated')),
4331 ('r', 'rev', [],
4338 ('r', 'rev', [],
4332 _('a changeset intended to be included in the destination'), _('REV')),
4339 _('a changeset intended to be included in the destination'), _('REV')),
4333 ('n', 'newest-first', None, _('show newest record first')),
4340 ('n', 'newest-first', None, _('show newest record first')),
4334 ('B', 'bookmarks', False, _('compare bookmarks')),
4341 ('B', 'bookmarks', False, _('compare bookmarks')),
4335 ('b', 'branch', [], _('a specific branch you would like to push'),
4342 ('b', 'branch', [], _('a specific branch you would like to push'),
4336 _('BRANCH')),
4343 _('BRANCH')),
4337 ] + logopts + remoteopts + subrepoopts,
4344 ] + logopts + remoteopts + subrepoopts,
4338 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4345 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4339 def outgoing(ui, repo, dest=None, **opts):
4346 def outgoing(ui, repo, dest=None, **opts):
4340 """show changesets not found in the destination
4347 """show changesets not found in the destination
4341
4348
4342 Show changesets not found in the specified destination repository
4349 Show changesets not found in the specified destination repository
4343 or the default push location. These are the changesets that would
4350 or the default push location. These are the changesets that would
4344 be pushed if a push was requested.
4351 be pushed if a push was requested.
4345
4352
4346 See pull for details of valid destination formats.
4353 See pull for details of valid destination formats.
4347
4354
4348 Returns 0 if there are outgoing changes, 1 otherwise.
4355 Returns 0 if there are outgoing changes, 1 otherwise.
4349 """
4356 """
4350 if opts.get('graph'):
4357 if opts.get('graph'):
4351 cmdutil.checkunsupportedgraphflags([], opts)
4358 cmdutil.checkunsupportedgraphflags([], opts)
4352 o, other = hg._outgoing(ui, repo, dest, opts)
4359 o, other = hg._outgoing(ui, repo, dest, opts)
4353 if not o:
4360 if not o:
4354 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4361 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4355 return
4362 return
4356
4363
4357 revdag = cmdutil.graphrevs(repo, o, opts)
4364 revdag = cmdutil.graphrevs(repo, o, opts)
4358 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4365 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4359 showparents = [ctx.node() for ctx in repo[None].parents()]
4366 showparents = [ctx.node() for ctx in repo[None].parents()]
4360 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4367 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4361 graphmod.asciiedges)
4368 graphmod.asciiedges)
4362 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4369 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4363 return 0
4370 return 0
4364
4371
4365 if opts.get('bookmarks'):
4372 if opts.get('bookmarks'):
4366 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4373 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4367 dest, branches = hg.parseurl(dest, opts.get('branch'))
4374 dest, branches = hg.parseurl(dest, opts.get('branch'))
4368 other = hg.peer(repo, opts, dest)
4375 other = hg.peer(repo, opts, dest)
4369 if 'bookmarks' not in other.listkeys('namespaces'):
4376 if 'bookmarks' not in other.listkeys('namespaces'):
4370 ui.warn(_("remote doesn't support bookmarks\n"))
4377 ui.warn(_("remote doesn't support bookmarks\n"))
4371 return 0
4378 return 0
4372 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4379 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4373 return bookmarks.diff(ui, other, repo)
4380 return bookmarks.diff(ui, other, repo)
4374
4381
4375 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4382 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4376 try:
4383 try:
4377 return hg.outgoing(ui, repo, dest, opts)
4384 return hg.outgoing(ui, repo, dest, opts)
4378 finally:
4385 finally:
4379 del repo._subtoppath
4386 del repo._subtoppath
4380
4387
4381 @command('parents',
4388 @command('parents',
4382 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4389 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4383 ] + templateopts,
4390 ] + templateopts,
4384 _('[-r REV] [FILE]'))
4391 _('[-r REV] [FILE]'))
4385 def parents(ui, repo, file_=None, **opts):
4392 def parents(ui, repo, file_=None, **opts):
4386 """show the parents of the working directory or revision
4393 """show the parents of the working directory or revision
4387
4394
4388 Print the working directory's parent revisions. If a revision is
4395 Print the working directory's parent revisions. If a revision is
4389 given via -r/--rev, the parent of that revision will be printed.
4396 given via -r/--rev, the parent of that revision will be printed.
4390 If a file argument is given, the revision in which the file was
4397 If a file argument is given, the revision in which the file was
4391 last changed (before the working directory revision or the
4398 last changed (before the working directory revision or the
4392 argument to --rev if given) is printed.
4399 argument to --rev if given) is printed.
4393
4400
4394 Returns 0 on success.
4401 Returns 0 on success.
4395 """
4402 """
4396
4403
4397 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4404 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4398
4405
4399 if file_:
4406 if file_:
4400 m = scmutil.match(ctx, (file_,), opts)
4407 m = scmutil.match(ctx, (file_,), opts)
4401 if m.anypats() or len(m.files()) != 1:
4408 if m.anypats() or len(m.files()) != 1:
4402 raise util.Abort(_('can only specify an explicit filename'))
4409 raise util.Abort(_('can only specify an explicit filename'))
4403 file_ = m.files()[0]
4410 file_ = m.files()[0]
4404 filenodes = []
4411 filenodes = []
4405 for cp in ctx.parents():
4412 for cp in ctx.parents():
4406 if not cp:
4413 if not cp:
4407 continue
4414 continue
4408 try:
4415 try:
4409 filenodes.append(cp.filenode(file_))
4416 filenodes.append(cp.filenode(file_))
4410 except error.LookupError:
4417 except error.LookupError:
4411 pass
4418 pass
4412 if not filenodes:
4419 if not filenodes:
4413 raise util.Abort(_("'%s' not found in manifest!") % file_)
4420 raise util.Abort(_("'%s' not found in manifest!") % file_)
4414 p = []
4421 p = []
4415 for fn in filenodes:
4422 for fn in filenodes:
4416 fctx = repo.filectx(file_, fileid=fn)
4423 fctx = repo.filectx(file_, fileid=fn)
4417 p.append(fctx.node())
4424 p.append(fctx.node())
4418 else:
4425 else:
4419 p = [cp.node() for cp in ctx.parents()]
4426 p = [cp.node() for cp in ctx.parents()]
4420
4427
4421 displayer = cmdutil.show_changeset(ui, repo, opts)
4428 displayer = cmdutil.show_changeset(ui, repo, opts)
4422 for n in p:
4429 for n in p:
4423 if n != nullid:
4430 if n != nullid:
4424 displayer.show(repo[n])
4431 displayer.show(repo[n])
4425 displayer.close()
4432 displayer.close()
4426
4433
4427 @command('paths', [], _('[NAME]'))
4434 @command('paths', [], _('[NAME]'))
4428 def paths(ui, repo, search=None):
4435 def paths(ui, repo, search=None):
4429 """show aliases for remote repositories
4436 """show aliases for remote repositories
4430
4437
4431 Show definition of symbolic path name NAME. If no name is given,
4438 Show definition of symbolic path name NAME. If no name is given,
4432 show definition of all available names.
4439 show definition of all available names.
4433
4440
4434 Option -q/--quiet suppresses all output when searching for NAME
4441 Option -q/--quiet suppresses all output when searching for NAME
4435 and shows only the path names when listing all definitions.
4442 and shows only the path names when listing all definitions.
4436
4443
4437 Path names are defined in the [paths] section of your
4444 Path names are defined in the [paths] section of your
4438 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4445 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4439 repository, ``.hg/hgrc`` is used, too.
4446 repository, ``.hg/hgrc`` is used, too.
4440
4447
4441 The path names ``default`` and ``default-push`` have a special
4448 The path names ``default`` and ``default-push`` have a special
4442 meaning. When performing a push or pull operation, they are used
4449 meaning. When performing a push or pull operation, they are used
4443 as fallbacks if no location is specified on the command-line.
4450 as fallbacks if no location is specified on the command-line.
4444 When ``default-push`` is set, it will be used for push and
4451 When ``default-push`` is set, it will be used for push and
4445 ``default`` will be used for pull; otherwise ``default`` is used
4452 ``default`` will be used for pull; otherwise ``default`` is used
4446 as the fallback for both. When cloning a repository, the clone
4453 as the fallback for both. When cloning a repository, the clone
4447 source is written as ``default`` in ``.hg/hgrc``. Note that
4454 source is written as ``default`` in ``.hg/hgrc``. Note that
4448 ``default`` and ``default-push`` apply to all inbound (e.g.
4455 ``default`` and ``default-push`` apply to all inbound (e.g.
4449 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4456 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4450 :hg:`bundle`) operations.
4457 :hg:`bundle`) operations.
4451
4458
4452 See :hg:`help urls` for more information.
4459 See :hg:`help urls` for more information.
4453
4460
4454 Returns 0 on success.
4461 Returns 0 on success.
4455 """
4462 """
4456 if search:
4463 if search:
4457 for name, path in ui.configitems("paths"):
4464 for name, path in ui.configitems("paths"):
4458 if name == search:
4465 if name == search:
4459 ui.status("%s\n" % util.hidepassword(path))
4466 ui.status("%s\n" % util.hidepassword(path))
4460 return
4467 return
4461 if not ui.quiet:
4468 if not ui.quiet:
4462 ui.warn(_("not found!\n"))
4469 ui.warn(_("not found!\n"))
4463 return 1
4470 return 1
4464 else:
4471 else:
4465 for name, path in ui.configitems("paths"):
4472 for name, path in ui.configitems("paths"):
4466 if ui.quiet:
4473 if ui.quiet:
4467 ui.write("%s\n" % name)
4474 ui.write("%s\n" % name)
4468 else:
4475 else:
4469 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4476 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4470
4477
4471 @command('phase',
4478 @command('phase',
4472 [('p', 'public', False, _('set changeset phase to public')),
4479 [('p', 'public', False, _('set changeset phase to public')),
4473 ('d', 'draft', False, _('set changeset phase to draft')),
4480 ('d', 'draft', False, _('set changeset phase to draft')),
4474 ('s', 'secret', False, _('set changeset phase to secret')),
4481 ('s', 'secret', False, _('set changeset phase to secret')),
4475 ('f', 'force', False, _('allow to move boundary backward')),
4482 ('f', 'force', False, _('allow to move boundary backward')),
4476 ('r', 'rev', [], _('target revision'), _('REV')),
4483 ('r', 'rev', [], _('target revision'), _('REV')),
4477 ],
4484 ],
4478 _('[-p|-d|-s] [-f] [-r] REV...'))
4485 _('[-p|-d|-s] [-f] [-r] REV...'))
4479 def phase(ui, repo, *revs, **opts):
4486 def phase(ui, repo, *revs, **opts):
4480 """set or show the current phase name
4487 """set or show the current phase name
4481
4488
4482 With no argument, show the phase name of specified revisions.
4489 With no argument, show the phase name of specified revisions.
4483
4490
4484 With one of -p/--public, -d/--draft or -s/--secret, change the
4491 With one of -p/--public, -d/--draft or -s/--secret, change the
4485 phase value of the specified revisions.
4492 phase value of the specified revisions.
4486
4493
4487 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4494 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4488 lower phase to an higher phase. Phases are ordered as follows::
4495 lower phase to an higher phase. Phases are ordered as follows::
4489
4496
4490 public < draft < secret
4497 public < draft < secret
4491
4498
4492 Returns 0 on success, 1 if no phases were changed or some could not
4499 Returns 0 on success, 1 if no phases were changed or some could not
4493 be changed.
4500 be changed.
4494 """
4501 """
4495 # search for a unique phase argument
4502 # search for a unique phase argument
4496 targetphase = None
4503 targetphase = None
4497 for idx, name in enumerate(phases.phasenames):
4504 for idx, name in enumerate(phases.phasenames):
4498 if opts[name]:
4505 if opts[name]:
4499 if targetphase is not None:
4506 if targetphase is not None:
4500 raise util.Abort(_('only one phase can be specified'))
4507 raise util.Abort(_('only one phase can be specified'))
4501 targetphase = idx
4508 targetphase = idx
4502
4509
4503 # look for specified revision
4510 # look for specified revision
4504 revs = list(revs)
4511 revs = list(revs)
4505 revs.extend(opts['rev'])
4512 revs.extend(opts['rev'])
4506 if not revs:
4513 if not revs:
4507 raise util.Abort(_('no revisions specified'))
4514 raise util.Abort(_('no revisions specified'))
4508
4515
4509 revs = scmutil.revrange(repo, revs)
4516 revs = scmutil.revrange(repo, revs)
4510
4517
4511 lock = None
4518 lock = None
4512 ret = 0
4519 ret = 0
4513 if targetphase is None:
4520 if targetphase is None:
4514 # display
4521 # display
4515 for r in revs:
4522 for r in revs:
4516 ctx = repo[r]
4523 ctx = repo[r]
4517 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4524 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4518 else:
4525 else:
4519 lock = repo.lock()
4526 lock = repo.lock()
4520 try:
4527 try:
4521 # set phase
4528 # set phase
4522 if not revs:
4529 if not revs:
4523 raise util.Abort(_('empty revision set'))
4530 raise util.Abort(_('empty revision set'))
4524 nodes = [repo[r].node() for r in revs]
4531 nodes = [repo[r].node() for r in revs]
4525 olddata = repo._phasecache.getphaserevs(repo)[:]
4532 olddata = repo._phasecache.getphaserevs(repo)[:]
4526 phases.advanceboundary(repo, targetphase, nodes)
4533 phases.advanceboundary(repo, targetphase, nodes)
4527 if opts['force']:
4534 if opts['force']:
4528 phases.retractboundary(repo, targetphase, nodes)
4535 phases.retractboundary(repo, targetphase, nodes)
4529 finally:
4536 finally:
4530 lock.release()
4537 lock.release()
4531 # moving revision from public to draft may hide them
4538 # moving revision from public to draft may hide them
4532 # We have to check result on an unfiltered repository
4539 # We have to check result on an unfiltered repository
4533 unfi = repo.unfiltered()
4540 unfi = repo.unfiltered()
4534 newdata = repo._phasecache.getphaserevs(unfi)
4541 newdata = repo._phasecache.getphaserevs(unfi)
4535 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4542 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4536 cl = unfi.changelog
4543 cl = unfi.changelog
4537 rejected = [n for n in nodes
4544 rejected = [n for n in nodes
4538 if newdata[cl.rev(n)] < targetphase]
4545 if newdata[cl.rev(n)] < targetphase]
4539 if rejected:
4546 if rejected:
4540 ui.warn(_('cannot move %i changesets to a higher '
4547 ui.warn(_('cannot move %i changesets to a higher '
4541 'phase, use --force\n') % len(rejected))
4548 'phase, use --force\n') % len(rejected))
4542 ret = 1
4549 ret = 1
4543 if changes:
4550 if changes:
4544 msg = _('phase changed for %i changesets\n') % changes
4551 msg = _('phase changed for %i changesets\n') % changes
4545 if ret:
4552 if ret:
4546 ui.status(msg)
4553 ui.status(msg)
4547 else:
4554 else:
4548 ui.note(msg)
4555 ui.note(msg)
4549 else:
4556 else:
4550 ui.warn(_('no phases changed\n'))
4557 ui.warn(_('no phases changed\n'))
4551 ret = 1
4558 ret = 1
4552 return ret
4559 return ret
4553
4560
4554 def postincoming(ui, repo, modheads, optupdate, checkout):
4561 def postincoming(ui, repo, modheads, optupdate, checkout):
4555 if modheads == 0:
4562 if modheads == 0:
4556 return
4563 return
4557 if optupdate:
4564 if optupdate:
4558 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4565 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4559 try:
4566 try:
4560 ret = hg.update(repo, checkout)
4567 ret = hg.update(repo, checkout)
4561 except util.Abort, inst:
4568 except util.Abort, inst:
4562 ui.warn(_("not updating: %s\n") % str(inst))
4569 ui.warn(_("not updating: %s\n") % str(inst))
4563 if inst.hint:
4570 if inst.hint:
4564 ui.warn(_("(%s)\n") % inst.hint)
4571 ui.warn(_("(%s)\n") % inst.hint)
4565 return 0
4572 return 0
4566 if not ret and not checkout:
4573 if not ret and not checkout:
4567 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4574 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4568 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4575 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4569 return ret
4576 return ret
4570 if modheads > 1:
4577 if modheads > 1:
4571 currentbranchheads = len(repo.branchheads())
4578 currentbranchheads = len(repo.branchheads())
4572 if currentbranchheads == modheads:
4579 if currentbranchheads == modheads:
4573 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4580 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4574 elif currentbranchheads > 1:
4581 elif currentbranchheads > 1:
4575 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4582 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4576 "merge)\n"))
4583 "merge)\n"))
4577 else:
4584 else:
4578 ui.status(_("(run 'hg heads' to see heads)\n"))
4585 ui.status(_("(run 'hg heads' to see heads)\n"))
4579 else:
4586 else:
4580 ui.status(_("(run 'hg update' to get a working copy)\n"))
4587 ui.status(_("(run 'hg update' to get a working copy)\n"))
4581
4588
4582 @command('^pull',
4589 @command('^pull',
4583 [('u', 'update', None,
4590 [('u', 'update', None,
4584 _('update to new branch head if changesets were pulled')),
4591 _('update to new branch head if changesets were pulled')),
4585 ('f', 'force', None, _('run even when remote repository is unrelated')),
4592 ('f', 'force', None, _('run even when remote repository is unrelated')),
4586 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4593 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4587 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4594 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4588 ('b', 'branch', [], _('a specific branch you would like to pull'),
4595 ('b', 'branch', [], _('a specific branch you would like to pull'),
4589 _('BRANCH')),
4596 _('BRANCH')),
4590 ] + remoteopts,
4597 ] + remoteopts,
4591 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4598 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4592 def pull(ui, repo, source="default", **opts):
4599 def pull(ui, repo, source="default", **opts):
4593 """pull changes from the specified source
4600 """pull changes from the specified source
4594
4601
4595 Pull changes from a remote repository to a local one.
4602 Pull changes from a remote repository to a local one.
4596
4603
4597 This finds all changes from the repository at the specified path
4604 This finds all changes from the repository at the specified path
4598 or URL and adds them to a local repository (the current one unless
4605 or URL and adds them to a local repository (the current one unless
4599 -R is specified). By default, this does not update the copy of the
4606 -R is specified). By default, this does not update the copy of the
4600 project in the working directory.
4607 project in the working directory.
4601
4608
4602 Use :hg:`incoming` if you want to see what would have been added
4609 Use :hg:`incoming` if you want to see what would have been added
4603 by a pull at the time you issued this command. If you then decide
4610 by a pull at the time you issued this command. If you then decide
4604 to add those changes to the repository, you should use :hg:`pull
4611 to add those changes to the repository, you should use :hg:`pull
4605 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4612 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4606
4613
4607 If SOURCE is omitted, the 'default' path will be used.
4614 If SOURCE is omitted, the 'default' path will be used.
4608 See :hg:`help urls` for more information.
4615 See :hg:`help urls` for more information.
4609
4616
4610 Returns 0 on success, 1 if an update had unresolved files.
4617 Returns 0 on success, 1 if an update had unresolved files.
4611 """
4618 """
4612 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4619 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4613 other = hg.peer(repo, opts, source)
4620 other = hg.peer(repo, opts, source)
4614 try:
4621 try:
4615 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4622 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4616 revs, checkout = hg.addbranchrevs(repo, other, branches,
4623 revs, checkout = hg.addbranchrevs(repo, other, branches,
4617 opts.get('rev'))
4624 opts.get('rev'))
4618
4625
4619 remotebookmarks = other.listkeys('bookmarks')
4626 remotebookmarks = other.listkeys('bookmarks')
4620
4627
4621 if opts.get('bookmark'):
4628 if opts.get('bookmark'):
4622 if not revs:
4629 if not revs:
4623 revs = []
4630 revs = []
4624 for b in opts['bookmark']:
4631 for b in opts['bookmark']:
4625 if b not in remotebookmarks:
4632 if b not in remotebookmarks:
4626 raise util.Abort(_('remote bookmark %s not found!') % b)
4633 raise util.Abort(_('remote bookmark %s not found!') % b)
4627 revs.append(remotebookmarks[b])
4634 revs.append(remotebookmarks[b])
4628
4635
4629 if revs:
4636 if revs:
4630 try:
4637 try:
4631 revs = [other.lookup(rev) for rev in revs]
4638 revs = [other.lookup(rev) for rev in revs]
4632 except error.CapabilityError:
4639 except error.CapabilityError:
4633 err = _("other repository doesn't support revision lookup, "
4640 err = _("other repository doesn't support revision lookup, "
4634 "so a rev cannot be specified.")
4641 "so a rev cannot be specified.")
4635 raise util.Abort(err)
4642 raise util.Abort(err)
4636
4643
4637 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4644 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4638 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4645 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4639 if checkout:
4646 if checkout:
4640 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4647 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4641 repo._subtoppath = source
4648 repo._subtoppath = source
4642 try:
4649 try:
4643 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4650 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4644
4651
4645 finally:
4652 finally:
4646 del repo._subtoppath
4653 del repo._subtoppath
4647
4654
4648 # update specified bookmarks
4655 # update specified bookmarks
4649 if opts.get('bookmark'):
4656 if opts.get('bookmark'):
4650 marks = repo._bookmarks
4657 marks = repo._bookmarks
4651 for b in opts['bookmark']:
4658 for b in opts['bookmark']:
4652 # explicit pull overrides local bookmark if any
4659 # explicit pull overrides local bookmark if any
4653 ui.status(_("importing bookmark %s\n") % b)
4660 ui.status(_("importing bookmark %s\n") % b)
4654 marks[b] = repo[remotebookmarks[b]].node()
4661 marks[b] = repo[remotebookmarks[b]].node()
4655 marks.write()
4662 marks.write()
4656 finally:
4663 finally:
4657 other.close()
4664 other.close()
4658 return ret
4665 return ret
4659
4666
4660 @command('^push',
4667 @command('^push',
4661 [('f', 'force', None, _('force push')),
4668 [('f', 'force', None, _('force push')),
4662 ('r', 'rev', [],
4669 ('r', 'rev', [],
4663 _('a changeset intended to be included in the destination'),
4670 _('a changeset intended to be included in the destination'),
4664 _('REV')),
4671 _('REV')),
4665 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4672 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4666 ('b', 'branch', [],
4673 ('b', 'branch', [],
4667 _('a specific branch you would like to push'), _('BRANCH')),
4674 _('a specific branch you would like to push'), _('BRANCH')),
4668 ('', 'new-branch', False, _('allow pushing a new branch')),
4675 ('', 'new-branch', False, _('allow pushing a new branch')),
4669 ] + remoteopts,
4676 ] + remoteopts,
4670 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4677 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4671 def push(ui, repo, dest=None, **opts):
4678 def push(ui, repo, dest=None, **opts):
4672 """push changes to the specified destination
4679 """push changes to the specified destination
4673
4680
4674 Push changesets from the local repository to the specified
4681 Push changesets from the local repository to the specified
4675 destination.
4682 destination.
4676
4683
4677 This operation is symmetrical to pull: it is identical to a pull
4684 This operation is symmetrical to pull: it is identical to a pull
4678 in the destination repository from the current one.
4685 in the destination repository from the current one.
4679
4686
4680 By default, push will not allow creation of new heads at the
4687 By default, push will not allow creation of new heads at the
4681 destination, since multiple heads would make it unclear which head
4688 destination, since multiple heads would make it unclear which head
4682 to use. In this situation, it is recommended to pull and merge
4689 to use. In this situation, it is recommended to pull and merge
4683 before pushing.
4690 before pushing.
4684
4691
4685 Use --new-branch if you want to allow push to create a new named
4692 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
4693 branch that is not present at the destination. This allows you to
4687 only create a new branch without forcing other changes.
4694 only create a new branch without forcing other changes.
4688
4695
4689 .. note::
4696 .. note::
4690
4697
4691 Extra care should be taken with the -f/--force option,
4698 Extra care should be taken with the -f/--force option,
4692 which will push all new heads on all branches, an action which will
4699 which will push all new heads on all branches, an action which will
4693 almost always cause confusion for collaborators.
4700 almost always cause confusion for collaborators.
4694
4701
4695 If -r/--rev is used, the specified revision and all its ancestors
4702 If -r/--rev is used, the specified revision and all its ancestors
4696 will be pushed to the remote repository.
4703 will be pushed to the remote repository.
4697
4704
4698 If -B/--bookmark is used, the specified bookmarked revision, its
4705 If -B/--bookmark is used, the specified bookmarked revision, its
4699 ancestors, and the bookmark will be pushed to the remote
4706 ancestors, and the bookmark will be pushed to the remote
4700 repository.
4707 repository.
4701
4708
4702 Please see :hg:`help urls` for important details about ``ssh://``
4709 Please see :hg:`help urls` for important details about ``ssh://``
4703 URLs. If DESTINATION is omitted, a default path will be used.
4710 URLs. If DESTINATION is omitted, a default path will be used.
4704
4711
4705 Returns 0 if push was successful, 1 if nothing to push.
4712 Returns 0 if push was successful, 1 if nothing to push.
4706 """
4713 """
4707
4714
4708 if opts.get('bookmark'):
4715 if opts.get('bookmark'):
4709 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4716 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4710 for b in opts['bookmark']:
4717 for b in opts['bookmark']:
4711 # translate -B options to -r so changesets get pushed
4718 # translate -B options to -r so changesets get pushed
4712 if b in repo._bookmarks:
4719 if b in repo._bookmarks:
4713 opts.setdefault('rev', []).append(b)
4720 opts.setdefault('rev', []).append(b)
4714 else:
4721 else:
4715 # if we try to push a deleted bookmark, translate it to null
4722 # if we try to push a deleted bookmark, translate it to null
4716 # this lets simultaneous -r, -b options continue working
4723 # this lets simultaneous -r, -b options continue working
4717 opts.setdefault('rev', []).append("null")
4724 opts.setdefault('rev', []).append("null")
4718
4725
4719 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4726 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4720 dest, branches = hg.parseurl(dest, opts.get('branch'))
4727 dest, branches = hg.parseurl(dest, opts.get('branch'))
4721 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4728 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4722 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4729 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4723 try:
4730 try:
4724 other = hg.peer(repo, opts, dest)
4731 other = hg.peer(repo, opts, dest)
4725 except error.RepoError:
4732 except error.RepoError:
4726 if dest == "default-push":
4733 if dest == "default-push":
4727 raise util.Abort(_("default repository not configured!"),
4734 raise util.Abort(_("default repository not configured!"),
4728 hint=_('see the "path" section in "hg help config"'))
4735 hint=_('see the "path" section in "hg help config"'))
4729 else:
4736 else:
4730 raise
4737 raise
4731
4738
4732 if revs:
4739 if revs:
4733 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4740 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4734
4741
4735 repo._subtoppath = dest
4742 repo._subtoppath = dest
4736 try:
4743 try:
4737 # push subrepos depth-first for coherent ordering
4744 # push subrepos depth-first for coherent ordering
4738 c = repo['']
4745 c = repo['']
4739 subs = c.substate # only repos that are committed
4746 subs = c.substate # only repos that are committed
4740 for s in sorted(subs):
4747 for s in sorted(subs):
4741 result = c.sub(s).push(opts)
4748 result = c.sub(s).push(opts)
4742 if result == 0:
4749 if result == 0:
4743 return not result
4750 return not result
4744 finally:
4751 finally:
4745 del repo._subtoppath
4752 del repo._subtoppath
4746 result = repo.push(other, opts.get('force'), revs=revs,
4753 result = repo.push(other, opts.get('force'), revs=revs,
4747 newbranch=opts.get('new_branch'))
4754 newbranch=opts.get('new_branch'))
4748
4755
4749 result = not result
4756 result = not result
4750
4757
4751 if opts.get('bookmark'):
4758 if opts.get('bookmark'):
4752 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4759 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4753 if bresult == 2:
4760 if bresult == 2:
4754 return 2
4761 return 2
4755 if not result and bresult:
4762 if not result and bresult:
4756 result = 2
4763 result = 2
4757
4764
4758 return result
4765 return result
4759
4766
4760 @command('recover', [])
4767 @command('recover', [])
4761 def recover(ui, repo):
4768 def recover(ui, repo):
4762 """roll back an interrupted transaction
4769 """roll back an interrupted transaction
4763
4770
4764 Recover from an interrupted commit or pull.
4771 Recover from an interrupted commit or pull.
4765
4772
4766 This command tries to fix the repository status after an
4773 This command tries to fix the repository status after an
4767 interrupted operation. It should only be necessary when Mercurial
4774 interrupted operation. It should only be necessary when Mercurial
4768 suggests it.
4775 suggests it.
4769
4776
4770 Returns 0 if successful, 1 if nothing to recover or verify fails.
4777 Returns 0 if successful, 1 if nothing to recover or verify fails.
4771 """
4778 """
4772 if repo.recover():
4779 if repo.recover():
4773 return hg.verify(repo)
4780 return hg.verify(repo)
4774 return 1
4781 return 1
4775
4782
4776 @command('^remove|rm',
4783 @command('^remove|rm',
4777 [('A', 'after', None, _('record delete for missing files')),
4784 [('A', 'after', None, _('record delete for missing files')),
4778 ('f', 'force', None,
4785 ('f', 'force', None,
4779 _('remove (and delete) file even if added or modified')),
4786 _('remove (and delete) file even if added or modified')),
4780 ] + walkopts,
4787 ] + walkopts,
4781 _('[OPTION]... FILE...'))
4788 _('[OPTION]... FILE...'))
4782 def remove(ui, repo, *pats, **opts):
4789 def remove(ui, repo, *pats, **opts):
4783 """remove the specified files on the next commit
4790 """remove the specified files on the next commit
4784
4791
4785 Schedule the indicated files for removal from the current branch.
4792 Schedule the indicated files for removal from the current branch.
4786
4793
4787 This command schedules the files to be removed at the next commit.
4794 This command schedules the files to be removed at the next commit.
4788 To undo a remove before that, see :hg:`revert`. To undo added
4795 To undo a remove before that, see :hg:`revert`. To undo added
4789 files, see :hg:`forget`.
4796 files, see :hg:`forget`.
4790
4797
4791 .. container:: verbose
4798 .. container:: verbose
4792
4799
4793 -A/--after can be used to remove only files that have already
4800 -A/--after can be used to remove only files that have already
4794 been deleted, -f/--force can be used to force deletion, and -Af
4801 been deleted, -f/--force can be used to force deletion, and -Af
4795 can be used to remove files from the next revision without
4802 can be used to remove files from the next revision without
4796 deleting them from the working directory.
4803 deleting them from the working directory.
4797
4804
4798 The following table details the behavior of remove for different
4805 The following table details the behavior of remove for different
4799 file states (columns) and option combinations (rows). The file
4806 file states (columns) and option combinations (rows). The file
4800 states are Added [A], Clean [C], Modified [M] and Missing [!]
4807 states are Added [A], Clean [C], Modified [M] and Missing [!]
4801 (as reported by :hg:`status`). The actions are Warn, Remove
4808 (as reported by :hg:`status`). The actions are Warn, Remove
4802 (from branch) and Delete (from disk):
4809 (from branch) and Delete (from disk):
4803
4810
4804 ========= == == == ==
4811 ========= == == == ==
4805 opt/state A C M !
4812 opt/state A C M !
4806 ========= == == == ==
4813 ========= == == == ==
4807 none W RD W R
4814 none W RD W R
4808 -f R RD RD R
4815 -f R RD RD R
4809 -A W W W R
4816 -A W W W R
4810 -Af R R R R
4817 -Af R R R R
4811 ========= == == == ==
4818 ========= == == == ==
4812
4819
4813 Note that remove never deletes files in Added [A] state from the
4820 Note that remove never deletes files in Added [A] state from the
4814 working directory, not even if option --force is specified.
4821 working directory, not even if option --force is specified.
4815
4822
4816 Returns 0 on success, 1 if any warnings encountered.
4823 Returns 0 on success, 1 if any warnings encountered.
4817 """
4824 """
4818
4825
4819 ret = 0
4826 ret = 0
4820 after, force = opts.get('after'), opts.get('force')
4827 after, force = opts.get('after'), opts.get('force')
4821 if not pats and not after:
4828 if not pats and not after:
4822 raise util.Abort(_('no files specified'))
4829 raise util.Abort(_('no files specified'))
4823
4830
4824 m = scmutil.match(repo[None], pats, opts)
4831 m = scmutil.match(repo[None], pats, opts)
4825 s = repo.status(match=m, clean=True)
4832 s = repo.status(match=m, clean=True)
4826 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4833 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4827
4834
4828 # warn about failure to delete explicit files/dirs
4835 # warn about failure to delete explicit files/dirs
4829 wctx = repo[None]
4836 wctx = repo[None]
4830 for f in m.files():
4837 for f in m.files():
4831 if f in repo.dirstate or f in wctx.dirs():
4838 if f in repo.dirstate or f in wctx.dirs():
4832 continue
4839 continue
4833 if os.path.exists(m.rel(f)):
4840 if os.path.exists(m.rel(f)):
4834 if os.path.isdir(m.rel(f)):
4841 if os.path.isdir(m.rel(f)):
4835 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4842 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4836 else:
4843 else:
4837 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4844 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4838 # missing files will generate a warning elsewhere
4845 # missing files will generate a warning elsewhere
4839 ret = 1
4846 ret = 1
4840
4847
4841 if force:
4848 if force:
4842 list = modified + deleted + clean + added
4849 list = modified + deleted + clean + added
4843 elif after:
4850 elif after:
4844 list = deleted
4851 list = deleted
4845 for f in modified + added + clean:
4852 for f in modified + added + clean:
4846 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4853 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4847 ret = 1
4854 ret = 1
4848 else:
4855 else:
4849 list = deleted + clean
4856 list = deleted + clean
4850 for f in modified:
4857 for f in modified:
4851 ui.warn(_('not removing %s: file is modified (use -f'
4858 ui.warn(_('not removing %s: file is modified (use -f'
4852 ' to force removal)\n') % m.rel(f))
4859 ' to force removal)\n') % m.rel(f))
4853 ret = 1
4860 ret = 1
4854 for f in added:
4861 for f in added:
4855 ui.warn(_('not removing %s: file has been marked for add'
4862 ui.warn(_('not removing %s: file has been marked for add'
4856 ' (use forget to undo)\n') % m.rel(f))
4863 ' (use forget to undo)\n') % m.rel(f))
4857 ret = 1
4864 ret = 1
4858
4865
4859 for f in sorted(list):
4866 for f in sorted(list):
4860 if ui.verbose or not m.exact(f):
4867 if ui.verbose or not m.exact(f):
4861 ui.status(_('removing %s\n') % m.rel(f))
4868 ui.status(_('removing %s\n') % m.rel(f))
4862
4869
4863 wlock = repo.wlock()
4870 wlock = repo.wlock()
4864 try:
4871 try:
4865 if not after:
4872 if not after:
4866 for f in list:
4873 for f in list:
4867 if f in added:
4874 if f in added:
4868 continue # we never unlink added files on remove
4875 continue # we never unlink added files on remove
4869 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4876 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4870 repo[None].forget(list)
4877 repo[None].forget(list)
4871 finally:
4878 finally:
4872 wlock.release()
4879 wlock.release()
4873
4880
4874 return ret
4881 return ret
4875
4882
4876 @command('rename|move|mv',
4883 @command('rename|move|mv',
4877 [('A', 'after', None, _('record a rename that has already occurred')),
4884 [('A', 'after', None, _('record a rename that has already occurred')),
4878 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4885 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4879 ] + walkopts + dryrunopts,
4886 ] + walkopts + dryrunopts,
4880 _('[OPTION]... SOURCE... DEST'))
4887 _('[OPTION]... SOURCE... DEST'))
4881 def rename(ui, repo, *pats, **opts):
4888 def rename(ui, repo, *pats, **opts):
4882 """rename files; equivalent of copy + remove
4889 """rename files; equivalent of copy + remove
4883
4890
4884 Mark dest as copies of sources; mark sources for deletion. If dest
4891 Mark dest as copies of sources; mark sources for deletion. If dest
4885 is a directory, copies are put in that directory. If dest is a
4892 is a directory, copies are put in that directory. If dest is a
4886 file, there can only be one source.
4893 file, there can only be one source.
4887
4894
4888 By default, this command copies the contents of files as they
4895 By default, this command copies the contents of files as they
4889 exist in the working directory. If invoked with -A/--after, the
4896 exist in the working directory. If invoked with -A/--after, the
4890 operation is recorded, but no copying is performed.
4897 operation is recorded, but no copying is performed.
4891
4898
4892 This command takes effect at the next commit. To undo a rename
4899 This command takes effect at the next commit. To undo a rename
4893 before that, see :hg:`revert`.
4900 before that, see :hg:`revert`.
4894
4901
4895 Returns 0 on success, 1 if errors are encountered.
4902 Returns 0 on success, 1 if errors are encountered.
4896 """
4903 """
4897 wlock = repo.wlock(False)
4904 wlock = repo.wlock(False)
4898 try:
4905 try:
4899 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4906 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4900 finally:
4907 finally:
4901 wlock.release()
4908 wlock.release()
4902
4909
4903 @command('resolve',
4910 @command('resolve',
4904 [('a', 'all', None, _('select all unresolved files')),
4911 [('a', 'all', None, _('select all unresolved files')),
4905 ('l', 'list', None, _('list state of files needing merge')),
4912 ('l', 'list', None, _('list state of files needing merge')),
4906 ('m', 'mark', None, _('mark files as resolved')),
4913 ('m', 'mark', None, _('mark files as resolved')),
4907 ('u', 'unmark', None, _('mark files as unresolved')),
4914 ('u', 'unmark', None, _('mark files as unresolved')),
4908 ('n', 'no-status', None, _('hide status prefix'))]
4915 ('n', 'no-status', None, _('hide status prefix'))]
4909 + mergetoolopts + walkopts,
4916 + mergetoolopts + walkopts,
4910 _('[OPTION]... [FILE]...'))
4917 _('[OPTION]... [FILE]...'))
4911 def resolve(ui, repo, *pats, **opts):
4918 def resolve(ui, repo, *pats, **opts):
4912 """redo merges or set/view the merge status of files
4919 """redo merges or set/view the merge status of files
4913
4920
4914 Merges with unresolved conflicts are often the result of
4921 Merges with unresolved conflicts are often the result of
4915 non-interactive merging using the ``internal:merge`` configuration
4922 non-interactive merging using the ``internal:merge`` configuration
4916 setting, or a command-line merge tool like ``diff3``. The resolve
4923 setting, or a command-line merge tool like ``diff3``. The resolve
4917 command is used to manage the files involved in a merge, after
4924 command is used to manage the files involved in a merge, after
4918 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4925 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4919 working directory must have two parents). See :hg:`help
4926 working directory must have two parents). See :hg:`help
4920 merge-tools` for information on configuring merge tools.
4927 merge-tools` for information on configuring merge tools.
4921
4928
4922 The resolve command can be used in the following ways:
4929 The resolve command can be used in the following ways:
4923
4930
4924 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4931 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4925 files, discarding any previous merge attempts. Re-merging is not
4932 files, discarding any previous merge attempts. Re-merging is not
4926 performed for files already marked as resolved. Use ``--all/-a``
4933 performed for files already marked as resolved. Use ``--all/-a``
4927 to select all unresolved files. ``--tool`` can be used to specify
4934 to select all unresolved files. ``--tool`` can be used to specify
4928 the merge tool used for the given files. It overrides the HGMERGE
4935 the merge tool used for the given files. It overrides the HGMERGE
4929 environment variable and your configuration files. Previous file
4936 environment variable and your configuration files. Previous file
4930 contents are saved with a ``.orig`` suffix.
4937 contents are saved with a ``.orig`` suffix.
4931
4938
4932 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4939 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4933 (e.g. after having manually fixed-up the files). The default is
4940 (e.g. after having manually fixed-up the files). The default is
4934 to mark all unresolved files.
4941 to mark all unresolved files.
4935
4942
4936 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4943 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4937 default is to mark all resolved files.
4944 default is to mark all resolved files.
4938
4945
4939 - :hg:`resolve -l`: list files which had or still have conflicts.
4946 - :hg:`resolve -l`: list files which had or still have conflicts.
4940 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4947 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4941
4948
4942 Note that Mercurial will not let you commit files with unresolved
4949 Note that Mercurial will not let you commit files with unresolved
4943 merge conflicts. You must use :hg:`resolve -m ...` before you can
4950 merge conflicts. You must use :hg:`resolve -m ...` before you can
4944 commit after a conflicting merge.
4951 commit after a conflicting merge.
4945
4952
4946 Returns 0 on success, 1 if any files fail a resolve attempt.
4953 Returns 0 on success, 1 if any files fail a resolve attempt.
4947 """
4954 """
4948
4955
4949 all, mark, unmark, show, nostatus = \
4956 all, mark, unmark, show, nostatus = \
4950 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4957 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4951
4958
4952 if (show and (mark or unmark)) or (mark and unmark):
4959 if (show and (mark or unmark)) or (mark and unmark):
4953 raise util.Abort(_("too many options specified"))
4960 raise util.Abort(_("too many options specified"))
4954 if pats and all:
4961 if pats and all:
4955 raise util.Abort(_("can't specify --all and patterns"))
4962 raise util.Abort(_("can't specify --all and patterns"))
4956 if not (all or pats or show or mark or unmark):
4963 if not (all or pats or show or mark or unmark):
4957 raise util.Abort(_('no files or directories specified; '
4964 raise util.Abort(_('no files or directories specified; '
4958 'use --all to remerge all files'))
4965 'use --all to remerge all files'))
4959
4966
4960 wlock = repo.wlock()
4967 wlock = repo.wlock()
4961 try:
4968 try:
4962 ms = mergemod.mergestate(repo)
4969 ms = mergemod.mergestate(repo)
4963
4970
4964 if not ms.active() and not show:
4971 if not ms.active() and not show:
4965 raise util.Abort(
4972 raise util.Abort(
4966 _('resolve command not applicable when not merging'))
4973 _('resolve command not applicable when not merging'))
4967
4974
4968 m = scmutil.match(repo[None], pats, opts)
4975 m = scmutil.match(repo[None], pats, opts)
4969 ret = 0
4976 ret = 0
4970 didwork = False
4977 didwork = False
4971
4978
4972 for f in ms:
4979 for f in ms:
4973 if not m(f):
4980 if not m(f):
4974 continue
4981 continue
4975
4982
4976 didwork = True
4983 didwork = True
4977
4984
4978 if show:
4985 if show:
4979 if nostatus:
4986 if nostatus:
4980 ui.write("%s\n" % f)
4987 ui.write("%s\n" % f)
4981 else:
4988 else:
4982 ui.write("%s %s\n" % (ms[f].upper(), f),
4989 ui.write("%s %s\n" % (ms[f].upper(), f),
4983 label='resolve.' +
4990 label='resolve.' +
4984 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4991 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4985 elif mark:
4992 elif mark:
4986 ms.mark(f, "r")
4993 ms.mark(f, "r")
4987 elif unmark:
4994 elif unmark:
4988 ms.mark(f, "u")
4995 ms.mark(f, "u")
4989 else:
4996 else:
4990 wctx = repo[None]
4997 wctx = repo[None]
4991
4998
4992 # backup pre-resolve (merge uses .orig for its own purposes)
4999 # backup pre-resolve (merge uses .orig for its own purposes)
4993 a = repo.wjoin(f)
5000 a = repo.wjoin(f)
4994 util.copyfile(a, a + ".resolve")
5001 util.copyfile(a, a + ".resolve")
4995
5002
4996 try:
5003 try:
4997 # resolve file
5004 # resolve file
4998 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5005 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4999 'resolve')
5006 'resolve')
5000 if ms.resolve(f, wctx):
5007 if ms.resolve(f, wctx):
5001 ret = 1
5008 ret = 1
5002 finally:
5009 finally:
5003 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5010 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5004 ms.commit()
5011 ms.commit()
5005
5012
5006 # replace filemerge's .orig file with our resolve file
5013 # replace filemerge's .orig file with our resolve file
5007 util.rename(a + ".resolve", a + ".orig")
5014 util.rename(a + ".resolve", a + ".orig")
5008
5015
5009 ms.commit()
5016 ms.commit()
5010
5017
5011 if not didwork and pats:
5018 if not didwork and pats:
5012 ui.warn(_("arguments do not match paths that need resolving\n"))
5019 ui.warn(_("arguments do not match paths that need resolving\n"))
5013
5020
5014 finally:
5021 finally:
5015 wlock.release()
5022 wlock.release()
5016
5023
5017 # Nudge users into finishing an unfinished operation. We don't print
5024 # Nudge users into finishing an unfinished operation. We don't print
5018 # this with the list/show operation because we want list/show to remain
5025 # this with the list/show operation because we want list/show to remain
5019 # machine readable.
5026 # machine readable.
5020 if not list(ms.unresolved()) and not show:
5027 if not list(ms.unresolved()) and not show:
5021 ui.status(_('no more unresolved files\n'))
5028 ui.status(_('no more unresolved files\n'))
5022
5029
5023 return ret
5030 return ret
5024
5031
5025 @command('revert',
5032 @command('revert',
5026 [('a', 'all', None, _('revert all changes when no arguments given')),
5033 [('a', 'all', None, _('revert all changes when no arguments given')),
5027 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5034 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5028 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5035 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5029 ('C', 'no-backup', None, _('do not save backup copies of files')),
5036 ('C', 'no-backup', None, _('do not save backup copies of files')),
5030 ] + walkopts + dryrunopts,
5037 ] + walkopts + dryrunopts,
5031 _('[OPTION]... [-r REV] [NAME]...'))
5038 _('[OPTION]... [-r REV] [NAME]...'))
5032 def revert(ui, repo, *pats, **opts):
5039 def revert(ui, repo, *pats, **opts):
5033 """restore files to their checkout state
5040 """restore files to their checkout state
5034
5041
5035 .. note::
5042 .. note::
5036
5043
5037 To check out earlier revisions, you should use :hg:`update REV`.
5044 To check out earlier revisions, you should use :hg:`update REV`.
5038 To cancel an uncommitted merge (and lose your changes),
5045 To cancel an uncommitted merge (and lose your changes),
5039 use :hg:`update --clean .`.
5046 use :hg:`update --clean .`.
5040
5047
5041 With no revision specified, revert the specified files or directories
5048 With no revision specified, revert the specified files or directories
5042 to the contents they had in the parent of the working directory.
5049 to the contents they had in the parent of the working directory.
5043 This restores the contents of files to an unmodified
5050 This restores the contents of files to an unmodified
5044 state and unschedules adds, removes, copies, and renames. If the
5051 state and unschedules adds, removes, copies, and renames. If the
5045 working directory has two parents, you must explicitly specify a
5052 working directory has two parents, you must explicitly specify a
5046 revision.
5053 revision.
5047
5054
5048 Using the -r/--rev or -d/--date options, revert the given files or
5055 Using the -r/--rev or -d/--date options, revert the given files or
5049 directories to their states as of a specific revision. Because
5056 directories to their states as of a specific revision. Because
5050 revert does not change the working directory parents, this will
5057 revert does not change the working directory parents, this will
5051 cause these files to appear modified. This can be helpful to "back
5058 cause these files to appear modified. This can be helpful to "back
5052 out" some or all of an earlier change. See :hg:`backout` for a
5059 out" some or all of an earlier change. See :hg:`backout` for a
5053 related method.
5060 related method.
5054
5061
5055 Modified files are saved with a .orig suffix before reverting.
5062 Modified files are saved with a .orig suffix before reverting.
5056 To disable these backups, use --no-backup.
5063 To disable these backups, use --no-backup.
5057
5064
5058 See :hg:`help dates` for a list of formats valid for -d/--date.
5065 See :hg:`help dates` for a list of formats valid for -d/--date.
5059
5066
5060 Returns 0 on success.
5067 Returns 0 on success.
5061 """
5068 """
5062
5069
5063 if opts.get("date"):
5070 if opts.get("date"):
5064 if opts.get("rev"):
5071 if opts.get("rev"):
5065 raise util.Abort(_("you can't specify a revision and a date"))
5072 raise util.Abort(_("you can't specify a revision and a date"))
5066 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5073 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5067
5074
5068 parent, p2 = repo.dirstate.parents()
5075 parent, p2 = repo.dirstate.parents()
5069 if not opts.get('rev') and p2 != nullid:
5076 if not opts.get('rev') and p2 != nullid:
5070 # revert after merge is a trap for new users (issue2915)
5077 # revert after merge is a trap for new users (issue2915)
5071 raise util.Abort(_('uncommitted merge with no revision specified'),
5078 raise util.Abort(_('uncommitted merge with no revision specified'),
5072 hint=_('use "hg update" or see "hg help revert"'))
5079 hint=_('use "hg update" or see "hg help revert"'))
5073
5080
5074 ctx = scmutil.revsingle(repo, opts.get('rev'))
5081 ctx = scmutil.revsingle(repo, opts.get('rev'))
5075
5082
5076 if not pats and not opts.get('all'):
5083 if not pats and not opts.get('all'):
5077 msg = _("no files or directories specified")
5084 msg = _("no files or directories specified")
5078 if p2 != nullid:
5085 if p2 != nullid:
5079 hint = _("uncommitted merge, use --all to discard all changes,"
5086 hint = _("uncommitted merge, use --all to discard all changes,"
5080 " or 'hg update -C .' to abort the merge")
5087 " or 'hg update -C .' to abort the merge")
5081 raise util.Abort(msg, hint=hint)
5088 raise util.Abort(msg, hint=hint)
5082 dirty = util.any(repo.status())
5089 dirty = util.any(repo.status())
5083 node = ctx.node()
5090 node = ctx.node()
5084 if node != parent:
5091 if node != parent:
5085 if dirty:
5092 if dirty:
5086 hint = _("uncommitted changes, use --all to discard all"
5093 hint = _("uncommitted changes, use --all to discard all"
5087 " changes, or 'hg update %s' to update") % ctx.rev()
5094 " changes, or 'hg update %s' to update") % ctx.rev()
5088 else:
5095 else:
5089 hint = _("use --all to revert all files,"
5096 hint = _("use --all to revert all files,"
5090 " or 'hg update %s' to update") % ctx.rev()
5097 " or 'hg update %s' to update") % ctx.rev()
5091 elif dirty:
5098 elif dirty:
5092 hint = _("uncommitted changes, use --all to discard all changes")
5099 hint = _("uncommitted changes, use --all to discard all changes")
5093 else:
5100 else:
5094 hint = _("use --all to revert all files")
5101 hint = _("use --all to revert all files")
5095 raise util.Abort(msg, hint=hint)
5102 raise util.Abort(msg, hint=hint)
5096
5103
5097 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5104 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5098
5105
5099 @command('rollback', dryrunopts +
5106 @command('rollback', dryrunopts +
5100 [('f', 'force', False, _('ignore safety measures'))])
5107 [('f', 'force', False, _('ignore safety measures'))])
5101 def rollback(ui, repo, **opts):
5108 def rollback(ui, repo, **opts):
5102 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5109 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5103
5110
5104 Please use :hg:`commit --amend` instead of rollback to correct
5111 Please use :hg:`commit --amend` instead of rollback to correct
5105 mistakes in the last commit.
5112 mistakes in the last commit.
5106
5113
5107 This command should be used with care. There is only one level of
5114 This command should be used with care. There is only one level of
5108 rollback, and there is no way to undo a rollback. It will also
5115 rollback, and there is no way to undo a rollback. It will also
5109 restore the dirstate at the time of the last transaction, losing
5116 restore the dirstate at the time of the last transaction, losing
5110 any dirstate changes since that time. This command does not alter
5117 any dirstate changes since that time. This command does not alter
5111 the working directory.
5118 the working directory.
5112
5119
5113 Transactions are used to encapsulate the effects of all commands
5120 Transactions are used to encapsulate the effects of all commands
5114 that create new changesets or propagate existing changesets into a
5121 that create new changesets or propagate existing changesets into a
5115 repository.
5122 repository.
5116
5123
5117 .. container:: verbose
5124 .. container:: verbose
5118
5125
5119 For example, the following commands are transactional, and their
5126 For example, the following commands are transactional, and their
5120 effects can be rolled back:
5127 effects can be rolled back:
5121
5128
5122 - commit
5129 - commit
5123 - import
5130 - import
5124 - pull
5131 - pull
5125 - push (with this repository as the destination)
5132 - push (with this repository as the destination)
5126 - unbundle
5133 - unbundle
5127
5134
5128 To avoid permanent data loss, rollback will refuse to rollback a
5135 To avoid permanent data loss, rollback will refuse to rollback a
5129 commit transaction if it isn't checked out. Use --force to
5136 commit transaction if it isn't checked out. Use --force to
5130 override this protection.
5137 override this protection.
5131
5138
5132 This command is not intended for use on public repositories. Once
5139 This command is not intended for use on public repositories. Once
5133 changes are visible for pull by other users, rolling a transaction
5140 changes are visible for pull by other users, rolling a transaction
5134 back locally is ineffective (someone else may already have pulled
5141 back locally is ineffective (someone else may already have pulled
5135 the changes). Furthermore, a race is possible with readers of the
5142 the changes). Furthermore, a race is possible with readers of the
5136 repository; for example an in-progress pull from the repository
5143 repository; for example an in-progress pull from the repository
5137 may fail if a rollback is performed.
5144 may fail if a rollback is performed.
5138
5145
5139 Returns 0 on success, 1 if no rollback data is available.
5146 Returns 0 on success, 1 if no rollback data is available.
5140 """
5147 """
5141 return repo.rollback(dryrun=opts.get('dry_run'),
5148 return repo.rollback(dryrun=opts.get('dry_run'),
5142 force=opts.get('force'))
5149 force=opts.get('force'))
5143
5150
5144 @command('root', [])
5151 @command('root', [])
5145 def root(ui, repo):
5152 def root(ui, repo):
5146 """print the root (top) of the current working directory
5153 """print the root (top) of the current working directory
5147
5154
5148 Print the root directory of the current repository.
5155 Print the root directory of the current repository.
5149
5156
5150 Returns 0 on success.
5157 Returns 0 on success.
5151 """
5158 """
5152 ui.write(repo.root + "\n")
5159 ui.write(repo.root + "\n")
5153
5160
5154 @command('^serve',
5161 @command('^serve',
5155 [('A', 'accesslog', '', _('name of access log file to write to'),
5162 [('A', 'accesslog', '', _('name of access log file to write to'),
5156 _('FILE')),
5163 _('FILE')),
5157 ('d', 'daemon', None, _('run server in background')),
5164 ('d', 'daemon', None, _('run server in background')),
5158 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5165 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5159 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5166 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5160 # use string type, then we can check if something was passed
5167 # use string type, then we can check if something was passed
5161 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5168 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5162 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5169 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5163 _('ADDR')),
5170 _('ADDR')),
5164 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5171 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5165 _('PREFIX')),
5172 _('PREFIX')),
5166 ('n', 'name', '',
5173 ('n', 'name', '',
5167 _('name to show in web pages (default: working directory)'), _('NAME')),
5174 _('name to show in web pages (default: working directory)'), _('NAME')),
5168 ('', 'web-conf', '',
5175 ('', 'web-conf', '',
5169 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5176 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5170 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5177 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5171 _('FILE')),
5178 _('FILE')),
5172 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5179 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5173 ('', 'stdio', None, _('for remote clients')),
5180 ('', 'stdio', None, _('for remote clients')),
5174 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5181 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5175 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5182 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5176 ('', 'style', '', _('template style to use'), _('STYLE')),
5183 ('', 'style', '', _('template style to use'), _('STYLE')),
5177 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5184 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5178 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5185 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5179 _('[OPTION]...'))
5186 _('[OPTION]...'))
5180 def serve(ui, repo, **opts):
5187 def serve(ui, repo, **opts):
5181 """start stand-alone webserver
5188 """start stand-alone webserver
5182
5189
5183 Start a local HTTP repository browser and pull server. You can use
5190 Start a local HTTP repository browser and pull server. You can use
5184 this for ad-hoc sharing and browsing of repositories. It is
5191 this for ad-hoc sharing and browsing of repositories. It is
5185 recommended to use a real web server to serve a repository for
5192 recommended to use a real web server to serve a repository for
5186 longer periods of time.
5193 longer periods of time.
5187
5194
5188 Please note that the server does not implement access control.
5195 Please note that the server does not implement access control.
5189 This means that, by default, anybody can read from the server and
5196 This means that, by default, anybody can read from the server and
5190 nobody can write to it by default. Set the ``web.allow_push``
5197 nobody can write to it by default. Set the ``web.allow_push``
5191 option to ``*`` to allow everybody to push to the server. You
5198 option to ``*`` to allow everybody to push to the server. You
5192 should use a real web server if you need to authenticate users.
5199 should use a real web server if you need to authenticate users.
5193
5200
5194 By default, the server logs accesses to stdout and errors to
5201 By default, the server logs accesses to stdout and errors to
5195 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5202 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5196 files.
5203 files.
5197
5204
5198 To have the server choose a free port number to listen on, specify
5205 To have the server choose a free port number to listen on, specify
5199 a port number of 0; in this case, the server will print the port
5206 a port number of 0; in this case, the server will print the port
5200 number it uses.
5207 number it uses.
5201
5208
5202 Returns 0 on success.
5209 Returns 0 on success.
5203 """
5210 """
5204
5211
5205 if opts["stdio"] and opts["cmdserver"]:
5212 if opts["stdio"] and opts["cmdserver"]:
5206 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5213 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5207
5214
5208 def checkrepo():
5215 def checkrepo():
5209 if repo is None:
5216 if repo is None:
5210 raise error.RepoError(_("there is no Mercurial repository here"
5217 raise error.RepoError(_("there is no Mercurial repository here"
5211 " (.hg not found)"))
5218 " (.hg not found)"))
5212
5219
5213 if opts["stdio"]:
5220 if opts["stdio"]:
5214 checkrepo()
5221 checkrepo()
5215 s = sshserver.sshserver(ui, repo)
5222 s = sshserver.sshserver(ui, repo)
5216 s.serve_forever()
5223 s.serve_forever()
5217
5224
5218 if opts["cmdserver"]:
5225 if opts["cmdserver"]:
5219 s = commandserver.server(ui, repo, opts["cmdserver"])
5226 s = commandserver.server(ui, repo, opts["cmdserver"])
5220 return s.serve()
5227 return s.serve()
5221
5228
5222 # this way we can check if something was given in the command-line
5229 # this way we can check if something was given in the command-line
5223 if opts.get('port'):
5230 if opts.get('port'):
5224 opts['port'] = util.getport(opts.get('port'))
5231 opts['port'] = util.getport(opts.get('port'))
5225
5232
5226 baseui = repo and repo.baseui or ui
5233 baseui = repo and repo.baseui or ui
5227 optlist = ("name templates style address port prefix ipv6"
5234 optlist = ("name templates style address port prefix ipv6"
5228 " accesslog errorlog certificate encoding")
5235 " accesslog errorlog certificate encoding")
5229 for o in optlist.split():
5236 for o in optlist.split():
5230 val = opts.get(o, '')
5237 val = opts.get(o, '')
5231 if val in (None, ''): # should check against default options instead
5238 if val in (None, ''): # should check against default options instead
5232 continue
5239 continue
5233 baseui.setconfig("web", o, val, 'serve')
5240 baseui.setconfig("web", o, val, 'serve')
5234 if repo and repo.ui != baseui:
5241 if repo and repo.ui != baseui:
5235 repo.ui.setconfig("web", o, val, 'serve')
5242 repo.ui.setconfig("web", o, val, 'serve')
5236
5243
5237 o = opts.get('web_conf') or opts.get('webdir_conf')
5244 o = opts.get('web_conf') or opts.get('webdir_conf')
5238 if not o:
5245 if not o:
5239 if not repo:
5246 if not repo:
5240 raise error.RepoError(_("there is no Mercurial repository"
5247 raise error.RepoError(_("there is no Mercurial repository"
5241 " here (.hg not found)"))
5248 " here (.hg not found)"))
5242 o = repo
5249 o = repo
5243
5250
5244 app = hgweb.hgweb(o, baseui=baseui)
5251 app = hgweb.hgweb(o, baseui=baseui)
5245 service = httpservice(ui, app, opts)
5252 service = httpservice(ui, app, opts)
5246 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5253 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5247
5254
5248 class httpservice(object):
5255 class httpservice(object):
5249 def __init__(self, ui, app, opts):
5256 def __init__(self, ui, app, opts):
5250 self.ui = ui
5257 self.ui = ui
5251 self.app = app
5258 self.app = app
5252 self.opts = opts
5259 self.opts = opts
5253
5260
5254 def init(self):
5261 def init(self):
5255 util.setsignalhandler()
5262 util.setsignalhandler()
5256 self.httpd = hgweb_server.create_server(self.ui, self.app)
5263 self.httpd = hgweb_server.create_server(self.ui, self.app)
5257
5264
5258 if self.opts['port'] and not self.ui.verbose:
5265 if self.opts['port'] and not self.ui.verbose:
5259 return
5266 return
5260
5267
5261 if self.httpd.prefix:
5268 if self.httpd.prefix:
5262 prefix = self.httpd.prefix.strip('/') + '/'
5269 prefix = self.httpd.prefix.strip('/') + '/'
5263 else:
5270 else:
5264 prefix = ''
5271 prefix = ''
5265
5272
5266 port = ':%d' % self.httpd.port
5273 port = ':%d' % self.httpd.port
5267 if port == ':80':
5274 if port == ':80':
5268 port = ''
5275 port = ''
5269
5276
5270 bindaddr = self.httpd.addr
5277 bindaddr = self.httpd.addr
5271 if bindaddr == '0.0.0.0':
5278 if bindaddr == '0.0.0.0':
5272 bindaddr = '*'
5279 bindaddr = '*'
5273 elif ':' in bindaddr: # IPv6
5280 elif ':' in bindaddr: # IPv6
5274 bindaddr = '[%s]' % bindaddr
5281 bindaddr = '[%s]' % bindaddr
5275
5282
5276 fqaddr = self.httpd.fqaddr
5283 fqaddr = self.httpd.fqaddr
5277 if ':' in fqaddr:
5284 if ':' in fqaddr:
5278 fqaddr = '[%s]' % fqaddr
5285 fqaddr = '[%s]' % fqaddr
5279 if self.opts['port']:
5286 if self.opts['port']:
5280 write = self.ui.status
5287 write = self.ui.status
5281 else:
5288 else:
5282 write = self.ui.write
5289 write = self.ui.write
5283 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5290 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5284 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5291 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5285
5292
5286 def run(self):
5293 def run(self):
5287 self.httpd.serve_forever()
5294 self.httpd.serve_forever()
5288
5295
5289
5296
5290 @command('^status|st',
5297 @command('^status|st',
5291 [('A', 'all', None, _('show status of all files')),
5298 [('A', 'all', None, _('show status of all files')),
5292 ('m', 'modified', None, _('show only modified files')),
5299 ('m', 'modified', None, _('show only modified files')),
5293 ('a', 'added', None, _('show only added files')),
5300 ('a', 'added', None, _('show only added files')),
5294 ('r', 'removed', None, _('show only removed files')),
5301 ('r', 'removed', None, _('show only removed files')),
5295 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5302 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5296 ('c', 'clean', None, _('show only files without changes')),
5303 ('c', 'clean', None, _('show only files without changes')),
5297 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5304 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5298 ('i', 'ignored', None, _('show only ignored files')),
5305 ('i', 'ignored', None, _('show only ignored files')),
5299 ('n', 'no-status', None, _('hide status prefix')),
5306 ('n', 'no-status', None, _('hide status prefix')),
5300 ('C', 'copies', None, _('show source of copied files')),
5307 ('C', 'copies', None, _('show source of copied files')),
5301 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5308 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5302 ('', 'rev', [], _('show difference from revision'), _('REV')),
5309 ('', 'rev', [], _('show difference from revision'), _('REV')),
5303 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5310 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5304 ] + walkopts + subrepoopts,
5311 ] + walkopts + subrepoopts,
5305 _('[OPTION]... [FILE]...'))
5312 _('[OPTION]... [FILE]...'))
5306 def status(ui, repo, *pats, **opts):
5313 def status(ui, repo, *pats, **opts):
5307 """show changed files in the working directory
5314 """show changed files in the working directory
5308
5315
5309 Show status of files in the repository. If names are given, only
5316 Show status of files in the repository. If names are given, only
5310 files that match are shown. Files that are clean or ignored or
5317 files that match are shown. Files that are clean or ignored or
5311 the source of a copy/move operation, are not listed unless
5318 the source of a copy/move operation, are not listed unless
5312 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5319 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5313 Unless options described with "show only ..." are given, the
5320 Unless options described with "show only ..." are given, the
5314 options -mardu are used.
5321 options -mardu are used.
5315
5322
5316 Option -q/--quiet hides untracked (unknown and ignored) files
5323 Option -q/--quiet hides untracked (unknown and ignored) files
5317 unless explicitly requested with -u/--unknown or -i/--ignored.
5324 unless explicitly requested with -u/--unknown or -i/--ignored.
5318
5325
5319 .. note::
5326 .. note::
5320
5327
5321 status may appear to disagree with diff if permissions have
5328 status may appear to disagree with diff if permissions have
5322 changed or a merge has occurred. The standard diff format does
5329 changed or a merge has occurred. The standard diff format does
5323 not report permission changes and diff only reports changes
5330 not report permission changes and diff only reports changes
5324 relative to one merge parent.
5331 relative to one merge parent.
5325
5332
5326 If one revision is given, it is used as the base revision.
5333 If one revision is given, it is used as the base revision.
5327 If two revisions are given, the differences between them are
5334 If two revisions are given, the differences between them are
5328 shown. The --change option can also be used as a shortcut to list
5335 shown. The --change option can also be used as a shortcut to list
5329 the changed files of a revision from its first parent.
5336 the changed files of a revision from its first parent.
5330
5337
5331 The codes used to show the status of files are::
5338 The codes used to show the status of files are::
5332
5339
5333 M = modified
5340 M = modified
5334 A = added
5341 A = added
5335 R = removed
5342 R = removed
5336 C = clean
5343 C = clean
5337 ! = missing (deleted by non-hg command, but still tracked)
5344 ! = missing (deleted by non-hg command, but still tracked)
5338 ? = not tracked
5345 ? = not tracked
5339 I = ignored
5346 I = ignored
5340 = origin of the previous file (with --copies)
5347 = origin of the previous file (with --copies)
5341
5348
5342 .. container:: verbose
5349 .. container:: verbose
5343
5350
5344 Examples:
5351 Examples:
5345
5352
5346 - show changes in the working directory relative to a
5353 - show changes in the working directory relative to a
5347 changeset::
5354 changeset::
5348
5355
5349 hg status --rev 9353
5356 hg status --rev 9353
5350
5357
5351 - show all changes including copies in an existing changeset::
5358 - show all changes including copies in an existing changeset::
5352
5359
5353 hg status --copies --change 9353
5360 hg status --copies --change 9353
5354
5361
5355 - get a NUL separated list of added files, suitable for xargs::
5362 - get a NUL separated list of added files, suitable for xargs::
5356
5363
5357 hg status -an0
5364 hg status -an0
5358
5365
5359 Returns 0 on success.
5366 Returns 0 on success.
5360 """
5367 """
5361
5368
5362 revs = opts.get('rev')
5369 revs = opts.get('rev')
5363 change = opts.get('change')
5370 change = opts.get('change')
5364
5371
5365 if revs and change:
5372 if revs and change:
5366 msg = _('cannot specify --rev and --change at the same time')
5373 msg = _('cannot specify --rev and --change at the same time')
5367 raise util.Abort(msg)
5374 raise util.Abort(msg)
5368 elif change:
5375 elif change:
5369 node2 = scmutil.revsingle(repo, change, None).node()
5376 node2 = scmutil.revsingle(repo, change, None).node()
5370 node1 = repo[node2].p1().node()
5377 node1 = repo[node2].p1().node()
5371 else:
5378 else:
5372 node1, node2 = scmutil.revpair(repo, revs)
5379 node1, node2 = scmutil.revpair(repo, revs)
5373
5380
5374 cwd = (pats and repo.getcwd()) or ''
5381 cwd = (pats and repo.getcwd()) or ''
5375 end = opts.get('print0') and '\0' or '\n'
5382 end = opts.get('print0') and '\0' or '\n'
5376 copy = {}
5383 copy = {}
5377 states = 'modified added removed deleted unknown ignored clean'.split()
5384 states = 'modified added removed deleted unknown ignored clean'.split()
5378 show = [k for k in states if opts.get(k)]
5385 show = [k for k in states if opts.get(k)]
5379 if opts.get('all'):
5386 if opts.get('all'):
5380 show += ui.quiet and (states[:4] + ['clean']) or states
5387 show += ui.quiet and (states[:4] + ['clean']) or states
5381 if not show:
5388 if not show:
5382 show = ui.quiet and states[:4] or states[:5]
5389 show = ui.quiet and states[:4] or states[:5]
5383
5390
5384 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5391 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5385 'ignored' in show, 'clean' in show, 'unknown' in show,
5392 'ignored' in show, 'clean' in show, 'unknown' in show,
5386 opts.get('subrepos'))
5393 opts.get('subrepos'))
5387 changestates = zip(states, 'MAR!?IC', stat)
5394 changestates = zip(states, 'MAR!?IC', stat)
5388
5395
5389 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5396 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5390 copy = copies.pathcopies(repo[node1], repo[node2])
5397 copy = copies.pathcopies(repo[node1], repo[node2])
5391
5398
5392 fm = ui.formatter('status', opts)
5399 fm = ui.formatter('status', opts)
5393 fmt = '%s' + end
5400 fmt = '%s' + end
5394 showchar = not opts.get('no_status')
5401 showchar = not opts.get('no_status')
5395
5402
5396 for state, char, files in changestates:
5403 for state, char, files in changestates:
5397 if state in show:
5404 if state in show:
5398 label = 'status.' + state
5405 label = 'status.' + state
5399 for f in files:
5406 for f in files:
5400 fm.startitem()
5407 fm.startitem()
5401 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5408 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5402 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5409 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5403 if f in copy:
5410 if f in copy:
5404 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5411 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5405 label='status.copied')
5412 label='status.copied')
5406 fm.end()
5413 fm.end()
5407
5414
5408 @command('^summary|sum',
5415 @command('^summary|sum',
5409 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5416 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5410 def summary(ui, repo, **opts):
5417 def summary(ui, repo, **opts):
5411 """summarize working directory state
5418 """summarize working directory state
5412
5419
5413 This generates a brief summary of the working directory state,
5420 This generates a brief summary of the working directory state,
5414 including parents, branch, commit status, and available updates.
5421 including parents, branch, commit status, and available updates.
5415
5422
5416 With the --remote option, this will check the default paths for
5423 With the --remote option, this will check the default paths for
5417 incoming and outgoing changes. This can be time-consuming.
5424 incoming and outgoing changes. This can be time-consuming.
5418
5425
5419 Returns 0 on success.
5426 Returns 0 on success.
5420 """
5427 """
5421
5428
5422 ctx = repo[None]
5429 ctx = repo[None]
5423 parents = ctx.parents()
5430 parents = ctx.parents()
5424 pnode = parents[0].node()
5431 pnode = parents[0].node()
5425 marks = []
5432 marks = []
5426
5433
5427 for p in parents:
5434 for p in parents:
5428 # label with log.changeset (instead of log.parent) since this
5435 # label with log.changeset (instead of log.parent) since this
5429 # shows a working directory parent *changeset*:
5436 # shows a working directory parent *changeset*:
5430 # i18n: column positioning for "hg summary"
5437 # i18n: column positioning for "hg summary"
5431 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5438 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5432 label='log.changeset changeset.%s' % p.phasestr())
5439 label='log.changeset changeset.%s' % p.phasestr())
5433 ui.write(' '.join(p.tags()), label='log.tag')
5440 ui.write(' '.join(p.tags()), label='log.tag')
5434 if p.bookmarks():
5441 if p.bookmarks():
5435 marks.extend(p.bookmarks())
5442 marks.extend(p.bookmarks())
5436 if p.rev() == -1:
5443 if p.rev() == -1:
5437 if not len(repo):
5444 if not len(repo):
5438 ui.write(_(' (empty repository)'))
5445 ui.write(_(' (empty repository)'))
5439 else:
5446 else:
5440 ui.write(_(' (no revision checked out)'))
5447 ui.write(_(' (no revision checked out)'))
5441 ui.write('\n')
5448 ui.write('\n')
5442 if p.description():
5449 if p.description():
5443 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5450 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5444 label='log.summary')
5451 label='log.summary')
5445
5452
5446 branch = ctx.branch()
5453 branch = ctx.branch()
5447 bheads = repo.branchheads(branch)
5454 bheads = repo.branchheads(branch)
5448 # i18n: column positioning for "hg summary"
5455 # i18n: column positioning for "hg summary"
5449 m = _('branch: %s\n') % branch
5456 m = _('branch: %s\n') % branch
5450 if branch != 'default':
5457 if branch != 'default':
5451 ui.write(m, label='log.branch')
5458 ui.write(m, label='log.branch')
5452 else:
5459 else:
5453 ui.status(m, label='log.branch')
5460 ui.status(m, label='log.branch')
5454
5461
5455 if marks:
5462 if marks:
5456 current = repo._bookmarkcurrent
5463 current = repo._bookmarkcurrent
5457 # i18n: column positioning for "hg summary"
5464 # i18n: column positioning for "hg summary"
5458 ui.write(_('bookmarks:'), label='log.bookmark')
5465 ui.write(_('bookmarks:'), label='log.bookmark')
5459 if current is not None:
5466 if current is not None:
5460 if current in marks:
5467 if current in marks:
5461 ui.write(' *' + current, label='bookmarks.current')
5468 ui.write(' *' + current, label='bookmarks.current')
5462 marks.remove(current)
5469 marks.remove(current)
5463 else:
5470 else:
5464 ui.write(' [%s]' % current, label='bookmarks.current')
5471 ui.write(' [%s]' % current, label='bookmarks.current')
5465 for m in marks:
5472 for m in marks:
5466 ui.write(' ' + m, label='log.bookmark')
5473 ui.write(' ' + m, label='log.bookmark')
5467 ui.write('\n', label='log.bookmark')
5474 ui.write('\n', label='log.bookmark')
5468
5475
5469 st = list(repo.status(unknown=True))[:6]
5476 st = list(repo.status(unknown=True))[:6]
5470
5477
5471 c = repo.dirstate.copies()
5478 c = repo.dirstate.copies()
5472 copied, renamed = [], []
5479 copied, renamed = [], []
5473 for d, s in c.iteritems():
5480 for d, s in c.iteritems():
5474 if s in st[2]:
5481 if s in st[2]:
5475 st[2].remove(s)
5482 st[2].remove(s)
5476 renamed.append(d)
5483 renamed.append(d)
5477 else:
5484 else:
5478 copied.append(d)
5485 copied.append(d)
5479 if d in st[1]:
5486 if d in st[1]:
5480 st[1].remove(d)
5487 st[1].remove(d)
5481 st.insert(3, renamed)
5488 st.insert(3, renamed)
5482 st.insert(4, copied)
5489 st.insert(4, copied)
5483
5490
5484 ms = mergemod.mergestate(repo)
5491 ms = mergemod.mergestate(repo)
5485 st.append([f for f in ms if ms[f] == 'u'])
5492 st.append([f for f in ms if ms[f] == 'u'])
5486
5493
5487 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5494 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5488 st.append(subs)
5495 st.append(subs)
5489
5496
5490 labels = [ui.label(_('%d modified'), 'status.modified'),
5497 labels = [ui.label(_('%d modified'), 'status.modified'),
5491 ui.label(_('%d added'), 'status.added'),
5498 ui.label(_('%d added'), 'status.added'),
5492 ui.label(_('%d removed'), 'status.removed'),
5499 ui.label(_('%d removed'), 'status.removed'),
5493 ui.label(_('%d renamed'), 'status.copied'),
5500 ui.label(_('%d renamed'), 'status.copied'),
5494 ui.label(_('%d copied'), 'status.copied'),
5501 ui.label(_('%d copied'), 'status.copied'),
5495 ui.label(_('%d deleted'), 'status.deleted'),
5502 ui.label(_('%d deleted'), 'status.deleted'),
5496 ui.label(_('%d unknown'), 'status.unknown'),
5503 ui.label(_('%d unknown'), 'status.unknown'),
5497 ui.label(_('%d ignored'), 'status.ignored'),
5504 ui.label(_('%d ignored'), 'status.ignored'),
5498 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5505 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5499 ui.label(_('%d subrepos'), 'status.modified')]
5506 ui.label(_('%d subrepos'), 'status.modified')]
5500 t = []
5507 t = []
5501 for s, l in zip(st, labels):
5508 for s, l in zip(st, labels):
5502 if s:
5509 if s:
5503 t.append(l % len(s))
5510 t.append(l % len(s))
5504
5511
5505 t = ', '.join(t)
5512 t = ', '.join(t)
5506 cleanworkdir = False
5513 cleanworkdir = False
5507
5514
5508 if repo.vfs.exists('updatestate'):
5515 if repo.vfs.exists('updatestate'):
5509 t += _(' (interrupted update)')
5516 t += _(' (interrupted update)')
5510 elif len(parents) > 1:
5517 elif len(parents) > 1:
5511 t += _(' (merge)')
5518 t += _(' (merge)')
5512 elif branch != parents[0].branch():
5519 elif branch != parents[0].branch():
5513 t += _(' (new branch)')
5520 t += _(' (new branch)')
5514 elif (parents[0].closesbranch() and
5521 elif (parents[0].closesbranch() and
5515 pnode in repo.branchheads(branch, closed=True)):
5522 pnode in repo.branchheads(branch, closed=True)):
5516 t += _(' (head closed)')
5523 t += _(' (head closed)')
5517 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5524 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5518 t += _(' (clean)')
5525 t += _(' (clean)')
5519 cleanworkdir = True
5526 cleanworkdir = True
5520 elif pnode not in bheads:
5527 elif pnode not in bheads:
5521 t += _(' (new branch head)')
5528 t += _(' (new branch head)')
5522
5529
5523 if cleanworkdir:
5530 if cleanworkdir:
5524 # i18n: column positioning for "hg summary"
5531 # i18n: column positioning for "hg summary"
5525 ui.status(_('commit: %s\n') % t.strip())
5532 ui.status(_('commit: %s\n') % t.strip())
5526 else:
5533 else:
5527 # i18n: column positioning for "hg summary"
5534 # i18n: column positioning for "hg summary"
5528 ui.write(_('commit: %s\n') % t.strip())
5535 ui.write(_('commit: %s\n') % t.strip())
5529
5536
5530 # all ancestors of branch heads - all ancestors of parent = new csets
5537 # all ancestors of branch heads - all ancestors of parent = new csets
5531 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5538 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5532 bheads))
5539 bheads))
5533
5540
5534 if new == 0:
5541 if new == 0:
5535 # i18n: column positioning for "hg summary"
5542 # i18n: column positioning for "hg summary"
5536 ui.status(_('update: (current)\n'))
5543 ui.status(_('update: (current)\n'))
5537 elif pnode not in bheads:
5544 elif pnode not in bheads:
5538 # i18n: column positioning for "hg summary"
5545 # i18n: column positioning for "hg summary"
5539 ui.write(_('update: %d new changesets (update)\n') % new)
5546 ui.write(_('update: %d new changesets (update)\n') % new)
5540 else:
5547 else:
5541 # i18n: column positioning for "hg summary"
5548 # i18n: column positioning for "hg summary"
5542 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5549 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5543 (new, len(bheads)))
5550 (new, len(bheads)))
5544
5551
5545 cmdutil.summaryhooks(ui, repo)
5552 cmdutil.summaryhooks(ui, repo)
5546
5553
5547 if opts.get('remote'):
5554 if opts.get('remote'):
5548 needsincoming, needsoutgoing = True, True
5555 needsincoming, needsoutgoing = True, True
5549 else:
5556 else:
5550 needsincoming, needsoutgoing = False, False
5557 needsincoming, needsoutgoing = False, False
5551 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5558 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5552 if i:
5559 if i:
5553 needsincoming = True
5560 needsincoming = True
5554 if o:
5561 if o:
5555 needsoutgoing = True
5562 needsoutgoing = True
5556 if not needsincoming and not needsoutgoing:
5563 if not needsincoming and not needsoutgoing:
5557 return
5564 return
5558
5565
5559 def getincoming():
5566 def getincoming():
5560 source, branches = hg.parseurl(ui.expandpath('default'))
5567 source, branches = hg.parseurl(ui.expandpath('default'))
5561 sbranch = branches[0]
5568 sbranch = branches[0]
5562 try:
5569 try:
5563 other = hg.peer(repo, {}, source)
5570 other = hg.peer(repo, {}, source)
5564 except error.RepoError:
5571 except error.RepoError:
5565 if opts.get('remote'):
5572 if opts.get('remote'):
5566 raise
5573 raise
5567 return source, sbranch, None, None, None
5574 return source, sbranch, None, None, None
5568 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5575 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5569 if revs:
5576 if revs:
5570 revs = [other.lookup(rev) for rev in revs]
5577 revs = [other.lookup(rev) for rev in revs]
5571 ui.debug('comparing with %s\n' % util.hidepassword(source))
5578 ui.debug('comparing with %s\n' % util.hidepassword(source))
5572 repo.ui.pushbuffer()
5579 repo.ui.pushbuffer()
5573 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5580 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5574 repo.ui.popbuffer()
5581 repo.ui.popbuffer()
5575 return source, sbranch, other, commoninc, commoninc[1]
5582 return source, sbranch, other, commoninc, commoninc[1]
5576
5583
5577 if needsincoming:
5584 if needsincoming:
5578 source, sbranch, sother, commoninc, incoming = getincoming()
5585 source, sbranch, sother, commoninc, incoming = getincoming()
5579 else:
5586 else:
5580 source = sbranch = sother = commoninc = incoming = None
5587 source = sbranch = sother = commoninc = incoming = None
5581
5588
5582 def getoutgoing():
5589 def getoutgoing():
5583 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5590 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5584 dbranch = branches[0]
5591 dbranch = branches[0]
5585 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5592 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5586 if source != dest:
5593 if source != dest:
5587 try:
5594 try:
5588 dother = hg.peer(repo, {}, dest)
5595 dother = hg.peer(repo, {}, dest)
5589 except error.RepoError:
5596 except error.RepoError:
5590 if opts.get('remote'):
5597 if opts.get('remote'):
5591 raise
5598 raise
5592 return dest, dbranch, None, None
5599 return dest, dbranch, None, None
5593 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5600 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5594 elif sother is None:
5601 elif sother is None:
5595 # there is no explicit destination peer, but source one is invalid
5602 # there is no explicit destination peer, but source one is invalid
5596 return dest, dbranch, None, None
5603 return dest, dbranch, None, None
5597 else:
5604 else:
5598 dother = sother
5605 dother = sother
5599 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5606 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5600 common = None
5607 common = None
5601 else:
5608 else:
5602 common = commoninc
5609 common = commoninc
5603 if revs:
5610 if revs:
5604 revs = [repo.lookup(rev) for rev in revs]
5611 revs = [repo.lookup(rev) for rev in revs]
5605 repo.ui.pushbuffer()
5612 repo.ui.pushbuffer()
5606 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5613 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5607 commoninc=common)
5614 commoninc=common)
5608 repo.ui.popbuffer()
5615 repo.ui.popbuffer()
5609 return dest, dbranch, dother, outgoing
5616 return dest, dbranch, dother, outgoing
5610
5617
5611 if needsoutgoing:
5618 if needsoutgoing:
5612 dest, dbranch, dother, outgoing = getoutgoing()
5619 dest, dbranch, dother, outgoing = getoutgoing()
5613 else:
5620 else:
5614 dest = dbranch = dother = outgoing = None
5621 dest = dbranch = dother = outgoing = None
5615
5622
5616 if opts.get('remote'):
5623 if opts.get('remote'):
5617 t = []
5624 t = []
5618 if incoming:
5625 if incoming:
5619 t.append(_('1 or more incoming'))
5626 t.append(_('1 or more incoming'))
5620 o = outgoing.missing
5627 o = outgoing.missing
5621 if o:
5628 if o:
5622 t.append(_('%d outgoing') % len(o))
5629 t.append(_('%d outgoing') % len(o))
5623 other = dother or sother
5630 other = dother or sother
5624 if 'bookmarks' in other.listkeys('namespaces'):
5631 if 'bookmarks' in other.listkeys('namespaces'):
5625 lmarks = repo.listkeys('bookmarks')
5632 lmarks = repo.listkeys('bookmarks')
5626 rmarks = other.listkeys('bookmarks')
5633 rmarks = other.listkeys('bookmarks')
5627 diff = set(rmarks) - set(lmarks)
5634 diff = set(rmarks) - set(lmarks)
5628 if len(diff) > 0:
5635 if len(diff) > 0:
5629 t.append(_('%d incoming bookmarks') % len(diff))
5636 t.append(_('%d incoming bookmarks') % len(diff))
5630 diff = set(lmarks) - set(rmarks)
5637 diff = set(lmarks) - set(rmarks)
5631 if len(diff) > 0:
5638 if len(diff) > 0:
5632 t.append(_('%d outgoing bookmarks') % len(diff))
5639 t.append(_('%d outgoing bookmarks') % len(diff))
5633
5640
5634 if t:
5641 if t:
5635 # i18n: column positioning for "hg summary"
5642 # i18n: column positioning for "hg summary"
5636 ui.write(_('remote: %s\n') % (', '.join(t)))
5643 ui.write(_('remote: %s\n') % (', '.join(t)))
5637 else:
5644 else:
5638 # i18n: column positioning for "hg summary"
5645 # i18n: column positioning for "hg summary"
5639 ui.status(_('remote: (synced)\n'))
5646 ui.status(_('remote: (synced)\n'))
5640
5647
5641 cmdutil.summaryremotehooks(ui, repo, opts,
5648 cmdutil.summaryremotehooks(ui, repo, opts,
5642 ((source, sbranch, sother, commoninc),
5649 ((source, sbranch, sother, commoninc),
5643 (dest, dbranch, dother, outgoing)))
5650 (dest, dbranch, dother, outgoing)))
5644
5651
5645 @command('tag',
5652 @command('tag',
5646 [('f', 'force', None, _('force tag')),
5653 [('f', 'force', None, _('force tag')),
5647 ('l', 'local', None, _('make the tag local')),
5654 ('l', 'local', None, _('make the tag local')),
5648 ('r', 'rev', '', _('revision to tag'), _('REV')),
5655 ('r', 'rev', '', _('revision to tag'), _('REV')),
5649 ('', 'remove', None, _('remove a tag')),
5656 ('', 'remove', None, _('remove a tag')),
5650 # -l/--local is already there, commitopts cannot be used
5657 # -l/--local is already there, commitopts cannot be used
5651 ('e', 'edit', None, _('edit commit message')),
5658 ('e', 'edit', None, _('edit commit message')),
5652 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5659 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5653 ] + commitopts2,
5660 ] + commitopts2,
5654 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5661 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5655 def tag(ui, repo, name1, *names, **opts):
5662 def tag(ui, repo, name1, *names, **opts):
5656 """add one or more tags for the current or given revision
5663 """add one or more tags for the current or given revision
5657
5664
5658 Name a particular revision using <name>.
5665 Name a particular revision using <name>.
5659
5666
5660 Tags are used to name particular revisions of the repository and are
5667 Tags are used to name particular revisions of the repository and are
5661 very useful to compare different revisions, to go back to significant
5668 very useful to compare different revisions, to go back to significant
5662 earlier versions or to mark branch points as releases, etc. Changing
5669 earlier versions or to mark branch points as releases, etc. Changing
5663 an existing tag is normally disallowed; use -f/--force to override.
5670 an existing tag is normally disallowed; use -f/--force to override.
5664
5671
5665 If no revision is given, the parent of the working directory is
5672 If no revision is given, the parent of the working directory is
5666 used.
5673 used.
5667
5674
5668 To facilitate version control, distribution, and merging of tags,
5675 To facilitate version control, distribution, and merging of tags,
5669 they are stored as a file named ".hgtags" which is managed similarly
5676 they are stored as a file named ".hgtags" which is managed similarly
5670 to other project files and can be hand-edited if necessary. This
5677 to other project files and can be hand-edited if necessary. This
5671 also means that tagging creates a new commit. The file
5678 also means that tagging creates a new commit. The file
5672 ".hg/localtags" is used for local tags (not shared among
5679 ".hg/localtags" is used for local tags (not shared among
5673 repositories).
5680 repositories).
5674
5681
5675 Tag commits are usually made at the head of a branch. If the parent
5682 Tag commits are usually made at the head of a branch. If the parent
5676 of the working directory is not a branch head, :hg:`tag` aborts; use
5683 of the working directory is not a branch head, :hg:`tag` aborts; use
5677 -f/--force to force the tag commit to be based on a non-head
5684 -f/--force to force the tag commit to be based on a non-head
5678 changeset.
5685 changeset.
5679
5686
5680 See :hg:`help dates` for a list of formats valid for -d/--date.
5687 See :hg:`help dates` for a list of formats valid for -d/--date.
5681
5688
5682 Since tag names have priority over branch names during revision
5689 Since tag names have priority over branch names during revision
5683 lookup, using an existing branch name as a tag name is discouraged.
5690 lookup, using an existing branch name as a tag name is discouraged.
5684
5691
5685 Returns 0 on success.
5692 Returns 0 on success.
5686 """
5693 """
5687 wlock = lock = None
5694 wlock = lock = None
5688 try:
5695 try:
5689 wlock = repo.wlock()
5696 wlock = repo.wlock()
5690 lock = repo.lock()
5697 lock = repo.lock()
5691 rev_ = "."
5698 rev_ = "."
5692 names = [t.strip() for t in (name1,) + names]
5699 names = [t.strip() for t in (name1,) + names]
5693 if len(names) != len(set(names)):
5700 if len(names) != len(set(names)):
5694 raise util.Abort(_('tag names must be unique'))
5701 raise util.Abort(_('tag names must be unique'))
5695 for n in names:
5702 for n in names:
5696 scmutil.checknewlabel(repo, n, 'tag')
5703 scmutil.checknewlabel(repo, n, 'tag')
5697 if not n:
5704 if not n:
5698 raise util.Abort(_('tag names cannot consist entirely of '
5705 raise util.Abort(_('tag names cannot consist entirely of '
5699 'whitespace'))
5706 'whitespace'))
5700 if opts.get('rev') and opts.get('remove'):
5707 if opts.get('rev') and opts.get('remove'):
5701 raise util.Abort(_("--rev and --remove are incompatible"))
5708 raise util.Abort(_("--rev and --remove are incompatible"))
5702 if opts.get('rev'):
5709 if opts.get('rev'):
5703 rev_ = opts['rev']
5710 rev_ = opts['rev']
5704 message = opts.get('message')
5711 message = opts.get('message')
5705 if opts.get('remove'):
5712 if opts.get('remove'):
5706 expectedtype = opts.get('local') and 'local' or 'global'
5713 expectedtype = opts.get('local') and 'local' or 'global'
5707 for n in names:
5714 for n in names:
5708 if not repo.tagtype(n):
5715 if not repo.tagtype(n):
5709 raise util.Abort(_("tag '%s' does not exist") % n)
5716 raise util.Abort(_("tag '%s' does not exist") % n)
5710 if repo.tagtype(n) != expectedtype:
5717 if repo.tagtype(n) != expectedtype:
5711 if expectedtype == 'global':
5718 if expectedtype == 'global':
5712 raise util.Abort(_("tag '%s' is not a global tag") % n)
5719 raise util.Abort(_("tag '%s' is not a global tag") % n)
5713 else:
5720 else:
5714 raise util.Abort(_("tag '%s' is not a local tag") % n)
5721 raise util.Abort(_("tag '%s' is not a local tag") % n)
5715 rev_ = nullid
5722 rev_ = nullid
5716 if not message:
5723 if not message:
5717 # we don't translate commit messages
5724 # we don't translate commit messages
5718 message = 'Removed tag %s' % ', '.join(names)
5725 message = 'Removed tag %s' % ', '.join(names)
5719 elif not opts.get('force'):
5726 elif not opts.get('force'):
5720 for n in names:
5727 for n in names:
5721 if n in repo.tags():
5728 if n in repo.tags():
5722 raise util.Abort(_("tag '%s' already exists "
5729 raise util.Abort(_("tag '%s' already exists "
5723 "(use -f to force)") % n)
5730 "(use -f to force)") % n)
5724 if not opts.get('local'):
5731 if not opts.get('local'):
5725 p1, p2 = repo.dirstate.parents()
5732 p1, p2 = repo.dirstate.parents()
5726 if p2 != nullid:
5733 if p2 != nullid:
5727 raise util.Abort(_('uncommitted merge'))
5734 raise util.Abort(_('uncommitted merge'))
5728 bheads = repo.branchheads()
5735 bheads = repo.branchheads()
5729 if not opts.get('force') and bheads and p1 not in bheads:
5736 if not opts.get('force') and bheads and p1 not in bheads:
5730 raise util.Abort(_('not at a branch head (use -f to force)'))
5737 raise util.Abort(_('not at a branch head (use -f to force)'))
5731 r = scmutil.revsingle(repo, rev_).node()
5738 r = scmutil.revsingle(repo, rev_).node()
5732
5739
5733 if not message:
5740 if not message:
5734 # we don't translate commit messages
5741 # we don't translate commit messages
5735 message = ('Added tag %s for changeset %s' %
5742 message = ('Added tag %s for changeset %s' %
5736 (', '.join(names), short(r)))
5743 (', '.join(names), short(r)))
5737
5744
5738 date = opts.get('date')
5745 date = opts.get('date')
5739 if date:
5746 if date:
5740 date = util.parsedate(date)
5747 date = util.parsedate(date)
5741
5748
5742 editor = cmdutil.getcommiteditor(**opts)
5749 editor = cmdutil.getcommiteditor(**opts)
5743
5750
5744 # don't allow tagging the null rev
5751 # don't allow tagging the null rev
5745 if (not opts.get('remove') and
5752 if (not opts.get('remove') and
5746 scmutil.revsingle(repo, rev_).rev() == nullrev):
5753 scmutil.revsingle(repo, rev_).rev() == nullrev):
5747 raise util.Abort(_("cannot tag null revision"))
5754 raise util.Abort(_("cannot tag null revision"))
5748
5755
5749 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5756 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5750 editor=editor)
5757 editor=editor)
5751 finally:
5758 finally:
5752 release(lock, wlock)
5759 release(lock, wlock)
5753
5760
5754 @command('tags', [], '')
5761 @command('tags', [], '')
5755 def tags(ui, repo, **opts):
5762 def tags(ui, repo, **opts):
5756 """list repository tags
5763 """list repository tags
5757
5764
5758 This lists both regular and local tags. When the -v/--verbose
5765 This lists both regular and local tags. When the -v/--verbose
5759 switch is used, a third column "local" is printed for local tags.
5766 switch is used, a third column "local" is printed for local tags.
5760
5767
5761 Returns 0 on success.
5768 Returns 0 on success.
5762 """
5769 """
5763
5770
5764 fm = ui.formatter('tags', opts)
5771 fm = ui.formatter('tags', opts)
5765 hexfunc = ui.debugflag and hex or short
5772 hexfunc = ui.debugflag and hex or short
5766 tagtype = ""
5773 tagtype = ""
5767
5774
5768 for t, n in reversed(repo.tagslist()):
5775 for t, n in reversed(repo.tagslist()):
5769 hn = hexfunc(n)
5776 hn = hexfunc(n)
5770 label = 'tags.normal'
5777 label = 'tags.normal'
5771 tagtype = ''
5778 tagtype = ''
5772 if repo.tagtype(t) == 'local':
5779 if repo.tagtype(t) == 'local':
5773 label = 'tags.local'
5780 label = 'tags.local'
5774 tagtype = 'local'
5781 tagtype = 'local'
5775
5782
5776 fm.startitem()
5783 fm.startitem()
5777 fm.write('tag', '%s', t, label=label)
5784 fm.write('tag', '%s', t, label=label)
5778 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5785 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5779 fm.condwrite(not ui.quiet, 'rev id', fmt,
5786 fm.condwrite(not ui.quiet, 'rev id', fmt,
5780 repo.changelog.rev(n), hn, label=label)
5787 repo.changelog.rev(n), hn, label=label)
5781 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5788 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5782 tagtype, label=label)
5789 tagtype, label=label)
5783 fm.plain('\n')
5790 fm.plain('\n')
5784 fm.end()
5791 fm.end()
5785
5792
5786 @command('tip',
5793 @command('tip',
5787 [('p', 'patch', None, _('show patch')),
5794 [('p', 'patch', None, _('show patch')),
5788 ('g', 'git', None, _('use git extended diff format')),
5795 ('g', 'git', None, _('use git extended diff format')),
5789 ] + templateopts,
5796 ] + templateopts,
5790 _('[-p] [-g]'))
5797 _('[-p] [-g]'))
5791 def tip(ui, repo, **opts):
5798 def tip(ui, repo, **opts):
5792 """show the tip revision (DEPRECATED)
5799 """show the tip revision (DEPRECATED)
5793
5800
5794 The tip revision (usually just called the tip) is the changeset
5801 The tip revision (usually just called the tip) is the changeset
5795 most recently added to the repository (and therefore the most
5802 most recently added to the repository (and therefore the most
5796 recently changed head).
5803 recently changed head).
5797
5804
5798 If you have just made a commit, that commit will be the tip. If
5805 If you have just made a commit, that commit will be the tip. If
5799 you have just pulled changes from another repository, the tip of
5806 you have just pulled changes from another repository, the tip of
5800 that repository becomes the current tip. The "tip" tag is special
5807 that repository becomes the current tip. The "tip" tag is special
5801 and cannot be renamed or assigned to a different changeset.
5808 and cannot be renamed or assigned to a different changeset.
5802
5809
5803 This command is deprecated, please use :hg:`heads` instead.
5810 This command is deprecated, please use :hg:`heads` instead.
5804
5811
5805 Returns 0 on success.
5812 Returns 0 on success.
5806 """
5813 """
5807 displayer = cmdutil.show_changeset(ui, repo, opts)
5814 displayer = cmdutil.show_changeset(ui, repo, opts)
5808 displayer.show(repo['tip'])
5815 displayer.show(repo['tip'])
5809 displayer.close()
5816 displayer.close()
5810
5817
5811 @command('unbundle',
5818 @command('unbundle',
5812 [('u', 'update', None,
5819 [('u', 'update', None,
5813 _('update to new branch head if changesets were unbundled'))],
5820 _('update to new branch head if changesets were unbundled'))],
5814 _('[-u] FILE...'))
5821 _('[-u] FILE...'))
5815 def unbundle(ui, repo, fname1, *fnames, **opts):
5822 def unbundle(ui, repo, fname1, *fnames, **opts):
5816 """apply one or more changegroup files
5823 """apply one or more changegroup files
5817
5824
5818 Apply one or more compressed changegroup files generated by the
5825 Apply one or more compressed changegroup files generated by the
5819 bundle command.
5826 bundle command.
5820
5827
5821 Returns 0 on success, 1 if an update has unresolved files.
5828 Returns 0 on success, 1 if an update has unresolved files.
5822 """
5829 """
5823 fnames = (fname1,) + fnames
5830 fnames = (fname1,) + fnames
5824
5831
5825 lock = repo.lock()
5832 lock = repo.lock()
5826 wc = repo['.']
5833 wc = repo['.']
5827 try:
5834 try:
5828 for fname in fnames:
5835 for fname in fnames:
5829 f = hg.openpath(ui, fname)
5836 f = hg.openpath(ui, fname)
5830 gen = exchange.readbundle(ui, f, fname)
5837 gen = exchange.readbundle(ui, f, fname)
5831 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
5838 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
5832 'bundle:' + fname)
5839 'bundle:' + fname)
5833 finally:
5840 finally:
5834 lock.release()
5841 lock.release()
5835 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5842 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5836 return postincoming(ui, repo, modheads, opts.get('update'), None)
5843 return postincoming(ui, repo, modheads, opts.get('update'), None)
5837
5844
5838 @command('^update|up|checkout|co',
5845 @command('^update|up|checkout|co',
5839 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5846 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5840 ('c', 'check', None,
5847 ('c', 'check', None,
5841 _('update across branches if no uncommitted changes')),
5848 _('update across branches if no uncommitted changes')),
5842 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5849 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5843 ('r', 'rev', '', _('revision'), _('REV'))
5850 ('r', 'rev', '', _('revision'), _('REV'))
5844 ] + mergetoolopts,
5851 ] + mergetoolopts,
5845 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5852 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5846 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5853 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5847 tool=None):
5854 tool=None):
5848 """update working directory (or switch revisions)
5855 """update working directory (or switch revisions)
5849
5856
5850 Update the repository's working directory to the specified
5857 Update the repository's working directory to the specified
5851 changeset. If no changeset is specified, update to the tip of the
5858 changeset. If no changeset is specified, update to the tip of the
5852 current named branch and move the current bookmark (see :hg:`help
5859 current named branch and move the current bookmark (see :hg:`help
5853 bookmarks`).
5860 bookmarks`).
5854
5861
5855 Update sets the working directory's parent revision to the specified
5862 Update sets the working directory's parent revision to the specified
5856 changeset (see :hg:`help parents`).
5863 changeset (see :hg:`help parents`).
5857
5864
5858 If the changeset is not a descendant or ancestor of the working
5865 If the changeset is not a descendant or ancestor of the working
5859 directory's parent, the update is aborted. With the -c/--check
5866 directory's parent, the update is aborted. With the -c/--check
5860 option, the working directory is checked for uncommitted changes; if
5867 option, the working directory is checked for uncommitted changes; if
5861 none are found, the working directory is updated to the specified
5868 none are found, the working directory is updated to the specified
5862 changeset.
5869 changeset.
5863
5870
5864 .. container:: verbose
5871 .. container:: verbose
5865
5872
5866 The following rules apply when the working directory contains
5873 The following rules apply when the working directory contains
5867 uncommitted changes:
5874 uncommitted changes:
5868
5875
5869 1. If neither -c/--check nor -C/--clean is specified, and if
5876 1. If neither -c/--check nor -C/--clean is specified, and if
5870 the requested changeset is an ancestor or descendant of
5877 the requested changeset is an ancestor or descendant of
5871 the working directory's parent, the uncommitted changes
5878 the working directory's parent, the uncommitted changes
5872 are merged into the requested changeset and the merged
5879 are merged into the requested changeset and the merged
5873 result is left uncommitted. If the requested changeset is
5880 result is left uncommitted. If the requested changeset is
5874 not an ancestor or descendant (that is, it is on another
5881 not an ancestor or descendant (that is, it is on another
5875 branch), the update is aborted and the uncommitted changes
5882 branch), the update is aborted and the uncommitted changes
5876 are preserved.
5883 are preserved.
5877
5884
5878 2. With the -c/--check option, the update is aborted and the
5885 2. With the -c/--check option, the update is aborted and the
5879 uncommitted changes are preserved.
5886 uncommitted changes are preserved.
5880
5887
5881 3. With the -C/--clean option, uncommitted changes are discarded and
5888 3. With the -C/--clean option, uncommitted changes are discarded and
5882 the working directory is updated to the requested changeset.
5889 the working directory is updated to the requested changeset.
5883
5890
5884 To cancel an uncommitted merge (and lose your changes), use
5891 To cancel an uncommitted merge (and lose your changes), use
5885 :hg:`update --clean .`.
5892 :hg:`update --clean .`.
5886
5893
5887 Use null as the changeset to remove the working directory (like
5894 Use null as the changeset to remove the working directory (like
5888 :hg:`clone -U`).
5895 :hg:`clone -U`).
5889
5896
5890 If you want to revert just one file to an older revision, use
5897 If you want to revert just one file to an older revision, use
5891 :hg:`revert [-r REV] NAME`.
5898 :hg:`revert [-r REV] NAME`.
5892
5899
5893 See :hg:`help dates` for a list of formats valid for -d/--date.
5900 See :hg:`help dates` for a list of formats valid for -d/--date.
5894
5901
5895 Returns 0 on success, 1 if there are unresolved files.
5902 Returns 0 on success, 1 if there are unresolved files.
5896 """
5903 """
5897 if rev and node:
5904 if rev and node:
5898 raise util.Abort(_("please specify just one revision"))
5905 raise util.Abort(_("please specify just one revision"))
5899
5906
5900 if rev is None or rev == '':
5907 if rev is None or rev == '':
5901 rev = node
5908 rev = node
5902
5909
5903 cmdutil.clearunfinished(repo)
5910 cmdutil.clearunfinished(repo)
5904
5911
5905 # with no argument, we also move the current bookmark, if any
5912 # with no argument, we also move the current bookmark, if any
5906 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5913 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5907
5914
5908 # if we defined a bookmark, we have to remember the original bookmark name
5915 # if we defined a bookmark, we have to remember the original bookmark name
5909 brev = rev
5916 brev = rev
5910 rev = scmutil.revsingle(repo, rev, rev).rev()
5917 rev = scmutil.revsingle(repo, rev, rev).rev()
5911
5918
5912 if check and clean:
5919 if check and clean:
5913 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5920 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5914
5921
5915 if date:
5922 if date:
5916 if rev is not None:
5923 if rev is not None:
5917 raise util.Abort(_("you can't specify a revision and a date"))
5924 raise util.Abort(_("you can't specify a revision and a date"))
5918 rev = cmdutil.finddate(ui, repo, date)
5925 rev = cmdutil.finddate(ui, repo, date)
5919
5926
5920 if check:
5927 if check:
5921 c = repo[None]
5928 c = repo[None]
5922 if c.dirty(merge=False, branch=False, missing=True):
5929 if c.dirty(merge=False, branch=False, missing=True):
5923 raise util.Abort(_("uncommitted changes"))
5930 raise util.Abort(_("uncommitted changes"))
5924 if rev is None:
5931 if rev is None:
5925 rev = repo[repo[None].branch()].rev()
5932 rev = repo[repo[None].branch()].rev()
5926 mergemod._checkunknown(repo, repo[None], repo[rev])
5933 mergemod._checkunknown(repo, repo[None], repo[rev])
5927
5934
5928 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5935 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5929
5936
5930 if clean:
5937 if clean:
5931 ret = hg.clean(repo, rev)
5938 ret = hg.clean(repo, rev)
5932 else:
5939 else:
5933 ret = hg.update(repo, rev)
5940 ret = hg.update(repo, rev)
5934
5941
5935 if not ret and movemarkfrom:
5942 if not ret and movemarkfrom:
5936 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5943 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5937 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5944 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5938 elif brev in repo._bookmarks:
5945 elif brev in repo._bookmarks:
5939 bookmarks.setcurrent(repo, brev)
5946 bookmarks.setcurrent(repo, brev)
5940 ui.status(_("(activating bookmark %s)\n") % brev)
5947 ui.status(_("(activating bookmark %s)\n") % brev)
5941 elif brev:
5948 elif brev:
5942 if repo._bookmarkcurrent:
5949 if repo._bookmarkcurrent:
5943 ui.status(_("(leaving bookmark %s)\n") %
5950 ui.status(_("(leaving bookmark %s)\n") %
5944 repo._bookmarkcurrent)
5951 repo._bookmarkcurrent)
5945 bookmarks.unsetcurrent(repo)
5952 bookmarks.unsetcurrent(repo)
5946
5953
5947 return ret
5954 return ret
5948
5955
5949 @command('verify', [])
5956 @command('verify', [])
5950 def verify(ui, repo):
5957 def verify(ui, repo):
5951 """verify the integrity of the repository
5958 """verify the integrity of the repository
5952
5959
5953 Verify the integrity of the current repository.
5960 Verify the integrity of the current repository.
5954
5961
5955 This will perform an extensive check of the repository's
5962 This will perform an extensive check of the repository's
5956 integrity, validating the hashes and checksums of each entry in
5963 integrity, validating the hashes and checksums of each entry in
5957 the changelog, manifest, and tracked files, as well as the
5964 the changelog, manifest, and tracked files, as well as the
5958 integrity of their crosslinks and indices.
5965 integrity of their crosslinks and indices.
5959
5966
5960 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5967 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5961 for more information about recovery from corruption of the
5968 for more information about recovery from corruption of the
5962 repository.
5969 repository.
5963
5970
5964 Returns 0 on success, 1 if errors are encountered.
5971 Returns 0 on success, 1 if errors are encountered.
5965 """
5972 """
5966 return hg.verify(repo)
5973 return hg.verify(repo)
5967
5974
5968 @command('version', [])
5975 @command('version', [])
5969 def version_(ui):
5976 def version_(ui):
5970 """output version and copyright information"""
5977 """output version and copyright information"""
5971 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5978 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5972 % util.version())
5979 % util.version())
5973 ui.status(_(
5980 ui.status(_(
5974 "(see http://mercurial.selenic.com for more information)\n"
5981 "(see http://mercurial.selenic.com for more information)\n"
5975 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
5982 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
5976 "This is free software; see the source for copying conditions. "
5983 "This is free software; see the source for copying conditions. "
5977 "There is NO\nwarranty; "
5984 "There is NO\nwarranty; "
5978 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5985 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5979 ))
5986 ))
5980
5981 norepo = ("clone init version help debugcommands debugcomplete"
5982 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5983 " debugknown debuggetbundle debugbundle")
5984 optionalrepo = ("identify paths serve config showconfig debugancestor debugdag"
5985 " debugdata debugindex debugindexdot debugrevlog")
5986 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5987 " remove resolve status debugwalk")
General Comments 0
You need to be logged in to leave comments. Login now