##// END OF EJS Templates
remove: move most of the implementation into cmdutils.remove()...
Matt Harbison -
r23289:ae5d0a22 default
parent child Browse files
Show More
@@ -1,2882 +1,2935 b''
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, nullid, nullrev, short
8 from node import hex, nullid, nullrev, short
9 from i18n import _
9 from i18n import _
10 import os, sys, errno, re, tempfile
10 import os, sys, errno, re, tempfile
11 import util, scmutil, templater, patch, error, templatekw, revlog, 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 encoding
16 import encoding
17 import lock as lockmod
17 import lock as lockmod
18
18
19 def parsealiases(cmd):
19 def parsealiases(cmd):
20 return cmd.lstrip("^").split("|")
20 return cmd.lstrip("^").split("|")
21
21
22 def findpossible(cmd, table, strict=False):
22 def findpossible(cmd, table, strict=False):
23 """
23 """
24 Return cmd -> (aliases, command table entry)
24 Return cmd -> (aliases, command table entry)
25 for each matching command.
25 for each matching command.
26 Return debug commands (or their aliases) only if no normal command matches.
26 Return debug commands (or their aliases) only if no normal command matches.
27 """
27 """
28 choice = {}
28 choice = {}
29 debugchoice = {}
29 debugchoice = {}
30
30
31 if cmd in table:
31 if cmd in table:
32 # short-circuit exact matches, "log" alias beats "^log|history"
32 # short-circuit exact matches, "log" alias beats "^log|history"
33 keys = [cmd]
33 keys = [cmd]
34 else:
34 else:
35 keys = table.keys()
35 keys = table.keys()
36
36
37 for e in keys:
37 for e in keys:
38 aliases = parsealiases(e)
38 aliases = parsealiases(e)
39 found = None
39 found = None
40 if cmd in aliases:
40 if cmd in aliases:
41 found = cmd
41 found = cmd
42 elif not strict:
42 elif not strict:
43 for a in aliases:
43 for a in aliases:
44 if a.startswith(cmd):
44 if a.startswith(cmd):
45 found = a
45 found = a
46 break
46 break
47 if found is not None:
47 if found is not None:
48 if aliases[0].startswith("debug") or found.startswith("debug"):
48 if aliases[0].startswith("debug") or found.startswith("debug"):
49 debugchoice[found] = (aliases, table[e])
49 debugchoice[found] = (aliases, table[e])
50 else:
50 else:
51 choice[found] = (aliases, table[e])
51 choice[found] = (aliases, table[e])
52
52
53 if not choice and debugchoice:
53 if not choice and debugchoice:
54 choice = debugchoice
54 choice = debugchoice
55
55
56 return choice
56 return choice
57
57
58 def findcmd(cmd, table, strict=True):
58 def findcmd(cmd, table, strict=True):
59 """Return (aliases, command table entry) for command string."""
59 """Return (aliases, command table entry) for command string."""
60 choice = findpossible(cmd, table, strict)
60 choice = findpossible(cmd, table, strict)
61
61
62 if cmd in choice:
62 if cmd in choice:
63 return choice[cmd]
63 return choice[cmd]
64
64
65 if len(choice) > 1:
65 if len(choice) > 1:
66 clist = choice.keys()
66 clist = choice.keys()
67 clist.sort()
67 clist.sort()
68 raise error.AmbiguousCommand(cmd, clist)
68 raise error.AmbiguousCommand(cmd, clist)
69
69
70 if choice:
70 if choice:
71 return choice.values()[0]
71 return choice.values()[0]
72
72
73 raise error.UnknownCommand(cmd)
73 raise error.UnknownCommand(cmd)
74
74
75 def findrepo(p):
75 def findrepo(p):
76 while not os.path.isdir(os.path.join(p, ".hg")):
76 while not os.path.isdir(os.path.join(p, ".hg")):
77 oldp, p = p, os.path.dirname(p)
77 oldp, p = p, os.path.dirname(p)
78 if p == oldp:
78 if p == oldp:
79 return None
79 return None
80
80
81 return p
81 return p
82
82
83 def bailifchanged(repo):
83 def bailifchanged(repo):
84 if repo.dirstate.p2() != nullid:
84 if repo.dirstate.p2() != nullid:
85 raise util.Abort(_('outstanding uncommitted merge'))
85 raise util.Abort(_('outstanding uncommitted merge'))
86 modified, added, removed, deleted = repo.status()[:4]
86 modified, added, removed, deleted = repo.status()[:4]
87 if modified or added or removed or deleted:
87 if modified or added or removed or deleted:
88 raise util.Abort(_('uncommitted changes'))
88 raise util.Abort(_('uncommitted changes'))
89 ctx = repo[None]
89 ctx = repo[None]
90 for s in sorted(ctx.substate):
90 for s in sorted(ctx.substate):
91 if ctx.sub(s).dirty():
91 if ctx.sub(s).dirty():
92 raise util.Abort(_("uncommitted changes in subrepo %s") % s)
92 raise util.Abort(_("uncommitted changes in subrepo %s") % s)
93
93
94 def logmessage(ui, opts):
94 def logmessage(ui, opts):
95 """ get the log message according to -m and -l option """
95 """ get the log message according to -m and -l option """
96 message = opts.get('message')
96 message = opts.get('message')
97 logfile = opts.get('logfile')
97 logfile = opts.get('logfile')
98
98
99 if message and logfile:
99 if message and logfile:
100 raise util.Abort(_('options --message and --logfile are mutually '
100 raise util.Abort(_('options --message and --logfile are mutually '
101 'exclusive'))
101 'exclusive'))
102 if not message and logfile:
102 if not message and logfile:
103 try:
103 try:
104 if logfile == '-':
104 if logfile == '-':
105 message = ui.fin.read()
105 message = ui.fin.read()
106 else:
106 else:
107 message = '\n'.join(util.readfile(logfile).splitlines())
107 message = '\n'.join(util.readfile(logfile).splitlines())
108 except IOError, inst:
108 except IOError, inst:
109 raise util.Abort(_("can't read commit message '%s': %s") %
109 raise util.Abort(_("can't read commit message '%s': %s") %
110 (logfile, inst.strerror))
110 (logfile, inst.strerror))
111 return message
111 return message
112
112
113 def mergeeditform(ctxorbool, baseform):
113 def mergeeditform(ctxorbool, baseform):
114 """build appropriate editform from ctxorbool and baseform
114 """build appropriate editform from ctxorbool and baseform
115
115
116 'ctxorbool' is one of a ctx to be committed, or a bool whether
116 'ctxorbool' is one of a ctx to be committed, or a bool whether
117 merging is committed.
117 merging is committed.
118
118
119 This returns editform 'baseform' with '.merge' if merging is
119 This returns editform 'baseform' with '.merge' if merging is
120 committed, or one with '.normal' suffix otherwise.
120 committed, or one with '.normal' suffix otherwise.
121 """
121 """
122 if isinstance(ctxorbool, bool):
122 if isinstance(ctxorbool, bool):
123 if ctxorbool:
123 if ctxorbool:
124 return baseform + ".merge"
124 return baseform + ".merge"
125 elif 1 < len(ctxorbool.parents()):
125 elif 1 < len(ctxorbool.parents()):
126 return baseform + ".merge"
126 return baseform + ".merge"
127
127
128 return baseform + ".normal"
128 return baseform + ".normal"
129
129
130 def getcommiteditor(edit=False, finishdesc=None, extramsg=None,
130 def getcommiteditor(edit=False, finishdesc=None, extramsg=None,
131 editform='', **opts):
131 editform='', **opts):
132 """get appropriate commit message editor according to '--edit' option
132 """get appropriate commit message editor according to '--edit' option
133
133
134 'finishdesc' is a function to be called with edited commit message
134 'finishdesc' is a function to be called with edited commit message
135 (= 'description' of the new changeset) just after editing, but
135 (= 'description' of the new changeset) just after editing, but
136 before checking empty-ness. It should return actual text to be
136 before checking empty-ness. It should return actual text to be
137 stored into history. This allows to change description before
137 stored into history. This allows to change description before
138 storing.
138 storing.
139
139
140 'extramsg' is a extra message to be shown in the editor instead of
140 'extramsg' is a extra message to be shown in the editor instead of
141 'Leave message empty to abort commit' line. 'HG: ' prefix and EOL
141 'Leave message empty to abort commit' line. 'HG: ' prefix and EOL
142 is automatically added.
142 is automatically added.
143
143
144 'editform' is a dot-separated list of names, to distinguish
144 'editform' is a dot-separated list of names, to distinguish
145 the purpose of commit text editing.
145 the purpose of commit text editing.
146
146
147 'getcommiteditor' returns 'commitforceeditor' regardless of
147 'getcommiteditor' returns 'commitforceeditor' regardless of
148 'edit', if one of 'finishdesc' or 'extramsg' is specified, because
148 'edit', if one of 'finishdesc' or 'extramsg' is specified, because
149 they are specific for usage in MQ.
149 they are specific for usage in MQ.
150 """
150 """
151 if edit or finishdesc or extramsg:
151 if edit or finishdesc or extramsg:
152 return lambda r, c, s: commitforceeditor(r, c, s,
152 return lambda r, c, s: commitforceeditor(r, c, s,
153 finishdesc=finishdesc,
153 finishdesc=finishdesc,
154 extramsg=extramsg,
154 extramsg=extramsg,
155 editform=editform)
155 editform=editform)
156 elif editform:
156 elif editform:
157 return lambda r, c, s: commiteditor(r, c, s, editform=editform)
157 return lambda r, c, s: commiteditor(r, c, s, editform=editform)
158 else:
158 else:
159 return commiteditor
159 return commiteditor
160
160
161 def loglimit(opts):
161 def loglimit(opts):
162 """get the log limit according to option -l/--limit"""
162 """get the log limit according to option -l/--limit"""
163 limit = opts.get('limit')
163 limit = opts.get('limit')
164 if limit:
164 if limit:
165 try:
165 try:
166 limit = int(limit)
166 limit = int(limit)
167 except ValueError:
167 except ValueError:
168 raise util.Abort(_('limit must be a positive integer'))
168 raise util.Abort(_('limit must be a positive integer'))
169 if limit <= 0:
169 if limit <= 0:
170 raise util.Abort(_('limit must be positive'))
170 raise util.Abort(_('limit must be positive'))
171 else:
171 else:
172 limit = None
172 limit = None
173 return limit
173 return limit
174
174
175 def makefilename(repo, pat, node, desc=None,
175 def makefilename(repo, pat, node, desc=None,
176 total=None, seqno=None, revwidth=None, pathname=None):
176 total=None, seqno=None, revwidth=None, pathname=None):
177 node_expander = {
177 node_expander = {
178 'H': lambda: hex(node),
178 'H': lambda: hex(node),
179 'R': lambda: str(repo.changelog.rev(node)),
179 'R': lambda: str(repo.changelog.rev(node)),
180 'h': lambda: short(node),
180 'h': lambda: short(node),
181 'm': lambda: re.sub('[^\w]', '_', str(desc))
181 'm': lambda: re.sub('[^\w]', '_', str(desc))
182 }
182 }
183 expander = {
183 expander = {
184 '%': lambda: '%',
184 '%': lambda: '%',
185 'b': lambda: os.path.basename(repo.root),
185 'b': lambda: os.path.basename(repo.root),
186 }
186 }
187
187
188 try:
188 try:
189 if node:
189 if node:
190 expander.update(node_expander)
190 expander.update(node_expander)
191 if node:
191 if node:
192 expander['r'] = (lambda:
192 expander['r'] = (lambda:
193 str(repo.changelog.rev(node)).zfill(revwidth or 0))
193 str(repo.changelog.rev(node)).zfill(revwidth or 0))
194 if total is not None:
194 if total is not None:
195 expander['N'] = lambda: str(total)
195 expander['N'] = lambda: str(total)
196 if seqno is not None:
196 if seqno is not None:
197 expander['n'] = lambda: str(seqno)
197 expander['n'] = lambda: str(seqno)
198 if total is not None and seqno is not None:
198 if total is not None and seqno is not None:
199 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
199 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
200 if pathname is not None:
200 if pathname is not None:
201 expander['s'] = lambda: os.path.basename(pathname)
201 expander['s'] = lambda: os.path.basename(pathname)
202 expander['d'] = lambda: os.path.dirname(pathname) or '.'
202 expander['d'] = lambda: os.path.dirname(pathname) or '.'
203 expander['p'] = lambda: pathname
203 expander['p'] = lambda: pathname
204
204
205 newname = []
205 newname = []
206 patlen = len(pat)
206 patlen = len(pat)
207 i = 0
207 i = 0
208 while i < patlen:
208 while i < patlen:
209 c = pat[i]
209 c = pat[i]
210 if c == '%':
210 if c == '%':
211 i += 1
211 i += 1
212 c = pat[i]
212 c = pat[i]
213 c = expander[c]()
213 c = expander[c]()
214 newname.append(c)
214 newname.append(c)
215 i += 1
215 i += 1
216 return ''.join(newname)
216 return ''.join(newname)
217 except KeyError, inst:
217 except KeyError, inst:
218 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
218 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
219 inst.args[0])
219 inst.args[0])
220
220
221 def makefileobj(repo, pat, node=None, desc=None, total=None,
221 def makefileobj(repo, pat, node=None, desc=None, total=None,
222 seqno=None, revwidth=None, mode='wb', modemap=None,
222 seqno=None, revwidth=None, mode='wb', modemap=None,
223 pathname=None):
223 pathname=None):
224
224
225 writable = mode not in ('r', 'rb')
225 writable = mode not in ('r', 'rb')
226
226
227 if not pat or pat == '-':
227 if not pat or pat == '-':
228 fp = writable and repo.ui.fout or repo.ui.fin
228 fp = writable and repo.ui.fout or repo.ui.fin
229 if util.safehasattr(fp, 'fileno'):
229 if util.safehasattr(fp, 'fileno'):
230 return os.fdopen(os.dup(fp.fileno()), mode)
230 return os.fdopen(os.dup(fp.fileno()), mode)
231 else:
231 else:
232 # if this fp can't be duped properly, return
232 # if this fp can't be duped properly, return
233 # a dummy object that can be closed
233 # a dummy object that can be closed
234 class wrappedfileobj(object):
234 class wrappedfileobj(object):
235 noop = lambda x: None
235 noop = lambda x: None
236 def __init__(self, f):
236 def __init__(self, f):
237 self.f = f
237 self.f = f
238 def __getattr__(self, attr):
238 def __getattr__(self, attr):
239 if attr == 'close':
239 if attr == 'close':
240 return self.noop
240 return self.noop
241 else:
241 else:
242 return getattr(self.f, attr)
242 return getattr(self.f, attr)
243
243
244 return wrappedfileobj(fp)
244 return wrappedfileobj(fp)
245 if util.safehasattr(pat, 'write') and writable:
245 if util.safehasattr(pat, 'write') and writable:
246 return pat
246 return pat
247 if util.safehasattr(pat, 'read') and 'r' in mode:
247 if util.safehasattr(pat, 'read') and 'r' in mode:
248 return pat
248 return pat
249 fn = makefilename(repo, pat, node, desc, total, seqno, revwidth, pathname)
249 fn = makefilename(repo, pat, node, desc, total, seqno, revwidth, pathname)
250 if modemap is not None:
250 if modemap is not None:
251 mode = modemap.get(fn, mode)
251 mode = modemap.get(fn, mode)
252 if mode == 'wb':
252 if mode == 'wb':
253 modemap[fn] = 'ab'
253 modemap[fn] = 'ab'
254 return open(fn, mode)
254 return open(fn, mode)
255
255
256 def openrevlog(repo, cmd, file_, opts):
256 def openrevlog(repo, cmd, file_, opts):
257 """opens the changelog, manifest, a filelog or a given revlog"""
257 """opens the changelog, manifest, a filelog or a given revlog"""
258 cl = opts['changelog']
258 cl = opts['changelog']
259 mf = opts['manifest']
259 mf = opts['manifest']
260 msg = None
260 msg = None
261 if cl and mf:
261 if cl and mf:
262 msg = _('cannot specify --changelog and --manifest at the same time')
262 msg = _('cannot specify --changelog and --manifest at the same time')
263 elif cl or mf:
263 elif cl or mf:
264 if file_:
264 if file_:
265 msg = _('cannot specify filename with --changelog or --manifest')
265 msg = _('cannot specify filename with --changelog or --manifest')
266 elif not repo:
266 elif not repo:
267 msg = _('cannot specify --changelog or --manifest '
267 msg = _('cannot specify --changelog or --manifest '
268 'without a repository')
268 'without a repository')
269 if msg:
269 if msg:
270 raise util.Abort(msg)
270 raise util.Abort(msg)
271
271
272 r = None
272 r = None
273 if repo:
273 if repo:
274 if cl:
274 if cl:
275 r = repo.unfiltered().changelog
275 r = repo.unfiltered().changelog
276 elif mf:
276 elif mf:
277 r = repo.manifest
277 r = repo.manifest
278 elif file_:
278 elif file_:
279 filelog = repo.file(file_)
279 filelog = repo.file(file_)
280 if len(filelog):
280 if len(filelog):
281 r = filelog
281 r = filelog
282 if not r:
282 if not r:
283 if not file_:
283 if not file_:
284 raise error.CommandError(cmd, _('invalid arguments'))
284 raise error.CommandError(cmd, _('invalid arguments'))
285 if not os.path.isfile(file_):
285 if not os.path.isfile(file_):
286 raise util.Abort(_("revlog '%s' not found") % file_)
286 raise util.Abort(_("revlog '%s' not found") % file_)
287 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
287 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
288 file_[:-2] + ".i")
288 file_[:-2] + ".i")
289 return r
289 return r
290
290
291 def copy(ui, repo, pats, opts, rename=False):
291 def copy(ui, repo, pats, opts, rename=False):
292 # called with the repo lock held
292 # called with the repo lock held
293 #
293 #
294 # hgsep => pathname that uses "/" to separate directories
294 # hgsep => pathname that uses "/" to separate directories
295 # ossep => pathname that uses os.sep to separate directories
295 # ossep => pathname that uses os.sep to separate directories
296 cwd = repo.getcwd()
296 cwd = repo.getcwd()
297 targets = {}
297 targets = {}
298 after = opts.get("after")
298 after = opts.get("after")
299 dryrun = opts.get("dry_run")
299 dryrun = opts.get("dry_run")
300 wctx = repo[None]
300 wctx = repo[None]
301
301
302 def walkpat(pat):
302 def walkpat(pat):
303 srcs = []
303 srcs = []
304 badstates = after and '?' or '?r'
304 badstates = after and '?' or '?r'
305 m = scmutil.match(repo[None], [pat], opts, globbed=True)
305 m = scmutil.match(repo[None], [pat], opts, globbed=True)
306 for abs in repo.walk(m):
306 for abs in repo.walk(m):
307 state = repo.dirstate[abs]
307 state = repo.dirstate[abs]
308 rel = m.rel(abs)
308 rel = m.rel(abs)
309 exact = m.exact(abs)
309 exact = m.exact(abs)
310 if state in badstates:
310 if state in badstates:
311 if exact and state == '?':
311 if exact and state == '?':
312 ui.warn(_('%s: not copying - file is not managed\n') % rel)
312 ui.warn(_('%s: not copying - file is not managed\n') % rel)
313 if exact and state == 'r':
313 if exact and state == 'r':
314 ui.warn(_('%s: not copying - file has been marked for'
314 ui.warn(_('%s: not copying - file has been marked for'
315 ' remove\n') % rel)
315 ' remove\n') % rel)
316 continue
316 continue
317 # abs: hgsep
317 # abs: hgsep
318 # rel: ossep
318 # rel: ossep
319 srcs.append((abs, rel, exact))
319 srcs.append((abs, rel, exact))
320 return srcs
320 return srcs
321
321
322 # abssrc: hgsep
322 # abssrc: hgsep
323 # relsrc: ossep
323 # relsrc: ossep
324 # otarget: ossep
324 # otarget: ossep
325 def copyfile(abssrc, relsrc, otarget, exact):
325 def copyfile(abssrc, relsrc, otarget, exact):
326 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
326 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
327 if '/' in abstarget:
327 if '/' in abstarget:
328 # We cannot normalize abstarget itself, this would prevent
328 # We cannot normalize abstarget itself, this would prevent
329 # case only renames, like a => A.
329 # case only renames, like a => A.
330 abspath, absname = abstarget.rsplit('/', 1)
330 abspath, absname = abstarget.rsplit('/', 1)
331 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
331 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
332 reltarget = repo.pathto(abstarget, cwd)
332 reltarget = repo.pathto(abstarget, cwd)
333 target = repo.wjoin(abstarget)
333 target = repo.wjoin(abstarget)
334 src = repo.wjoin(abssrc)
334 src = repo.wjoin(abssrc)
335 state = repo.dirstate[abstarget]
335 state = repo.dirstate[abstarget]
336
336
337 scmutil.checkportable(ui, abstarget)
337 scmutil.checkportable(ui, abstarget)
338
338
339 # check for collisions
339 # check for collisions
340 prevsrc = targets.get(abstarget)
340 prevsrc = targets.get(abstarget)
341 if prevsrc is not None:
341 if prevsrc is not None:
342 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
342 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
343 (reltarget, repo.pathto(abssrc, cwd),
343 (reltarget, repo.pathto(abssrc, cwd),
344 repo.pathto(prevsrc, cwd)))
344 repo.pathto(prevsrc, cwd)))
345 return
345 return
346
346
347 # check for overwrites
347 # check for overwrites
348 exists = os.path.lexists(target)
348 exists = os.path.lexists(target)
349 samefile = False
349 samefile = False
350 if exists and abssrc != abstarget:
350 if exists and abssrc != abstarget:
351 if (repo.dirstate.normalize(abssrc) ==
351 if (repo.dirstate.normalize(abssrc) ==
352 repo.dirstate.normalize(abstarget)):
352 repo.dirstate.normalize(abstarget)):
353 if not rename:
353 if not rename:
354 ui.warn(_("%s: can't copy - same file\n") % reltarget)
354 ui.warn(_("%s: can't copy - same file\n") % reltarget)
355 return
355 return
356 exists = False
356 exists = False
357 samefile = True
357 samefile = True
358
358
359 if not after and exists or after and state in 'mn':
359 if not after and exists or after and state in 'mn':
360 if not opts['force']:
360 if not opts['force']:
361 ui.warn(_('%s: not overwriting - file exists\n') %
361 ui.warn(_('%s: not overwriting - file exists\n') %
362 reltarget)
362 reltarget)
363 return
363 return
364
364
365 if after:
365 if after:
366 if not exists:
366 if not exists:
367 if rename:
367 if rename:
368 ui.warn(_('%s: not recording move - %s does not exist\n') %
368 ui.warn(_('%s: not recording move - %s does not exist\n') %
369 (relsrc, reltarget))
369 (relsrc, reltarget))
370 else:
370 else:
371 ui.warn(_('%s: not recording copy - %s does not exist\n') %
371 ui.warn(_('%s: not recording copy - %s does not exist\n') %
372 (relsrc, reltarget))
372 (relsrc, reltarget))
373 return
373 return
374 elif not dryrun:
374 elif not dryrun:
375 try:
375 try:
376 if exists:
376 if exists:
377 os.unlink(target)
377 os.unlink(target)
378 targetdir = os.path.dirname(target) or '.'
378 targetdir = os.path.dirname(target) or '.'
379 if not os.path.isdir(targetdir):
379 if not os.path.isdir(targetdir):
380 os.makedirs(targetdir)
380 os.makedirs(targetdir)
381 if samefile:
381 if samefile:
382 tmp = target + "~hgrename"
382 tmp = target + "~hgrename"
383 os.rename(src, tmp)
383 os.rename(src, tmp)
384 os.rename(tmp, target)
384 os.rename(tmp, target)
385 else:
385 else:
386 util.copyfile(src, target)
386 util.copyfile(src, target)
387 srcexists = True
387 srcexists = True
388 except IOError, inst:
388 except IOError, inst:
389 if inst.errno == errno.ENOENT:
389 if inst.errno == errno.ENOENT:
390 ui.warn(_('%s: deleted in working copy\n') % relsrc)
390 ui.warn(_('%s: deleted in working copy\n') % relsrc)
391 srcexists = False
391 srcexists = False
392 else:
392 else:
393 ui.warn(_('%s: cannot copy - %s\n') %
393 ui.warn(_('%s: cannot copy - %s\n') %
394 (relsrc, inst.strerror))
394 (relsrc, inst.strerror))
395 return True # report a failure
395 return True # report a failure
396
396
397 if ui.verbose or not exact:
397 if ui.verbose or not exact:
398 if rename:
398 if rename:
399 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
399 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
400 else:
400 else:
401 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
401 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
402
402
403 targets[abstarget] = abssrc
403 targets[abstarget] = abssrc
404
404
405 # fix up dirstate
405 # fix up dirstate
406 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
406 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
407 dryrun=dryrun, cwd=cwd)
407 dryrun=dryrun, cwd=cwd)
408 if rename and not dryrun:
408 if rename and not dryrun:
409 if not after and srcexists and not samefile:
409 if not after and srcexists and not samefile:
410 util.unlinkpath(repo.wjoin(abssrc))
410 util.unlinkpath(repo.wjoin(abssrc))
411 wctx.forget([abssrc])
411 wctx.forget([abssrc])
412
412
413 # pat: ossep
413 # pat: ossep
414 # dest ossep
414 # dest ossep
415 # srcs: list of (hgsep, hgsep, ossep, bool)
415 # srcs: list of (hgsep, hgsep, ossep, bool)
416 # return: function that takes hgsep and returns ossep
416 # return: function that takes hgsep and returns ossep
417 def targetpathfn(pat, dest, srcs):
417 def targetpathfn(pat, dest, srcs):
418 if os.path.isdir(pat):
418 if os.path.isdir(pat):
419 abspfx = pathutil.canonpath(repo.root, cwd, pat)
419 abspfx = pathutil.canonpath(repo.root, cwd, pat)
420 abspfx = util.localpath(abspfx)
420 abspfx = util.localpath(abspfx)
421 if destdirexists:
421 if destdirexists:
422 striplen = len(os.path.split(abspfx)[0])
422 striplen = len(os.path.split(abspfx)[0])
423 else:
423 else:
424 striplen = len(abspfx)
424 striplen = len(abspfx)
425 if striplen:
425 if striplen:
426 striplen += len(os.sep)
426 striplen += len(os.sep)
427 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
427 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
428 elif destdirexists:
428 elif destdirexists:
429 res = lambda p: os.path.join(dest,
429 res = lambda p: os.path.join(dest,
430 os.path.basename(util.localpath(p)))
430 os.path.basename(util.localpath(p)))
431 else:
431 else:
432 res = lambda p: dest
432 res = lambda p: dest
433 return res
433 return res
434
434
435 # pat: ossep
435 # pat: ossep
436 # dest ossep
436 # dest ossep
437 # srcs: list of (hgsep, hgsep, ossep, bool)
437 # srcs: list of (hgsep, hgsep, ossep, bool)
438 # return: function that takes hgsep and returns ossep
438 # return: function that takes hgsep and returns ossep
439 def targetpathafterfn(pat, dest, srcs):
439 def targetpathafterfn(pat, dest, srcs):
440 if matchmod.patkind(pat):
440 if matchmod.patkind(pat):
441 # a mercurial pattern
441 # a mercurial pattern
442 res = lambda p: os.path.join(dest,
442 res = lambda p: os.path.join(dest,
443 os.path.basename(util.localpath(p)))
443 os.path.basename(util.localpath(p)))
444 else:
444 else:
445 abspfx = pathutil.canonpath(repo.root, cwd, pat)
445 abspfx = pathutil.canonpath(repo.root, cwd, pat)
446 if len(abspfx) < len(srcs[0][0]):
446 if len(abspfx) < len(srcs[0][0]):
447 # A directory. Either the target path contains the last
447 # A directory. Either the target path contains the last
448 # component of the source path or it does not.
448 # component of the source path or it does not.
449 def evalpath(striplen):
449 def evalpath(striplen):
450 score = 0
450 score = 0
451 for s in srcs:
451 for s in srcs:
452 t = os.path.join(dest, util.localpath(s[0])[striplen:])
452 t = os.path.join(dest, util.localpath(s[0])[striplen:])
453 if os.path.lexists(t):
453 if os.path.lexists(t):
454 score += 1
454 score += 1
455 return score
455 return score
456
456
457 abspfx = util.localpath(abspfx)
457 abspfx = util.localpath(abspfx)
458 striplen = len(abspfx)
458 striplen = len(abspfx)
459 if striplen:
459 if striplen:
460 striplen += len(os.sep)
460 striplen += len(os.sep)
461 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
461 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
462 score = evalpath(striplen)
462 score = evalpath(striplen)
463 striplen1 = len(os.path.split(abspfx)[0])
463 striplen1 = len(os.path.split(abspfx)[0])
464 if striplen1:
464 if striplen1:
465 striplen1 += len(os.sep)
465 striplen1 += len(os.sep)
466 if evalpath(striplen1) > score:
466 if evalpath(striplen1) > score:
467 striplen = striplen1
467 striplen = striplen1
468 res = lambda p: os.path.join(dest,
468 res = lambda p: os.path.join(dest,
469 util.localpath(p)[striplen:])
469 util.localpath(p)[striplen:])
470 else:
470 else:
471 # a file
471 # a file
472 if destdirexists:
472 if destdirexists:
473 res = lambda p: os.path.join(dest,
473 res = lambda p: os.path.join(dest,
474 os.path.basename(util.localpath(p)))
474 os.path.basename(util.localpath(p)))
475 else:
475 else:
476 res = lambda p: dest
476 res = lambda p: dest
477 return res
477 return res
478
478
479
479
480 pats = scmutil.expandpats(pats)
480 pats = scmutil.expandpats(pats)
481 if not pats:
481 if not pats:
482 raise util.Abort(_('no source or destination specified'))
482 raise util.Abort(_('no source or destination specified'))
483 if len(pats) == 1:
483 if len(pats) == 1:
484 raise util.Abort(_('no destination specified'))
484 raise util.Abort(_('no destination specified'))
485 dest = pats.pop()
485 dest = pats.pop()
486 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
486 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
487 if not destdirexists:
487 if not destdirexists:
488 if len(pats) > 1 or matchmod.patkind(pats[0]):
488 if len(pats) > 1 or matchmod.patkind(pats[0]):
489 raise util.Abort(_('with multiple sources, destination must be an '
489 raise util.Abort(_('with multiple sources, destination must be an '
490 'existing directory'))
490 'existing directory'))
491 if util.endswithsep(dest):
491 if util.endswithsep(dest):
492 raise util.Abort(_('destination %s is not a directory') % dest)
492 raise util.Abort(_('destination %s is not a directory') % dest)
493
493
494 tfn = targetpathfn
494 tfn = targetpathfn
495 if after:
495 if after:
496 tfn = targetpathafterfn
496 tfn = targetpathafterfn
497 copylist = []
497 copylist = []
498 for pat in pats:
498 for pat in pats:
499 srcs = walkpat(pat)
499 srcs = walkpat(pat)
500 if not srcs:
500 if not srcs:
501 continue
501 continue
502 copylist.append((tfn(pat, dest, srcs), srcs))
502 copylist.append((tfn(pat, dest, srcs), srcs))
503 if not copylist:
503 if not copylist:
504 raise util.Abort(_('no files to copy'))
504 raise util.Abort(_('no files to copy'))
505
505
506 errors = 0
506 errors = 0
507 for targetpath, srcs in copylist:
507 for targetpath, srcs in copylist:
508 for abssrc, relsrc, exact in srcs:
508 for abssrc, relsrc, exact in srcs:
509 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
509 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
510 errors += 1
510 errors += 1
511
511
512 if errors:
512 if errors:
513 ui.warn(_('(consider using --after)\n'))
513 ui.warn(_('(consider using --after)\n'))
514
514
515 return errors != 0
515 return errors != 0
516
516
517 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
517 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
518 runargs=None, appendpid=False):
518 runargs=None, appendpid=False):
519 '''Run a command as a service.'''
519 '''Run a command as a service.'''
520
520
521 def writepid(pid):
521 def writepid(pid):
522 if opts['pid_file']:
522 if opts['pid_file']:
523 mode = appendpid and 'a' or 'w'
523 mode = appendpid and 'a' or 'w'
524 fp = open(opts['pid_file'], mode)
524 fp = open(opts['pid_file'], mode)
525 fp.write(str(pid) + '\n')
525 fp.write(str(pid) + '\n')
526 fp.close()
526 fp.close()
527
527
528 if opts['daemon'] and not opts['daemon_pipefds']:
528 if opts['daemon'] and not opts['daemon_pipefds']:
529 # Signal child process startup with file removal
529 # Signal child process startup with file removal
530 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
530 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
531 os.close(lockfd)
531 os.close(lockfd)
532 try:
532 try:
533 if not runargs:
533 if not runargs:
534 runargs = util.hgcmd() + sys.argv[1:]
534 runargs = util.hgcmd() + sys.argv[1:]
535 runargs.append('--daemon-pipefds=%s' % lockpath)
535 runargs.append('--daemon-pipefds=%s' % lockpath)
536 # Don't pass --cwd to the child process, because we've already
536 # Don't pass --cwd to the child process, because we've already
537 # changed directory.
537 # changed directory.
538 for i in xrange(1, len(runargs)):
538 for i in xrange(1, len(runargs)):
539 if runargs[i].startswith('--cwd='):
539 if runargs[i].startswith('--cwd='):
540 del runargs[i]
540 del runargs[i]
541 break
541 break
542 elif runargs[i].startswith('--cwd'):
542 elif runargs[i].startswith('--cwd'):
543 del runargs[i:i + 2]
543 del runargs[i:i + 2]
544 break
544 break
545 def condfn():
545 def condfn():
546 return not os.path.exists(lockpath)
546 return not os.path.exists(lockpath)
547 pid = util.rundetached(runargs, condfn)
547 pid = util.rundetached(runargs, condfn)
548 if pid < 0:
548 if pid < 0:
549 raise util.Abort(_('child process failed to start'))
549 raise util.Abort(_('child process failed to start'))
550 writepid(pid)
550 writepid(pid)
551 finally:
551 finally:
552 try:
552 try:
553 os.unlink(lockpath)
553 os.unlink(lockpath)
554 except OSError, e:
554 except OSError, e:
555 if e.errno != errno.ENOENT:
555 if e.errno != errno.ENOENT:
556 raise
556 raise
557 if parentfn:
557 if parentfn:
558 return parentfn(pid)
558 return parentfn(pid)
559 else:
559 else:
560 return
560 return
561
561
562 if initfn:
562 if initfn:
563 initfn()
563 initfn()
564
564
565 if not opts['daemon']:
565 if not opts['daemon']:
566 writepid(os.getpid())
566 writepid(os.getpid())
567
567
568 if opts['daemon_pipefds']:
568 if opts['daemon_pipefds']:
569 lockpath = opts['daemon_pipefds']
569 lockpath = opts['daemon_pipefds']
570 try:
570 try:
571 os.setsid()
571 os.setsid()
572 except AttributeError:
572 except AttributeError:
573 pass
573 pass
574 os.unlink(lockpath)
574 os.unlink(lockpath)
575 util.hidewindow()
575 util.hidewindow()
576 sys.stdout.flush()
576 sys.stdout.flush()
577 sys.stderr.flush()
577 sys.stderr.flush()
578
578
579 nullfd = os.open(os.devnull, os.O_RDWR)
579 nullfd = os.open(os.devnull, os.O_RDWR)
580 logfilefd = nullfd
580 logfilefd = nullfd
581 if logfile:
581 if logfile:
582 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
582 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
583 os.dup2(nullfd, 0)
583 os.dup2(nullfd, 0)
584 os.dup2(logfilefd, 1)
584 os.dup2(logfilefd, 1)
585 os.dup2(logfilefd, 2)
585 os.dup2(logfilefd, 2)
586 if nullfd not in (0, 1, 2):
586 if nullfd not in (0, 1, 2):
587 os.close(nullfd)
587 os.close(nullfd)
588 if logfile and logfilefd not in (0, 1, 2):
588 if logfile and logfilefd not in (0, 1, 2):
589 os.close(logfilefd)
589 os.close(logfilefd)
590
590
591 if runfn:
591 if runfn:
592 return runfn()
592 return runfn()
593
593
594 def tryimportone(ui, repo, hunk, parents, opts, msgs, updatefunc):
594 def tryimportone(ui, repo, hunk, parents, opts, msgs, updatefunc):
595 """Utility function used by commands.import to import a single patch
595 """Utility function used by commands.import to import a single patch
596
596
597 This function is explicitly defined here to help the evolve extension to
597 This function is explicitly defined here to help the evolve extension to
598 wrap this part of the import logic.
598 wrap this part of the import logic.
599
599
600 The API is currently a bit ugly because it a simple code translation from
600 The API is currently a bit ugly because it a simple code translation from
601 the import command. Feel free to make it better.
601 the import command. Feel free to make it better.
602
602
603 :hunk: a patch (as a binary string)
603 :hunk: a patch (as a binary string)
604 :parents: nodes that will be parent of the created commit
604 :parents: nodes that will be parent of the created commit
605 :opts: the full dict of option passed to the import command
605 :opts: the full dict of option passed to the import command
606 :msgs: list to save commit message to.
606 :msgs: list to save commit message to.
607 (used in case we need to save it when failing)
607 (used in case we need to save it when failing)
608 :updatefunc: a function that update a repo to a given node
608 :updatefunc: a function that update a repo to a given node
609 updatefunc(<repo>, <node>)
609 updatefunc(<repo>, <node>)
610 """
610 """
611 tmpname, message, user, date, branch, nodeid, p1, p2 = \
611 tmpname, message, user, date, branch, nodeid, p1, p2 = \
612 patch.extract(ui, hunk)
612 patch.extract(ui, hunk)
613
613
614 update = not opts.get('bypass')
614 update = not opts.get('bypass')
615 strip = opts["strip"]
615 strip = opts["strip"]
616 sim = float(opts.get('similarity') or 0)
616 sim = float(opts.get('similarity') or 0)
617 if not tmpname:
617 if not tmpname:
618 return (None, None, False)
618 return (None, None, False)
619 msg = _('applied to working directory')
619 msg = _('applied to working directory')
620
620
621 rejects = False
621 rejects = False
622
622
623 try:
623 try:
624 cmdline_message = logmessage(ui, opts)
624 cmdline_message = logmessage(ui, opts)
625 if cmdline_message:
625 if cmdline_message:
626 # pickup the cmdline msg
626 # pickup the cmdline msg
627 message = cmdline_message
627 message = cmdline_message
628 elif message:
628 elif message:
629 # pickup the patch msg
629 # pickup the patch msg
630 message = message.strip()
630 message = message.strip()
631 else:
631 else:
632 # launch the editor
632 # launch the editor
633 message = None
633 message = None
634 ui.debug('message:\n%s\n' % message)
634 ui.debug('message:\n%s\n' % message)
635
635
636 if len(parents) == 1:
636 if len(parents) == 1:
637 parents.append(repo[nullid])
637 parents.append(repo[nullid])
638 if opts.get('exact'):
638 if opts.get('exact'):
639 if not nodeid or not p1:
639 if not nodeid or not p1:
640 raise util.Abort(_('not a Mercurial patch'))
640 raise util.Abort(_('not a Mercurial patch'))
641 p1 = repo[p1]
641 p1 = repo[p1]
642 p2 = repo[p2 or nullid]
642 p2 = repo[p2 or nullid]
643 elif p2:
643 elif p2:
644 try:
644 try:
645 p1 = repo[p1]
645 p1 = repo[p1]
646 p2 = repo[p2]
646 p2 = repo[p2]
647 # Without any options, consider p2 only if the
647 # Without any options, consider p2 only if the
648 # patch is being applied on top of the recorded
648 # patch is being applied on top of the recorded
649 # first parent.
649 # first parent.
650 if p1 != parents[0]:
650 if p1 != parents[0]:
651 p1 = parents[0]
651 p1 = parents[0]
652 p2 = repo[nullid]
652 p2 = repo[nullid]
653 except error.RepoError:
653 except error.RepoError:
654 p1, p2 = parents
654 p1, p2 = parents
655 if p2.node() == nullid:
655 if p2.node() == nullid:
656 ui.warn(_("warning: import the patch as a normal revision\n"
656 ui.warn(_("warning: import the patch as a normal revision\n"
657 "(use --exact to import the patch as a merge)\n"))
657 "(use --exact to import the patch as a merge)\n"))
658 else:
658 else:
659 p1, p2 = parents
659 p1, p2 = parents
660
660
661 n = None
661 n = None
662 if update:
662 if update:
663 repo.dirstate.beginparentchange()
663 repo.dirstate.beginparentchange()
664 if p1 != parents[0]:
664 if p1 != parents[0]:
665 updatefunc(repo, p1.node())
665 updatefunc(repo, p1.node())
666 if p2 != parents[1]:
666 if p2 != parents[1]:
667 repo.setparents(p1.node(), p2.node())
667 repo.setparents(p1.node(), p2.node())
668
668
669 if opts.get('exact') or opts.get('import_branch'):
669 if opts.get('exact') or opts.get('import_branch'):
670 repo.dirstate.setbranch(branch or 'default')
670 repo.dirstate.setbranch(branch or 'default')
671
671
672 partial = opts.get('partial', False)
672 partial = opts.get('partial', False)
673 files = set()
673 files = set()
674 try:
674 try:
675 patch.patch(ui, repo, tmpname, strip=strip, files=files,
675 patch.patch(ui, repo, tmpname, strip=strip, files=files,
676 eolmode=None, similarity=sim / 100.0)
676 eolmode=None, similarity=sim / 100.0)
677 except patch.PatchError, e:
677 except patch.PatchError, e:
678 if not partial:
678 if not partial:
679 raise util.Abort(str(e))
679 raise util.Abort(str(e))
680 if partial:
680 if partial:
681 rejects = True
681 rejects = True
682
682
683 files = list(files)
683 files = list(files)
684 if opts.get('no_commit'):
684 if opts.get('no_commit'):
685 if message:
685 if message:
686 msgs.append(message)
686 msgs.append(message)
687 else:
687 else:
688 if opts.get('exact') or p2:
688 if opts.get('exact') or p2:
689 # If you got here, you either use --force and know what
689 # If you got here, you either use --force and know what
690 # you are doing or used --exact or a merge patch while
690 # you are doing or used --exact or a merge patch while
691 # being updated to its first parent.
691 # being updated to its first parent.
692 m = None
692 m = None
693 else:
693 else:
694 m = scmutil.matchfiles(repo, files or [])
694 m = scmutil.matchfiles(repo, files or [])
695 editform = mergeeditform(repo[None], 'import.normal')
695 editform = mergeeditform(repo[None], 'import.normal')
696 if opts.get('exact'):
696 if opts.get('exact'):
697 editor = None
697 editor = None
698 else:
698 else:
699 editor = getcommiteditor(editform=editform, **opts)
699 editor = getcommiteditor(editform=editform, **opts)
700 n = repo.commit(message, opts.get('user') or user,
700 n = repo.commit(message, opts.get('user') or user,
701 opts.get('date') or date, match=m,
701 opts.get('date') or date, match=m,
702 editor=editor, force=partial)
702 editor=editor, force=partial)
703 repo.dirstate.endparentchange()
703 repo.dirstate.endparentchange()
704 else:
704 else:
705 if opts.get('exact') or opts.get('import_branch'):
705 if opts.get('exact') or opts.get('import_branch'):
706 branch = branch or 'default'
706 branch = branch or 'default'
707 else:
707 else:
708 branch = p1.branch()
708 branch = p1.branch()
709 store = patch.filestore()
709 store = patch.filestore()
710 try:
710 try:
711 files = set()
711 files = set()
712 try:
712 try:
713 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
713 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
714 files, eolmode=None)
714 files, eolmode=None)
715 except patch.PatchError, e:
715 except patch.PatchError, e:
716 raise util.Abort(str(e))
716 raise util.Abort(str(e))
717 if opts.get('exact'):
717 if opts.get('exact'):
718 editor = None
718 editor = None
719 else:
719 else:
720 editor = getcommiteditor(editform='import.bypass')
720 editor = getcommiteditor(editform='import.bypass')
721 memctx = context.makememctx(repo, (p1.node(), p2.node()),
721 memctx = context.makememctx(repo, (p1.node(), p2.node()),
722 message,
722 message,
723 opts.get('user') or user,
723 opts.get('user') or user,
724 opts.get('date') or date,
724 opts.get('date') or date,
725 branch, files, store,
725 branch, files, store,
726 editor=editor)
726 editor=editor)
727 n = memctx.commit()
727 n = memctx.commit()
728 finally:
728 finally:
729 store.close()
729 store.close()
730 if opts.get('exact') and opts.get('no_commit'):
730 if opts.get('exact') and opts.get('no_commit'):
731 # --exact with --no-commit is still useful in that it does merge
731 # --exact with --no-commit is still useful in that it does merge
732 # and branch bits
732 # and branch bits
733 ui.warn(_("warning: can't check exact import with --no-commit\n"))
733 ui.warn(_("warning: can't check exact import with --no-commit\n"))
734 elif opts.get('exact') and hex(n) != nodeid:
734 elif opts.get('exact') and hex(n) != nodeid:
735 raise util.Abort(_('patch is damaged or loses information'))
735 raise util.Abort(_('patch is damaged or loses information'))
736 if n:
736 if n:
737 # i18n: refers to a short changeset id
737 # i18n: refers to a short changeset id
738 msg = _('created %s') % short(n)
738 msg = _('created %s') % short(n)
739 return (msg, n, rejects)
739 return (msg, n, rejects)
740 finally:
740 finally:
741 os.unlink(tmpname)
741 os.unlink(tmpname)
742
742
743 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
743 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
744 opts=None):
744 opts=None):
745 '''export changesets as hg patches.'''
745 '''export changesets as hg patches.'''
746
746
747 total = len(revs)
747 total = len(revs)
748 revwidth = max([len(str(rev)) for rev in revs])
748 revwidth = max([len(str(rev)) for rev in revs])
749 filemode = {}
749 filemode = {}
750
750
751 def single(rev, seqno, fp):
751 def single(rev, seqno, fp):
752 ctx = repo[rev]
752 ctx = repo[rev]
753 node = ctx.node()
753 node = ctx.node()
754 parents = [p.node() for p in ctx.parents() if p]
754 parents = [p.node() for p in ctx.parents() if p]
755 branch = ctx.branch()
755 branch = ctx.branch()
756 if switch_parent:
756 if switch_parent:
757 parents.reverse()
757 parents.reverse()
758 prev = (parents and parents[0]) or nullid
758 prev = (parents and parents[0]) or nullid
759
759
760 shouldclose = False
760 shouldclose = False
761 if not fp and len(template) > 0:
761 if not fp and len(template) > 0:
762 desc_lines = ctx.description().rstrip().split('\n')
762 desc_lines = ctx.description().rstrip().split('\n')
763 desc = desc_lines[0] #Commit always has a first line.
763 desc = desc_lines[0] #Commit always has a first line.
764 fp = makefileobj(repo, template, node, desc=desc, total=total,
764 fp = makefileobj(repo, template, node, desc=desc, total=total,
765 seqno=seqno, revwidth=revwidth, mode='wb',
765 seqno=seqno, revwidth=revwidth, mode='wb',
766 modemap=filemode)
766 modemap=filemode)
767 if fp != template:
767 if fp != template:
768 shouldclose = True
768 shouldclose = True
769 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
769 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
770 repo.ui.note("%s\n" % fp.name)
770 repo.ui.note("%s\n" % fp.name)
771
771
772 if not fp:
772 if not fp:
773 write = repo.ui.write
773 write = repo.ui.write
774 else:
774 else:
775 def write(s, **kw):
775 def write(s, **kw):
776 fp.write(s)
776 fp.write(s)
777
777
778
778
779 write("# HG changeset patch\n")
779 write("# HG changeset patch\n")
780 write("# User %s\n" % ctx.user())
780 write("# User %s\n" % ctx.user())
781 write("# Date %d %d\n" % ctx.date())
781 write("# Date %d %d\n" % ctx.date())
782 write("# %s\n" % util.datestr(ctx.date()))
782 write("# %s\n" % util.datestr(ctx.date()))
783 if branch and branch != 'default':
783 if branch and branch != 'default':
784 write("# Branch %s\n" % branch)
784 write("# Branch %s\n" % branch)
785 write("# Node ID %s\n" % hex(node))
785 write("# Node ID %s\n" % hex(node))
786 write("# Parent %s\n" % hex(prev))
786 write("# Parent %s\n" % hex(prev))
787 if len(parents) > 1:
787 if len(parents) > 1:
788 write("# Parent %s\n" % hex(parents[1]))
788 write("# Parent %s\n" % hex(parents[1]))
789 write(ctx.description().rstrip())
789 write(ctx.description().rstrip())
790 write("\n\n")
790 write("\n\n")
791
791
792 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
792 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
793 write(chunk, label=label)
793 write(chunk, label=label)
794
794
795 if shouldclose:
795 if shouldclose:
796 fp.close()
796 fp.close()
797
797
798 for seqno, rev in enumerate(revs):
798 for seqno, rev in enumerate(revs):
799 single(rev, seqno + 1, fp)
799 single(rev, seqno + 1, fp)
800
800
801 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
801 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
802 changes=None, stat=False, fp=None, prefix='',
802 changes=None, stat=False, fp=None, prefix='',
803 listsubrepos=False):
803 listsubrepos=False):
804 '''show diff or diffstat.'''
804 '''show diff or diffstat.'''
805 if fp is None:
805 if fp is None:
806 write = ui.write
806 write = ui.write
807 else:
807 else:
808 def write(s, **kw):
808 def write(s, **kw):
809 fp.write(s)
809 fp.write(s)
810
810
811 if stat:
811 if stat:
812 diffopts = diffopts.copy(context=0)
812 diffopts = diffopts.copy(context=0)
813 width = 80
813 width = 80
814 if not ui.plain():
814 if not ui.plain():
815 width = ui.termwidth()
815 width = ui.termwidth()
816 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
816 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
817 prefix=prefix)
817 prefix=prefix)
818 for chunk, label in patch.diffstatui(util.iterlines(chunks),
818 for chunk, label in patch.diffstatui(util.iterlines(chunks),
819 width=width,
819 width=width,
820 git=diffopts.git):
820 git=diffopts.git):
821 write(chunk, label=label)
821 write(chunk, label=label)
822 else:
822 else:
823 for chunk, label in patch.diffui(repo, node1, node2, match,
823 for chunk, label in patch.diffui(repo, node1, node2, match,
824 changes, diffopts, prefix=prefix):
824 changes, diffopts, prefix=prefix):
825 write(chunk, label=label)
825 write(chunk, label=label)
826
826
827 if listsubrepos:
827 if listsubrepos:
828 ctx1 = repo[node1]
828 ctx1 = repo[node1]
829 ctx2 = repo[node2]
829 ctx2 = repo[node2]
830 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
830 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
831 tempnode2 = node2
831 tempnode2 = node2
832 try:
832 try:
833 if node2 is not None:
833 if node2 is not None:
834 tempnode2 = ctx2.substate[subpath][1]
834 tempnode2 = ctx2.substate[subpath][1]
835 except KeyError:
835 except KeyError:
836 # A subrepo that existed in node1 was deleted between node1 and
836 # A subrepo that existed in node1 was deleted between node1 and
837 # node2 (inclusive). Thus, ctx2's substate won't contain that
837 # node2 (inclusive). Thus, ctx2's substate won't contain that
838 # subpath. The best we can do is to ignore it.
838 # subpath. The best we can do is to ignore it.
839 tempnode2 = None
839 tempnode2 = None
840 submatch = matchmod.narrowmatcher(subpath, match)
840 submatch = matchmod.narrowmatcher(subpath, match)
841 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
841 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
842 stat=stat, fp=fp, prefix=prefix)
842 stat=stat, fp=fp, prefix=prefix)
843
843
844 class changeset_printer(object):
844 class changeset_printer(object):
845 '''show changeset information when templating not requested.'''
845 '''show changeset information when templating not requested.'''
846
846
847 def __init__(self, ui, repo, matchfn, diffopts, buffered):
847 def __init__(self, ui, repo, matchfn, diffopts, buffered):
848 self.ui = ui
848 self.ui = ui
849 self.repo = repo
849 self.repo = repo
850 self.buffered = buffered
850 self.buffered = buffered
851 self.matchfn = matchfn
851 self.matchfn = matchfn
852 self.diffopts = diffopts
852 self.diffopts = diffopts
853 self.header = {}
853 self.header = {}
854 self.hunk = {}
854 self.hunk = {}
855 self.lastheader = None
855 self.lastheader = None
856 self.footer = None
856 self.footer = None
857
857
858 def flush(self, rev):
858 def flush(self, rev):
859 if rev in self.header:
859 if rev in self.header:
860 h = self.header[rev]
860 h = self.header[rev]
861 if h != self.lastheader:
861 if h != self.lastheader:
862 self.lastheader = h
862 self.lastheader = h
863 self.ui.write(h)
863 self.ui.write(h)
864 del self.header[rev]
864 del self.header[rev]
865 if rev in self.hunk:
865 if rev in self.hunk:
866 self.ui.write(self.hunk[rev])
866 self.ui.write(self.hunk[rev])
867 del self.hunk[rev]
867 del self.hunk[rev]
868 return 1
868 return 1
869 return 0
869 return 0
870
870
871 def close(self):
871 def close(self):
872 if self.footer:
872 if self.footer:
873 self.ui.write(self.footer)
873 self.ui.write(self.footer)
874
874
875 def show(self, ctx, copies=None, matchfn=None, **props):
875 def show(self, ctx, copies=None, matchfn=None, **props):
876 if self.buffered:
876 if self.buffered:
877 self.ui.pushbuffer()
877 self.ui.pushbuffer()
878 self._show(ctx, copies, matchfn, props)
878 self._show(ctx, copies, matchfn, props)
879 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
879 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
880 else:
880 else:
881 self._show(ctx, copies, matchfn, props)
881 self._show(ctx, copies, matchfn, props)
882
882
883 def _show(self, ctx, copies, matchfn, props):
883 def _show(self, ctx, copies, matchfn, props):
884 '''show a single changeset or file revision'''
884 '''show a single changeset or file revision'''
885 changenode = ctx.node()
885 changenode = ctx.node()
886 rev = ctx.rev()
886 rev = ctx.rev()
887
887
888 if self.ui.quiet:
888 if self.ui.quiet:
889 self.ui.write("%d:%s\n" % (rev, short(changenode)),
889 self.ui.write("%d:%s\n" % (rev, short(changenode)),
890 label='log.node')
890 label='log.node')
891 return
891 return
892
892
893 log = self.repo.changelog
893 log = self.repo.changelog
894 date = util.datestr(ctx.date())
894 date = util.datestr(ctx.date())
895
895
896 hexfunc = self.ui.debugflag and hex or short
896 hexfunc = self.ui.debugflag and hex or short
897
897
898 parents = [(p, hexfunc(log.node(p)))
898 parents = [(p, hexfunc(log.node(p)))
899 for p in self._meaningful_parentrevs(log, rev)]
899 for p in self._meaningful_parentrevs(log, rev)]
900
900
901 # i18n: column positioning for "hg log"
901 # i18n: column positioning for "hg log"
902 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
902 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
903 label='log.changeset changeset.%s' % ctx.phasestr())
903 label='log.changeset changeset.%s' % ctx.phasestr())
904
904
905 branch = ctx.branch()
905 branch = ctx.branch()
906 # don't show the default branch name
906 # don't show the default branch name
907 if branch != 'default':
907 if branch != 'default':
908 # i18n: column positioning for "hg log"
908 # i18n: column positioning for "hg log"
909 self.ui.write(_("branch: %s\n") % branch,
909 self.ui.write(_("branch: %s\n") % branch,
910 label='log.branch')
910 label='log.branch')
911 for bookmark in self.repo.nodebookmarks(changenode):
911 for bookmark in self.repo.nodebookmarks(changenode):
912 # i18n: column positioning for "hg log"
912 # i18n: column positioning for "hg log"
913 self.ui.write(_("bookmark: %s\n") % bookmark,
913 self.ui.write(_("bookmark: %s\n") % bookmark,
914 label='log.bookmark')
914 label='log.bookmark')
915 for tag in self.repo.nodetags(changenode):
915 for tag in self.repo.nodetags(changenode):
916 # i18n: column positioning for "hg log"
916 # i18n: column positioning for "hg log"
917 self.ui.write(_("tag: %s\n") % tag,
917 self.ui.write(_("tag: %s\n") % tag,
918 label='log.tag')
918 label='log.tag')
919 if self.ui.debugflag:
919 if self.ui.debugflag:
920 # i18n: column positioning for "hg log"
920 # i18n: column positioning for "hg log"
921 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
921 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
922 label='log.phase')
922 label='log.phase')
923 for parent in parents:
923 for parent in parents:
924 label = 'log.parent changeset.%s' % self.repo[parent[0]].phasestr()
924 label = 'log.parent changeset.%s' % self.repo[parent[0]].phasestr()
925 # i18n: column positioning for "hg log"
925 # i18n: column positioning for "hg log"
926 self.ui.write(_("parent: %d:%s\n") % parent,
926 self.ui.write(_("parent: %d:%s\n") % parent,
927 label=label)
927 label=label)
928
928
929 if self.ui.debugflag:
929 if self.ui.debugflag:
930 mnode = ctx.manifestnode()
930 mnode = ctx.manifestnode()
931 # i18n: column positioning for "hg log"
931 # i18n: column positioning for "hg log"
932 self.ui.write(_("manifest: %d:%s\n") %
932 self.ui.write(_("manifest: %d:%s\n") %
933 (self.repo.manifest.rev(mnode), hex(mnode)),
933 (self.repo.manifest.rev(mnode), hex(mnode)),
934 label='ui.debug log.manifest')
934 label='ui.debug log.manifest')
935 # i18n: column positioning for "hg log"
935 # i18n: column positioning for "hg log"
936 self.ui.write(_("user: %s\n") % ctx.user(),
936 self.ui.write(_("user: %s\n") % ctx.user(),
937 label='log.user')
937 label='log.user')
938 # i18n: column positioning for "hg log"
938 # i18n: column positioning for "hg log"
939 self.ui.write(_("date: %s\n") % date,
939 self.ui.write(_("date: %s\n") % date,
940 label='log.date')
940 label='log.date')
941
941
942 if self.ui.debugflag:
942 if self.ui.debugflag:
943 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
943 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
944 for key, value in zip([# i18n: column positioning for "hg log"
944 for key, value in zip([# i18n: column positioning for "hg log"
945 _("files:"),
945 _("files:"),
946 # i18n: column positioning for "hg log"
946 # i18n: column positioning for "hg log"
947 _("files+:"),
947 _("files+:"),
948 # i18n: column positioning for "hg log"
948 # i18n: column positioning for "hg log"
949 _("files-:")], files):
949 _("files-:")], files):
950 if value:
950 if value:
951 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
951 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
952 label='ui.debug log.files')
952 label='ui.debug log.files')
953 elif ctx.files() and self.ui.verbose:
953 elif ctx.files() and self.ui.verbose:
954 # i18n: column positioning for "hg log"
954 # i18n: column positioning for "hg log"
955 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
955 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
956 label='ui.note log.files')
956 label='ui.note log.files')
957 if copies and self.ui.verbose:
957 if copies and self.ui.verbose:
958 copies = ['%s (%s)' % c for c in copies]
958 copies = ['%s (%s)' % c for c in copies]
959 # i18n: column positioning for "hg log"
959 # i18n: column positioning for "hg log"
960 self.ui.write(_("copies: %s\n") % ' '.join(copies),
960 self.ui.write(_("copies: %s\n") % ' '.join(copies),
961 label='ui.note log.copies')
961 label='ui.note log.copies')
962
962
963 extra = ctx.extra()
963 extra = ctx.extra()
964 if extra and self.ui.debugflag:
964 if extra and self.ui.debugflag:
965 for key, value in sorted(extra.items()):
965 for key, value in sorted(extra.items()):
966 # i18n: column positioning for "hg log"
966 # i18n: column positioning for "hg log"
967 self.ui.write(_("extra: %s=%s\n")
967 self.ui.write(_("extra: %s=%s\n")
968 % (key, value.encode('string_escape')),
968 % (key, value.encode('string_escape')),
969 label='ui.debug log.extra')
969 label='ui.debug log.extra')
970
970
971 description = ctx.description().strip()
971 description = ctx.description().strip()
972 if description:
972 if description:
973 if self.ui.verbose:
973 if self.ui.verbose:
974 self.ui.write(_("description:\n"),
974 self.ui.write(_("description:\n"),
975 label='ui.note log.description')
975 label='ui.note log.description')
976 self.ui.write(description,
976 self.ui.write(description,
977 label='ui.note log.description')
977 label='ui.note log.description')
978 self.ui.write("\n\n")
978 self.ui.write("\n\n")
979 else:
979 else:
980 # i18n: column positioning for "hg log"
980 # i18n: column positioning for "hg log"
981 self.ui.write(_("summary: %s\n") %
981 self.ui.write(_("summary: %s\n") %
982 description.splitlines()[0],
982 description.splitlines()[0],
983 label='log.summary')
983 label='log.summary')
984 self.ui.write("\n")
984 self.ui.write("\n")
985
985
986 self.showpatch(changenode, matchfn)
986 self.showpatch(changenode, matchfn)
987
987
988 def showpatch(self, node, matchfn):
988 def showpatch(self, node, matchfn):
989 if not matchfn:
989 if not matchfn:
990 matchfn = self.matchfn
990 matchfn = self.matchfn
991 if matchfn:
991 if matchfn:
992 stat = self.diffopts.get('stat')
992 stat = self.diffopts.get('stat')
993 diff = self.diffopts.get('patch')
993 diff = self.diffopts.get('patch')
994 diffopts = patch.diffopts(self.ui, self.diffopts)
994 diffopts = patch.diffopts(self.ui, self.diffopts)
995 prev = self.repo.changelog.parents(node)[0]
995 prev = self.repo.changelog.parents(node)[0]
996 if stat:
996 if stat:
997 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
997 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
998 match=matchfn, stat=True)
998 match=matchfn, stat=True)
999 if diff:
999 if diff:
1000 if stat:
1000 if stat:
1001 self.ui.write("\n")
1001 self.ui.write("\n")
1002 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1002 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1003 match=matchfn, stat=False)
1003 match=matchfn, stat=False)
1004 self.ui.write("\n")
1004 self.ui.write("\n")
1005
1005
1006 def _meaningful_parentrevs(self, log, rev):
1006 def _meaningful_parentrevs(self, log, rev):
1007 """Return list of meaningful (or all if debug) parentrevs for rev.
1007 """Return list of meaningful (or all if debug) parentrevs for rev.
1008
1008
1009 For merges (two non-nullrev revisions) both parents are meaningful.
1009 For merges (two non-nullrev revisions) both parents are meaningful.
1010 Otherwise the first parent revision is considered meaningful if it
1010 Otherwise the first parent revision is considered meaningful if it
1011 is not the preceding revision.
1011 is not the preceding revision.
1012 """
1012 """
1013 parents = log.parentrevs(rev)
1013 parents = log.parentrevs(rev)
1014 if not self.ui.debugflag and parents[1] == nullrev:
1014 if not self.ui.debugflag and parents[1] == nullrev:
1015 if parents[0] >= rev - 1:
1015 if parents[0] >= rev - 1:
1016 parents = []
1016 parents = []
1017 else:
1017 else:
1018 parents = [parents[0]]
1018 parents = [parents[0]]
1019 return parents
1019 return parents
1020
1020
1021 class jsonchangeset(changeset_printer):
1021 class jsonchangeset(changeset_printer):
1022 '''format changeset information.'''
1022 '''format changeset information.'''
1023
1023
1024 def __init__(self, ui, repo, matchfn, diffopts, buffered):
1024 def __init__(self, ui, repo, matchfn, diffopts, buffered):
1025 changeset_printer.__init__(self, ui, repo, matchfn, diffopts, buffered)
1025 changeset_printer.__init__(self, ui, repo, matchfn, diffopts, buffered)
1026 self.cache = {}
1026 self.cache = {}
1027 self._first = True
1027 self._first = True
1028
1028
1029 def close(self):
1029 def close(self):
1030 if not self._first:
1030 if not self._first:
1031 self.ui.write("\n]\n")
1031 self.ui.write("\n]\n")
1032 else:
1032 else:
1033 self.ui.write("[]\n")
1033 self.ui.write("[]\n")
1034
1034
1035 def _show(self, ctx, copies, matchfn, props):
1035 def _show(self, ctx, copies, matchfn, props):
1036 '''show a single changeset or file revision'''
1036 '''show a single changeset or file revision'''
1037 hexnode = hex(ctx.node())
1037 hexnode = hex(ctx.node())
1038 rev = ctx.rev()
1038 rev = ctx.rev()
1039 j = encoding.jsonescape
1039 j = encoding.jsonescape
1040
1040
1041 if self._first:
1041 if self._first:
1042 self.ui.write("[\n {")
1042 self.ui.write("[\n {")
1043 self._first = False
1043 self._first = False
1044 else:
1044 else:
1045 self.ui.write(",\n {")
1045 self.ui.write(",\n {")
1046
1046
1047 if self.ui.quiet:
1047 if self.ui.quiet:
1048 self.ui.write('\n "rev": %d' % rev)
1048 self.ui.write('\n "rev": %d' % rev)
1049 self.ui.write(',\n "node": "%s"' % hexnode)
1049 self.ui.write(',\n "node": "%s"' % hexnode)
1050 self.ui.write('\n }')
1050 self.ui.write('\n }')
1051 return
1051 return
1052
1052
1053 self.ui.write('\n "rev": %d' % rev)
1053 self.ui.write('\n "rev": %d' % rev)
1054 self.ui.write(',\n "node": "%s"' % hexnode)
1054 self.ui.write(',\n "node": "%s"' % hexnode)
1055 self.ui.write(',\n "branch": "%s"' % j(ctx.branch()))
1055 self.ui.write(',\n "branch": "%s"' % j(ctx.branch()))
1056 self.ui.write(',\n "phase": "%s"' % ctx.phasestr())
1056 self.ui.write(',\n "phase": "%s"' % ctx.phasestr())
1057 self.ui.write(',\n "user": "%s"' % j(ctx.user()))
1057 self.ui.write(',\n "user": "%s"' % j(ctx.user()))
1058 self.ui.write(',\n "date": [%d, %d]' % ctx.date())
1058 self.ui.write(',\n "date": [%d, %d]' % ctx.date())
1059 self.ui.write(',\n "desc": "%s"' % j(ctx.description()))
1059 self.ui.write(',\n "desc": "%s"' % j(ctx.description()))
1060
1060
1061 self.ui.write(',\n "bookmarks": [%s]' %
1061 self.ui.write(',\n "bookmarks": [%s]' %
1062 ", ".join('"%s"' % j(b) for b in ctx.bookmarks()))
1062 ", ".join('"%s"' % j(b) for b in ctx.bookmarks()))
1063 self.ui.write(',\n "tags": [%s]' %
1063 self.ui.write(',\n "tags": [%s]' %
1064 ", ".join('"%s"' % j(t) for t in ctx.tags()))
1064 ", ".join('"%s"' % j(t) for t in ctx.tags()))
1065 self.ui.write(',\n "parents": [%s]' %
1065 self.ui.write(',\n "parents": [%s]' %
1066 ", ".join('"%s"' % c.hex() for c in ctx.parents()))
1066 ", ".join('"%s"' % c.hex() for c in ctx.parents()))
1067
1067
1068 if self.ui.debugflag:
1068 if self.ui.debugflag:
1069 self.ui.write(',\n "manifest": "%s"' % hex(ctx.manifestnode()))
1069 self.ui.write(',\n "manifest": "%s"' % hex(ctx.manifestnode()))
1070
1070
1071 self.ui.write(',\n "extra": {%s}' %
1071 self.ui.write(',\n "extra": {%s}' %
1072 ", ".join('"%s": "%s"' % (j(k), j(v))
1072 ", ".join('"%s": "%s"' % (j(k), j(v))
1073 for k, v in ctx.extra().items()))
1073 for k, v in ctx.extra().items()))
1074
1074
1075 files = ctx.status(ctx.p1())
1075 files = ctx.status(ctx.p1())
1076 self.ui.write(',\n "modified": [%s]' %
1076 self.ui.write(',\n "modified": [%s]' %
1077 ", ".join('"%s"' % j(f) for f in files[0]))
1077 ", ".join('"%s"' % j(f) for f in files[0]))
1078 self.ui.write(',\n "added": [%s]' %
1078 self.ui.write(',\n "added": [%s]' %
1079 ", ".join('"%s"' % j(f) for f in files[1]))
1079 ", ".join('"%s"' % j(f) for f in files[1]))
1080 self.ui.write(',\n "removed": [%s]' %
1080 self.ui.write(',\n "removed": [%s]' %
1081 ", ".join('"%s"' % j(f) for f in files[2]))
1081 ", ".join('"%s"' % j(f) for f in files[2]))
1082
1082
1083 elif self.ui.verbose:
1083 elif self.ui.verbose:
1084 self.ui.write(',\n "files": [%s]' %
1084 self.ui.write(',\n "files": [%s]' %
1085 ", ".join('"%s"' % j(f) for f in ctx.files()))
1085 ", ".join('"%s"' % j(f) for f in ctx.files()))
1086
1086
1087 if copies:
1087 if copies:
1088 self.ui.write(',\n "copies": {%s}' %
1088 self.ui.write(',\n "copies": {%s}' %
1089 ", ".join('"%s": %s' % (j(k), j(copies[k]))
1089 ", ".join('"%s": %s' % (j(k), j(copies[k]))
1090 for k in copies))
1090 for k in copies))
1091
1091
1092 matchfn = self.matchfn
1092 matchfn = self.matchfn
1093 if matchfn:
1093 if matchfn:
1094 stat = self.diffopts.get('stat')
1094 stat = self.diffopts.get('stat')
1095 diff = self.diffopts.get('patch')
1095 diff = self.diffopts.get('patch')
1096 diffopts = patch.diffopts(self.ui, self.diffopts)
1096 diffopts = patch.diffopts(self.ui, self.diffopts)
1097 node, prev = ctx.node(), ctx.p1().node()
1097 node, prev = ctx.node(), ctx.p1().node()
1098 if stat:
1098 if stat:
1099 self.ui.pushbuffer()
1099 self.ui.pushbuffer()
1100 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1100 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1101 match=matchfn, stat=True)
1101 match=matchfn, stat=True)
1102 self.ui.write(',\n "diffstat": "%s"' % j(self.ui.popbuffer()))
1102 self.ui.write(',\n "diffstat": "%s"' % j(self.ui.popbuffer()))
1103 if diff:
1103 if diff:
1104 self.ui.pushbuffer()
1104 self.ui.pushbuffer()
1105 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1105 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1106 match=matchfn, stat=False)
1106 match=matchfn, stat=False)
1107 self.ui.write(',\n "diff": "%s"' % j(self.ui.popbuffer()))
1107 self.ui.write(',\n "diff": "%s"' % j(self.ui.popbuffer()))
1108
1108
1109 self.ui.write("\n }")
1109 self.ui.write("\n }")
1110
1110
1111 class changeset_templater(changeset_printer):
1111 class changeset_templater(changeset_printer):
1112 '''format changeset information.'''
1112 '''format changeset information.'''
1113
1113
1114 def __init__(self, ui, repo, matchfn, diffopts, tmpl, mapfile, buffered):
1114 def __init__(self, ui, repo, matchfn, diffopts, tmpl, mapfile, buffered):
1115 changeset_printer.__init__(self, ui, repo, matchfn, diffopts, buffered)
1115 changeset_printer.__init__(self, ui, repo, matchfn, diffopts, buffered)
1116 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
1116 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
1117 defaulttempl = {
1117 defaulttempl = {
1118 'parent': '{rev}:{node|formatnode} ',
1118 'parent': '{rev}:{node|formatnode} ',
1119 'manifest': '{rev}:{node|formatnode}',
1119 'manifest': '{rev}:{node|formatnode}',
1120 'file_copy': '{name} ({source})',
1120 'file_copy': '{name} ({source})',
1121 'extra': '{key}={value|stringescape}'
1121 'extra': '{key}={value|stringescape}'
1122 }
1122 }
1123 # filecopy is preserved for compatibility reasons
1123 # filecopy is preserved for compatibility reasons
1124 defaulttempl['filecopy'] = defaulttempl['file_copy']
1124 defaulttempl['filecopy'] = defaulttempl['file_copy']
1125 self.t = templater.templater(mapfile, {'formatnode': formatnode},
1125 self.t = templater.templater(mapfile, {'formatnode': formatnode},
1126 cache=defaulttempl)
1126 cache=defaulttempl)
1127 if tmpl:
1127 if tmpl:
1128 self.t.cache['changeset'] = tmpl
1128 self.t.cache['changeset'] = tmpl
1129
1129
1130 self.cache = {}
1130 self.cache = {}
1131
1131
1132 def _meaningful_parentrevs(self, ctx):
1132 def _meaningful_parentrevs(self, ctx):
1133 """Return list of meaningful (or all if debug) parentrevs for rev.
1133 """Return list of meaningful (or all if debug) parentrevs for rev.
1134 """
1134 """
1135 parents = ctx.parents()
1135 parents = ctx.parents()
1136 if len(parents) > 1:
1136 if len(parents) > 1:
1137 return parents
1137 return parents
1138 if self.ui.debugflag:
1138 if self.ui.debugflag:
1139 return [parents[0], self.repo['null']]
1139 return [parents[0], self.repo['null']]
1140 if parents[0].rev() >= ctx.rev() - 1:
1140 if parents[0].rev() >= ctx.rev() - 1:
1141 return []
1141 return []
1142 return parents
1142 return parents
1143
1143
1144 def _show(self, ctx, copies, matchfn, props):
1144 def _show(self, ctx, copies, matchfn, props):
1145 '''show a single changeset or file revision'''
1145 '''show a single changeset or file revision'''
1146
1146
1147 showlist = templatekw.showlist
1147 showlist = templatekw.showlist
1148
1148
1149 # showparents() behaviour depends on ui trace level which
1149 # showparents() behaviour depends on ui trace level which
1150 # causes unexpected behaviours at templating level and makes
1150 # causes unexpected behaviours at templating level and makes
1151 # it harder to extract it in a standalone function. Its
1151 # it harder to extract it in a standalone function. Its
1152 # behaviour cannot be changed so leave it here for now.
1152 # behaviour cannot be changed so leave it here for now.
1153 def showparents(**args):
1153 def showparents(**args):
1154 ctx = args['ctx']
1154 ctx = args['ctx']
1155 parents = [[('rev', p.rev()),
1155 parents = [[('rev', p.rev()),
1156 ('node', p.hex()),
1156 ('node', p.hex()),
1157 ('phase', p.phasestr())]
1157 ('phase', p.phasestr())]
1158 for p in self._meaningful_parentrevs(ctx)]
1158 for p in self._meaningful_parentrevs(ctx)]
1159 return showlist('parent', parents, **args)
1159 return showlist('parent', parents, **args)
1160
1160
1161 props = props.copy()
1161 props = props.copy()
1162 props.update(templatekw.keywords)
1162 props.update(templatekw.keywords)
1163 props['parents'] = showparents
1163 props['parents'] = showparents
1164 props['templ'] = self.t
1164 props['templ'] = self.t
1165 props['ctx'] = ctx
1165 props['ctx'] = ctx
1166 props['repo'] = self.repo
1166 props['repo'] = self.repo
1167 props['revcache'] = {'copies': copies}
1167 props['revcache'] = {'copies': copies}
1168 props['cache'] = self.cache
1168 props['cache'] = self.cache
1169
1169
1170 # find correct templates for current mode
1170 # find correct templates for current mode
1171
1171
1172 tmplmodes = [
1172 tmplmodes = [
1173 (True, None),
1173 (True, None),
1174 (self.ui.verbose, 'verbose'),
1174 (self.ui.verbose, 'verbose'),
1175 (self.ui.quiet, 'quiet'),
1175 (self.ui.quiet, 'quiet'),
1176 (self.ui.debugflag, 'debug'),
1176 (self.ui.debugflag, 'debug'),
1177 ]
1177 ]
1178
1178
1179 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
1179 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
1180 for mode, postfix in tmplmodes:
1180 for mode, postfix in tmplmodes:
1181 for type in types:
1181 for type in types:
1182 cur = postfix and ('%s_%s' % (type, postfix)) or type
1182 cur = postfix and ('%s_%s' % (type, postfix)) or type
1183 if mode and cur in self.t:
1183 if mode and cur in self.t:
1184 types[type] = cur
1184 types[type] = cur
1185
1185
1186 try:
1186 try:
1187
1187
1188 # write header
1188 # write header
1189 if types['header']:
1189 if types['header']:
1190 h = templater.stringify(self.t(types['header'], **props))
1190 h = templater.stringify(self.t(types['header'], **props))
1191 if self.buffered:
1191 if self.buffered:
1192 self.header[ctx.rev()] = h
1192 self.header[ctx.rev()] = h
1193 else:
1193 else:
1194 if self.lastheader != h:
1194 if self.lastheader != h:
1195 self.lastheader = h
1195 self.lastheader = h
1196 self.ui.write(h)
1196 self.ui.write(h)
1197
1197
1198 # write changeset metadata, then patch if requested
1198 # write changeset metadata, then patch if requested
1199 key = types['changeset']
1199 key = types['changeset']
1200 self.ui.write(templater.stringify(self.t(key, **props)))
1200 self.ui.write(templater.stringify(self.t(key, **props)))
1201 self.showpatch(ctx.node(), matchfn)
1201 self.showpatch(ctx.node(), matchfn)
1202
1202
1203 if types['footer']:
1203 if types['footer']:
1204 if not self.footer:
1204 if not self.footer:
1205 self.footer = templater.stringify(self.t(types['footer'],
1205 self.footer = templater.stringify(self.t(types['footer'],
1206 **props))
1206 **props))
1207
1207
1208 except KeyError, inst:
1208 except KeyError, inst:
1209 msg = _("%s: no key named '%s'")
1209 msg = _("%s: no key named '%s'")
1210 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
1210 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
1211 except SyntaxError, inst:
1211 except SyntaxError, inst:
1212 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
1212 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
1213
1213
1214 def gettemplate(ui, tmpl, style):
1214 def gettemplate(ui, tmpl, style):
1215 """
1215 """
1216 Find the template matching the given template spec or style.
1216 Find the template matching the given template spec or style.
1217 """
1217 """
1218
1218
1219 # ui settings
1219 # ui settings
1220 if not tmpl and not style: # template are stronger than style
1220 if not tmpl and not style: # template are stronger than style
1221 tmpl = ui.config('ui', 'logtemplate')
1221 tmpl = ui.config('ui', 'logtemplate')
1222 if tmpl:
1222 if tmpl:
1223 try:
1223 try:
1224 tmpl = templater.parsestring(tmpl)
1224 tmpl = templater.parsestring(tmpl)
1225 except SyntaxError:
1225 except SyntaxError:
1226 tmpl = templater.parsestring(tmpl, quoted=False)
1226 tmpl = templater.parsestring(tmpl, quoted=False)
1227 return tmpl, None
1227 return tmpl, None
1228 else:
1228 else:
1229 style = util.expandpath(ui.config('ui', 'style', ''))
1229 style = util.expandpath(ui.config('ui', 'style', ''))
1230
1230
1231 if not tmpl and style:
1231 if not tmpl and style:
1232 mapfile = style
1232 mapfile = style
1233 if not os.path.split(mapfile)[0]:
1233 if not os.path.split(mapfile)[0]:
1234 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1234 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1235 or templater.templatepath(mapfile))
1235 or templater.templatepath(mapfile))
1236 if mapname:
1236 if mapname:
1237 mapfile = mapname
1237 mapfile = mapname
1238 return None, mapfile
1238 return None, mapfile
1239
1239
1240 if not tmpl:
1240 if not tmpl:
1241 return None, None
1241 return None, None
1242
1242
1243 # looks like a literal template?
1243 # looks like a literal template?
1244 if '{' in tmpl:
1244 if '{' in tmpl:
1245 return tmpl, None
1245 return tmpl, None
1246
1246
1247 # perhaps a stock style?
1247 # perhaps a stock style?
1248 if not os.path.split(tmpl)[0]:
1248 if not os.path.split(tmpl)[0]:
1249 mapname = (templater.templatepath('map-cmdline.' + tmpl)
1249 mapname = (templater.templatepath('map-cmdline.' + tmpl)
1250 or templater.templatepath(tmpl))
1250 or templater.templatepath(tmpl))
1251 if mapname and os.path.isfile(mapname):
1251 if mapname and os.path.isfile(mapname):
1252 return None, mapname
1252 return None, mapname
1253
1253
1254 # perhaps it's a reference to [templates]
1254 # perhaps it's a reference to [templates]
1255 t = ui.config('templates', tmpl)
1255 t = ui.config('templates', tmpl)
1256 if t:
1256 if t:
1257 try:
1257 try:
1258 tmpl = templater.parsestring(t)
1258 tmpl = templater.parsestring(t)
1259 except SyntaxError:
1259 except SyntaxError:
1260 tmpl = templater.parsestring(t, quoted=False)
1260 tmpl = templater.parsestring(t, quoted=False)
1261 return tmpl, None
1261 return tmpl, None
1262
1262
1263 if tmpl == 'list':
1263 if tmpl == 'list':
1264 ui.write(_("available styles: %s\n") % templater.stylelist())
1264 ui.write(_("available styles: %s\n") % templater.stylelist())
1265 raise util.Abort(_("specify a template"))
1265 raise util.Abort(_("specify a template"))
1266
1266
1267 # perhaps it's a path to a map or a template
1267 # perhaps it's a path to a map or a template
1268 if ('/' in tmpl or '\\' in tmpl) and os.path.isfile(tmpl):
1268 if ('/' in tmpl or '\\' in tmpl) and os.path.isfile(tmpl):
1269 # is it a mapfile for a style?
1269 # is it a mapfile for a style?
1270 if os.path.basename(tmpl).startswith("map-"):
1270 if os.path.basename(tmpl).startswith("map-"):
1271 return None, os.path.realpath(tmpl)
1271 return None, os.path.realpath(tmpl)
1272 tmpl = open(tmpl).read()
1272 tmpl = open(tmpl).read()
1273 return tmpl, None
1273 return tmpl, None
1274
1274
1275 # constant string?
1275 # constant string?
1276 return tmpl, None
1276 return tmpl, None
1277
1277
1278 def show_changeset(ui, repo, opts, buffered=False):
1278 def show_changeset(ui, repo, opts, buffered=False):
1279 """show one changeset using template or regular display.
1279 """show one changeset using template or regular display.
1280
1280
1281 Display format will be the first non-empty hit of:
1281 Display format will be the first non-empty hit of:
1282 1. option 'template'
1282 1. option 'template'
1283 2. option 'style'
1283 2. option 'style'
1284 3. [ui] setting 'logtemplate'
1284 3. [ui] setting 'logtemplate'
1285 4. [ui] setting 'style'
1285 4. [ui] setting 'style'
1286 If all of these values are either the unset or the empty string,
1286 If all of these values are either the unset or the empty string,
1287 regular display via changeset_printer() is done.
1287 regular display via changeset_printer() is done.
1288 """
1288 """
1289 # options
1289 # options
1290 matchfn = None
1290 matchfn = None
1291 if opts.get('patch') or opts.get('stat'):
1291 if opts.get('patch') or opts.get('stat'):
1292 matchfn = scmutil.matchall(repo)
1292 matchfn = scmutil.matchall(repo)
1293
1293
1294 if opts.get('template') == 'json':
1294 if opts.get('template') == 'json':
1295 return jsonchangeset(ui, repo, matchfn, opts, buffered)
1295 return jsonchangeset(ui, repo, matchfn, opts, buffered)
1296
1296
1297 tmpl, mapfile = gettemplate(ui, opts.get('template'), opts.get('style'))
1297 tmpl, mapfile = gettemplate(ui, opts.get('template'), opts.get('style'))
1298
1298
1299 if not tmpl and not mapfile:
1299 if not tmpl and not mapfile:
1300 return changeset_printer(ui, repo, matchfn, opts, buffered)
1300 return changeset_printer(ui, repo, matchfn, opts, buffered)
1301
1301
1302 try:
1302 try:
1303 t = changeset_templater(ui, repo, matchfn, opts, tmpl, mapfile,
1303 t = changeset_templater(ui, repo, matchfn, opts, tmpl, mapfile,
1304 buffered)
1304 buffered)
1305 except SyntaxError, inst:
1305 except SyntaxError, inst:
1306 raise util.Abort(inst.args[0])
1306 raise util.Abort(inst.args[0])
1307 return t
1307 return t
1308
1308
1309 def showmarker(ui, marker):
1309 def showmarker(ui, marker):
1310 """utility function to display obsolescence marker in a readable way
1310 """utility function to display obsolescence marker in a readable way
1311
1311
1312 To be used by debug function."""
1312 To be used by debug function."""
1313 ui.write(hex(marker.precnode()))
1313 ui.write(hex(marker.precnode()))
1314 for repl in marker.succnodes():
1314 for repl in marker.succnodes():
1315 ui.write(' ')
1315 ui.write(' ')
1316 ui.write(hex(repl))
1316 ui.write(hex(repl))
1317 ui.write(' %X ' % marker.flags())
1317 ui.write(' %X ' % marker.flags())
1318 parents = marker.parentnodes()
1318 parents = marker.parentnodes()
1319 if parents is not None:
1319 if parents is not None:
1320 ui.write('{%s} ' % ', '.join(hex(p) for p in parents))
1320 ui.write('{%s} ' % ', '.join(hex(p) for p in parents))
1321 ui.write('(%s) ' % util.datestr(marker.date()))
1321 ui.write('(%s) ' % util.datestr(marker.date()))
1322 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
1322 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
1323 sorted(marker.metadata().items())
1323 sorted(marker.metadata().items())
1324 if t[0] != 'date')))
1324 if t[0] != 'date')))
1325 ui.write('\n')
1325 ui.write('\n')
1326
1326
1327 def finddate(ui, repo, date):
1327 def finddate(ui, repo, date):
1328 """Find the tipmost changeset that matches the given date spec"""
1328 """Find the tipmost changeset that matches the given date spec"""
1329
1329
1330 df = util.matchdate(date)
1330 df = util.matchdate(date)
1331 m = scmutil.matchall(repo)
1331 m = scmutil.matchall(repo)
1332 results = {}
1332 results = {}
1333
1333
1334 def prep(ctx, fns):
1334 def prep(ctx, fns):
1335 d = ctx.date()
1335 d = ctx.date()
1336 if df(d[0]):
1336 if df(d[0]):
1337 results[ctx.rev()] = d
1337 results[ctx.rev()] = d
1338
1338
1339 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1339 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1340 rev = ctx.rev()
1340 rev = ctx.rev()
1341 if rev in results:
1341 if rev in results:
1342 ui.status(_("found revision %s from %s\n") %
1342 ui.status(_("found revision %s from %s\n") %
1343 (rev, util.datestr(results[rev])))
1343 (rev, util.datestr(results[rev])))
1344 return str(rev)
1344 return str(rev)
1345
1345
1346 raise util.Abort(_("revision matching date not found"))
1346 raise util.Abort(_("revision matching date not found"))
1347
1347
1348 def increasingwindows(windowsize=8, sizelimit=512):
1348 def increasingwindows(windowsize=8, sizelimit=512):
1349 while True:
1349 while True:
1350 yield windowsize
1350 yield windowsize
1351 if windowsize < sizelimit:
1351 if windowsize < sizelimit:
1352 windowsize *= 2
1352 windowsize *= 2
1353
1353
1354 class FileWalkError(Exception):
1354 class FileWalkError(Exception):
1355 pass
1355 pass
1356
1356
1357 def walkfilerevs(repo, match, follow, revs, fncache):
1357 def walkfilerevs(repo, match, follow, revs, fncache):
1358 '''Walks the file history for the matched files.
1358 '''Walks the file history for the matched files.
1359
1359
1360 Returns the changeset revs that are involved in the file history.
1360 Returns the changeset revs that are involved in the file history.
1361
1361
1362 Throws FileWalkError if the file history can't be walked using
1362 Throws FileWalkError if the file history can't be walked using
1363 filelogs alone.
1363 filelogs alone.
1364 '''
1364 '''
1365 wanted = set()
1365 wanted = set()
1366 copies = []
1366 copies = []
1367 minrev, maxrev = min(revs), max(revs)
1367 minrev, maxrev = min(revs), max(revs)
1368 def filerevgen(filelog, last):
1368 def filerevgen(filelog, last):
1369 """
1369 """
1370 Only files, no patterns. Check the history of each file.
1370 Only files, no patterns. Check the history of each file.
1371
1371
1372 Examines filelog entries within minrev, maxrev linkrev range
1372 Examines filelog entries within minrev, maxrev linkrev range
1373 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1373 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1374 tuples in backwards order
1374 tuples in backwards order
1375 """
1375 """
1376 cl_count = len(repo)
1376 cl_count = len(repo)
1377 revs = []
1377 revs = []
1378 for j in xrange(0, last + 1):
1378 for j in xrange(0, last + 1):
1379 linkrev = filelog.linkrev(j)
1379 linkrev = filelog.linkrev(j)
1380 if linkrev < minrev:
1380 if linkrev < minrev:
1381 continue
1381 continue
1382 # only yield rev for which we have the changelog, it can
1382 # only yield rev for which we have the changelog, it can
1383 # happen while doing "hg log" during a pull or commit
1383 # happen while doing "hg log" during a pull or commit
1384 if linkrev >= cl_count:
1384 if linkrev >= cl_count:
1385 break
1385 break
1386
1386
1387 parentlinkrevs = []
1387 parentlinkrevs = []
1388 for p in filelog.parentrevs(j):
1388 for p in filelog.parentrevs(j):
1389 if p != nullrev:
1389 if p != nullrev:
1390 parentlinkrevs.append(filelog.linkrev(p))
1390 parentlinkrevs.append(filelog.linkrev(p))
1391 n = filelog.node(j)
1391 n = filelog.node(j)
1392 revs.append((linkrev, parentlinkrevs,
1392 revs.append((linkrev, parentlinkrevs,
1393 follow and filelog.renamed(n)))
1393 follow and filelog.renamed(n)))
1394
1394
1395 return reversed(revs)
1395 return reversed(revs)
1396 def iterfiles():
1396 def iterfiles():
1397 pctx = repo['.']
1397 pctx = repo['.']
1398 for filename in match.files():
1398 for filename in match.files():
1399 if follow:
1399 if follow:
1400 if filename not in pctx:
1400 if filename not in pctx:
1401 raise util.Abort(_('cannot follow file not in parent '
1401 raise util.Abort(_('cannot follow file not in parent '
1402 'revision: "%s"') % filename)
1402 'revision: "%s"') % filename)
1403 yield filename, pctx[filename].filenode()
1403 yield filename, pctx[filename].filenode()
1404 else:
1404 else:
1405 yield filename, None
1405 yield filename, None
1406 for filename_node in copies:
1406 for filename_node in copies:
1407 yield filename_node
1407 yield filename_node
1408
1408
1409 for file_, node in iterfiles():
1409 for file_, node in iterfiles():
1410 filelog = repo.file(file_)
1410 filelog = repo.file(file_)
1411 if not len(filelog):
1411 if not len(filelog):
1412 if node is None:
1412 if node is None:
1413 # A zero count may be a directory or deleted file, so
1413 # A zero count may be a directory or deleted file, so
1414 # try to find matching entries on the slow path.
1414 # try to find matching entries on the slow path.
1415 if follow:
1415 if follow:
1416 raise util.Abort(
1416 raise util.Abort(
1417 _('cannot follow nonexistent file: "%s"') % file_)
1417 _('cannot follow nonexistent file: "%s"') % file_)
1418 raise FileWalkError("Cannot walk via filelog")
1418 raise FileWalkError("Cannot walk via filelog")
1419 else:
1419 else:
1420 continue
1420 continue
1421
1421
1422 if node is None:
1422 if node is None:
1423 last = len(filelog) - 1
1423 last = len(filelog) - 1
1424 else:
1424 else:
1425 last = filelog.rev(node)
1425 last = filelog.rev(node)
1426
1426
1427
1427
1428 # keep track of all ancestors of the file
1428 # keep track of all ancestors of the file
1429 ancestors = set([filelog.linkrev(last)])
1429 ancestors = set([filelog.linkrev(last)])
1430
1430
1431 # iterate from latest to oldest revision
1431 # iterate from latest to oldest revision
1432 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1432 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1433 if not follow:
1433 if not follow:
1434 if rev > maxrev:
1434 if rev > maxrev:
1435 continue
1435 continue
1436 else:
1436 else:
1437 # Note that last might not be the first interesting
1437 # Note that last might not be the first interesting
1438 # rev to us:
1438 # rev to us:
1439 # if the file has been changed after maxrev, we'll
1439 # if the file has been changed after maxrev, we'll
1440 # have linkrev(last) > maxrev, and we still need
1440 # have linkrev(last) > maxrev, and we still need
1441 # to explore the file graph
1441 # to explore the file graph
1442 if rev not in ancestors:
1442 if rev not in ancestors:
1443 continue
1443 continue
1444 # XXX insert 1327 fix here
1444 # XXX insert 1327 fix here
1445 if flparentlinkrevs:
1445 if flparentlinkrevs:
1446 ancestors.update(flparentlinkrevs)
1446 ancestors.update(flparentlinkrevs)
1447
1447
1448 fncache.setdefault(rev, []).append(file_)
1448 fncache.setdefault(rev, []).append(file_)
1449 wanted.add(rev)
1449 wanted.add(rev)
1450 if copied:
1450 if copied:
1451 copies.append(copied)
1451 copies.append(copied)
1452
1452
1453 return wanted
1453 return wanted
1454
1454
1455 def walkchangerevs(repo, match, opts, prepare):
1455 def walkchangerevs(repo, match, opts, prepare):
1456 '''Iterate over files and the revs in which they changed.
1456 '''Iterate over files and the revs in which they changed.
1457
1457
1458 Callers most commonly need to iterate backwards over the history
1458 Callers most commonly need to iterate backwards over the history
1459 in which they are interested. Doing so has awful (quadratic-looking)
1459 in which they are interested. Doing so has awful (quadratic-looking)
1460 performance, so we use iterators in a "windowed" way.
1460 performance, so we use iterators in a "windowed" way.
1461
1461
1462 We walk a window of revisions in the desired order. Within the
1462 We walk a window of revisions in the desired order. Within the
1463 window, we first walk forwards to gather data, then in the desired
1463 window, we first walk forwards to gather data, then in the desired
1464 order (usually backwards) to display it.
1464 order (usually backwards) to display it.
1465
1465
1466 This function returns an iterator yielding contexts. Before
1466 This function returns an iterator yielding contexts. Before
1467 yielding each context, the iterator will first call the prepare
1467 yielding each context, the iterator will first call the prepare
1468 function on each context in the window in forward order.'''
1468 function on each context in the window in forward order.'''
1469
1469
1470 follow = opts.get('follow') or opts.get('follow_first')
1470 follow = opts.get('follow') or opts.get('follow_first')
1471
1471
1472 if opts.get('rev'):
1472 if opts.get('rev'):
1473 revs = scmutil.revrange(repo, opts.get('rev'))
1473 revs = scmutil.revrange(repo, opts.get('rev'))
1474 elif follow:
1474 elif follow:
1475 revs = repo.revs('reverse(:.)')
1475 revs = repo.revs('reverse(:.)')
1476 else:
1476 else:
1477 revs = revset.spanset(repo)
1477 revs = revset.spanset(repo)
1478 revs.reverse()
1478 revs.reverse()
1479 if not revs:
1479 if not revs:
1480 return []
1480 return []
1481 wanted = set()
1481 wanted = set()
1482 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1482 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1483 fncache = {}
1483 fncache = {}
1484 change = repo.changectx
1484 change = repo.changectx
1485
1485
1486 # First step is to fill wanted, the set of revisions that we want to yield.
1486 # First step is to fill wanted, the set of revisions that we want to yield.
1487 # When it does not induce extra cost, we also fill fncache for revisions in
1487 # When it does not induce extra cost, we also fill fncache for revisions in
1488 # wanted: a cache of filenames that were changed (ctx.files()) and that
1488 # wanted: a cache of filenames that were changed (ctx.files()) and that
1489 # match the file filtering conditions.
1489 # match the file filtering conditions.
1490
1490
1491 if not slowpath and not match.files():
1491 if not slowpath and not match.files():
1492 # No files, no patterns. Display all revs.
1492 # No files, no patterns. Display all revs.
1493 wanted = revs
1493 wanted = revs
1494
1494
1495 if not slowpath and match.files():
1495 if not slowpath and match.files():
1496 # We only have to read through the filelog to find wanted revisions
1496 # We only have to read through the filelog to find wanted revisions
1497
1497
1498 try:
1498 try:
1499 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1499 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1500 except FileWalkError:
1500 except FileWalkError:
1501 slowpath = True
1501 slowpath = True
1502
1502
1503 # We decided to fall back to the slowpath because at least one
1503 # We decided to fall back to the slowpath because at least one
1504 # of the paths was not a file. Check to see if at least one of them
1504 # of the paths was not a file. Check to see if at least one of them
1505 # existed in history, otherwise simply return
1505 # existed in history, otherwise simply return
1506 for path in match.files():
1506 for path in match.files():
1507 if path == '.' or path in repo.store:
1507 if path == '.' or path in repo.store:
1508 break
1508 break
1509 else:
1509 else:
1510 return []
1510 return []
1511
1511
1512 if slowpath:
1512 if slowpath:
1513 # We have to read the changelog to match filenames against
1513 # We have to read the changelog to match filenames against
1514 # changed files
1514 # changed files
1515
1515
1516 if follow:
1516 if follow:
1517 raise util.Abort(_('can only follow copies/renames for explicit '
1517 raise util.Abort(_('can only follow copies/renames for explicit '
1518 'filenames'))
1518 'filenames'))
1519
1519
1520 # The slow path checks files modified in every changeset.
1520 # The slow path checks files modified in every changeset.
1521 # This is really slow on large repos, so compute the set lazily.
1521 # This is really slow on large repos, so compute the set lazily.
1522 class lazywantedset(object):
1522 class lazywantedset(object):
1523 def __init__(self):
1523 def __init__(self):
1524 self.set = set()
1524 self.set = set()
1525 self.revs = set(revs)
1525 self.revs = set(revs)
1526
1526
1527 # No need to worry about locality here because it will be accessed
1527 # No need to worry about locality here because it will be accessed
1528 # in the same order as the increasing window below.
1528 # in the same order as the increasing window below.
1529 def __contains__(self, value):
1529 def __contains__(self, value):
1530 if value in self.set:
1530 if value in self.set:
1531 return True
1531 return True
1532 elif not value in self.revs:
1532 elif not value in self.revs:
1533 return False
1533 return False
1534 else:
1534 else:
1535 self.revs.discard(value)
1535 self.revs.discard(value)
1536 ctx = change(value)
1536 ctx = change(value)
1537 matches = filter(match, ctx.files())
1537 matches = filter(match, ctx.files())
1538 if matches:
1538 if matches:
1539 fncache[value] = matches
1539 fncache[value] = matches
1540 self.set.add(value)
1540 self.set.add(value)
1541 return True
1541 return True
1542 return False
1542 return False
1543
1543
1544 def discard(self, value):
1544 def discard(self, value):
1545 self.revs.discard(value)
1545 self.revs.discard(value)
1546 self.set.discard(value)
1546 self.set.discard(value)
1547
1547
1548 wanted = lazywantedset()
1548 wanted = lazywantedset()
1549
1549
1550 class followfilter(object):
1550 class followfilter(object):
1551 def __init__(self, onlyfirst=False):
1551 def __init__(self, onlyfirst=False):
1552 self.startrev = nullrev
1552 self.startrev = nullrev
1553 self.roots = set()
1553 self.roots = set()
1554 self.onlyfirst = onlyfirst
1554 self.onlyfirst = onlyfirst
1555
1555
1556 def match(self, rev):
1556 def match(self, rev):
1557 def realparents(rev):
1557 def realparents(rev):
1558 if self.onlyfirst:
1558 if self.onlyfirst:
1559 return repo.changelog.parentrevs(rev)[0:1]
1559 return repo.changelog.parentrevs(rev)[0:1]
1560 else:
1560 else:
1561 return filter(lambda x: x != nullrev,
1561 return filter(lambda x: x != nullrev,
1562 repo.changelog.parentrevs(rev))
1562 repo.changelog.parentrevs(rev))
1563
1563
1564 if self.startrev == nullrev:
1564 if self.startrev == nullrev:
1565 self.startrev = rev
1565 self.startrev = rev
1566 return True
1566 return True
1567
1567
1568 if rev > self.startrev:
1568 if rev > self.startrev:
1569 # forward: all descendants
1569 # forward: all descendants
1570 if not self.roots:
1570 if not self.roots:
1571 self.roots.add(self.startrev)
1571 self.roots.add(self.startrev)
1572 for parent in realparents(rev):
1572 for parent in realparents(rev):
1573 if parent in self.roots:
1573 if parent in self.roots:
1574 self.roots.add(rev)
1574 self.roots.add(rev)
1575 return True
1575 return True
1576 else:
1576 else:
1577 # backwards: all parents
1577 # backwards: all parents
1578 if not self.roots:
1578 if not self.roots:
1579 self.roots.update(realparents(self.startrev))
1579 self.roots.update(realparents(self.startrev))
1580 if rev in self.roots:
1580 if rev in self.roots:
1581 self.roots.remove(rev)
1581 self.roots.remove(rev)
1582 self.roots.update(realparents(rev))
1582 self.roots.update(realparents(rev))
1583 return True
1583 return True
1584
1584
1585 return False
1585 return False
1586
1586
1587 # it might be worthwhile to do this in the iterator if the rev range
1587 # it might be worthwhile to do this in the iterator if the rev range
1588 # is descending and the prune args are all within that range
1588 # is descending and the prune args are all within that range
1589 for rev in opts.get('prune', ()):
1589 for rev in opts.get('prune', ()):
1590 rev = repo[rev].rev()
1590 rev = repo[rev].rev()
1591 ff = followfilter()
1591 ff = followfilter()
1592 stop = min(revs[0], revs[-1])
1592 stop = min(revs[0], revs[-1])
1593 for x in xrange(rev, stop - 1, -1):
1593 for x in xrange(rev, stop - 1, -1):
1594 if ff.match(x):
1594 if ff.match(x):
1595 wanted = wanted - [x]
1595 wanted = wanted - [x]
1596
1596
1597 # Now that wanted is correctly initialized, we can iterate over the
1597 # Now that wanted is correctly initialized, we can iterate over the
1598 # revision range, yielding only revisions in wanted.
1598 # revision range, yielding only revisions in wanted.
1599 def iterate():
1599 def iterate():
1600 if follow and not match.files():
1600 if follow and not match.files():
1601 ff = followfilter(onlyfirst=opts.get('follow_first'))
1601 ff = followfilter(onlyfirst=opts.get('follow_first'))
1602 def want(rev):
1602 def want(rev):
1603 return ff.match(rev) and rev in wanted
1603 return ff.match(rev) and rev in wanted
1604 else:
1604 else:
1605 def want(rev):
1605 def want(rev):
1606 return rev in wanted
1606 return rev in wanted
1607
1607
1608 it = iter(revs)
1608 it = iter(revs)
1609 stopiteration = False
1609 stopiteration = False
1610 for windowsize in increasingwindows():
1610 for windowsize in increasingwindows():
1611 nrevs = []
1611 nrevs = []
1612 for i in xrange(windowsize):
1612 for i in xrange(windowsize):
1613 try:
1613 try:
1614 rev = it.next()
1614 rev = it.next()
1615 if want(rev):
1615 if want(rev):
1616 nrevs.append(rev)
1616 nrevs.append(rev)
1617 except (StopIteration):
1617 except (StopIteration):
1618 stopiteration = True
1618 stopiteration = True
1619 break
1619 break
1620 for rev in sorted(nrevs):
1620 for rev in sorted(nrevs):
1621 fns = fncache.get(rev)
1621 fns = fncache.get(rev)
1622 ctx = change(rev)
1622 ctx = change(rev)
1623 if not fns:
1623 if not fns:
1624 def fns_generator():
1624 def fns_generator():
1625 for f in ctx.files():
1625 for f in ctx.files():
1626 if match(f):
1626 if match(f):
1627 yield f
1627 yield f
1628 fns = fns_generator()
1628 fns = fns_generator()
1629 prepare(ctx, fns)
1629 prepare(ctx, fns)
1630 for rev in nrevs:
1630 for rev in nrevs:
1631 yield change(rev)
1631 yield change(rev)
1632
1632
1633 if stopiteration:
1633 if stopiteration:
1634 break
1634 break
1635
1635
1636 return iterate()
1636 return iterate()
1637
1637
1638 def _makefollowlogfilematcher(repo, files, followfirst):
1638 def _makefollowlogfilematcher(repo, files, followfirst):
1639 # When displaying a revision with --patch --follow FILE, we have
1639 # When displaying a revision with --patch --follow FILE, we have
1640 # to know which file of the revision must be diffed. With
1640 # to know which file of the revision must be diffed. With
1641 # --follow, we want the names of the ancestors of FILE in the
1641 # --follow, we want the names of the ancestors of FILE in the
1642 # revision, stored in "fcache". "fcache" is populated by
1642 # revision, stored in "fcache". "fcache" is populated by
1643 # reproducing the graph traversal already done by --follow revset
1643 # reproducing the graph traversal already done by --follow revset
1644 # and relating linkrevs to file names (which is not "correct" but
1644 # and relating linkrevs to file names (which is not "correct" but
1645 # good enough).
1645 # good enough).
1646 fcache = {}
1646 fcache = {}
1647 fcacheready = [False]
1647 fcacheready = [False]
1648 pctx = repo['.']
1648 pctx = repo['.']
1649
1649
1650 def populate():
1650 def populate():
1651 for fn in files:
1651 for fn in files:
1652 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1652 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1653 for c in i:
1653 for c in i:
1654 fcache.setdefault(c.linkrev(), set()).add(c.path())
1654 fcache.setdefault(c.linkrev(), set()).add(c.path())
1655
1655
1656 def filematcher(rev):
1656 def filematcher(rev):
1657 if not fcacheready[0]:
1657 if not fcacheready[0]:
1658 # Lazy initialization
1658 # Lazy initialization
1659 fcacheready[0] = True
1659 fcacheready[0] = True
1660 populate()
1660 populate()
1661 return scmutil.matchfiles(repo, fcache.get(rev, []))
1661 return scmutil.matchfiles(repo, fcache.get(rev, []))
1662
1662
1663 return filematcher
1663 return filematcher
1664
1664
1665 def _makenofollowlogfilematcher(repo, pats, opts):
1665 def _makenofollowlogfilematcher(repo, pats, opts):
1666 '''hook for extensions to override the filematcher for non-follow cases'''
1666 '''hook for extensions to override the filematcher for non-follow cases'''
1667 return None
1667 return None
1668
1668
1669 def _makelogrevset(repo, pats, opts, revs):
1669 def _makelogrevset(repo, pats, opts, revs):
1670 """Return (expr, filematcher) where expr is a revset string built
1670 """Return (expr, filematcher) where expr is a revset string built
1671 from log options and file patterns or None. If --stat or --patch
1671 from log options and file patterns or None. If --stat or --patch
1672 are not passed filematcher is None. Otherwise it is a callable
1672 are not passed filematcher is None. Otherwise it is a callable
1673 taking a revision number and returning a match objects filtering
1673 taking a revision number and returning a match objects filtering
1674 the files to be detailed when displaying the revision.
1674 the files to be detailed when displaying the revision.
1675 """
1675 """
1676 opt2revset = {
1676 opt2revset = {
1677 'no_merges': ('not merge()', None),
1677 'no_merges': ('not merge()', None),
1678 'only_merges': ('merge()', None),
1678 'only_merges': ('merge()', None),
1679 '_ancestors': ('ancestors(%(val)s)', None),
1679 '_ancestors': ('ancestors(%(val)s)', None),
1680 '_fancestors': ('_firstancestors(%(val)s)', None),
1680 '_fancestors': ('_firstancestors(%(val)s)', None),
1681 '_descendants': ('descendants(%(val)s)', None),
1681 '_descendants': ('descendants(%(val)s)', None),
1682 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1682 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1683 '_matchfiles': ('_matchfiles(%(val)s)', None),
1683 '_matchfiles': ('_matchfiles(%(val)s)', None),
1684 'date': ('date(%(val)r)', None),
1684 'date': ('date(%(val)r)', None),
1685 'branch': ('branch(%(val)r)', ' or '),
1685 'branch': ('branch(%(val)r)', ' or '),
1686 '_patslog': ('filelog(%(val)r)', ' or '),
1686 '_patslog': ('filelog(%(val)r)', ' or '),
1687 '_patsfollow': ('follow(%(val)r)', ' or '),
1687 '_patsfollow': ('follow(%(val)r)', ' or '),
1688 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1688 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1689 'keyword': ('keyword(%(val)r)', ' or '),
1689 'keyword': ('keyword(%(val)r)', ' or '),
1690 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1690 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1691 'user': ('user(%(val)r)', ' or '),
1691 'user': ('user(%(val)r)', ' or '),
1692 }
1692 }
1693
1693
1694 opts = dict(opts)
1694 opts = dict(opts)
1695 # follow or not follow?
1695 # follow or not follow?
1696 follow = opts.get('follow') or opts.get('follow_first')
1696 follow = opts.get('follow') or opts.get('follow_first')
1697 followfirst = opts.get('follow_first') and 1 or 0
1697 followfirst = opts.get('follow_first') and 1 or 0
1698 # --follow with FILE behaviour depends on revs...
1698 # --follow with FILE behaviour depends on revs...
1699 it = iter(revs)
1699 it = iter(revs)
1700 startrev = it.next()
1700 startrev = it.next()
1701 try:
1701 try:
1702 followdescendants = startrev < it.next()
1702 followdescendants = startrev < it.next()
1703 except (StopIteration):
1703 except (StopIteration):
1704 followdescendants = False
1704 followdescendants = False
1705
1705
1706 # branch and only_branch are really aliases and must be handled at
1706 # branch and only_branch are really aliases and must be handled at
1707 # the same time
1707 # the same time
1708 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1708 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1709 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1709 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1710 # pats/include/exclude are passed to match.match() directly in
1710 # pats/include/exclude are passed to match.match() directly in
1711 # _matchfiles() revset but walkchangerevs() builds its matcher with
1711 # _matchfiles() revset but walkchangerevs() builds its matcher with
1712 # scmutil.match(). The difference is input pats are globbed on
1712 # scmutil.match(). The difference is input pats are globbed on
1713 # platforms without shell expansion (windows).
1713 # platforms without shell expansion (windows).
1714 pctx = repo[None]
1714 pctx = repo[None]
1715 match, pats = scmutil.matchandpats(pctx, pats, opts)
1715 match, pats = scmutil.matchandpats(pctx, pats, opts)
1716 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1716 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1717 if not slowpath:
1717 if not slowpath:
1718 for f in match.files():
1718 for f in match.files():
1719 if follow and f not in pctx:
1719 if follow and f not in pctx:
1720 # If the file exists, it may be a directory, so let it
1720 # If the file exists, it may be a directory, so let it
1721 # take the slow path.
1721 # take the slow path.
1722 if os.path.exists(repo.wjoin(f)):
1722 if os.path.exists(repo.wjoin(f)):
1723 slowpath = True
1723 slowpath = True
1724 continue
1724 continue
1725 else:
1725 else:
1726 raise util.Abort(_('cannot follow file not in parent '
1726 raise util.Abort(_('cannot follow file not in parent '
1727 'revision: "%s"') % f)
1727 'revision: "%s"') % f)
1728 filelog = repo.file(f)
1728 filelog = repo.file(f)
1729 if not filelog:
1729 if not filelog:
1730 # A zero count may be a directory or deleted file, so
1730 # A zero count may be a directory or deleted file, so
1731 # try to find matching entries on the slow path.
1731 # try to find matching entries on the slow path.
1732 if follow:
1732 if follow:
1733 raise util.Abort(
1733 raise util.Abort(
1734 _('cannot follow nonexistent file: "%s"') % f)
1734 _('cannot follow nonexistent file: "%s"') % f)
1735 slowpath = True
1735 slowpath = True
1736
1736
1737 # We decided to fall back to the slowpath because at least one
1737 # We decided to fall back to the slowpath because at least one
1738 # of the paths was not a file. Check to see if at least one of them
1738 # of the paths was not a file. Check to see if at least one of them
1739 # existed in history - in that case, we'll continue down the
1739 # existed in history - in that case, we'll continue down the
1740 # slowpath; otherwise, we can turn off the slowpath
1740 # slowpath; otherwise, we can turn off the slowpath
1741 if slowpath:
1741 if slowpath:
1742 for path in match.files():
1742 for path in match.files():
1743 if path == '.' or path in repo.store:
1743 if path == '.' or path in repo.store:
1744 break
1744 break
1745 else:
1745 else:
1746 slowpath = False
1746 slowpath = False
1747
1747
1748 if slowpath:
1748 if slowpath:
1749 # See walkchangerevs() slow path.
1749 # See walkchangerevs() slow path.
1750 #
1750 #
1751 # pats/include/exclude cannot be represented as separate
1751 # pats/include/exclude cannot be represented as separate
1752 # revset expressions as their filtering logic applies at file
1752 # revset expressions as their filtering logic applies at file
1753 # level. For instance "-I a -X a" matches a revision touching
1753 # level. For instance "-I a -X a" matches a revision touching
1754 # "a" and "b" while "file(a) and not file(b)" does
1754 # "a" and "b" while "file(a) and not file(b)" does
1755 # not. Besides, filesets are evaluated against the working
1755 # not. Besides, filesets are evaluated against the working
1756 # directory.
1756 # directory.
1757 matchargs = ['r:', 'd:relpath']
1757 matchargs = ['r:', 'd:relpath']
1758 for p in pats:
1758 for p in pats:
1759 matchargs.append('p:' + p)
1759 matchargs.append('p:' + p)
1760 for p in opts.get('include', []):
1760 for p in opts.get('include', []):
1761 matchargs.append('i:' + p)
1761 matchargs.append('i:' + p)
1762 for p in opts.get('exclude', []):
1762 for p in opts.get('exclude', []):
1763 matchargs.append('x:' + p)
1763 matchargs.append('x:' + p)
1764 matchargs = ','.join(('%r' % p) for p in matchargs)
1764 matchargs = ','.join(('%r' % p) for p in matchargs)
1765 opts['_matchfiles'] = matchargs
1765 opts['_matchfiles'] = matchargs
1766 else:
1766 else:
1767 if follow:
1767 if follow:
1768 fpats = ('_patsfollow', '_patsfollowfirst')
1768 fpats = ('_patsfollow', '_patsfollowfirst')
1769 fnopats = (('_ancestors', '_fancestors'),
1769 fnopats = (('_ancestors', '_fancestors'),
1770 ('_descendants', '_fdescendants'))
1770 ('_descendants', '_fdescendants'))
1771 if pats:
1771 if pats:
1772 # follow() revset interprets its file argument as a
1772 # follow() revset interprets its file argument as a
1773 # manifest entry, so use match.files(), not pats.
1773 # manifest entry, so use match.files(), not pats.
1774 opts[fpats[followfirst]] = list(match.files())
1774 opts[fpats[followfirst]] = list(match.files())
1775 else:
1775 else:
1776 opts[fnopats[followdescendants][followfirst]] = str(startrev)
1776 opts[fnopats[followdescendants][followfirst]] = str(startrev)
1777 else:
1777 else:
1778 opts['_patslog'] = list(pats)
1778 opts['_patslog'] = list(pats)
1779
1779
1780 filematcher = None
1780 filematcher = None
1781 if opts.get('patch') or opts.get('stat'):
1781 if opts.get('patch') or opts.get('stat'):
1782 # When following files, track renames via a special matcher.
1782 # When following files, track renames via a special matcher.
1783 # If we're forced to take the slowpath it means we're following
1783 # If we're forced to take the slowpath it means we're following
1784 # at least one pattern/directory, so don't bother with rename tracking.
1784 # at least one pattern/directory, so don't bother with rename tracking.
1785 if follow and not match.always() and not slowpath:
1785 if follow and not match.always() and not slowpath:
1786 # _makefollowlogfilematcher expects its files argument to be
1786 # _makefollowlogfilematcher expects its files argument to be
1787 # relative to the repo root, so use match.files(), not pats.
1787 # relative to the repo root, so use match.files(), not pats.
1788 filematcher = _makefollowlogfilematcher(repo, match.files(),
1788 filematcher = _makefollowlogfilematcher(repo, match.files(),
1789 followfirst)
1789 followfirst)
1790 else:
1790 else:
1791 filematcher = _makenofollowlogfilematcher(repo, pats, opts)
1791 filematcher = _makenofollowlogfilematcher(repo, pats, opts)
1792 if filematcher is None:
1792 if filematcher is None:
1793 filematcher = lambda rev: match
1793 filematcher = lambda rev: match
1794
1794
1795 expr = []
1795 expr = []
1796 for op, val in opts.iteritems():
1796 for op, val in opts.iteritems():
1797 if not val:
1797 if not val:
1798 continue
1798 continue
1799 if op not in opt2revset:
1799 if op not in opt2revset:
1800 continue
1800 continue
1801 revop, andor = opt2revset[op]
1801 revop, andor = opt2revset[op]
1802 if '%(val)' not in revop:
1802 if '%(val)' not in revop:
1803 expr.append(revop)
1803 expr.append(revop)
1804 else:
1804 else:
1805 if not isinstance(val, list):
1805 if not isinstance(val, list):
1806 e = revop % {'val': val}
1806 e = revop % {'val': val}
1807 else:
1807 else:
1808 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1808 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1809 expr.append(e)
1809 expr.append(e)
1810
1810
1811 if expr:
1811 if expr:
1812 expr = '(' + ' and '.join(expr) + ')'
1812 expr = '(' + ' and '.join(expr) + ')'
1813 else:
1813 else:
1814 expr = None
1814 expr = None
1815 return expr, filematcher
1815 return expr, filematcher
1816
1816
1817 def getgraphlogrevs(repo, pats, opts):
1817 def getgraphlogrevs(repo, pats, opts):
1818 """Return (revs, expr, filematcher) where revs is an iterable of
1818 """Return (revs, expr, filematcher) where revs is an iterable of
1819 revision numbers, expr is a revset string built from log options
1819 revision numbers, expr is a revset string built from log options
1820 and file patterns or None, and used to filter 'revs'. If --stat or
1820 and file patterns or None, and used to filter 'revs'. If --stat or
1821 --patch are not passed filematcher is None. Otherwise it is a
1821 --patch are not passed filematcher is None. Otherwise it is a
1822 callable taking a revision number and returning a match objects
1822 callable taking a revision number and returning a match objects
1823 filtering the files to be detailed when displaying the revision.
1823 filtering the files to be detailed when displaying the revision.
1824 """
1824 """
1825 if not len(repo):
1825 if not len(repo):
1826 return [], None, None
1826 return [], None, None
1827 limit = loglimit(opts)
1827 limit = loglimit(opts)
1828 # Default --rev value depends on --follow but --follow behaviour
1828 # Default --rev value depends on --follow but --follow behaviour
1829 # depends on revisions resolved from --rev...
1829 # depends on revisions resolved from --rev...
1830 follow = opts.get('follow') or opts.get('follow_first')
1830 follow = opts.get('follow') or opts.get('follow_first')
1831 possiblyunsorted = False # whether revs might need sorting
1831 possiblyunsorted = False # whether revs might need sorting
1832 if opts.get('rev'):
1832 if opts.get('rev'):
1833 revs = scmutil.revrange(repo, opts['rev'])
1833 revs = scmutil.revrange(repo, opts['rev'])
1834 # Don't sort here because _makelogrevset might depend on the
1834 # Don't sort here because _makelogrevset might depend on the
1835 # order of revs
1835 # order of revs
1836 possiblyunsorted = True
1836 possiblyunsorted = True
1837 else:
1837 else:
1838 if follow and len(repo) > 0:
1838 if follow and len(repo) > 0:
1839 revs = repo.revs('reverse(:.)')
1839 revs = repo.revs('reverse(:.)')
1840 else:
1840 else:
1841 revs = revset.spanset(repo)
1841 revs = revset.spanset(repo)
1842 revs.reverse()
1842 revs.reverse()
1843 if not revs:
1843 if not revs:
1844 return revset.baseset(), None, None
1844 return revset.baseset(), None, None
1845 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
1845 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
1846 if possiblyunsorted:
1846 if possiblyunsorted:
1847 revs.sort(reverse=True)
1847 revs.sort(reverse=True)
1848 if expr:
1848 if expr:
1849 # Revset matchers often operate faster on revisions in changelog
1849 # Revset matchers often operate faster on revisions in changelog
1850 # order, because most filters deal with the changelog.
1850 # order, because most filters deal with the changelog.
1851 revs.reverse()
1851 revs.reverse()
1852 matcher = revset.match(repo.ui, expr)
1852 matcher = revset.match(repo.ui, expr)
1853 # Revset matches can reorder revisions. "A or B" typically returns
1853 # Revset matches can reorder revisions. "A or B" typically returns
1854 # returns the revision matching A then the revision matching B. Sort
1854 # returns the revision matching A then the revision matching B. Sort
1855 # again to fix that.
1855 # again to fix that.
1856 revs = matcher(repo, revs)
1856 revs = matcher(repo, revs)
1857 revs.sort(reverse=True)
1857 revs.sort(reverse=True)
1858 if limit is not None:
1858 if limit is not None:
1859 limitedrevs = []
1859 limitedrevs = []
1860 for idx, rev in enumerate(revs):
1860 for idx, rev in enumerate(revs):
1861 if idx >= limit:
1861 if idx >= limit:
1862 break
1862 break
1863 limitedrevs.append(rev)
1863 limitedrevs.append(rev)
1864 revs = revset.baseset(limitedrevs)
1864 revs = revset.baseset(limitedrevs)
1865
1865
1866 return revs, expr, filematcher
1866 return revs, expr, filematcher
1867
1867
1868 def getlogrevs(repo, pats, opts):
1868 def getlogrevs(repo, pats, opts):
1869 """Return (revs, expr, filematcher) where revs is an iterable of
1869 """Return (revs, expr, filematcher) where revs is an iterable of
1870 revision numbers, expr is a revset string built from log options
1870 revision numbers, expr is a revset string built from log options
1871 and file patterns or None, and used to filter 'revs'. If --stat or
1871 and file patterns or None, and used to filter 'revs'. If --stat or
1872 --patch are not passed filematcher is None. Otherwise it is a
1872 --patch are not passed filematcher is None. Otherwise it is a
1873 callable taking a revision number and returning a match objects
1873 callable taking a revision number and returning a match objects
1874 filtering the files to be detailed when displaying the revision.
1874 filtering the files to be detailed when displaying the revision.
1875 """
1875 """
1876 limit = loglimit(opts)
1876 limit = loglimit(opts)
1877 # Default --rev value depends on --follow but --follow behaviour
1877 # Default --rev value depends on --follow but --follow behaviour
1878 # depends on revisions resolved from --rev...
1878 # depends on revisions resolved from --rev...
1879 follow = opts.get('follow') or opts.get('follow_first')
1879 follow = opts.get('follow') or opts.get('follow_first')
1880 if opts.get('rev'):
1880 if opts.get('rev'):
1881 revs = scmutil.revrange(repo, opts['rev'])
1881 revs = scmutil.revrange(repo, opts['rev'])
1882 elif follow:
1882 elif follow:
1883 revs = repo.revs('reverse(:.)')
1883 revs = repo.revs('reverse(:.)')
1884 else:
1884 else:
1885 revs = revset.spanset(repo)
1885 revs = revset.spanset(repo)
1886 revs.reverse()
1886 revs.reverse()
1887 if not revs:
1887 if not revs:
1888 return revset.baseset([]), None, None
1888 return revset.baseset([]), None, None
1889 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
1889 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
1890 if expr:
1890 if expr:
1891 # Revset matchers often operate faster on revisions in changelog
1891 # Revset matchers often operate faster on revisions in changelog
1892 # order, because most filters deal with the changelog.
1892 # order, because most filters deal with the changelog.
1893 if not opts.get('rev'):
1893 if not opts.get('rev'):
1894 revs.reverse()
1894 revs.reverse()
1895 matcher = revset.match(repo.ui, expr)
1895 matcher = revset.match(repo.ui, expr)
1896 # Revset matches can reorder revisions. "A or B" typically returns
1896 # Revset matches can reorder revisions. "A or B" typically returns
1897 # returns the revision matching A then the revision matching B. Sort
1897 # returns the revision matching A then the revision matching B. Sort
1898 # again to fix that.
1898 # again to fix that.
1899 revs = matcher(repo, revs)
1899 revs = matcher(repo, revs)
1900 if not opts.get('rev'):
1900 if not opts.get('rev'):
1901 revs.sort(reverse=True)
1901 revs.sort(reverse=True)
1902 if limit is not None:
1902 if limit is not None:
1903 count = 0
1903 count = 0
1904 limitedrevs = []
1904 limitedrevs = []
1905 it = iter(revs)
1905 it = iter(revs)
1906 while count < limit:
1906 while count < limit:
1907 try:
1907 try:
1908 limitedrevs.append(it.next())
1908 limitedrevs.append(it.next())
1909 except (StopIteration):
1909 except (StopIteration):
1910 break
1910 break
1911 count += 1
1911 count += 1
1912 revs = revset.baseset(limitedrevs)
1912 revs = revset.baseset(limitedrevs)
1913
1913
1914 return revs, expr, filematcher
1914 return revs, expr, filematcher
1915
1915
1916 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
1916 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
1917 filematcher=None):
1917 filematcher=None):
1918 seen, state = [], graphmod.asciistate()
1918 seen, state = [], graphmod.asciistate()
1919 for rev, type, ctx, parents in dag:
1919 for rev, type, ctx, parents in dag:
1920 char = 'o'
1920 char = 'o'
1921 if ctx.node() in showparents:
1921 if ctx.node() in showparents:
1922 char = '@'
1922 char = '@'
1923 elif ctx.obsolete():
1923 elif ctx.obsolete():
1924 char = 'x'
1924 char = 'x'
1925 copies = None
1925 copies = None
1926 if getrenamed and ctx.rev():
1926 if getrenamed and ctx.rev():
1927 copies = []
1927 copies = []
1928 for fn in ctx.files():
1928 for fn in ctx.files():
1929 rename = getrenamed(fn, ctx.rev())
1929 rename = getrenamed(fn, ctx.rev())
1930 if rename:
1930 if rename:
1931 copies.append((fn, rename[0]))
1931 copies.append((fn, rename[0]))
1932 revmatchfn = None
1932 revmatchfn = None
1933 if filematcher is not None:
1933 if filematcher is not None:
1934 revmatchfn = filematcher(ctx.rev())
1934 revmatchfn = filematcher(ctx.rev())
1935 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
1935 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
1936 lines = displayer.hunk.pop(rev).split('\n')
1936 lines = displayer.hunk.pop(rev).split('\n')
1937 if not lines[-1]:
1937 if not lines[-1]:
1938 del lines[-1]
1938 del lines[-1]
1939 displayer.flush(rev)
1939 displayer.flush(rev)
1940 edges = edgefn(type, char, lines, seen, rev, parents)
1940 edges = edgefn(type, char, lines, seen, rev, parents)
1941 for type, char, lines, coldata in edges:
1941 for type, char, lines, coldata in edges:
1942 graphmod.ascii(ui, state, type, char, lines, coldata)
1942 graphmod.ascii(ui, state, type, char, lines, coldata)
1943 displayer.close()
1943 displayer.close()
1944
1944
1945 def graphlog(ui, repo, *pats, **opts):
1945 def graphlog(ui, repo, *pats, **opts):
1946 # Parameters are identical to log command ones
1946 # Parameters are identical to log command ones
1947 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
1947 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
1948 revdag = graphmod.dagwalker(repo, revs)
1948 revdag = graphmod.dagwalker(repo, revs)
1949
1949
1950 getrenamed = None
1950 getrenamed = None
1951 if opts.get('copies'):
1951 if opts.get('copies'):
1952 endrev = None
1952 endrev = None
1953 if opts.get('rev'):
1953 if opts.get('rev'):
1954 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
1954 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
1955 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
1955 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
1956 displayer = show_changeset(ui, repo, opts, buffered=True)
1956 displayer = show_changeset(ui, repo, opts, buffered=True)
1957 showparents = [ctx.node() for ctx in repo[None].parents()]
1957 showparents = [ctx.node() for ctx in repo[None].parents()]
1958 displaygraph(ui, revdag, displayer, showparents,
1958 displaygraph(ui, revdag, displayer, showparents,
1959 graphmod.asciiedges, getrenamed, filematcher)
1959 graphmod.asciiedges, getrenamed, filematcher)
1960
1960
1961 def checkunsupportedgraphflags(pats, opts):
1961 def checkunsupportedgraphflags(pats, opts):
1962 for op in ["newest_first"]:
1962 for op in ["newest_first"]:
1963 if op in opts and opts[op]:
1963 if op in opts and opts[op]:
1964 raise util.Abort(_("-G/--graph option is incompatible with --%s")
1964 raise util.Abort(_("-G/--graph option is incompatible with --%s")
1965 % op.replace("_", "-"))
1965 % op.replace("_", "-"))
1966
1966
1967 def graphrevs(repo, nodes, opts):
1967 def graphrevs(repo, nodes, opts):
1968 limit = loglimit(opts)
1968 limit = loglimit(opts)
1969 nodes.reverse()
1969 nodes.reverse()
1970 if limit is not None:
1970 if limit is not None:
1971 nodes = nodes[:limit]
1971 nodes = nodes[:limit]
1972 return graphmod.nodes(repo, nodes)
1972 return graphmod.nodes(repo, nodes)
1973
1973
1974 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1974 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1975 join = lambda f: os.path.join(prefix, f)
1975 join = lambda f: os.path.join(prefix, f)
1976 bad = []
1976 bad = []
1977 oldbad = match.bad
1977 oldbad = match.bad
1978 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1978 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1979 names = []
1979 names = []
1980 wctx = repo[None]
1980 wctx = repo[None]
1981 cca = None
1981 cca = None
1982 abort, warn = scmutil.checkportabilityalert(ui)
1982 abort, warn = scmutil.checkportabilityalert(ui)
1983 if abort or warn:
1983 if abort or warn:
1984 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
1984 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
1985 for f in wctx.walk(match):
1985 for f in wctx.walk(match):
1986 exact = match.exact(f)
1986 exact = match.exact(f)
1987 if exact or not explicitonly and f not in wctx:
1987 if exact or not explicitonly and f not in wctx:
1988 if cca:
1988 if cca:
1989 cca(f)
1989 cca(f)
1990 names.append(f)
1990 names.append(f)
1991 if ui.verbose or not exact:
1991 if ui.verbose or not exact:
1992 ui.status(_('adding %s\n') % match.rel(join(f)))
1992 ui.status(_('adding %s\n') % match.rel(join(f)))
1993
1993
1994 for subpath in sorted(wctx.substate):
1994 for subpath in sorted(wctx.substate):
1995 sub = wctx.sub(subpath)
1995 sub = wctx.sub(subpath)
1996 try:
1996 try:
1997 submatch = matchmod.narrowmatcher(subpath, match)
1997 submatch = matchmod.narrowmatcher(subpath, match)
1998 if listsubrepos:
1998 if listsubrepos:
1999 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1999 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
2000 False))
2000 False))
2001 else:
2001 else:
2002 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
2002 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
2003 True))
2003 True))
2004 except error.LookupError:
2004 except error.LookupError:
2005 ui.status(_("skipping missing subrepository: %s\n")
2005 ui.status(_("skipping missing subrepository: %s\n")
2006 % join(subpath))
2006 % join(subpath))
2007
2007
2008 if not dryrun:
2008 if not dryrun:
2009 rejected = wctx.add(names, prefix)
2009 rejected = wctx.add(names, prefix)
2010 bad.extend(f for f in rejected if f in match.files())
2010 bad.extend(f for f in rejected if f in match.files())
2011 return bad
2011 return bad
2012
2012
2013 def forget(ui, repo, match, prefix, explicitonly):
2013 def forget(ui, repo, match, prefix, explicitonly):
2014 join = lambda f: os.path.join(prefix, f)
2014 join = lambda f: os.path.join(prefix, f)
2015 bad = []
2015 bad = []
2016 oldbad = match.bad
2016 oldbad = match.bad
2017 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
2017 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
2018 wctx = repo[None]
2018 wctx = repo[None]
2019 forgot = []
2019 forgot = []
2020 s = repo.status(match=match, clean=True)
2020 s = repo.status(match=match, clean=True)
2021 forget = sorted(s[0] + s[1] + s[3] + s[6])
2021 forget = sorted(s[0] + s[1] + s[3] + s[6])
2022 if explicitonly:
2022 if explicitonly:
2023 forget = [f for f in forget if match.exact(f)]
2023 forget = [f for f in forget if match.exact(f)]
2024
2024
2025 for subpath in sorted(wctx.substate):
2025 for subpath in sorted(wctx.substate):
2026 sub = wctx.sub(subpath)
2026 sub = wctx.sub(subpath)
2027 try:
2027 try:
2028 submatch = matchmod.narrowmatcher(subpath, match)
2028 submatch = matchmod.narrowmatcher(subpath, match)
2029 subbad, subforgot = sub.forget(ui, submatch, prefix)
2029 subbad, subforgot = sub.forget(ui, submatch, prefix)
2030 bad.extend([subpath + '/' + f for f in subbad])
2030 bad.extend([subpath + '/' + f for f in subbad])
2031 forgot.extend([subpath + '/' + f for f in subforgot])
2031 forgot.extend([subpath + '/' + f for f in subforgot])
2032 except error.LookupError:
2032 except error.LookupError:
2033 ui.status(_("skipping missing subrepository: %s\n")
2033 ui.status(_("skipping missing subrepository: %s\n")
2034 % join(subpath))
2034 % join(subpath))
2035
2035
2036 if not explicitonly:
2036 if not explicitonly:
2037 for f in match.files():
2037 for f in match.files():
2038 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
2038 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
2039 if f not in forgot:
2039 if f not in forgot:
2040 if os.path.exists(match.rel(join(f))):
2040 if os.path.exists(match.rel(join(f))):
2041 ui.warn(_('not removing %s: '
2041 ui.warn(_('not removing %s: '
2042 'file is already untracked\n')
2042 'file is already untracked\n')
2043 % match.rel(join(f)))
2043 % match.rel(join(f)))
2044 bad.append(f)
2044 bad.append(f)
2045
2045
2046 for f in forget:
2046 for f in forget:
2047 if ui.verbose or not match.exact(f):
2047 if ui.verbose or not match.exact(f):
2048 ui.status(_('removing %s\n') % match.rel(join(f)))
2048 ui.status(_('removing %s\n') % match.rel(join(f)))
2049
2049
2050 rejected = wctx.forget(forget, prefix)
2050 rejected = wctx.forget(forget, prefix)
2051 bad.extend(f for f in rejected if f in match.files())
2051 bad.extend(f for f in rejected if f in match.files())
2052 forgot.extend(forget)
2052 forgot.extend(forget)
2053 return bad, forgot
2053 return bad, forgot
2054
2054
2055 def remove(ui, repo, m, after, force):
2056 ret = 0
2057 s = repo.status(match=m, clean=True)
2058 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2059
2060 # warn about failure to delete explicit files/dirs
2061 wctx = repo[None]
2062 for f in m.files():
2063 if f in repo.dirstate or f in wctx.dirs():
2064 continue
2065 if os.path.exists(m.rel(f)):
2066 if os.path.isdir(m.rel(f)):
2067 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
2068 else:
2069 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2070 # missing files will generate a warning elsewhere
2071 ret = 1
2072
2073 if force:
2074 list = modified + deleted + clean + added
2075 elif after:
2076 list = deleted
2077 for f in modified + added + clean:
2078 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
2079 ret = 1
2080 else:
2081 list = deleted + clean
2082 for f in modified:
2083 ui.warn(_('not removing %s: file is modified (use -f'
2084 ' to force removal)\n') % m.rel(f))
2085 ret = 1
2086 for f in added:
2087 ui.warn(_('not removing %s: file has been marked for add'
2088 ' (use forget to undo)\n') % m.rel(f))
2089 ret = 1
2090
2091 for f in sorted(list):
2092 if ui.verbose or not m.exact(f):
2093 ui.status(_('removing %s\n') % m.rel(f))
2094
2095 wlock = repo.wlock()
2096 try:
2097 if not after:
2098 for f in list:
2099 if f in added:
2100 continue # we never unlink added files on remove
2101 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
2102 repo[None].forget(list)
2103 finally:
2104 wlock.release()
2105
2106 return ret
2107
2055 def cat(ui, repo, ctx, matcher, prefix, **opts):
2108 def cat(ui, repo, ctx, matcher, prefix, **opts):
2056 err = 1
2109 err = 1
2057
2110
2058 def write(path):
2111 def write(path):
2059 fp = makefileobj(repo, opts.get('output'), ctx.node(),
2112 fp = makefileobj(repo, opts.get('output'), ctx.node(),
2060 pathname=os.path.join(prefix, path))
2113 pathname=os.path.join(prefix, path))
2061 data = ctx[path].data()
2114 data = ctx[path].data()
2062 if opts.get('decode'):
2115 if opts.get('decode'):
2063 data = repo.wwritedata(path, data)
2116 data = repo.wwritedata(path, data)
2064 fp.write(data)
2117 fp.write(data)
2065 fp.close()
2118 fp.close()
2066
2119
2067 # Automation often uses hg cat on single files, so special case it
2120 # Automation often uses hg cat on single files, so special case it
2068 # for performance to avoid the cost of parsing the manifest.
2121 # for performance to avoid the cost of parsing the manifest.
2069 if len(matcher.files()) == 1 and not matcher.anypats():
2122 if len(matcher.files()) == 1 and not matcher.anypats():
2070 file = matcher.files()[0]
2123 file = matcher.files()[0]
2071 mf = repo.manifest
2124 mf = repo.manifest
2072 mfnode = ctx._changeset[0]
2125 mfnode = ctx._changeset[0]
2073 if mf.find(mfnode, file)[0]:
2126 if mf.find(mfnode, file)[0]:
2074 write(file)
2127 write(file)
2075 return 0
2128 return 0
2076
2129
2077 # Don't warn about "missing" files that are really in subrepos
2130 # Don't warn about "missing" files that are really in subrepos
2078 bad = matcher.bad
2131 bad = matcher.bad
2079
2132
2080 def badfn(path, msg):
2133 def badfn(path, msg):
2081 for subpath in ctx.substate:
2134 for subpath in ctx.substate:
2082 if path.startswith(subpath):
2135 if path.startswith(subpath):
2083 return
2136 return
2084 bad(path, msg)
2137 bad(path, msg)
2085
2138
2086 matcher.bad = badfn
2139 matcher.bad = badfn
2087
2140
2088 for abs in ctx.walk(matcher):
2141 for abs in ctx.walk(matcher):
2089 write(abs)
2142 write(abs)
2090 err = 0
2143 err = 0
2091
2144
2092 matcher.bad = bad
2145 matcher.bad = bad
2093
2146
2094 for subpath in sorted(ctx.substate):
2147 for subpath in sorted(ctx.substate):
2095 sub = ctx.sub(subpath)
2148 sub = ctx.sub(subpath)
2096 try:
2149 try:
2097 submatch = matchmod.narrowmatcher(subpath, matcher)
2150 submatch = matchmod.narrowmatcher(subpath, matcher)
2098
2151
2099 if not sub.cat(ui, submatch, os.path.join(prefix, sub._path),
2152 if not sub.cat(ui, submatch, os.path.join(prefix, sub._path),
2100 **opts):
2153 **opts):
2101 err = 0
2154 err = 0
2102 except error.RepoLookupError:
2155 except error.RepoLookupError:
2103 ui.status(_("skipping missing subrepository: %s\n")
2156 ui.status(_("skipping missing subrepository: %s\n")
2104 % os.path.join(prefix, subpath))
2157 % os.path.join(prefix, subpath))
2105
2158
2106 return err
2159 return err
2107
2160
2108 def commit(ui, repo, commitfunc, pats, opts):
2161 def commit(ui, repo, commitfunc, pats, opts):
2109 '''commit the specified files or all outstanding changes'''
2162 '''commit the specified files or all outstanding changes'''
2110 date = opts.get('date')
2163 date = opts.get('date')
2111 if date:
2164 if date:
2112 opts['date'] = util.parsedate(date)
2165 opts['date'] = util.parsedate(date)
2113 message = logmessage(ui, opts)
2166 message = logmessage(ui, opts)
2114
2167
2115 # extract addremove carefully -- this function can be called from a command
2168 # extract addremove carefully -- this function can be called from a command
2116 # that doesn't support addremove
2169 # that doesn't support addremove
2117 if opts.get('addremove'):
2170 if opts.get('addremove'):
2118 scmutil.addremove(repo, pats, opts)
2171 scmutil.addremove(repo, pats, opts)
2119
2172
2120 return commitfunc(ui, repo, message,
2173 return commitfunc(ui, repo, message,
2121 scmutil.match(repo[None], pats, opts), opts)
2174 scmutil.match(repo[None], pats, opts), opts)
2122
2175
2123 def amend(ui, repo, commitfunc, old, extra, pats, opts):
2176 def amend(ui, repo, commitfunc, old, extra, pats, opts):
2124 # amend will reuse the existing user if not specified, but the obsolete
2177 # amend will reuse the existing user if not specified, but the obsolete
2125 # marker creation requires that the current user's name is specified.
2178 # marker creation requires that the current user's name is specified.
2126 if obsolete._enabled:
2179 if obsolete._enabled:
2127 ui.username() # raise exception if username not set
2180 ui.username() # raise exception if username not set
2128
2181
2129 ui.note(_('amending changeset %s\n') % old)
2182 ui.note(_('amending changeset %s\n') % old)
2130 base = old.p1()
2183 base = old.p1()
2131
2184
2132 wlock = lock = newid = None
2185 wlock = lock = newid = None
2133 try:
2186 try:
2134 wlock = repo.wlock()
2187 wlock = repo.wlock()
2135 lock = repo.lock()
2188 lock = repo.lock()
2136 tr = repo.transaction('amend')
2189 tr = repo.transaction('amend')
2137 try:
2190 try:
2138 # See if we got a message from -m or -l, if not, open the editor
2191 # See if we got a message from -m or -l, if not, open the editor
2139 # with the message of the changeset to amend
2192 # with the message of the changeset to amend
2140 message = logmessage(ui, opts)
2193 message = logmessage(ui, opts)
2141 # ensure logfile does not conflict with later enforcement of the
2194 # ensure logfile does not conflict with later enforcement of the
2142 # message. potential logfile content has been processed by
2195 # message. potential logfile content has been processed by
2143 # `logmessage` anyway.
2196 # `logmessage` anyway.
2144 opts.pop('logfile')
2197 opts.pop('logfile')
2145 # First, do a regular commit to record all changes in the working
2198 # First, do a regular commit to record all changes in the working
2146 # directory (if there are any)
2199 # directory (if there are any)
2147 ui.callhooks = False
2200 ui.callhooks = False
2148 currentbookmark = repo._bookmarkcurrent
2201 currentbookmark = repo._bookmarkcurrent
2149 try:
2202 try:
2150 repo._bookmarkcurrent = None
2203 repo._bookmarkcurrent = None
2151 opts['message'] = 'temporary amend commit for %s' % old
2204 opts['message'] = 'temporary amend commit for %s' % old
2152 node = commit(ui, repo, commitfunc, pats, opts)
2205 node = commit(ui, repo, commitfunc, pats, opts)
2153 finally:
2206 finally:
2154 repo._bookmarkcurrent = currentbookmark
2207 repo._bookmarkcurrent = currentbookmark
2155 ui.callhooks = True
2208 ui.callhooks = True
2156 ctx = repo[node]
2209 ctx = repo[node]
2157
2210
2158 # Participating changesets:
2211 # Participating changesets:
2159 #
2212 #
2160 # node/ctx o - new (intermediate) commit that contains changes
2213 # node/ctx o - new (intermediate) commit that contains changes
2161 # | from working dir to go into amending commit
2214 # | from working dir to go into amending commit
2162 # | (or a workingctx if there were no changes)
2215 # | (or a workingctx if there were no changes)
2163 # |
2216 # |
2164 # old o - changeset to amend
2217 # old o - changeset to amend
2165 # |
2218 # |
2166 # base o - parent of amending changeset
2219 # base o - parent of amending changeset
2167
2220
2168 # Update extra dict from amended commit (e.g. to preserve graft
2221 # Update extra dict from amended commit (e.g. to preserve graft
2169 # source)
2222 # source)
2170 extra.update(old.extra())
2223 extra.update(old.extra())
2171
2224
2172 # Also update it from the intermediate commit or from the wctx
2225 # Also update it from the intermediate commit or from the wctx
2173 extra.update(ctx.extra())
2226 extra.update(ctx.extra())
2174
2227
2175 if len(old.parents()) > 1:
2228 if len(old.parents()) > 1:
2176 # ctx.files() isn't reliable for merges, so fall back to the
2229 # ctx.files() isn't reliable for merges, so fall back to the
2177 # slower repo.status() method
2230 # slower repo.status() method
2178 files = set([fn for st in repo.status(base, old)[:3]
2231 files = set([fn for st in repo.status(base, old)[:3]
2179 for fn in st])
2232 for fn in st])
2180 else:
2233 else:
2181 files = set(old.files())
2234 files = set(old.files())
2182
2235
2183 # Second, we use either the commit we just did, or if there were no
2236 # Second, we use either the commit we just did, or if there were no
2184 # changes the parent of the working directory as the version of the
2237 # changes the parent of the working directory as the version of the
2185 # files in the final amend commit
2238 # files in the final amend commit
2186 if node:
2239 if node:
2187 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
2240 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
2188
2241
2189 user = ctx.user()
2242 user = ctx.user()
2190 date = ctx.date()
2243 date = ctx.date()
2191 # Recompute copies (avoid recording a -> b -> a)
2244 # Recompute copies (avoid recording a -> b -> a)
2192 copied = copies.pathcopies(base, ctx)
2245 copied = copies.pathcopies(base, ctx)
2193
2246
2194 # Prune files which were reverted by the updates: if old
2247 # Prune files which were reverted by the updates: if old
2195 # introduced file X and our intermediate commit, node,
2248 # introduced file X and our intermediate commit, node,
2196 # renamed that file, then those two files are the same and
2249 # renamed that file, then those two files are the same and
2197 # we can discard X from our list of files. Likewise if X
2250 # we can discard X from our list of files. Likewise if X
2198 # was deleted, it's no longer relevant
2251 # was deleted, it's no longer relevant
2199 files.update(ctx.files())
2252 files.update(ctx.files())
2200
2253
2201 def samefile(f):
2254 def samefile(f):
2202 if f in ctx.manifest():
2255 if f in ctx.manifest():
2203 a = ctx.filectx(f)
2256 a = ctx.filectx(f)
2204 if f in base.manifest():
2257 if f in base.manifest():
2205 b = base.filectx(f)
2258 b = base.filectx(f)
2206 return (not a.cmp(b)
2259 return (not a.cmp(b)
2207 and a.flags() == b.flags())
2260 and a.flags() == b.flags())
2208 else:
2261 else:
2209 return False
2262 return False
2210 else:
2263 else:
2211 return f not in base.manifest()
2264 return f not in base.manifest()
2212 files = [f for f in files if not samefile(f)]
2265 files = [f for f in files if not samefile(f)]
2213
2266
2214 def filectxfn(repo, ctx_, path):
2267 def filectxfn(repo, ctx_, path):
2215 try:
2268 try:
2216 fctx = ctx[path]
2269 fctx = ctx[path]
2217 flags = fctx.flags()
2270 flags = fctx.flags()
2218 mctx = context.memfilectx(repo,
2271 mctx = context.memfilectx(repo,
2219 fctx.path(), fctx.data(),
2272 fctx.path(), fctx.data(),
2220 islink='l' in flags,
2273 islink='l' in flags,
2221 isexec='x' in flags,
2274 isexec='x' in flags,
2222 copied=copied.get(path))
2275 copied=copied.get(path))
2223 return mctx
2276 return mctx
2224 except KeyError:
2277 except KeyError:
2225 return None
2278 return None
2226 else:
2279 else:
2227 ui.note(_('copying changeset %s to %s\n') % (old, base))
2280 ui.note(_('copying changeset %s to %s\n') % (old, base))
2228
2281
2229 # Use version of files as in the old cset
2282 # Use version of files as in the old cset
2230 def filectxfn(repo, ctx_, path):
2283 def filectxfn(repo, ctx_, path):
2231 try:
2284 try:
2232 return old.filectx(path)
2285 return old.filectx(path)
2233 except KeyError:
2286 except KeyError:
2234 return None
2287 return None
2235
2288
2236 user = opts.get('user') or old.user()
2289 user = opts.get('user') or old.user()
2237 date = opts.get('date') or old.date()
2290 date = opts.get('date') or old.date()
2238 editform = mergeeditform(old, 'commit.amend')
2291 editform = mergeeditform(old, 'commit.amend')
2239 editor = getcommiteditor(editform=editform, **opts)
2292 editor = getcommiteditor(editform=editform, **opts)
2240 if not message:
2293 if not message:
2241 editor = getcommiteditor(edit=True, editform=editform)
2294 editor = getcommiteditor(edit=True, editform=editform)
2242 message = old.description()
2295 message = old.description()
2243
2296
2244 pureextra = extra.copy()
2297 pureextra = extra.copy()
2245 extra['amend_source'] = old.hex()
2298 extra['amend_source'] = old.hex()
2246
2299
2247 new = context.memctx(repo,
2300 new = context.memctx(repo,
2248 parents=[base.node(), old.p2().node()],
2301 parents=[base.node(), old.p2().node()],
2249 text=message,
2302 text=message,
2250 files=files,
2303 files=files,
2251 filectxfn=filectxfn,
2304 filectxfn=filectxfn,
2252 user=user,
2305 user=user,
2253 date=date,
2306 date=date,
2254 extra=extra,
2307 extra=extra,
2255 editor=editor)
2308 editor=editor)
2256
2309
2257 newdesc = changelog.stripdesc(new.description())
2310 newdesc = changelog.stripdesc(new.description())
2258 if ((not node)
2311 if ((not node)
2259 and newdesc == old.description()
2312 and newdesc == old.description()
2260 and user == old.user()
2313 and user == old.user()
2261 and date == old.date()
2314 and date == old.date()
2262 and pureextra == old.extra()):
2315 and pureextra == old.extra()):
2263 # nothing changed. continuing here would create a new node
2316 # nothing changed. continuing here would create a new node
2264 # anyway because of the amend_source noise.
2317 # anyway because of the amend_source noise.
2265 #
2318 #
2266 # This not what we expect from amend.
2319 # This not what we expect from amend.
2267 return old.node()
2320 return old.node()
2268
2321
2269 ph = repo.ui.config('phases', 'new-commit', phases.draft)
2322 ph = repo.ui.config('phases', 'new-commit', phases.draft)
2270 try:
2323 try:
2271 if opts.get('secret'):
2324 if opts.get('secret'):
2272 commitphase = 'secret'
2325 commitphase = 'secret'
2273 else:
2326 else:
2274 commitphase = old.phase()
2327 commitphase = old.phase()
2275 repo.ui.setconfig('phases', 'new-commit', commitphase, 'amend')
2328 repo.ui.setconfig('phases', 'new-commit', commitphase, 'amend')
2276 newid = repo.commitctx(new)
2329 newid = repo.commitctx(new)
2277 finally:
2330 finally:
2278 repo.ui.setconfig('phases', 'new-commit', ph, 'amend')
2331 repo.ui.setconfig('phases', 'new-commit', ph, 'amend')
2279 if newid != old.node():
2332 if newid != old.node():
2280 # Reroute the working copy parent to the new changeset
2333 # Reroute the working copy parent to the new changeset
2281 repo.setparents(newid, nullid)
2334 repo.setparents(newid, nullid)
2282
2335
2283 # Move bookmarks from old parent to amend commit
2336 # Move bookmarks from old parent to amend commit
2284 bms = repo.nodebookmarks(old.node())
2337 bms = repo.nodebookmarks(old.node())
2285 if bms:
2338 if bms:
2286 marks = repo._bookmarks
2339 marks = repo._bookmarks
2287 for bm in bms:
2340 for bm in bms:
2288 marks[bm] = newid
2341 marks[bm] = newid
2289 marks.write()
2342 marks.write()
2290 #commit the whole amend process
2343 #commit the whole amend process
2291 createmarkers = obsolete.isenabled(repo, obsolete.createmarkersopt)
2344 createmarkers = obsolete.isenabled(repo, obsolete.createmarkersopt)
2292 if createmarkers and newid != old.node():
2345 if createmarkers and newid != old.node():
2293 # mark the new changeset as successor of the rewritten one
2346 # mark the new changeset as successor of the rewritten one
2294 new = repo[newid]
2347 new = repo[newid]
2295 obs = [(old, (new,))]
2348 obs = [(old, (new,))]
2296 if node:
2349 if node:
2297 obs.append((ctx, ()))
2350 obs.append((ctx, ()))
2298
2351
2299 obsolete.createmarkers(repo, obs)
2352 obsolete.createmarkers(repo, obs)
2300 tr.close()
2353 tr.close()
2301 finally:
2354 finally:
2302 tr.release()
2355 tr.release()
2303 if not createmarkers and newid != old.node():
2356 if not createmarkers and newid != old.node():
2304 # Strip the intermediate commit (if there was one) and the amended
2357 # Strip the intermediate commit (if there was one) and the amended
2305 # commit
2358 # commit
2306 if node:
2359 if node:
2307 ui.note(_('stripping intermediate changeset %s\n') % ctx)
2360 ui.note(_('stripping intermediate changeset %s\n') % ctx)
2308 ui.note(_('stripping amended changeset %s\n') % old)
2361 ui.note(_('stripping amended changeset %s\n') % old)
2309 repair.strip(ui, repo, old.node(), topic='amend-backup')
2362 repair.strip(ui, repo, old.node(), topic='amend-backup')
2310 finally:
2363 finally:
2311 if newid is None:
2364 if newid is None:
2312 repo.dirstate.invalidate()
2365 repo.dirstate.invalidate()
2313 lockmod.release(lock, wlock)
2366 lockmod.release(lock, wlock)
2314 return newid
2367 return newid
2315
2368
2316 def commiteditor(repo, ctx, subs, editform=''):
2369 def commiteditor(repo, ctx, subs, editform=''):
2317 if ctx.description():
2370 if ctx.description():
2318 return ctx.description()
2371 return ctx.description()
2319 return commitforceeditor(repo, ctx, subs, editform=editform)
2372 return commitforceeditor(repo, ctx, subs, editform=editform)
2320
2373
2321 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None,
2374 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None,
2322 editform=''):
2375 editform=''):
2323 if not extramsg:
2376 if not extramsg:
2324 extramsg = _("Leave message empty to abort commit.")
2377 extramsg = _("Leave message empty to abort commit.")
2325
2378
2326 forms = [e for e in editform.split('.') if e]
2379 forms = [e for e in editform.split('.') if e]
2327 forms.insert(0, 'changeset')
2380 forms.insert(0, 'changeset')
2328 while forms:
2381 while forms:
2329 tmpl = repo.ui.config('committemplate', '.'.join(forms))
2382 tmpl = repo.ui.config('committemplate', '.'.join(forms))
2330 if tmpl:
2383 if tmpl:
2331 committext = buildcommittemplate(repo, ctx, subs, extramsg, tmpl)
2384 committext = buildcommittemplate(repo, ctx, subs, extramsg, tmpl)
2332 break
2385 break
2333 forms.pop()
2386 forms.pop()
2334 else:
2387 else:
2335 committext = buildcommittext(repo, ctx, subs, extramsg)
2388 committext = buildcommittext(repo, ctx, subs, extramsg)
2336
2389
2337 # run editor in the repository root
2390 # run editor in the repository root
2338 olddir = os.getcwd()
2391 olddir = os.getcwd()
2339 os.chdir(repo.root)
2392 os.chdir(repo.root)
2340 text = repo.ui.edit(committext, ctx.user(), ctx.extra(), editform=editform)
2393 text = repo.ui.edit(committext, ctx.user(), ctx.extra(), editform=editform)
2341 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2394 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2342 os.chdir(olddir)
2395 os.chdir(olddir)
2343
2396
2344 if finishdesc:
2397 if finishdesc:
2345 text = finishdesc(text)
2398 text = finishdesc(text)
2346 if not text.strip():
2399 if not text.strip():
2347 raise util.Abort(_("empty commit message"))
2400 raise util.Abort(_("empty commit message"))
2348
2401
2349 return text
2402 return text
2350
2403
2351 def buildcommittemplate(repo, ctx, subs, extramsg, tmpl):
2404 def buildcommittemplate(repo, ctx, subs, extramsg, tmpl):
2352 ui = repo.ui
2405 ui = repo.ui
2353 tmpl, mapfile = gettemplate(ui, tmpl, None)
2406 tmpl, mapfile = gettemplate(ui, tmpl, None)
2354
2407
2355 try:
2408 try:
2356 t = changeset_templater(ui, repo, None, {}, tmpl, mapfile, False)
2409 t = changeset_templater(ui, repo, None, {}, tmpl, mapfile, False)
2357 except SyntaxError, inst:
2410 except SyntaxError, inst:
2358 raise util.Abort(inst.args[0])
2411 raise util.Abort(inst.args[0])
2359
2412
2360 for k, v in repo.ui.configitems('committemplate'):
2413 for k, v in repo.ui.configitems('committemplate'):
2361 if k != 'changeset':
2414 if k != 'changeset':
2362 t.t.cache[k] = v
2415 t.t.cache[k] = v
2363
2416
2364 if not extramsg:
2417 if not extramsg:
2365 extramsg = '' # ensure that extramsg is string
2418 extramsg = '' # ensure that extramsg is string
2366
2419
2367 ui.pushbuffer()
2420 ui.pushbuffer()
2368 t.show(ctx, extramsg=extramsg)
2421 t.show(ctx, extramsg=extramsg)
2369 return ui.popbuffer()
2422 return ui.popbuffer()
2370
2423
2371 def buildcommittext(repo, ctx, subs, extramsg):
2424 def buildcommittext(repo, ctx, subs, extramsg):
2372 edittext = []
2425 edittext = []
2373 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
2426 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
2374 if ctx.description():
2427 if ctx.description():
2375 edittext.append(ctx.description())
2428 edittext.append(ctx.description())
2376 edittext.append("")
2429 edittext.append("")
2377 edittext.append("") # Empty line between message and comments.
2430 edittext.append("") # Empty line between message and comments.
2378 edittext.append(_("HG: Enter commit message."
2431 edittext.append(_("HG: Enter commit message."
2379 " Lines beginning with 'HG:' are removed."))
2432 " Lines beginning with 'HG:' are removed."))
2380 edittext.append("HG: %s" % extramsg)
2433 edittext.append("HG: %s" % extramsg)
2381 edittext.append("HG: --")
2434 edittext.append("HG: --")
2382 edittext.append(_("HG: user: %s") % ctx.user())
2435 edittext.append(_("HG: user: %s") % ctx.user())
2383 if ctx.p2():
2436 if ctx.p2():
2384 edittext.append(_("HG: branch merge"))
2437 edittext.append(_("HG: branch merge"))
2385 if ctx.branch():
2438 if ctx.branch():
2386 edittext.append(_("HG: branch '%s'") % ctx.branch())
2439 edittext.append(_("HG: branch '%s'") % ctx.branch())
2387 if bookmarks.iscurrent(repo):
2440 if bookmarks.iscurrent(repo):
2388 edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
2441 edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
2389 edittext.extend([_("HG: subrepo %s") % s for s in subs])
2442 edittext.extend([_("HG: subrepo %s") % s for s in subs])
2390 edittext.extend([_("HG: added %s") % f for f in added])
2443 edittext.extend([_("HG: added %s") % f for f in added])
2391 edittext.extend([_("HG: changed %s") % f for f in modified])
2444 edittext.extend([_("HG: changed %s") % f for f in modified])
2392 edittext.extend([_("HG: removed %s") % f for f in removed])
2445 edittext.extend([_("HG: removed %s") % f for f in removed])
2393 if not added and not modified and not removed:
2446 if not added and not modified and not removed:
2394 edittext.append(_("HG: no files changed"))
2447 edittext.append(_("HG: no files changed"))
2395 edittext.append("")
2448 edittext.append("")
2396
2449
2397 return "\n".join(edittext)
2450 return "\n".join(edittext)
2398
2451
2399 def commitstatus(repo, node, branch, bheads=None, opts={}):
2452 def commitstatus(repo, node, branch, bheads=None, opts={}):
2400 ctx = repo[node]
2453 ctx = repo[node]
2401 parents = ctx.parents()
2454 parents = ctx.parents()
2402
2455
2403 if (not opts.get('amend') and bheads and node not in bheads and not
2456 if (not opts.get('amend') and bheads and node not in bheads and not
2404 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2457 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2405 repo.ui.status(_('created new head\n'))
2458 repo.ui.status(_('created new head\n'))
2406 # The message is not printed for initial roots. For the other
2459 # The message is not printed for initial roots. For the other
2407 # changesets, it is printed in the following situations:
2460 # changesets, it is printed in the following situations:
2408 #
2461 #
2409 # Par column: for the 2 parents with ...
2462 # Par column: for the 2 parents with ...
2410 # N: null or no parent
2463 # N: null or no parent
2411 # B: parent is on another named branch
2464 # B: parent is on another named branch
2412 # C: parent is a regular non head changeset
2465 # C: parent is a regular non head changeset
2413 # H: parent was a branch head of the current branch
2466 # H: parent was a branch head of the current branch
2414 # Msg column: whether we print "created new head" message
2467 # Msg column: whether we print "created new head" message
2415 # In the following, it is assumed that there already exists some
2468 # In the following, it is assumed that there already exists some
2416 # initial branch heads of the current branch, otherwise nothing is
2469 # initial branch heads of the current branch, otherwise nothing is
2417 # printed anyway.
2470 # printed anyway.
2418 #
2471 #
2419 # Par Msg Comment
2472 # Par Msg Comment
2420 # N N y additional topo root
2473 # N N y additional topo root
2421 #
2474 #
2422 # B N y additional branch root
2475 # B N y additional branch root
2423 # C N y additional topo head
2476 # C N y additional topo head
2424 # H N n usual case
2477 # H N n usual case
2425 #
2478 #
2426 # B B y weird additional branch root
2479 # B B y weird additional branch root
2427 # C B y branch merge
2480 # C B y branch merge
2428 # H B n merge with named branch
2481 # H B n merge with named branch
2429 #
2482 #
2430 # C C y additional head from merge
2483 # C C y additional head from merge
2431 # C H n merge with a head
2484 # C H n merge with a head
2432 #
2485 #
2433 # H H n head merge: head count decreases
2486 # H H n head merge: head count decreases
2434
2487
2435 if not opts.get('close_branch'):
2488 if not opts.get('close_branch'):
2436 for r in parents:
2489 for r in parents:
2437 if r.closesbranch() and r.branch() == branch:
2490 if r.closesbranch() and r.branch() == branch:
2438 repo.ui.status(_('reopening closed branch head %d\n') % r)
2491 repo.ui.status(_('reopening closed branch head %d\n') % r)
2439
2492
2440 if repo.ui.debugflag:
2493 if repo.ui.debugflag:
2441 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
2494 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
2442 elif repo.ui.verbose:
2495 elif repo.ui.verbose:
2443 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
2496 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
2444
2497
2445 def revert(ui, repo, ctx, parents, *pats, **opts):
2498 def revert(ui, repo, ctx, parents, *pats, **opts):
2446 parent, p2 = parents
2499 parent, p2 = parents
2447 node = ctx.node()
2500 node = ctx.node()
2448
2501
2449 mf = ctx.manifest()
2502 mf = ctx.manifest()
2450 if node == p2:
2503 if node == p2:
2451 parent = p2
2504 parent = p2
2452 if node == parent:
2505 if node == parent:
2453 pmf = mf
2506 pmf = mf
2454 else:
2507 else:
2455 pmf = None
2508 pmf = None
2456
2509
2457 # need all matching names in dirstate and manifest of target rev,
2510 # need all matching names in dirstate and manifest of target rev,
2458 # so have to walk both. do not print errors if files exist in one
2511 # so have to walk both. do not print errors if files exist in one
2459 # but not other.
2512 # but not other.
2460
2513
2461 # `names` is a mapping for all elements in working copy and target revision
2514 # `names` is a mapping for all elements in working copy and target revision
2462 # The mapping is in the form:
2515 # The mapping is in the form:
2463 # <asb path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
2516 # <asb path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
2464 names = {}
2517 names = {}
2465
2518
2466 wlock = repo.wlock()
2519 wlock = repo.wlock()
2467 try:
2520 try:
2468 ## filling of the `names` mapping
2521 ## filling of the `names` mapping
2469 # walk dirstate to fill `names`
2522 # walk dirstate to fill `names`
2470
2523
2471 m = scmutil.match(repo[None], pats, opts)
2524 m = scmutil.match(repo[None], pats, opts)
2472 if not m.always() or node != parent:
2525 if not m.always() or node != parent:
2473 m.bad = lambda x, y: False
2526 m.bad = lambda x, y: False
2474 for abs in repo.walk(m):
2527 for abs in repo.walk(m):
2475 names[abs] = m.rel(abs), m.exact(abs)
2528 names[abs] = m.rel(abs), m.exact(abs)
2476
2529
2477 # walk target manifest to fill `names`
2530 # walk target manifest to fill `names`
2478
2531
2479 def badfn(path, msg):
2532 def badfn(path, msg):
2480 if path in names:
2533 if path in names:
2481 return
2534 return
2482 if path in ctx.substate:
2535 if path in ctx.substate:
2483 return
2536 return
2484 path_ = path + '/'
2537 path_ = path + '/'
2485 for f in names:
2538 for f in names:
2486 if f.startswith(path_):
2539 if f.startswith(path_):
2487 return
2540 return
2488 ui.warn("%s: %s\n" % (m.rel(path), msg))
2541 ui.warn("%s: %s\n" % (m.rel(path), msg))
2489
2542
2490 m = scmutil.match(ctx, pats, opts)
2543 m = scmutil.match(ctx, pats, opts)
2491 m.bad = badfn
2544 m.bad = badfn
2492 for abs in ctx.walk(m):
2545 for abs in ctx.walk(m):
2493 if abs not in names:
2546 if abs not in names:
2494 names[abs] = m.rel(abs), m.exact(abs)
2547 names[abs] = m.rel(abs), m.exact(abs)
2495
2548
2496 # Find status of all file in `names`.
2549 # Find status of all file in `names`.
2497 m = scmutil.matchfiles(repo, names)
2550 m = scmutil.matchfiles(repo, names)
2498
2551
2499 changes = repo.status(node1=node, match=m,
2552 changes = repo.status(node1=node, match=m,
2500 unknown=True, ignored=True, clean=True)
2553 unknown=True, ignored=True, clean=True)
2501 else:
2554 else:
2502 changes = repo.status(match=m)
2555 changes = repo.status(match=m)
2503 for kind in changes:
2556 for kind in changes:
2504 for abs in kind:
2557 for abs in kind:
2505 names[abs] = m.rel(abs), m.exact(abs)
2558 names[abs] = m.rel(abs), m.exact(abs)
2506
2559
2507 m = scmutil.matchfiles(repo, names)
2560 m = scmutil.matchfiles(repo, names)
2508
2561
2509 modified = set(changes[0])
2562 modified = set(changes[0])
2510 added = set(changes[1])
2563 added = set(changes[1])
2511 removed = set(changes[2])
2564 removed = set(changes[2])
2512 _deleted = set(changes[3])
2565 _deleted = set(changes[3])
2513 unknown = set(changes[4])
2566 unknown = set(changes[4])
2514 unknown.update(changes[5])
2567 unknown.update(changes[5])
2515 clean = set(changes[6])
2568 clean = set(changes[6])
2516 modadded = set()
2569 modadded = set()
2517
2570
2518 # split between files known in target manifest and the others
2571 # split between files known in target manifest and the others
2519 smf = set(mf)
2572 smf = set(mf)
2520
2573
2521 # determine the exact nature of the deleted changesets
2574 # determine the exact nature of the deleted changesets
2522 deladded = _deleted - smf
2575 deladded = _deleted - smf
2523 deleted = _deleted - deladded
2576 deleted = _deleted - deladded
2524
2577
2525 # We need to account for the state of file in the dirstate.
2578 # We need to account for the state of file in the dirstate.
2526 #
2579 #
2527 # Even, when we revert against something else than parent. This will
2580 # Even, when we revert against something else than parent. This will
2528 # slightly alter the behavior of revert (doing back up or not, delete
2581 # slightly alter the behavior of revert (doing back up or not, delete
2529 # or just forget etc).
2582 # or just forget etc).
2530 if parent == node:
2583 if parent == node:
2531 dsmodified = modified
2584 dsmodified = modified
2532 dsadded = added
2585 dsadded = added
2533 dsremoved = removed
2586 dsremoved = removed
2534 modified, added, removed = set(), set(), set()
2587 modified, added, removed = set(), set(), set()
2535 else:
2588 else:
2536 changes = repo.status(node1=parent, match=m)
2589 changes = repo.status(node1=parent, match=m)
2537 dsmodified = set(changes[0])
2590 dsmodified = set(changes[0])
2538 dsadded = set(changes[1])
2591 dsadded = set(changes[1])
2539 dsremoved = set(changes[2])
2592 dsremoved = set(changes[2])
2540
2593
2541 # only take into account for removes between wc and target
2594 # only take into account for removes between wc and target
2542 clean |= dsremoved - removed
2595 clean |= dsremoved - removed
2543 dsremoved &= removed
2596 dsremoved &= removed
2544 # distinct between dirstate remove and other
2597 # distinct between dirstate remove and other
2545 removed -= dsremoved
2598 removed -= dsremoved
2546
2599
2547 modadded = added & dsmodified
2600 modadded = added & dsmodified
2548 added -= modadded
2601 added -= modadded
2549
2602
2550 # tell newly modified apart.
2603 # tell newly modified apart.
2551 dsmodified &= modified
2604 dsmodified &= modified
2552 dsmodified |= modified & dsadded # dirstate added may needs backup
2605 dsmodified |= modified & dsadded # dirstate added may needs backup
2553 modified -= dsmodified
2606 modified -= dsmodified
2554
2607
2555 # We need to wait for some post-processing to update this set
2608 # We need to wait for some post-processing to update this set
2556 # before making the distinction. The dirstate will be used for
2609 # before making the distinction. The dirstate will be used for
2557 # that purpose.
2610 # that purpose.
2558 dsadded = added
2611 dsadded = added
2559
2612
2560 # in case of merge, files that are actually added can be reported as
2613 # in case of merge, files that are actually added can be reported as
2561 # modified, we need to post process the result
2614 # modified, we need to post process the result
2562 if p2 != nullid:
2615 if p2 != nullid:
2563 if pmf is None:
2616 if pmf is None:
2564 # only need parent manifest in the merge case,
2617 # only need parent manifest in the merge case,
2565 # so do not read by default
2618 # so do not read by default
2566 pmf = repo[parent].manifest()
2619 pmf = repo[parent].manifest()
2567 mergeadd = dsmodified - set(pmf)
2620 mergeadd = dsmodified - set(pmf)
2568 dsadded |= mergeadd
2621 dsadded |= mergeadd
2569 dsmodified -= mergeadd
2622 dsmodified -= mergeadd
2570
2623
2571 # if f is a rename, update `names` to also revert the source
2624 # if f is a rename, update `names` to also revert the source
2572 cwd = repo.getcwd()
2625 cwd = repo.getcwd()
2573 for f in dsadded:
2626 for f in dsadded:
2574 src = repo.dirstate.copied(f)
2627 src = repo.dirstate.copied(f)
2575 # XXX should we check for rename down to target node?
2628 # XXX should we check for rename down to target node?
2576 if src and src not in names and repo.dirstate[src] == 'r':
2629 if src and src not in names and repo.dirstate[src] == 'r':
2577 dsremoved.add(src)
2630 dsremoved.add(src)
2578 names[src] = (repo.pathto(src, cwd), True)
2631 names[src] = (repo.pathto(src, cwd), True)
2579
2632
2580 # distinguish between file to forget and the other
2633 # distinguish between file to forget and the other
2581 added = set()
2634 added = set()
2582 for abs in dsadded:
2635 for abs in dsadded:
2583 if repo.dirstate[abs] != 'a':
2636 if repo.dirstate[abs] != 'a':
2584 added.add(abs)
2637 added.add(abs)
2585 dsadded -= added
2638 dsadded -= added
2586
2639
2587 for abs in deladded:
2640 for abs in deladded:
2588 if repo.dirstate[abs] == 'a':
2641 if repo.dirstate[abs] == 'a':
2589 dsadded.add(abs)
2642 dsadded.add(abs)
2590 deladded -= dsadded
2643 deladded -= dsadded
2591
2644
2592 # For files marked as removed, we check if an unknown file is present at
2645 # For files marked as removed, we check if an unknown file is present at
2593 # the same path. If a such file exists it may need to be backed up.
2646 # the same path. If a such file exists it may need to be backed up.
2594 # Making the distinction at this stage helps have simpler backup
2647 # Making the distinction at this stage helps have simpler backup
2595 # logic.
2648 # logic.
2596 removunk = set()
2649 removunk = set()
2597 for abs in removed:
2650 for abs in removed:
2598 target = repo.wjoin(abs)
2651 target = repo.wjoin(abs)
2599 if os.path.lexists(target):
2652 if os.path.lexists(target):
2600 removunk.add(abs)
2653 removunk.add(abs)
2601 removed -= removunk
2654 removed -= removunk
2602
2655
2603 dsremovunk = set()
2656 dsremovunk = set()
2604 for abs in dsremoved:
2657 for abs in dsremoved:
2605 target = repo.wjoin(abs)
2658 target = repo.wjoin(abs)
2606 if os.path.lexists(target):
2659 if os.path.lexists(target):
2607 dsremovunk.add(abs)
2660 dsremovunk.add(abs)
2608 dsremoved -= dsremovunk
2661 dsremoved -= dsremovunk
2609
2662
2610 # action to be actually performed by revert
2663 # action to be actually performed by revert
2611 # (<list of file>, message>) tuple
2664 # (<list of file>, message>) tuple
2612 actions = {'revert': ([], _('reverting %s\n')),
2665 actions = {'revert': ([], _('reverting %s\n')),
2613 'add': ([], _('adding %s\n')),
2666 'add': ([], _('adding %s\n')),
2614 'remove': ([], _('removing %s\n')),
2667 'remove': ([], _('removing %s\n')),
2615 'drop': ([], _('removing %s\n')),
2668 'drop': ([], _('removing %s\n')),
2616 'forget': ([], _('forgetting %s\n')),
2669 'forget': ([], _('forgetting %s\n')),
2617 'undelete': ([], _('undeleting %s\n')),
2670 'undelete': ([], _('undeleting %s\n')),
2618 'noop': (None, _('no changes needed to %s\n')),
2671 'noop': (None, _('no changes needed to %s\n')),
2619 'unknown': (None, _('file not managed: %s\n')),
2672 'unknown': (None, _('file not managed: %s\n')),
2620 }
2673 }
2621
2674
2622 # "constant" that convey the backup strategy.
2675 # "constant" that convey the backup strategy.
2623 # All set to `discard` if `no-backup` is set do avoid checking
2676 # All set to `discard` if `no-backup` is set do avoid checking
2624 # no_backup lower in the code.
2677 # no_backup lower in the code.
2625 # These values are ordered for comparison purposes
2678 # These values are ordered for comparison purposes
2626 backup = 2 # unconditionally do backup
2679 backup = 2 # unconditionally do backup
2627 check = 1 # check if the existing file differs from target
2680 check = 1 # check if the existing file differs from target
2628 discard = 0 # never do backup
2681 discard = 0 # never do backup
2629 if opts.get('no_backup'):
2682 if opts.get('no_backup'):
2630 backup = check = discard
2683 backup = check = discard
2631
2684
2632 backupanddel = actions['remove']
2685 backupanddel = actions['remove']
2633 if not opts.get('no_backup'):
2686 if not opts.get('no_backup'):
2634 backupanddel = actions['drop']
2687 backupanddel = actions['drop']
2635
2688
2636 disptable = (
2689 disptable = (
2637 # dispatch table:
2690 # dispatch table:
2638 # file state
2691 # file state
2639 # action
2692 # action
2640 # make backup
2693 # make backup
2641
2694
2642 ## Sets that results that will change file on disk
2695 ## Sets that results that will change file on disk
2643 # Modified compared to target, no local change
2696 # Modified compared to target, no local change
2644 (modified, actions['revert'], discard),
2697 (modified, actions['revert'], discard),
2645 # Modified compared to target, but local file is deleted
2698 # Modified compared to target, but local file is deleted
2646 (deleted, actions['revert'], discard),
2699 (deleted, actions['revert'], discard),
2647 # Modified compared to target, local change
2700 # Modified compared to target, local change
2648 (dsmodified, actions['revert'], backup),
2701 (dsmodified, actions['revert'], backup),
2649 # Added since target
2702 # Added since target
2650 (added, actions['remove'], discard),
2703 (added, actions['remove'], discard),
2651 # Added in working directory
2704 # Added in working directory
2652 (dsadded, actions['forget'], discard),
2705 (dsadded, actions['forget'], discard),
2653 # Added since target, have local modification
2706 # Added since target, have local modification
2654 (modadded, backupanddel, backup),
2707 (modadded, backupanddel, backup),
2655 # Added since target but file is missing in working directory
2708 # Added since target but file is missing in working directory
2656 (deladded, actions['drop'], discard),
2709 (deladded, actions['drop'], discard),
2657 # Removed since target, before working copy parent
2710 # Removed since target, before working copy parent
2658 (removed, actions['add'], discard),
2711 (removed, actions['add'], discard),
2659 # Same as `removed` but an unknown file exists at the same path
2712 # Same as `removed` but an unknown file exists at the same path
2660 (removunk, actions['add'], check),
2713 (removunk, actions['add'], check),
2661 # Removed since targe, marked as such in working copy parent
2714 # Removed since targe, marked as such in working copy parent
2662 (dsremoved, actions['undelete'], discard),
2715 (dsremoved, actions['undelete'], discard),
2663 # Same as `dsremoved` but an unknown file exists at the same path
2716 # Same as `dsremoved` but an unknown file exists at the same path
2664 (dsremovunk, actions['undelete'], check),
2717 (dsremovunk, actions['undelete'], check),
2665 ## the following sets does not result in any file changes
2718 ## the following sets does not result in any file changes
2666 # File with no modification
2719 # File with no modification
2667 (clean, actions['noop'], discard),
2720 (clean, actions['noop'], discard),
2668 # Existing file, not tracked anywhere
2721 # Existing file, not tracked anywhere
2669 (unknown, actions['unknown'], discard),
2722 (unknown, actions['unknown'], discard),
2670 )
2723 )
2671
2724
2672 needdata = ('revert', 'add', 'undelete')
2725 needdata = ('revert', 'add', 'undelete')
2673 _revertprefetch(repo, ctx, *[actions[name][0] for name in needdata])
2726 _revertprefetch(repo, ctx, *[actions[name][0] for name in needdata])
2674
2727
2675 wctx = repo[None]
2728 wctx = repo[None]
2676 for abs, (rel, exact) in sorted(names.items()):
2729 for abs, (rel, exact) in sorted(names.items()):
2677 # target file to be touch on disk (relative to cwd)
2730 # target file to be touch on disk (relative to cwd)
2678 target = repo.wjoin(abs)
2731 target = repo.wjoin(abs)
2679 # search the entry in the dispatch table.
2732 # search the entry in the dispatch table.
2680 # if the file is in any of these sets, it was touched in the working
2733 # if the file is in any of these sets, it was touched in the working
2681 # directory parent and we are sure it needs to be reverted.
2734 # directory parent and we are sure it needs to be reverted.
2682 for table, (xlist, msg), dobackup in disptable:
2735 for table, (xlist, msg), dobackup in disptable:
2683 if abs not in table:
2736 if abs not in table:
2684 continue
2737 continue
2685 if xlist is not None:
2738 if xlist is not None:
2686 xlist.append(abs)
2739 xlist.append(abs)
2687 if dobackup and (backup <= dobackup
2740 if dobackup and (backup <= dobackup
2688 or wctx[abs].cmp(ctx[abs])):
2741 or wctx[abs].cmp(ctx[abs])):
2689 bakname = "%s.orig" % rel
2742 bakname = "%s.orig" % rel
2690 ui.note(_('saving current version of %s as %s\n') %
2743 ui.note(_('saving current version of %s as %s\n') %
2691 (rel, bakname))
2744 (rel, bakname))
2692 if not opts.get('dry_run'):
2745 if not opts.get('dry_run'):
2693 util.rename(target, bakname)
2746 util.rename(target, bakname)
2694 if ui.verbose or not exact:
2747 if ui.verbose or not exact:
2695 if not isinstance(msg, basestring):
2748 if not isinstance(msg, basestring):
2696 msg = msg(abs)
2749 msg = msg(abs)
2697 ui.status(msg % rel)
2750 ui.status(msg % rel)
2698 elif exact:
2751 elif exact:
2699 ui.warn(msg % rel)
2752 ui.warn(msg % rel)
2700 break
2753 break
2701
2754
2702
2755
2703 if not opts.get('dry_run'):
2756 if not opts.get('dry_run'):
2704 _performrevert(repo, parents, ctx, actions)
2757 _performrevert(repo, parents, ctx, actions)
2705
2758
2706 # get the list of subrepos that must be reverted
2759 # get the list of subrepos that must be reverted
2707 subrepomatch = scmutil.match(ctx, pats, opts)
2760 subrepomatch = scmutil.match(ctx, pats, opts)
2708 targetsubs = sorted(s for s in ctx.substate if subrepomatch(s))
2761 targetsubs = sorted(s for s in ctx.substate if subrepomatch(s))
2709
2762
2710 if targetsubs:
2763 if targetsubs:
2711 # Revert the subrepos on the revert list
2764 # Revert the subrepos on the revert list
2712 for sub in targetsubs:
2765 for sub in targetsubs:
2713 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
2766 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
2714 finally:
2767 finally:
2715 wlock.release()
2768 wlock.release()
2716
2769
2717 def _revertprefetch(repo, ctx, *files):
2770 def _revertprefetch(repo, ctx, *files):
2718 """Let extension changing the storage layer prefetch content"""
2771 """Let extension changing the storage layer prefetch content"""
2719 pass
2772 pass
2720
2773
2721 def _performrevert(repo, parents, ctx, actions):
2774 def _performrevert(repo, parents, ctx, actions):
2722 """function that actually perform all the actions computed for revert
2775 """function that actually perform all the actions computed for revert
2723
2776
2724 This is an independent function to let extension to plug in and react to
2777 This is an independent function to let extension to plug in and react to
2725 the imminent revert.
2778 the imminent revert.
2726
2779
2727 Make sure you have the working directory locked when calling this function.
2780 Make sure you have the working directory locked when calling this function.
2728 """
2781 """
2729 parent, p2 = parents
2782 parent, p2 = parents
2730 node = ctx.node()
2783 node = ctx.node()
2731 def checkout(f):
2784 def checkout(f):
2732 fc = ctx[f]
2785 fc = ctx[f]
2733 repo.wwrite(f, fc.data(), fc.flags())
2786 repo.wwrite(f, fc.data(), fc.flags())
2734
2787
2735 audit_path = pathutil.pathauditor(repo.root)
2788 audit_path = pathutil.pathauditor(repo.root)
2736 for f in actions['forget'][0]:
2789 for f in actions['forget'][0]:
2737 repo.dirstate.drop(f)
2790 repo.dirstate.drop(f)
2738 for f in actions['remove'][0]:
2791 for f in actions['remove'][0]:
2739 audit_path(f)
2792 audit_path(f)
2740 util.unlinkpath(repo.wjoin(f))
2793 util.unlinkpath(repo.wjoin(f))
2741 repo.dirstate.remove(f)
2794 repo.dirstate.remove(f)
2742 for f in actions['drop'][0]:
2795 for f in actions['drop'][0]:
2743 audit_path(f)
2796 audit_path(f)
2744 repo.dirstate.remove(f)
2797 repo.dirstate.remove(f)
2745
2798
2746 normal = None
2799 normal = None
2747 if node == parent:
2800 if node == parent:
2748 # We're reverting to our parent. If possible, we'd like status
2801 # We're reverting to our parent. If possible, we'd like status
2749 # to report the file as clean. We have to use normallookup for
2802 # to report the file as clean. We have to use normallookup for
2750 # merges to avoid losing information about merged/dirty files.
2803 # merges to avoid losing information about merged/dirty files.
2751 if p2 != nullid:
2804 if p2 != nullid:
2752 normal = repo.dirstate.normallookup
2805 normal = repo.dirstate.normallookup
2753 else:
2806 else:
2754 normal = repo.dirstate.normal
2807 normal = repo.dirstate.normal
2755 for f in actions['revert'][0]:
2808 for f in actions['revert'][0]:
2756 checkout(f)
2809 checkout(f)
2757 if normal:
2810 if normal:
2758 normal(f)
2811 normal(f)
2759
2812
2760 for f in actions['add'][0]:
2813 for f in actions['add'][0]:
2761 checkout(f)
2814 checkout(f)
2762 repo.dirstate.add(f)
2815 repo.dirstate.add(f)
2763
2816
2764 normal = repo.dirstate.normallookup
2817 normal = repo.dirstate.normallookup
2765 if node == parent and p2 == nullid:
2818 if node == parent and p2 == nullid:
2766 normal = repo.dirstate.normal
2819 normal = repo.dirstate.normal
2767 for f in actions['undelete'][0]:
2820 for f in actions['undelete'][0]:
2768 checkout(f)
2821 checkout(f)
2769 normal(f)
2822 normal(f)
2770
2823
2771 copied = copies.pathcopies(repo[parent], ctx)
2824 copied = copies.pathcopies(repo[parent], ctx)
2772
2825
2773 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
2826 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
2774 if f in copied:
2827 if f in copied:
2775 repo.dirstate.copy(copied[f], f)
2828 repo.dirstate.copy(copied[f], f)
2776
2829
2777 def command(table):
2830 def command(table):
2778 """Returns a function object to be used as a decorator for making commands.
2831 """Returns a function object to be used as a decorator for making commands.
2779
2832
2780 This function receives a command table as its argument. The table should
2833 This function receives a command table as its argument. The table should
2781 be a dict.
2834 be a dict.
2782
2835
2783 The returned function can be used as a decorator for adding commands
2836 The returned function can be used as a decorator for adding commands
2784 to that command table. This function accepts multiple arguments to define
2837 to that command table. This function accepts multiple arguments to define
2785 a command.
2838 a command.
2786
2839
2787 The first argument is the command name.
2840 The first argument is the command name.
2788
2841
2789 The options argument is an iterable of tuples defining command arguments.
2842 The options argument is an iterable of tuples defining command arguments.
2790 See ``mercurial.fancyopts.fancyopts()`` for the format of each tuple.
2843 See ``mercurial.fancyopts.fancyopts()`` for the format of each tuple.
2791
2844
2792 The synopsis argument defines a short, one line summary of how to use the
2845 The synopsis argument defines a short, one line summary of how to use the
2793 command. This shows up in the help output.
2846 command. This shows up in the help output.
2794
2847
2795 The norepo argument defines whether the command does not require a
2848 The norepo argument defines whether the command does not require a
2796 local repository. Most commands operate against a repository, thus the
2849 local repository. Most commands operate against a repository, thus the
2797 default is False.
2850 default is False.
2798
2851
2799 The optionalrepo argument defines whether the command optionally requires
2852 The optionalrepo argument defines whether the command optionally requires
2800 a local repository.
2853 a local repository.
2801
2854
2802 The inferrepo argument defines whether to try to find a repository from the
2855 The inferrepo argument defines whether to try to find a repository from the
2803 command line arguments. If True, arguments will be examined for potential
2856 command line arguments. If True, arguments will be examined for potential
2804 repository locations. See ``findrepo()``. If a repository is found, it
2857 repository locations. See ``findrepo()``. If a repository is found, it
2805 will be used.
2858 will be used.
2806 """
2859 """
2807 def cmd(name, options=(), synopsis=None, norepo=False, optionalrepo=False,
2860 def cmd(name, options=(), synopsis=None, norepo=False, optionalrepo=False,
2808 inferrepo=False):
2861 inferrepo=False):
2809 def decorator(func):
2862 def decorator(func):
2810 if synopsis:
2863 if synopsis:
2811 table[name] = func, list(options), synopsis
2864 table[name] = func, list(options), synopsis
2812 else:
2865 else:
2813 table[name] = func, list(options)
2866 table[name] = func, list(options)
2814
2867
2815 if norepo:
2868 if norepo:
2816 # Avoid import cycle.
2869 # Avoid import cycle.
2817 import commands
2870 import commands
2818 commands.norepo += ' %s' % ' '.join(parsealiases(name))
2871 commands.norepo += ' %s' % ' '.join(parsealiases(name))
2819
2872
2820 if optionalrepo:
2873 if optionalrepo:
2821 import commands
2874 import commands
2822 commands.optionalrepo += ' %s' % ' '.join(parsealiases(name))
2875 commands.optionalrepo += ' %s' % ' '.join(parsealiases(name))
2823
2876
2824 if inferrepo:
2877 if inferrepo:
2825 import commands
2878 import commands
2826 commands.inferrepo += ' %s' % ' '.join(parsealiases(name))
2879 commands.inferrepo += ' %s' % ' '.join(parsealiases(name))
2827
2880
2828 return func
2881 return func
2829 return decorator
2882 return decorator
2830
2883
2831 return cmd
2884 return cmd
2832
2885
2833 # a list of (ui, repo, otherpeer, opts, missing) functions called by
2886 # a list of (ui, repo, otherpeer, opts, missing) functions called by
2834 # commands.outgoing. "missing" is "missing" of the result of
2887 # commands.outgoing. "missing" is "missing" of the result of
2835 # "findcommonoutgoing()"
2888 # "findcommonoutgoing()"
2836 outgoinghooks = util.hooks()
2889 outgoinghooks = util.hooks()
2837
2890
2838 # a list of (ui, repo) functions called by commands.summary
2891 # a list of (ui, repo) functions called by commands.summary
2839 summaryhooks = util.hooks()
2892 summaryhooks = util.hooks()
2840
2893
2841 # a list of (ui, repo, opts, changes) functions called by commands.summary.
2894 # a list of (ui, repo, opts, changes) functions called by commands.summary.
2842 #
2895 #
2843 # functions should return tuple of booleans below, if 'changes' is None:
2896 # functions should return tuple of booleans below, if 'changes' is None:
2844 # (whether-incomings-are-needed, whether-outgoings-are-needed)
2897 # (whether-incomings-are-needed, whether-outgoings-are-needed)
2845 #
2898 #
2846 # otherwise, 'changes' is a tuple of tuples below:
2899 # otherwise, 'changes' is a tuple of tuples below:
2847 # - (sourceurl, sourcebranch, sourcepeer, incoming)
2900 # - (sourceurl, sourcebranch, sourcepeer, incoming)
2848 # - (desturl, destbranch, destpeer, outgoing)
2901 # - (desturl, destbranch, destpeer, outgoing)
2849 summaryremotehooks = util.hooks()
2902 summaryremotehooks = util.hooks()
2850
2903
2851 # A list of state files kept by multistep operations like graft.
2904 # A list of state files kept by multistep operations like graft.
2852 # Since graft cannot be aborted, it is considered 'clearable' by update.
2905 # Since graft cannot be aborted, it is considered 'clearable' by update.
2853 # note: bisect is intentionally excluded
2906 # note: bisect is intentionally excluded
2854 # (state file, clearable, allowcommit, error, hint)
2907 # (state file, clearable, allowcommit, error, hint)
2855 unfinishedstates = [
2908 unfinishedstates = [
2856 ('graftstate', True, False, _('graft in progress'),
2909 ('graftstate', True, False, _('graft in progress'),
2857 _("use 'hg graft --continue' or 'hg update' to abort")),
2910 _("use 'hg graft --continue' or 'hg update' to abort")),
2858 ('updatestate', True, False, _('last update was interrupted'),
2911 ('updatestate', True, False, _('last update was interrupted'),
2859 _("use 'hg update' to get a consistent checkout"))
2912 _("use 'hg update' to get a consistent checkout"))
2860 ]
2913 ]
2861
2914
2862 def checkunfinished(repo, commit=False):
2915 def checkunfinished(repo, commit=False):
2863 '''Look for an unfinished multistep operation, like graft, and abort
2916 '''Look for an unfinished multistep operation, like graft, and abort
2864 if found. It's probably good to check this right before
2917 if found. It's probably good to check this right before
2865 bailifchanged().
2918 bailifchanged().
2866 '''
2919 '''
2867 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2920 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2868 if commit and allowcommit:
2921 if commit and allowcommit:
2869 continue
2922 continue
2870 if repo.vfs.exists(f):
2923 if repo.vfs.exists(f):
2871 raise util.Abort(msg, hint=hint)
2924 raise util.Abort(msg, hint=hint)
2872
2925
2873 def clearunfinished(repo):
2926 def clearunfinished(repo):
2874 '''Check for unfinished operations (as above), and clear the ones
2927 '''Check for unfinished operations (as above), and clear the ones
2875 that are clearable.
2928 that are clearable.
2876 '''
2929 '''
2877 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2930 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2878 if not clearable and repo.vfs.exists(f):
2931 if not clearable and repo.vfs.exists(f):
2879 raise util.Abort(msg, hint=hint)
2932 raise util.Abort(msg, hint=hint)
2880 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2933 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2881 if clearable and repo.vfs.exists(f):
2934 if clearable and repo.vfs.exists(f):
2882 util.unlink(repo.join(f))
2935 util.unlink(repo.join(f))
@@ -1,6302 +1,6252 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _
10 from i18n import _
11 import os, re, difflib, time, tempfile, errno, shlex
11 import os, re, difflib, time, tempfile, errno, shlex
12 import sys, socket
12 import sys, socket
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 import extensions
17 import extensions
18 from hgweb import server as hgweb_server
18 from hgweb import server as hgweb_server
19 import merge as mergemod
19 import merge as mergemod
20 import minirst, revset, fileset
20 import minirst, revset, fileset
21 import dagparser, context, simplemerge, graphmod, copies
21 import dagparser, context, simplemerge, graphmod, copies
22 import random
22 import random
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
24 import phases, obsolete, exchange
24 import phases, obsolete, exchange
25 import ui as uimod
25 import ui as uimod
26
26
27 table = {}
27 table = {}
28
28
29 command = cmdutil.command(table)
29 command = cmdutil.command(table)
30
30
31 # Space delimited list of commands that don't require local repositories.
31 # Space delimited list of commands that don't require local repositories.
32 # This should be populated by passing norepo=True into the @command decorator.
32 # This should be populated by passing norepo=True into the @command decorator.
33 norepo = ''
33 norepo = ''
34 # Space delimited list of commands that optionally require local repositories.
34 # Space delimited list of commands that optionally require local repositories.
35 # This should be populated by passing optionalrepo=True into the @command
35 # This should be populated by passing optionalrepo=True into the @command
36 # decorator.
36 # decorator.
37 optionalrepo = ''
37 optionalrepo = ''
38 # Space delimited list of commands that will examine arguments looking for
38 # Space delimited list of commands that will examine arguments looking for
39 # a repository. This should be populated by passing inferrepo=True into the
39 # a repository. This should be populated by passing inferrepo=True into the
40 # @command decorator.
40 # @command decorator.
41 inferrepo = ''
41 inferrepo = ''
42
42
43 # common command options
43 # common command options
44
44
45 globalopts = [
45 globalopts = [
46 ('R', 'repository', '',
46 ('R', 'repository', '',
47 _('repository root directory or name of overlay bundle file'),
47 _('repository root directory or name of overlay bundle file'),
48 _('REPO')),
48 _('REPO')),
49 ('', 'cwd', '',
49 ('', 'cwd', '',
50 _('change working directory'), _('DIR')),
50 _('change working directory'), _('DIR')),
51 ('y', 'noninteractive', None,
51 ('y', 'noninteractive', None,
52 _('do not prompt, automatically pick the first choice for all prompts')),
52 _('do not prompt, automatically pick the first choice for all prompts')),
53 ('q', 'quiet', None, _('suppress output')),
53 ('q', 'quiet', None, _('suppress output')),
54 ('v', 'verbose', None, _('enable additional output')),
54 ('v', 'verbose', None, _('enable additional output')),
55 ('', 'config', [],
55 ('', 'config', [],
56 _('set/override config option (use \'section.name=value\')'),
56 _('set/override config option (use \'section.name=value\')'),
57 _('CONFIG')),
57 _('CONFIG')),
58 ('', 'debug', None, _('enable debugging output')),
58 ('', 'debug', None, _('enable debugging output')),
59 ('', 'debugger', None, _('start debugger')),
59 ('', 'debugger', None, _('start debugger')),
60 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
60 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
61 _('ENCODE')),
61 _('ENCODE')),
62 ('', 'encodingmode', encoding.encodingmode,
62 ('', 'encodingmode', encoding.encodingmode,
63 _('set the charset encoding mode'), _('MODE')),
63 _('set the charset encoding mode'), _('MODE')),
64 ('', 'traceback', None, _('always print a traceback on exception')),
64 ('', 'traceback', None, _('always print a traceback on exception')),
65 ('', 'time', None, _('time how long the command takes')),
65 ('', 'time', None, _('time how long the command takes')),
66 ('', 'profile', None, _('print command execution profile')),
66 ('', 'profile', None, _('print command execution profile')),
67 ('', 'version', None, _('output version information and exit')),
67 ('', 'version', None, _('output version information and exit')),
68 ('h', 'help', None, _('display help and exit')),
68 ('h', 'help', None, _('display help and exit')),
69 ('', 'hidden', False, _('consider hidden changesets')),
69 ('', 'hidden', False, _('consider hidden changesets')),
70 ]
70 ]
71
71
72 dryrunopts = [('n', 'dry-run', None,
72 dryrunopts = [('n', 'dry-run', None,
73 _('do not perform actions, just print output'))]
73 _('do not perform actions, just print output'))]
74
74
75 remoteopts = [
75 remoteopts = [
76 ('e', 'ssh', '',
76 ('e', 'ssh', '',
77 _('specify ssh command to use'), _('CMD')),
77 _('specify ssh command to use'), _('CMD')),
78 ('', 'remotecmd', '',
78 ('', 'remotecmd', '',
79 _('specify hg command to run on the remote side'), _('CMD')),
79 _('specify hg command to run on the remote side'), _('CMD')),
80 ('', 'insecure', None,
80 ('', 'insecure', None,
81 _('do not verify server certificate (ignoring web.cacerts config)')),
81 _('do not verify server certificate (ignoring web.cacerts config)')),
82 ]
82 ]
83
83
84 walkopts = [
84 walkopts = [
85 ('I', 'include', [],
85 ('I', 'include', [],
86 _('include names matching the given patterns'), _('PATTERN')),
86 _('include names matching the given patterns'), _('PATTERN')),
87 ('X', 'exclude', [],
87 ('X', 'exclude', [],
88 _('exclude names matching the given patterns'), _('PATTERN')),
88 _('exclude names matching the given patterns'), _('PATTERN')),
89 ]
89 ]
90
90
91 commitopts = [
91 commitopts = [
92 ('m', 'message', '',
92 ('m', 'message', '',
93 _('use text as commit message'), _('TEXT')),
93 _('use text as commit message'), _('TEXT')),
94 ('l', 'logfile', '',
94 ('l', 'logfile', '',
95 _('read commit message from file'), _('FILE')),
95 _('read commit message from file'), _('FILE')),
96 ]
96 ]
97
97
98 commitopts2 = [
98 commitopts2 = [
99 ('d', 'date', '',
99 ('d', 'date', '',
100 _('record the specified date as commit date'), _('DATE')),
100 _('record the specified date as commit date'), _('DATE')),
101 ('u', 'user', '',
101 ('u', 'user', '',
102 _('record the specified user as committer'), _('USER')),
102 _('record the specified user as committer'), _('USER')),
103 ]
103 ]
104
104
105 # hidden for now
105 # hidden for now
106 formatteropts = [
106 formatteropts = [
107 ('T', 'template', '',
107 ('T', 'template', '',
108 _('display with template (DEPRECATED)'), _('TEMPLATE')),
108 _('display with template (DEPRECATED)'), _('TEMPLATE')),
109 ]
109 ]
110
110
111 templateopts = [
111 templateopts = [
112 ('', 'style', '',
112 ('', 'style', '',
113 _('display using template map file (DEPRECATED)'), _('STYLE')),
113 _('display using template map file (DEPRECATED)'), _('STYLE')),
114 ('T', 'template', '',
114 ('T', 'template', '',
115 _('display with template'), _('TEMPLATE')),
115 _('display with template'), _('TEMPLATE')),
116 ]
116 ]
117
117
118 logopts = [
118 logopts = [
119 ('p', 'patch', None, _('show patch')),
119 ('p', 'patch', None, _('show patch')),
120 ('g', 'git', None, _('use git extended diff format')),
120 ('g', 'git', None, _('use git extended diff format')),
121 ('l', 'limit', '',
121 ('l', 'limit', '',
122 _('limit number of changes displayed'), _('NUM')),
122 _('limit number of changes displayed'), _('NUM')),
123 ('M', 'no-merges', None, _('do not show merges')),
123 ('M', 'no-merges', None, _('do not show merges')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ('G', 'graph', None, _("show the revision DAG")),
125 ('G', 'graph', None, _("show the revision DAG")),
126 ] + templateopts
126 ] + templateopts
127
127
128 diffopts = [
128 diffopts = [
129 ('a', 'text', None, _('treat all files as text')),
129 ('a', 'text', None, _('treat all files as text')),
130 ('g', 'git', None, _('use git extended diff format')),
130 ('g', 'git', None, _('use git extended diff format')),
131 ('', 'nodates', None, _('omit dates from diff headers'))
131 ('', 'nodates', None, _('omit dates from diff headers'))
132 ]
132 ]
133
133
134 diffwsopts = [
134 diffwsopts = [
135 ('w', 'ignore-all-space', None,
135 ('w', 'ignore-all-space', None,
136 _('ignore white space when comparing lines')),
136 _('ignore white space when comparing lines')),
137 ('b', 'ignore-space-change', None,
137 ('b', 'ignore-space-change', None,
138 _('ignore changes in the amount of white space')),
138 _('ignore changes in the amount of white space')),
139 ('B', 'ignore-blank-lines', None,
139 ('B', 'ignore-blank-lines', None,
140 _('ignore changes whose lines are all blank')),
140 _('ignore changes whose lines are all blank')),
141 ]
141 ]
142
142
143 diffopts2 = [
143 diffopts2 = [
144 ('p', 'show-function', None, _('show which function each change is in')),
144 ('p', 'show-function', None, _('show which function each change is in')),
145 ('', 'reverse', None, _('produce a diff that undoes the changes')),
145 ('', 'reverse', None, _('produce a diff that undoes the changes')),
146 ] + diffwsopts + [
146 ] + diffwsopts + [
147 ('U', 'unified', '',
147 ('U', 'unified', '',
148 _('number of lines of context to show'), _('NUM')),
148 _('number of lines of context to show'), _('NUM')),
149 ('', 'stat', None, _('output diffstat-style summary of changes')),
149 ('', 'stat', None, _('output diffstat-style summary of changes')),
150 ]
150 ]
151
151
152 mergetoolopts = [
152 mergetoolopts = [
153 ('t', 'tool', '', _('specify merge tool')),
153 ('t', 'tool', '', _('specify merge tool')),
154 ]
154 ]
155
155
156 similarityopts = [
156 similarityopts = [
157 ('s', 'similarity', '',
157 ('s', 'similarity', '',
158 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
158 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
159 ]
159 ]
160
160
161 subrepoopts = [
161 subrepoopts = [
162 ('S', 'subrepos', None,
162 ('S', 'subrepos', None,
163 _('recurse into subrepositories'))
163 _('recurse into subrepositories'))
164 ]
164 ]
165
165
166 # Commands start here, listed alphabetically
166 # Commands start here, listed alphabetically
167
167
168 @command('^add',
168 @command('^add',
169 walkopts + subrepoopts + dryrunopts,
169 walkopts + subrepoopts + dryrunopts,
170 _('[OPTION]... [FILE]...'),
170 _('[OPTION]... [FILE]...'),
171 inferrepo=True)
171 inferrepo=True)
172 def add(ui, repo, *pats, **opts):
172 def add(ui, repo, *pats, **opts):
173 """add the specified files on the next commit
173 """add the specified files on the next commit
174
174
175 Schedule files to be version controlled and added to the
175 Schedule files to be version controlled and added to the
176 repository.
176 repository.
177
177
178 The files will be added to the repository at the next commit. To
178 The files will be added to the repository at the next commit. To
179 undo an add before that, see :hg:`forget`.
179 undo an add before that, see :hg:`forget`.
180
180
181 If no names are given, add all files to the repository.
181 If no names are given, add all files to the repository.
182
182
183 .. container:: verbose
183 .. container:: verbose
184
184
185 An example showing how new (unknown) files are added
185 An example showing how new (unknown) files are added
186 automatically by :hg:`add`::
186 automatically by :hg:`add`::
187
187
188 $ ls
188 $ ls
189 foo.c
189 foo.c
190 $ hg status
190 $ hg status
191 ? foo.c
191 ? foo.c
192 $ hg add
192 $ hg add
193 adding foo.c
193 adding foo.c
194 $ hg status
194 $ hg status
195 A foo.c
195 A foo.c
196
196
197 Returns 0 if all files are successfully added.
197 Returns 0 if all files are successfully added.
198 """
198 """
199
199
200 m = scmutil.match(repo[None], pats, opts)
200 m = scmutil.match(repo[None], pats, opts)
201 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
201 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
202 opts.get('subrepos'), prefix="", explicitonly=False)
202 opts.get('subrepos'), prefix="", explicitonly=False)
203 return rejected and 1 or 0
203 return rejected and 1 or 0
204
204
205 @command('addremove',
205 @command('addremove',
206 similarityopts + walkopts + dryrunopts,
206 similarityopts + walkopts + dryrunopts,
207 _('[OPTION]... [FILE]...'),
207 _('[OPTION]... [FILE]...'),
208 inferrepo=True)
208 inferrepo=True)
209 def addremove(ui, repo, *pats, **opts):
209 def addremove(ui, repo, *pats, **opts):
210 """add all new files, delete all missing files
210 """add all new files, delete all missing files
211
211
212 Add all new files and remove all missing files from the
212 Add all new files and remove all missing files from the
213 repository.
213 repository.
214
214
215 New files are ignored if they match any of the patterns in
215 New files are ignored if they match any of the patterns in
216 ``.hgignore``. As with add, these changes take effect at the next
216 ``.hgignore``. As with add, these changes take effect at the next
217 commit.
217 commit.
218
218
219 Use the -s/--similarity option to detect renamed files. This
219 Use the -s/--similarity option to detect renamed files. This
220 option takes a percentage between 0 (disabled) and 100 (files must
220 option takes a percentage between 0 (disabled) and 100 (files must
221 be identical) as its parameter. With a parameter greater than 0,
221 be identical) as its parameter. With a parameter greater than 0,
222 this compares every removed file with every added file and records
222 this compares every removed file with every added file and records
223 those similar enough as renames. Detecting renamed files this way
223 those similar enough as renames. Detecting renamed files this way
224 can be expensive. After using this option, :hg:`status -C` can be
224 can be expensive. After using this option, :hg:`status -C` can be
225 used to check which files were identified as moved or renamed. If
225 used to check which files were identified as moved or renamed. If
226 not specified, -s/--similarity defaults to 100 and only renames of
226 not specified, -s/--similarity defaults to 100 and only renames of
227 identical files are detected.
227 identical files are detected.
228
228
229 Returns 0 if all files are successfully added.
229 Returns 0 if all files are successfully added.
230 """
230 """
231 try:
231 try:
232 sim = float(opts.get('similarity') or 100)
232 sim = float(opts.get('similarity') or 100)
233 except ValueError:
233 except ValueError:
234 raise util.Abort(_('similarity must be a number'))
234 raise util.Abort(_('similarity must be a number'))
235 if sim < 0 or sim > 100:
235 if sim < 0 or sim > 100:
236 raise util.Abort(_('similarity must be between 0 and 100'))
236 raise util.Abort(_('similarity must be between 0 and 100'))
237 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
237 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
238
238
239 @command('^annotate|blame',
239 @command('^annotate|blame',
240 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
240 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
241 ('', 'follow', None,
241 ('', 'follow', None,
242 _('follow copies/renames and list the filename (DEPRECATED)')),
242 _('follow copies/renames and list the filename (DEPRECATED)')),
243 ('', 'no-follow', None, _("don't follow copies and renames")),
243 ('', 'no-follow', None, _("don't follow copies and renames")),
244 ('a', 'text', None, _('treat all files as text')),
244 ('a', 'text', None, _('treat all files as text')),
245 ('u', 'user', None, _('list the author (long with -v)')),
245 ('u', 'user', None, _('list the author (long with -v)')),
246 ('f', 'file', None, _('list the filename')),
246 ('f', 'file', None, _('list the filename')),
247 ('d', 'date', None, _('list the date (short with -q)')),
247 ('d', 'date', None, _('list the date (short with -q)')),
248 ('n', 'number', None, _('list the revision number (default)')),
248 ('n', 'number', None, _('list the revision number (default)')),
249 ('c', 'changeset', None, _('list the changeset')),
249 ('c', 'changeset', None, _('list the changeset')),
250 ('l', 'line-number', None, _('show line number at the first appearance'))
250 ('l', 'line-number', None, _('show line number at the first appearance'))
251 ] + diffwsopts + walkopts + formatteropts,
251 ] + diffwsopts + walkopts + formatteropts,
252 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
252 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
253 inferrepo=True)
253 inferrepo=True)
254 def annotate(ui, repo, *pats, **opts):
254 def annotate(ui, repo, *pats, **opts):
255 """show changeset information by line for each file
255 """show changeset information by line for each file
256
256
257 List changes in files, showing the revision id responsible for
257 List changes in files, showing the revision id responsible for
258 each line
258 each line
259
259
260 This command is useful for discovering when a change was made and
260 This command is useful for discovering when a change was made and
261 by whom.
261 by whom.
262
262
263 Without the -a/--text option, annotate will avoid processing files
263 Without the -a/--text option, annotate will avoid processing files
264 it detects as binary. With -a, annotate will annotate the file
264 it detects as binary. With -a, annotate will annotate the file
265 anyway, although the results will probably be neither useful
265 anyway, although the results will probably be neither useful
266 nor desirable.
266 nor desirable.
267
267
268 Returns 0 on success.
268 Returns 0 on success.
269 """
269 """
270 if not pats:
270 if not pats:
271 raise util.Abort(_('at least one filename or pattern is required'))
271 raise util.Abort(_('at least one filename or pattern is required'))
272
272
273 if opts.get('follow'):
273 if opts.get('follow'):
274 # --follow is deprecated and now just an alias for -f/--file
274 # --follow is deprecated and now just an alias for -f/--file
275 # to mimic the behavior of Mercurial before version 1.5
275 # to mimic the behavior of Mercurial before version 1.5
276 opts['file'] = True
276 opts['file'] = True
277
277
278 fm = ui.formatter('annotate', opts)
278 fm = ui.formatter('annotate', opts)
279 datefunc = ui.quiet and util.shortdate or util.datestr
279 datefunc = ui.quiet and util.shortdate or util.datestr
280 hexfn = fm.hexfunc
280 hexfn = fm.hexfunc
281
281
282 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
282 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
283 ('number', ' ', lambda x: x[0].rev(), str),
283 ('number', ' ', lambda x: x[0].rev(), str),
284 ('changeset', ' ', lambda x: hexfn(x[0].node()), str),
284 ('changeset', ' ', lambda x: hexfn(x[0].node()), str),
285 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
285 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
286 ('file', ' ', lambda x: x[0].path(), str),
286 ('file', ' ', lambda x: x[0].path(), str),
287 ('line_number', ':', lambda x: x[1], str),
287 ('line_number', ':', lambda x: x[1], str),
288 ]
288 ]
289 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
289 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
290
290
291 if (not opts.get('user') and not opts.get('changeset')
291 if (not opts.get('user') and not opts.get('changeset')
292 and not opts.get('date') and not opts.get('file')):
292 and not opts.get('date') and not opts.get('file')):
293 opts['number'] = True
293 opts['number'] = True
294
294
295 linenumber = opts.get('line_number') is not None
295 linenumber = opts.get('line_number') is not None
296 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
296 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
297 raise util.Abort(_('at least one of -n/-c is required for -l'))
297 raise util.Abort(_('at least one of -n/-c is required for -l'))
298
298
299 if fm:
299 if fm:
300 def makefunc(get, fmt):
300 def makefunc(get, fmt):
301 return get
301 return get
302 else:
302 else:
303 def makefunc(get, fmt):
303 def makefunc(get, fmt):
304 return lambda x: fmt(get(x))
304 return lambda x: fmt(get(x))
305 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
305 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
306 if opts.get(op)]
306 if opts.get(op)]
307 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
307 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
308 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
308 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
309 if opts.get(op))
309 if opts.get(op))
310
310
311 def bad(x, y):
311 def bad(x, y):
312 raise util.Abort("%s: %s" % (x, y))
312 raise util.Abort("%s: %s" % (x, y))
313
313
314 ctx = scmutil.revsingle(repo, opts.get('rev'))
314 ctx = scmutil.revsingle(repo, opts.get('rev'))
315 m = scmutil.match(ctx, pats, opts)
315 m = scmutil.match(ctx, pats, opts)
316 m.bad = bad
316 m.bad = bad
317 follow = not opts.get('no_follow')
317 follow = not opts.get('no_follow')
318 diffopts = patch.diffopts(ui, opts, section='annotate')
318 diffopts = patch.diffopts(ui, opts, section='annotate')
319 for abs in ctx.walk(m):
319 for abs in ctx.walk(m):
320 fctx = ctx[abs]
320 fctx = ctx[abs]
321 if not opts.get('text') and util.binary(fctx.data()):
321 if not opts.get('text') and util.binary(fctx.data()):
322 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
322 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
323 continue
323 continue
324
324
325 lines = fctx.annotate(follow=follow, linenumber=linenumber,
325 lines = fctx.annotate(follow=follow, linenumber=linenumber,
326 diffopts=diffopts)
326 diffopts=diffopts)
327 formats = []
327 formats = []
328 pieces = []
328 pieces = []
329
329
330 for f, sep in funcmap:
330 for f, sep in funcmap:
331 l = [f(n) for n, dummy in lines]
331 l = [f(n) for n, dummy in lines]
332 if l:
332 if l:
333 if fm:
333 if fm:
334 formats.append(['%s' for x in l])
334 formats.append(['%s' for x in l])
335 else:
335 else:
336 sizes = [encoding.colwidth(x) for x in l]
336 sizes = [encoding.colwidth(x) for x in l]
337 ml = max(sizes)
337 ml = max(sizes)
338 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
338 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
339 pieces.append(l)
339 pieces.append(l)
340
340
341 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
341 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
342 fm.startitem()
342 fm.startitem()
343 fm.write(fields, "".join(f), *p)
343 fm.write(fields, "".join(f), *p)
344 fm.write('line', ": %s", l[1])
344 fm.write('line', ": %s", l[1])
345
345
346 if lines and not lines[-1][1].endswith('\n'):
346 if lines and not lines[-1][1].endswith('\n'):
347 fm.plain('\n')
347 fm.plain('\n')
348
348
349 fm.end()
349 fm.end()
350
350
351 @command('archive',
351 @command('archive',
352 [('', 'no-decode', None, _('do not pass files through decoders')),
352 [('', 'no-decode', None, _('do not pass files through decoders')),
353 ('p', 'prefix', '', _('directory prefix for files in archive'),
353 ('p', 'prefix', '', _('directory prefix for files in archive'),
354 _('PREFIX')),
354 _('PREFIX')),
355 ('r', 'rev', '', _('revision to distribute'), _('REV')),
355 ('r', 'rev', '', _('revision to distribute'), _('REV')),
356 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
356 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
357 ] + subrepoopts + walkopts,
357 ] + subrepoopts + walkopts,
358 _('[OPTION]... DEST'))
358 _('[OPTION]... DEST'))
359 def archive(ui, repo, dest, **opts):
359 def archive(ui, repo, dest, **opts):
360 '''create an unversioned archive of a repository revision
360 '''create an unversioned archive of a repository revision
361
361
362 By default, the revision used is the parent of the working
362 By default, the revision used is the parent of the working
363 directory; use -r/--rev to specify a different revision.
363 directory; use -r/--rev to specify a different revision.
364
364
365 The archive type is automatically detected based on file
365 The archive type is automatically detected based on file
366 extension (or override using -t/--type).
366 extension (or override using -t/--type).
367
367
368 .. container:: verbose
368 .. container:: verbose
369
369
370 Examples:
370 Examples:
371
371
372 - create a zip file containing the 1.0 release::
372 - create a zip file containing the 1.0 release::
373
373
374 hg archive -r 1.0 project-1.0.zip
374 hg archive -r 1.0 project-1.0.zip
375
375
376 - create a tarball excluding .hg files::
376 - create a tarball excluding .hg files::
377
377
378 hg archive project.tar.gz -X ".hg*"
378 hg archive project.tar.gz -X ".hg*"
379
379
380 Valid types are:
380 Valid types are:
381
381
382 :``files``: a directory full of files (default)
382 :``files``: a directory full of files (default)
383 :``tar``: tar archive, uncompressed
383 :``tar``: tar archive, uncompressed
384 :``tbz2``: tar archive, compressed using bzip2
384 :``tbz2``: tar archive, compressed using bzip2
385 :``tgz``: tar archive, compressed using gzip
385 :``tgz``: tar archive, compressed using gzip
386 :``uzip``: zip archive, uncompressed
386 :``uzip``: zip archive, uncompressed
387 :``zip``: zip archive, compressed using deflate
387 :``zip``: zip archive, compressed using deflate
388
388
389 The exact name of the destination archive or directory is given
389 The exact name of the destination archive or directory is given
390 using a format string; see :hg:`help export` for details.
390 using a format string; see :hg:`help export` for details.
391
391
392 Each member added to an archive file has a directory prefix
392 Each member added to an archive file has a directory prefix
393 prepended. Use -p/--prefix to specify a format string for the
393 prepended. Use -p/--prefix to specify a format string for the
394 prefix. The default is the basename of the archive, with suffixes
394 prefix. The default is the basename of the archive, with suffixes
395 removed.
395 removed.
396
396
397 Returns 0 on success.
397 Returns 0 on success.
398 '''
398 '''
399
399
400 ctx = scmutil.revsingle(repo, opts.get('rev'))
400 ctx = scmutil.revsingle(repo, opts.get('rev'))
401 if not ctx:
401 if not ctx:
402 raise util.Abort(_('no working directory: please specify a revision'))
402 raise util.Abort(_('no working directory: please specify a revision'))
403 node = ctx.node()
403 node = ctx.node()
404 dest = cmdutil.makefilename(repo, dest, node)
404 dest = cmdutil.makefilename(repo, dest, node)
405 if os.path.realpath(dest) == repo.root:
405 if os.path.realpath(dest) == repo.root:
406 raise util.Abort(_('repository root cannot be destination'))
406 raise util.Abort(_('repository root cannot be destination'))
407
407
408 kind = opts.get('type') or archival.guesskind(dest) or 'files'
408 kind = opts.get('type') or archival.guesskind(dest) or 'files'
409 prefix = opts.get('prefix')
409 prefix = opts.get('prefix')
410
410
411 if dest == '-':
411 if dest == '-':
412 if kind == 'files':
412 if kind == 'files':
413 raise util.Abort(_('cannot archive plain files to stdout'))
413 raise util.Abort(_('cannot archive plain files to stdout'))
414 dest = cmdutil.makefileobj(repo, dest)
414 dest = cmdutil.makefileobj(repo, dest)
415 if not prefix:
415 if not prefix:
416 prefix = os.path.basename(repo.root) + '-%h'
416 prefix = os.path.basename(repo.root) + '-%h'
417
417
418 prefix = cmdutil.makefilename(repo, prefix, node)
418 prefix = cmdutil.makefilename(repo, prefix, node)
419 matchfn = scmutil.match(ctx, [], opts)
419 matchfn = scmutil.match(ctx, [], opts)
420 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
420 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
421 matchfn, prefix, subrepos=opts.get('subrepos'))
421 matchfn, prefix, subrepos=opts.get('subrepos'))
422
422
423 @command('backout',
423 @command('backout',
424 [('', 'merge', None, _('merge with old dirstate parent after backout')),
424 [('', 'merge', None, _('merge with old dirstate parent after backout')),
425 ('', 'parent', '',
425 ('', 'parent', '',
426 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
426 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
427 ('r', 'rev', '', _('revision to backout'), _('REV')),
427 ('r', 'rev', '', _('revision to backout'), _('REV')),
428 ('e', 'edit', False, _('invoke editor on commit messages')),
428 ('e', 'edit', False, _('invoke editor on commit messages')),
429 ] + mergetoolopts + walkopts + commitopts + commitopts2,
429 ] + mergetoolopts + walkopts + commitopts + commitopts2,
430 _('[OPTION]... [-r] REV'))
430 _('[OPTION]... [-r] REV'))
431 def backout(ui, repo, node=None, rev=None, **opts):
431 def backout(ui, repo, node=None, rev=None, **opts):
432 '''reverse effect of earlier changeset
432 '''reverse effect of earlier changeset
433
433
434 Prepare a new changeset with the effect of REV undone in the
434 Prepare a new changeset with the effect of REV undone in the
435 current working directory.
435 current working directory.
436
436
437 If REV is the parent of the working directory, then this new changeset
437 If REV is the parent of the working directory, then this new changeset
438 is committed automatically. Otherwise, hg needs to merge the
438 is committed automatically. Otherwise, hg needs to merge the
439 changes and the merged result is left uncommitted.
439 changes and the merged result is left uncommitted.
440
440
441 .. note::
441 .. note::
442
442
443 backout cannot be used to fix either an unwanted or
443 backout cannot be used to fix either an unwanted or
444 incorrect merge.
444 incorrect merge.
445
445
446 .. container:: verbose
446 .. container:: verbose
447
447
448 By default, the pending changeset will have one parent,
448 By default, the pending changeset will have one parent,
449 maintaining a linear history. With --merge, the pending
449 maintaining a linear history. With --merge, the pending
450 changeset will instead have two parents: the old parent of the
450 changeset will instead have two parents: the old parent of the
451 working directory and a new child of REV that simply undoes REV.
451 working directory and a new child of REV that simply undoes REV.
452
452
453 Before version 1.7, the behavior without --merge was equivalent
453 Before version 1.7, the behavior without --merge was equivalent
454 to specifying --merge followed by :hg:`update --clean .` to
454 to specifying --merge followed by :hg:`update --clean .` to
455 cancel the merge and leave the child of REV as a head to be
455 cancel the merge and leave the child of REV as a head to be
456 merged separately.
456 merged separately.
457
457
458 See :hg:`help dates` for a list of formats valid for -d/--date.
458 See :hg:`help dates` for a list of formats valid for -d/--date.
459
459
460 Returns 0 on success, 1 if nothing to backout or there are unresolved
460 Returns 0 on success, 1 if nothing to backout or there are unresolved
461 files.
461 files.
462 '''
462 '''
463 if rev and node:
463 if rev and node:
464 raise util.Abort(_("please specify just one revision"))
464 raise util.Abort(_("please specify just one revision"))
465
465
466 if not rev:
466 if not rev:
467 rev = node
467 rev = node
468
468
469 if not rev:
469 if not rev:
470 raise util.Abort(_("please specify a revision to backout"))
470 raise util.Abort(_("please specify a revision to backout"))
471
471
472 date = opts.get('date')
472 date = opts.get('date')
473 if date:
473 if date:
474 opts['date'] = util.parsedate(date)
474 opts['date'] = util.parsedate(date)
475
475
476 cmdutil.checkunfinished(repo)
476 cmdutil.checkunfinished(repo)
477 cmdutil.bailifchanged(repo)
477 cmdutil.bailifchanged(repo)
478 node = scmutil.revsingle(repo, rev).node()
478 node = scmutil.revsingle(repo, rev).node()
479
479
480 op1, op2 = repo.dirstate.parents()
480 op1, op2 = repo.dirstate.parents()
481 if not repo.changelog.isancestor(node, op1):
481 if not repo.changelog.isancestor(node, op1):
482 raise util.Abort(_('cannot backout change that is not an ancestor'))
482 raise util.Abort(_('cannot backout change that is not an ancestor'))
483
483
484 p1, p2 = repo.changelog.parents(node)
484 p1, p2 = repo.changelog.parents(node)
485 if p1 == nullid:
485 if p1 == nullid:
486 raise util.Abort(_('cannot backout a change with no parents'))
486 raise util.Abort(_('cannot backout a change with no parents'))
487 if p2 != nullid:
487 if p2 != nullid:
488 if not opts.get('parent'):
488 if not opts.get('parent'):
489 raise util.Abort(_('cannot backout a merge changeset'))
489 raise util.Abort(_('cannot backout a merge changeset'))
490 p = repo.lookup(opts['parent'])
490 p = repo.lookup(opts['parent'])
491 if p not in (p1, p2):
491 if p not in (p1, p2):
492 raise util.Abort(_('%s is not a parent of %s') %
492 raise util.Abort(_('%s is not a parent of %s') %
493 (short(p), short(node)))
493 (short(p), short(node)))
494 parent = p
494 parent = p
495 else:
495 else:
496 if opts.get('parent'):
496 if opts.get('parent'):
497 raise util.Abort(_('cannot use --parent on non-merge changeset'))
497 raise util.Abort(_('cannot use --parent on non-merge changeset'))
498 parent = p1
498 parent = p1
499
499
500 # the backout should appear on the same branch
500 # the backout should appear on the same branch
501 wlock = repo.wlock()
501 wlock = repo.wlock()
502 try:
502 try:
503 branch = repo.dirstate.branch()
503 branch = repo.dirstate.branch()
504 bheads = repo.branchheads(branch)
504 bheads = repo.branchheads(branch)
505 rctx = scmutil.revsingle(repo, hex(parent))
505 rctx = scmutil.revsingle(repo, hex(parent))
506 if not opts.get('merge') and op1 != node:
506 if not opts.get('merge') and op1 != node:
507 try:
507 try:
508 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
508 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
509 'backout')
509 'backout')
510 repo.dirstate.beginparentchange()
510 repo.dirstate.beginparentchange()
511 stats = mergemod.update(repo, parent, True, True, False,
511 stats = mergemod.update(repo, parent, True, True, False,
512 node, False)
512 node, False)
513 repo.setparents(op1, op2)
513 repo.setparents(op1, op2)
514 repo.dirstate.endparentchange()
514 repo.dirstate.endparentchange()
515 hg._showstats(repo, stats)
515 hg._showstats(repo, stats)
516 if stats[3]:
516 if stats[3]:
517 repo.ui.status(_("use 'hg resolve' to retry unresolved "
517 repo.ui.status(_("use 'hg resolve' to retry unresolved "
518 "file merges\n"))
518 "file merges\n"))
519 else:
519 else:
520 msg = _("changeset %s backed out, "
520 msg = _("changeset %s backed out, "
521 "don't forget to commit.\n")
521 "don't forget to commit.\n")
522 ui.status(msg % short(node))
522 ui.status(msg % short(node))
523 return stats[3] > 0
523 return stats[3] > 0
524 finally:
524 finally:
525 ui.setconfig('ui', 'forcemerge', '', '')
525 ui.setconfig('ui', 'forcemerge', '', '')
526 else:
526 else:
527 hg.clean(repo, node, show_stats=False)
527 hg.clean(repo, node, show_stats=False)
528 repo.dirstate.setbranch(branch)
528 repo.dirstate.setbranch(branch)
529 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
529 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
530
530
531
531
532 def commitfunc(ui, repo, message, match, opts):
532 def commitfunc(ui, repo, message, match, opts):
533 editform = 'backout'
533 editform = 'backout'
534 e = cmdutil.getcommiteditor(editform=editform, **opts)
534 e = cmdutil.getcommiteditor(editform=editform, **opts)
535 if not message:
535 if not message:
536 # we don't translate commit messages
536 # we don't translate commit messages
537 message = "Backed out changeset %s" % short(node)
537 message = "Backed out changeset %s" % short(node)
538 e = cmdutil.getcommiteditor(edit=True, editform=editform)
538 e = cmdutil.getcommiteditor(edit=True, editform=editform)
539 return repo.commit(message, opts.get('user'), opts.get('date'),
539 return repo.commit(message, opts.get('user'), opts.get('date'),
540 match, editor=e)
540 match, editor=e)
541 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
541 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
542 if not newnode:
542 if not newnode:
543 ui.status(_("nothing changed\n"))
543 ui.status(_("nothing changed\n"))
544 return 1
544 return 1
545 cmdutil.commitstatus(repo, newnode, branch, bheads)
545 cmdutil.commitstatus(repo, newnode, branch, bheads)
546
546
547 def nice(node):
547 def nice(node):
548 return '%d:%s' % (repo.changelog.rev(node), short(node))
548 return '%d:%s' % (repo.changelog.rev(node), short(node))
549 ui.status(_('changeset %s backs out changeset %s\n') %
549 ui.status(_('changeset %s backs out changeset %s\n') %
550 (nice(repo.changelog.tip()), nice(node)))
550 (nice(repo.changelog.tip()), nice(node)))
551 if opts.get('merge') and op1 != node:
551 if opts.get('merge') and op1 != node:
552 hg.clean(repo, op1, show_stats=False)
552 hg.clean(repo, op1, show_stats=False)
553 ui.status(_('merging with changeset %s\n')
553 ui.status(_('merging with changeset %s\n')
554 % nice(repo.changelog.tip()))
554 % nice(repo.changelog.tip()))
555 try:
555 try:
556 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
556 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
557 'backout')
557 'backout')
558 return hg.merge(repo, hex(repo.changelog.tip()))
558 return hg.merge(repo, hex(repo.changelog.tip()))
559 finally:
559 finally:
560 ui.setconfig('ui', 'forcemerge', '', '')
560 ui.setconfig('ui', 'forcemerge', '', '')
561 finally:
561 finally:
562 wlock.release()
562 wlock.release()
563 return 0
563 return 0
564
564
565 @command('bisect',
565 @command('bisect',
566 [('r', 'reset', False, _('reset bisect state')),
566 [('r', 'reset', False, _('reset bisect state')),
567 ('g', 'good', False, _('mark changeset good')),
567 ('g', 'good', False, _('mark changeset good')),
568 ('b', 'bad', False, _('mark changeset bad')),
568 ('b', 'bad', False, _('mark changeset bad')),
569 ('s', 'skip', False, _('skip testing changeset')),
569 ('s', 'skip', False, _('skip testing changeset')),
570 ('e', 'extend', False, _('extend the bisect range')),
570 ('e', 'extend', False, _('extend the bisect range')),
571 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
571 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
572 ('U', 'noupdate', False, _('do not update to target'))],
572 ('U', 'noupdate', False, _('do not update to target'))],
573 _("[-gbsr] [-U] [-c CMD] [REV]"))
573 _("[-gbsr] [-U] [-c CMD] [REV]"))
574 def bisect(ui, repo, rev=None, extra=None, command=None,
574 def bisect(ui, repo, rev=None, extra=None, command=None,
575 reset=None, good=None, bad=None, skip=None, extend=None,
575 reset=None, good=None, bad=None, skip=None, extend=None,
576 noupdate=None):
576 noupdate=None):
577 """subdivision search of changesets
577 """subdivision search of changesets
578
578
579 This command helps to find changesets which introduce problems. To
579 This command helps to find changesets which introduce problems. To
580 use, mark the earliest changeset you know exhibits the problem as
580 use, mark the earliest changeset you know exhibits the problem as
581 bad, then mark the latest changeset which is free from the problem
581 bad, then mark the latest changeset which is free from the problem
582 as good. Bisect will update your working directory to a revision
582 as good. Bisect will update your working directory to a revision
583 for testing (unless the -U/--noupdate option is specified). Once
583 for testing (unless the -U/--noupdate option is specified). Once
584 you have performed tests, mark the working directory as good or
584 you have performed tests, mark the working directory as good or
585 bad, and bisect will either update to another candidate changeset
585 bad, and bisect will either update to another candidate changeset
586 or announce that it has found the bad revision.
586 or announce that it has found the bad revision.
587
587
588 As a shortcut, you can also use the revision argument to mark a
588 As a shortcut, you can also use the revision argument to mark a
589 revision as good or bad without checking it out first.
589 revision as good or bad without checking it out first.
590
590
591 If you supply a command, it will be used for automatic bisection.
591 If you supply a command, it will be used for automatic bisection.
592 The environment variable HG_NODE will contain the ID of the
592 The environment variable HG_NODE will contain the ID of the
593 changeset being tested. The exit status of the command will be
593 changeset being tested. The exit status of the command will be
594 used to mark revisions as good or bad: status 0 means good, 125
594 used to mark revisions as good or bad: status 0 means good, 125
595 means to skip the revision, 127 (command not found) will abort the
595 means to skip the revision, 127 (command not found) will abort the
596 bisection, and any other non-zero exit status means the revision
596 bisection, and any other non-zero exit status means the revision
597 is bad.
597 is bad.
598
598
599 .. container:: verbose
599 .. container:: verbose
600
600
601 Some examples:
601 Some examples:
602
602
603 - start a bisection with known bad revision 34, and good revision 12::
603 - start a bisection with known bad revision 34, and good revision 12::
604
604
605 hg bisect --bad 34
605 hg bisect --bad 34
606 hg bisect --good 12
606 hg bisect --good 12
607
607
608 - advance the current bisection by marking current revision as good or
608 - advance the current bisection by marking current revision as good or
609 bad::
609 bad::
610
610
611 hg bisect --good
611 hg bisect --good
612 hg bisect --bad
612 hg bisect --bad
613
613
614 - mark the current revision, or a known revision, to be skipped (e.g. if
614 - mark the current revision, or a known revision, to be skipped (e.g. if
615 that revision is not usable because of another issue)::
615 that revision is not usable because of another issue)::
616
616
617 hg bisect --skip
617 hg bisect --skip
618 hg bisect --skip 23
618 hg bisect --skip 23
619
619
620 - skip all revisions that do not touch directories ``foo`` or ``bar``::
620 - skip all revisions that do not touch directories ``foo`` or ``bar``::
621
621
622 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
622 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
623
623
624 - forget the current bisection::
624 - forget the current bisection::
625
625
626 hg bisect --reset
626 hg bisect --reset
627
627
628 - use 'make && make tests' to automatically find the first broken
628 - use 'make && make tests' to automatically find the first broken
629 revision::
629 revision::
630
630
631 hg bisect --reset
631 hg bisect --reset
632 hg bisect --bad 34
632 hg bisect --bad 34
633 hg bisect --good 12
633 hg bisect --good 12
634 hg bisect --command "make && make tests"
634 hg bisect --command "make && make tests"
635
635
636 - see all changesets whose states are already known in the current
636 - see all changesets whose states are already known in the current
637 bisection::
637 bisection::
638
638
639 hg log -r "bisect(pruned)"
639 hg log -r "bisect(pruned)"
640
640
641 - see the changeset currently being bisected (especially useful
641 - see the changeset currently being bisected (especially useful
642 if running with -U/--noupdate)::
642 if running with -U/--noupdate)::
643
643
644 hg log -r "bisect(current)"
644 hg log -r "bisect(current)"
645
645
646 - see all changesets that took part in the current bisection::
646 - see all changesets that took part in the current bisection::
647
647
648 hg log -r "bisect(range)"
648 hg log -r "bisect(range)"
649
649
650 - you can even get a nice graph::
650 - you can even get a nice graph::
651
651
652 hg log --graph -r "bisect(range)"
652 hg log --graph -r "bisect(range)"
653
653
654 See :hg:`help revsets` for more about the `bisect()` keyword.
654 See :hg:`help revsets` for more about the `bisect()` keyword.
655
655
656 Returns 0 on success.
656 Returns 0 on success.
657 """
657 """
658 def extendbisectrange(nodes, good):
658 def extendbisectrange(nodes, good):
659 # bisect is incomplete when it ends on a merge node and
659 # bisect is incomplete when it ends on a merge node and
660 # one of the parent was not checked.
660 # one of the parent was not checked.
661 parents = repo[nodes[0]].parents()
661 parents = repo[nodes[0]].parents()
662 if len(parents) > 1:
662 if len(parents) > 1:
663 side = good and state['bad'] or state['good']
663 side = good and state['bad'] or state['good']
664 num = len(set(i.node() for i in parents) & set(side))
664 num = len(set(i.node() for i in parents) & set(side))
665 if num == 1:
665 if num == 1:
666 return parents[0].ancestor(parents[1])
666 return parents[0].ancestor(parents[1])
667 return None
667 return None
668
668
669 def print_result(nodes, good):
669 def print_result(nodes, good):
670 displayer = cmdutil.show_changeset(ui, repo, {})
670 displayer = cmdutil.show_changeset(ui, repo, {})
671 if len(nodes) == 1:
671 if len(nodes) == 1:
672 # narrowed it down to a single revision
672 # narrowed it down to a single revision
673 if good:
673 if good:
674 ui.write(_("The first good revision is:\n"))
674 ui.write(_("The first good revision is:\n"))
675 else:
675 else:
676 ui.write(_("The first bad revision is:\n"))
676 ui.write(_("The first bad revision is:\n"))
677 displayer.show(repo[nodes[0]])
677 displayer.show(repo[nodes[0]])
678 extendnode = extendbisectrange(nodes, good)
678 extendnode = extendbisectrange(nodes, good)
679 if extendnode is not None:
679 if extendnode is not None:
680 ui.write(_('Not all ancestors of this changeset have been'
680 ui.write(_('Not all ancestors of this changeset have been'
681 ' checked.\nUse bisect --extend to continue the '
681 ' checked.\nUse bisect --extend to continue the '
682 'bisection from\nthe common ancestor, %s.\n')
682 'bisection from\nthe common ancestor, %s.\n')
683 % extendnode)
683 % extendnode)
684 else:
684 else:
685 # multiple possible revisions
685 # multiple possible revisions
686 if good:
686 if good:
687 ui.write(_("Due to skipped revisions, the first "
687 ui.write(_("Due to skipped revisions, the first "
688 "good revision could be any of:\n"))
688 "good revision could be any of:\n"))
689 else:
689 else:
690 ui.write(_("Due to skipped revisions, the first "
690 ui.write(_("Due to skipped revisions, the first "
691 "bad revision could be any of:\n"))
691 "bad revision could be any of:\n"))
692 for n in nodes:
692 for n in nodes:
693 displayer.show(repo[n])
693 displayer.show(repo[n])
694 displayer.close()
694 displayer.close()
695
695
696 def check_state(state, interactive=True):
696 def check_state(state, interactive=True):
697 if not state['good'] or not state['bad']:
697 if not state['good'] or not state['bad']:
698 if (good or bad or skip or reset) and interactive:
698 if (good or bad or skip or reset) and interactive:
699 return
699 return
700 if not state['good']:
700 if not state['good']:
701 raise util.Abort(_('cannot bisect (no known good revisions)'))
701 raise util.Abort(_('cannot bisect (no known good revisions)'))
702 else:
702 else:
703 raise util.Abort(_('cannot bisect (no known bad revisions)'))
703 raise util.Abort(_('cannot bisect (no known bad revisions)'))
704 return True
704 return True
705
705
706 # backward compatibility
706 # backward compatibility
707 if rev in "good bad reset init".split():
707 if rev in "good bad reset init".split():
708 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
708 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
709 cmd, rev, extra = rev, extra, None
709 cmd, rev, extra = rev, extra, None
710 if cmd == "good":
710 if cmd == "good":
711 good = True
711 good = True
712 elif cmd == "bad":
712 elif cmd == "bad":
713 bad = True
713 bad = True
714 else:
714 else:
715 reset = True
715 reset = True
716 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
716 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
717 raise util.Abort(_('incompatible arguments'))
717 raise util.Abort(_('incompatible arguments'))
718
718
719 cmdutil.checkunfinished(repo)
719 cmdutil.checkunfinished(repo)
720
720
721 if reset:
721 if reset:
722 p = repo.join("bisect.state")
722 p = repo.join("bisect.state")
723 if os.path.exists(p):
723 if os.path.exists(p):
724 os.unlink(p)
724 os.unlink(p)
725 return
725 return
726
726
727 state = hbisect.load_state(repo)
727 state = hbisect.load_state(repo)
728
728
729 if command:
729 if command:
730 changesets = 1
730 changesets = 1
731 if noupdate:
731 if noupdate:
732 try:
732 try:
733 node = state['current'][0]
733 node = state['current'][0]
734 except LookupError:
734 except LookupError:
735 raise util.Abort(_('current bisect revision is unknown - '
735 raise util.Abort(_('current bisect revision is unknown - '
736 'start a new bisect to fix'))
736 'start a new bisect to fix'))
737 else:
737 else:
738 node, p2 = repo.dirstate.parents()
738 node, p2 = repo.dirstate.parents()
739 if p2 != nullid:
739 if p2 != nullid:
740 raise util.Abort(_('current bisect revision is a merge'))
740 raise util.Abort(_('current bisect revision is a merge'))
741 try:
741 try:
742 while changesets:
742 while changesets:
743 # update state
743 # update state
744 state['current'] = [node]
744 state['current'] = [node]
745 hbisect.save_state(repo, state)
745 hbisect.save_state(repo, state)
746 status = ui.system(command, environ={'HG_NODE': hex(node)})
746 status = ui.system(command, environ={'HG_NODE': hex(node)})
747 if status == 125:
747 if status == 125:
748 transition = "skip"
748 transition = "skip"
749 elif status == 0:
749 elif status == 0:
750 transition = "good"
750 transition = "good"
751 # status < 0 means process was killed
751 # status < 0 means process was killed
752 elif status == 127:
752 elif status == 127:
753 raise util.Abort(_("failed to execute %s") % command)
753 raise util.Abort(_("failed to execute %s") % command)
754 elif status < 0:
754 elif status < 0:
755 raise util.Abort(_("%s killed") % command)
755 raise util.Abort(_("%s killed") % command)
756 else:
756 else:
757 transition = "bad"
757 transition = "bad"
758 ctx = scmutil.revsingle(repo, rev, node)
758 ctx = scmutil.revsingle(repo, rev, node)
759 rev = None # clear for future iterations
759 rev = None # clear for future iterations
760 state[transition].append(ctx.node())
760 state[transition].append(ctx.node())
761 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
761 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
762 check_state(state, interactive=False)
762 check_state(state, interactive=False)
763 # bisect
763 # bisect
764 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
764 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
765 # update to next check
765 # update to next check
766 node = nodes[0]
766 node = nodes[0]
767 if not noupdate:
767 if not noupdate:
768 cmdutil.bailifchanged(repo)
768 cmdutil.bailifchanged(repo)
769 hg.clean(repo, node, show_stats=False)
769 hg.clean(repo, node, show_stats=False)
770 finally:
770 finally:
771 state['current'] = [node]
771 state['current'] = [node]
772 hbisect.save_state(repo, state)
772 hbisect.save_state(repo, state)
773 print_result(nodes, bgood)
773 print_result(nodes, bgood)
774 return
774 return
775
775
776 # update state
776 # update state
777
777
778 if rev:
778 if rev:
779 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
779 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
780 else:
780 else:
781 nodes = [repo.lookup('.')]
781 nodes = [repo.lookup('.')]
782
782
783 if good or bad or skip:
783 if good or bad or skip:
784 if good:
784 if good:
785 state['good'] += nodes
785 state['good'] += nodes
786 elif bad:
786 elif bad:
787 state['bad'] += nodes
787 state['bad'] += nodes
788 elif skip:
788 elif skip:
789 state['skip'] += nodes
789 state['skip'] += nodes
790 hbisect.save_state(repo, state)
790 hbisect.save_state(repo, state)
791
791
792 if not check_state(state):
792 if not check_state(state):
793 return
793 return
794
794
795 # actually bisect
795 # actually bisect
796 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
796 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
797 if extend:
797 if extend:
798 if not changesets:
798 if not changesets:
799 extendnode = extendbisectrange(nodes, good)
799 extendnode = extendbisectrange(nodes, good)
800 if extendnode is not None:
800 if extendnode is not None:
801 ui.write(_("Extending search to changeset %d:%s\n")
801 ui.write(_("Extending search to changeset %d:%s\n")
802 % (extendnode.rev(), extendnode))
802 % (extendnode.rev(), extendnode))
803 state['current'] = [extendnode.node()]
803 state['current'] = [extendnode.node()]
804 hbisect.save_state(repo, state)
804 hbisect.save_state(repo, state)
805 if noupdate:
805 if noupdate:
806 return
806 return
807 cmdutil.bailifchanged(repo)
807 cmdutil.bailifchanged(repo)
808 return hg.clean(repo, extendnode.node())
808 return hg.clean(repo, extendnode.node())
809 raise util.Abort(_("nothing to extend"))
809 raise util.Abort(_("nothing to extend"))
810
810
811 if changesets == 0:
811 if changesets == 0:
812 print_result(nodes, good)
812 print_result(nodes, good)
813 else:
813 else:
814 assert len(nodes) == 1 # only a single node can be tested next
814 assert len(nodes) == 1 # only a single node can be tested next
815 node = nodes[0]
815 node = nodes[0]
816 # compute the approximate number of remaining tests
816 # compute the approximate number of remaining tests
817 tests, size = 0, 2
817 tests, size = 0, 2
818 while size <= changesets:
818 while size <= changesets:
819 tests, size = tests + 1, size * 2
819 tests, size = tests + 1, size * 2
820 rev = repo.changelog.rev(node)
820 rev = repo.changelog.rev(node)
821 ui.write(_("Testing changeset %d:%s "
821 ui.write(_("Testing changeset %d:%s "
822 "(%d changesets remaining, ~%d tests)\n")
822 "(%d changesets remaining, ~%d tests)\n")
823 % (rev, short(node), changesets, tests))
823 % (rev, short(node), changesets, tests))
824 state['current'] = [node]
824 state['current'] = [node]
825 hbisect.save_state(repo, state)
825 hbisect.save_state(repo, state)
826 if not noupdate:
826 if not noupdate:
827 cmdutil.bailifchanged(repo)
827 cmdutil.bailifchanged(repo)
828 return hg.clean(repo, node)
828 return hg.clean(repo, node)
829
829
830 @command('bookmarks|bookmark',
830 @command('bookmarks|bookmark',
831 [('f', 'force', False, _('force')),
831 [('f', 'force', False, _('force')),
832 ('r', 'rev', '', _('revision'), _('REV')),
832 ('r', 'rev', '', _('revision'), _('REV')),
833 ('d', 'delete', False, _('delete a given bookmark')),
833 ('d', 'delete', False, _('delete a given bookmark')),
834 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
834 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
835 ('i', 'inactive', False, _('mark a bookmark inactive')),
835 ('i', 'inactive', False, _('mark a bookmark inactive')),
836 ] + formatteropts,
836 ] + formatteropts,
837 _('hg bookmarks [OPTIONS]... [NAME]...'))
837 _('hg bookmarks [OPTIONS]... [NAME]...'))
838 def bookmark(ui, repo, *names, **opts):
838 def bookmark(ui, repo, *names, **opts):
839 '''create a new bookmark or list existing bookmarks
839 '''create a new bookmark or list existing bookmarks
840
840
841 Bookmarks are labels on changesets to help track lines of development.
841 Bookmarks are labels on changesets to help track lines of development.
842 Bookmarks are unversioned and can be moved, renamed and deleted.
842 Bookmarks are unversioned and can be moved, renamed and deleted.
843 Deleting or moving a bookmark has no effect on the associated changesets.
843 Deleting or moving a bookmark has no effect on the associated changesets.
844
844
845 Creating or updating to a bookmark causes it to be marked as 'active'.
845 Creating or updating to a bookmark causes it to be marked as 'active'.
846 The active bookmark is indicated with a '*'.
846 The active bookmark is indicated with a '*'.
847 When a commit is made, the active bookmark will advance to the new commit.
847 When a commit is made, the active bookmark will advance to the new commit.
848 A plain :hg:`update` will also advance an active bookmark, if possible.
848 A plain :hg:`update` will also advance an active bookmark, if possible.
849 Updating away from a bookmark will cause it to be deactivated.
849 Updating away from a bookmark will cause it to be deactivated.
850
850
851 Bookmarks can be pushed and pulled between repositories (see
851 Bookmarks can be pushed and pulled between repositories (see
852 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
852 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
853 diverged, a new 'divergent bookmark' of the form 'name@path' will
853 diverged, a new 'divergent bookmark' of the form 'name@path' will
854 be created. Using :hg:`merge` will resolve the divergence.
854 be created. Using :hg:`merge` will resolve the divergence.
855
855
856 A bookmark named '@' has the special property that :hg:`clone` will
856 A bookmark named '@' has the special property that :hg:`clone` will
857 check it out by default if it exists.
857 check it out by default if it exists.
858
858
859 .. container:: verbose
859 .. container:: verbose
860
860
861 Examples:
861 Examples:
862
862
863 - create an active bookmark for a new line of development::
863 - create an active bookmark for a new line of development::
864
864
865 hg book new-feature
865 hg book new-feature
866
866
867 - create an inactive bookmark as a place marker::
867 - create an inactive bookmark as a place marker::
868
868
869 hg book -i reviewed
869 hg book -i reviewed
870
870
871 - create an inactive bookmark on another changeset::
871 - create an inactive bookmark on another changeset::
872
872
873 hg book -r .^ tested
873 hg book -r .^ tested
874
874
875 - move the '@' bookmark from another branch::
875 - move the '@' bookmark from another branch::
876
876
877 hg book -f @
877 hg book -f @
878 '''
878 '''
879 force = opts.get('force')
879 force = opts.get('force')
880 rev = opts.get('rev')
880 rev = opts.get('rev')
881 delete = opts.get('delete')
881 delete = opts.get('delete')
882 rename = opts.get('rename')
882 rename = opts.get('rename')
883 inactive = opts.get('inactive')
883 inactive = opts.get('inactive')
884
884
885 def checkformat(mark):
885 def checkformat(mark):
886 mark = mark.strip()
886 mark = mark.strip()
887 if not mark:
887 if not mark:
888 raise util.Abort(_("bookmark names cannot consist entirely of "
888 raise util.Abort(_("bookmark names cannot consist entirely of "
889 "whitespace"))
889 "whitespace"))
890 scmutil.checknewlabel(repo, mark, 'bookmark')
890 scmutil.checknewlabel(repo, mark, 'bookmark')
891 return mark
891 return mark
892
892
893 def checkconflict(repo, mark, cur, force=False, target=None):
893 def checkconflict(repo, mark, cur, force=False, target=None):
894 if mark in marks and not force:
894 if mark in marks and not force:
895 if target:
895 if target:
896 if marks[mark] == target and target == cur:
896 if marks[mark] == target and target == cur:
897 # re-activating a bookmark
897 # re-activating a bookmark
898 return
898 return
899 anc = repo.changelog.ancestors([repo[target].rev()])
899 anc = repo.changelog.ancestors([repo[target].rev()])
900 bmctx = repo[marks[mark]]
900 bmctx = repo[marks[mark]]
901 divs = [repo[b].node() for b in marks
901 divs = [repo[b].node() for b in marks
902 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
902 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
903
903
904 # allow resolving a single divergent bookmark even if moving
904 # allow resolving a single divergent bookmark even if moving
905 # the bookmark across branches when a revision is specified
905 # the bookmark across branches when a revision is specified
906 # that contains a divergent bookmark
906 # that contains a divergent bookmark
907 if bmctx.rev() not in anc and target in divs:
907 if bmctx.rev() not in anc and target in divs:
908 bookmarks.deletedivergent(repo, [target], mark)
908 bookmarks.deletedivergent(repo, [target], mark)
909 return
909 return
910
910
911 deletefrom = [b for b in divs
911 deletefrom = [b for b in divs
912 if repo[b].rev() in anc or b == target]
912 if repo[b].rev() in anc or b == target]
913 bookmarks.deletedivergent(repo, deletefrom, mark)
913 bookmarks.deletedivergent(repo, deletefrom, mark)
914 if bookmarks.validdest(repo, bmctx, repo[target]):
914 if bookmarks.validdest(repo, bmctx, repo[target]):
915 ui.status(_("moving bookmark '%s' forward from %s\n") %
915 ui.status(_("moving bookmark '%s' forward from %s\n") %
916 (mark, short(bmctx.node())))
916 (mark, short(bmctx.node())))
917 return
917 return
918 raise util.Abort(_("bookmark '%s' already exists "
918 raise util.Abort(_("bookmark '%s' already exists "
919 "(use -f to force)") % mark)
919 "(use -f to force)") % mark)
920 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
920 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
921 and not force):
921 and not force):
922 raise util.Abort(
922 raise util.Abort(
923 _("a bookmark cannot have the name of an existing branch"))
923 _("a bookmark cannot have the name of an existing branch"))
924
924
925 if delete and rename:
925 if delete and rename:
926 raise util.Abort(_("--delete and --rename are incompatible"))
926 raise util.Abort(_("--delete and --rename are incompatible"))
927 if delete and rev:
927 if delete and rev:
928 raise util.Abort(_("--rev is incompatible with --delete"))
928 raise util.Abort(_("--rev is incompatible with --delete"))
929 if rename and rev:
929 if rename and rev:
930 raise util.Abort(_("--rev is incompatible with --rename"))
930 raise util.Abort(_("--rev is incompatible with --rename"))
931 if not names and (delete or rev):
931 if not names and (delete or rev):
932 raise util.Abort(_("bookmark name required"))
932 raise util.Abort(_("bookmark name required"))
933
933
934 if delete or rename or names or inactive:
934 if delete or rename or names or inactive:
935 wlock = repo.wlock()
935 wlock = repo.wlock()
936 try:
936 try:
937 cur = repo.changectx('.').node()
937 cur = repo.changectx('.').node()
938 marks = repo._bookmarks
938 marks = repo._bookmarks
939 if delete:
939 if delete:
940 for mark in names:
940 for mark in names:
941 if mark not in marks:
941 if mark not in marks:
942 raise util.Abort(_("bookmark '%s' does not exist") %
942 raise util.Abort(_("bookmark '%s' does not exist") %
943 mark)
943 mark)
944 if mark == repo._bookmarkcurrent:
944 if mark == repo._bookmarkcurrent:
945 bookmarks.unsetcurrent(repo)
945 bookmarks.unsetcurrent(repo)
946 del marks[mark]
946 del marks[mark]
947 marks.write()
947 marks.write()
948
948
949 elif rename:
949 elif rename:
950 if not names:
950 if not names:
951 raise util.Abort(_("new bookmark name required"))
951 raise util.Abort(_("new bookmark name required"))
952 elif len(names) > 1:
952 elif len(names) > 1:
953 raise util.Abort(_("only one new bookmark name allowed"))
953 raise util.Abort(_("only one new bookmark name allowed"))
954 mark = checkformat(names[0])
954 mark = checkformat(names[0])
955 if rename not in marks:
955 if rename not in marks:
956 raise util.Abort(_("bookmark '%s' does not exist") % rename)
956 raise util.Abort(_("bookmark '%s' does not exist") % rename)
957 checkconflict(repo, mark, cur, force)
957 checkconflict(repo, mark, cur, force)
958 marks[mark] = marks[rename]
958 marks[mark] = marks[rename]
959 if repo._bookmarkcurrent == rename and not inactive:
959 if repo._bookmarkcurrent == rename and not inactive:
960 bookmarks.setcurrent(repo, mark)
960 bookmarks.setcurrent(repo, mark)
961 del marks[rename]
961 del marks[rename]
962 marks.write()
962 marks.write()
963
963
964 elif names:
964 elif names:
965 newact = None
965 newact = None
966 for mark in names:
966 for mark in names:
967 mark = checkformat(mark)
967 mark = checkformat(mark)
968 if newact is None:
968 if newact is None:
969 newact = mark
969 newact = mark
970 if inactive and mark == repo._bookmarkcurrent:
970 if inactive and mark == repo._bookmarkcurrent:
971 bookmarks.unsetcurrent(repo)
971 bookmarks.unsetcurrent(repo)
972 return
972 return
973 tgt = cur
973 tgt = cur
974 if rev:
974 if rev:
975 tgt = scmutil.revsingle(repo, rev).node()
975 tgt = scmutil.revsingle(repo, rev).node()
976 checkconflict(repo, mark, cur, force, tgt)
976 checkconflict(repo, mark, cur, force, tgt)
977 marks[mark] = tgt
977 marks[mark] = tgt
978 if not inactive and cur == marks[newact] and not rev:
978 if not inactive and cur == marks[newact] and not rev:
979 bookmarks.setcurrent(repo, newact)
979 bookmarks.setcurrent(repo, newact)
980 elif cur != tgt and newact == repo._bookmarkcurrent:
980 elif cur != tgt and newact == repo._bookmarkcurrent:
981 bookmarks.unsetcurrent(repo)
981 bookmarks.unsetcurrent(repo)
982 marks.write()
982 marks.write()
983
983
984 elif inactive:
984 elif inactive:
985 if len(marks) == 0:
985 if len(marks) == 0:
986 ui.status(_("no bookmarks set\n"))
986 ui.status(_("no bookmarks set\n"))
987 elif not repo._bookmarkcurrent:
987 elif not repo._bookmarkcurrent:
988 ui.status(_("no active bookmark\n"))
988 ui.status(_("no active bookmark\n"))
989 else:
989 else:
990 bookmarks.unsetcurrent(repo)
990 bookmarks.unsetcurrent(repo)
991 finally:
991 finally:
992 wlock.release()
992 wlock.release()
993 else: # show bookmarks
993 else: # show bookmarks
994 fm = ui.formatter('bookmarks', opts)
994 fm = ui.formatter('bookmarks', opts)
995 hexfn = fm.hexfunc
995 hexfn = fm.hexfunc
996 marks = repo._bookmarks
996 marks = repo._bookmarks
997 if len(marks) == 0 and not fm:
997 if len(marks) == 0 and not fm:
998 ui.status(_("no bookmarks set\n"))
998 ui.status(_("no bookmarks set\n"))
999 for bmark, n in sorted(marks.iteritems()):
999 for bmark, n in sorted(marks.iteritems()):
1000 current = repo._bookmarkcurrent
1000 current = repo._bookmarkcurrent
1001 if bmark == current:
1001 if bmark == current:
1002 prefix, label = '*', 'bookmarks.current'
1002 prefix, label = '*', 'bookmarks.current'
1003 else:
1003 else:
1004 prefix, label = ' ', ''
1004 prefix, label = ' ', ''
1005
1005
1006 fm.startitem()
1006 fm.startitem()
1007 if not ui.quiet:
1007 if not ui.quiet:
1008 fm.plain(' %s ' % prefix, label=label)
1008 fm.plain(' %s ' % prefix, label=label)
1009 fm.write('bookmark', '%s', bmark, label=label)
1009 fm.write('bookmark', '%s', bmark, label=label)
1010 pad = " " * (25 - encoding.colwidth(bmark))
1010 pad = " " * (25 - encoding.colwidth(bmark))
1011 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1011 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1012 repo.changelog.rev(n), hexfn(n), label=label)
1012 repo.changelog.rev(n), hexfn(n), label=label)
1013 fm.data(active=(bmark == current))
1013 fm.data(active=(bmark == current))
1014 fm.plain('\n')
1014 fm.plain('\n')
1015 fm.end()
1015 fm.end()
1016
1016
1017 @command('branch',
1017 @command('branch',
1018 [('f', 'force', None,
1018 [('f', 'force', None,
1019 _('set branch name even if it shadows an existing branch')),
1019 _('set branch name even if it shadows an existing branch')),
1020 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1020 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1021 _('[-fC] [NAME]'))
1021 _('[-fC] [NAME]'))
1022 def branch(ui, repo, label=None, **opts):
1022 def branch(ui, repo, label=None, **opts):
1023 """set or show the current branch name
1023 """set or show the current branch name
1024
1024
1025 .. note::
1025 .. note::
1026
1026
1027 Branch names are permanent and global. Use :hg:`bookmark` to create a
1027 Branch names are permanent and global. Use :hg:`bookmark` to create a
1028 light-weight bookmark instead. See :hg:`help glossary` for more
1028 light-weight bookmark instead. See :hg:`help glossary` for more
1029 information about named branches and bookmarks.
1029 information about named branches and bookmarks.
1030
1030
1031 With no argument, show the current branch name. With one argument,
1031 With no argument, show the current branch name. With one argument,
1032 set the working directory branch name (the branch will not exist
1032 set the working directory branch name (the branch will not exist
1033 in the repository until the next commit). Standard practice
1033 in the repository until the next commit). Standard practice
1034 recommends that primary development take place on the 'default'
1034 recommends that primary development take place on the 'default'
1035 branch.
1035 branch.
1036
1036
1037 Unless -f/--force is specified, branch will not let you set a
1037 Unless -f/--force is specified, branch will not let you set a
1038 branch name that already exists, even if it's inactive.
1038 branch name that already exists, even if it's inactive.
1039
1039
1040 Use -C/--clean to reset the working directory branch to that of
1040 Use -C/--clean to reset the working directory branch to that of
1041 the parent of the working directory, negating a previous branch
1041 the parent of the working directory, negating a previous branch
1042 change.
1042 change.
1043
1043
1044 Use the command :hg:`update` to switch to an existing branch. Use
1044 Use the command :hg:`update` to switch to an existing branch. Use
1045 :hg:`commit --close-branch` to mark this branch as closed.
1045 :hg:`commit --close-branch` to mark this branch as closed.
1046
1046
1047 Returns 0 on success.
1047 Returns 0 on success.
1048 """
1048 """
1049 if label:
1049 if label:
1050 label = label.strip()
1050 label = label.strip()
1051
1051
1052 if not opts.get('clean') and not label:
1052 if not opts.get('clean') and not label:
1053 ui.write("%s\n" % repo.dirstate.branch())
1053 ui.write("%s\n" % repo.dirstate.branch())
1054 return
1054 return
1055
1055
1056 wlock = repo.wlock()
1056 wlock = repo.wlock()
1057 try:
1057 try:
1058 if opts.get('clean'):
1058 if opts.get('clean'):
1059 label = repo[None].p1().branch()
1059 label = repo[None].p1().branch()
1060 repo.dirstate.setbranch(label)
1060 repo.dirstate.setbranch(label)
1061 ui.status(_('reset working directory to branch %s\n') % label)
1061 ui.status(_('reset working directory to branch %s\n') % label)
1062 elif label:
1062 elif label:
1063 if not opts.get('force') and label in repo.branchmap():
1063 if not opts.get('force') and label in repo.branchmap():
1064 if label not in [p.branch() for p in repo.parents()]:
1064 if label not in [p.branch() for p in repo.parents()]:
1065 raise util.Abort(_('a branch of the same name already'
1065 raise util.Abort(_('a branch of the same name already'
1066 ' exists'),
1066 ' exists'),
1067 # i18n: "it" refers to an existing branch
1067 # i18n: "it" refers to an existing branch
1068 hint=_("use 'hg update' to switch to it"))
1068 hint=_("use 'hg update' to switch to it"))
1069 scmutil.checknewlabel(repo, label, 'branch')
1069 scmutil.checknewlabel(repo, label, 'branch')
1070 repo.dirstate.setbranch(label)
1070 repo.dirstate.setbranch(label)
1071 ui.status(_('marked working directory as branch %s\n') % label)
1071 ui.status(_('marked working directory as branch %s\n') % label)
1072 ui.status(_('(branches are permanent and global, '
1072 ui.status(_('(branches are permanent and global, '
1073 'did you want a bookmark?)\n'))
1073 'did you want a bookmark?)\n'))
1074 finally:
1074 finally:
1075 wlock.release()
1075 wlock.release()
1076
1076
1077 @command('branches',
1077 @command('branches',
1078 [('a', 'active', False, _('show only branches that have unmerged heads')),
1078 [('a', 'active', False, _('show only branches that have unmerged heads')),
1079 ('c', 'closed', False, _('show normal and closed branches')),
1079 ('c', 'closed', False, _('show normal and closed branches')),
1080 ] + formatteropts,
1080 ] + formatteropts,
1081 _('[-ac]'))
1081 _('[-ac]'))
1082 def branches(ui, repo, active=False, closed=False, **opts):
1082 def branches(ui, repo, active=False, closed=False, **opts):
1083 """list repository named branches
1083 """list repository named branches
1084
1084
1085 List the repository's named branches, indicating which ones are
1085 List the repository's named branches, indicating which ones are
1086 inactive. If -c/--closed is specified, also list branches which have
1086 inactive. If -c/--closed is specified, also list branches which have
1087 been marked closed (see :hg:`commit --close-branch`).
1087 been marked closed (see :hg:`commit --close-branch`).
1088
1088
1089 If -a/--active is specified, only show active branches. A branch
1089 If -a/--active is specified, only show active branches. A branch
1090 is considered active if it contains repository heads.
1090 is considered active if it contains repository heads.
1091
1091
1092 Use the command :hg:`update` to switch to an existing branch.
1092 Use the command :hg:`update` to switch to an existing branch.
1093
1093
1094 Returns 0.
1094 Returns 0.
1095 """
1095 """
1096
1096
1097 fm = ui.formatter('branches', opts)
1097 fm = ui.formatter('branches', opts)
1098 hexfunc = fm.hexfunc
1098 hexfunc = fm.hexfunc
1099
1099
1100 allheads = set(repo.heads())
1100 allheads = set(repo.heads())
1101 branches = []
1101 branches = []
1102 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1102 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1103 isactive = not isclosed and bool(set(heads) & allheads)
1103 isactive = not isclosed and bool(set(heads) & allheads)
1104 branches.append((tag, repo[tip], isactive, not isclosed))
1104 branches.append((tag, repo[tip], isactive, not isclosed))
1105 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1105 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1106 reverse=True)
1106 reverse=True)
1107
1107
1108 for tag, ctx, isactive, isopen in branches:
1108 for tag, ctx, isactive, isopen in branches:
1109 if active and not isactive:
1109 if active and not isactive:
1110 continue
1110 continue
1111 if isactive:
1111 if isactive:
1112 label = 'branches.active'
1112 label = 'branches.active'
1113 notice = ''
1113 notice = ''
1114 elif not isopen:
1114 elif not isopen:
1115 if not closed:
1115 if not closed:
1116 continue
1116 continue
1117 label = 'branches.closed'
1117 label = 'branches.closed'
1118 notice = _(' (closed)')
1118 notice = _(' (closed)')
1119 else:
1119 else:
1120 label = 'branches.inactive'
1120 label = 'branches.inactive'
1121 notice = _(' (inactive)')
1121 notice = _(' (inactive)')
1122 current = (tag == repo.dirstate.branch())
1122 current = (tag == repo.dirstate.branch())
1123 if current:
1123 if current:
1124 label = 'branches.current'
1124 label = 'branches.current'
1125
1125
1126 fm.startitem()
1126 fm.startitem()
1127 fm.write('branch', '%s', tag, label=label)
1127 fm.write('branch', '%s', tag, label=label)
1128 rev = ctx.rev()
1128 rev = ctx.rev()
1129 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1129 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1130 fmt = ' ' * padsize + ' %d:%s'
1130 fmt = ' ' * padsize + ' %d:%s'
1131 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1131 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1132 label='log.changeset changeset.%s' % ctx.phasestr())
1132 label='log.changeset changeset.%s' % ctx.phasestr())
1133 fm.data(active=isactive, closed=not isopen, current=current)
1133 fm.data(active=isactive, closed=not isopen, current=current)
1134 if not ui.quiet:
1134 if not ui.quiet:
1135 fm.plain(notice)
1135 fm.plain(notice)
1136 fm.plain('\n')
1136 fm.plain('\n')
1137 fm.end()
1137 fm.end()
1138
1138
1139 @command('bundle',
1139 @command('bundle',
1140 [('f', 'force', None, _('run even when the destination is unrelated')),
1140 [('f', 'force', None, _('run even when the destination is unrelated')),
1141 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1141 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1142 _('REV')),
1142 _('REV')),
1143 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1143 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1144 _('BRANCH')),
1144 _('BRANCH')),
1145 ('', 'base', [],
1145 ('', 'base', [],
1146 _('a base changeset assumed to be available at the destination'),
1146 _('a base changeset assumed to be available at the destination'),
1147 _('REV')),
1147 _('REV')),
1148 ('a', 'all', None, _('bundle all changesets in the repository')),
1148 ('a', 'all', None, _('bundle all changesets in the repository')),
1149 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1149 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1150 ] + remoteopts,
1150 ] + remoteopts,
1151 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1151 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1152 def bundle(ui, repo, fname, dest=None, **opts):
1152 def bundle(ui, repo, fname, dest=None, **opts):
1153 """create a changegroup file
1153 """create a changegroup file
1154
1154
1155 Generate a compressed changegroup file collecting changesets not
1155 Generate a compressed changegroup file collecting changesets not
1156 known to be in another repository.
1156 known to be in another repository.
1157
1157
1158 If you omit the destination repository, then hg assumes the
1158 If you omit the destination repository, then hg assumes the
1159 destination will have all the nodes you specify with --base
1159 destination will have all the nodes you specify with --base
1160 parameters. To create a bundle containing all changesets, use
1160 parameters. To create a bundle containing all changesets, use
1161 -a/--all (or --base null).
1161 -a/--all (or --base null).
1162
1162
1163 You can change compression method with the -t/--type option.
1163 You can change compression method with the -t/--type option.
1164 The available compression methods are: none, bzip2, and
1164 The available compression methods are: none, bzip2, and
1165 gzip (by default, bundles are compressed using bzip2).
1165 gzip (by default, bundles are compressed using bzip2).
1166
1166
1167 The bundle file can then be transferred using conventional means
1167 The bundle file can then be transferred using conventional means
1168 and applied to another repository with the unbundle or pull
1168 and applied to another repository with the unbundle or pull
1169 command. This is useful when direct push and pull are not
1169 command. This is useful when direct push and pull are not
1170 available or when exporting an entire repository is undesirable.
1170 available or when exporting an entire repository is undesirable.
1171
1171
1172 Applying bundles preserves all changeset contents including
1172 Applying bundles preserves all changeset contents including
1173 permissions, copy/rename information, and revision history.
1173 permissions, copy/rename information, and revision history.
1174
1174
1175 Returns 0 on success, 1 if no changes found.
1175 Returns 0 on success, 1 if no changes found.
1176 """
1176 """
1177 revs = None
1177 revs = None
1178 if 'rev' in opts:
1178 if 'rev' in opts:
1179 revs = scmutil.revrange(repo, opts['rev'])
1179 revs = scmutil.revrange(repo, opts['rev'])
1180
1180
1181 bundletype = opts.get('type', 'bzip2').lower()
1181 bundletype = opts.get('type', 'bzip2').lower()
1182 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1182 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1183 bundletype = btypes.get(bundletype)
1183 bundletype = btypes.get(bundletype)
1184 if bundletype not in changegroup.bundletypes:
1184 if bundletype not in changegroup.bundletypes:
1185 raise util.Abort(_('unknown bundle type specified with --type'))
1185 raise util.Abort(_('unknown bundle type specified with --type'))
1186
1186
1187 if opts.get('all'):
1187 if opts.get('all'):
1188 base = ['null']
1188 base = ['null']
1189 else:
1189 else:
1190 base = scmutil.revrange(repo, opts.get('base'))
1190 base = scmutil.revrange(repo, opts.get('base'))
1191 # TODO: get desired bundlecaps from command line.
1191 # TODO: get desired bundlecaps from command line.
1192 bundlecaps = None
1192 bundlecaps = None
1193 if base:
1193 if base:
1194 if dest:
1194 if dest:
1195 raise util.Abort(_("--base is incompatible with specifying "
1195 raise util.Abort(_("--base is incompatible with specifying "
1196 "a destination"))
1196 "a destination"))
1197 common = [repo.lookup(rev) for rev in base]
1197 common = [repo.lookup(rev) for rev in base]
1198 heads = revs and map(repo.lookup, revs) or revs
1198 heads = revs and map(repo.lookup, revs) or revs
1199 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1199 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1200 common=common, bundlecaps=bundlecaps)
1200 common=common, bundlecaps=bundlecaps)
1201 outgoing = None
1201 outgoing = None
1202 else:
1202 else:
1203 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1203 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1204 dest, branches = hg.parseurl(dest, opts.get('branch'))
1204 dest, branches = hg.parseurl(dest, opts.get('branch'))
1205 other = hg.peer(repo, opts, dest)
1205 other = hg.peer(repo, opts, dest)
1206 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1206 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1207 heads = revs and map(repo.lookup, revs) or revs
1207 heads = revs and map(repo.lookup, revs) or revs
1208 outgoing = discovery.findcommonoutgoing(repo, other,
1208 outgoing = discovery.findcommonoutgoing(repo, other,
1209 onlyheads=heads,
1209 onlyheads=heads,
1210 force=opts.get('force'),
1210 force=opts.get('force'),
1211 portable=True)
1211 portable=True)
1212 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1212 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1213 bundlecaps)
1213 bundlecaps)
1214 if not cg:
1214 if not cg:
1215 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1215 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1216 return 1
1216 return 1
1217
1217
1218 changegroup.writebundle(cg, fname, bundletype)
1218 changegroup.writebundle(cg, fname, bundletype)
1219
1219
1220 @command('cat',
1220 @command('cat',
1221 [('o', 'output', '',
1221 [('o', 'output', '',
1222 _('print output to file with formatted name'), _('FORMAT')),
1222 _('print output to file with formatted name'), _('FORMAT')),
1223 ('r', 'rev', '', _('print the given revision'), _('REV')),
1223 ('r', 'rev', '', _('print the given revision'), _('REV')),
1224 ('', 'decode', None, _('apply any matching decode filter')),
1224 ('', 'decode', None, _('apply any matching decode filter')),
1225 ] + walkopts,
1225 ] + walkopts,
1226 _('[OPTION]... FILE...'),
1226 _('[OPTION]... FILE...'),
1227 inferrepo=True)
1227 inferrepo=True)
1228 def cat(ui, repo, file1, *pats, **opts):
1228 def cat(ui, repo, file1, *pats, **opts):
1229 """output the current or given revision of files
1229 """output the current or given revision of files
1230
1230
1231 Print the specified files as they were at the given revision. If
1231 Print the specified files as they were at the given revision. If
1232 no revision is given, the parent of the working directory is used.
1232 no revision is given, the parent of the working directory is used.
1233
1233
1234 Output may be to a file, in which case the name of the file is
1234 Output may be to a file, in which case the name of the file is
1235 given using a format string. The formatting rules as follows:
1235 given using a format string. The formatting rules as follows:
1236
1236
1237 :``%%``: literal "%" character
1237 :``%%``: literal "%" character
1238 :``%s``: basename of file being printed
1238 :``%s``: basename of file being printed
1239 :``%d``: dirname of file being printed, or '.' if in repository root
1239 :``%d``: dirname of file being printed, or '.' if in repository root
1240 :``%p``: root-relative path name of file being printed
1240 :``%p``: root-relative path name of file being printed
1241 :``%H``: changeset hash (40 hexadecimal digits)
1241 :``%H``: changeset hash (40 hexadecimal digits)
1242 :``%R``: changeset revision number
1242 :``%R``: changeset revision number
1243 :``%h``: short-form changeset hash (12 hexadecimal digits)
1243 :``%h``: short-form changeset hash (12 hexadecimal digits)
1244 :``%r``: zero-padded changeset revision number
1244 :``%r``: zero-padded changeset revision number
1245 :``%b``: basename of the exporting repository
1245 :``%b``: basename of the exporting repository
1246
1246
1247 Returns 0 on success.
1247 Returns 0 on success.
1248 """
1248 """
1249 ctx = scmutil.revsingle(repo, opts.get('rev'))
1249 ctx = scmutil.revsingle(repo, opts.get('rev'))
1250 m = scmutil.match(ctx, (file1,) + pats, opts)
1250 m = scmutil.match(ctx, (file1,) + pats, opts)
1251
1251
1252 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1252 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1253
1253
1254 @command('^clone',
1254 @command('^clone',
1255 [('U', 'noupdate', None,
1255 [('U', 'noupdate', None,
1256 _('the clone will include an empty working copy (only a repository)')),
1256 _('the clone will include an empty working copy (only a repository)')),
1257 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1257 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1258 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1258 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1259 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1259 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1260 ('', 'pull', None, _('use pull protocol to copy metadata')),
1260 ('', 'pull', None, _('use pull protocol to copy metadata')),
1261 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1261 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1262 ] + remoteopts,
1262 ] + remoteopts,
1263 _('[OPTION]... SOURCE [DEST]'),
1263 _('[OPTION]... SOURCE [DEST]'),
1264 norepo=True)
1264 norepo=True)
1265 def clone(ui, source, dest=None, **opts):
1265 def clone(ui, source, dest=None, **opts):
1266 """make a copy of an existing repository
1266 """make a copy of an existing repository
1267
1267
1268 Create a copy of an existing repository in a new directory.
1268 Create a copy of an existing repository in a new directory.
1269
1269
1270 If no destination directory name is specified, it defaults to the
1270 If no destination directory name is specified, it defaults to the
1271 basename of the source.
1271 basename of the source.
1272
1272
1273 The location of the source is added to the new repository's
1273 The location of the source is added to the new repository's
1274 ``.hg/hgrc`` file, as the default to be used for future pulls.
1274 ``.hg/hgrc`` file, as the default to be used for future pulls.
1275
1275
1276 Only local paths and ``ssh://`` URLs are supported as
1276 Only local paths and ``ssh://`` URLs are supported as
1277 destinations. For ``ssh://`` destinations, no working directory or
1277 destinations. For ``ssh://`` destinations, no working directory or
1278 ``.hg/hgrc`` will be created on the remote side.
1278 ``.hg/hgrc`` will be created on the remote side.
1279
1279
1280 To pull only a subset of changesets, specify one or more revisions
1280 To pull only a subset of changesets, specify one or more revisions
1281 identifiers with -r/--rev or branches with -b/--branch. The
1281 identifiers with -r/--rev or branches with -b/--branch. The
1282 resulting clone will contain only the specified changesets and
1282 resulting clone will contain only the specified changesets and
1283 their ancestors. These options (or 'clone src#rev dest') imply
1283 their ancestors. These options (or 'clone src#rev dest') imply
1284 --pull, even for local source repositories. Note that specifying a
1284 --pull, even for local source repositories. Note that specifying a
1285 tag will include the tagged changeset but not the changeset
1285 tag will include the tagged changeset but not the changeset
1286 containing the tag.
1286 containing the tag.
1287
1287
1288 If the source repository has a bookmark called '@' set, that
1288 If the source repository has a bookmark called '@' set, that
1289 revision will be checked out in the new repository by default.
1289 revision will be checked out in the new repository by default.
1290
1290
1291 To check out a particular version, use -u/--update, or
1291 To check out a particular version, use -u/--update, or
1292 -U/--noupdate to create a clone with no working directory.
1292 -U/--noupdate to create a clone with no working directory.
1293
1293
1294 .. container:: verbose
1294 .. container:: verbose
1295
1295
1296 For efficiency, hardlinks are used for cloning whenever the
1296 For efficiency, hardlinks are used for cloning whenever the
1297 source and destination are on the same filesystem (note this
1297 source and destination are on the same filesystem (note this
1298 applies only to the repository data, not to the working
1298 applies only to the repository data, not to the working
1299 directory). Some filesystems, such as AFS, implement hardlinking
1299 directory). Some filesystems, such as AFS, implement hardlinking
1300 incorrectly, but do not report errors. In these cases, use the
1300 incorrectly, but do not report errors. In these cases, use the
1301 --pull option to avoid hardlinking.
1301 --pull option to avoid hardlinking.
1302
1302
1303 In some cases, you can clone repositories and the working
1303 In some cases, you can clone repositories and the working
1304 directory using full hardlinks with ::
1304 directory using full hardlinks with ::
1305
1305
1306 $ cp -al REPO REPOCLONE
1306 $ cp -al REPO REPOCLONE
1307
1307
1308 This is the fastest way to clone, but it is not always safe. The
1308 This is the fastest way to clone, but it is not always safe. The
1309 operation is not atomic (making sure REPO is not modified during
1309 operation is not atomic (making sure REPO is not modified during
1310 the operation is up to you) and you have to make sure your
1310 the operation is up to you) and you have to make sure your
1311 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1311 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1312 so). Also, this is not compatible with certain extensions that
1312 so). Also, this is not compatible with certain extensions that
1313 place their metadata under the .hg directory, such as mq.
1313 place their metadata under the .hg directory, such as mq.
1314
1314
1315 Mercurial will update the working directory to the first applicable
1315 Mercurial will update the working directory to the first applicable
1316 revision from this list:
1316 revision from this list:
1317
1317
1318 a) null if -U or the source repository has no changesets
1318 a) null if -U or the source repository has no changesets
1319 b) if -u . and the source repository is local, the first parent of
1319 b) if -u . and the source repository is local, the first parent of
1320 the source repository's working directory
1320 the source repository's working directory
1321 c) the changeset specified with -u (if a branch name, this means the
1321 c) the changeset specified with -u (if a branch name, this means the
1322 latest head of that branch)
1322 latest head of that branch)
1323 d) the changeset specified with -r
1323 d) the changeset specified with -r
1324 e) the tipmost head specified with -b
1324 e) the tipmost head specified with -b
1325 f) the tipmost head specified with the url#branch source syntax
1325 f) the tipmost head specified with the url#branch source syntax
1326 g) the revision marked with the '@' bookmark, if present
1326 g) the revision marked with the '@' bookmark, if present
1327 h) the tipmost head of the default branch
1327 h) the tipmost head of the default branch
1328 i) tip
1328 i) tip
1329
1329
1330 Examples:
1330 Examples:
1331
1331
1332 - clone a remote repository to a new directory named hg/::
1332 - clone a remote repository to a new directory named hg/::
1333
1333
1334 hg clone http://selenic.com/hg
1334 hg clone http://selenic.com/hg
1335
1335
1336 - create a lightweight local clone::
1336 - create a lightweight local clone::
1337
1337
1338 hg clone project/ project-feature/
1338 hg clone project/ project-feature/
1339
1339
1340 - clone from an absolute path on an ssh server (note double-slash)::
1340 - clone from an absolute path on an ssh server (note double-slash)::
1341
1341
1342 hg clone ssh://user@server//home/projects/alpha/
1342 hg clone ssh://user@server//home/projects/alpha/
1343
1343
1344 - do a high-speed clone over a LAN while checking out a
1344 - do a high-speed clone over a LAN while checking out a
1345 specified version::
1345 specified version::
1346
1346
1347 hg clone --uncompressed http://server/repo -u 1.5
1347 hg clone --uncompressed http://server/repo -u 1.5
1348
1348
1349 - create a repository without changesets after a particular revision::
1349 - create a repository without changesets after a particular revision::
1350
1350
1351 hg clone -r 04e544 experimental/ good/
1351 hg clone -r 04e544 experimental/ good/
1352
1352
1353 - clone (and track) a particular named branch::
1353 - clone (and track) a particular named branch::
1354
1354
1355 hg clone http://selenic.com/hg#stable
1355 hg clone http://selenic.com/hg#stable
1356
1356
1357 See :hg:`help urls` for details on specifying URLs.
1357 See :hg:`help urls` for details on specifying URLs.
1358
1358
1359 Returns 0 on success.
1359 Returns 0 on success.
1360 """
1360 """
1361 if opts.get('noupdate') and opts.get('updaterev'):
1361 if opts.get('noupdate') and opts.get('updaterev'):
1362 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1362 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1363
1363
1364 r = hg.clone(ui, opts, source, dest,
1364 r = hg.clone(ui, opts, source, dest,
1365 pull=opts.get('pull'),
1365 pull=opts.get('pull'),
1366 stream=opts.get('uncompressed'),
1366 stream=opts.get('uncompressed'),
1367 rev=opts.get('rev'),
1367 rev=opts.get('rev'),
1368 update=opts.get('updaterev') or not opts.get('noupdate'),
1368 update=opts.get('updaterev') or not opts.get('noupdate'),
1369 branch=opts.get('branch'))
1369 branch=opts.get('branch'))
1370
1370
1371 return r is None
1371 return r is None
1372
1372
1373 @command('^commit|ci',
1373 @command('^commit|ci',
1374 [('A', 'addremove', None,
1374 [('A', 'addremove', None,
1375 _('mark new/missing files as added/removed before committing')),
1375 _('mark new/missing files as added/removed before committing')),
1376 ('', 'close-branch', None,
1376 ('', 'close-branch', None,
1377 _('mark a branch as closed, hiding it from the branch list')),
1377 _('mark a branch as closed, hiding it from the branch list')),
1378 ('', 'amend', None, _('amend the parent of the working dir')),
1378 ('', 'amend', None, _('amend the parent of the working dir')),
1379 ('s', 'secret', None, _('use the secret phase for committing')),
1379 ('s', 'secret', None, _('use the secret phase for committing')),
1380 ('e', 'edit', None, _('invoke editor on commit messages')),
1380 ('e', 'edit', None, _('invoke editor on commit messages')),
1381 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1381 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1382 _('[OPTION]... [FILE]...'),
1382 _('[OPTION]... [FILE]...'),
1383 inferrepo=True)
1383 inferrepo=True)
1384 def commit(ui, repo, *pats, **opts):
1384 def commit(ui, repo, *pats, **opts):
1385 """commit the specified files or all outstanding changes
1385 """commit the specified files or all outstanding changes
1386
1386
1387 Commit changes to the given files into the repository. Unlike a
1387 Commit changes to the given files into the repository. Unlike a
1388 centralized SCM, this operation is a local operation. See
1388 centralized SCM, this operation is a local operation. See
1389 :hg:`push` for a way to actively distribute your changes.
1389 :hg:`push` for a way to actively distribute your changes.
1390
1390
1391 If a list of files is omitted, all changes reported by :hg:`status`
1391 If a list of files is omitted, all changes reported by :hg:`status`
1392 will be committed.
1392 will be committed.
1393
1393
1394 If you are committing the result of a merge, do not provide any
1394 If you are committing the result of a merge, do not provide any
1395 filenames or -I/-X filters.
1395 filenames or -I/-X filters.
1396
1396
1397 If no commit message is specified, Mercurial starts your
1397 If no commit message is specified, Mercurial starts your
1398 configured editor where you can enter a message. In case your
1398 configured editor where you can enter a message. In case your
1399 commit fails, you will find a backup of your message in
1399 commit fails, you will find a backup of your message in
1400 ``.hg/last-message.txt``.
1400 ``.hg/last-message.txt``.
1401
1401
1402 The --amend flag can be used to amend the parent of the
1402 The --amend flag can be used to amend the parent of the
1403 working directory with a new commit that contains the changes
1403 working directory with a new commit that contains the changes
1404 in the parent in addition to those currently reported by :hg:`status`,
1404 in the parent in addition to those currently reported by :hg:`status`,
1405 if there are any. The old commit is stored in a backup bundle in
1405 if there are any. The old commit is stored in a backup bundle in
1406 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1406 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1407 on how to restore it).
1407 on how to restore it).
1408
1408
1409 Message, user and date are taken from the amended commit unless
1409 Message, user and date are taken from the amended commit unless
1410 specified. When a message isn't specified on the command line,
1410 specified. When a message isn't specified on the command line,
1411 the editor will open with the message of the amended commit.
1411 the editor will open with the message of the amended commit.
1412
1412
1413 It is not possible to amend public changesets (see :hg:`help phases`)
1413 It is not possible to amend public changesets (see :hg:`help phases`)
1414 or changesets that have children.
1414 or changesets that have children.
1415
1415
1416 See :hg:`help dates` for a list of formats valid for -d/--date.
1416 See :hg:`help dates` for a list of formats valid for -d/--date.
1417
1417
1418 Returns 0 on success, 1 if nothing changed.
1418 Returns 0 on success, 1 if nothing changed.
1419 """
1419 """
1420 if opts.get('subrepos'):
1420 if opts.get('subrepos'):
1421 if opts.get('amend'):
1421 if opts.get('amend'):
1422 raise util.Abort(_('cannot amend with --subrepos'))
1422 raise util.Abort(_('cannot amend with --subrepos'))
1423 # Let --subrepos on the command line override config setting.
1423 # Let --subrepos on the command line override config setting.
1424 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1424 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1425
1425
1426 cmdutil.checkunfinished(repo, commit=True)
1426 cmdutil.checkunfinished(repo, commit=True)
1427
1427
1428 branch = repo[None].branch()
1428 branch = repo[None].branch()
1429 bheads = repo.branchheads(branch)
1429 bheads = repo.branchheads(branch)
1430
1430
1431 extra = {}
1431 extra = {}
1432 if opts.get('close_branch'):
1432 if opts.get('close_branch'):
1433 extra['close'] = 1
1433 extra['close'] = 1
1434
1434
1435 if not bheads:
1435 if not bheads:
1436 raise util.Abort(_('can only close branch heads'))
1436 raise util.Abort(_('can only close branch heads'))
1437 elif opts.get('amend'):
1437 elif opts.get('amend'):
1438 if repo.parents()[0].p1().branch() != branch and \
1438 if repo.parents()[0].p1().branch() != branch and \
1439 repo.parents()[0].p2().branch() != branch:
1439 repo.parents()[0].p2().branch() != branch:
1440 raise util.Abort(_('can only close branch heads'))
1440 raise util.Abort(_('can only close branch heads'))
1441
1441
1442 if opts.get('amend'):
1442 if opts.get('amend'):
1443 if ui.configbool('ui', 'commitsubrepos'):
1443 if ui.configbool('ui', 'commitsubrepos'):
1444 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1444 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1445
1445
1446 old = repo['.']
1446 old = repo['.']
1447 if not old.mutable():
1447 if not old.mutable():
1448 raise util.Abort(_('cannot amend public changesets'))
1448 raise util.Abort(_('cannot amend public changesets'))
1449 if len(repo[None].parents()) > 1:
1449 if len(repo[None].parents()) > 1:
1450 raise util.Abort(_('cannot amend while merging'))
1450 raise util.Abort(_('cannot amend while merging'))
1451 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1451 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1452 if not allowunstable and old.children():
1452 if not allowunstable and old.children():
1453 raise util.Abort(_('cannot amend changeset with children'))
1453 raise util.Abort(_('cannot amend changeset with children'))
1454
1454
1455 # commitfunc is used only for temporary amend commit by cmdutil.amend
1455 # commitfunc is used only for temporary amend commit by cmdutil.amend
1456 def commitfunc(ui, repo, message, match, opts):
1456 def commitfunc(ui, repo, message, match, opts):
1457 return repo.commit(message,
1457 return repo.commit(message,
1458 opts.get('user') or old.user(),
1458 opts.get('user') or old.user(),
1459 opts.get('date') or old.date(),
1459 opts.get('date') or old.date(),
1460 match,
1460 match,
1461 extra=extra)
1461 extra=extra)
1462
1462
1463 current = repo._bookmarkcurrent
1463 current = repo._bookmarkcurrent
1464 marks = old.bookmarks()
1464 marks = old.bookmarks()
1465 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1465 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1466 if node == old.node():
1466 if node == old.node():
1467 ui.status(_("nothing changed\n"))
1467 ui.status(_("nothing changed\n"))
1468 return 1
1468 return 1
1469 elif marks:
1469 elif marks:
1470 ui.debug('moving bookmarks %r from %s to %s\n' %
1470 ui.debug('moving bookmarks %r from %s to %s\n' %
1471 (marks, old.hex(), hex(node)))
1471 (marks, old.hex(), hex(node)))
1472 newmarks = repo._bookmarks
1472 newmarks = repo._bookmarks
1473 for bm in marks:
1473 for bm in marks:
1474 newmarks[bm] = node
1474 newmarks[bm] = node
1475 if bm == current:
1475 if bm == current:
1476 bookmarks.setcurrent(repo, bm)
1476 bookmarks.setcurrent(repo, bm)
1477 newmarks.write()
1477 newmarks.write()
1478 else:
1478 else:
1479 def commitfunc(ui, repo, message, match, opts):
1479 def commitfunc(ui, repo, message, match, opts):
1480 backup = ui.backupconfig('phases', 'new-commit')
1480 backup = ui.backupconfig('phases', 'new-commit')
1481 baseui = repo.baseui
1481 baseui = repo.baseui
1482 basebackup = baseui.backupconfig('phases', 'new-commit')
1482 basebackup = baseui.backupconfig('phases', 'new-commit')
1483 try:
1483 try:
1484 if opts.get('secret'):
1484 if opts.get('secret'):
1485 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1485 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1486 # Propagate to subrepos
1486 # Propagate to subrepos
1487 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1487 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1488
1488
1489 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1489 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1490 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1490 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1491 return repo.commit(message, opts.get('user'), opts.get('date'),
1491 return repo.commit(message, opts.get('user'), opts.get('date'),
1492 match,
1492 match,
1493 editor=editor,
1493 editor=editor,
1494 extra=extra)
1494 extra=extra)
1495 finally:
1495 finally:
1496 ui.restoreconfig(backup)
1496 ui.restoreconfig(backup)
1497 repo.baseui.restoreconfig(basebackup)
1497 repo.baseui.restoreconfig(basebackup)
1498
1498
1499
1499
1500 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1500 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1501
1501
1502 if not node:
1502 if not node:
1503 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1503 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1504 if stat[3]:
1504 if stat[3]:
1505 ui.status(_("nothing changed (%d missing files, see "
1505 ui.status(_("nothing changed (%d missing files, see "
1506 "'hg status')\n") % len(stat[3]))
1506 "'hg status')\n") % len(stat[3]))
1507 else:
1507 else:
1508 ui.status(_("nothing changed\n"))
1508 ui.status(_("nothing changed\n"))
1509 return 1
1509 return 1
1510
1510
1511 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1511 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1512
1512
1513 @command('config|showconfig|debugconfig',
1513 @command('config|showconfig|debugconfig',
1514 [('u', 'untrusted', None, _('show untrusted configuration options')),
1514 [('u', 'untrusted', None, _('show untrusted configuration options')),
1515 ('e', 'edit', None, _('edit user config')),
1515 ('e', 'edit', None, _('edit user config')),
1516 ('l', 'local', None, _('edit repository config')),
1516 ('l', 'local', None, _('edit repository config')),
1517 ('g', 'global', None, _('edit global config'))],
1517 ('g', 'global', None, _('edit global config'))],
1518 _('[-u] [NAME]...'),
1518 _('[-u] [NAME]...'),
1519 optionalrepo=True)
1519 optionalrepo=True)
1520 def config(ui, repo, *values, **opts):
1520 def config(ui, repo, *values, **opts):
1521 """show combined config settings from all hgrc files
1521 """show combined config settings from all hgrc files
1522
1522
1523 With no arguments, print names and values of all config items.
1523 With no arguments, print names and values of all config items.
1524
1524
1525 With one argument of the form section.name, print just the value
1525 With one argument of the form section.name, print just the value
1526 of that config item.
1526 of that config item.
1527
1527
1528 With multiple arguments, print names and values of all config
1528 With multiple arguments, print names and values of all config
1529 items with matching section names.
1529 items with matching section names.
1530
1530
1531 With --edit, start an editor on the user-level config file. With
1531 With --edit, start an editor on the user-level config file. With
1532 --global, edit the system-wide config file. With --local, edit the
1532 --global, edit the system-wide config file. With --local, edit the
1533 repository-level config file.
1533 repository-level config file.
1534
1534
1535 With --debug, the source (filename and line number) is printed
1535 With --debug, the source (filename and line number) is printed
1536 for each config item.
1536 for each config item.
1537
1537
1538 See :hg:`help config` for more information about config files.
1538 See :hg:`help config` for more information about config files.
1539
1539
1540 Returns 0 on success, 1 if NAME does not exist.
1540 Returns 0 on success, 1 if NAME does not exist.
1541
1541
1542 """
1542 """
1543
1543
1544 if opts.get('edit') or opts.get('local') or opts.get('global'):
1544 if opts.get('edit') or opts.get('local') or opts.get('global'):
1545 if opts.get('local') and opts.get('global'):
1545 if opts.get('local') and opts.get('global'):
1546 raise util.Abort(_("can't use --local and --global together"))
1546 raise util.Abort(_("can't use --local and --global together"))
1547
1547
1548 if opts.get('local'):
1548 if opts.get('local'):
1549 if not repo:
1549 if not repo:
1550 raise util.Abort(_("can't use --local outside a repository"))
1550 raise util.Abort(_("can't use --local outside a repository"))
1551 paths = [repo.join('hgrc')]
1551 paths = [repo.join('hgrc')]
1552 elif opts.get('global'):
1552 elif opts.get('global'):
1553 paths = scmutil.systemrcpath()
1553 paths = scmutil.systemrcpath()
1554 else:
1554 else:
1555 paths = scmutil.userrcpath()
1555 paths = scmutil.userrcpath()
1556
1556
1557 for f in paths:
1557 for f in paths:
1558 if os.path.exists(f):
1558 if os.path.exists(f):
1559 break
1559 break
1560 else:
1560 else:
1561 if opts.get('global'):
1561 if opts.get('global'):
1562 samplehgrc = uimod.samplehgrcs['global']
1562 samplehgrc = uimod.samplehgrcs['global']
1563 elif opts.get('local'):
1563 elif opts.get('local'):
1564 samplehgrc = uimod.samplehgrcs['local']
1564 samplehgrc = uimod.samplehgrcs['local']
1565 else:
1565 else:
1566 samplehgrc = uimod.samplehgrcs['user']
1566 samplehgrc = uimod.samplehgrcs['user']
1567
1567
1568 f = paths[0]
1568 f = paths[0]
1569 fp = open(f, "w")
1569 fp = open(f, "w")
1570 fp.write(samplehgrc)
1570 fp.write(samplehgrc)
1571 fp.close()
1571 fp.close()
1572
1572
1573 editor = ui.geteditor()
1573 editor = ui.geteditor()
1574 ui.system("%s \"%s\"" % (editor, f),
1574 ui.system("%s \"%s\"" % (editor, f),
1575 onerr=util.Abort, errprefix=_("edit failed"))
1575 onerr=util.Abort, errprefix=_("edit failed"))
1576 return
1576 return
1577
1577
1578 for f in scmutil.rcpath():
1578 for f in scmutil.rcpath():
1579 ui.debug('read config from: %s\n' % f)
1579 ui.debug('read config from: %s\n' % f)
1580 untrusted = bool(opts.get('untrusted'))
1580 untrusted = bool(opts.get('untrusted'))
1581 if values:
1581 if values:
1582 sections = [v for v in values if '.' not in v]
1582 sections = [v for v in values if '.' not in v]
1583 items = [v for v in values if '.' in v]
1583 items = [v for v in values if '.' in v]
1584 if len(items) > 1 or items and sections:
1584 if len(items) > 1 or items and sections:
1585 raise util.Abort(_('only one config item permitted'))
1585 raise util.Abort(_('only one config item permitted'))
1586 matched = False
1586 matched = False
1587 for section, name, value in ui.walkconfig(untrusted=untrusted):
1587 for section, name, value in ui.walkconfig(untrusted=untrusted):
1588 value = str(value).replace('\n', '\\n')
1588 value = str(value).replace('\n', '\\n')
1589 sectname = section + '.' + name
1589 sectname = section + '.' + name
1590 if values:
1590 if values:
1591 for v in values:
1591 for v in values:
1592 if v == section:
1592 if v == section:
1593 ui.debug('%s: ' %
1593 ui.debug('%s: ' %
1594 ui.configsource(section, name, untrusted))
1594 ui.configsource(section, name, untrusted))
1595 ui.write('%s=%s\n' % (sectname, value))
1595 ui.write('%s=%s\n' % (sectname, value))
1596 matched = True
1596 matched = True
1597 elif v == sectname:
1597 elif v == sectname:
1598 ui.debug('%s: ' %
1598 ui.debug('%s: ' %
1599 ui.configsource(section, name, untrusted))
1599 ui.configsource(section, name, untrusted))
1600 ui.write(value, '\n')
1600 ui.write(value, '\n')
1601 matched = True
1601 matched = True
1602 else:
1602 else:
1603 ui.debug('%s: ' %
1603 ui.debug('%s: ' %
1604 ui.configsource(section, name, untrusted))
1604 ui.configsource(section, name, untrusted))
1605 ui.write('%s=%s\n' % (sectname, value))
1605 ui.write('%s=%s\n' % (sectname, value))
1606 matched = True
1606 matched = True
1607 if matched:
1607 if matched:
1608 return 0
1608 return 0
1609 return 1
1609 return 1
1610
1610
1611 @command('copy|cp',
1611 @command('copy|cp',
1612 [('A', 'after', None, _('record a copy that has already occurred')),
1612 [('A', 'after', None, _('record a copy that has already occurred')),
1613 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1613 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1614 ] + walkopts + dryrunopts,
1614 ] + walkopts + dryrunopts,
1615 _('[OPTION]... [SOURCE]... DEST'))
1615 _('[OPTION]... [SOURCE]... DEST'))
1616 def copy(ui, repo, *pats, **opts):
1616 def copy(ui, repo, *pats, **opts):
1617 """mark files as copied for the next commit
1617 """mark files as copied for the next commit
1618
1618
1619 Mark dest as having copies of source files. If dest is a
1619 Mark dest as having copies of source files. If dest is a
1620 directory, copies are put in that directory. If dest is a file,
1620 directory, copies are put in that directory. If dest is a file,
1621 the source must be a single file.
1621 the source must be a single file.
1622
1622
1623 By default, this command copies the contents of files as they
1623 By default, this command copies the contents of files as they
1624 exist in the working directory. If invoked with -A/--after, the
1624 exist in the working directory. If invoked with -A/--after, the
1625 operation is recorded, but no copying is performed.
1625 operation is recorded, but no copying is performed.
1626
1626
1627 This command takes effect with the next commit. To undo a copy
1627 This command takes effect with the next commit. To undo a copy
1628 before that, see :hg:`revert`.
1628 before that, see :hg:`revert`.
1629
1629
1630 Returns 0 on success, 1 if errors are encountered.
1630 Returns 0 on success, 1 if errors are encountered.
1631 """
1631 """
1632 wlock = repo.wlock(False)
1632 wlock = repo.wlock(False)
1633 try:
1633 try:
1634 return cmdutil.copy(ui, repo, pats, opts)
1634 return cmdutil.copy(ui, repo, pats, opts)
1635 finally:
1635 finally:
1636 wlock.release()
1636 wlock.release()
1637
1637
1638 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1638 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1639 def debugancestor(ui, repo, *args):
1639 def debugancestor(ui, repo, *args):
1640 """find the ancestor revision of two revisions in a given index"""
1640 """find the ancestor revision of two revisions in a given index"""
1641 if len(args) == 3:
1641 if len(args) == 3:
1642 index, rev1, rev2 = args
1642 index, rev1, rev2 = args
1643 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1643 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1644 lookup = r.lookup
1644 lookup = r.lookup
1645 elif len(args) == 2:
1645 elif len(args) == 2:
1646 if not repo:
1646 if not repo:
1647 raise util.Abort(_("there is no Mercurial repository here "
1647 raise util.Abort(_("there is no Mercurial repository here "
1648 "(.hg not found)"))
1648 "(.hg not found)"))
1649 rev1, rev2 = args
1649 rev1, rev2 = args
1650 r = repo.changelog
1650 r = repo.changelog
1651 lookup = repo.lookup
1651 lookup = repo.lookup
1652 else:
1652 else:
1653 raise util.Abort(_('either two or three arguments required'))
1653 raise util.Abort(_('either two or three arguments required'))
1654 a = r.ancestor(lookup(rev1), lookup(rev2))
1654 a = r.ancestor(lookup(rev1), lookup(rev2))
1655 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1655 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1656
1656
1657 @command('debugbuilddag',
1657 @command('debugbuilddag',
1658 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1658 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1659 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1659 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1660 ('n', 'new-file', None, _('add new file at each rev'))],
1660 ('n', 'new-file', None, _('add new file at each rev'))],
1661 _('[OPTION]... [TEXT]'))
1661 _('[OPTION]... [TEXT]'))
1662 def debugbuilddag(ui, repo, text=None,
1662 def debugbuilddag(ui, repo, text=None,
1663 mergeable_file=False,
1663 mergeable_file=False,
1664 overwritten_file=False,
1664 overwritten_file=False,
1665 new_file=False):
1665 new_file=False):
1666 """builds a repo with a given DAG from scratch in the current empty repo
1666 """builds a repo with a given DAG from scratch in the current empty repo
1667
1667
1668 The description of the DAG is read from stdin if not given on the
1668 The description of the DAG is read from stdin if not given on the
1669 command line.
1669 command line.
1670
1670
1671 Elements:
1671 Elements:
1672
1672
1673 - "+n" is a linear run of n nodes based on the current default parent
1673 - "+n" is a linear run of n nodes based on the current default parent
1674 - "." is a single node based on the current default parent
1674 - "." is a single node based on the current default parent
1675 - "$" resets the default parent to null (implied at the start);
1675 - "$" resets the default parent to null (implied at the start);
1676 otherwise the default parent is always the last node created
1676 otherwise the default parent is always the last node created
1677 - "<p" sets the default parent to the backref p
1677 - "<p" sets the default parent to the backref p
1678 - "*p" is a fork at parent p, which is a backref
1678 - "*p" is a fork at parent p, which is a backref
1679 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1679 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1680 - "/p2" is a merge of the preceding node and p2
1680 - "/p2" is a merge of the preceding node and p2
1681 - ":tag" defines a local tag for the preceding node
1681 - ":tag" defines a local tag for the preceding node
1682 - "@branch" sets the named branch for subsequent nodes
1682 - "@branch" sets the named branch for subsequent nodes
1683 - "#...\\n" is a comment up to the end of the line
1683 - "#...\\n" is a comment up to the end of the line
1684
1684
1685 Whitespace between the above elements is ignored.
1685 Whitespace between the above elements is ignored.
1686
1686
1687 A backref is either
1687 A backref is either
1688
1688
1689 - a number n, which references the node curr-n, where curr is the current
1689 - a number n, which references the node curr-n, where curr is the current
1690 node, or
1690 node, or
1691 - the name of a local tag you placed earlier using ":tag", or
1691 - the name of a local tag you placed earlier using ":tag", or
1692 - empty to denote the default parent.
1692 - empty to denote the default parent.
1693
1693
1694 All string valued-elements are either strictly alphanumeric, or must
1694 All string valued-elements are either strictly alphanumeric, or must
1695 be enclosed in double quotes ("..."), with "\\" as escape character.
1695 be enclosed in double quotes ("..."), with "\\" as escape character.
1696 """
1696 """
1697
1697
1698 if text is None:
1698 if text is None:
1699 ui.status(_("reading DAG from stdin\n"))
1699 ui.status(_("reading DAG from stdin\n"))
1700 text = ui.fin.read()
1700 text = ui.fin.read()
1701
1701
1702 cl = repo.changelog
1702 cl = repo.changelog
1703 if len(cl) > 0:
1703 if len(cl) > 0:
1704 raise util.Abort(_('repository is not empty'))
1704 raise util.Abort(_('repository is not empty'))
1705
1705
1706 # determine number of revs in DAG
1706 # determine number of revs in DAG
1707 total = 0
1707 total = 0
1708 for type, data in dagparser.parsedag(text):
1708 for type, data in dagparser.parsedag(text):
1709 if type == 'n':
1709 if type == 'n':
1710 total += 1
1710 total += 1
1711
1711
1712 if mergeable_file:
1712 if mergeable_file:
1713 linesperrev = 2
1713 linesperrev = 2
1714 # make a file with k lines per rev
1714 # make a file with k lines per rev
1715 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1715 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1716 initialmergedlines.append("")
1716 initialmergedlines.append("")
1717
1717
1718 tags = []
1718 tags = []
1719
1719
1720 lock = tr = None
1720 lock = tr = None
1721 try:
1721 try:
1722 lock = repo.lock()
1722 lock = repo.lock()
1723 tr = repo.transaction("builddag")
1723 tr = repo.transaction("builddag")
1724
1724
1725 at = -1
1725 at = -1
1726 atbranch = 'default'
1726 atbranch = 'default'
1727 nodeids = []
1727 nodeids = []
1728 id = 0
1728 id = 0
1729 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1729 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1730 for type, data in dagparser.parsedag(text):
1730 for type, data in dagparser.parsedag(text):
1731 if type == 'n':
1731 if type == 'n':
1732 ui.note(('node %s\n' % str(data)))
1732 ui.note(('node %s\n' % str(data)))
1733 id, ps = data
1733 id, ps = data
1734
1734
1735 files = []
1735 files = []
1736 fctxs = {}
1736 fctxs = {}
1737
1737
1738 p2 = None
1738 p2 = None
1739 if mergeable_file:
1739 if mergeable_file:
1740 fn = "mf"
1740 fn = "mf"
1741 p1 = repo[ps[0]]
1741 p1 = repo[ps[0]]
1742 if len(ps) > 1:
1742 if len(ps) > 1:
1743 p2 = repo[ps[1]]
1743 p2 = repo[ps[1]]
1744 pa = p1.ancestor(p2)
1744 pa = p1.ancestor(p2)
1745 base, local, other = [x[fn].data() for x in (pa, p1,
1745 base, local, other = [x[fn].data() for x in (pa, p1,
1746 p2)]
1746 p2)]
1747 m3 = simplemerge.Merge3Text(base, local, other)
1747 m3 = simplemerge.Merge3Text(base, local, other)
1748 ml = [l.strip() for l in m3.merge_lines()]
1748 ml = [l.strip() for l in m3.merge_lines()]
1749 ml.append("")
1749 ml.append("")
1750 elif at > 0:
1750 elif at > 0:
1751 ml = p1[fn].data().split("\n")
1751 ml = p1[fn].data().split("\n")
1752 else:
1752 else:
1753 ml = initialmergedlines
1753 ml = initialmergedlines
1754 ml[id * linesperrev] += " r%i" % id
1754 ml[id * linesperrev] += " r%i" % id
1755 mergedtext = "\n".join(ml)
1755 mergedtext = "\n".join(ml)
1756 files.append(fn)
1756 files.append(fn)
1757 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1757 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1758
1758
1759 if overwritten_file:
1759 if overwritten_file:
1760 fn = "of"
1760 fn = "of"
1761 files.append(fn)
1761 files.append(fn)
1762 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1762 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1763
1763
1764 if new_file:
1764 if new_file:
1765 fn = "nf%i" % id
1765 fn = "nf%i" % id
1766 files.append(fn)
1766 files.append(fn)
1767 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1767 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1768 if len(ps) > 1:
1768 if len(ps) > 1:
1769 if not p2:
1769 if not p2:
1770 p2 = repo[ps[1]]
1770 p2 = repo[ps[1]]
1771 for fn in p2:
1771 for fn in p2:
1772 if fn.startswith("nf"):
1772 if fn.startswith("nf"):
1773 files.append(fn)
1773 files.append(fn)
1774 fctxs[fn] = p2[fn]
1774 fctxs[fn] = p2[fn]
1775
1775
1776 def fctxfn(repo, cx, path):
1776 def fctxfn(repo, cx, path):
1777 return fctxs.get(path)
1777 return fctxs.get(path)
1778
1778
1779 if len(ps) == 0 or ps[0] < 0:
1779 if len(ps) == 0 or ps[0] < 0:
1780 pars = [None, None]
1780 pars = [None, None]
1781 elif len(ps) == 1:
1781 elif len(ps) == 1:
1782 pars = [nodeids[ps[0]], None]
1782 pars = [nodeids[ps[0]], None]
1783 else:
1783 else:
1784 pars = [nodeids[p] for p in ps]
1784 pars = [nodeids[p] for p in ps]
1785 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1785 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1786 date=(id, 0),
1786 date=(id, 0),
1787 user="debugbuilddag",
1787 user="debugbuilddag",
1788 extra={'branch': atbranch})
1788 extra={'branch': atbranch})
1789 nodeid = repo.commitctx(cx)
1789 nodeid = repo.commitctx(cx)
1790 nodeids.append(nodeid)
1790 nodeids.append(nodeid)
1791 at = id
1791 at = id
1792 elif type == 'l':
1792 elif type == 'l':
1793 id, name = data
1793 id, name = data
1794 ui.note(('tag %s\n' % name))
1794 ui.note(('tag %s\n' % name))
1795 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1795 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1796 elif type == 'a':
1796 elif type == 'a':
1797 ui.note(('branch %s\n' % data))
1797 ui.note(('branch %s\n' % data))
1798 atbranch = data
1798 atbranch = data
1799 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1799 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1800 tr.close()
1800 tr.close()
1801
1801
1802 if tags:
1802 if tags:
1803 repo.opener.write("localtags", "".join(tags))
1803 repo.opener.write("localtags", "".join(tags))
1804 finally:
1804 finally:
1805 ui.progress(_('building'), None)
1805 ui.progress(_('building'), None)
1806 release(tr, lock)
1806 release(tr, lock)
1807
1807
1808 @command('debugbundle',
1808 @command('debugbundle',
1809 [('a', 'all', None, _('show all details'))],
1809 [('a', 'all', None, _('show all details'))],
1810 _('FILE'),
1810 _('FILE'),
1811 norepo=True)
1811 norepo=True)
1812 def debugbundle(ui, bundlepath, all=None, **opts):
1812 def debugbundle(ui, bundlepath, all=None, **opts):
1813 """lists the contents of a bundle"""
1813 """lists the contents of a bundle"""
1814 f = hg.openpath(ui, bundlepath)
1814 f = hg.openpath(ui, bundlepath)
1815 try:
1815 try:
1816 gen = exchange.readbundle(ui, f, bundlepath)
1816 gen = exchange.readbundle(ui, f, bundlepath)
1817 if all:
1817 if all:
1818 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1818 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1819
1819
1820 def showchunks(named):
1820 def showchunks(named):
1821 ui.write("\n%s\n" % named)
1821 ui.write("\n%s\n" % named)
1822 chain = None
1822 chain = None
1823 while True:
1823 while True:
1824 chunkdata = gen.deltachunk(chain)
1824 chunkdata = gen.deltachunk(chain)
1825 if not chunkdata:
1825 if not chunkdata:
1826 break
1826 break
1827 node = chunkdata['node']
1827 node = chunkdata['node']
1828 p1 = chunkdata['p1']
1828 p1 = chunkdata['p1']
1829 p2 = chunkdata['p2']
1829 p2 = chunkdata['p2']
1830 cs = chunkdata['cs']
1830 cs = chunkdata['cs']
1831 deltabase = chunkdata['deltabase']
1831 deltabase = chunkdata['deltabase']
1832 delta = chunkdata['delta']
1832 delta = chunkdata['delta']
1833 ui.write("%s %s %s %s %s %s\n" %
1833 ui.write("%s %s %s %s %s %s\n" %
1834 (hex(node), hex(p1), hex(p2),
1834 (hex(node), hex(p1), hex(p2),
1835 hex(cs), hex(deltabase), len(delta)))
1835 hex(cs), hex(deltabase), len(delta)))
1836 chain = node
1836 chain = node
1837
1837
1838 chunkdata = gen.changelogheader()
1838 chunkdata = gen.changelogheader()
1839 showchunks("changelog")
1839 showchunks("changelog")
1840 chunkdata = gen.manifestheader()
1840 chunkdata = gen.manifestheader()
1841 showchunks("manifest")
1841 showchunks("manifest")
1842 while True:
1842 while True:
1843 chunkdata = gen.filelogheader()
1843 chunkdata = gen.filelogheader()
1844 if not chunkdata:
1844 if not chunkdata:
1845 break
1845 break
1846 fname = chunkdata['filename']
1846 fname = chunkdata['filename']
1847 showchunks(fname)
1847 showchunks(fname)
1848 else:
1848 else:
1849 chunkdata = gen.changelogheader()
1849 chunkdata = gen.changelogheader()
1850 chain = None
1850 chain = None
1851 while True:
1851 while True:
1852 chunkdata = gen.deltachunk(chain)
1852 chunkdata = gen.deltachunk(chain)
1853 if not chunkdata:
1853 if not chunkdata:
1854 break
1854 break
1855 node = chunkdata['node']
1855 node = chunkdata['node']
1856 ui.write("%s\n" % hex(node))
1856 ui.write("%s\n" % hex(node))
1857 chain = node
1857 chain = node
1858 finally:
1858 finally:
1859 f.close()
1859 f.close()
1860
1860
1861 @command('debugcheckstate', [], '')
1861 @command('debugcheckstate', [], '')
1862 def debugcheckstate(ui, repo):
1862 def debugcheckstate(ui, repo):
1863 """validate the correctness of the current dirstate"""
1863 """validate the correctness of the current dirstate"""
1864 parent1, parent2 = repo.dirstate.parents()
1864 parent1, parent2 = repo.dirstate.parents()
1865 m1 = repo[parent1].manifest()
1865 m1 = repo[parent1].manifest()
1866 m2 = repo[parent2].manifest()
1866 m2 = repo[parent2].manifest()
1867 errors = 0
1867 errors = 0
1868 for f in repo.dirstate:
1868 for f in repo.dirstate:
1869 state = repo.dirstate[f]
1869 state = repo.dirstate[f]
1870 if state in "nr" and f not in m1:
1870 if state in "nr" and f not in m1:
1871 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1871 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1872 errors += 1
1872 errors += 1
1873 if state in "a" and f in m1:
1873 if state in "a" and f in m1:
1874 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1874 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1875 errors += 1
1875 errors += 1
1876 if state in "m" and f not in m1 and f not in m2:
1876 if state in "m" and f not in m1 and f not in m2:
1877 ui.warn(_("%s in state %s, but not in either manifest\n") %
1877 ui.warn(_("%s in state %s, but not in either manifest\n") %
1878 (f, state))
1878 (f, state))
1879 errors += 1
1879 errors += 1
1880 for f in m1:
1880 for f in m1:
1881 state = repo.dirstate[f]
1881 state = repo.dirstate[f]
1882 if state not in "nrm":
1882 if state not in "nrm":
1883 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1883 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1884 errors += 1
1884 errors += 1
1885 if errors:
1885 if errors:
1886 error = _(".hg/dirstate inconsistent with current parent's manifest")
1886 error = _(".hg/dirstate inconsistent with current parent's manifest")
1887 raise util.Abort(error)
1887 raise util.Abort(error)
1888
1888
1889 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1889 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1890 def debugcommands(ui, cmd='', *args):
1890 def debugcommands(ui, cmd='', *args):
1891 """list all available commands and options"""
1891 """list all available commands and options"""
1892 for cmd, vals in sorted(table.iteritems()):
1892 for cmd, vals in sorted(table.iteritems()):
1893 cmd = cmd.split('|')[0].strip('^')
1893 cmd = cmd.split('|')[0].strip('^')
1894 opts = ', '.join([i[1] for i in vals[1]])
1894 opts = ', '.join([i[1] for i in vals[1]])
1895 ui.write('%s: %s\n' % (cmd, opts))
1895 ui.write('%s: %s\n' % (cmd, opts))
1896
1896
1897 @command('debugcomplete',
1897 @command('debugcomplete',
1898 [('o', 'options', None, _('show the command options'))],
1898 [('o', 'options', None, _('show the command options'))],
1899 _('[-o] CMD'),
1899 _('[-o] CMD'),
1900 norepo=True)
1900 norepo=True)
1901 def debugcomplete(ui, cmd='', **opts):
1901 def debugcomplete(ui, cmd='', **opts):
1902 """returns the completion list associated with the given command"""
1902 """returns the completion list associated with the given command"""
1903
1903
1904 if opts.get('options'):
1904 if opts.get('options'):
1905 options = []
1905 options = []
1906 otables = [globalopts]
1906 otables = [globalopts]
1907 if cmd:
1907 if cmd:
1908 aliases, entry = cmdutil.findcmd(cmd, table, False)
1908 aliases, entry = cmdutil.findcmd(cmd, table, False)
1909 otables.append(entry[1])
1909 otables.append(entry[1])
1910 for t in otables:
1910 for t in otables:
1911 for o in t:
1911 for o in t:
1912 if "(DEPRECATED)" in o[3]:
1912 if "(DEPRECATED)" in o[3]:
1913 continue
1913 continue
1914 if o[0]:
1914 if o[0]:
1915 options.append('-%s' % o[0])
1915 options.append('-%s' % o[0])
1916 options.append('--%s' % o[1])
1916 options.append('--%s' % o[1])
1917 ui.write("%s\n" % "\n".join(options))
1917 ui.write("%s\n" % "\n".join(options))
1918 return
1918 return
1919
1919
1920 cmdlist = cmdutil.findpossible(cmd, table)
1920 cmdlist = cmdutil.findpossible(cmd, table)
1921 if ui.verbose:
1921 if ui.verbose:
1922 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1922 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1923 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1923 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1924
1924
1925 @command('debugdag',
1925 @command('debugdag',
1926 [('t', 'tags', None, _('use tags as labels')),
1926 [('t', 'tags', None, _('use tags as labels')),
1927 ('b', 'branches', None, _('annotate with branch names')),
1927 ('b', 'branches', None, _('annotate with branch names')),
1928 ('', 'dots', None, _('use dots for runs')),
1928 ('', 'dots', None, _('use dots for runs')),
1929 ('s', 'spaces', None, _('separate elements by spaces'))],
1929 ('s', 'spaces', None, _('separate elements by spaces'))],
1930 _('[OPTION]... [FILE [REV]...]'),
1930 _('[OPTION]... [FILE [REV]...]'),
1931 optionalrepo=True)
1931 optionalrepo=True)
1932 def debugdag(ui, repo, file_=None, *revs, **opts):
1932 def debugdag(ui, repo, file_=None, *revs, **opts):
1933 """format the changelog or an index DAG as a concise textual description
1933 """format the changelog or an index DAG as a concise textual description
1934
1934
1935 If you pass a revlog index, the revlog's DAG is emitted. If you list
1935 If you pass a revlog index, the revlog's DAG is emitted. If you list
1936 revision numbers, they get labeled in the output as rN.
1936 revision numbers, they get labeled in the output as rN.
1937
1937
1938 Otherwise, the changelog DAG of the current repo is emitted.
1938 Otherwise, the changelog DAG of the current repo is emitted.
1939 """
1939 """
1940 spaces = opts.get('spaces')
1940 spaces = opts.get('spaces')
1941 dots = opts.get('dots')
1941 dots = opts.get('dots')
1942 if file_:
1942 if file_:
1943 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1943 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1944 revs = set((int(r) for r in revs))
1944 revs = set((int(r) for r in revs))
1945 def events():
1945 def events():
1946 for r in rlog:
1946 for r in rlog:
1947 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1947 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1948 if p != -1))
1948 if p != -1))
1949 if r in revs:
1949 if r in revs:
1950 yield 'l', (r, "r%i" % r)
1950 yield 'l', (r, "r%i" % r)
1951 elif repo:
1951 elif repo:
1952 cl = repo.changelog
1952 cl = repo.changelog
1953 tags = opts.get('tags')
1953 tags = opts.get('tags')
1954 branches = opts.get('branches')
1954 branches = opts.get('branches')
1955 if tags:
1955 if tags:
1956 labels = {}
1956 labels = {}
1957 for l, n in repo.tags().items():
1957 for l, n in repo.tags().items():
1958 labels.setdefault(cl.rev(n), []).append(l)
1958 labels.setdefault(cl.rev(n), []).append(l)
1959 def events():
1959 def events():
1960 b = "default"
1960 b = "default"
1961 for r in cl:
1961 for r in cl:
1962 if branches:
1962 if branches:
1963 newb = cl.read(cl.node(r))[5]['branch']
1963 newb = cl.read(cl.node(r))[5]['branch']
1964 if newb != b:
1964 if newb != b:
1965 yield 'a', newb
1965 yield 'a', newb
1966 b = newb
1966 b = newb
1967 yield 'n', (r, list(p for p in cl.parentrevs(r)
1967 yield 'n', (r, list(p for p in cl.parentrevs(r)
1968 if p != -1))
1968 if p != -1))
1969 if tags:
1969 if tags:
1970 ls = labels.get(r)
1970 ls = labels.get(r)
1971 if ls:
1971 if ls:
1972 for l in ls:
1972 for l in ls:
1973 yield 'l', (r, l)
1973 yield 'l', (r, l)
1974 else:
1974 else:
1975 raise util.Abort(_('need repo for changelog dag'))
1975 raise util.Abort(_('need repo for changelog dag'))
1976
1976
1977 for line in dagparser.dagtextlines(events(),
1977 for line in dagparser.dagtextlines(events(),
1978 addspaces=spaces,
1978 addspaces=spaces,
1979 wraplabels=True,
1979 wraplabels=True,
1980 wrapannotations=True,
1980 wrapannotations=True,
1981 wrapnonlinear=dots,
1981 wrapnonlinear=dots,
1982 usedots=dots,
1982 usedots=dots,
1983 maxlinewidth=70):
1983 maxlinewidth=70):
1984 ui.write(line)
1984 ui.write(line)
1985 ui.write("\n")
1985 ui.write("\n")
1986
1986
1987 @command('debugdata',
1987 @command('debugdata',
1988 [('c', 'changelog', False, _('open changelog')),
1988 [('c', 'changelog', False, _('open changelog')),
1989 ('m', 'manifest', False, _('open manifest'))],
1989 ('m', 'manifest', False, _('open manifest'))],
1990 _('-c|-m|FILE REV'))
1990 _('-c|-m|FILE REV'))
1991 def debugdata(ui, repo, file_, rev=None, **opts):
1991 def debugdata(ui, repo, file_, rev=None, **opts):
1992 """dump the contents of a data file revision"""
1992 """dump the contents of a data file revision"""
1993 if opts.get('changelog') or opts.get('manifest'):
1993 if opts.get('changelog') or opts.get('manifest'):
1994 file_, rev = None, file_
1994 file_, rev = None, file_
1995 elif rev is None:
1995 elif rev is None:
1996 raise error.CommandError('debugdata', _('invalid arguments'))
1996 raise error.CommandError('debugdata', _('invalid arguments'))
1997 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1997 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1998 try:
1998 try:
1999 ui.write(r.revision(r.lookup(rev)))
1999 ui.write(r.revision(r.lookup(rev)))
2000 except KeyError:
2000 except KeyError:
2001 raise util.Abort(_('invalid revision identifier %s') % rev)
2001 raise util.Abort(_('invalid revision identifier %s') % rev)
2002
2002
2003 @command('debugdate',
2003 @command('debugdate',
2004 [('e', 'extended', None, _('try extended date formats'))],
2004 [('e', 'extended', None, _('try extended date formats'))],
2005 _('[-e] DATE [RANGE]'),
2005 _('[-e] DATE [RANGE]'),
2006 norepo=True, optionalrepo=True)
2006 norepo=True, optionalrepo=True)
2007 def debugdate(ui, date, range=None, **opts):
2007 def debugdate(ui, date, range=None, **opts):
2008 """parse and display a date"""
2008 """parse and display a date"""
2009 if opts["extended"]:
2009 if opts["extended"]:
2010 d = util.parsedate(date, util.extendeddateformats)
2010 d = util.parsedate(date, util.extendeddateformats)
2011 else:
2011 else:
2012 d = util.parsedate(date)
2012 d = util.parsedate(date)
2013 ui.write(("internal: %s %s\n") % d)
2013 ui.write(("internal: %s %s\n") % d)
2014 ui.write(("standard: %s\n") % util.datestr(d))
2014 ui.write(("standard: %s\n") % util.datestr(d))
2015 if range:
2015 if range:
2016 m = util.matchdate(range)
2016 m = util.matchdate(range)
2017 ui.write(("match: %s\n") % m(d[0]))
2017 ui.write(("match: %s\n") % m(d[0]))
2018
2018
2019 @command('debugdiscovery',
2019 @command('debugdiscovery',
2020 [('', 'old', None, _('use old-style discovery')),
2020 [('', 'old', None, _('use old-style discovery')),
2021 ('', 'nonheads', None,
2021 ('', 'nonheads', None,
2022 _('use old-style discovery with non-heads included')),
2022 _('use old-style discovery with non-heads included')),
2023 ] + remoteopts,
2023 ] + remoteopts,
2024 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2024 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2025 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2025 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2026 """runs the changeset discovery protocol in isolation"""
2026 """runs the changeset discovery protocol in isolation"""
2027 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2027 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2028 opts.get('branch'))
2028 opts.get('branch'))
2029 remote = hg.peer(repo, opts, remoteurl)
2029 remote = hg.peer(repo, opts, remoteurl)
2030 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2030 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2031
2031
2032 # make sure tests are repeatable
2032 # make sure tests are repeatable
2033 random.seed(12323)
2033 random.seed(12323)
2034
2034
2035 def doit(localheads, remoteheads, remote=remote):
2035 def doit(localheads, remoteheads, remote=remote):
2036 if opts.get('old'):
2036 if opts.get('old'):
2037 if localheads:
2037 if localheads:
2038 raise util.Abort('cannot use localheads with old style '
2038 raise util.Abort('cannot use localheads with old style '
2039 'discovery')
2039 'discovery')
2040 if not util.safehasattr(remote, 'branches'):
2040 if not util.safehasattr(remote, 'branches'):
2041 # enable in-client legacy support
2041 # enable in-client legacy support
2042 remote = localrepo.locallegacypeer(remote.local())
2042 remote = localrepo.locallegacypeer(remote.local())
2043 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2043 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2044 force=True)
2044 force=True)
2045 common = set(common)
2045 common = set(common)
2046 if not opts.get('nonheads'):
2046 if not opts.get('nonheads'):
2047 ui.write(("unpruned common: %s\n") %
2047 ui.write(("unpruned common: %s\n") %
2048 " ".join(sorted(short(n) for n in common)))
2048 " ".join(sorted(short(n) for n in common)))
2049 dag = dagutil.revlogdag(repo.changelog)
2049 dag = dagutil.revlogdag(repo.changelog)
2050 all = dag.ancestorset(dag.internalizeall(common))
2050 all = dag.ancestorset(dag.internalizeall(common))
2051 common = dag.externalizeall(dag.headsetofconnecteds(all))
2051 common = dag.externalizeall(dag.headsetofconnecteds(all))
2052 else:
2052 else:
2053 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2053 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2054 common = set(common)
2054 common = set(common)
2055 rheads = set(hds)
2055 rheads = set(hds)
2056 lheads = set(repo.heads())
2056 lheads = set(repo.heads())
2057 ui.write(("common heads: %s\n") %
2057 ui.write(("common heads: %s\n") %
2058 " ".join(sorted(short(n) for n in common)))
2058 " ".join(sorted(short(n) for n in common)))
2059 if lheads <= common:
2059 if lheads <= common:
2060 ui.write(("local is subset\n"))
2060 ui.write(("local is subset\n"))
2061 elif rheads <= common:
2061 elif rheads <= common:
2062 ui.write(("remote is subset\n"))
2062 ui.write(("remote is subset\n"))
2063
2063
2064 serverlogs = opts.get('serverlog')
2064 serverlogs = opts.get('serverlog')
2065 if serverlogs:
2065 if serverlogs:
2066 for filename in serverlogs:
2066 for filename in serverlogs:
2067 logfile = open(filename, 'r')
2067 logfile = open(filename, 'r')
2068 try:
2068 try:
2069 line = logfile.readline()
2069 line = logfile.readline()
2070 while line:
2070 while line:
2071 parts = line.strip().split(';')
2071 parts = line.strip().split(';')
2072 op = parts[1]
2072 op = parts[1]
2073 if op == 'cg':
2073 if op == 'cg':
2074 pass
2074 pass
2075 elif op == 'cgss':
2075 elif op == 'cgss':
2076 doit(parts[2].split(' '), parts[3].split(' '))
2076 doit(parts[2].split(' '), parts[3].split(' '))
2077 elif op == 'unb':
2077 elif op == 'unb':
2078 doit(parts[3].split(' '), parts[2].split(' '))
2078 doit(parts[3].split(' '), parts[2].split(' '))
2079 line = logfile.readline()
2079 line = logfile.readline()
2080 finally:
2080 finally:
2081 logfile.close()
2081 logfile.close()
2082
2082
2083 else:
2083 else:
2084 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2084 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2085 opts.get('remote_head'))
2085 opts.get('remote_head'))
2086 localrevs = opts.get('local_head')
2086 localrevs = opts.get('local_head')
2087 doit(localrevs, remoterevs)
2087 doit(localrevs, remoterevs)
2088
2088
2089 @command('debugfileset',
2089 @command('debugfileset',
2090 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2090 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2091 _('[-r REV] FILESPEC'))
2091 _('[-r REV] FILESPEC'))
2092 def debugfileset(ui, repo, expr, **opts):
2092 def debugfileset(ui, repo, expr, **opts):
2093 '''parse and apply a fileset specification'''
2093 '''parse and apply a fileset specification'''
2094 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2094 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2095 if ui.verbose:
2095 if ui.verbose:
2096 tree = fileset.parse(expr)[0]
2096 tree = fileset.parse(expr)[0]
2097 ui.note(tree, "\n")
2097 ui.note(tree, "\n")
2098
2098
2099 for f in ctx.getfileset(expr):
2099 for f in ctx.getfileset(expr):
2100 ui.write("%s\n" % f)
2100 ui.write("%s\n" % f)
2101
2101
2102 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2102 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2103 def debugfsinfo(ui, path="."):
2103 def debugfsinfo(ui, path="."):
2104 """show information detected about current filesystem"""
2104 """show information detected about current filesystem"""
2105 util.writefile('.debugfsinfo', '')
2105 util.writefile('.debugfsinfo', '')
2106 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2106 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2107 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2107 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2108 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2108 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2109 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2109 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2110 and 'yes' or 'no'))
2110 and 'yes' or 'no'))
2111 os.unlink('.debugfsinfo')
2111 os.unlink('.debugfsinfo')
2112
2112
2113 @command('debuggetbundle',
2113 @command('debuggetbundle',
2114 [('H', 'head', [], _('id of head node'), _('ID')),
2114 [('H', 'head', [], _('id of head node'), _('ID')),
2115 ('C', 'common', [], _('id of common node'), _('ID')),
2115 ('C', 'common', [], _('id of common node'), _('ID')),
2116 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2116 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2117 _('REPO FILE [-H|-C ID]...'),
2117 _('REPO FILE [-H|-C ID]...'),
2118 norepo=True)
2118 norepo=True)
2119 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2119 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2120 """retrieves a bundle from a repo
2120 """retrieves a bundle from a repo
2121
2121
2122 Every ID must be a full-length hex node id string. Saves the bundle to the
2122 Every ID must be a full-length hex node id string. Saves the bundle to the
2123 given file.
2123 given file.
2124 """
2124 """
2125 repo = hg.peer(ui, opts, repopath)
2125 repo = hg.peer(ui, opts, repopath)
2126 if not repo.capable('getbundle'):
2126 if not repo.capable('getbundle'):
2127 raise util.Abort("getbundle() not supported by target repository")
2127 raise util.Abort("getbundle() not supported by target repository")
2128 args = {}
2128 args = {}
2129 if common:
2129 if common:
2130 args['common'] = [bin(s) for s in common]
2130 args['common'] = [bin(s) for s in common]
2131 if head:
2131 if head:
2132 args['heads'] = [bin(s) for s in head]
2132 args['heads'] = [bin(s) for s in head]
2133 # TODO: get desired bundlecaps from command line.
2133 # TODO: get desired bundlecaps from command line.
2134 args['bundlecaps'] = None
2134 args['bundlecaps'] = None
2135 bundle = repo.getbundle('debug', **args)
2135 bundle = repo.getbundle('debug', **args)
2136
2136
2137 bundletype = opts.get('type', 'bzip2').lower()
2137 bundletype = opts.get('type', 'bzip2').lower()
2138 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2138 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2139 bundletype = btypes.get(bundletype)
2139 bundletype = btypes.get(bundletype)
2140 if bundletype not in changegroup.bundletypes:
2140 if bundletype not in changegroup.bundletypes:
2141 raise util.Abort(_('unknown bundle type specified with --type'))
2141 raise util.Abort(_('unknown bundle type specified with --type'))
2142 changegroup.writebundle(bundle, bundlepath, bundletype)
2142 changegroup.writebundle(bundle, bundlepath, bundletype)
2143
2143
2144 @command('debugignore', [], '')
2144 @command('debugignore', [], '')
2145 def debugignore(ui, repo, *values, **opts):
2145 def debugignore(ui, repo, *values, **opts):
2146 """display the combined ignore pattern"""
2146 """display the combined ignore pattern"""
2147 ignore = repo.dirstate._ignore
2147 ignore = repo.dirstate._ignore
2148 includepat = getattr(ignore, 'includepat', None)
2148 includepat = getattr(ignore, 'includepat', None)
2149 if includepat is not None:
2149 if includepat is not None:
2150 ui.write("%s\n" % includepat)
2150 ui.write("%s\n" % includepat)
2151 else:
2151 else:
2152 raise util.Abort(_("no ignore patterns found"))
2152 raise util.Abort(_("no ignore patterns found"))
2153
2153
2154 @command('debugindex',
2154 @command('debugindex',
2155 [('c', 'changelog', False, _('open changelog')),
2155 [('c', 'changelog', False, _('open changelog')),
2156 ('m', 'manifest', False, _('open manifest')),
2156 ('m', 'manifest', False, _('open manifest')),
2157 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2157 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2158 _('[-f FORMAT] -c|-m|FILE'),
2158 _('[-f FORMAT] -c|-m|FILE'),
2159 optionalrepo=True)
2159 optionalrepo=True)
2160 def debugindex(ui, repo, file_=None, **opts):
2160 def debugindex(ui, repo, file_=None, **opts):
2161 """dump the contents of an index file"""
2161 """dump the contents of an index file"""
2162 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2162 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2163 format = opts.get('format', 0)
2163 format = opts.get('format', 0)
2164 if format not in (0, 1):
2164 if format not in (0, 1):
2165 raise util.Abort(_("unknown format %d") % format)
2165 raise util.Abort(_("unknown format %d") % format)
2166
2166
2167 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2167 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2168 if generaldelta:
2168 if generaldelta:
2169 basehdr = ' delta'
2169 basehdr = ' delta'
2170 else:
2170 else:
2171 basehdr = ' base'
2171 basehdr = ' base'
2172
2172
2173 if format == 0:
2173 if format == 0:
2174 ui.write(" rev offset length " + basehdr + " linkrev"
2174 ui.write(" rev offset length " + basehdr + " linkrev"
2175 " nodeid p1 p2\n")
2175 " nodeid p1 p2\n")
2176 elif format == 1:
2176 elif format == 1:
2177 ui.write(" rev flag offset length"
2177 ui.write(" rev flag offset length"
2178 " size " + basehdr + " link p1 p2"
2178 " size " + basehdr + " link p1 p2"
2179 " nodeid\n")
2179 " nodeid\n")
2180
2180
2181 for i in r:
2181 for i in r:
2182 node = r.node(i)
2182 node = r.node(i)
2183 if generaldelta:
2183 if generaldelta:
2184 base = r.deltaparent(i)
2184 base = r.deltaparent(i)
2185 else:
2185 else:
2186 base = r.chainbase(i)
2186 base = r.chainbase(i)
2187 if format == 0:
2187 if format == 0:
2188 try:
2188 try:
2189 pp = r.parents(node)
2189 pp = r.parents(node)
2190 except Exception:
2190 except Exception:
2191 pp = [nullid, nullid]
2191 pp = [nullid, nullid]
2192 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2192 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2193 i, r.start(i), r.length(i), base, r.linkrev(i),
2193 i, r.start(i), r.length(i), base, r.linkrev(i),
2194 short(node), short(pp[0]), short(pp[1])))
2194 short(node), short(pp[0]), short(pp[1])))
2195 elif format == 1:
2195 elif format == 1:
2196 pr = r.parentrevs(i)
2196 pr = r.parentrevs(i)
2197 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2197 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2198 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2198 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2199 base, r.linkrev(i), pr[0], pr[1], short(node)))
2199 base, r.linkrev(i), pr[0], pr[1], short(node)))
2200
2200
2201 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2201 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2202 def debugindexdot(ui, repo, file_):
2202 def debugindexdot(ui, repo, file_):
2203 """dump an index DAG as a graphviz dot file"""
2203 """dump an index DAG as a graphviz dot file"""
2204 r = None
2204 r = None
2205 if repo:
2205 if repo:
2206 filelog = repo.file(file_)
2206 filelog = repo.file(file_)
2207 if len(filelog):
2207 if len(filelog):
2208 r = filelog
2208 r = filelog
2209 if not r:
2209 if not r:
2210 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2210 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2211 ui.write(("digraph G {\n"))
2211 ui.write(("digraph G {\n"))
2212 for i in r:
2212 for i in r:
2213 node = r.node(i)
2213 node = r.node(i)
2214 pp = r.parents(node)
2214 pp = r.parents(node)
2215 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2215 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2216 if pp[1] != nullid:
2216 if pp[1] != nullid:
2217 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2217 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2218 ui.write("}\n")
2218 ui.write("}\n")
2219
2219
2220 @command('debuginstall', [], '', norepo=True)
2220 @command('debuginstall', [], '', norepo=True)
2221 def debuginstall(ui):
2221 def debuginstall(ui):
2222 '''test Mercurial installation
2222 '''test Mercurial installation
2223
2223
2224 Returns 0 on success.
2224 Returns 0 on success.
2225 '''
2225 '''
2226
2226
2227 def writetemp(contents):
2227 def writetemp(contents):
2228 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2228 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2229 f = os.fdopen(fd, "wb")
2229 f = os.fdopen(fd, "wb")
2230 f.write(contents)
2230 f.write(contents)
2231 f.close()
2231 f.close()
2232 return name
2232 return name
2233
2233
2234 problems = 0
2234 problems = 0
2235
2235
2236 # encoding
2236 # encoding
2237 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2237 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2238 try:
2238 try:
2239 encoding.fromlocal("test")
2239 encoding.fromlocal("test")
2240 except util.Abort, inst:
2240 except util.Abort, inst:
2241 ui.write(" %s\n" % inst)
2241 ui.write(" %s\n" % inst)
2242 ui.write(_(" (check that your locale is properly set)\n"))
2242 ui.write(_(" (check that your locale is properly set)\n"))
2243 problems += 1
2243 problems += 1
2244
2244
2245 # Python
2245 # Python
2246 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2246 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2247 ui.status(_("checking Python version (%s)\n")
2247 ui.status(_("checking Python version (%s)\n")
2248 % ("%s.%s.%s" % sys.version_info[:3]))
2248 % ("%s.%s.%s" % sys.version_info[:3]))
2249 ui.status(_("checking Python lib (%s)...\n")
2249 ui.status(_("checking Python lib (%s)...\n")
2250 % os.path.dirname(os.__file__))
2250 % os.path.dirname(os.__file__))
2251
2251
2252 # compiled modules
2252 # compiled modules
2253 ui.status(_("checking installed modules (%s)...\n")
2253 ui.status(_("checking installed modules (%s)...\n")
2254 % os.path.dirname(__file__))
2254 % os.path.dirname(__file__))
2255 try:
2255 try:
2256 import bdiff, mpatch, base85, osutil
2256 import bdiff, mpatch, base85, osutil
2257 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2257 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2258 except Exception, inst:
2258 except Exception, inst:
2259 ui.write(" %s\n" % inst)
2259 ui.write(" %s\n" % inst)
2260 ui.write(_(" One or more extensions could not be found"))
2260 ui.write(_(" One or more extensions could not be found"))
2261 ui.write(_(" (check that you compiled the extensions)\n"))
2261 ui.write(_(" (check that you compiled the extensions)\n"))
2262 problems += 1
2262 problems += 1
2263
2263
2264 # templates
2264 # templates
2265 import templater
2265 import templater
2266 p = templater.templatepaths()
2266 p = templater.templatepaths()
2267 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2267 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2268 if p:
2268 if p:
2269 m = templater.templatepath("map-cmdline.default")
2269 m = templater.templatepath("map-cmdline.default")
2270 if m:
2270 if m:
2271 # template found, check if it is working
2271 # template found, check if it is working
2272 try:
2272 try:
2273 templater.templater(m)
2273 templater.templater(m)
2274 except Exception, inst:
2274 except Exception, inst:
2275 ui.write(" %s\n" % inst)
2275 ui.write(" %s\n" % inst)
2276 p = None
2276 p = None
2277 else:
2277 else:
2278 ui.write(_(" template 'default' not found\n"))
2278 ui.write(_(" template 'default' not found\n"))
2279 p = None
2279 p = None
2280 else:
2280 else:
2281 ui.write(_(" no template directories found\n"))
2281 ui.write(_(" no template directories found\n"))
2282 if not p:
2282 if not p:
2283 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2283 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2284 problems += 1
2284 problems += 1
2285
2285
2286 # editor
2286 # editor
2287 ui.status(_("checking commit editor...\n"))
2287 ui.status(_("checking commit editor...\n"))
2288 editor = ui.geteditor()
2288 editor = ui.geteditor()
2289 cmdpath = util.findexe(shlex.split(editor)[0])
2289 cmdpath = util.findexe(shlex.split(editor)[0])
2290 if not cmdpath:
2290 if not cmdpath:
2291 if editor == 'vi':
2291 if editor == 'vi':
2292 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2292 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2293 ui.write(_(" (specify a commit editor in your configuration"
2293 ui.write(_(" (specify a commit editor in your configuration"
2294 " file)\n"))
2294 " file)\n"))
2295 else:
2295 else:
2296 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2296 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2297 ui.write(_(" (specify a commit editor in your configuration"
2297 ui.write(_(" (specify a commit editor in your configuration"
2298 " file)\n"))
2298 " file)\n"))
2299 problems += 1
2299 problems += 1
2300
2300
2301 # check username
2301 # check username
2302 ui.status(_("checking username...\n"))
2302 ui.status(_("checking username...\n"))
2303 try:
2303 try:
2304 ui.username()
2304 ui.username()
2305 except util.Abort, e:
2305 except util.Abort, e:
2306 ui.write(" %s\n" % e)
2306 ui.write(" %s\n" % e)
2307 ui.write(_(" (specify a username in your configuration file)\n"))
2307 ui.write(_(" (specify a username in your configuration file)\n"))
2308 problems += 1
2308 problems += 1
2309
2309
2310 if not problems:
2310 if not problems:
2311 ui.status(_("no problems detected\n"))
2311 ui.status(_("no problems detected\n"))
2312 else:
2312 else:
2313 ui.write(_("%s problems detected,"
2313 ui.write(_("%s problems detected,"
2314 " please check your install!\n") % problems)
2314 " please check your install!\n") % problems)
2315
2315
2316 return problems
2316 return problems
2317
2317
2318 @command('debugknown', [], _('REPO ID...'), norepo=True)
2318 @command('debugknown', [], _('REPO ID...'), norepo=True)
2319 def debugknown(ui, repopath, *ids, **opts):
2319 def debugknown(ui, repopath, *ids, **opts):
2320 """test whether node ids are known to a repo
2320 """test whether node ids are known to a repo
2321
2321
2322 Every ID must be a full-length hex node id string. Returns a list of 0s
2322 Every ID must be a full-length hex node id string. Returns a list of 0s
2323 and 1s indicating unknown/known.
2323 and 1s indicating unknown/known.
2324 """
2324 """
2325 repo = hg.peer(ui, opts, repopath)
2325 repo = hg.peer(ui, opts, repopath)
2326 if not repo.capable('known'):
2326 if not repo.capable('known'):
2327 raise util.Abort("known() not supported by target repository")
2327 raise util.Abort("known() not supported by target repository")
2328 flags = repo.known([bin(s) for s in ids])
2328 flags = repo.known([bin(s) for s in ids])
2329 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2329 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2330
2330
2331 @command('debuglabelcomplete', [], _('LABEL...'))
2331 @command('debuglabelcomplete', [], _('LABEL...'))
2332 def debuglabelcomplete(ui, repo, *args):
2332 def debuglabelcomplete(ui, repo, *args):
2333 '''complete "labels" - tags, open branch names, bookmark names'''
2333 '''complete "labels" - tags, open branch names, bookmark names'''
2334
2334
2335 labels = set()
2335 labels = set()
2336 labels.update(t[0] for t in repo.tagslist())
2336 labels.update(t[0] for t in repo.tagslist())
2337 labels.update(repo._bookmarks.keys())
2337 labels.update(repo._bookmarks.keys())
2338 labels.update(tag for (tag, heads, tip, closed)
2338 labels.update(tag for (tag, heads, tip, closed)
2339 in repo.branchmap().iterbranches() if not closed)
2339 in repo.branchmap().iterbranches() if not closed)
2340 completions = set()
2340 completions = set()
2341 if not args:
2341 if not args:
2342 args = ['']
2342 args = ['']
2343 for a in args:
2343 for a in args:
2344 completions.update(l for l in labels if l.startswith(a))
2344 completions.update(l for l in labels if l.startswith(a))
2345 ui.write('\n'.join(sorted(completions)))
2345 ui.write('\n'.join(sorted(completions)))
2346 ui.write('\n')
2346 ui.write('\n')
2347
2347
2348 @command('debuglocks',
2348 @command('debuglocks',
2349 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2349 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2350 ('W', 'force-wlock', None,
2350 ('W', 'force-wlock', None,
2351 _('free the working state lock (DANGEROUS)'))],
2351 _('free the working state lock (DANGEROUS)'))],
2352 _('[OPTION]...'))
2352 _('[OPTION]...'))
2353 def debuglocks(ui, repo, **opts):
2353 def debuglocks(ui, repo, **opts):
2354 """show or modify state of locks
2354 """show or modify state of locks
2355
2355
2356 By default, this command will show which locks are held. This
2356 By default, this command will show which locks are held. This
2357 includes the user and process holding the lock, the amount of time
2357 includes the user and process holding the lock, the amount of time
2358 the lock has been held, and the machine name where the process is
2358 the lock has been held, and the machine name where the process is
2359 running if it's not local.
2359 running if it's not local.
2360
2360
2361 Locks protect the integrity of Mercurial's data, so should be
2361 Locks protect the integrity of Mercurial's data, so should be
2362 treated with care. System crashes or other interruptions may cause
2362 treated with care. System crashes or other interruptions may cause
2363 locks to not be properly released, though Mercurial will usually
2363 locks to not be properly released, though Mercurial will usually
2364 detect and remove such stale locks automatically.
2364 detect and remove such stale locks automatically.
2365
2365
2366 However, detecting stale locks may not always be possible (for
2366 However, detecting stale locks may not always be possible (for
2367 instance, on a shared filesystem). Removing locks may also be
2367 instance, on a shared filesystem). Removing locks may also be
2368 blocked by filesystem permissions.
2368 blocked by filesystem permissions.
2369
2369
2370 Returns 0 if no locks are held.
2370 Returns 0 if no locks are held.
2371
2371
2372 """
2372 """
2373
2373
2374 if opts.get('force_lock'):
2374 if opts.get('force_lock'):
2375 repo.svfs.unlink('lock')
2375 repo.svfs.unlink('lock')
2376 if opts.get('force_wlock'):
2376 if opts.get('force_wlock'):
2377 repo.vfs.unlink('wlock')
2377 repo.vfs.unlink('wlock')
2378 if opts.get('force_lock') or opts.get('force_lock'):
2378 if opts.get('force_lock') or opts.get('force_lock'):
2379 return 0
2379 return 0
2380
2380
2381 now = time.time()
2381 now = time.time()
2382 held = 0
2382 held = 0
2383
2383
2384 def report(vfs, name, method):
2384 def report(vfs, name, method):
2385 # this causes stale locks to get reaped for more accurate reporting
2385 # this causes stale locks to get reaped for more accurate reporting
2386 try:
2386 try:
2387 l = method(False)
2387 l = method(False)
2388 except error.LockHeld:
2388 except error.LockHeld:
2389 l = None
2389 l = None
2390
2390
2391 if l:
2391 if l:
2392 l.release()
2392 l.release()
2393 else:
2393 else:
2394 try:
2394 try:
2395 stat = repo.svfs.lstat(name)
2395 stat = repo.svfs.lstat(name)
2396 age = now - stat.st_mtime
2396 age = now - stat.st_mtime
2397 user = util.username(stat.st_uid)
2397 user = util.username(stat.st_uid)
2398 locker = vfs.readlock(name)
2398 locker = vfs.readlock(name)
2399 if ":" in locker:
2399 if ":" in locker:
2400 host, pid = locker.split(':')
2400 host, pid = locker.split(':')
2401 if host == socket.gethostname():
2401 if host == socket.gethostname():
2402 locker = 'user %s, process %s' % (user, pid)
2402 locker = 'user %s, process %s' % (user, pid)
2403 else:
2403 else:
2404 locker = 'user %s, process %s, host %s' \
2404 locker = 'user %s, process %s, host %s' \
2405 % (user, pid, host)
2405 % (user, pid, host)
2406 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2406 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2407 return 1
2407 return 1
2408 except OSError, e:
2408 except OSError, e:
2409 if e.errno != errno.ENOENT:
2409 if e.errno != errno.ENOENT:
2410 raise
2410 raise
2411
2411
2412 ui.write("%-6s free\n" % (name + ":"))
2412 ui.write("%-6s free\n" % (name + ":"))
2413 return 0
2413 return 0
2414
2414
2415 held += report(repo.svfs, "lock", repo.lock)
2415 held += report(repo.svfs, "lock", repo.lock)
2416 held += report(repo.vfs, "wlock", repo.wlock)
2416 held += report(repo.vfs, "wlock", repo.wlock)
2417
2417
2418 return held
2418 return held
2419
2419
2420 @command('debugobsolete',
2420 @command('debugobsolete',
2421 [('', 'flags', 0, _('markers flag')),
2421 [('', 'flags', 0, _('markers flag')),
2422 ('', 'record-parents', False,
2422 ('', 'record-parents', False,
2423 _('record parent information for the precursor')),
2423 _('record parent information for the precursor')),
2424 ('r', 'rev', [], _('display markers relevant to REV')),
2424 ('r', 'rev', [], _('display markers relevant to REV')),
2425 ] + commitopts2,
2425 ] + commitopts2,
2426 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2426 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2427 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2427 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2428 """create arbitrary obsolete marker
2428 """create arbitrary obsolete marker
2429
2429
2430 With no arguments, displays the list of obsolescence markers."""
2430 With no arguments, displays the list of obsolescence markers."""
2431
2431
2432 def parsenodeid(s):
2432 def parsenodeid(s):
2433 try:
2433 try:
2434 # We do not use revsingle/revrange functions here to accept
2434 # We do not use revsingle/revrange functions here to accept
2435 # arbitrary node identifiers, possibly not present in the
2435 # arbitrary node identifiers, possibly not present in the
2436 # local repository.
2436 # local repository.
2437 n = bin(s)
2437 n = bin(s)
2438 if len(n) != len(nullid):
2438 if len(n) != len(nullid):
2439 raise TypeError()
2439 raise TypeError()
2440 return n
2440 return n
2441 except TypeError:
2441 except TypeError:
2442 raise util.Abort('changeset references must be full hexadecimal '
2442 raise util.Abort('changeset references must be full hexadecimal '
2443 'node identifiers')
2443 'node identifiers')
2444
2444
2445 if precursor is not None:
2445 if precursor is not None:
2446 if opts['rev']:
2446 if opts['rev']:
2447 raise util.Abort('cannot select revision when creating marker')
2447 raise util.Abort('cannot select revision when creating marker')
2448 metadata = {}
2448 metadata = {}
2449 metadata['user'] = opts['user'] or ui.username()
2449 metadata['user'] = opts['user'] or ui.username()
2450 succs = tuple(parsenodeid(succ) for succ in successors)
2450 succs = tuple(parsenodeid(succ) for succ in successors)
2451 l = repo.lock()
2451 l = repo.lock()
2452 try:
2452 try:
2453 tr = repo.transaction('debugobsolete')
2453 tr = repo.transaction('debugobsolete')
2454 try:
2454 try:
2455 try:
2455 try:
2456 date = opts.get('date')
2456 date = opts.get('date')
2457 if date:
2457 if date:
2458 date = util.parsedate(date)
2458 date = util.parsedate(date)
2459 else:
2459 else:
2460 date = None
2460 date = None
2461 prec = parsenodeid(precursor)
2461 prec = parsenodeid(precursor)
2462 parents = None
2462 parents = None
2463 if opts['record_parents']:
2463 if opts['record_parents']:
2464 if prec not in repo.unfiltered():
2464 if prec not in repo.unfiltered():
2465 raise util.Abort('cannot used --record-parents on '
2465 raise util.Abort('cannot used --record-parents on '
2466 'unknown changesets')
2466 'unknown changesets')
2467 parents = repo.unfiltered()[prec].parents()
2467 parents = repo.unfiltered()[prec].parents()
2468 parents = tuple(p.node() for p in parents)
2468 parents = tuple(p.node() for p in parents)
2469 repo.obsstore.create(tr, prec, succs, opts['flags'],
2469 repo.obsstore.create(tr, prec, succs, opts['flags'],
2470 parents=parents, date=date,
2470 parents=parents, date=date,
2471 metadata=metadata)
2471 metadata=metadata)
2472 tr.close()
2472 tr.close()
2473 except ValueError, exc:
2473 except ValueError, exc:
2474 raise util.Abort(_('bad obsmarker input: %s') % exc)
2474 raise util.Abort(_('bad obsmarker input: %s') % exc)
2475 finally:
2475 finally:
2476 tr.release()
2476 tr.release()
2477 finally:
2477 finally:
2478 l.release()
2478 l.release()
2479 else:
2479 else:
2480 if opts['rev']:
2480 if opts['rev']:
2481 revs = scmutil.revrange(repo, opts['rev'])
2481 revs = scmutil.revrange(repo, opts['rev'])
2482 nodes = [repo[r].node() for r in revs]
2482 nodes = [repo[r].node() for r in revs]
2483 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2483 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2484 markers.sort(key=lambda x: x._data)
2484 markers.sort(key=lambda x: x._data)
2485 else:
2485 else:
2486 markers = obsolete.getmarkers(repo)
2486 markers = obsolete.getmarkers(repo)
2487
2487
2488 for m in markers:
2488 for m in markers:
2489 cmdutil.showmarker(ui, m)
2489 cmdutil.showmarker(ui, m)
2490
2490
2491 @command('debugpathcomplete',
2491 @command('debugpathcomplete',
2492 [('f', 'full', None, _('complete an entire path')),
2492 [('f', 'full', None, _('complete an entire path')),
2493 ('n', 'normal', None, _('show only normal files')),
2493 ('n', 'normal', None, _('show only normal files')),
2494 ('a', 'added', None, _('show only added files')),
2494 ('a', 'added', None, _('show only added files')),
2495 ('r', 'removed', None, _('show only removed files'))],
2495 ('r', 'removed', None, _('show only removed files'))],
2496 _('FILESPEC...'))
2496 _('FILESPEC...'))
2497 def debugpathcomplete(ui, repo, *specs, **opts):
2497 def debugpathcomplete(ui, repo, *specs, **opts):
2498 '''complete part or all of a tracked path
2498 '''complete part or all of a tracked path
2499
2499
2500 This command supports shells that offer path name completion. It
2500 This command supports shells that offer path name completion. It
2501 currently completes only files already known to the dirstate.
2501 currently completes only files already known to the dirstate.
2502
2502
2503 Completion extends only to the next path segment unless
2503 Completion extends only to the next path segment unless
2504 --full is specified, in which case entire paths are used.'''
2504 --full is specified, in which case entire paths are used.'''
2505
2505
2506 def complete(path, acceptable):
2506 def complete(path, acceptable):
2507 dirstate = repo.dirstate
2507 dirstate = repo.dirstate
2508 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2508 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2509 rootdir = repo.root + os.sep
2509 rootdir = repo.root + os.sep
2510 if spec != repo.root and not spec.startswith(rootdir):
2510 if spec != repo.root and not spec.startswith(rootdir):
2511 return [], []
2511 return [], []
2512 if os.path.isdir(spec):
2512 if os.path.isdir(spec):
2513 spec += '/'
2513 spec += '/'
2514 spec = spec[len(rootdir):]
2514 spec = spec[len(rootdir):]
2515 fixpaths = os.sep != '/'
2515 fixpaths = os.sep != '/'
2516 if fixpaths:
2516 if fixpaths:
2517 spec = spec.replace(os.sep, '/')
2517 spec = spec.replace(os.sep, '/')
2518 speclen = len(spec)
2518 speclen = len(spec)
2519 fullpaths = opts['full']
2519 fullpaths = opts['full']
2520 files, dirs = set(), set()
2520 files, dirs = set(), set()
2521 adddir, addfile = dirs.add, files.add
2521 adddir, addfile = dirs.add, files.add
2522 for f, st in dirstate.iteritems():
2522 for f, st in dirstate.iteritems():
2523 if f.startswith(spec) and st[0] in acceptable:
2523 if f.startswith(spec) and st[0] in acceptable:
2524 if fixpaths:
2524 if fixpaths:
2525 f = f.replace('/', os.sep)
2525 f = f.replace('/', os.sep)
2526 if fullpaths:
2526 if fullpaths:
2527 addfile(f)
2527 addfile(f)
2528 continue
2528 continue
2529 s = f.find(os.sep, speclen)
2529 s = f.find(os.sep, speclen)
2530 if s >= 0:
2530 if s >= 0:
2531 adddir(f[:s])
2531 adddir(f[:s])
2532 else:
2532 else:
2533 addfile(f)
2533 addfile(f)
2534 return files, dirs
2534 return files, dirs
2535
2535
2536 acceptable = ''
2536 acceptable = ''
2537 if opts['normal']:
2537 if opts['normal']:
2538 acceptable += 'nm'
2538 acceptable += 'nm'
2539 if opts['added']:
2539 if opts['added']:
2540 acceptable += 'a'
2540 acceptable += 'a'
2541 if opts['removed']:
2541 if opts['removed']:
2542 acceptable += 'r'
2542 acceptable += 'r'
2543 cwd = repo.getcwd()
2543 cwd = repo.getcwd()
2544 if not specs:
2544 if not specs:
2545 specs = ['.']
2545 specs = ['.']
2546
2546
2547 files, dirs = set(), set()
2547 files, dirs = set(), set()
2548 for spec in specs:
2548 for spec in specs:
2549 f, d = complete(spec, acceptable or 'nmar')
2549 f, d = complete(spec, acceptable or 'nmar')
2550 files.update(f)
2550 files.update(f)
2551 dirs.update(d)
2551 dirs.update(d)
2552 files.update(dirs)
2552 files.update(dirs)
2553 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2553 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2554 ui.write('\n')
2554 ui.write('\n')
2555
2555
2556 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2556 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2557 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2557 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2558 '''access the pushkey key/value protocol
2558 '''access the pushkey key/value protocol
2559
2559
2560 With two args, list the keys in the given namespace.
2560 With two args, list the keys in the given namespace.
2561
2561
2562 With five args, set a key to new if it currently is set to old.
2562 With five args, set a key to new if it currently is set to old.
2563 Reports success or failure.
2563 Reports success or failure.
2564 '''
2564 '''
2565
2565
2566 target = hg.peer(ui, {}, repopath)
2566 target = hg.peer(ui, {}, repopath)
2567 if keyinfo:
2567 if keyinfo:
2568 key, old, new = keyinfo
2568 key, old, new = keyinfo
2569 r = target.pushkey(namespace, key, old, new)
2569 r = target.pushkey(namespace, key, old, new)
2570 ui.status(str(r) + '\n')
2570 ui.status(str(r) + '\n')
2571 return not r
2571 return not r
2572 else:
2572 else:
2573 for k, v in sorted(target.listkeys(namespace).iteritems()):
2573 for k, v in sorted(target.listkeys(namespace).iteritems()):
2574 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2574 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2575 v.encode('string-escape')))
2575 v.encode('string-escape')))
2576
2576
2577 @command('debugpvec', [], _('A B'))
2577 @command('debugpvec', [], _('A B'))
2578 def debugpvec(ui, repo, a, b=None):
2578 def debugpvec(ui, repo, a, b=None):
2579 ca = scmutil.revsingle(repo, a)
2579 ca = scmutil.revsingle(repo, a)
2580 cb = scmutil.revsingle(repo, b)
2580 cb = scmutil.revsingle(repo, b)
2581 pa = pvec.ctxpvec(ca)
2581 pa = pvec.ctxpvec(ca)
2582 pb = pvec.ctxpvec(cb)
2582 pb = pvec.ctxpvec(cb)
2583 if pa == pb:
2583 if pa == pb:
2584 rel = "="
2584 rel = "="
2585 elif pa > pb:
2585 elif pa > pb:
2586 rel = ">"
2586 rel = ">"
2587 elif pa < pb:
2587 elif pa < pb:
2588 rel = "<"
2588 rel = "<"
2589 elif pa | pb:
2589 elif pa | pb:
2590 rel = "|"
2590 rel = "|"
2591 ui.write(_("a: %s\n") % pa)
2591 ui.write(_("a: %s\n") % pa)
2592 ui.write(_("b: %s\n") % pb)
2592 ui.write(_("b: %s\n") % pb)
2593 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2593 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2594 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2594 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2595 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2595 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2596 pa.distance(pb), rel))
2596 pa.distance(pb), rel))
2597
2597
2598 @command('debugrebuilddirstate|debugrebuildstate',
2598 @command('debugrebuilddirstate|debugrebuildstate',
2599 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2599 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2600 _('[-r REV]'))
2600 _('[-r REV]'))
2601 def debugrebuilddirstate(ui, repo, rev):
2601 def debugrebuilddirstate(ui, repo, rev):
2602 """rebuild the dirstate as it would look like for the given revision
2602 """rebuild the dirstate as it would look like for the given revision
2603
2603
2604 If no revision is specified the first current parent will be used.
2604 If no revision is specified the first current parent will be used.
2605
2605
2606 The dirstate will be set to the files of the given revision.
2606 The dirstate will be set to the files of the given revision.
2607 The actual working directory content or existing dirstate
2607 The actual working directory content or existing dirstate
2608 information such as adds or removes is not considered.
2608 information such as adds or removes is not considered.
2609
2609
2610 One use of this command is to make the next :hg:`status` invocation
2610 One use of this command is to make the next :hg:`status` invocation
2611 check the actual file content.
2611 check the actual file content.
2612 """
2612 """
2613 ctx = scmutil.revsingle(repo, rev)
2613 ctx = scmutil.revsingle(repo, rev)
2614 wlock = repo.wlock()
2614 wlock = repo.wlock()
2615 try:
2615 try:
2616 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2616 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2617 finally:
2617 finally:
2618 wlock.release()
2618 wlock.release()
2619
2619
2620 @command('debugrename',
2620 @command('debugrename',
2621 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2621 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2622 _('[-r REV] FILE'))
2622 _('[-r REV] FILE'))
2623 def debugrename(ui, repo, file1, *pats, **opts):
2623 def debugrename(ui, repo, file1, *pats, **opts):
2624 """dump rename information"""
2624 """dump rename information"""
2625
2625
2626 ctx = scmutil.revsingle(repo, opts.get('rev'))
2626 ctx = scmutil.revsingle(repo, opts.get('rev'))
2627 m = scmutil.match(ctx, (file1,) + pats, opts)
2627 m = scmutil.match(ctx, (file1,) + pats, opts)
2628 for abs in ctx.walk(m):
2628 for abs in ctx.walk(m):
2629 fctx = ctx[abs]
2629 fctx = ctx[abs]
2630 o = fctx.filelog().renamed(fctx.filenode())
2630 o = fctx.filelog().renamed(fctx.filenode())
2631 rel = m.rel(abs)
2631 rel = m.rel(abs)
2632 if o:
2632 if o:
2633 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2633 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2634 else:
2634 else:
2635 ui.write(_("%s not renamed\n") % rel)
2635 ui.write(_("%s not renamed\n") % rel)
2636
2636
2637 @command('debugrevlog',
2637 @command('debugrevlog',
2638 [('c', 'changelog', False, _('open changelog')),
2638 [('c', 'changelog', False, _('open changelog')),
2639 ('m', 'manifest', False, _('open manifest')),
2639 ('m', 'manifest', False, _('open manifest')),
2640 ('d', 'dump', False, _('dump index data'))],
2640 ('d', 'dump', False, _('dump index data'))],
2641 _('-c|-m|FILE'),
2641 _('-c|-m|FILE'),
2642 optionalrepo=True)
2642 optionalrepo=True)
2643 def debugrevlog(ui, repo, file_=None, **opts):
2643 def debugrevlog(ui, repo, file_=None, **opts):
2644 """show data and statistics about a revlog"""
2644 """show data and statistics about a revlog"""
2645 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2645 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2646
2646
2647 if opts.get("dump"):
2647 if opts.get("dump"):
2648 numrevs = len(r)
2648 numrevs = len(r)
2649 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2649 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2650 " rawsize totalsize compression heads chainlen\n")
2650 " rawsize totalsize compression heads chainlen\n")
2651 ts = 0
2651 ts = 0
2652 heads = set()
2652 heads = set()
2653
2653
2654 for rev in xrange(numrevs):
2654 for rev in xrange(numrevs):
2655 dbase = r.deltaparent(rev)
2655 dbase = r.deltaparent(rev)
2656 if dbase == -1:
2656 if dbase == -1:
2657 dbase = rev
2657 dbase = rev
2658 cbase = r.chainbase(rev)
2658 cbase = r.chainbase(rev)
2659 clen = r.chainlen(rev)
2659 clen = r.chainlen(rev)
2660 p1, p2 = r.parentrevs(rev)
2660 p1, p2 = r.parentrevs(rev)
2661 rs = r.rawsize(rev)
2661 rs = r.rawsize(rev)
2662 ts = ts + rs
2662 ts = ts + rs
2663 heads -= set(r.parentrevs(rev))
2663 heads -= set(r.parentrevs(rev))
2664 heads.add(rev)
2664 heads.add(rev)
2665 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2665 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2666 "%11d %5d %8d\n" %
2666 "%11d %5d %8d\n" %
2667 (rev, p1, p2, r.start(rev), r.end(rev),
2667 (rev, p1, p2, r.start(rev), r.end(rev),
2668 r.start(dbase), r.start(cbase),
2668 r.start(dbase), r.start(cbase),
2669 r.start(p1), r.start(p2),
2669 r.start(p1), r.start(p2),
2670 rs, ts, ts / r.end(rev), len(heads), clen))
2670 rs, ts, ts / r.end(rev), len(heads), clen))
2671 return 0
2671 return 0
2672
2672
2673 v = r.version
2673 v = r.version
2674 format = v & 0xFFFF
2674 format = v & 0xFFFF
2675 flags = []
2675 flags = []
2676 gdelta = False
2676 gdelta = False
2677 if v & revlog.REVLOGNGINLINEDATA:
2677 if v & revlog.REVLOGNGINLINEDATA:
2678 flags.append('inline')
2678 flags.append('inline')
2679 if v & revlog.REVLOGGENERALDELTA:
2679 if v & revlog.REVLOGGENERALDELTA:
2680 gdelta = True
2680 gdelta = True
2681 flags.append('generaldelta')
2681 flags.append('generaldelta')
2682 if not flags:
2682 if not flags:
2683 flags = ['(none)']
2683 flags = ['(none)']
2684
2684
2685 nummerges = 0
2685 nummerges = 0
2686 numfull = 0
2686 numfull = 0
2687 numprev = 0
2687 numprev = 0
2688 nump1 = 0
2688 nump1 = 0
2689 nump2 = 0
2689 nump2 = 0
2690 numother = 0
2690 numother = 0
2691 nump1prev = 0
2691 nump1prev = 0
2692 nump2prev = 0
2692 nump2prev = 0
2693 chainlengths = []
2693 chainlengths = []
2694
2694
2695 datasize = [None, 0, 0L]
2695 datasize = [None, 0, 0L]
2696 fullsize = [None, 0, 0L]
2696 fullsize = [None, 0, 0L]
2697 deltasize = [None, 0, 0L]
2697 deltasize = [None, 0, 0L]
2698
2698
2699 def addsize(size, l):
2699 def addsize(size, l):
2700 if l[0] is None or size < l[0]:
2700 if l[0] is None or size < l[0]:
2701 l[0] = size
2701 l[0] = size
2702 if size > l[1]:
2702 if size > l[1]:
2703 l[1] = size
2703 l[1] = size
2704 l[2] += size
2704 l[2] += size
2705
2705
2706 numrevs = len(r)
2706 numrevs = len(r)
2707 for rev in xrange(numrevs):
2707 for rev in xrange(numrevs):
2708 p1, p2 = r.parentrevs(rev)
2708 p1, p2 = r.parentrevs(rev)
2709 delta = r.deltaparent(rev)
2709 delta = r.deltaparent(rev)
2710 if format > 0:
2710 if format > 0:
2711 addsize(r.rawsize(rev), datasize)
2711 addsize(r.rawsize(rev), datasize)
2712 if p2 != nullrev:
2712 if p2 != nullrev:
2713 nummerges += 1
2713 nummerges += 1
2714 size = r.length(rev)
2714 size = r.length(rev)
2715 if delta == nullrev:
2715 if delta == nullrev:
2716 chainlengths.append(0)
2716 chainlengths.append(0)
2717 numfull += 1
2717 numfull += 1
2718 addsize(size, fullsize)
2718 addsize(size, fullsize)
2719 else:
2719 else:
2720 chainlengths.append(chainlengths[delta] + 1)
2720 chainlengths.append(chainlengths[delta] + 1)
2721 addsize(size, deltasize)
2721 addsize(size, deltasize)
2722 if delta == rev - 1:
2722 if delta == rev - 1:
2723 numprev += 1
2723 numprev += 1
2724 if delta == p1:
2724 if delta == p1:
2725 nump1prev += 1
2725 nump1prev += 1
2726 elif delta == p2:
2726 elif delta == p2:
2727 nump2prev += 1
2727 nump2prev += 1
2728 elif delta == p1:
2728 elif delta == p1:
2729 nump1 += 1
2729 nump1 += 1
2730 elif delta == p2:
2730 elif delta == p2:
2731 nump2 += 1
2731 nump2 += 1
2732 elif delta != nullrev:
2732 elif delta != nullrev:
2733 numother += 1
2733 numother += 1
2734
2734
2735 # Adjust size min value for empty cases
2735 # Adjust size min value for empty cases
2736 for size in (datasize, fullsize, deltasize):
2736 for size in (datasize, fullsize, deltasize):
2737 if size[0] is None:
2737 if size[0] is None:
2738 size[0] = 0
2738 size[0] = 0
2739
2739
2740 numdeltas = numrevs - numfull
2740 numdeltas = numrevs - numfull
2741 numoprev = numprev - nump1prev - nump2prev
2741 numoprev = numprev - nump1prev - nump2prev
2742 totalrawsize = datasize[2]
2742 totalrawsize = datasize[2]
2743 datasize[2] /= numrevs
2743 datasize[2] /= numrevs
2744 fulltotal = fullsize[2]
2744 fulltotal = fullsize[2]
2745 fullsize[2] /= numfull
2745 fullsize[2] /= numfull
2746 deltatotal = deltasize[2]
2746 deltatotal = deltasize[2]
2747 if numrevs - numfull > 0:
2747 if numrevs - numfull > 0:
2748 deltasize[2] /= numrevs - numfull
2748 deltasize[2] /= numrevs - numfull
2749 totalsize = fulltotal + deltatotal
2749 totalsize = fulltotal + deltatotal
2750 avgchainlen = sum(chainlengths) / numrevs
2750 avgchainlen = sum(chainlengths) / numrevs
2751 compratio = totalrawsize / totalsize
2751 compratio = totalrawsize / totalsize
2752
2752
2753 basedfmtstr = '%%%dd\n'
2753 basedfmtstr = '%%%dd\n'
2754 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2754 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2755
2755
2756 def dfmtstr(max):
2756 def dfmtstr(max):
2757 return basedfmtstr % len(str(max))
2757 return basedfmtstr % len(str(max))
2758 def pcfmtstr(max, padding=0):
2758 def pcfmtstr(max, padding=0):
2759 return basepcfmtstr % (len(str(max)), ' ' * padding)
2759 return basepcfmtstr % (len(str(max)), ' ' * padding)
2760
2760
2761 def pcfmt(value, total):
2761 def pcfmt(value, total):
2762 return (value, 100 * float(value) / total)
2762 return (value, 100 * float(value) / total)
2763
2763
2764 ui.write(('format : %d\n') % format)
2764 ui.write(('format : %d\n') % format)
2765 ui.write(('flags : %s\n') % ', '.join(flags))
2765 ui.write(('flags : %s\n') % ', '.join(flags))
2766
2766
2767 ui.write('\n')
2767 ui.write('\n')
2768 fmt = pcfmtstr(totalsize)
2768 fmt = pcfmtstr(totalsize)
2769 fmt2 = dfmtstr(totalsize)
2769 fmt2 = dfmtstr(totalsize)
2770 ui.write(('revisions : ') + fmt2 % numrevs)
2770 ui.write(('revisions : ') + fmt2 % numrevs)
2771 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2771 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2772 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2772 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2773 ui.write(('revisions : ') + fmt2 % numrevs)
2773 ui.write(('revisions : ') + fmt2 % numrevs)
2774 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2774 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2775 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2775 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2776 ui.write(('revision size : ') + fmt2 % totalsize)
2776 ui.write(('revision size : ') + fmt2 % totalsize)
2777 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2777 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2778 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2778 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2779
2779
2780 ui.write('\n')
2780 ui.write('\n')
2781 fmt = dfmtstr(max(avgchainlen, compratio))
2781 fmt = dfmtstr(max(avgchainlen, compratio))
2782 ui.write(('avg chain length : ') + fmt % avgchainlen)
2782 ui.write(('avg chain length : ') + fmt % avgchainlen)
2783 ui.write(('compression ratio : ') + fmt % compratio)
2783 ui.write(('compression ratio : ') + fmt % compratio)
2784
2784
2785 if format > 0:
2785 if format > 0:
2786 ui.write('\n')
2786 ui.write('\n')
2787 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2787 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2788 % tuple(datasize))
2788 % tuple(datasize))
2789 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2789 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2790 % tuple(fullsize))
2790 % tuple(fullsize))
2791 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2791 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2792 % tuple(deltasize))
2792 % tuple(deltasize))
2793
2793
2794 if numdeltas > 0:
2794 if numdeltas > 0:
2795 ui.write('\n')
2795 ui.write('\n')
2796 fmt = pcfmtstr(numdeltas)
2796 fmt = pcfmtstr(numdeltas)
2797 fmt2 = pcfmtstr(numdeltas, 4)
2797 fmt2 = pcfmtstr(numdeltas, 4)
2798 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2798 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2799 if numprev > 0:
2799 if numprev > 0:
2800 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2800 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2801 numprev))
2801 numprev))
2802 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2802 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2803 numprev))
2803 numprev))
2804 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2804 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2805 numprev))
2805 numprev))
2806 if gdelta:
2806 if gdelta:
2807 ui.write(('deltas against p1 : ')
2807 ui.write(('deltas against p1 : ')
2808 + fmt % pcfmt(nump1, numdeltas))
2808 + fmt % pcfmt(nump1, numdeltas))
2809 ui.write(('deltas against p2 : ')
2809 ui.write(('deltas against p2 : ')
2810 + fmt % pcfmt(nump2, numdeltas))
2810 + fmt % pcfmt(nump2, numdeltas))
2811 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2811 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2812 numdeltas))
2812 numdeltas))
2813
2813
2814 @command('debugrevspec',
2814 @command('debugrevspec',
2815 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2815 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2816 ('REVSPEC'))
2816 ('REVSPEC'))
2817 def debugrevspec(ui, repo, expr, **opts):
2817 def debugrevspec(ui, repo, expr, **opts):
2818 """parse and apply a revision specification
2818 """parse and apply a revision specification
2819
2819
2820 Use --verbose to print the parsed tree before and after aliases
2820 Use --verbose to print the parsed tree before and after aliases
2821 expansion.
2821 expansion.
2822 """
2822 """
2823 if ui.verbose:
2823 if ui.verbose:
2824 tree = revset.parse(expr)[0]
2824 tree = revset.parse(expr)[0]
2825 ui.note(revset.prettyformat(tree), "\n")
2825 ui.note(revset.prettyformat(tree), "\n")
2826 newtree = revset.findaliases(ui, tree)
2826 newtree = revset.findaliases(ui, tree)
2827 if newtree != tree:
2827 if newtree != tree:
2828 ui.note(revset.prettyformat(newtree), "\n")
2828 ui.note(revset.prettyformat(newtree), "\n")
2829 if opts["optimize"]:
2829 if opts["optimize"]:
2830 weight, optimizedtree = revset.optimize(newtree, True)
2830 weight, optimizedtree = revset.optimize(newtree, True)
2831 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2831 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2832 func = revset.match(ui, expr)
2832 func = revset.match(ui, expr)
2833 for c in func(repo, revset.spanset(repo)):
2833 for c in func(repo, revset.spanset(repo)):
2834 ui.write("%s\n" % c)
2834 ui.write("%s\n" % c)
2835
2835
2836 @command('debugsetparents', [], _('REV1 [REV2]'))
2836 @command('debugsetparents', [], _('REV1 [REV2]'))
2837 def debugsetparents(ui, repo, rev1, rev2=None):
2837 def debugsetparents(ui, repo, rev1, rev2=None):
2838 """manually set the parents of the current working directory
2838 """manually set the parents of the current working directory
2839
2839
2840 This is useful for writing repository conversion tools, but should
2840 This is useful for writing repository conversion tools, but should
2841 be used with care.
2841 be used with care.
2842
2842
2843 Returns 0 on success.
2843 Returns 0 on success.
2844 """
2844 """
2845
2845
2846 r1 = scmutil.revsingle(repo, rev1).node()
2846 r1 = scmutil.revsingle(repo, rev1).node()
2847 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2847 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2848
2848
2849 wlock = repo.wlock()
2849 wlock = repo.wlock()
2850 try:
2850 try:
2851 repo.dirstate.beginparentchange()
2851 repo.dirstate.beginparentchange()
2852 repo.setparents(r1, r2)
2852 repo.setparents(r1, r2)
2853 repo.dirstate.endparentchange()
2853 repo.dirstate.endparentchange()
2854 finally:
2854 finally:
2855 wlock.release()
2855 wlock.release()
2856
2856
2857 @command('debugdirstate|debugstate',
2857 @command('debugdirstate|debugstate',
2858 [('', 'nodates', None, _('do not display the saved mtime')),
2858 [('', 'nodates', None, _('do not display the saved mtime')),
2859 ('', 'datesort', None, _('sort by saved mtime'))],
2859 ('', 'datesort', None, _('sort by saved mtime'))],
2860 _('[OPTION]...'))
2860 _('[OPTION]...'))
2861 def debugstate(ui, repo, nodates=None, datesort=None):
2861 def debugstate(ui, repo, nodates=None, datesort=None):
2862 """show the contents of the current dirstate"""
2862 """show the contents of the current dirstate"""
2863 timestr = ""
2863 timestr = ""
2864 showdate = not nodates
2864 showdate = not nodates
2865 if datesort:
2865 if datesort:
2866 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2866 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2867 else:
2867 else:
2868 keyfunc = None # sort by filename
2868 keyfunc = None # sort by filename
2869 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2869 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2870 if showdate:
2870 if showdate:
2871 if ent[3] == -1:
2871 if ent[3] == -1:
2872 # Pad or slice to locale representation
2872 # Pad or slice to locale representation
2873 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2873 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2874 time.localtime(0)))
2874 time.localtime(0)))
2875 timestr = 'unset'
2875 timestr = 'unset'
2876 timestr = (timestr[:locale_len] +
2876 timestr = (timestr[:locale_len] +
2877 ' ' * (locale_len - len(timestr)))
2877 ' ' * (locale_len - len(timestr)))
2878 else:
2878 else:
2879 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2879 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2880 time.localtime(ent[3]))
2880 time.localtime(ent[3]))
2881 if ent[1] & 020000:
2881 if ent[1] & 020000:
2882 mode = 'lnk'
2882 mode = 'lnk'
2883 else:
2883 else:
2884 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2884 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2885 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2885 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2886 for f in repo.dirstate.copies():
2886 for f in repo.dirstate.copies():
2887 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2887 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2888
2888
2889 @command('debugsub',
2889 @command('debugsub',
2890 [('r', 'rev', '',
2890 [('r', 'rev', '',
2891 _('revision to check'), _('REV'))],
2891 _('revision to check'), _('REV'))],
2892 _('[-r REV] [REV]'))
2892 _('[-r REV] [REV]'))
2893 def debugsub(ui, repo, rev=None):
2893 def debugsub(ui, repo, rev=None):
2894 ctx = scmutil.revsingle(repo, rev, None)
2894 ctx = scmutil.revsingle(repo, rev, None)
2895 for k, v in sorted(ctx.substate.items()):
2895 for k, v in sorted(ctx.substate.items()):
2896 ui.write(('path %s\n') % k)
2896 ui.write(('path %s\n') % k)
2897 ui.write((' source %s\n') % v[0])
2897 ui.write((' source %s\n') % v[0])
2898 ui.write((' revision %s\n') % v[1])
2898 ui.write((' revision %s\n') % v[1])
2899
2899
2900 @command('debugsuccessorssets',
2900 @command('debugsuccessorssets',
2901 [],
2901 [],
2902 _('[REV]'))
2902 _('[REV]'))
2903 def debugsuccessorssets(ui, repo, *revs):
2903 def debugsuccessorssets(ui, repo, *revs):
2904 """show set of successors for revision
2904 """show set of successors for revision
2905
2905
2906 A successors set of changeset A is a consistent group of revisions that
2906 A successors set of changeset A is a consistent group of revisions that
2907 succeed A. It contains non-obsolete changesets only.
2907 succeed A. It contains non-obsolete changesets only.
2908
2908
2909 In most cases a changeset A has a single successors set containing a single
2909 In most cases a changeset A has a single successors set containing a single
2910 successor (changeset A replaced by A').
2910 successor (changeset A replaced by A').
2911
2911
2912 A changeset that is made obsolete with no successors are called "pruned".
2912 A changeset that is made obsolete with no successors are called "pruned".
2913 Such changesets have no successors sets at all.
2913 Such changesets have no successors sets at all.
2914
2914
2915 A changeset that has been "split" will have a successors set containing
2915 A changeset that has been "split" will have a successors set containing
2916 more than one successor.
2916 more than one successor.
2917
2917
2918 A changeset that has been rewritten in multiple different ways is called
2918 A changeset that has been rewritten in multiple different ways is called
2919 "divergent". Such changesets have multiple successor sets (each of which
2919 "divergent". Such changesets have multiple successor sets (each of which
2920 may also be split, i.e. have multiple successors).
2920 may also be split, i.e. have multiple successors).
2921
2921
2922 Results are displayed as follows::
2922 Results are displayed as follows::
2923
2923
2924 <rev1>
2924 <rev1>
2925 <successors-1A>
2925 <successors-1A>
2926 <rev2>
2926 <rev2>
2927 <successors-2A>
2927 <successors-2A>
2928 <successors-2B1> <successors-2B2> <successors-2B3>
2928 <successors-2B1> <successors-2B2> <successors-2B3>
2929
2929
2930 Here rev2 has two possible (i.e. divergent) successors sets. The first
2930 Here rev2 has two possible (i.e. divergent) successors sets. The first
2931 holds one element, whereas the second holds three (i.e. the changeset has
2931 holds one element, whereas the second holds three (i.e. the changeset has
2932 been split).
2932 been split).
2933 """
2933 """
2934 # passed to successorssets caching computation from one call to another
2934 # passed to successorssets caching computation from one call to another
2935 cache = {}
2935 cache = {}
2936 ctx2str = str
2936 ctx2str = str
2937 node2str = short
2937 node2str = short
2938 if ui.debug():
2938 if ui.debug():
2939 def ctx2str(ctx):
2939 def ctx2str(ctx):
2940 return ctx.hex()
2940 return ctx.hex()
2941 node2str = hex
2941 node2str = hex
2942 for rev in scmutil.revrange(repo, revs):
2942 for rev in scmutil.revrange(repo, revs):
2943 ctx = repo[rev]
2943 ctx = repo[rev]
2944 ui.write('%s\n'% ctx2str(ctx))
2944 ui.write('%s\n'% ctx2str(ctx))
2945 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2945 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2946 if succsset:
2946 if succsset:
2947 ui.write(' ')
2947 ui.write(' ')
2948 ui.write(node2str(succsset[0]))
2948 ui.write(node2str(succsset[0]))
2949 for node in succsset[1:]:
2949 for node in succsset[1:]:
2950 ui.write(' ')
2950 ui.write(' ')
2951 ui.write(node2str(node))
2951 ui.write(node2str(node))
2952 ui.write('\n')
2952 ui.write('\n')
2953
2953
2954 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2954 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2955 def debugwalk(ui, repo, *pats, **opts):
2955 def debugwalk(ui, repo, *pats, **opts):
2956 """show how files match on given patterns"""
2956 """show how files match on given patterns"""
2957 m = scmutil.match(repo[None], pats, opts)
2957 m = scmutil.match(repo[None], pats, opts)
2958 items = list(repo.walk(m))
2958 items = list(repo.walk(m))
2959 if not items:
2959 if not items:
2960 return
2960 return
2961 f = lambda fn: fn
2961 f = lambda fn: fn
2962 if ui.configbool('ui', 'slash') and os.sep != '/':
2962 if ui.configbool('ui', 'slash') and os.sep != '/':
2963 f = lambda fn: util.normpath(fn)
2963 f = lambda fn: util.normpath(fn)
2964 fmt = 'f %%-%ds %%-%ds %%s' % (
2964 fmt = 'f %%-%ds %%-%ds %%s' % (
2965 max([len(abs) for abs in items]),
2965 max([len(abs) for abs in items]),
2966 max([len(m.rel(abs)) for abs in items]))
2966 max([len(m.rel(abs)) for abs in items]))
2967 for abs in items:
2967 for abs in items:
2968 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2968 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2969 ui.write("%s\n" % line.rstrip())
2969 ui.write("%s\n" % line.rstrip())
2970
2970
2971 @command('debugwireargs',
2971 @command('debugwireargs',
2972 [('', 'three', '', 'three'),
2972 [('', 'three', '', 'three'),
2973 ('', 'four', '', 'four'),
2973 ('', 'four', '', 'four'),
2974 ('', 'five', '', 'five'),
2974 ('', 'five', '', 'five'),
2975 ] + remoteopts,
2975 ] + remoteopts,
2976 _('REPO [OPTIONS]... [ONE [TWO]]'),
2976 _('REPO [OPTIONS]... [ONE [TWO]]'),
2977 norepo=True)
2977 norepo=True)
2978 def debugwireargs(ui, repopath, *vals, **opts):
2978 def debugwireargs(ui, repopath, *vals, **opts):
2979 repo = hg.peer(ui, opts, repopath)
2979 repo = hg.peer(ui, opts, repopath)
2980 for opt in remoteopts:
2980 for opt in remoteopts:
2981 del opts[opt[1]]
2981 del opts[opt[1]]
2982 args = {}
2982 args = {}
2983 for k, v in opts.iteritems():
2983 for k, v in opts.iteritems():
2984 if v:
2984 if v:
2985 args[k] = v
2985 args[k] = v
2986 # run twice to check that we don't mess up the stream for the next command
2986 # run twice to check that we don't mess up the stream for the next command
2987 res1 = repo.debugwireargs(*vals, **args)
2987 res1 = repo.debugwireargs(*vals, **args)
2988 res2 = repo.debugwireargs(*vals, **args)
2988 res2 = repo.debugwireargs(*vals, **args)
2989 ui.write("%s\n" % res1)
2989 ui.write("%s\n" % res1)
2990 if res1 != res2:
2990 if res1 != res2:
2991 ui.warn("%s\n" % res2)
2991 ui.warn("%s\n" % res2)
2992
2992
2993 @command('^diff',
2993 @command('^diff',
2994 [('r', 'rev', [], _('revision'), _('REV')),
2994 [('r', 'rev', [], _('revision'), _('REV')),
2995 ('c', 'change', '', _('change made by revision'), _('REV'))
2995 ('c', 'change', '', _('change made by revision'), _('REV'))
2996 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2996 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2997 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2997 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2998 inferrepo=True)
2998 inferrepo=True)
2999 def diff(ui, repo, *pats, **opts):
2999 def diff(ui, repo, *pats, **opts):
3000 """diff repository (or selected files)
3000 """diff repository (or selected files)
3001
3001
3002 Show differences between revisions for the specified files.
3002 Show differences between revisions for the specified files.
3003
3003
3004 Differences between files are shown using the unified diff format.
3004 Differences between files are shown using the unified diff format.
3005
3005
3006 .. note::
3006 .. note::
3007
3007
3008 diff may generate unexpected results for merges, as it will
3008 diff may generate unexpected results for merges, as it will
3009 default to comparing against the working directory's first
3009 default to comparing against the working directory's first
3010 parent changeset if no revisions are specified.
3010 parent changeset if no revisions are specified.
3011
3011
3012 When two revision arguments are given, then changes are shown
3012 When two revision arguments are given, then changes are shown
3013 between those revisions. If only one revision is specified then
3013 between those revisions. If only one revision is specified then
3014 that revision is compared to the working directory, and, when no
3014 that revision is compared to the working directory, and, when no
3015 revisions are specified, the working directory files are compared
3015 revisions are specified, the working directory files are compared
3016 to its parent.
3016 to its parent.
3017
3017
3018 Alternatively you can specify -c/--change with a revision to see
3018 Alternatively you can specify -c/--change with a revision to see
3019 the changes in that changeset relative to its first parent.
3019 the changes in that changeset relative to its first parent.
3020
3020
3021 Without the -a/--text option, diff will avoid generating diffs of
3021 Without the -a/--text option, diff will avoid generating diffs of
3022 files it detects as binary. With -a, diff will generate a diff
3022 files it detects as binary. With -a, diff will generate a diff
3023 anyway, probably with undesirable results.
3023 anyway, probably with undesirable results.
3024
3024
3025 Use the -g/--git option to generate diffs in the git extended diff
3025 Use the -g/--git option to generate diffs in the git extended diff
3026 format. For more information, read :hg:`help diffs`.
3026 format. For more information, read :hg:`help diffs`.
3027
3027
3028 .. container:: verbose
3028 .. container:: verbose
3029
3029
3030 Examples:
3030 Examples:
3031
3031
3032 - compare a file in the current working directory to its parent::
3032 - compare a file in the current working directory to its parent::
3033
3033
3034 hg diff foo.c
3034 hg diff foo.c
3035
3035
3036 - compare two historical versions of a directory, with rename info::
3036 - compare two historical versions of a directory, with rename info::
3037
3037
3038 hg diff --git -r 1.0:1.2 lib/
3038 hg diff --git -r 1.0:1.2 lib/
3039
3039
3040 - get change stats relative to the last change on some date::
3040 - get change stats relative to the last change on some date::
3041
3041
3042 hg diff --stat -r "date('may 2')"
3042 hg diff --stat -r "date('may 2')"
3043
3043
3044 - diff all newly-added files that contain a keyword::
3044 - diff all newly-added files that contain a keyword::
3045
3045
3046 hg diff "set:added() and grep(GNU)"
3046 hg diff "set:added() and grep(GNU)"
3047
3047
3048 - compare a revision and its parents::
3048 - compare a revision and its parents::
3049
3049
3050 hg diff -c 9353 # compare against first parent
3050 hg diff -c 9353 # compare against first parent
3051 hg diff -r 9353^:9353 # same using revset syntax
3051 hg diff -r 9353^:9353 # same using revset syntax
3052 hg diff -r 9353^2:9353 # compare against the second parent
3052 hg diff -r 9353^2:9353 # compare against the second parent
3053
3053
3054 Returns 0 on success.
3054 Returns 0 on success.
3055 """
3055 """
3056
3056
3057 revs = opts.get('rev')
3057 revs = opts.get('rev')
3058 change = opts.get('change')
3058 change = opts.get('change')
3059 stat = opts.get('stat')
3059 stat = opts.get('stat')
3060 reverse = opts.get('reverse')
3060 reverse = opts.get('reverse')
3061
3061
3062 if revs and change:
3062 if revs and change:
3063 msg = _('cannot specify --rev and --change at the same time')
3063 msg = _('cannot specify --rev and --change at the same time')
3064 raise util.Abort(msg)
3064 raise util.Abort(msg)
3065 elif change:
3065 elif change:
3066 node2 = scmutil.revsingle(repo, change, None).node()
3066 node2 = scmutil.revsingle(repo, change, None).node()
3067 node1 = repo[node2].p1().node()
3067 node1 = repo[node2].p1().node()
3068 else:
3068 else:
3069 node1, node2 = scmutil.revpair(repo, revs)
3069 node1, node2 = scmutil.revpair(repo, revs)
3070
3070
3071 if reverse:
3071 if reverse:
3072 node1, node2 = node2, node1
3072 node1, node2 = node2, node1
3073
3073
3074 diffopts = patch.diffopts(ui, opts)
3074 diffopts = patch.diffopts(ui, opts)
3075 m = scmutil.match(repo[node2], pats, opts)
3075 m = scmutil.match(repo[node2], pats, opts)
3076 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3076 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3077 listsubrepos=opts.get('subrepos'))
3077 listsubrepos=opts.get('subrepos'))
3078
3078
3079 @command('^export',
3079 @command('^export',
3080 [('o', 'output', '',
3080 [('o', 'output', '',
3081 _('print output to file with formatted name'), _('FORMAT')),
3081 _('print output to file with formatted name'), _('FORMAT')),
3082 ('', 'switch-parent', None, _('diff against the second parent')),
3082 ('', 'switch-parent', None, _('diff against the second parent')),
3083 ('r', 'rev', [], _('revisions to export'), _('REV')),
3083 ('r', 'rev', [], _('revisions to export'), _('REV')),
3084 ] + diffopts,
3084 ] + diffopts,
3085 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3085 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3086 def export(ui, repo, *changesets, **opts):
3086 def export(ui, repo, *changesets, **opts):
3087 """dump the header and diffs for one or more changesets
3087 """dump the header and diffs for one or more changesets
3088
3088
3089 Print the changeset header and diffs for one or more revisions.
3089 Print the changeset header and diffs for one or more revisions.
3090 If no revision is given, the parent of the working directory is used.
3090 If no revision is given, the parent of the working directory is used.
3091
3091
3092 The information shown in the changeset header is: author, date,
3092 The information shown in the changeset header is: author, date,
3093 branch name (if non-default), changeset hash, parent(s) and commit
3093 branch name (if non-default), changeset hash, parent(s) and commit
3094 comment.
3094 comment.
3095
3095
3096 .. note::
3096 .. note::
3097
3097
3098 export may generate unexpected diff output for merge
3098 export may generate unexpected diff output for merge
3099 changesets, as it will compare the merge changeset against its
3099 changesets, as it will compare the merge changeset against its
3100 first parent only.
3100 first parent only.
3101
3101
3102 Output may be to a file, in which case the name of the file is
3102 Output may be to a file, in which case the name of the file is
3103 given using a format string. The formatting rules are as follows:
3103 given using a format string. The formatting rules are as follows:
3104
3104
3105 :``%%``: literal "%" character
3105 :``%%``: literal "%" character
3106 :``%H``: changeset hash (40 hexadecimal digits)
3106 :``%H``: changeset hash (40 hexadecimal digits)
3107 :``%N``: number of patches being generated
3107 :``%N``: number of patches being generated
3108 :``%R``: changeset revision number
3108 :``%R``: changeset revision number
3109 :``%b``: basename of the exporting repository
3109 :``%b``: basename of the exporting repository
3110 :``%h``: short-form changeset hash (12 hexadecimal digits)
3110 :``%h``: short-form changeset hash (12 hexadecimal digits)
3111 :``%m``: first line of the commit message (only alphanumeric characters)
3111 :``%m``: first line of the commit message (only alphanumeric characters)
3112 :``%n``: zero-padded sequence number, starting at 1
3112 :``%n``: zero-padded sequence number, starting at 1
3113 :``%r``: zero-padded changeset revision number
3113 :``%r``: zero-padded changeset revision number
3114
3114
3115 Without the -a/--text option, export will avoid generating diffs
3115 Without the -a/--text option, export will avoid generating diffs
3116 of files it detects as binary. With -a, export will generate a
3116 of files it detects as binary. With -a, export will generate a
3117 diff anyway, probably with undesirable results.
3117 diff anyway, probably with undesirable results.
3118
3118
3119 Use the -g/--git option to generate diffs in the git extended diff
3119 Use the -g/--git option to generate diffs in the git extended diff
3120 format. See :hg:`help diffs` for more information.
3120 format. See :hg:`help diffs` for more information.
3121
3121
3122 With the --switch-parent option, the diff will be against the
3122 With the --switch-parent option, the diff will be against the
3123 second parent. It can be useful to review a merge.
3123 second parent. It can be useful to review a merge.
3124
3124
3125 .. container:: verbose
3125 .. container:: verbose
3126
3126
3127 Examples:
3127 Examples:
3128
3128
3129 - use export and import to transplant a bugfix to the current
3129 - use export and import to transplant a bugfix to the current
3130 branch::
3130 branch::
3131
3131
3132 hg export -r 9353 | hg import -
3132 hg export -r 9353 | hg import -
3133
3133
3134 - export all the changesets between two revisions to a file with
3134 - export all the changesets between two revisions to a file with
3135 rename information::
3135 rename information::
3136
3136
3137 hg export --git -r 123:150 > changes.txt
3137 hg export --git -r 123:150 > changes.txt
3138
3138
3139 - split outgoing changes into a series of patches with
3139 - split outgoing changes into a series of patches with
3140 descriptive names::
3140 descriptive names::
3141
3141
3142 hg export -r "outgoing()" -o "%n-%m.patch"
3142 hg export -r "outgoing()" -o "%n-%m.patch"
3143
3143
3144 Returns 0 on success.
3144 Returns 0 on success.
3145 """
3145 """
3146 changesets += tuple(opts.get('rev', []))
3146 changesets += tuple(opts.get('rev', []))
3147 if not changesets:
3147 if not changesets:
3148 changesets = ['.']
3148 changesets = ['.']
3149 revs = scmutil.revrange(repo, changesets)
3149 revs = scmutil.revrange(repo, changesets)
3150 if not revs:
3150 if not revs:
3151 raise util.Abort(_("export requires at least one changeset"))
3151 raise util.Abort(_("export requires at least one changeset"))
3152 if len(revs) > 1:
3152 if len(revs) > 1:
3153 ui.note(_('exporting patches:\n'))
3153 ui.note(_('exporting patches:\n'))
3154 else:
3154 else:
3155 ui.note(_('exporting patch:\n'))
3155 ui.note(_('exporting patch:\n'))
3156 cmdutil.export(repo, revs, template=opts.get('output'),
3156 cmdutil.export(repo, revs, template=opts.get('output'),
3157 switch_parent=opts.get('switch_parent'),
3157 switch_parent=opts.get('switch_parent'),
3158 opts=patch.diffopts(ui, opts))
3158 opts=patch.diffopts(ui, opts))
3159
3159
3160 @command('files',
3160 @command('files',
3161 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3161 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3162 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3162 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3163 ] + walkopts + formatteropts,
3163 ] + walkopts + formatteropts,
3164 _('[OPTION]... [PATTERN]...'))
3164 _('[OPTION]... [PATTERN]...'))
3165 def files(ui, repo, *pats, **opts):
3165 def files(ui, repo, *pats, **opts):
3166 """list tracked files
3166 """list tracked files
3167
3167
3168 Print files under Mercurial control in the working directory or
3168 Print files under Mercurial control in the working directory or
3169 specified revision whose names match the given patterns (excluding
3169 specified revision whose names match the given patterns (excluding
3170 removed files).
3170 removed files).
3171
3171
3172 If no patterns are given to match, this command prints the names
3172 If no patterns are given to match, this command prints the names
3173 of all files under Mercurial control in the working copy.
3173 of all files under Mercurial control in the working copy.
3174
3174
3175 .. container:: verbose
3175 .. container:: verbose
3176
3176
3177 Examples:
3177 Examples:
3178
3178
3179 - list all files under the current directory::
3179 - list all files under the current directory::
3180
3180
3181 hg files .
3181 hg files .
3182
3182
3183 - shows sizes and flags for current revision::
3183 - shows sizes and flags for current revision::
3184
3184
3185 hg files -vr .
3185 hg files -vr .
3186
3186
3187 - list all files named README::
3187 - list all files named README::
3188
3188
3189 hg files -I "**/README"
3189 hg files -I "**/README"
3190
3190
3191 - list all binary files::
3191 - list all binary files::
3192
3192
3193 hg files "set:binary()"
3193 hg files "set:binary()"
3194
3194
3195 - find files containing a regular expression::
3195 - find files containing a regular expression::
3196
3196
3197 hg files "set:grep('bob')"
3197 hg files "set:grep('bob')"
3198
3198
3199 - search tracked file contents with xargs and grep::
3199 - search tracked file contents with xargs and grep::
3200
3200
3201 hg files -0 | xargs -0 grep foo
3201 hg files -0 | xargs -0 grep foo
3202
3202
3203 See :hg:`help pattern` and :hg:`help filesets` for more information
3203 See :hg:`help pattern` and :hg:`help filesets` for more information
3204 on specifying file patterns.
3204 on specifying file patterns.
3205
3205
3206 Returns 0 if a match is found, 1 otherwise.
3206 Returns 0 if a match is found, 1 otherwise.
3207
3207
3208 """
3208 """
3209 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3209 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3210 rev = ctx.rev()
3210 rev = ctx.rev()
3211 ret = 1
3211 ret = 1
3212
3212
3213 end = '\n'
3213 end = '\n'
3214 if opts.get('print0'):
3214 if opts.get('print0'):
3215 end = '\0'
3215 end = '\0'
3216 fm = ui.formatter('files', opts)
3216 fm = ui.formatter('files', opts)
3217 fmt = '%s' + end
3217 fmt = '%s' + end
3218
3218
3219 m = scmutil.match(ctx, pats, opts)
3219 m = scmutil.match(ctx, pats, opts)
3220 ds = repo.dirstate
3220 ds = repo.dirstate
3221 for f in ctx.matches(m):
3221 for f in ctx.matches(m):
3222 if rev is None and ds[f] == 'r':
3222 if rev is None and ds[f] == 'r':
3223 continue
3223 continue
3224 fm.startitem()
3224 fm.startitem()
3225 if ui.verbose:
3225 if ui.verbose:
3226 fc = ctx[f]
3226 fc = ctx[f]
3227 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
3227 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
3228 fm.data(abspath=f)
3228 fm.data(abspath=f)
3229 fm.write('path', fmt, m.rel(f))
3229 fm.write('path', fmt, m.rel(f))
3230 ret = 0
3230 ret = 0
3231
3231
3232 fm.end()
3232 fm.end()
3233
3233
3234 return ret
3234 return ret
3235
3235
3236 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3236 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3237 def forget(ui, repo, *pats, **opts):
3237 def forget(ui, repo, *pats, **opts):
3238 """forget the specified files on the next commit
3238 """forget the specified files on the next commit
3239
3239
3240 Mark the specified files so they will no longer be tracked
3240 Mark the specified files so they will no longer be tracked
3241 after the next commit.
3241 after the next commit.
3242
3242
3243 This only removes files from the current branch, not from the
3243 This only removes files from the current branch, not from the
3244 entire project history, and it does not delete them from the
3244 entire project history, and it does not delete them from the
3245 working directory.
3245 working directory.
3246
3246
3247 To undo a forget before the next commit, see :hg:`add`.
3247 To undo a forget before the next commit, see :hg:`add`.
3248
3248
3249 .. container:: verbose
3249 .. container:: verbose
3250
3250
3251 Examples:
3251 Examples:
3252
3252
3253 - forget newly-added binary files::
3253 - forget newly-added binary files::
3254
3254
3255 hg forget "set:added() and binary()"
3255 hg forget "set:added() and binary()"
3256
3256
3257 - forget files that would be excluded by .hgignore::
3257 - forget files that would be excluded by .hgignore::
3258
3258
3259 hg forget "set:hgignore()"
3259 hg forget "set:hgignore()"
3260
3260
3261 Returns 0 on success.
3261 Returns 0 on success.
3262 """
3262 """
3263
3263
3264 if not pats:
3264 if not pats:
3265 raise util.Abort(_('no files specified'))
3265 raise util.Abort(_('no files specified'))
3266
3266
3267 m = scmutil.match(repo[None], pats, opts)
3267 m = scmutil.match(repo[None], pats, opts)
3268 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3268 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3269 return rejected and 1 or 0
3269 return rejected and 1 or 0
3270
3270
3271 @command(
3271 @command(
3272 'graft',
3272 'graft',
3273 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3273 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3274 ('c', 'continue', False, _('resume interrupted graft')),
3274 ('c', 'continue', False, _('resume interrupted graft')),
3275 ('e', 'edit', False, _('invoke editor on commit messages')),
3275 ('e', 'edit', False, _('invoke editor on commit messages')),
3276 ('', 'log', None, _('append graft info to log message')),
3276 ('', 'log', None, _('append graft info to log message')),
3277 ('f', 'force', False, _('force graft')),
3277 ('f', 'force', False, _('force graft')),
3278 ('D', 'currentdate', False,
3278 ('D', 'currentdate', False,
3279 _('record the current date as commit date')),
3279 _('record the current date as commit date')),
3280 ('U', 'currentuser', False,
3280 ('U', 'currentuser', False,
3281 _('record the current user as committer'), _('DATE'))]
3281 _('record the current user as committer'), _('DATE'))]
3282 + commitopts2 + mergetoolopts + dryrunopts,
3282 + commitopts2 + mergetoolopts + dryrunopts,
3283 _('[OPTION]... [-r] REV...'))
3283 _('[OPTION]... [-r] REV...'))
3284 def graft(ui, repo, *revs, **opts):
3284 def graft(ui, repo, *revs, **opts):
3285 '''copy changes from other branches onto the current branch
3285 '''copy changes from other branches onto the current branch
3286
3286
3287 This command uses Mercurial's merge logic to copy individual
3287 This command uses Mercurial's merge logic to copy individual
3288 changes from other branches without merging branches in the
3288 changes from other branches without merging branches in the
3289 history graph. This is sometimes known as 'backporting' or
3289 history graph. This is sometimes known as 'backporting' or
3290 'cherry-picking'. By default, graft will copy user, date, and
3290 'cherry-picking'. By default, graft will copy user, date, and
3291 description from the source changesets.
3291 description from the source changesets.
3292
3292
3293 Changesets that are ancestors of the current revision, that have
3293 Changesets that are ancestors of the current revision, that have
3294 already been grafted, or that are merges will be skipped.
3294 already been grafted, or that are merges will be skipped.
3295
3295
3296 If --log is specified, log messages will have a comment appended
3296 If --log is specified, log messages will have a comment appended
3297 of the form::
3297 of the form::
3298
3298
3299 (grafted from CHANGESETHASH)
3299 (grafted from CHANGESETHASH)
3300
3300
3301 If --force is specified, revisions will be grafted even if they
3301 If --force is specified, revisions will be grafted even if they
3302 are already ancestors of or have been grafted to the destination.
3302 are already ancestors of or have been grafted to the destination.
3303 This is useful when the revisions have since been backed out.
3303 This is useful when the revisions have since been backed out.
3304
3304
3305 If a graft merge results in conflicts, the graft process is
3305 If a graft merge results in conflicts, the graft process is
3306 interrupted so that the current merge can be manually resolved.
3306 interrupted so that the current merge can be manually resolved.
3307 Once all conflicts are addressed, the graft process can be
3307 Once all conflicts are addressed, the graft process can be
3308 continued with the -c/--continue option.
3308 continued with the -c/--continue option.
3309
3309
3310 .. note::
3310 .. note::
3311
3311
3312 The -c/--continue option does not reapply earlier options, except
3312 The -c/--continue option does not reapply earlier options, except
3313 for --force.
3313 for --force.
3314
3314
3315 .. container:: verbose
3315 .. container:: verbose
3316
3316
3317 Examples:
3317 Examples:
3318
3318
3319 - copy a single change to the stable branch and edit its description::
3319 - copy a single change to the stable branch and edit its description::
3320
3320
3321 hg update stable
3321 hg update stable
3322 hg graft --edit 9393
3322 hg graft --edit 9393
3323
3323
3324 - graft a range of changesets with one exception, updating dates::
3324 - graft a range of changesets with one exception, updating dates::
3325
3325
3326 hg graft -D "2085::2093 and not 2091"
3326 hg graft -D "2085::2093 and not 2091"
3327
3327
3328 - continue a graft after resolving conflicts::
3328 - continue a graft after resolving conflicts::
3329
3329
3330 hg graft -c
3330 hg graft -c
3331
3331
3332 - show the source of a grafted changeset::
3332 - show the source of a grafted changeset::
3333
3333
3334 hg log --debug -r .
3334 hg log --debug -r .
3335
3335
3336 See :hg:`help revisions` and :hg:`help revsets` for more about
3336 See :hg:`help revisions` and :hg:`help revsets` for more about
3337 specifying revisions.
3337 specifying revisions.
3338
3338
3339 Returns 0 on successful completion.
3339 Returns 0 on successful completion.
3340 '''
3340 '''
3341
3341
3342 revs = list(revs)
3342 revs = list(revs)
3343 revs.extend(opts['rev'])
3343 revs.extend(opts['rev'])
3344
3344
3345 if not opts.get('user') and opts.get('currentuser'):
3345 if not opts.get('user') and opts.get('currentuser'):
3346 opts['user'] = ui.username()
3346 opts['user'] = ui.username()
3347 if not opts.get('date') and opts.get('currentdate'):
3347 if not opts.get('date') and opts.get('currentdate'):
3348 opts['date'] = "%d %d" % util.makedate()
3348 opts['date'] = "%d %d" % util.makedate()
3349
3349
3350 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3350 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3351
3351
3352 cont = False
3352 cont = False
3353 if opts['continue']:
3353 if opts['continue']:
3354 cont = True
3354 cont = True
3355 if revs:
3355 if revs:
3356 raise util.Abort(_("can't specify --continue and revisions"))
3356 raise util.Abort(_("can't specify --continue and revisions"))
3357 # read in unfinished revisions
3357 # read in unfinished revisions
3358 try:
3358 try:
3359 nodes = repo.opener.read('graftstate').splitlines()
3359 nodes = repo.opener.read('graftstate').splitlines()
3360 revs = [repo[node].rev() for node in nodes]
3360 revs = [repo[node].rev() for node in nodes]
3361 except IOError, inst:
3361 except IOError, inst:
3362 if inst.errno != errno.ENOENT:
3362 if inst.errno != errno.ENOENT:
3363 raise
3363 raise
3364 raise util.Abort(_("no graft state found, can't continue"))
3364 raise util.Abort(_("no graft state found, can't continue"))
3365 else:
3365 else:
3366 cmdutil.checkunfinished(repo)
3366 cmdutil.checkunfinished(repo)
3367 cmdutil.bailifchanged(repo)
3367 cmdutil.bailifchanged(repo)
3368 if not revs:
3368 if not revs:
3369 raise util.Abort(_('no revisions specified'))
3369 raise util.Abort(_('no revisions specified'))
3370 revs = scmutil.revrange(repo, revs)
3370 revs = scmutil.revrange(repo, revs)
3371
3371
3372 skipped = set()
3372 skipped = set()
3373 # check for merges
3373 # check for merges
3374 for rev in repo.revs('%ld and merge()', revs):
3374 for rev in repo.revs('%ld and merge()', revs):
3375 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3375 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3376 skipped.add(rev)
3376 skipped.add(rev)
3377 revs = [r for r in revs if r not in skipped]
3377 revs = [r for r in revs if r not in skipped]
3378 if not revs:
3378 if not revs:
3379 return -1
3379 return -1
3380
3380
3381 # Don't check in the --continue case, in effect retaining --force across
3381 # Don't check in the --continue case, in effect retaining --force across
3382 # --continues. That's because without --force, any revisions we decided to
3382 # --continues. That's because without --force, any revisions we decided to
3383 # skip would have been filtered out here, so they wouldn't have made their
3383 # skip would have been filtered out here, so they wouldn't have made their
3384 # way to the graftstate. With --force, any revisions we would have otherwise
3384 # way to the graftstate. With --force, any revisions we would have otherwise
3385 # skipped would not have been filtered out, and if they hadn't been applied
3385 # skipped would not have been filtered out, and if they hadn't been applied
3386 # already, they'd have been in the graftstate.
3386 # already, they'd have been in the graftstate.
3387 if not (cont or opts.get('force')):
3387 if not (cont or opts.get('force')):
3388 # check for ancestors of dest branch
3388 # check for ancestors of dest branch
3389 crev = repo['.'].rev()
3389 crev = repo['.'].rev()
3390 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3390 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3391 # Cannot use x.remove(y) on smart set, this has to be a list.
3391 # Cannot use x.remove(y) on smart set, this has to be a list.
3392 # XXX make this lazy in the future
3392 # XXX make this lazy in the future
3393 revs = list(revs)
3393 revs = list(revs)
3394 # don't mutate while iterating, create a copy
3394 # don't mutate while iterating, create a copy
3395 for rev in list(revs):
3395 for rev in list(revs):
3396 if rev in ancestors:
3396 if rev in ancestors:
3397 ui.warn(_('skipping ancestor revision %s\n') % rev)
3397 ui.warn(_('skipping ancestor revision %s\n') % rev)
3398 # XXX remove on list is slow
3398 # XXX remove on list is slow
3399 revs.remove(rev)
3399 revs.remove(rev)
3400 if not revs:
3400 if not revs:
3401 return -1
3401 return -1
3402
3402
3403 # analyze revs for earlier grafts
3403 # analyze revs for earlier grafts
3404 ids = {}
3404 ids = {}
3405 for ctx in repo.set("%ld", revs):
3405 for ctx in repo.set("%ld", revs):
3406 ids[ctx.hex()] = ctx.rev()
3406 ids[ctx.hex()] = ctx.rev()
3407 n = ctx.extra().get('source')
3407 n = ctx.extra().get('source')
3408 if n:
3408 if n:
3409 ids[n] = ctx.rev()
3409 ids[n] = ctx.rev()
3410
3410
3411 # check ancestors for earlier grafts
3411 # check ancestors for earlier grafts
3412 ui.debug('scanning for duplicate grafts\n')
3412 ui.debug('scanning for duplicate grafts\n')
3413
3413
3414 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3414 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3415 ctx = repo[rev]
3415 ctx = repo[rev]
3416 n = ctx.extra().get('source')
3416 n = ctx.extra().get('source')
3417 if n in ids:
3417 if n in ids:
3418 try:
3418 try:
3419 r = repo[n].rev()
3419 r = repo[n].rev()
3420 except error.RepoLookupError:
3420 except error.RepoLookupError:
3421 r = None
3421 r = None
3422 if r in revs:
3422 if r in revs:
3423 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3423 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3424 % (r, rev))
3424 % (r, rev))
3425 revs.remove(r)
3425 revs.remove(r)
3426 elif ids[n] in revs:
3426 elif ids[n] in revs:
3427 if r is None:
3427 if r is None:
3428 ui.warn(_('skipping already grafted revision %s '
3428 ui.warn(_('skipping already grafted revision %s '
3429 '(%s also has unknown origin %s)\n')
3429 '(%s also has unknown origin %s)\n')
3430 % (ids[n], rev, n))
3430 % (ids[n], rev, n))
3431 else:
3431 else:
3432 ui.warn(_('skipping already grafted revision %s '
3432 ui.warn(_('skipping already grafted revision %s '
3433 '(%s also has origin %d)\n')
3433 '(%s also has origin %d)\n')
3434 % (ids[n], rev, r))
3434 % (ids[n], rev, r))
3435 revs.remove(ids[n])
3435 revs.remove(ids[n])
3436 elif ctx.hex() in ids:
3436 elif ctx.hex() in ids:
3437 r = ids[ctx.hex()]
3437 r = ids[ctx.hex()]
3438 ui.warn(_('skipping already grafted revision %s '
3438 ui.warn(_('skipping already grafted revision %s '
3439 '(was grafted from %d)\n') % (r, rev))
3439 '(was grafted from %d)\n') % (r, rev))
3440 revs.remove(r)
3440 revs.remove(r)
3441 if not revs:
3441 if not revs:
3442 return -1
3442 return -1
3443
3443
3444 wlock = repo.wlock()
3444 wlock = repo.wlock()
3445 try:
3445 try:
3446 for pos, ctx in enumerate(repo.set("%ld", revs)):
3446 for pos, ctx in enumerate(repo.set("%ld", revs)):
3447
3447
3448 ui.status(_('grafting revision %s\n') % ctx.rev())
3448 ui.status(_('grafting revision %s\n') % ctx.rev())
3449 if opts.get('dry_run'):
3449 if opts.get('dry_run'):
3450 continue
3450 continue
3451
3451
3452 source = ctx.extra().get('source')
3452 source = ctx.extra().get('source')
3453 if not source:
3453 if not source:
3454 source = ctx.hex()
3454 source = ctx.hex()
3455 extra = {'source': source}
3455 extra = {'source': source}
3456 user = ctx.user()
3456 user = ctx.user()
3457 if opts.get('user'):
3457 if opts.get('user'):
3458 user = opts['user']
3458 user = opts['user']
3459 date = ctx.date()
3459 date = ctx.date()
3460 if opts.get('date'):
3460 if opts.get('date'):
3461 date = opts['date']
3461 date = opts['date']
3462 message = ctx.description()
3462 message = ctx.description()
3463 if opts.get('log'):
3463 if opts.get('log'):
3464 message += '\n(grafted from %s)' % ctx.hex()
3464 message += '\n(grafted from %s)' % ctx.hex()
3465
3465
3466 # we don't merge the first commit when continuing
3466 # we don't merge the first commit when continuing
3467 if not cont:
3467 if not cont:
3468 # perform the graft merge with p1(rev) as 'ancestor'
3468 # perform the graft merge with p1(rev) as 'ancestor'
3469 try:
3469 try:
3470 # ui.forcemerge is an internal variable, do not document
3470 # ui.forcemerge is an internal variable, do not document
3471 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3471 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3472 'graft')
3472 'graft')
3473 stats = mergemod.graft(repo, ctx, ctx.p1(),
3473 stats = mergemod.graft(repo, ctx, ctx.p1(),
3474 ['local', 'graft'])
3474 ['local', 'graft'])
3475 finally:
3475 finally:
3476 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3476 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3477 # report any conflicts
3477 # report any conflicts
3478 if stats and stats[3] > 0:
3478 if stats and stats[3] > 0:
3479 # write out state for --continue
3479 # write out state for --continue
3480 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3480 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3481 repo.opener.write('graftstate', ''.join(nodelines))
3481 repo.opener.write('graftstate', ''.join(nodelines))
3482 raise util.Abort(
3482 raise util.Abort(
3483 _("unresolved conflicts, can't continue"),
3483 _("unresolved conflicts, can't continue"),
3484 hint=_('use hg resolve and hg graft --continue'))
3484 hint=_('use hg resolve and hg graft --continue'))
3485 else:
3485 else:
3486 cont = False
3486 cont = False
3487
3487
3488 # commit
3488 # commit
3489 node = repo.commit(text=message, user=user,
3489 node = repo.commit(text=message, user=user,
3490 date=date, extra=extra, editor=editor)
3490 date=date, extra=extra, editor=editor)
3491 if node is None:
3491 if node is None:
3492 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3492 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3493 finally:
3493 finally:
3494 wlock.release()
3494 wlock.release()
3495
3495
3496 # remove state when we complete successfully
3496 # remove state when we complete successfully
3497 if not opts.get('dry_run'):
3497 if not opts.get('dry_run'):
3498 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3498 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3499
3499
3500 return 0
3500 return 0
3501
3501
3502 @command('grep',
3502 @command('grep',
3503 [('0', 'print0', None, _('end fields with NUL')),
3503 [('0', 'print0', None, _('end fields with NUL')),
3504 ('', 'all', None, _('print all revisions that match')),
3504 ('', 'all', None, _('print all revisions that match')),
3505 ('a', 'text', None, _('treat all files as text')),
3505 ('a', 'text', None, _('treat all files as text')),
3506 ('f', 'follow', None,
3506 ('f', 'follow', None,
3507 _('follow changeset history,'
3507 _('follow changeset history,'
3508 ' or file history across copies and renames')),
3508 ' or file history across copies and renames')),
3509 ('i', 'ignore-case', None, _('ignore case when matching')),
3509 ('i', 'ignore-case', None, _('ignore case when matching')),
3510 ('l', 'files-with-matches', None,
3510 ('l', 'files-with-matches', None,
3511 _('print only filenames and revisions that match')),
3511 _('print only filenames and revisions that match')),
3512 ('n', 'line-number', None, _('print matching line numbers')),
3512 ('n', 'line-number', None, _('print matching line numbers')),
3513 ('r', 'rev', [],
3513 ('r', 'rev', [],
3514 _('only search files changed within revision range'), _('REV')),
3514 _('only search files changed within revision range'), _('REV')),
3515 ('u', 'user', None, _('list the author (long with -v)')),
3515 ('u', 'user', None, _('list the author (long with -v)')),
3516 ('d', 'date', None, _('list the date (short with -q)')),
3516 ('d', 'date', None, _('list the date (short with -q)')),
3517 ] + walkopts,
3517 ] + walkopts,
3518 _('[OPTION]... PATTERN [FILE]...'),
3518 _('[OPTION]... PATTERN [FILE]...'),
3519 inferrepo=True)
3519 inferrepo=True)
3520 def grep(ui, repo, pattern, *pats, **opts):
3520 def grep(ui, repo, pattern, *pats, **opts):
3521 """search for a pattern in specified files and revisions
3521 """search for a pattern in specified files and revisions
3522
3522
3523 Search revisions of files for a regular expression.
3523 Search revisions of files for a regular expression.
3524
3524
3525 This command behaves differently than Unix grep. It only accepts
3525 This command behaves differently than Unix grep. It only accepts
3526 Python/Perl regexps. It searches repository history, not the
3526 Python/Perl regexps. It searches repository history, not the
3527 working directory. It always prints the revision number in which a
3527 working directory. It always prints the revision number in which a
3528 match appears.
3528 match appears.
3529
3529
3530 By default, grep only prints output for the first revision of a
3530 By default, grep only prints output for the first revision of a
3531 file in which it finds a match. To get it to print every revision
3531 file in which it finds a match. To get it to print every revision
3532 that contains a change in match status ("-" for a match that
3532 that contains a change in match status ("-" for a match that
3533 becomes a non-match, or "+" for a non-match that becomes a match),
3533 becomes a non-match, or "+" for a non-match that becomes a match),
3534 use the --all flag.
3534 use the --all flag.
3535
3535
3536 Returns 0 if a match is found, 1 otherwise.
3536 Returns 0 if a match is found, 1 otherwise.
3537 """
3537 """
3538 reflags = re.M
3538 reflags = re.M
3539 if opts.get('ignore_case'):
3539 if opts.get('ignore_case'):
3540 reflags |= re.I
3540 reflags |= re.I
3541 try:
3541 try:
3542 regexp = util.re.compile(pattern, reflags)
3542 regexp = util.re.compile(pattern, reflags)
3543 except re.error, inst:
3543 except re.error, inst:
3544 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3544 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3545 return 1
3545 return 1
3546 sep, eol = ':', '\n'
3546 sep, eol = ':', '\n'
3547 if opts.get('print0'):
3547 if opts.get('print0'):
3548 sep = eol = '\0'
3548 sep = eol = '\0'
3549
3549
3550 getfile = util.lrucachefunc(repo.file)
3550 getfile = util.lrucachefunc(repo.file)
3551
3551
3552 def matchlines(body):
3552 def matchlines(body):
3553 begin = 0
3553 begin = 0
3554 linenum = 0
3554 linenum = 0
3555 while begin < len(body):
3555 while begin < len(body):
3556 match = regexp.search(body, begin)
3556 match = regexp.search(body, begin)
3557 if not match:
3557 if not match:
3558 break
3558 break
3559 mstart, mend = match.span()
3559 mstart, mend = match.span()
3560 linenum += body.count('\n', begin, mstart) + 1
3560 linenum += body.count('\n', begin, mstart) + 1
3561 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3561 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3562 begin = body.find('\n', mend) + 1 or len(body) + 1
3562 begin = body.find('\n', mend) + 1 or len(body) + 1
3563 lend = begin - 1
3563 lend = begin - 1
3564 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3564 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3565
3565
3566 class linestate(object):
3566 class linestate(object):
3567 def __init__(self, line, linenum, colstart, colend):
3567 def __init__(self, line, linenum, colstart, colend):
3568 self.line = line
3568 self.line = line
3569 self.linenum = linenum
3569 self.linenum = linenum
3570 self.colstart = colstart
3570 self.colstart = colstart
3571 self.colend = colend
3571 self.colend = colend
3572
3572
3573 def __hash__(self):
3573 def __hash__(self):
3574 return hash((self.linenum, self.line))
3574 return hash((self.linenum, self.line))
3575
3575
3576 def __eq__(self, other):
3576 def __eq__(self, other):
3577 return self.line == other.line
3577 return self.line == other.line
3578
3578
3579 def __iter__(self):
3579 def __iter__(self):
3580 yield (self.line[:self.colstart], '')
3580 yield (self.line[:self.colstart], '')
3581 yield (self.line[self.colstart:self.colend], 'grep.match')
3581 yield (self.line[self.colstart:self.colend], 'grep.match')
3582 rest = self.line[self.colend:]
3582 rest = self.line[self.colend:]
3583 while rest != '':
3583 while rest != '':
3584 match = regexp.search(rest)
3584 match = regexp.search(rest)
3585 if not match:
3585 if not match:
3586 yield (rest, '')
3586 yield (rest, '')
3587 break
3587 break
3588 mstart, mend = match.span()
3588 mstart, mend = match.span()
3589 yield (rest[:mstart], '')
3589 yield (rest[:mstart], '')
3590 yield (rest[mstart:mend], 'grep.match')
3590 yield (rest[mstart:mend], 'grep.match')
3591 rest = rest[mend:]
3591 rest = rest[mend:]
3592
3592
3593 matches = {}
3593 matches = {}
3594 copies = {}
3594 copies = {}
3595 def grepbody(fn, rev, body):
3595 def grepbody(fn, rev, body):
3596 matches[rev].setdefault(fn, [])
3596 matches[rev].setdefault(fn, [])
3597 m = matches[rev][fn]
3597 m = matches[rev][fn]
3598 for lnum, cstart, cend, line in matchlines(body):
3598 for lnum, cstart, cend, line in matchlines(body):
3599 s = linestate(line, lnum, cstart, cend)
3599 s = linestate(line, lnum, cstart, cend)
3600 m.append(s)
3600 m.append(s)
3601
3601
3602 def difflinestates(a, b):
3602 def difflinestates(a, b):
3603 sm = difflib.SequenceMatcher(None, a, b)
3603 sm = difflib.SequenceMatcher(None, a, b)
3604 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3604 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3605 if tag == 'insert':
3605 if tag == 'insert':
3606 for i in xrange(blo, bhi):
3606 for i in xrange(blo, bhi):
3607 yield ('+', b[i])
3607 yield ('+', b[i])
3608 elif tag == 'delete':
3608 elif tag == 'delete':
3609 for i in xrange(alo, ahi):
3609 for i in xrange(alo, ahi):
3610 yield ('-', a[i])
3610 yield ('-', a[i])
3611 elif tag == 'replace':
3611 elif tag == 'replace':
3612 for i in xrange(alo, ahi):
3612 for i in xrange(alo, ahi):
3613 yield ('-', a[i])
3613 yield ('-', a[i])
3614 for i in xrange(blo, bhi):
3614 for i in xrange(blo, bhi):
3615 yield ('+', b[i])
3615 yield ('+', b[i])
3616
3616
3617 def display(fn, ctx, pstates, states):
3617 def display(fn, ctx, pstates, states):
3618 rev = ctx.rev()
3618 rev = ctx.rev()
3619 datefunc = ui.quiet and util.shortdate or util.datestr
3619 datefunc = ui.quiet and util.shortdate or util.datestr
3620 found = False
3620 found = False
3621 @util.cachefunc
3621 @util.cachefunc
3622 def binary():
3622 def binary():
3623 flog = getfile(fn)
3623 flog = getfile(fn)
3624 return util.binary(flog.read(ctx.filenode(fn)))
3624 return util.binary(flog.read(ctx.filenode(fn)))
3625
3625
3626 if opts.get('all'):
3626 if opts.get('all'):
3627 iter = difflinestates(pstates, states)
3627 iter = difflinestates(pstates, states)
3628 else:
3628 else:
3629 iter = [('', l) for l in states]
3629 iter = [('', l) for l in states]
3630 for change, l in iter:
3630 for change, l in iter:
3631 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3631 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3632
3632
3633 if opts.get('line_number'):
3633 if opts.get('line_number'):
3634 cols.append((str(l.linenum), 'grep.linenumber'))
3634 cols.append((str(l.linenum), 'grep.linenumber'))
3635 if opts.get('all'):
3635 if opts.get('all'):
3636 cols.append((change, 'grep.change'))
3636 cols.append((change, 'grep.change'))
3637 if opts.get('user'):
3637 if opts.get('user'):
3638 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3638 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3639 if opts.get('date'):
3639 if opts.get('date'):
3640 cols.append((datefunc(ctx.date()), 'grep.date'))
3640 cols.append((datefunc(ctx.date()), 'grep.date'))
3641 for col, label in cols[:-1]:
3641 for col, label in cols[:-1]:
3642 ui.write(col, label=label)
3642 ui.write(col, label=label)
3643 ui.write(sep, label='grep.sep')
3643 ui.write(sep, label='grep.sep')
3644 ui.write(cols[-1][0], label=cols[-1][1])
3644 ui.write(cols[-1][0], label=cols[-1][1])
3645 if not opts.get('files_with_matches'):
3645 if not opts.get('files_with_matches'):
3646 ui.write(sep, label='grep.sep')
3646 ui.write(sep, label='grep.sep')
3647 if not opts.get('text') and binary():
3647 if not opts.get('text') and binary():
3648 ui.write(" Binary file matches")
3648 ui.write(" Binary file matches")
3649 else:
3649 else:
3650 for s, label in l:
3650 for s, label in l:
3651 ui.write(s, label=label)
3651 ui.write(s, label=label)
3652 ui.write(eol)
3652 ui.write(eol)
3653 found = True
3653 found = True
3654 if opts.get('files_with_matches'):
3654 if opts.get('files_with_matches'):
3655 break
3655 break
3656 return found
3656 return found
3657
3657
3658 skip = {}
3658 skip = {}
3659 revfiles = {}
3659 revfiles = {}
3660 matchfn = scmutil.match(repo[None], pats, opts)
3660 matchfn = scmutil.match(repo[None], pats, opts)
3661 found = False
3661 found = False
3662 follow = opts.get('follow')
3662 follow = opts.get('follow')
3663
3663
3664 def prep(ctx, fns):
3664 def prep(ctx, fns):
3665 rev = ctx.rev()
3665 rev = ctx.rev()
3666 pctx = ctx.p1()
3666 pctx = ctx.p1()
3667 parent = pctx.rev()
3667 parent = pctx.rev()
3668 matches.setdefault(rev, {})
3668 matches.setdefault(rev, {})
3669 matches.setdefault(parent, {})
3669 matches.setdefault(parent, {})
3670 files = revfiles.setdefault(rev, [])
3670 files = revfiles.setdefault(rev, [])
3671 for fn in fns:
3671 for fn in fns:
3672 flog = getfile(fn)
3672 flog = getfile(fn)
3673 try:
3673 try:
3674 fnode = ctx.filenode(fn)
3674 fnode = ctx.filenode(fn)
3675 except error.LookupError:
3675 except error.LookupError:
3676 continue
3676 continue
3677
3677
3678 copied = flog.renamed(fnode)
3678 copied = flog.renamed(fnode)
3679 copy = follow and copied and copied[0]
3679 copy = follow and copied and copied[0]
3680 if copy:
3680 if copy:
3681 copies.setdefault(rev, {})[fn] = copy
3681 copies.setdefault(rev, {})[fn] = copy
3682 if fn in skip:
3682 if fn in skip:
3683 if copy:
3683 if copy:
3684 skip[copy] = True
3684 skip[copy] = True
3685 continue
3685 continue
3686 files.append(fn)
3686 files.append(fn)
3687
3687
3688 if fn not in matches[rev]:
3688 if fn not in matches[rev]:
3689 grepbody(fn, rev, flog.read(fnode))
3689 grepbody(fn, rev, flog.read(fnode))
3690
3690
3691 pfn = copy or fn
3691 pfn = copy or fn
3692 if pfn not in matches[parent]:
3692 if pfn not in matches[parent]:
3693 try:
3693 try:
3694 fnode = pctx.filenode(pfn)
3694 fnode = pctx.filenode(pfn)
3695 grepbody(pfn, parent, flog.read(fnode))
3695 grepbody(pfn, parent, flog.read(fnode))
3696 except error.LookupError:
3696 except error.LookupError:
3697 pass
3697 pass
3698
3698
3699 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3699 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3700 rev = ctx.rev()
3700 rev = ctx.rev()
3701 parent = ctx.p1().rev()
3701 parent = ctx.p1().rev()
3702 for fn in sorted(revfiles.get(rev, [])):
3702 for fn in sorted(revfiles.get(rev, [])):
3703 states = matches[rev][fn]
3703 states = matches[rev][fn]
3704 copy = copies.get(rev, {}).get(fn)
3704 copy = copies.get(rev, {}).get(fn)
3705 if fn in skip:
3705 if fn in skip:
3706 if copy:
3706 if copy:
3707 skip[copy] = True
3707 skip[copy] = True
3708 continue
3708 continue
3709 pstates = matches.get(parent, {}).get(copy or fn, [])
3709 pstates = matches.get(parent, {}).get(copy or fn, [])
3710 if pstates or states:
3710 if pstates or states:
3711 r = display(fn, ctx, pstates, states)
3711 r = display(fn, ctx, pstates, states)
3712 found = found or r
3712 found = found or r
3713 if r and not opts.get('all'):
3713 if r and not opts.get('all'):
3714 skip[fn] = True
3714 skip[fn] = True
3715 if copy:
3715 if copy:
3716 skip[copy] = True
3716 skip[copy] = True
3717 del matches[rev]
3717 del matches[rev]
3718 del revfiles[rev]
3718 del revfiles[rev]
3719
3719
3720 return not found
3720 return not found
3721
3721
3722 @command('heads',
3722 @command('heads',
3723 [('r', 'rev', '',
3723 [('r', 'rev', '',
3724 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3724 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3725 ('t', 'topo', False, _('show topological heads only')),
3725 ('t', 'topo', False, _('show topological heads only')),
3726 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3726 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3727 ('c', 'closed', False, _('show normal and closed branch heads')),
3727 ('c', 'closed', False, _('show normal and closed branch heads')),
3728 ] + templateopts,
3728 ] + templateopts,
3729 _('[-ct] [-r STARTREV] [REV]...'))
3729 _('[-ct] [-r STARTREV] [REV]...'))
3730 def heads(ui, repo, *branchrevs, **opts):
3730 def heads(ui, repo, *branchrevs, **opts):
3731 """show branch heads
3731 """show branch heads
3732
3732
3733 With no arguments, show all open branch heads in the repository.
3733 With no arguments, show all open branch heads in the repository.
3734 Branch heads are changesets that have no descendants on the
3734 Branch heads are changesets that have no descendants on the
3735 same branch. They are where development generally takes place and
3735 same branch. They are where development generally takes place and
3736 are the usual targets for update and merge operations.
3736 are the usual targets for update and merge operations.
3737
3737
3738 If one or more REVs are given, only open branch heads on the
3738 If one or more REVs are given, only open branch heads on the
3739 branches associated with the specified changesets are shown. This
3739 branches associated with the specified changesets are shown. This
3740 means that you can use :hg:`heads .` to see the heads on the
3740 means that you can use :hg:`heads .` to see the heads on the
3741 currently checked-out branch.
3741 currently checked-out branch.
3742
3742
3743 If -c/--closed is specified, also show branch heads marked closed
3743 If -c/--closed is specified, also show branch heads marked closed
3744 (see :hg:`commit --close-branch`).
3744 (see :hg:`commit --close-branch`).
3745
3745
3746 If STARTREV is specified, only those heads that are descendants of
3746 If STARTREV is specified, only those heads that are descendants of
3747 STARTREV will be displayed.
3747 STARTREV will be displayed.
3748
3748
3749 If -t/--topo is specified, named branch mechanics will be ignored and only
3749 If -t/--topo is specified, named branch mechanics will be ignored and only
3750 topological heads (changesets with no children) will be shown.
3750 topological heads (changesets with no children) will be shown.
3751
3751
3752 Returns 0 if matching heads are found, 1 if not.
3752 Returns 0 if matching heads are found, 1 if not.
3753 """
3753 """
3754
3754
3755 start = None
3755 start = None
3756 if 'rev' in opts:
3756 if 'rev' in opts:
3757 start = scmutil.revsingle(repo, opts['rev'], None).node()
3757 start = scmutil.revsingle(repo, opts['rev'], None).node()
3758
3758
3759 if opts.get('topo'):
3759 if opts.get('topo'):
3760 heads = [repo[h] for h in repo.heads(start)]
3760 heads = [repo[h] for h in repo.heads(start)]
3761 else:
3761 else:
3762 heads = []
3762 heads = []
3763 for branch in repo.branchmap():
3763 for branch in repo.branchmap():
3764 heads += repo.branchheads(branch, start, opts.get('closed'))
3764 heads += repo.branchheads(branch, start, opts.get('closed'))
3765 heads = [repo[h] for h in heads]
3765 heads = [repo[h] for h in heads]
3766
3766
3767 if branchrevs:
3767 if branchrevs:
3768 branches = set(repo[br].branch() for br in branchrevs)
3768 branches = set(repo[br].branch() for br in branchrevs)
3769 heads = [h for h in heads if h.branch() in branches]
3769 heads = [h for h in heads if h.branch() in branches]
3770
3770
3771 if opts.get('active') and branchrevs:
3771 if opts.get('active') and branchrevs:
3772 dagheads = repo.heads(start)
3772 dagheads = repo.heads(start)
3773 heads = [h for h in heads if h.node() in dagheads]
3773 heads = [h for h in heads if h.node() in dagheads]
3774
3774
3775 if branchrevs:
3775 if branchrevs:
3776 haveheads = set(h.branch() for h in heads)
3776 haveheads = set(h.branch() for h in heads)
3777 if branches - haveheads:
3777 if branches - haveheads:
3778 headless = ', '.join(b for b in branches - haveheads)
3778 headless = ', '.join(b for b in branches - haveheads)
3779 msg = _('no open branch heads found on branches %s')
3779 msg = _('no open branch heads found on branches %s')
3780 if opts.get('rev'):
3780 if opts.get('rev'):
3781 msg += _(' (started at %s)') % opts['rev']
3781 msg += _(' (started at %s)') % opts['rev']
3782 ui.warn((msg + '\n') % headless)
3782 ui.warn((msg + '\n') % headless)
3783
3783
3784 if not heads:
3784 if not heads:
3785 return 1
3785 return 1
3786
3786
3787 heads = sorted(heads, key=lambda x: -x.rev())
3787 heads = sorted(heads, key=lambda x: -x.rev())
3788 displayer = cmdutil.show_changeset(ui, repo, opts)
3788 displayer = cmdutil.show_changeset(ui, repo, opts)
3789 for ctx in heads:
3789 for ctx in heads:
3790 displayer.show(ctx)
3790 displayer.show(ctx)
3791 displayer.close()
3791 displayer.close()
3792
3792
3793 @command('help',
3793 @command('help',
3794 [('e', 'extension', None, _('show only help for extensions')),
3794 [('e', 'extension', None, _('show only help for extensions')),
3795 ('c', 'command', None, _('show only help for commands')),
3795 ('c', 'command', None, _('show only help for commands')),
3796 ('k', 'keyword', '', _('show topics matching keyword')),
3796 ('k', 'keyword', '', _('show topics matching keyword')),
3797 ],
3797 ],
3798 _('[-ec] [TOPIC]'),
3798 _('[-ec] [TOPIC]'),
3799 norepo=True)
3799 norepo=True)
3800 def help_(ui, name=None, **opts):
3800 def help_(ui, name=None, **opts):
3801 """show help for a given topic or a help overview
3801 """show help for a given topic or a help overview
3802
3802
3803 With no arguments, print a list of commands with short help messages.
3803 With no arguments, print a list of commands with short help messages.
3804
3804
3805 Given a topic, extension, or command name, print help for that
3805 Given a topic, extension, or command name, print help for that
3806 topic.
3806 topic.
3807
3807
3808 Returns 0 if successful.
3808 Returns 0 if successful.
3809 """
3809 """
3810
3810
3811 textwidth = min(ui.termwidth(), 80) - 2
3811 textwidth = min(ui.termwidth(), 80) - 2
3812
3812
3813 keep = []
3813 keep = []
3814 if ui.verbose:
3814 if ui.verbose:
3815 keep.append('verbose')
3815 keep.append('verbose')
3816 if sys.platform.startswith('win'):
3816 if sys.platform.startswith('win'):
3817 keep.append('windows')
3817 keep.append('windows')
3818 elif sys.platform == 'OpenVMS':
3818 elif sys.platform == 'OpenVMS':
3819 keep.append('vms')
3819 keep.append('vms')
3820 elif sys.platform == 'plan9':
3820 elif sys.platform == 'plan9':
3821 keep.append('plan9')
3821 keep.append('plan9')
3822 else:
3822 else:
3823 keep.append('unix')
3823 keep.append('unix')
3824 keep.append(sys.platform.lower())
3824 keep.append(sys.platform.lower())
3825
3825
3826 section = None
3826 section = None
3827 if name and '.' in name:
3827 if name and '.' in name:
3828 name, section = name.split('.', 1)
3828 name, section = name.split('.', 1)
3829
3829
3830 text = help.help_(ui, name, **opts)
3830 text = help.help_(ui, name, **opts)
3831
3831
3832 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3832 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3833 section=section)
3833 section=section)
3834 if section and not formatted:
3834 if section and not formatted:
3835 raise util.Abort(_("help section not found"))
3835 raise util.Abort(_("help section not found"))
3836
3836
3837 if 'verbose' in pruned:
3837 if 'verbose' in pruned:
3838 keep.append('omitted')
3838 keep.append('omitted')
3839 else:
3839 else:
3840 keep.append('notomitted')
3840 keep.append('notomitted')
3841 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3841 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3842 section=section)
3842 section=section)
3843 ui.write(formatted)
3843 ui.write(formatted)
3844
3844
3845
3845
3846 @command('identify|id',
3846 @command('identify|id',
3847 [('r', 'rev', '',
3847 [('r', 'rev', '',
3848 _('identify the specified revision'), _('REV')),
3848 _('identify the specified revision'), _('REV')),
3849 ('n', 'num', None, _('show local revision number')),
3849 ('n', 'num', None, _('show local revision number')),
3850 ('i', 'id', None, _('show global revision id')),
3850 ('i', 'id', None, _('show global revision id')),
3851 ('b', 'branch', None, _('show branch')),
3851 ('b', 'branch', None, _('show branch')),
3852 ('t', 'tags', None, _('show tags')),
3852 ('t', 'tags', None, _('show tags')),
3853 ('B', 'bookmarks', None, _('show bookmarks')),
3853 ('B', 'bookmarks', None, _('show bookmarks')),
3854 ] + remoteopts,
3854 ] + remoteopts,
3855 _('[-nibtB] [-r REV] [SOURCE]'),
3855 _('[-nibtB] [-r REV] [SOURCE]'),
3856 optionalrepo=True)
3856 optionalrepo=True)
3857 def identify(ui, repo, source=None, rev=None,
3857 def identify(ui, repo, source=None, rev=None,
3858 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3858 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3859 """identify the working copy or specified revision
3859 """identify the working copy or specified revision
3860
3860
3861 Print a summary identifying the repository state at REV using one or
3861 Print a summary identifying the repository state at REV using one or
3862 two parent hash identifiers, followed by a "+" if the working
3862 two parent hash identifiers, followed by a "+" if the working
3863 directory has uncommitted changes, the branch name (if not default),
3863 directory has uncommitted changes, the branch name (if not default),
3864 a list of tags, and a list of bookmarks.
3864 a list of tags, and a list of bookmarks.
3865
3865
3866 When REV is not given, print a summary of the current state of the
3866 When REV is not given, print a summary of the current state of the
3867 repository.
3867 repository.
3868
3868
3869 Specifying a path to a repository root or Mercurial bundle will
3869 Specifying a path to a repository root or Mercurial bundle will
3870 cause lookup to operate on that repository/bundle.
3870 cause lookup to operate on that repository/bundle.
3871
3871
3872 .. container:: verbose
3872 .. container:: verbose
3873
3873
3874 Examples:
3874 Examples:
3875
3875
3876 - generate a build identifier for the working directory::
3876 - generate a build identifier for the working directory::
3877
3877
3878 hg id --id > build-id.dat
3878 hg id --id > build-id.dat
3879
3879
3880 - find the revision corresponding to a tag::
3880 - find the revision corresponding to a tag::
3881
3881
3882 hg id -n -r 1.3
3882 hg id -n -r 1.3
3883
3883
3884 - check the most recent revision of a remote repository::
3884 - check the most recent revision of a remote repository::
3885
3885
3886 hg id -r tip http://selenic.com/hg/
3886 hg id -r tip http://selenic.com/hg/
3887
3887
3888 Returns 0 if successful.
3888 Returns 0 if successful.
3889 """
3889 """
3890
3890
3891 if not repo and not source:
3891 if not repo and not source:
3892 raise util.Abort(_("there is no Mercurial repository here "
3892 raise util.Abort(_("there is no Mercurial repository here "
3893 "(.hg not found)"))
3893 "(.hg not found)"))
3894
3894
3895 hexfunc = ui.debugflag and hex or short
3895 hexfunc = ui.debugflag and hex or short
3896 default = not (num or id or branch or tags or bookmarks)
3896 default = not (num or id or branch or tags or bookmarks)
3897 output = []
3897 output = []
3898 revs = []
3898 revs = []
3899
3899
3900 if source:
3900 if source:
3901 source, branches = hg.parseurl(ui.expandpath(source))
3901 source, branches = hg.parseurl(ui.expandpath(source))
3902 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3902 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3903 repo = peer.local()
3903 repo = peer.local()
3904 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3904 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3905
3905
3906 if not repo:
3906 if not repo:
3907 if num or branch or tags:
3907 if num or branch or tags:
3908 raise util.Abort(
3908 raise util.Abort(
3909 _("can't query remote revision number, branch, or tags"))
3909 _("can't query remote revision number, branch, or tags"))
3910 if not rev and revs:
3910 if not rev and revs:
3911 rev = revs[0]
3911 rev = revs[0]
3912 if not rev:
3912 if not rev:
3913 rev = "tip"
3913 rev = "tip"
3914
3914
3915 remoterev = peer.lookup(rev)
3915 remoterev = peer.lookup(rev)
3916 if default or id:
3916 if default or id:
3917 output = [hexfunc(remoterev)]
3917 output = [hexfunc(remoterev)]
3918
3918
3919 def getbms():
3919 def getbms():
3920 bms = []
3920 bms = []
3921
3921
3922 if 'bookmarks' in peer.listkeys('namespaces'):
3922 if 'bookmarks' in peer.listkeys('namespaces'):
3923 hexremoterev = hex(remoterev)
3923 hexremoterev = hex(remoterev)
3924 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3924 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3925 if bmr == hexremoterev]
3925 if bmr == hexremoterev]
3926
3926
3927 return sorted(bms)
3927 return sorted(bms)
3928
3928
3929 if bookmarks:
3929 if bookmarks:
3930 output.extend(getbms())
3930 output.extend(getbms())
3931 elif default and not ui.quiet:
3931 elif default and not ui.quiet:
3932 # multiple bookmarks for a single parent separated by '/'
3932 # multiple bookmarks for a single parent separated by '/'
3933 bm = '/'.join(getbms())
3933 bm = '/'.join(getbms())
3934 if bm:
3934 if bm:
3935 output.append(bm)
3935 output.append(bm)
3936 else:
3936 else:
3937 if not rev:
3937 if not rev:
3938 ctx = repo[None]
3938 ctx = repo[None]
3939 parents = ctx.parents()
3939 parents = ctx.parents()
3940 changed = ""
3940 changed = ""
3941 if default or id or num:
3941 if default or id or num:
3942 if (util.any(repo.status())
3942 if (util.any(repo.status())
3943 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3943 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3944 changed = '+'
3944 changed = '+'
3945 if default or id:
3945 if default or id:
3946 output = ["%s%s" %
3946 output = ["%s%s" %
3947 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3947 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3948 if num:
3948 if num:
3949 output.append("%s%s" %
3949 output.append("%s%s" %
3950 ('+'.join([str(p.rev()) for p in parents]), changed))
3950 ('+'.join([str(p.rev()) for p in parents]), changed))
3951 else:
3951 else:
3952 ctx = scmutil.revsingle(repo, rev)
3952 ctx = scmutil.revsingle(repo, rev)
3953 if default or id:
3953 if default or id:
3954 output = [hexfunc(ctx.node())]
3954 output = [hexfunc(ctx.node())]
3955 if num:
3955 if num:
3956 output.append(str(ctx.rev()))
3956 output.append(str(ctx.rev()))
3957
3957
3958 if default and not ui.quiet:
3958 if default and not ui.quiet:
3959 b = ctx.branch()
3959 b = ctx.branch()
3960 if b != 'default':
3960 if b != 'default':
3961 output.append("(%s)" % b)
3961 output.append("(%s)" % b)
3962
3962
3963 # multiple tags for a single parent separated by '/'
3963 # multiple tags for a single parent separated by '/'
3964 t = '/'.join(ctx.tags())
3964 t = '/'.join(ctx.tags())
3965 if t:
3965 if t:
3966 output.append(t)
3966 output.append(t)
3967
3967
3968 # multiple bookmarks for a single parent separated by '/'
3968 # multiple bookmarks for a single parent separated by '/'
3969 bm = '/'.join(ctx.bookmarks())
3969 bm = '/'.join(ctx.bookmarks())
3970 if bm:
3970 if bm:
3971 output.append(bm)
3971 output.append(bm)
3972 else:
3972 else:
3973 if branch:
3973 if branch:
3974 output.append(ctx.branch())
3974 output.append(ctx.branch())
3975
3975
3976 if tags:
3976 if tags:
3977 output.extend(ctx.tags())
3977 output.extend(ctx.tags())
3978
3978
3979 if bookmarks:
3979 if bookmarks:
3980 output.extend(ctx.bookmarks())
3980 output.extend(ctx.bookmarks())
3981
3981
3982 ui.write("%s\n" % ' '.join(output))
3982 ui.write("%s\n" % ' '.join(output))
3983
3983
3984 @command('import|patch',
3984 @command('import|patch',
3985 [('p', 'strip', 1,
3985 [('p', 'strip', 1,
3986 _('directory strip option for patch. This has the same '
3986 _('directory strip option for patch. This has the same '
3987 'meaning as the corresponding patch option'), _('NUM')),
3987 'meaning as the corresponding patch option'), _('NUM')),
3988 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3988 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3989 ('e', 'edit', False, _('invoke editor on commit messages')),
3989 ('e', 'edit', False, _('invoke editor on commit messages')),
3990 ('f', 'force', None,
3990 ('f', 'force', None,
3991 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3991 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3992 ('', 'no-commit', None,
3992 ('', 'no-commit', None,
3993 _("don't commit, just update the working directory")),
3993 _("don't commit, just update the working directory")),
3994 ('', 'bypass', None,
3994 ('', 'bypass', None,
3995 _("apply patch without touching the working directory")),
3995 _("apply patch without touching the working directory")),
3996 ('', 'partial', None,
3996 ('', 'partial', None,
3997 _('commit even if some hunks fail')),
3997 _('commit even if some hunks fail')),
3998 ('', 'exact', None,
3998 ('', 'exact', None,
3999 _('apply patch to the nodes from which it was generated')),
3999 _('apply patch to the nodes from which it was generated')),
4000 ('', 'import-branch', None,
4000 ('', 'import-branch', None,
4001 _('use any branch information in patch (implied by --exact)'))] +
4001 _('use any branch information in patch (implied by --exact)'))] +
4002 commitopts + commitopts2 + similarityopts,
4002 commitopts + commitopts2 + similarityopts,
4003 _('[OPTION]... PATCH...'))
4003 _('[OPTION]... PATCH...'))
4004 def import_(ui, repo, patch1=None, *patches, **opts):
4004 def import_(ui, repo, patch1=None, *patches, **opts):
4005 """import an ordered set of patches
4005 """import an ordered set of patches
4006
4006
4007 Import a list of patches and commit them individually (unless
4007 Import a list of patches and commit them individually (unless
4008 --no-commit is specified).
4008 --no-commit is specified).
4009
4009
4010 Because import first applies changes to the working directory,
4010 Because import first applies changes to the working directory,
4011 import will abort if there are outstanding changes.
4011 import will abort if there are outstanding changes.
4012
4012
4013 You can import a patch straight from a mail message. Even patches
4013 You can import a patch straight from a mail message. Even patches
4014 as attachments work (to use the body part, it must have type
4014 as attachments work (to use the body part, it must have type
4015 text/plain or text/x-patch). From and Subject headers of email
4015 text/plain or text/x-patch). From and Subject headers of email
4016 message are used as default committer and commit message. All
4016 message are used as default committer and commit message. All
4017 text/plain body parts before first diff are added to commit
4017 text/plain body parts before first diff are added to commit
4018 message.
4018 message.
4019
4019
4020 If the imported patch was generated by :hg:`export`, user and
4020 If the imported patch was generated by :hg:`export`, user and
4021 description from patch override values from message headers and
4021 description from patch override values from message headers and
4022 body. Values given on command line with -m/--message and -u/--user
4022 body. Values given on command line with -m/--message and -u/--user
4023 override these.
4023 override these.
4024
4024
4025 If --exact is specified, import will set the working directory to
4025 If --exact is specified, import will set the working directory to
4026 the parent of each patch before applying it, and will abort if the
4026 the parent of each patch before applying it, and will abort if the
4027 resulting changeset has a different ID than the one recorded in
4027 resulting changeset has a different ID than the one recorded in
4028 the patch. This may happen due to character set problems or other
4028 the patch. This may happen due to character set problems or other
4029 deficiencies in the text patch format.
4029 deficiencies in the text patch format.
4030
4030
4031 Use --bypass to apply and commit patches directly to the
4031 Use --bypass to apply and commit patches directly to the
4032 repository, not touching the working directory. Without --exact,
4032 repository, not touching the working directory. Without --exact,
4033 patches will be applied on top of the working directory parent
4033 patches will be applied on top of the working directory parent
4034 revision.
4034 revision.
4035
4035
4036 With -s/--similarity, hg will attempt to discover renames and
4036 With -s/--similarity, hg will attempt to discover renames and
4037 copies in the patch in the same way as :hg:`addremove`.
4037 copies in the patch in the same way as :hg:`addremove`.
4038
4038
4039 Use --partial to ensure a changeset will be created from the patch
4039 Use --partial to ensure a changeset will be created from the patch
4040 even if some hunks fail to apply. Hunks that fail to apply will be
4040 even if some hunks fail to apply. Hunks that fail to apply will be
4041 written to a <target-file>.rej file. Conflicts can then be resolved
4041 written to a <target-file>.rej file. Conflicts can then be resolved
4042 by hand before :hg:`commit --amend` is run to update the created
4042 by hand before :hg:`commit --amend` is run to update the created
4043 changeset. This flag exists to let people import patches that
4043 changeset. This flag exists to let people import patches that
4044 partially apply without losing the associated metadata (author,
4044 partially apply without losing the associated metadata (author,
4045 date, description, ...). Note that when none of the hunk applies
4045 date, description, ...). Note that when none of the hunk applies
4046 cleanly, :hg:`import --partial` will create an empty changeset,
4046 cleanly, :hg:`import --partial` will create an empty changeset,
4047 importing only the patch metadata.
4047 importing only the patch metadata.
4048
4048
4049 To read a patch from standard input, use "-" as the patch name. If
4049 To read a patch from standard input, use "-" as the patch name. If
4050 a URL is specified, the patch will be downloaded from it.
4050 a URL is specified, the patch will be downloaded from it.
4051 See :hg:`help dates` for a list of formats valid for -d/--date.
4051 See :hg:`help dates` for a list of formats valid for -d/--date.
4052
4052
4053 .. container:: verbose
4053 .. container:: verbose
4054
4054
4055 Examples:
4055 Examples:
4056
4056
4057 - import a traditional patch from a website and detect renames::
4057 - import a traditional patch from a website and detect renames::
4058
4058
4059 hg import -s 80 http://example.com/bugfix.patch
4059 hg import -s 80 http://example.com/bugfix.patch
4060
4060
4061 - import a changeset from an hgweb server::
4061 - import a changeset from an hgweb server::
4062
4062
4063 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4063 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4064
4064
4065 - import all the patches in an Unix-style mbox::
4065 - import all the patches in an Unix-style mbox::
4066
4066
4067 hg import incoming-patches.mbox
4067 hg import incoming-patches.mbox
4068
4068
4069 - attempt to exactly restore an exported changeset (not always
4069 - attempt to exactly restore an exported changeset (not always
4070 possible)::
4070 possible)::
4071
4071
4072 hg import --exact proposed-fix.patch
4072 hg import --exact proposed-fix.patch
4073
4073
4074 Returns 0 on success, 1 on partial success (see --partial).
4074 Returns 0 on success, 1 on partial success (see --partial).
4075 """
4075 """
4076
4076
4077 if not patch1:
4077 if not patch1:
4078 raise util.Abort(_('need at least one patch to import'))
4078 raise util.Abort(_('need at least one patch to import'))
4079
4079
4080 patches = (patch1,) + patches
4080 patches = (patch1,) + patches
4081
4081
4082 date = opts.get('date')
4082 date = opts.get('date')
4083 if date:
4083 if date:
4084 opts['date'] = util.parsedate(date)
4084 opts['date'] = util.parsedate(date)
4085
4085
4086 update = not opts.get('bypass')
4086 update = not opts.get('bypass')
4087 if not update and opts.get('no_commit'):
4087 if not update and opts.get('no_commit'):
4088 raise util.Abort(_('cannot use --no-commit with --bypass'))
4088 raise util.Abort(_('cannot use --no-commit with --bypass'))
4089 try:
4089 try:
4090 sim = float(opts.get('similarity') or 0)
4090 sim = float(opts.get('similarity') or 0)
4091 except ValueError:
4091 except ValueError:
4092 raise util.Abort(_('similarity must be a number'))
4092 raise util.Abort(_('similarity must be a number'))
4093 if sim < 0 or sim > 100:
4093 if sim < 0 or sim > 100:
4094 raise util.Abort(_('similarity must be between 0 and 100'))
4094 raise util.Abort(_('similarity must be between 0 and 100'))
4095 if sim and not update:
4095 if sim and not update:
4096 raise util.Abort(_('cannot use --similarity with --bypass'))
4096 raise util.Abort(_('cannot use --similarity with --bypass'))
4097 if opts.get('exact') and opts.get('edit'):
4097 if opts.get('exact') and opts.get('edit'):
4098 raise util.Abort(_('cannot use --exact with --edit'))
4098 raise util.Abort(_('cannot use --exact with --edit'))
4099
4099
4100 if update:
4100 if update:
4101 cmdutil.checkunfinished(repo)
4101 cmdutil.checkunfinished(repo)
4102 if (opts.get('exact') or not opts.get('force')) and update:
4102 if (opts.get('exact') or not opts.get('force')) and update:
4103 cmdutil.bailifchanged(repo)
4103 cmdutil.bailifchanged(repo)
4104
4104
4105 base = opts["base"]
4105 base = opts["base"]
4106 wlock = lock = tr = None
4106 wlock = lock = tr = None
4107 msgs = []
4107 msgs = []
4108 ret = 0
4108 ret = 0
4109
4109
4110
4110
4111 try:
4111 try:
4112 try:
4112 try:
4113 wlock = repo.wlock()
4113 wlock = repo.wlock()
4114 repo.dirstate.beginparentchange()
4114 repo.dirstate.beginparentchange()
4115 if not opts.get('no_commit'):
4115 if not opts.get('no_commit'):
4116 lock = repo.lock()
4116 lock = repo.lock()
4117 tr = repo.transaction('import')
4117 tr = repo.transaction('import')
4118 parents = repo.parents()
4118 parents = repo.parents()
4119 for patchurl in patches:
4119 for patchurl in patches:
4120 if patchurl == '-':
4120 if patchurl == '-':
4121 ui.status(_('applying patch from stdin\n'))
4121 ui.status(_('applying patch from stdin\n'))
4122 patchfile = ui.fin
4122 patchfile = ui.fin
4123 patchurl = 'stdin' # for error message
4123 patchurl = 'stdin' # for error message
4124 else:
4124 else:
4125 patchurl = os.path.join(base, patchurl)
4125 patchurl = os.path.join(base, patchurl)
4126 ui.status(_('applying %s\n') % patchurl)
4126 ui.status(_('applying %s\n') % patchurl)
4127 patchfile = hg.openpath(ui, patchurl)
4127 patchfile = hg.openpath(ui, patchurl)
4128
4128
4129 haspatch = False
4129 haspatch = False
4130 for hunk in patch.split(patchfile):
4130 for hunk in patch.split(patchfile):
4131 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4131 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4132 parents, opts,
4132 parents, opts,
4133 msgs, hg.clean)
4133 msgs, hg.clean)
4134 if msg:
4134 if msg:
4135 haspatch = True
4135 haspatch = True
4136 ui.note(msg + '\n')
4136 ui.note(msg + '\n')
4137 if update or opts.get('exact'):
4137 if update or opts.get('exact'):
4138 parents = repo.parents()
4138 parents = repo.parents()
4139 else:
4139 else:
4140 parents = [repo[node]]
4140 parents = [repo[node]]
4141 if rej:
4141 if rej:
4142 ui.write_err(_("patch applied partially\n"))
4142 ui.write_err(_("patch applied partially\n"))
4143 ui.write_err(_("(fix the .rej files and run "
4143 ui.write_err(_("(fix the .rej files and run "
4144 "`hg commit --amend`)\n"))
4144 "`hg commit --amend`)\n"))
4145 ret = 1
4145 ret = 1
4146 break
4146 break
4147
4147
4148 if not haspatch:
4148 if not haspatch:
4149 raise util.Abort(_('%s: no diffs found') % patchurl)
4149 raise util.Abort(_('%s: no diffs found') % patchurl)
4150
4150
4151 if tr:
4151 if tr:
4152 tr.close()
4152 tr.close()
4153 if msgs:
4153 if msgs:
4154 repo.savecommitmessage('\n* * *\n'.join(msgs))
4154 repo.savecommitmessage('\n* * *\n'.join(msgs))
4155 repo.dirstate.endparentchange()
4155 repo.dirstate.endparentchange()
4156 return ret
4156 return ret
4157 except: # re-raises
4157 except: # re-raises
4158 # wlock.release() indirectly calls dirstate.write(): since
4158 # wlock.release() indirectly calls dirstate.write(): since
4159 # we're crashing, we do not want to change the working dir
4159 # we're crashing, we do not want to change the working dir
4160 # parent after all, so make sure it writes nothing
4160 # parent after all, so make sure it writes nothing
4161 repo.dirstate.invalidate()
4161 repo.dirstate.invalidate()
4162 raise
4162 raise
4163 finally:
4163 finally:
4164 if tr:
4164 if tr:
4165 tr.release()
4165 tr.release()
4166 release(lock, wlock)
4166 release(lock, wlock)
4167
4167
4168 @command('incoming|in',
4168 @command('incoming|in',
4169 [('f', 'force', None,
4169 [('f', 'force', None,
4170 _('run even if remote repository is unrelated')),
4170 _('run even if remote repository is unrelated')),
4171 ('n', 'newest-first', None, _('show newest record first')),
4171 ('n', 'newest-first', None, _('show newest record first')),
4172 ('', 'bundle', '',
4172 ('', 'bundle', '',
4173 _('file to store the bundles into'), _('FILE')),
4173 _('file to store the bundles into'), _('FILE')),
4174 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4174 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4175 ('B', 'bookmarks', False, _("compare bookmarks")),
4175 ('B', 'bookmarks', False, _("compare bookmarks")),
4176 ('b', 'branch', [],
4176 ('b', 'branch', [],
4177 _('a specific branch you would like to pull'), _('BRANCH')),
4177 _('a specific branch you would like to pull'), _('BRANCH')),
4178 ] + logopts + remoteopts + subrepoopts,
4178 ] + logopts + remoteopts + subrepoopts,
4179 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4179 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4180 def incoming(ui, repo, source="default", **opts):
4180 def incoming(ui, repo, source="default", **opts):
4181 """show new changesets found in source
4181 """show new changesets found in source
4182
4182
4183 Show new changesets found in the specified path/URL or the default
4183 Show new changesets found in the specified path/URL or the default
4184 pull location. These are the changesets that would have been pulled
4184 pull location. These are the changesets that would have been pulled
4185 if a pull at the time you issued this command.
4185 if a pull at the time you issued this command.
4186
4186
4187 For remote repository, using --bundle avoids downloading the
4187 For remote repository, using --bundle avoids downloading the
4188 changesets twice if the incoming is followed by a pull.
4188 changesets twice if the incoming is followed by a pull.
4189
4189
4190 See pull for valid source format details.
4190 See pull for valid source format details.
4191
4191
4192 .. container:: verbose
4192 .. container:: verbose
4193
4193
4194 Examples:
4194 Examples:
4195
4195
4196 - show incoming changes with patches and full description::
4196 - show incoming changes with patches and full description::
4197
4197
4198 hg incoming -vp
4198 hg incoming -vp
4199
4199
4200 - show incoming changes excluding merges, store a bundle::
4200 - show incoming changes excluding merges, store a bundle::
4201
4201
4202 hg in -vpM --bundle incoming.hg
4202 hg in -vpM --bundle incoming.hg
4203 hg pull incoming.hg
4203 hg pull incoming.hg
4204
4204
4205 - briefly list changes inside a bundle::
4205 - briefly list changes inside a bundle::
4206
4206
4207 hg in changes.hg -T "{desc|firstline}\\n"
4207 hg in changes.hg -T "{desc|firstline}\\n"
4208
4208
4209 Returns 0 if there are incoming changes, 1 otherwise.
4209 Returns 0 if there are incoming changes, 1 otherwise.
4210 """
4210 """
4211 if opts.get('graph'):
4211 if opts.get('graph'):
4212 cmdutil.checkunsupportedgraphflags([], opts)
4212 cmdutil.checkunsupportedgraphflags([], opts)
4213 def display(other, chlist, displayer):
4213 def display(other, chlist, displayer):
4214 revdag = cmdutil.graphrevs(other, chlist, opts)
4214 revdag = cmdutil.graphrevs(other, chlist, opts)
4215 showparents = [ctx.node() for ctx in repo[None].parents()]
4215 showparents = [ctx.node() for ctx in repo[None].parents()]
4216 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4216 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4217 graphmod.asciiedges)
4217 graphmod.asciiedges)
4218
4218
4219 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4219 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4220 return 0
4220 return 0
4221
4221
4222 if opts.get('bundle') and opts.get('subrepos'):
4222 if opts.get('bundle') and opts.get('subrepos'):
4223 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4223 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4224
4224
4225 if opts.get('bookmarks'):
4225 if opts.get('bookmarks'):
4226 source, branches = hg.parseurl(ui.expandpath(source),
4226 source, branches = hg.parseurl(ui.expandpath(source),
4227 opts.get('branch'))
4227 opts.get('branch'))
4228 other = hg.peer(repo, opts, source)
4228 other = hg.peer(repo, opts, source)
4229 if 'bookmarks' not in other.listkeys('namespaces'):
4229 if 'bookmarks' not in other.listkeys('namespaces'):
4230 ui.warn(_("remote doesn't support bookmarks\n"))
4230 ui.warn(_("remote doesn't support bookmarks\n"))
4231 return 0
4231 return 0
4232 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4232 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4233 return bookmarks.diff(ui, repo, other)
4233 return bookmarks.diff(ui, repo, other)
4234
4234
4235 repo._subtoppath = ui.expandpath(source)
4235 repo._subtoppath = ui.expandpath(source)
4236 try:
4236 try:
4237 return hg.incoming(ui, repo, source, opts)
4237 return hg.incoming(ui, repo, source, opts)
4238 finally:
4238 finally:
4239 del repo._subtoppath
4239 del repo._subtoppath
4240
4240
4241
4241
4242 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4242 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4243 norepo=True)
4243 norepo=True)
4244 def init(ui, dest=".", **opts):
4244 def init(ui, dest=".", **opts):
4245 """create a new repository in the given directory
4245 """create a new repository in the given directory
4246
4246
4247 Initialize a new repository in the given directory. If the given
4247 Initialize a new repository in the given directory. If the given
4248 directory does not exist, it will be created.
4248 directory does not exist, it will be created.
4249
4249
4250 If no directory is given, the current directory is used.
4250 If no directory is given, the current directory is used.
4251
4251
4252 It is possible to specify an ``ssh://`` URL as the destination.
4252 It is possible to specify an ``ssh://`` URL as the destination.
4253 See :hg:`help urls` for more information.
4253 See :hg:`help urls` for more information.
4254
4254
4255 Returns 0 on success.
4255 Returns 0 on success.
4256 """
4256 """
4257 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4257 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4258
4258
4259 @command('locate',
4259 @command('locate',
4260 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4260 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4261 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4261 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4262 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4262 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4263 ] + walkopts,
4263 ] + walkopts,
4264 _('[OPTION]... [PATTERN]...'))
4264 _('[OPTION]... [PATTERN]...'))
4265 def locate(ui, repo, *pats, **opts):
4265 def locate(ui, repo, *pats, **opts):
4266 """locate files matching specific patterns (DEPRECATED)
4266 """locate files matching specific patterns (DEPRECATED)
4267
4267
4268 Print files under Mercurial control in the working directory whose
4268 Print files under Mercurial control in the working directory whose
4269 names match the given patterns.
4269 names match the given patterns.
4270
4270
4271 By default, this command searches all directories in the working
4271 By default, this command searches all directories in the working
4272 directory. To search just the current directory and its
4272 directory. To search just the current directory and its
4273 subdirectories, use "--include .".
4273 subdirectories, use "--include .".
4274
4274
4275 If no patterns are given to match, this command prints the names
4275 If no patterns are given to match, this command prints the names
4276 of all files under Mercurial control in the working directory.
4276 of all files under Mercurial control in the working directory.
4277
4277
4278 If you want to feed the output of this command into the "xargs"
4278 If you want to feed the output of this command into the "xargs"
4279 command, use the -0 option to both this command and "xargs". This
4279 command, use the -0 option to both this command and "xargs". This
4280 will avoid the problem of "xargs" treating single filenames that
4280 will avoid the problem of "xargs" treating single filenames that
4281 contain whitespace as multiple filenames.
4281 contain whitespace as multiple filenames.
4282
4282
4283 See :hg:`help files` for a more versatile command.
4283 See :hg:`help files` for a more versatile command.
4284
4284
4285 Returns 0 if a match is found, 1 otherwise.
4285 Returns 0 if a match is found, 1 otherwise.
4286 """
4286 """
4287 end = opts.get('print0') and '\0' or '\n'
4287 end = opts.get('print0') and '\0' or '\n'
4288 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4288 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4289
4289
4290 ret = 1
4290 ret = 1
4291 ctx = repo[rev]
4291 ctx = repo[rev]
4292 m = scmutil.match(ctx, pats, opts, default='relglob')
4292 m = scmutil.match(ctx, pats, opts, default='relglob')
4293 m.bad = lambda x, y: False
4293 m.bad = lambda x, y: False
4294
4294
4295 for abs in ctx.matches(m):
4295 for abs in ctx.matches(m):
4296 if opts.get('fullpath'):
4296 if opts.get('fullpath'):
4297 ui.write(repo.wjoin(abs), end)
4297 ui.write(repo.wjoin(abs), end)
4298 else:
4298 else:
4299 ui.write(((pats and m.rel(abs)) or abs), end)
4299 ui.write(((pats and m.rel(abs)) or abs), end)
4300 ret = 0
4300 ret = 0
4301
4301
4302 return ret
4302 return ret
4303
4303
4304 @command('^log|history',
4304 @command('^log|history',
4305 [('f', 'follow', None,
4305 [('f', 'follow', None,
4306 _('follow changeset history, or file history across copies and renames')),
4306 _('follow changeset history, or file history across copies and renames')),
4307 ('', 'follow-first', None,
4307 ('', 'follow-first', None,
4308 _('only follow the first parent of merge changesets (DEPRECATED)')),
4308 _('only follow the first parent of merge changesets (DEPRECATED)')),
4309 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4309 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4310 ('C', 'copies', None, _('show copied files')),
4310 ('C', 'copies', None, _('show copied files')),
4311 ('k', 'keyword', [],
4311 ('k', 'keyword', [],
4312 _('do case-insensitive search for a given text'), _('TEXT')),
4312 _('do case-insensitive search for a given text'), _('TEXT')),
4313 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4313 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4314 ('', 'removed', None, _('include revisions where files were removed')),
4314 ('', 'removed', None, _('include revisions where files were removed')),
4315 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4315 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4316 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4316 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4317 ('', 'only-branch', [],
4317 ('', 'only-branch', [],
4318 _('show only changesets within the given named branch (DEPRECATED)'),
4318 _('show only changesets within the given named branch (DEPRECATED)'),
4319 _('BRANCH')),
4319 _('BRANCH')),
4320 ('b', 'branch', [],
4320 ('b', 'branch', [],
4321 _('show changesets within the given named branch'), _('BRANCH')),
4321 _('show changesets within the given named branch'), _('BRANCH')),
4322 ('P', 'prune', [],
4322 ('P', 'prune', [],
4323 _('do not display revision or any of its ancestors'), _('REV')),
4323 _('do not display revision or any of its ancestors'), _('REV')),
4324 ] + logopts + walkopts,
4324 ] + logopts + walkopts,
4325 _('[OPTION]... [FILE]'),
4325 _('[OPTION]... [FILE]'),
4326 inferrepo=True)
4326 inferrepo=True)
4327 def log(ui, repo, *pats, **opts):
4327 def log(ui, repo, *pats, **opts):
4328 """show revision history of entire repository or files
4328 """show revision history of entire repository or files
4329
4329
4330 Print the revision history of the specified files or the entire
4330 Print the revision history of the specified files or the entire
4331 project.
4331 project.
4332
4332
4333 If no revision range is specified, the default is ``tip:0`` unless
4333 If no revision range is specified, the default is ``tip:0`` unless
4334 --follow is set, in which case the working directory parent is
4334 --follow is set, in which case the working directory parent is
4335 used as the starting revision.
4335 used as the starting revision.
4336
4336
4337 File history is shown without following rename or copy history of
4337 File history is shown without following rename or copy history of
4338 files. Use -f/--follow with a filename to follow history across
4338 files. Use -f/--follow with a filename to follow history across
4339 renames and copies. --follow without a filename will only show
4339 renames and copies. --follow without a filename will only show
4340 ancestors or descendants of the starting revision.
4340 ancestors or descendants of the starting revision.
4341
4341
4342 By default this command prints revision number and changeset id,
4342 By default this command prints revision number and changeset id,
4343 tags, non-trivial parents, user, date and time, and a summary for
4343 tags, non-trivial parents, user, date and time, and a summary for
4344 each commit. When the -v/--verbose switch is used, the list of
4344 each commit. When the -v/--verbose switch is used, the list of
4345 changed files and full commit message are shown.
4345 changed files and full commit message are shown.
4346
4346
4347 With --graph the revisions are shown as an ASCII art DAG with the most
4347 With --graph the revisions are shown as an ASCII art DAG with the most
4348 recent changeset at the top.
4348 recent changeset at the top.
4349 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4349 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4350 and '+' represents a fork where the changeset from the lines below is a
4350 and '+' represents a fork where the changeset from the lines below is a
4351 parent of the 'o' merge on the same line.
4351 parent of the 'o' merge on the same line.
4352
4352
4353 .. note::
4353 .. note::
4354
4354
4355 log -p/--patch may generate unexpected diff output for merge
4355 log -p/--patch may generate unexpected diff output for merge
4356 changesets, as it will only compare the merge changeset against
4356 changesets, as it will only compare the merge changeset against
4357 its first parent. Also, only files different from BOTH parents
4357 its first parent. Also, only files different from BOTH parents
4358 will appear in files:.
4358 will appear in files:.
4359
4359
4360 .. note::
4360 .. note::
4361
4361
4362 for performance reasons, log FILE may omit duplicate changes
4362 for performance reasons, log FILE may omit duplicate changes
4363 made on branches and will not show removals or mode changes. To
4363 made on branches and will not show removals or mode changes. To
4364 see all such changes, use the --removed switch.
4364 see all such changes, use the --removed switch.
4365
4365
4366 .. container:: verbose
4366 .. container:: verbose
4367
4367
4368 Some examples:
4368 Some examples:
4369
4369
4370 - changesets with full descriptions and file lists::
4370 - changesets with full descriptions and file lists::
4371
4371
4372 hg log -v
4372 hg log -v
4373
4373
4374 - changesets ancestral to the working directory::
4374 - changesets ancestral to the working directory::
4375
4375
4376 hg log -f
4376 hg log -f
4377
4377
4378 - last 10 commits on the current branch::
4378 - last 10 commits on the current branch::
4379
4379
4380 hg log -l 10 -b .
4380 hg log -l 10 -b .
4381
4381
4382 - changesets showing all modifications of a file, including removals::
4382 - changesets showing all modifications of a file, including removals::
4383
4383
4384 hg log --removed file.c
4384 hg log --removed file.c
4385
4385
4386 - all changesets that touch a directory, with diffs, excluding merges::
4386 - all changesets that touch a directory, with diffs, excluding merges::
4387
4387
4388 hg log -Mp lib/
4388 hg log -Mp lib/
4389
4389
4390 - all revision numbers that match a keyword::
4390 - all revision numbers that match a keyword::
4391
4391
4392 hg log -k bug --template "{rev}\\n"
4392 hg log -k bug --template "{rev}\\n"
4393
4393
4394 - list available log templates::
4394 - list available log templates::
4395
4395
4396 hg log -T list
4396 hg log -T list
4397
4397
4398 - check if a given changeset is included in a tagged release::
4398 - check if a given changeset is included in a tagged release::
4399
4399
4400 hg log -r "a21ccf and ancestor(1.9)"
4400 hg log -r "a21ccf and ancestor(1.9)"
4401
4401
4402 - find all changesets by some user in a date range::
4402 - find all changesets by some user in a date range::
4403
4403
4404 hg log -k alice -d "may 2008 to jul 2008"
4404 hg log -k alice -d "may 2008 to jul 2008"
4405
4405
4406 - summary of all changesets after the last tag::
4406 - summary of all changesets after the last tag::
4407
4407
4408 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4408 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4409
4409
4410 See :hg:`help dates` for a list of formats valid for -d/--date.
4410 See :hg:`help dates` for a list of formats valid for -d/--date.
4411
4411
4412 See :hg:`help revisions` and :hg:`help revsets` for more about
4412 See :hg:`help revisions` and :hg:`help revsets` for more about
4413 specifying revisions.
4413 specifying revisions.
4414
4414
4415 See :hg:`help templates` for more about pre-packaged styles and
4415 See :hg:`help templates` for more about pre-packaged styles and
4416 specifying custom templates.
4416 specifying custom templates.
4417
4417
4418 Returns 0 on success.
4418 Returns 0 on success.
4419
4419
4420 """
4420 """
4421 if opts.get('graph'):
4421 if opts.get('graph'):
4422 return cmdutil.graphlog(ui, repo, *pats, **opts)
4422 return cmdutil.graphlog(ui, repo, *pats, **opts)
4423
4423
4424 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4424 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4425 limit = cmdutil.loglimit(opts)
4425 limit = cmdutil.loglimit(opts)
4426 count = 0
4426 count = 0
4427
4427
4428 getrenamed = None
4428 getrenamed = None
4429 if opts.get('copies'):
4429 if opts.get('copies'):
4430 endrev = None
4430 endrev = None
4431 if opts.get('rev'):
4431 if opts.get('rev'):
4432 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4432 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4433 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4433 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4434
4434
4435 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4435 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4436 for rev in revs:
4436 for rev in revs:
4437 if count == limit:
4437 if count == limit:
4438 break
4438 break
4439 ctx = repo[rev]
4439 ctx = repo[rev]
4440 copies = None
4440 copies = None
4441 if getrenamed is not None and rev:
4441 if getrenamed is not None and rev:
4442 copies = []
4442 copies = []
4443 for fn in ctx.files():
4443 for fn in ctx.files():
4444 rename = getrenamed(fn, rev)
4444 rename = getrenamed(fn, rev)
4445 if rename:
4445 if rename:
4446 copies.append((fn, rename[0]))
4446 copies.append((fn, rename[0]))
4447 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4447 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4448 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4448 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4449 if displayer.flush(rev):
4449 if displayer.flush(rev):
4450 count += 1
4450 count += 1
4451
4451
4452 displayer.close()
4452 displayer.close()
4453
4453
4454 @command('manifest',
4454 @command('manifest',
4455 [('r', 'rev', '', _('revision to display'), _('REV')),
4455 [('r', 'rev', '', _('revision to display'), _('REV')),
4456 ('', 'all', False, _("list files from all revisions"))]
4456 ('', 'all', False, _("list files from all revisions"))]
4457 + formatteropts,
4457 + formatteropts,
4458 _('[-r REV]'))
4458 _('[-r REV]'))
4459 def manifest(ui, repo, node=None, rev=None, **opts):
4459 def manifest(ui, repo, node=None, rev=None, **opts):
4460 """output the current or given revision of the project manifest
4460 """output the current or given revision of the project manifest
4461
4461
4462 Print a list of version controlled files for the given revision.
4462 Print a list of version controlled files for the given revision.
4463 If no revision is given, the first parent of the working directory
4463 If no revision is given, the first parent of the working directory
4464 is used, or the null revision if no revision is checked out.
4464 is used, or the null revision if no revision is checked out.
4465
4465
4466 With -v, print file permissions, symlink and executable bits.
4466 With -v, print file permissions, symlink and executable bits.
4467 With --debug, print file revision hashes.
4467 With --debug, print file revision hashes.
4468
4468
4469 If option --all is specified, the list of all files from all revisions
4469 If option --all is specified, the list of all files from all revisions
4470 is printed. This includes deleted and renamed files.
4470 is printed. This includes deleted and renamed files.
4471
4471
4472 Returns 0 on success.
4472 Returns 0 on success.
4473 """
4473 """
4474
4474
4475 fm = ui.formatter('manifest', opts)
4475 fm = ui.formatter('manifest', opts)
4476
4476
4477 if opts.get('all'):
4477 if opts.get('all'):
4478 if rev or node:
4478 if rev or node:
4479 raise util.Abort(_("can't specify a revision with --all"))
4479 raise util.Abort(_("can't specify a revision with --all"))
4480
4480
4481 res = []
4481 res = []
4482 prefix = "data/"
4482 prefix = "data/"
4483 suffix = ".i"
4483 suffix = ".i"
4484 plen = len(prefix)
4484 plen = len(prefix)
4485 slen = len(suffix)
4485 slen = len(suffix)
4486 lock = repo.lock()
4486 lock = repo.lock()
4487 try:
4487 try:
4488 for fn, b, size in repo.store.datafiles():
4488 for fn, b, size in repo.store.datafiles():
4489 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4489 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4490 res.append(fn[plen:-slen])
4490 res.append(fn[plen:-slen])
4491 finally:
4491 finally:
4492 lock.release()
4492 lock.release()
4493 for f in res:
4493 for f in res:
4494 fm.startitem()
4494 fm.startitem()
4495 fm.write("path", '%s\n', f)
4495 fm.write("path", '%s\n', f)
4496 fm.end()
4496 fm.end()
4497 return
4497 return
4498
4498
4499 if rev and node:
4499 if rev and node:
4500 raise util.Abort(_("please specify just one revision"))
4500 raise util.Abort(_("please specify just one revision"))
4501
4501
4502 if not node:
4502 if not node:
4503 node = rev
4503 node = rev
4504
4504
4505 char = {'l': '@', 'x': '*', '': ''}
4505 char = {'l': '@', 'x': '*', '': ''}
4506 mode = {'l': '644', 'x': '755', '': '644'}
4506 mode = {'l': '644', 'x': '755', '': '644'}
4507 ctx = scmutil.revsingle(repo, node)
4507 ctx = scmutil.revsingle(repo, node)
4508 mf = ctx.manifest()
4508 mf = ctx.manifest()
4509 for f in ctx:
4509 for f in ctx:
4510 fm.startitem()
4510 fm.startitem()
4511 fl = ctx[f].flags()
4511 fl = ctx[f].flags()
4512 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4512 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4513 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4513 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4514 fm.write('path', '%s\n', f)
4514 fm.write('path', '%s\n', f)
4515 fm.end()
4515 fm.end()
4516
4516
4517 @command('^merge',
4517 @command('^merge',
4518 [('f', 'force', None,
4518 [('f', 'force', None,
4519 _('force a merge including outstanding changes (DEPRECATED)')),
4519 _('force a merge including outstanding changes (DEPRECATED)')),
4520 ('r', 'rev', '', _('revision to merge'), _('REV')),
4520 ('r', 'rev', '', _('revision to merge'), _('REV')),
4521 ('P', 'preview', None,
4521 ('P', 'preview', None,
4522 _('review revisions to merge (no merge is performed)'))
4522 _('review revisions to merge (no merge is performed)'))
4523 ] + mergetoolopts,
4523 ] + mergetoolopts,
4524 _('[-P] [-f] [[-r] REV]'))
4524 _('[-P] [-f] [[-r] REV]'))
4525 def merge(ui, repo, node=None, **opts):
4525 def merge(ui, repo, node=None, **opts):
4526 """merge working directory with another revision
4526 """merge working directory with another revision
4527
4527
4528 The current working directory is updated with all changes made in
4528 The current working directory is updated with all changes made in
4529 the requested revision since the last common predecessor revision.
4529 the requested revision since the last common predecessor revision.
4530
4530
4531 Files that changed between either parent are marked as changed for
4531 Files that changed between either parent are marked as changed for
4532 the next commit and a commit must be performed before any further
4532 the next commit and a commit must be performed before any further
4533 updates to the repository are allowed. The next commit will have
4533 updates to the repository are allowed. The next commit will have
4534 two parents.
4534 two parents.
4535
4535
4536 ``--tool`` can be used to specify the merge tool used for file
4536 ``--tool`` can be used to specify the merge tool used for file
4537 merges. It overrides the HGMERGE environment variable and your
4537 merges. It overrides the HGMERGE environment variable and your
4538 configuration files. See :hg:`help merge-tools` for options.
4538 configuration files. See :hg:`help merge-tools` for options.
4539
4539
4540 If no revision is specified, the working directory's parent is a
4540 If no revision is specified, the working directory's parent is a
4541 head revision, and the current branch contains exactly one other
4541 head revision, and the current branch contains exactly one other
4542 head, the other head is merged with by default. Otherwise, an
4542 head, the other head is merged with by default. Otherwise, an
4543 explicit revision with which to merge with must be provided.
4543 explicit revision with which to merge with must be provided.
4544
4544
4545 :hg:`resolve` must be used to resolve unresolved files.
4545 :hg:`resolve` must be used to resolve unresolved files.
4546
4546
4547 To undo an uncommitted merge, use :hg:`update --clean .` which
4547 To undo an uncommitted merge, use :hg:`update --clean .` which
4548 will check out a clean copy of the original merge parent, losing
4548 will check out a clean copy of the original merge parent, losing
4549 all changes.
4549 all changes.
4550
4550
4551 Returns 0 on success, 1 if there are unresolved files.
4551 Returns 0 on success, 1 if there are unresolved files.
4552 """
4552 """
4553
4553
4554 if opts.get('rev') and node:
4554 if opts.get('rev') and node:
4555 raise util.Abort(_("please specify just one revision"))
4555 raise util.Abort(_("please specify just one revision"))
4556 if not node:
4556 if not node:
4557 node = opts.get('rev')
4557 node = opts.get('rev')
4558
4558
4559 if node:
4559 if node:
4560 node = scmutil.revsingle(repo, node).node()
4560 node = scmutil.revsingle(repo, node).node()
4561
4561
4562 if not node and repo._bookmarkcurrent:
4562 if not node and repo._bookmarkcurrent:
4563 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4563 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4564 curhead = repo[repo._bookmarkcurrent].node()
4564 curhead = repo[repo._bookmarkcurrent].node()
4565 if len(bmheads) == 2:
4565 if len(bmheads) == 2:
4566 if curhead == bmheads[0]:
4566 if curhead == bmheads[0]:
4567 node = bmheads[1]
4567 node = bmheads[1]
4568 else:
4568 else:
4569 node = bmheads[0]
4569 node = bmheads[0]
4570 elif len(bmheads) > 2:
4570 elif len(bmheads) > 2:
4571 raise util.Abort(_("multiple matching bookmarks to merge - "
4571 raise util.Abort(_("multiple matching bookmarks to merge - "
4572 "please merge with an explicit rev or bookmark"),
4572 "please merge with an explicit rev or bookmark"),
4573 hint=_("run 'hg heads' to see all heads"))
4573 hint=_("run 'hg heads' to see all heads"))
4574 elif len(bmheads) <= 1:
4574 elif len(bmheads) <= 1:
4575 raise util.Abort(_("no matching bookmark to merge - "
4575 raise util.Abort(_("no matching bookmark to merge - "
4576 "please merge with an explicit rev or bookmark"),
4576 "please merge with an explicit rev or bookmark"),
4577 hint=_("run 'hg heads' to see all heads"))
4577 hint=_("run 'hg heads' to see all heads"))
4578
4578
4579 if not node and not repo._bookmarkcurrent:
4579 if not node and not repo._bookmarkcurrent:
4580 branch = repo[None].branch()
4580 branch = repo[None].branch()
4581 bheads = repo.branchheads(branch)
4581 bheads = repo.branchheads(branch)
4582 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4582 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4583
4583
4584 if len(nbhs) > 2:
4584 if len(nbhs) > 2:
4585 raise util.Abort(_("branch '%s' has %d heads - "
4585 raise util.Abort(_("branch '%s' has %d heads - "
4586 "please merge with an explicit rev")
4586 "please merge with an explicit rev")
4587 % (branch, len(bheads)),
4587 % (branch, len(bheads)),
4588 hint=_("run 'hg heads .' to see heads"))
4588 hint=_("run 'hg heads .' to see heads"))
4589
4589
4590 parent = repo.dirstate.p1()
4590 parent = repo.dirstate.p1()
4591 if len(nbhs) <= 1:
4591 if len(nbhs) <= 1:
4592 if len(bheads) > 1:
4592 if len(bheads) > 1:
4593 raise util.Abort(_("heads are bookmarked - "
4593 raise util.Abort(_("heads are bookmarked - "
4594 "please merge with an explicit rev"),
4594 "please merge with an explicit rev"),
4595 hint=_("run 'hg heads' to see all heads"))
4595 hint=_("run 'hg heads' to see all heads"))
4596 if len(repo.heads()) > 1:
4596 if len(repo.heads()) > 1:
4597 raise util.Abort(_("branch '%s' has one head - "
4597 raise util.Abort(_("branch '%s' has one head - "
4598 "please merge with an explicit rev")
4598 "please merge with an explicit rev")
4599 % branch,
4599 % branch,
4600 hint=_("run 'hg heads' to see all heads"))
4600 hint=_("run 'hg heads' to see all heads"))
4601 msg, hint = _('nothing to merge'), None
4601 msg, hint = _('nothing to merge'), None
4602 if parent != repo.lookup(branch):
4602 if parent != repo.lookup(branch):
4603 hint = _("use 'hg update' instead")
4603 hint = _("use 'hg update' instead")
4604 raise util.Abort(msg, hint=hint)
4604 raise util.Abort(msg, hint=hint)
4605
4605
4606 if parent not in bheads:
4606 if parent not in bheads:
4607 raise util.Abort(_('working directory not at a head revision'),
4607 raise util.Abort(_('working directory not at a head revision'),
4608 hint=_("use 'hg update' or merge with an "
4608 hint=_("use 'hg update' or merge with an "
4609 "explicit revision"))
4609 "explicit revision"))
4610 if parent == nbhs[0]:
4610 if parent == nbhs[0]:
4611 node = nbhs[-1]
4611 node = nbhs[-1]
4612 else:
4612 else:
4613 node = nbhs[0]
4613 node = nbhs[0]
4614
4614
4615 if opts.get('preview'):
4615 if opts.get('preview'):
4616 # find nodes that are ancestors of p2 but not of p1
4616 # find nodes that are ancestors of p2 but not of p1
4617 p1 = repo.lookup('.')
4617 p1 = repo.lookup('.')
4618 p2 = repo.lookup(node)
4618 p2 = repo.lookup(node)
4619 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4619 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4620
4620
4621 displayer = cmdutil.show_changeset(ui, repo, opts)
4621 displayer = cmdutil.show_changeset(ui, repo, opts)
4622 for node in nodes:
4622 for node in nodes:
4623 displayer.show(repo[node])
4623 displayer.show(repo[node])
4624 displayer.close()
4624 displayer.close()
4625 return 0
4625 return 0
4626
4626
4627 try:
4627 try:
4628 # ui.forcemerge is an internal variable, do not document
4628 # ui.forcemerge is an internal variable, do not document
4629 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4629 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4630 return hg.merge(repo, node, force=opts.get('force'))
4630 return hg.merge(repo, node, force=opts.get('force'))
4631 finally:
4631 finally:
4632 ui.setconfig('ui', 'forcemerge', '', 'merge')
4632 ui.setconfig('ui', 'forcemerge', '', 'merge')
4633
4633
4634 @command('outgoing|out',
4634 @command('outgoing|out',
4635 [('f', 'force', None, _('run even when the destination is unrelated')),
4635 [('f', 'force', None, _('run even when the destination is unrelated')),
4636 ('r', 'rev', [],
4636 ('r', 'rev', [],
4637 _('a changeset intended to be included in the destination'), _('REV')),
4637 _('a changeset intended to be included in the destination'), _('REV')),
4638 ('n', 'newest-first', None, _('show newest record first')),
4638 ('n', 'newest-first', None, _('show newest record first')),
4639 ('B', 'bookmarks', False, _('compare bookmarks')),
4639 ('B', 'bookmarks', False, _('compare bookmarks')),
4640 ('b', 'branch', [], _('a specific branch you would like to push'),
4640 ('b', 'branch', [], _('a specific branch you would like to push'),
4641 _('BRANCH')),
4641 _('BRANCH')),
4642 ] + logopts + remoteopts + subrepoopts,
4642 ] + logopts + remoteopts + subrepoopts,
4643 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4643 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4644 def outgoing(ui, repo, dest=None, **opts):
4644 def outgoing(ui, repo, dest=None, **opts):
4645 """show changesets not found in the destination
4645 """show changesets not found in the destination
4646
4646
4647 Show changesets not found in the specified destination repository
4647 Show changesets not found in the specified destination repository
4648 or the default push location. These are the changesets that would
4648 or the default push location. These are the changesets that would
4649 be pushed if a push was requested.
4649 be pushed if a push was requested.
4650
4650
4651 See pull for details of valid destination formats.
4651 See pull for details of valid destination formats.
4652
4652
4653 Returns 0 if there are outgoing changes, 1 otherwise.
4653 Returns 0 if there are outgoing changes, 1 otherwise.
4654 """
4654 """
4655 if opts.get('graph'):
4655 if opts.get('graph'):
4656 cmdutil.checkunsupportedgraphflags([], opts)
4656 cmdutil.checkunsupportedgraphflags([], opts)
4657 o, other = hg._outgoing(ui, repo, dest, opts)
4657 o, other = hg._outgoing(ui, repo, dest, opts)
4658 if not o:
4658 if not o:
4659 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4659 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4660 return
4660 return
4661
4661
4662 revdag = cmdutil.graphrevs(repo, o, opts)
4662 revdag = cmdutil.graphrevs(repo, o, opts)
4663 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4663 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4664 showparents = [ctx.node() for ctx in repo[None].parents()]
4664 showparents = [ctx.node() for ctx in repo[None].parents()]
4665 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4665 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4666 graphmod.asciiedges)
4666 graphmod.asciiedges)
4667 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4667 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4668 return 0
4668 return 0
4669
4669
4670 if opts.get('bookmarks'):
4670 if opts.get('bookmarks'):
4671 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4671 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4672 dest, branches = hg.parseurl(dest, opts.get('branch'))
4672 dest, branches = hg.parseurl(dest, opts.get('branch'))
4673 other = hg.peer(repo, opts, dest)
4673 other = hg.peer(repo, opts, dest)
4674 if 'bookmarks' not in other.listkeys('namespaces'):
4674 if 'bookmarks' not in other.listkeys('namespaces'):
4675 ui.warn(_("remote doesn't support bookmarks\n"))
4675 ui.warn(_("remote doesn't support bookmarks\n"))
4676 return 0
4676 return 0
4677 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4677 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4678 return bookmarks.diff(ui, other, repo)
4678 return bookmarks.diff(ui, other, repo)
4679
4679
4680 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4680 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4681 try:
4681 try:
4682 return hg.outgoing(ui, repo, dest, opts)
4682 return hg.outgoing(ui, repo, dest, opts)
4683 finally:
4683 finally:
4684 del repo._subtoppath
4684 del repo._subtoppath
4685
4685
4686 @command('parents',
4686 @command('parents',
4687 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4687 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4688 ] + templateopts,
4688 ] + templateopts,
4689 _('[-r REV] [FILE]'),
4689 _('[-r REV] [FILE]'),
4690 inferrepo=True)
4690 inferrepo=True)
4691 def parents(ui, repo, file_=None, **opts):
4691 def parents(ui, repo, file_=None, **opts):
4692 """show the parents of the working directory or revision (DEPRECATED)
4692 """show the parents of the working directory or revision (DEPRECATED)
4693
4693
4694 Print the working directory's parent revisions. If a revision is
4694 Print the working directory's parent revisions. If a revision is
4695 given via -r/--rev, the parent of that revision will be printed.
4695 given via -r/--rev, the parent of that revision will be printed.
4696 If a file argument is given, the revision in which the file was
4696 If a file argument is given, the revision in which the file was
4697 last changed (before the working directory revision or the
4697 last changed (before the working directory revision or the
4698 argument to --rev if given) is printed.
4698 argument to --rev if given) is printed.
4699
4699
4700 See :hg:`summary` and :hg:`help revsets` for related information.
4700 See :hg:`summary` and :hg:`help revsets` for related information.
4701
4701
4702 Returns 0 on success.
4702 Returns 0 on success.
4703 """
4703 """
4704
4704
4705 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4705 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4706
4706
4707 if file_:
4707 if file_:
4708 m = scmutil.match(ctx, (file_,), opts)
4708 m = scmutil.match(ctx, (file_,), opts)
4709 if m.anypats() or len(m.files()) != 1:
4709 if m.anypats() or len(m.files()) != 1:
4710 raise util.Abort(_('can only specify an explicit filename'))
4710 raise util.Abort(_('can only specify an explicit filename'))
4711 file_ = m.files()[0]
4711 file_ = m.files()[0]
4712 filenodes = []
4712 filenodes = []
4713 for cp in ctx.parents():
4713 for cp in ctx.parents():
4714 if not cp:
4714 if not cp:
4715 continue
4715 continue
4716 try:
4716 try:
4717 filenodes.append(cp.filenode(file_))
4717 filenodes.append(cp.filenode(file_))
4718 except error.LookupError:
4718 except error.LookupError:
4719 pass
4719 pass
4720 if not filenodes:
4720 if not filenodes:
4721 raise util.Abort(_("'%s' not found in manifest!") % file_)
4721 raise util.Abort(_("'%s' not found in manifest!") % file_)
4722 p = []
4722 p = []
4723 for fn in filenodes:
4723 for fn in filenodes:
4724 fctx = repo.filectx(file_, fileid=fn)
4724 fctx = repo.filectx(file_, fileid=fn)
4725 p.append(fctx.node())
4725 p.append(fctx.node())
4726 else:
4726 else:
4727 p = [cp.node() for cp in ctx.parents()]
4727 p = [cp.node() for cp in ctx.parents()]
4728
4728
4729 displayer = cmdutil.show_changeset(ui, repo, opts)
4729 displayer = cmdutil.show_changeset(ui, repo, opts)
4730 for n in p:
4730 for n in p:
4731 if n != nullid:
4731 if n != nullid:
4732 displayer.show(repo[n])
4732 displayer.show(repo[n])
4733 displayer.close()
4733 displayer.close()
4734
4734
4735 @command('paths', [], _('[NAME]'), optionalrepo=True)
4735 @command('paths', [], _('[NAME]'), optionalrepo=True)
4736 def paths(ui, repo, search=None):
4736 def paths(ui, repo, search=None):
4737 """show aliases for remote repositories
4737 """show aliases for remote repositories
4738
4738
4739 Show definition of symbolic path name NAME. If no name is given,
4739 Show definition of symbolic path name NAME. If no name is given,
4740 show definition of all available names.
4740 show definition of all available names.
4741
4741
4742 Option -q/--quiet suppresses all output when searching for NAME
4742 Option -q/--quiet suppresses all output when searching for NAME
4743 and shows only the path names when listing all definitions.
4743 and shows only the path names when listing all definitions.
4744
4744
4745 Path names are defined in the [paths] section of your
4745 Path names are defined in the [paths] section of your
4746 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4746 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4747 repository, ``.hg/hgrc`` is used, too.
4747 repository, ``.hg/hgrc`` is used, too.
4748
4748
4749 The path names ``default`` and ``default-push`` have a special
4749 The path names ``default`` and ``default-push`` have a special
4750 meaning. When performing a push or pull operation, they are used
4750 meaning. When performing a push or pull operation, they are used
4751 as fallbacks if no location is specified on the command-line.
4751 as fallbacks if no location is specified on the command-line.
4752 When ``default-push`` is set, it will be used for push and
4752 When ``default-push`` is set, it will be used for push and
4753 ``default`` will be used for pull; otherwise ``default`` is used
4753 ``default`` will be used for pull; otherwise ``default`` is used
4754 as the fallback for both. When cloning a repository, the clone
4754 as the fallback for both. When cloning a repository, the clone
4755 source is written as ``default`` in ``.hg/hgrc``. Note that
4755 source is written as ``default`` in ``.hg/hgrc``. Note that
4756 ``default`` and ``default-push`` apply to all inbound (e.g.
4756 ``default`` and ``default-push`` apply to all inbound (e.g.
4757 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4757 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4758 :hg:`bundle`) operations.
4758 :hg:`bundle`) operations.
4759
4759
4760 See :hg:`help urls` for more information.
4760 See :hg:`help urls` for more information.
4761
4761
4762 Returns 0 on success.
4762 Returns 0 on success.
4763 """
4763 """
4764 if search:
4764 if search:
4765 for name, path in ui.configitems("paths"):
4765 for name, path in ui.configitems("paths"):
4766 if name == search:
4766 if name == search:
4767 ui.status("%s\n" % util.hidepassword(path))
4767 ui.status("%s\n" % util.hidepassword(path))
4768 return
4768 return
4769 if not ui.quiet:
4769 if not ui.quiet:
4770 ui.warn(_("not found!\n"))
4770 ui.warn(_("not found!\n"))
4771 return 1
4771 return 1
4772 else:
4772 else:
4773 for name, path in ui.configitems("paths"):
4773 for name, path in ui.configitems("paths"):
4774 if ui.quiet:
4774 if ui.quiet:
4775 ui.write("%s\n" % name)
4775 ui.write("%s\n" % name)
4776 else:
4776 else:
4777 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4777 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4778
4778
4779 @command('phase',
4779 @command('phase',
4780 [('p', 'public', False, _('set changeset phase to public')),
4780 [('p', 'public', False, _('set changeset phase to public')),
4781 ('d', 'draft', False, _('set changeset phase to draft')),
4781 ('d', 'draft', False, _('set changeset phase to draft')),
4782 ('s', 'secret', False, _('set changeset phase to secret')),
4782 ('s', 'secret', False, _('set changeset phase to secret')),
4783 ('f', 'force', False, _('allow to move boundary backward')),
4783 ('f', 'force', False, _('allow to move boundary backward')),
4784 ('r', 'rev', [], _('target revision'), _('REV')),
4784 ('r', 'rev', [], _('target revision'), _('REV')),
4785 ],
4785 ],
4786 _('[-p|-d|-s] [-f] [-r] REV...'))
4786 _('[-p|-d|-s] [-f] [-r] REV...'))
4787 def phase(ui, repo, *revs, **opts):
4787 def phase(ui, repo, *revs, **opts):
4788 """set or show the current phase name
4788 """set or show the current phase name
4789
4789
4790 With no argument, show the phase name of specified revisions.
4790 With no argument, show the phase name of specified revisions.
4791
4791
4792 With one of -p/--public, -d/--draft or -s/--secret, change the
4792 With one of -p/--public, -d/--draft or -s/--secret, change the
4793 phase value of the specified revisions.
4793 phase value of the specified revisions.
4794
4794
4795 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4795 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4796 lower phase to an higher phase. Phases are ordered as follows::
4796 lower phase to an higher phase. Phases are ordered as follows::
4797
4797
4798 public < draft < secret
4798 public < draft < secret
4799
4799
4800 Returns 0 on success, 1 if no phases were changed or some could not
4800 Returns 0 on success, 1 if no phases were changed or some could not
4801 be changed.
4801 be changed.
4802 """
4802 """
4803 # search for a unique phase argument
4803 # search for a unique phase argument
4804 targetphase = None
4804 targetphase = None
4805 for idx, name in enumerate(phases.phasenames):
4805 for idx, name in enumerate(phases.phasenames):
4806 if opts[name]:
4806 if opts[name]:
4807 if targetphase is not None:
4807 if targetphase is not None:
4808 raise util.Abort(_('only one phase can be specified'))
4808 raise util.Abort(_('only one phase can be specified'))
4809 targetphase = idx
4809 targetphase = idx
4810
4810
4811 # look for specified revision
4811 # look for specified revision
4812 revs = list(revs)
4812 revs = list(revs)
4813 revs.extend(opts['rev'])
4813 revs.extend(opts['rev'])
4814 if not revs:
4814 if not revs:
4815 raise util.Abort(_('no revisions specified'))
4815 raise util.Abort(_('no revisions specified'))
4816
4816
4817 revs = scmutil.revrange(repo, revs)
4817 revs = scmutil.revrange(repo, revs)
4818
4818
4819 lock = None
4819 lock = None
4820 ret = 0
4820 ret = 0
4821 if targetphase is None:
4821 if targetphase is None:
4822 # display
4822 # display
4823 for r in revs:
4823 for r in revs:
4824 ctx = repo[r]
4824 ctx = repo[r]
4825 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4825 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4826 else:
4826 else:
4827 tr = None
4827 tr = None
4828 lock = repo.lock()
4828 lock = repo.lock()
4829 try:
4829 try:
4830 tr = repo.transaction("phase")
4830 tr = repo.transaction("phase")
4831 # set phase
4831 # set phase
4832 if not revs:
4832 if not revs:
4833 raise util.Abort(_('empty revision set'))
4833 raise util.Abort(_('empty revision set'))
4834 nodes = [repo[r].node() for r in revs]
4834 nodes = [repo[r].node() for r in revs]
4835 # moving revision from public to draft may hide them
4835 # moving revision from public to draft may hide them
4836 # We have to check result on an unfiltered repository
4836 # We have to check result on an unfiltered repository
4837 unfi = repo.unfiltered()
4837 unfi = repo.unfiltered()
4838 getphase = unfi._phasecache.phase
4838 getphase = unfi._phasecache.phase
4839 olddata = [getphase(unfi, r) for r in unfi]
4839 olddata = [getphase(unfi, r) for r in unfi]
4840 phases.advanceboundary(repo, tr, targetphase, nodes)
4840 phases.advanceboundary(repo, tr, targetphase, nodes)
4841 if opts['force']:
4841 if opts['force']:
4842 phases.retractboundary(repo, tr, targetphase, nodes)
4842 phases.retractboundary(repo, tr, targetphase, nodes)
4843 tr.close()
4843 tr.close()
4844 finally:
4844 finally:
4845 if tr is not None:
4845 if tr is not None:
4846 tr.release()
4846 tr.release()
4847 lock.release()
4847 lock.release()
4848 getphase = unfi._phasecache.phase
4848 getphase = unfi._phasecache.phase
4849 newdata = [getphase(unfi, r) for r in unfi]
4849 newdata = [getphase(unfi, r) for r in unfi]
4850 changes = sum(newdata[r] != olddata[r] for r in unfi)
4850 changes = sum(newdata[r] != olddata[r] for r in unfi)
4851 cl = unfi.changelog
4851 cl = unfi.changelog
4852 rejected = [n for n in nodes
4852 rejected = [n for n in nodes
4853 if newdata[cl.rev(n)] < targetphase]
4853 if newdata[cl.rev(n)] < targetphase]
4854 if rejected:
4854 if rejected:
4855 ui.warn(_('cannot move %i changesets to a higher '
4855 ui.warn(_('cannot move %i changesets to a higher '
4856 'phase, use --force\n') % len(rejected))
4856 'phase, use --force\n') % len(rejected))
4857 ret = 1
4857 ret = 1
4858 if changes:
4858 if changes:
4859 msg = _('phase changed for %i changesets\n') % changes
4859 msg = _('phase changed for %i changesets\n') % changes
4860 if ret:
4860 if ret:
4861 ui.status(msg)
4861 ui.status(msg)
4862 else:
4862 else:
4863 ui.note(msg)
4863 ui.note(msg)
4864 else:
4864 else:
4865 ui.warn(_('no phases changed\n'))
4865 ui.warn(_('no phases changed\n'))
4866 ret = 1
4866 ret = 1
4867 return ret
4867 return ret
4868
4868
4869 def postincoming(ui, repo, modheads, optupdate, checkout):
4869 def postincoming(ui, repo, modheads, optupdate, checkout):
4870 if modheads == 0:
4870 if modheads == 0:
4871 return
4871 return
4872 if optupdate:
4872 if optupdate:
4873 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4873 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4874 try:
4874 try:
4875 ret = hg.update(repo, checkout)
4875 ret = hg.update(repo, checkout)
4876 except util.Abort, inst:
4876 except util.Abort, inst:
4877 ui.warn(_("not updating: %s\n") % str(inst))
4877 ui.warn(_("not updating: %s\n") % str(inst))
4878 if inst.hint:
4878 if inst.hint:
4879 ui.warn(_("(%s)\n") % inst.hint)
4879 ui.warn(_("(%s)\n") % inst.hint)
4880 return 0
4880 return 0
4881 if not ret and not checkout:
4881 if not ret and not checkout:
4882 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4882 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4883 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4883 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4884 return ret
4884 return ret
4885 if modheads > 1:
4885 if modheads > 1:
4886 currentbranchheads = len(repo.branchheads())
4886 currentbranchheads = len(repo.branchheads())
4887 if currentbranchheads == modheads:
4887 if currentbranchheads == modheads:
4888 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4888 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4889 elif currentbranchheads > 1:
4889 elif currentbranchheads > 1:
4890 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4890 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4891 "merge)\n"))
4891 "merge)\n"))
4892 else:
4892 else:
4893 ui.status(_("(run 'hg heads' to see heads)\n"))
4893 ui.status(_("(run 'hg heads' to see heads)\n"))
4894 else:
4894 else:
4895 ui.status(_("(run 'hg update' to get a working copy)\n"))
4895 ui.status(_("(run 'hg update' to get a working copy)\n"))
4896
4896
4897 @command('^pull',
4897 @command('^pull',
4898 [('u', 'update', None,
4898 [('u', 'update', None,
4899 _('update to new branch head if changesets were pulled')),
4899 _('update to new branch head if changesets were pulled')),
4900 ('f', 'force', None, _('run even when remote repository is unrelated')),
4900 ('f', 'force', None, _('run even when remote repository is unrelated')),
4901 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4901 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4902 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4902 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4903 ('b', 'branch', [], _('a specific branch you would like to pull'),
4903 ('b', 'branch', [], _('a specific branch you would like to pull'),
4904 _('BRANCH')),
4904 _('BRANCH')),
4905 ] + remoteopts,
4905 ] + remoteopts,
4906 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4906 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4907 def pull(ui, repo, source="default", **opts):
4907 def pull(ui, repo, source="default", **opts):
4908 """pull changes from the specified source
4908 """pull changes from the specified source
4909
4909
4910 Pull changes from a remote repository to a local one.
4910 Pull changes from a remote repository to a local one.
4911
4911
4912 This finds all changes from the repository at the specified path
4912 This finds all changes from the repository at the specified path
4913 or URL and adds them to a local repository (the current one unless
4913 or URL and adds them to a local repository (the current one unless
4914 -R is specified). By default, this does not update the copy of the
4914 -R is specified). By default, this does not update the copy of the
4915 project in the working directory.
4915 project in the working directory.
4916
4916
4917 Use :hg:`incoming` if you want to see what would have been added
4917 Use :hg:`incoming` if you want to see what would have been added
4918 by a pull at the time you issued this command. If you then decide
4918 by a pull at the time you issued this command. If you then decide
4919 to add those changes to the repository, you should use :hg:`pull
4919 to add those changes to the repository, you should use :hg:`pull
4920 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4920 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4921
4921
4922 If SOURCE is omitted, the 'default' path will be used.
4922 If SOURCE is omitted, the 'default' path will be used.
4923 See :hg:`help urls` for more information.
4923 See :hg:`help urls` for more information.
4924
4924
4925 Returns 0 on success, 1 if an update had unresolved files.
4925 Returns 0 on success, 1 if an update had unresolved files.
4926 """
4926 """
4927 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4927 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4928 other = hg.peer(repo, opts, source)
4928 other = hg.peer(repo, opts, source)
4929 try:
4929 try:
4930 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4930 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4931 revs, checkout = hg.addbranchrevs(repo, other, branches,
4931 revs, checkout = hg.addbranchrevs(repo, other, branches,
4932 opts.get('rev'))
4932 opts.get('rev'))
4933
4933
4934 remotebookmarks = other.listkeys('bookmarks')
4934 remotebookmarks = other.listkeys('bookmarks')
4935
4935
4936 if opts.get('bookmark'):
4936 if opts.get('bookmark'):
4937 if not revs:
4937 if not revs:
4938 revs = []
4938 revs = []
4939 for b in opts['bookmark']:
4939 for b in opts['bookmark']:
4940 if b not in remotebookmarks:
4940 if b not in remotebookmarks:
4941 raise util.Abort(_('remote bookmark %s not found!') % b)
4941 raise util.Abort(_('remote bookmark %s not found!') % b)
4942 revs.append(remotebookmarks[b])
4942 revs.append(remotebookmarks[b])
4943
4943
4944 if revs:
4944 if revs:
4945 try:
4945 try:
4946 revs = [other.lookup(rev) for rev in revs]
4946 revs = [other.lookup(rev) for rev in revs]
4947 except error.CapabilityError:
4947 except error.CapabilityError:
4948 err = _("other repository doesn't support revision lookup, "
4948 err = _("other repository doesn't support revision lookup, "
4949 "so a rev cannot be specified.")
4949 "so a rev cannot be specified.")
4950 raise util.Abort(err)
4950 raise util.Abort(err)
4951
4951
4952 modheads = exchange.pull(repo, other, heads=revs,
4952 modheads = exchange.pull(repo, other, heads=revs,
4953 force=opts.get('force'),
4953 force=opts.get('force'),
4954 bookmarks=opts.get('bookmark', ())).cgresult
4954 bookmarks=opts.get('bookmark', ())).cgresult
4955 if checkout:
4955 if checkout:
4956 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4956 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4957 repo._subtoppath = source
4957 repo._subtoppath = source
4958 try:
4958 try:
4959 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4959 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4960
4960
4961 finally:
4961 finally:
4962 del repo._subtoppath
4962 del repo._subtoppath
4963
4963
4964 finally:
4964 finally:
4965 other.close()
4965 other.close()
4966 return ret
4966 return ret
4967
4967
4968 @command('^push',
4968 @command('^push',
4969 [('f', 'force', None, _('force push')),
4969 [('f', 'force', None, _('force push')),
4970 ('r', 'rev', [],
4970 ('r', 'rev', [],
4971 _('a changeset intended to be included in the destination'),
4971 _('a changeset intended to be included in the destination'),
4972 _('REV')),
4972 _('REV')),
4973 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4973 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4974 ('b', 'branch', [],
4974 ('b', 'branch', [],
4975 _('a specific branch you would like to push'), _('BRANCH')),
4975 _('a specific branch you would like to push'), _('BRANCH')),
4976 ('', 'new-branch', False, _('allow pushing a new branch')),
4976 ('', 'new-branch', False, _('allow pushing a new branch')),
4977 ] + remoteopts,
4977 ] + remoteopts,
4978 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4978 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4979 def push(ui, repo, dest=None, **opts):
4979 def push(ui, repo, dest=None, **opts):
4980 """push changes to the specified destination
4980 """push changes to the specified destination
4981
4981
4982 Push changesets from the local repository to the specified
4982 Push changesets from the local repository to the specified
4983 destination.
4983 destination.
4984
4984
4985 This operation is symmetrical to pull: it is identical to a pull
4985 This operation is symmetrical to pull: it is identical to a pull
4986 in the destination repository from the current one.
4986 in the destination repository from the current one.
4987
4987
4988 By default, push will not allow creation of new heads at the
4988 By default, push will not allow creation of new heads at the
4989 destination, since multiple heads would make it unclear which head
4989 destination, since multiple heads would make it unclear which head
4990 to use. In this situation, it is recommended to pull and merge
4990 to use. In this situation, it is recommended to pull and merge
4991 before pushing.
4991 before pushing.
4992
4992
4993 Use --new-branch if you want to allow push to create a new named
4993 Use --new-branch if you want to allow push to create a new named
4994 branch that is not present at the destination. This allows you to
4994 branch that is not present at the destination. This allows you to
4995 only create a new branch without forcing other changes.
4995 only create a new branch without forcing other changes.
4996
4996
4997 .. note::
4997 .. note::
4998
4998
4999 Extra care should be taken with the -f/--force option,
4999 Extra care should be taken with the -f/--force option,
5000 which will push all new heads on all branches, an action which will
5000 which will push all new heads on all branches, an action which will
5001 almost always cause confusion for collaborators.
5001 almost always cause confusion for collaborators.
5002
5002
5003 If -r/--rev is used, the specified revision and all its ancestors
5003 If -r/--rev is used, the specified revision and all its ancestors
5004 will be pushed to the remote repository.
5004 will be pushed to the remote repository.
5005
5005
5006 If -B/--bookmark is used, the specified bookmarked revision, its
5006 If -B/--bookmark is used, the specified bookmarked revision, its
5007 ancestors, and the bookmark will be pushed to the remote
5007 ancestors, and the bookmark will be pushed to the remote
5008 repository.
5008 repository.
5009
5009
5010 Please see :hg:`help urls` for important details about ``ssh://``
5010 Please see :hg:`help urls` for important details about ``ssh://``
5011 URLs. If DESTINATION is omitted, a default path will be used.
5011 URLs. If DESTINATION is omitted, a default path will be used.
5012
5012
5013 Returns 0 if push was successful, 1 if nothing to push.
5013 Returns 0 if push was successful, 1 if nothing to push.
5014 """
5014 """
5015
5015
5016 if opts.get('bookmark'):
5016 if opts.get('bookmark'):
5017 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5017 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5018 for b in opts['bookmark']:
5018 for b in opts['bookmark']:
5019 # translate -B options to -r so changesets get pushed
5019 # translate -B options to -r so changesets get pushed
5020 if b in repo._bookmarks:
5020 if b in repo._bookmarks:
5021 opts.setdefault('rev', []).append(b)
5021 opts.setdefault('rev', []).append(b)
5022 else:
5022 else:
5023 # if we try to push a deleted bookmark, translate it to null
5023 # if we try to push a deleted bookmark, translate it to null
5024 # this lets simultaneous -r, -b options continue working
5024 # this lets simultaneous -r, -b options continue working
5025 opts.setdefault('rev', []).append("null")
5025 opts.setdefault('rev', []).append("null")
5026
5026
5027 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5027 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5028 dest, branches = hg.parseurl(dest, opts.get('branch'))
5028 dest, branches = hg.parseurl(dest, opts.get('branch'))
5029 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5029 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5030 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5030 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5031 try:
5031 try:
5032 other = hg.peer(repo, opts, dest)
5032 other = hg.peer(repo, opts, dest)
5033 except error.RepoError:
5033 except error.RepoError:
5034 if dest == "default-push":
5034 if dest == "default-push":
5035 raise util.Abort(_("default repository not configured!"),
5035 raise util.Abort(_("default repository not configured!"),
5036 hint=_('see the "path" section in "hg help config"'))
5036 hint=_('see the "path" section in "hg help config"'))
5037 else:
5037 else:
5038 raise
5038 raise
5039
5039
5040 if revs:
5040 if revs:
5041 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5041 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5042
5042
5043 repo._subtoppath = dest
5043 repo._subtoppath = dest
5044 try:
5044 try:
5045 # push subrepos depth-first for coherent ordering
5045 # push subrepos depth-first for coherent ordering
5046 c = repo['']
5046 c = repo['']
5047 subs = c.substate # only repos that are committed
5047 subs = c.substate # only repos that are committed
5048 for s in sorted(subs):
5048 for s in sorted(subs):
5049 result = c.sub(s).push(opts)
5049 result = c.sub(s).push(opts)
5050 if result == 0:
5050 if result == 0:
5051 return not result
5051 return not result
5052 finally:
5052 finally:
5053 del repo._subtoppath
5053 del repo._subtoppath
5054 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5054 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5055 newbranch=opts.get('new_branch'),
5055 newbranch=opts.get('new_branch'),
5056 bookmarks=opts.get('bookmark', ()))
5056 bookmarks=opts.get('bookmark', ()))
5057
5057
5058 result = not pushop.cgresult
5058 result = not pushop.cgresult
5059
5059
5060 if pushop.bkresult is not None:
5060 if pushop.bkresult is not None:
5061 if pushop.bkresult == 2:
5061 if pushop.bkresult == 2:
5062 result = 2
5062 result = 2
5063 elif not result and pushop.bkresult:
5063 elif not result and pushop.bkresult:
5064 result = 2
5064 result = 2
5065
5065
5066 return result
5066 return result
5067
5067
5068 @command('recover', [])
5068 @command('recover', [])
5069 def recover(ui, repo):
5069 def recover(ui, repo):
5070 """roll back an interrupted transaction
5070 """roll back an interrupted transaction
5071
5071
5072 Recover from an interrupted commit or pull.
5072 Recover from an interrupted commit or pull.
5073
5073
5074 This command tries to fix the repository status after an
5074 This command tries to fix the repository status after an
5075 interrupted operation. It should only be necessary when Mercurial
5075 interrupted operation. It should only be necessary when Mercurial
5076 suggests it.
5076 suggests it.
5077
5077
5078 Returns 0 if successful, 1 if nothing to recover or verify fails.
5078 Returns 0 if successful, 1 if nothing to recover or verify fails.
5079 """
5079 """
5080 if repo.recover():
5080 if repo.recover():
5081 return hg.verify(repo)
5081 return hg.verify(repo)
5082 return 1
5082 return 1
5083
5083
5084 @command('^remove|rm',
5084 @command('^remove|rm',
5085 [('A', 'after', None, _('record delete for missing files')),
5085 [('A', 'after', None, _('record delete for missing files')),
5086 ('f', 'force', None,
5086 ('f', 'force', None,
5087 _('remove (and delete) file even if added or modified')),
5087 _('remove (and delete) file even if added or modified')),
5088 ] + walkopts,
5088 ] + walkopts,
5089 _('[OPTION]... FILE...'),
5089 _('[OPTION]... FILE...'),
5090 inferrepo=True)
5090 inferrepo=True)
5091 def remove(ui, repo, *pats, **opts):
5091 def remove(ui, repo, *pats, **opts):
5092 """remove the specified files on the next commit
5092 """remove the specified files on the next commit
5093
5093
5094 Schedule the indicated files for removal from the current branch.
5094 Schedule the indicated files for removal from the current branch.
5095
5095
5096 This command schedules the files to be removed at the next commit.
5096 This command schedules the files to be removed at the next commit.
5097 To undo a remove before that, see :hg:`revert`. To undo added
5097 To undo a remove before that, see :hg:`revert`. To undo added
5098 files, see :hg:`forget`.
5098 files, see :hg:`forget`.
5099
5099
5100 .. container:: verbose
5100 .. container:: verbose
5101
5101
5102 -A/--after can be used to remove only files that have already
5102 -A/--after can be used to remove only files that have already
5103 been deleted, -f/--force can be used to force deletion, and -Af
5103 been deleted, -f/--force can be used to force deletion, and -Af
5104 can be used to remove files from the next revision without
5104 can be used to remove files from the next revision without
5105 deleting them from the working directory.
5105 deleting them from the working directory.
5106
5106
5107 The following table details the behavior of remove for different
5107 The following table details the behavior of remove for different
5108 file states (columns) and option combinations (rows). The file
5108 file states (columns) and option combinations (rows). The file
5109 states are Added [A], Clean [C], Modified [M] and Missing [!]
5109 states are Added [A], Clean [C], Modified [M] and Missing [!]
5110 (as reported by :hg:`status`). The actions are Warn, Remove
5110 (as reported by :hg:`status`). The actions are Warn, Remove
5111 (from branch) and Delete (from disk):
5111 (from branch) and Delete (from disk):
5112
5112
5113 ========= == == == ==
5113 ========= == == == ==
5114 opt/state A C M !
5114 opt/state A C M !
5115 ========= == == == ==
5115 ========= == == == ==
5116 none W RD W R
5116 none W RD W R
5117 -f R RD RD R
5117 -f R RD RD R
5118 -A W W W R
5118 -A W W W R
5119 -Af R R R R
5119 -Af R R R R
5120 ========= == == == ==
5120 ========= == == == ==
5121
5121
5122 Note that remove never deletes files in Added [A] state from the
5122 Note that remove never deletes files in Added [A] state from the
5123 working directory, not even if option --force is specified.
5123 working directory, not even if option --force is specified.
5124
5124
5125 Returns 0 on success, 1 if any warnings encountered.
5125 Returns 0 on success, 1 if any warnings encountered.
5126 """
5126 """
5127
5127
5128 ret = 0
5129 after, force = opts.get('after'), opts.get('force')
5128 after, force = opts.get('after'), opts.get('force')
5130 if not pats and not after:
5129 if not pats and not after:
5131 raise util.Abort(_('no files specified'))
5130 raise util.Abort(_('no files specified'))
5132
5131
5133 m = scmutil.match(repo[None], pats, opts)
5132 m = scmutil.match(repo[None], pats, opts)
5134 s = repo.status(match=m, clean=True)
5133 return cmdutil.remove(ui, repo, m, after, force)
5135 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
5136
5137 # warn about failure to delete explicit files/dirs
5138 wctx = repo[None]
5139 for f in m.files():
5140 if f in repo.dirstate or f in wctx.dirs():
5141 continue
5142 if os.path.exists(m.rel(f)):
5143 if os.path.isdir(m.rel(f)):
5144 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
5145 else:
5146 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
5147 # missing files will generate a warning elsewhere
5148 ret = 1
5149
5150 if force:
5151 list = modified + deleted + clean + added
5152 elif after:
5153 list = deleted
5154 for f in modified + added + clean:
5155 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
5156 ret = 1
5157 else:
5158 list = deleted + clean
5159 for f in modified:
5160 ui.warn(_('not removing %s: file is modified (use -f'
5161 ' to force removal)\n') % m.rel(f))
5162 ret = 1
5163 for f in added:
5164 ui.warn(_('not removing %s: file has been marked for add'
5165 ' (use forget to undo)\n') % m.rel(f))
5166 ret = 1
5167
5168 for f in sorted(list):
5169 if ui.verbose or not m.exact(f):
5170 ui.status(_('removing %s\n') % m.rel(f))
5171
5172 wlock = repo.wlock()
5173 try:
5174 if not after:
5175 for f in list:
5176 if f in added:
5177 continue # we never unlink added files on remove
5178 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
5179 repo[None].forget(list)
5180 finally:
5181 wlock.release()
5182
5183 return ret
5184
5134
5185 @command('rename|move|mv',
5135 @command('rename|move|mv',
5186 [('A', 'after', None, _('record a rename that has already occurred')),
5136 [('A', 'after', None, _('record a rename that has already occurred')),
5187 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5137 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5188 ] + walkopts + dryrunopts,
5138 ] + walkopts + dryrunopts,
5189 _('[OPTION]... SOURCE... DEST'))
5139 _('[OPTION]... SOURCE... DEST'))
5190 def rename(ui, repo, *pats, **opts):
5140 def rename(ui, repo, *pats, **opts):
5191 """rename files; equivalent of copy + remove
5141 """rename files; equivalent of copy + remove
5192
5142
5193 Mark dest as copies of sources; mark sources for deletion. If dest
5143 Mark dest as copies of sources; mark sources for deletion. If dest
5194 is a directory, copies are put in that directory. If dest is a
5144 is a directory, copies are put in that directory. If dest is a
5195 file, there can only be one source.
5145 file, there can only be one source.
5196
5146
5197 By default, this command copies the contents of files as they
5147 By default, this command copies the contents of files as they
5198 exist in the working directory. If invoked with -A/--after, the
5148 exist in the working directory. If invoked with -A/--after, the
5199 operation is recorded, but no copying is performed.
5149 operation is recorded, but no copying is performed.
5200
5150
5201 This command takes effect at the next commit. To undo a rename
5151 This command takes effect at the next commit. To undo a rename
5202 before that, see :hg:`revert`.
5152 before that, see :hg:`revert`.
5203
5153
5204 Returns 0 on success, 1 if errors are encountered.
5154 Returns 0 on success, 1 if errors are encountered.
5205 """
5155 """
5206 wlock = repo.wlock(False)
5156 wlock = repo.wlock(False)
5207 try:
5157 try:
5208 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5158 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5209 finally:
5159 finally:
5210 wlock.release()
5160 wlock.release()
5211
5161
5212 @command('resolve',
5162 @command('resolve',
5213 [('a', 'all', None, _('select all unresolved files')),
5163 [('a', 'all', None, _('select all unresolved files')),
5214 ('l', 'list', None, _('list state of files needing merge')),
5164 ('l', 'list', None, _('list state of files needing merge')),
5215 ('m', 'mark', None, _('mark files as resolved')),
5165 ('m', 'mark', None, _('mark files as resolved')),
5216 ('u', 'unmark', None, _('mark files as unresolved')),
5166 ('u', 'unmark', None, _('mark files as unresolved')),
5217 ('n', 'no-status', None, _('hide status prefix'))]
5167 ('n', 'no-status', None, _('hide status prefix'))]
5218 + mergetoolopts + walkopts,
5168 + mergetoolopts + walkopts,
5219 _('[OPTION]... [FILE]...'),
5169 _('[OPTION]... [FILE]...'),
5220 inferrepo=True)
5170 inferrepo=True)
5221 def resolve(ui, repo, *pats, **opts):
5171 def resolve(ui, repo, *pats, **opts):
5222 """redo merges or set/view the merge status of files
5172 """redo merges or set/view the merge status of files
5223
5173
5224 Merges with unresolved conflicts are often the result of
5174 Merges with unresolved conflicts are often the result of
5225 non-interactive merging using the ``internal:merge`` configuration
5175 non-interactive merging using the ``internal:merge`` configuration
5226 setting, or a command-line merge tool like ``diff3``. The resolve
5176 setting, or a command-line merge tool like ``diff3``. The resolve
5227 command is used to manage the files involved in a merge, after
5177 command is used to manage the files involved in a merge, after
5228 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5178 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5229 working directory must have two parents). See :hg:`help
5179 working directory must have two parents). See :hg:`help
5230 merge-tools` for information on configuring merge tools.
5180 merge-tools` for information on configuring merge tools.
5231
5181
5232 The resolve command can be used in the following ways:
5182 The resolve command can be used in the following ways:
5233
5183
5234 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5184 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5235 files, discarding any previous merge attempts. Re-merging is not
5185 files, discarding any previous merge attempts. Re-merging is not
5236 performed for files already marked as resolved. Use ``--all/-a``
5186 performed for files already marked as resolved. Use ``--all/-a``
5237 to select all unresolved files. ``--tool`` can be used to specify
5187 to select all unresolved files. ``--tool`` can be used to specify
5238 the merge tool used for the given files. It overrides the HGMERGE
5188 the merge tool used for the given files. It overrides the HGMERGE
5239 environment variable and your configuration files. Previous file
5189 environment variable and your configuration files. Previous file
5240 contents are saved with a ``.orig`` suffix.
5190 contents are saved with a ``.orig`` suffix.
5241
5191
5242 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5192 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5243 (e.g. after having manually fixed-up the files). The default is
5193 (e.g. after having manually fixed-up the files). The default is
5244 to mark all unresolved files.
5194 to mark all unresolved files.
5245
5195
5246 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5196 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5247 default is to mark all resolved files.
5197 default is to mark all resolved files.
5248
5198
5249 - :hg:`resolve -l`: list files which had or still have conflicts.
5199 - :hg:`resolve -l`: list files which had or still have conflicts.
5250 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5200 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5251
5201
5252 Note that Mercurial will not let you commit files with unresolved
5202 Note that Mercurial will not let you commit files with unresolved
5253 merge conflicts. You must use :hg:`resolve -m ...` before you can
5203 merge conflicts. You must use :hg:`resolve -m ...` before you can
5254 commit after a conflicting merge.
5204 commit after a conflicting merge.
5255
5205
5256 Returns 0 on success, 1 if any files fail a resolve attempt.
5206 Returns 0 on success, 1 if any files fail a resolve attempt.
5257 """
5207 """
5258
5208
5259 all, mark, unmark, show, nostatus = \
5209 all, mark, unmark, show, nostatus = \
5260 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5210 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5261
5211
5262 if (show and (mark or unmark)) or (mark and unmark):
5212 if (show and (mark or unmark)) or (mark and unmark):
5263 raise util.Abort(_("too many options specified"))
5213 raise util.Abort(_("too many options specified"))
5264 if pats and all:
5214 if pats and all:
5265 raise util.Abort(_("can't specify --all and patterns"))
5215 raise util.Abort(_("can't specify --all and patterns"))
5266 if not (all or pats or show or mark or unmark):
5216 if not (all or pats or show or mark or unmark):
5267 raise util.Abort(_('no files or directories specified'),
5217 raise util.Abort(_('no files or directories specified'),
5268 hint=('use --all to remerge all files'))
5218 hint=('use --all to remerge all files'))
5269
5219
5270 wlock = repo.wlock()
5220 wlock = repo.wlock()
5271 try:
5221 try:
5272 ms = mergemod.mergestate(repo)
5222 ms = mergemod.mergestate(repo)
5273
5223
5274 if not (ms.active() or repo.dirstate.p2() != nullid) and not show:
5224 if not (ms.active() or repo.dirstate.p2() != nullid) and not show:
5275 raise util.Abort(
5225 raise util.Abort(
5276 _('resolve command not applicable when not merging'))
5226 _('resolve command not applicable when not merging'))
5277
5227
5278 m = scmutil.match(repo[None], pats, opts)
5228 m = scmutil.match(repo[None], pats, opts)
5279 ret = 0
5229 ret = 0
5280 didwork = False
5230 didwork = False
5281
5231
5282 for f in ms:
5232 for f in ms:
5283 if not m(f):
5233 if not m(f):
5284 continue
5234 continue
5285
5235
5286 didwork = True
5236 didwork = True
5287
5237
5288 if show:
5238 if show:
5289 if nostatus:
5239 if nostatus:
5290 ui.write("%s\n" % f)
5240 ui.write("%s\n" % f)
5291 else:
5241 else:
5292 ui.write("%s %s\n" % (ms[f].upper(), f),
5242 ui.write("%s %s\n" % (ms[f].upper(), f),
5293 label='resolve.' +
5243 label='resolve.' +
5294 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5244 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5295 elif mark:
5245 elif mark:
5296 ms.mark(f, "r")
5246 ms.mark(f, "r")
5297 elif unmark:
5247 elif unmark:
5298 ms.mark(f, "u")
5248 ms.mark(f, "u")
5299 else:
5249 else:
5300 wctx = repo[None]
5250 wctx = repo[None]
5301
5251
5302 # backup pre-resolve (merge uses .orig for its own purposes)
5252 # backup pre-resolve (merge uses .orig for its own purposes)
5303 a = repo.wjoin(f)
5253 a = repo.wjoin(f)
5304 util.copyfile(a, a + ".resolve")
5254 util.copyfile(a, a + ".resolve")
5305
5255
5306 try:
5256 try:
5307 # resolve file
5257 # resolve file
5308 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5258 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5309 'resolve')
5259 'resolve')
5310 if ms.resolve(f, wctx):
5260 if ms.resolve(f, wctx):
5311 ret = 1
5261 ret = 1
5312 finally:
5262 finally:
5313 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5263 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5314 ms.commit()
5264 ms.commit()
5315
5265
5316 # replace filemerge's .orig file with our resolve file
5266 # replace filemerge's .orig file with our resolve file
5317 util.rename(a + ".resolve", a + ".orig")
5267 util.rename(a + ".resolve", a + ".orig")
5318
5268
5319 ms.commit()
5269 ms.commit()
5320
5270
5321 if not didwork and pats:
5271 if not didwork and pats:
5322 ui.warn(_("arguments do not match paths that need resolving\n"))
5272 ui.warn(_("arguments do not match paths that need resolving\n"))
5323
5273
5324 finally:
5274 finally:
5325 wlock.release()
5275 wlock.release()
5326
5276
5327 # Nudge users into finishing an unfinished operation. We don't print
5277 # Nudge users into finishing an unfinished operation. We don't print
5328 # this with the list/show operation because we want list/show to remain
5278 # this with the list/show operation because we want list/show to remain
5329 # machine readable.
5279 # machine readable.
5330 if not list(ms.unresolved()) and not show:
5280 if not list(ms.unresolved()) and not show:
5331 ui.status(_('(no more unresolved files)\n'))
5281 ui.status(_('(no more unresolved files)\n'))
5332
5282
5333 return ret
5283 return ret
5334
5284
5335 @command('revert',
5285 @command('revert',
5336 [('a', 'all', None, _('revert all changes when no arguments given')),
5286 [('a', 'all', None, _('revert all changes when no arguments given')),
5337 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5287 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5338 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5288 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5339 ('C', 'no-backup', None, _('do not save backup copies of files')),
5289 ('C', 'no-backup', None, _('do not save backup copies of files')),
5340 ] + walkopts + dryrunopts,
5290 ] + walkopts + dryrunopts,
5341 _('[OPTION]... [-r REV] [NAME]...'))
5291 _('[OPTION]... [-r REV] [NAME]...'))
5342 def revert(ui, repo, *pats, **opts):
5292 def revert(ui, repo, *pats, **opts):
5343 """restore files to their checkout state
5293 """restore files to their checkout state
5344
5294
5345 .. note::
5295 .. note::
5346
5296
5347 To check out earlier revisions, you should use :hg:`update REV`.
5297 To check out earlier revisions, you should use :hg:`update REV`.
5348 To cancel an uncommitted merge (and lose your changes),
5298 To cancel an uncommitted merge (and lose your changes),
5349 use :hg:`update --clean .`.
5299 use :hg:`update --clean .`.
5350
5300
5351 With no revision specified, revert the specified files or directories
5301 With no revision specified, revert the specified files or directories
5352 to the contents they had in the parent of the working directory.
5302 to the contents they had in the parent of the working directory.
5353 This restores the contents of files to an unmodified
5303 This restores the contents of files to an unmodified
5354 state and unschedules adds, removes, copies, and renames. If the
5304 state and unschedules adds, removes, copies, and renames. If the
5355 working directory has two parents, you must explicitly specify a
5305 working directory has two parents, you must explicitly specify a
5356 revision.
5306 revision.
5357
5307
5358 Using the -r/--rev or -d/--date options, revert the given files or
5308 Using the -r/--rev or -d/--date options, revert the given files or
5359 directories to their states as of a specific revision. Because
5309 directories to their states as of a specific revision. Because
5360 revert does not change the working directory parents, this will
5310 revert does not change the working directory parents, this will
5361 cause these files to appear modified. This can be helpful to "back
5311 cause these files to appear modified. This can be helpful to "back
5362 out" some or all of an earlier change. See :hg:`backout` for a
5312 out" some or all of an earlier change. See :hg:`backout` for a
5363 related method.
5313 related method.
5364
5314
5365 Modified files are saved with a .orig suffix before reverting.
5315 Modified files are saved with a .orig suffix before reverting.
5366 To disable these backups, use --no-backup.
5316 To disable these backups, use --no-backup.
5367
5317
5368 See :hg:`help dates` for a list of formats valid for -d/--date.
5318 See :hg:`help dates` for a list of formats valid for -d/--date.
5369
5319
5370 Returns 0 on success.
5320 Returns 0 on success.
5371 """
5321 """
5372
5322
5373 if opts.get("date"):
5323 if opts.get("date"):
5374 if opts.get("rev"):
5324 if opts.get("rev"):
5375 raise util.Abort(_("you can't specify a revision and a date"))
5325 raise util.Abort(_("you can't specify a revision and a date"))
5376 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5326 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5377
5327
5378 parent, p2 = repo.dirstate.parents()
5328 parent, p2 = repo.dirstate.parents()
5379 if not opts.get('rev') and p2 != nullid:
5329 if not opts.get('rev') and p2 != nullid:
5380 # revert after merge is a trap for new users (issue2915)
5330 # revert after merge is a trap for new users (issue2915)
5381 raise util.Abort(_('uncommitted merge with no revision specified'),
5331 raise util.Abort(_('uncommitted merge with no revision specified'),
5382 hint=_('use "hg update" or see "hg help revert"'))
5332 hint=_('use "hg update" or see "hg help revert"'))
5383
5333
5384 ctx = scmutil.revsingle(repo, opts.get('rev'))
5334 ctx = scmutil.revsingle(repo, opts.get('rev'))
5385
5335
5386 if not pats and not opts.get('all'):
5336 if not pats and not opts.get('all'):
5387 msg = _("no files or directories specified")
5337 msg = _("no files or directories specified")
5388 if p2 != nullid:
5338 if p2 != nullid:
5389 hint = _("uncommitted merge, use --all to discard all changes,"
5339 hint = _("uncommitted merge, use --all to discard all changes,"
5390 " or 'hg update -C .' to abort the merge")
5340 " or 'hg update -C .' to abort the merge")
5391 raise util.Abort(msg, hint=hint)
5341 raise util.Abort(msg, hint=hint)
5392 dirty = util.any(repo.status())
5342 dirty = util.any(repo.status())
5393 node = ctx.node()
5343 node = ctx.node()
5394 if node != parent:
5344 if node != parent:
5395 if dirty:
5345 if dirty:
5396 hint = _("uncommitted changes, use --all to discard all"
5346 hint = _("uncommitted changes, use --all to discard all"
5397 " changes, or 'hg update %s' to update") % ctx.rev()
5347 " changes, or 'hg update %s' to update") % ctx.rev()
5398 else:
5348 else:
5399 hint = _("use --all to revert all files,"
5349 hint = _("use --all to revert all files,"
5400 " or 'hg update %s' to update") % ctx.rev()
5350 " or 'hg update %s' to update") % ctx.rev()
5401 elif dirty:
5351 elif dirty:
5402 hint = _("uncommitted changes, use --all to discard all changes")
5352 hint = _("uncommitted changes, use --all to discard all changes")
5403 else:
5353 else:
5404 hint = _("use --all to revert all files")
5354 hint = _("use --all to revert all files")
5405 raise util.Abort(msg, hint=hint)
5355 raise util.Abort(msg, hint=hint)
5406
5356
5407 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5357 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5408
5358
5409 @command('rollback', dryrunopts +
5359 @command('rollback', dryrunopts +
5410 [('f', 'force', False, _('ignore safety measures'))])
5360 [('f', 'force', False, _('ignore safety measures'))])
5411 def rollback(ui, repo, **opts):
5361 def rollback(ui, repo, **opts):
5412 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5362 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5413
5363
5414 Please use :hg:`commit --amend` instead of rollback to correct
5364 Please use :hg:`commit --amend` instead of rollback to correct
5415 mistakes in the last commit.
5365 mistakes in the last commit.
5416
5366
5417 This command should be used with care. There is only one level of
5367 This command should be used with care. There is only one level of
5418 rollback, and there is no way to undo a rollback. It will also
5368 rollback, and there is no way to undo a rollback. It will also
5419 restore the dirstate at the time of the last transaction, losing
5369 restore the dirstate at the time of the last transaction, losing
5420 any dirstate changes since that time. This command does not alter
5370 any dirstate changes since that time. This command does not alter
5421 the working directory.
5371 the working directory.
5422
5372
5423 Transactions are used to encapsulate the effects of all commands
5373 Transactions are used to encapsulate the effects of all commands
5424 that create new changesets or propagate existing changesets into a
5374 that create new changesets or propagate existing changesets into a
5425 repository.
5375 repository.
5426
5376
5427 .. container:: verbose
5377 .. container:: verbose
5428
5378
5429 For example, the following commands are transactional, and their
5379 For example, the following commands are transactional, and their
5430 effects can be rolled back:
5380 effects can be rolled back:
5431
5381
5432 - commit
5382 - commit
5433 - import
5383 - import
5434 - pull
5384 - pull
5435 - push (with this repository as the destination)
5385 - push (with this repository as the destination)
5436 - unbundle
5386 - unbundle
5437
5387
5438 To avoid permanent data loss, rollback will refuse to rollback a
5388 To avoid permanent data loss, rollback will refuse to rollback a
5439 commit transaction if it isn't checked out. Use --force to
5389 commit transaction if it isn't checked out. Use --force to
5440 override this protection.
5390 override this protection.
5441
5391
5442 This command is not intended for use on public repositories. Once
5392 This command is not intended for use on public repositories. Once
5443 changes are visible for pull by other users, rolling a transaction
5393 changes are visible for pull by other users, rolling a transaction
5444 back locally is ineffective (someone else may already have pulled
5394 back locally is ineffective (someone else may already have pulled
5445 the changes). Furthermore, a race is possible with readers of the
5395 the changes). Furthermore, a race is possible with readers of the
5446 repository; for example an in-progress pull from the repository
5396 repository; for example an in-progress pull from the repository
5447 may fail if a rollback is performed.
5397 may fail if a rollback is performed.
5448
5398
5449 Returns 0 on success, 1 if no rollback data is available.
5399 Returns 0 on success, 1 if no rollback data is available.
5450 """
5400 """
5451 return repo.rollback(dryrun=opts.get('dry_run'),
5401 return repo.rollback(dryrun=opts.get('dry_run'),
5452 force=opts.get('force'))
5402 force=opts.get('force'))
5453
5403
5454 @command('root', [])
5404 @command('root', [])
5455 def root(ui, repo):
5405 def root(ui, repo):
5456 """print the root (top) of the current working directory
5406 """print the root (top) of the current working directory
5457
5407
5458 Print the root directory of the current repository.
5408 Print the root directory of the current repository.
5459
5409
5460 Returns 0 on success.
5410 Returns 0 on success.
5461 """
5411 """
5462 ui.write(repo.root + "\n")
5412 ui.write(repo.root + "\n")
5463
5413
5464 @command('^serve',
5414 @command('^serve',
5465 [('A', 'accesslog', '', _('name of access log file to write to'),
5415 [('A', 'accesslog', '', _('name of access log file to write to'),
5466 _('FILE')),
5416 _('FILE')),
5467 ('d', 'daemon', None, _('run server in background')),
5417 ('d', 'daemon', None, _('run server in background')),
5468 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5418 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5469 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5419 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5470 # use string type, then we can check if something was passed
5420 # use string type, then we can check if something was passed
5471 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5421 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5472 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5422 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5473 _('ADDR')),
5423 _('ADDR')),
5474 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5424 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5475 _('PREFIX')),
5425 _('PREFIX')),
5476 ('n', 'name', '',
5426 ('n', 'name', '',
5477 _('name to show in web pages (default: working directory)'), _('NAME')),
5427 _('name to show in web pages (default: working directory)'), _('NAME')),
5478 ('', 'web-conf', '',
5428 ('', 'web-conf', '',
5479 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5429 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5480 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5430 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5481 _('FILE')),
5431 _('FILE')),
5482 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5432 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5483 ('', 'stdio', None, _('for remote clients')),
5433 ('', 'stdio', None, _('for remote clients')),
5484 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5434 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5485 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5435 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5486 ('', 'style', '', _('template style to use'), _('STYLE')),
5436 ('', 'style', '', _('template style to use'), _('STYLE')),
5487 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5437 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5488 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5438 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5489 _('[OPTION]...'),
5439 _('[OPTION]...'),
5490 optionalrepo=True)
5440 optionalrepo=True)
5491 def serve(ui, repo, **opts):
5441 def serve(ui, repo, **opts):
5492 """start stand-alone webserver
5442 """start stand-alone webserver
5493
5443
5494 Start a local HTTP repository browser and pull server. You can use
5444 Start a local HTTP repository browser and pull server. You can use
5495 this for ad-hoc sharing and browsing of repositories. It is
5445 this for ad-hoc sharing and browsing of repositories. It is
5496 recommended to use a real web server to serve a repository for
5446 recommended to use a real web server to serve a repository for
5497 longer periods of time.
5447 longer periods of time.
5498
5448
5499 Please note that the server does not implement access control.
5449 Please note that the server does not implement access control.
5500 This means that, by default, anybody can read from the server and
5450 This means that, by default, anybody can read from the server and
5501 nobody can write to it by default. Set the ``web.allow_push``
5451 nobody can write to it by default. Set the ``web.allow_push``
5502 option to ``*`` to allow everybody to push to the server. You
5452 option to ``*`` to allow everybody to push to the server. You
5503 should use a real web server if you need to authenticate users.
5453 should use a real web server if you need to authenticate users.
5504
5454
5505 By default, the server logs accesses to stdout and errors to
5455 By default, the server logs accesses to stdout and errors to
5506 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5456 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5507 files.
5457 files.
5508
5458
5509 To have the server choose a free port number to listen on, specify
5459 To have the server choose a free port number to listen on, specify
5510 a port number of 0; in this case, the server will print the port
5460 a port number of 0; in this case, the server will print the port
5511 number it uses.
5461 number it uses.
5512
5462
5513 Returns 0 on success.
5463 Returns 0 on success.
5514 """
5464 """
5515
5465
5516 if opts["stdio"] and opts["cmdserver"]:
5466 if opts["stdio"] and opts["cmdserver"]:
5517 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5467 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5518
5468
5519 if opts["stdio"]:
5469 if opts["stdio"]:
5520 if repo is None:
5470 if repo is None:
5521 raise error.RepoError(_("there is no Mercurial repository here"
5471 raise error.RepoError(_("there is no Mercurial repository here"
5522 " (.hg not found)"))
5472 " (.hg not found)"))
5523 s = sshserver.sshserver(ui, repo)
5473 s = sshserver.sshserver(ui, repo)
5524 s.serve_forever()
5474 s.serve_forever()
5525
5475
5526 if opts["cmdserver"]:
5476 if opts["cmdserver"]:
5527 service = commandserver.createservice(ui, repo, opts)
5477 service = commandserver.createservice(ui, repo, opts)
5528 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5478 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5529
5479
5530 # this way we can check if something was given in the command-line
5480 # this way we can check if something was given in the command-line
5531 if opts.get('port'):
5481 if opts.get('port'):
5532 opts['port'] = util.getport(opts.get('port'))
5482 opts['port'] = util.getport(opts.get('port'))
5533
5483
5534 baseui = repo and repo.baseui or ui
5484 baseui = repo and repo.baseui or ui
5535 optlist = ("name templates style address port prefix ipv6"
5485 optlist = ("name templates style address port prefix ipv6"
5536 " accesslog errorlog certificate encoding")
5486 " accesslog errorlog certificate encoding")
5537 for o in optlist.split():
5487 for o in optlist.split():
5538 val = opts.get(o, '')
5488 val = opts.get(o, '')
5539 if val in (None, ''): # should check against default options instead
5489 if val in (None, ''): # should check against default options instead
5540 continue
5490 continue
5541 baseui.setconfig("web", o, val, 'serve')
5491 baseui.setconfig("web", o, val, 'serve')
5542 if repo and repo.ui != baseui:
5492 if repo and repo.ui != baseui:
5543 repo.ui.setconfig("web", o, val, 'serve')
5493 repo.ui.setconfig("web", o, val, 'serve')
5544
5494
5545 o = opts.get('web_conf') or opts.get('webdir_conf')
5495 o = opts.get('web_conf') or opts.get('webdir_conf')
5546 if not o:
5496 if not o:
5547 if not repo:
5497 if not repo:
5548 raise error.RepoError(_("there is no Mercurial repository"
5498 raise error.RepoError(_("there is no Mercurial repository"
5549 " here (.hg not found)"))
5499 " here (.hg not found)"))
5550 o = repo
5500 o = repo
5551
5501
5552 app = hgweb.hgweb(o, baseui=baseui)
5502 app = hgweb.hgweb(o, baseui=baseui)
5553 service = httpservice(ui, app, opts)
5503 service = httpservice(ui, app, opts)
5554 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5504 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5555
5505
5556 class httpservice(object):
5506 class httpservice(object):
5557 def __init__(self, ui, app, opts):
5507 def __init__(self, ui, app, opts):
5558 self.ui = ui
5508 self.ui = ui
5559 self.app = app
5509 self.app = app
5560 self.opts = opts
5510 self.opts = opts
5561
5511
5562 def init(self):
5512 def init(self):
5563 util.setsignalhandler()
5513 util.setsignalhandler()
5564 self.httpd = hgweb_server.create_server(self.ui, self.app)
5514 self.httpd = hgweb_server.create_server(self.ui, self.app)
5565
5515
5566 if self.opts['port'] and not self.ui.verbose:
5516 if self.opts['port'] and not self.ui.verbose:
5567 return
5517 return
5568
5518
5569 if self.httpd.prefix:
5519 if self.httpd.prefix:
5570 prefix = self.httpd.prefix.strip('/') + '/'
5520 prefix = self.httpd.prefix.strip('/') + '/'
5571 else:
5521 else:
5572 prefix = ''
5522 prefix = ''
5573
5523
5574 port = ':%d' % self.httpd.port
5524 port = ':%d' % self.httpd.port
5575 if port == ':80':
5525 if port == ':80':
5576 port = ''
5526 port = ''
5577
5527
5578 bindaddr = self.httpd.addr
5528 bindaddr = self.httpd.addr
5579 if bindaddr == '0.0.0.0':
5529 if bindaddr == '0.0.0.0':
5580 bindaddr = '*'
5530 bindaddr = '*'
5581 elif ':' in bindaddr: # IPv6
5531 elif ':' in bindaddr: # IPv6
5582 bindaddr = '[%s]' % bindaddr
5532 bindaddr = '[%s]' % bindaddr
5583
5533
5584 fqaddr = self.httpd.fqaddr
5534 fqaddr = self.httpd.fqaddr
5585 if ':' in fqaddr:
5535 if ':' in fqaddr:
5586 fqaddr = '[%s]' % fqaddr
5536 fqaddr = '[%s]' % fqaddr
5587 if self.opts['port']:
5537 if self.opts['port']:
5588 write = self.ui.status
5538 write = self.ui.status
5589 else:
5539 else:
5590 write = self.ui.write
5540 write = self.ui.write
5591 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5541 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5592 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5542 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5593 self.ui.flush() # avoid buffering of status message
5543 self.ui.flush() # avoid buffering of status message
5594
5544
5595 def run(self):
5545 def run(self):
5596 self.httpd.serve_forever()
5546 self.httpd.serve_forever()
5597
5547
5598
5548
5599 @command('^status|st',
5549 @command('^status|st',
5600 [('A', 'all', None, _('show status of all files')),
5550 [('A', 'all', None, _('show status of all files')),
5601 ('m', 'modified', None, _('show only modified files')),
5551 ('m', 'modified', None, _('show only modified files')),
5602 ('a', 'added', None, _('show only added files')),
5552 ('a', 'added', None, _('show only added files')),
5603 ('r', 'removed', None, _('show only removed files')),
5553 ('r', 'removed', None, _('show only removed files')),
5604 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5554 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5605 ('c', 'clean', None, _('show only files without changes')),
5555 ('c', 'clean', None, _('show only files without changes')),
5606 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5556 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5607 ('i', 'ignored', None, _('show only ignored files')),
5557 ('i', 'ignored', None, _('show only ignored files')),
5608 ('n', 'no-status', None, _('hide status prefix')),
5558 ('n', 'no-status', None, _('hide status prefix')),
5609 ('C', 'copies', None, _('show source of copied files')),
5559 ('C', 'copies', None, _('show source of copied files')),
5610 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5560 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5611 ('', 'rev', [], _('show difference from revision'), _('REV')),
5561 ('', 'rev', [], _('show difference from revision'), _('REV')),
5612 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5562 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5613 ] + walkopts + subrepoopts + formatteropts,
5563 ] + walkopts + subrepoopts + formatteropts,
5614 _('[OPTION]... [FILE]...'),
5564 _('[OPTION]... [FILE]...'),
5615 inferrepo=True)
5565 inferrepo=True)
5616 def status(ui, repo, *pats, **opts):
5566 def status(ui, repo, *pats, **opts):
5617 """show changed files in the working directory
5567 """show changed files in the working directory
5618
5568
5619 Show status of files in the repository. If names are given, only
5569 Show status of files in the repository. If names are given, only
5620 files that match are shown. Files that are clean or ignored or
5570 files that match are shown. Files that are clean or ignored or
5621 the source of a copy/move operation, are not listed unless
5571 the source of a copy/move operation, are not listed unless
5622 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5572 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5623 Unless options described with "show only ..." are given, the
5573 Unless options described with "show only ..." are given, the
5624 options -mardu are used.
5574 options -mardu are used.
5625
5575
5626 Option -q/--quiet hides untracked (unknown and ignored) files
5576 Option -q/--quiet hides untracked (unknown and ignored) files
5627 unless explicitly requested with -u/--unknown or -i/--ignored.
5577 unless explicitly requested with -u/--unknown or -i/--ignored.
5628
5578
5629 .. note::
5579 .. note::
5630
5580
5631 status may appear to disagree with diff if permissions have
5581 status may appear to disagree with diff if permissions have
5632 changed or a merge has occurred. The standard diff format does
5582 changed or a merge has occurred. The standard diff format does
5633 not report permission changes and diff only reports changes
5583 not report permission changes and diff only reports changes
5634 relative to one merge parent.
5584 relative to one merge parent.
5635
5585
5636 If one revision is given, it is used as the base revision.
5586 If one revision is given, it is used as the base revision.
5637 If two revisions are given, the differences between them are
5587 If two revisions are given, the differences between them are
5638 shown. The --change option can also be used as a shortcut to list
5588 shown. The --change option can also be used as a shortcut to list
5639 the changed files of a revision from its first parent.
5589 the changed files of a revision from its first parent.
5640
5590
5641 The codes used to show the status of files are::
5591 The codes used to show the status of files are::
5642
5592
5643 M = modified
5593 M = modified
5644 A = added
5594 A = added
5645 R = removed
5595 R = removed
5646 C = clean
5596 C = clean
5647 ! = missing (deleted by non-hg command, but still tracked)
5597 ! = missing (deleted by non-hg command, but still tracked)
5648 ? = not tracked
5598 ? = not tracked
5649 I = ignored
5599 I = ignored
5650 = origin of the previous file (with --copies)
5600 = origin of the previous file (with --copies)
5651
5601
5652 .. container:: verbose
5602 .. container:: verbose
5653
5603
5654 Examples:
5604 Examples:
5655
5605
5656 - show changes in the working directory relative to a
5606 - show changes in the working directory relative to a
5657 changeset::
5607 changeset::
5658
5608
5659 hg status --rev 9353
5609 hg status --rev 9353
5660
5610
5661 - show all changes including copies in an existing changeset::
5611 - show all changes including copies in an existing changeset::
5662
5612
5663 hg status --copies --change 9353
5613 hg status --copies --change 9353
5664
5614
5665 - get a NUL separated list of added files, suitable for xargs::
5615 - get a NUL separated list of added files, suitable for xargs::
5666
5616
5667 hg status -an0
5617 hg status -an0
5668
5618
5669 Returns 0 on success.
5619 Returns 0 on success.
5670 """
5620 """
5671
5621
5672 revs = opts.get('rev')
5622 revs = opts.get('rev')
5673 change = opts.get('change')
5623 change = opts.get('change')
5674
5624
5675 if revs and change:
5625 if revs and change:
5676 msg = _('cannot specify --rev and --change at the same time')
5626 msg = _('cannot specify --rev and --change at the same time')
5677 raise util.Abort(msg)
5627 raise util.Abort(msg)
5678 elif change:
5628 elif change:
5679 node2 = scmutil.revsingle(repo, change, None).node()
5629 node2 = scmutil.revsingle(repo, change, None).node()
5680 node1 = repo[node2].p1().node()
5630 node1 = repo[node2].p1().node()
5681 else:
5631 else:
5682 node1, node2 = scmutil.revpair(repo, revs)
5632 node1, node2 = scmutil.revpair(repo, revs)
5683
5633
5684 cwd = (pats and repo.getcwd()) or ''
5634 cwd = (pats and repo.getcwd()) or ''
5685 end = opts.get('print0') and '\0' or '\n'
5635 end = opts.get('print0') and '\0' or '\n'
5686 copy = {}
5636 copy = {}
5687 states = 'modified added removed deleted unknown ignored clean'.split()
5637 states = 'modified added removed deleted unknown ignored clean'.split()
5688 show = [k for k in states if opts.get(k)]
5638 show = [k for k in states if opts.get(k)]
5689 if opts.get('all'):
5639 if opts.get('all'):
5690 show += ui.quiet and (states[:4] + ['clean']) or states
5640 show += ui.quiet and (states[:4] + ['clean']) or states
5691 if not show:
5641 if not show:
5692 show = ui.quiet and states[:4] or states[:5]
5642 show = ui.quiet and states[:4] or states[:5]
5693
5643
5694 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5644 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5695 'ignored' in show, 'clean' in show, 'unknown' in show,
5645 'ignored' in show, 'clean' in show, 'unknown' in show,
5696 opts.get('subrepos'))
5646 opts.get('subrepos'))
5697 changestates = zip(states, 'MAR!?IC', stat)
5647 changestates = zip(states, 'MAR!?IC', stat)
5698
5648
5699 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5649 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5700 copy = copies.pathcopies(repo[node1], repo[node2])
5650 copy = copies.pathcopies(repo[node1], repo[node2])
5701
5651
5702 fm = ui.formatter('status', opts)
5652 fm = ui.formatter('status', opts)
5703 fmt = '%s' + end
5653 fmt = '%s' + end
5704 showchar = not opts.get('no_status')
5654 showchar = not opts.get('no_status')
5705
5655
5706 for state, char, files in changestates:
5656 for state, char, files in changestates:
5707 if state in show:
5657 if state in show:
5708 label = 'status.' + state
5658 label = 'status.' + state
5709 for f in files:
5659 for f in files:
5710 fm.startitem()
5660 fm.startitem()
5711 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5661 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5712 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5662 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5713 if f in copy:
5663 if f in copy:
5714 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5664 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5715 label='status.copied')
5665 label='status.copied')
5716 fm.end()
5666 fm.end()
5717
5667
5718 @command('^summary|sum',
5668 @command('^summary|sum',
5719 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5669 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5720 def summary(ui, repo, **opts):
5670 def summary(ui, repo, **opts):
5721 """summarize working directory state
5671 """summarize working directory state
5722
5672
5723 This generates a brief summary of the working directory state,
5673 This generates a brief summary of the working directory state,
5724 including parents, branch, commit status, and available updates.
5674 including parents, branch, commit status, and available updates.
5725
5675
5726 With the --remote option, this will check the default paths for
5676 With the --remote option, this will check the default paths for
5727 incoming and outgoing changes. This can be time-consuming.
5677 incoming and outgoing changes. This can be time-consuming.
5728
5678
5729 Returns 0 on success.
5679 Returns 0 on success.
5730 """
5680 """
5731
5681
5732 ctx = repo[None]
5682 ctx = repo[None]
5733 parents = ctx.parents()
5683 parents = ctx.parents()
5734 pnode = parents[0].node()
5684 pnode = parents[0].node()
5735 marks = []
5685 marks = []
5736
5686
5737 for p in parents:
5687 for p in parents:
5738 # label with log.changeset (instead of log.parent) since this
5688 # label with log.changeset (instead of log.parent) since this
5739 # shows a working directory parent *changeset*:
5689 # shows a working directory parent *changeset*:
5740 # i18n: column positioning for "hg summary"
5690 # i18n: column positioning for "hg summary"
5741 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5691 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5742 label='log.changeset changeset.%s' % p.phasestr())
5692 label='log.changeset changeset.%s' % p.phasestr())
5743 ui.write(' '.join(p.tags()), label='log.tag')
5693 ui.write(' '.join(p.tags()), label='log.tag')
5744 if p.bookmarks():
5694 if p.bookmarks():
5745 marks.extend(p.bookmarks())
5695 marks.extend(p.bookmarks())
5746 if p.rev() == -1:
5696 if p.rev() == -1:
5747 if not len(repo):
5697 if not len(repo):
5748 ui.write(_(' (empty repository)'))
5698 ui.write(_(' (empty repository)'))
5749 else:
5699 else:
5750 ui.write(_(' (no revision checked out)'))
5700 ui.write(_(' (no revision checked out)'))
5751 ui.write('\n')
5701 ui.write('\n')
5752 if p.description():
5702 if p.description():
5753 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5703 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5754 label='log.summary')
5704 label='log.summary')
5755
5705
5756 branch = ctx.branch()
5706 branch = ctx.branch()
5757 bheads = repo.branchheads(branch)
5707 bheads = repo.branchheads(branch)
5758 # i18n: column positioning for "hg summary"
5708 # i18n: column positioning for "hg summary"
5759 m = _('branch: %s\n') % branch
5709 m = _('branch: %s\n') % branch
5760 if branch != 'default':
5710 if branch != 'default':
5761 ui.write(m, label='log.branch')
5711 ui.write(m, label='log.branch')
5762 else:
5712 else:
5763 ui.status(m, label='log.branch')
5713 ui.status(m, label='log.branch')
5764
5714
5765 if marks:
5715 if marks:
5766 current = repo._bookmarkcurrent
5716 current = repo._bookmarkcurrent
5767 # i18n: column positioning for "hg summary"
5717 # i18n: column positioning for "hg summary"
5768 ui.write(_('bookmarks:'), label='log.bookmark')
5718 ui.write(_('bookmarks:'), label='log.bookmark')
5769 if current is not None:
5719 if current is not None:
5770 if current in marks:
5720 if current in marks:
5771 ui.write(' *' + current, label='bookmarks.current')
5721 ui.write(' *' + current, label='bookmarks.current')
5772 marks.remove(current)
5722 marks.remove(current)
5773 else:
5723 else:
5774 ui.write(' [%s]' % current, label='bookmarks.current')
5724 ui.write(' [%s]' % current, label='bookmarks.current')
5775 for m in marks:
5725 for m in marks:
5776 ui.write(' ' + m, label='log.bookmark')
5726 ui.write(' ' + m, label='log.bookmark')
5777 ui.write('\n', label='log.bookmark')
5727 ui.write('\n', label='log.bookmark')
5778
5728
5779 status = repo.status(unknown=True)
5729 status = repo.status(unknown=True)
5780
5730
5781 c = repo.dirstate.copies()
5731 c = repo.dirstate.copies()
5782 copied, renamed = [], []
5732 copied, renamed = [], []
5783 for d, s in c.iteritems():
5733 for d, s in c.iteritems():
5784 if s in status.removed:
5734 if s in status.removed:
5785 status.removed.remove(s)
5735 status.removed.remove(s)
5786 renamed.append(d)
5736 renamed.append(d)
5787 else:
5737 else:
5788 copied.append(d)
5738 copied.append(d)
5789 if d in status.added:
5739 if d in status.added:
5790 status.added.remove(d)
5740 status.added.remove(d)
5791
5741
5792 ms = mergemod.mergestate(repo)
5742 ms = mergemod.mergestate(repo)
5793 unresolved = [f for f in ms if ms[f] == 'u']
5743 unresolved = [f for f in ms if ms[f] == 'u']
5794
5744
5795 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5745 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5796
5746
5797 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5747 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5798 (ui.label(_('%d added'), 'status.added'), status.added),
5748 (ui.label(_('%d added'), 'status.added'), status.added),
5799 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5749 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5800 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5750 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5801 (ui.label(_('%d copied'), 'status.copied'), copied),
5751 (ui.label(_('%d copied'), 'status.copied'), copied),
5802 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5752 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5803 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5753 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5804 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5754 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5805 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5755 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5806 t = []
5756 t = []
5807 for l, s in labels:
5757 for l, s in labels:
5808 if s:
5758 if s:
5809 t.append(l % len(s))
5759 t.append(l % len(s))
5810
5760
5811 t = ', '.join(t)
5761 t = ', '.join(t)
5812 cleanworkdir = False
5762 cleanworkdir = False
5813
5763
5814 if repo.vfs.exists('updatestate'):
5764 if repo.vfs.exists('updatestate'):
5815 t += _(' (interrupted update)')
5765 t += _(' (interrupted update)')
5816 elif len(parents) > 1:
5766 elif len(parents) > 1:
5817 t += _(' (merge)')
5767 t += _(' (merge)')
5818 elif branch != parents[0].branch():
5768 elif branch != parents[0].branch():
5819 t += _(' (new branch)')
5769 t += _(' (new branch)')
5820 elif (parents[0].closesbranch() and
5770 elif (parents[0].closesbranch() and
5821 pnode in repo.branchheads(branch, closed=True)):
5771 pnode in repo.branchheads(branch, closed=True)):
5822 t += _(' (head closed)')
5772 t += _(' (head closed)')
5823 elif not (status.modified or status.added or status.removed or renamed or
5773 elif not (status.modified or status.added or status.removed or renamed or
5824 copied or subs):
5774 copied or subs):
5825 t += _(' (clean)')
5775 t += _(' (clean)')
5826 cleanworkdir = True
5776 cleanworkdir = True
5827 elif pnode not in bheads:
5777 elif pnode not in bheads:
5828 t += _(' (new branch head)')
5778 t += _(' (new branch head)')
5829
5779
5830 if cleanworkdir:
5780 if cleanworkdir:
5831 # i18n: column positioning for "hg summary"
5781 # i18n: column positioning for "hg summary"
5832 ui.status(_('commit: %s\n') % t.strip())
5782 ui.status(_('commit: %s\n') % t.strip())
5833 else:
5783 else:
5834 # i18n: column positioning for "hg summary"
5784 # i18n: column positioning for "hg summary"
5835 ui.write(_('commit: %s\n') % t.strip())
5785 ui.write(_('commit: %s\n') % t.strip())
5836
5786
5837 # all ancestors of branch heads - all ancestors of parent = new csets
5787 # all ancestors of branch heads - all ancestors of parent = new csets
5838 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5788 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5839 bheads))
5789 bheads))
5840
5790
5841 if new == 0:
5791 if new == 0:
5842 # i18n: column positioning for "hg summary"
5792 # i18n: column positioning for "hg summary"
5843 ui.status(_('update: (current)\n'))
5793 ui.status(_('update: (current)\n'))
5844 elif pnode not in bheads:
5794 elif pnode not in bheads:
5845 # i18n: column positioning for "hg summary"
5795 # i18n: column positioning for "hg summary"
5846 ui.write(_('update: %d new changesets (update)\n') % new)
5796 ui.write(_('update: %d new changesets (update)\n') % new)
5847 else:
5797 else:
5848 # i18n: column positioning for "hg summary"
5798 # i18n: column positioning for "hg summary"
5849 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5799 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5850 (new, len(bheads)))
5800 (new, len(bheads)))
5851
5801
5852 cmdutil.summaryhooks(ui, repo)
5802 cmdutil.summaryhooks(ui, repo)
5853
5803
5854 if opts.get('remote'):
5804 if opts.get('remote'):
5855 needsincoming, needsoutgoing = True, True
5805 needsincoming, needsoutgoing = True, True
5856 else:
5806 else:
5857 needsincoming, needsoutgoing = False, False
5807 needsincoming, needsoutgoing = False, False
5858 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5808 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5859 if i:
5809 if i:
5860 needsincoming = True
5810 needsincoming = True
5861 if o:
5811 if o:
5862 needsoutgoing = True
5812 needsoutgoing = True
5863 if not needsincoming and not needsoutgoing:
5813 if not needsincoming and not needsoutgoing:
5864 return
5814 return
5865
5815
5866 def getincoming():
5816 def getincoming():
5867 source, branches = hg.parseurl(ui.expandpath('default'))
5817 source, branches = hg.parseurl(ui.expandpath('default'))
5868 sbranch = branches[0]
5818 sbranch = branches[0]
5869 try:
5819 try:
5870 other = hg.peer(repo, {}, source)
5820 other = hg.peer(repo, {}, source)
5871 except error.RepoError:
5821 except error.RepoError:
5872 if opts.get('remote'):
5822 if opts.get('remote'):
5873 raise
5823 raise
5874 return source, sbranch, None, None, None
5824 return source, sbranch, None, None, None
5875 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5825 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5876 if revs:
5826 if revs:
5877 revs = [other.lookup(rev) for rev in revs]
5827 revs = [other.lookup(rev) for rev in revs]
5878 ui.debug('comparing with %s\n' % util.hidepassword(source))
5828 ui.debug('comparing with %s\n' % util.hidepassword(source))
5879 repo.ui.pushbuffer()
5829 repo.ui.pushbuffer()
5880 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5830 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5881 repo.ui.popbuffer()
5831 repo.ui.popbuffer()
5882 return source, sbranch, other, commoninc, commoninc[1]
5832 return source, sbranch, other, commoninc, commoninc[1]
5883
5833
5884 if needsincoming:
5834 if needsincoming:
5885 source, sbranch, sother, commoninc, incoming = getincoming()
5835 source, sbranch, sother, commoninc, incoming = getincoming()
5886 else:
5836 else:
5887 source = sbranch = sother = commoninc = incoming = None
5837 source = sbranch = sother = commoninc = incoming = None
5888
5838
5889 def getoutgoing():
5839 def getoutgoing():
5890 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5840 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5891 dbranch = branches[0]
5841 dbranch = branches[0]
5892 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5842 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5893 if source != dest:
5843 if source != dest:
5894 try:
5844 try:
5895 dother = hg.peer(repo, {}, dest)
5845 dother = hg.peer(repo, {}, dest)
5896 except error.RepoError:
5846 except error.RepoError:
5897 if opts.get('remote'):
5847 if opts.get('remote'):
5898 raise
5848 raise
5899 return dest, dbranch, None, None
5849 return dest, dbranch, None, None
5900 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5850 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5901 elif sother is None:
5851 elif sother is None:
5902 # there is no explicit destination peer, but source one is invalid
5852 # there is no explicit destination peer, but source one is invalid
5903 return dest, dbranch, None, None
5853 return dest, dbranch, None, None
5904 else:
5854 else:
5905 dother = sother
5855 dother = sother
5906 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5856 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5907 common = None
5857 common = None
5908 else:
5858 else:
5909 common = commoninc
5859 common = commoninc
5910 if revs:
5860 if revs:
5911 revs = [repo.lookup(rev) for rev in revs]
5861 revs = [repo.lookup(rev) for rev in revs]
5912 repo.ui.pushbuffer()
5862 repo.ui.pushbuffer()
5913 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5863 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5914 commoninc=common)
5864 commoninc=common)
5915 repo.ui.popbuffer()
5865 repo.ui.popbuffer()
5916 return dest, dbranch, dother, outgoing
5866 return dest, dbranch, dother, outgoing
5917
5867
5918 if needsoutgoing:
5868 if needsoutgoing:
5919 dest, dbranch, dother, outgoing = getoutgoing()
5869 dest, dbranch, dother, outgoing = getoutgoing()
5920 else:
5870 else:
5921 dest = dbranch = dother = outgoing = None
5871 dest = dbranch = dother = outgoing = None
5922
5872
5923 if opts.get('remote'):
5873 if opts.get('remote'):
5924 t = []
5874 t = []
5925 if incoming:
5875 if incoming:
5926 t.append(_('1 or more incoming'))
5876 t.append(_('1 or more incoming'))
5927 o = outgoing.missing
5877 o = outgoing.missing
5928 if o:
5878 if o:
5929 t.append(_('%d outgoing') % len(o))
5879 t.append(_('%d outgoing') % len(o))
5930 other = dother or sother
5880 other = dother or sother
5931 if 'bookmarks' in other.listkeys('namespaces'):
5881 if 'bookmarks' in other.listkeys('namespaces'):
5932 lmarks = repo.listkeys('bookmarks')
5882 lmarks = repo.listkeys('bookmarks')
5933 rmarks = other.listkeys('bookmarks')
5883 rmarks = other.listkeys('bookmarks')
5934 diff = set(rmarks) - set(lmarks)
5884 diff = set(rmarks) - set(lmarks)
5935 if len(diff) > 0:
5885 if len(diff) > 0:
5936 t.append(_('%d incoming bookmarks') % len(diff))
5886 t.append(_('%d incoming bookmarks') % len(diff))
5937 diff = set(lmarks) - set(rmarks)
5887 diff = set(lmarks) - set(rmarks)
5938 if len(diff) > 0:
5888 if len(diff) > 0:
5939 t.append(_('%d outgoing bookmarks') % len(diff))
5889 t.append(_('%d outgoing bookmarks') % len(diff))
5940
5890
5941 if t:
5891 if t:
5942 # i18n: column positioning for "hg summary"
5892 # i18n: column positioning for "hg summary"
5943 ui.write(_('remote: %s\n') % (', '.join(t)))
5893 ui.write(_('remote: %s\n') % (', '.join(t)))
5944 else:
5894 else:
5945 # i18n: column positioning for "hg summary"
5895 # i18n: column positioning for "hg summary"
5946 ui.status(_('remote: (synced)\n'))
5896 ui.status(_('remote: (synced)\n'))
5947
5897
5948 cmdutil.summaryremotehooks(ui, repo, opts,
5898 cmdutil.summaryremotehooks(ui, repo, opts,
5949 ((source, sbranch, sother, commoninc),
5899 ((source, sbranch, sother, commoninc),
5950 (dest, dbranch, dother, outgoing)))
5900 (dest, dbranch, dother, outgoing)))
5951
5901
5952 @command('tag',
5902 @command('tag',
5953 [('f', 'force', None, _('force tag')),
5903 [('f', 'force', None, _('force tag')),
5954 ('l', 'local', None, _('make the tag local')),
5904 ('l', 'local', None, _('make the tag local')),
5955 ('r', 'rev', '', _('revision to tag'), _('REV')),
5905 ('r', 'rev', '', _('revision to tag'), _('REV')),
5956 ('', 'remove', None, _('remove a tag')),
5906 ('', 'remove', None, _('remove a tag')),
5957 # -l/--local is already there, commitopts cannot be used
5907 # -l/--local is already there, commitopts cannot be used
5958 ('e', 'edit', None, _('invoke editor on commit messages')),
5908 ('e', 'edit', None, _('invoke editor on commit messages')),
5959 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5909 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5960 ] + commitopts2,
5910 ] + commitopts2,
5961 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5911 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5962 def tag(ui, repo, name1, *names, **opts):
5912 def tag(ui, repo, name1, *names, **opts):
5963 """add one or more tags for the current or given revision
5913 """add one or more tags for the current or given revision
5964
5914
5965 Name a particular revision using <name>.
5915 Name a particular revision using <name>.
5966
5916
5967 Tags are used to name particular revisions of the repository and are
5917 Tags are used to name particular revisions of the repository and are
5968 very useful to compare different revisions, to go back to significant
5918 very useful to compare different revisions, to go back to significant
5969 earlier versions or to mark branch points as releases, etc. Changing
5919 earlier versions or to mark branch points as releases, etc. Changing
5970 an existing tag is normally disallowed; use -f/--force to override.
5920 an existing tag is normally disallowed; use -f/--force to override.
5971
5921
5972 If no revision is given, the parent of the working directory is
5922 If no revision is given, the parent of the working directory is
5973 used.
5923 used.
5974
5924
5975 To facilitate version control, distribution, and merging of tags,
5925 To facilitate version control, distribution, and merging of tags,
5976 they are stored as a file named ".hgtags" which is managed similarly
5926 they are stored as a file named ".hgtags" which is managed similarly
5977 to other project files and can be hand-edited if necessary. This
5927 to other project files and can be hand-edited if necessary. This
5978 also means that tagging creates a new commit. The file
5928 also means that tagging creates a new commit. The file
5979 ".hg/localtags" is used for local tags (not shared among
5929 ".hg/localtags" is used for local tags (not shared among
5980 repositories).
5930 repositories).
5981
5931
5982 Tag commits are usually made at the head of a branch. If the parent
5932 Tag commits are usually made at the head of a branch. If the parent
5983 of the working directory is not a branch head, :hg:`tag` aborts; use
5933 of the working directory is not a branch head, :hg:`tag` aborts; use
5984 -f/--force to force the tag commit to be based on a non-head
5934 -f/--force to force the tag commit to be based on a non-head
5985 changeset.
5935 changeset.
5986
5936
5987 See :hg:`help dates` for a list of formats valid for -d/--date.
5937 See :hg:`help dates` for a list of formats valid for -d/--date.
5988
5938
5989 Since tag names have priority over branch names during revision
5939 Since tag names have priority over branch names during revision
5990 lookup, using an existing branch name as a tag name is discouraged.
5940 lookup, using an existing branch name as a tag name is discouraged.
5991
5941
5992 Returns 0 on success.
5942 Returns 0 on success.
5993 """
5943 """
5994 wlock = lock = None
5944 wlock = lock = None
5995 try:
5945 try:
5996 wlock = repo.wlock()
5946 wlock = repo.wlock()
5997 lock = repo.lock()
5947 lock = repo.lock()
5998 rev_ = "."
5948 rev_ = "."
5999 names = [t.strip() for t in (name1,) + names]
5949 names = [t.strip() for t in (name1,) + names]
6000 if len(names) != len(set(names)):
5950 if len(names) != len(set(names)):
6001 raise util.Abort(_('tag names must be unique'))
5951 raise util.Abort(_('tag names must be unique'))
6002 for n in names:
5952 for n in names:
6003 scmutil.checknewlabel(repo, n, 'tag')
5953 scmutil.checknewlabel(repo, n, 'tag')
6004 if not n:
5954 if not n:
6005 raise util.Abort(_('tag names cannot consist entirely of '
5955 raise util.Abort(_('tag names cannot consist entirely of '
6006 'whitespace'))
5956 'whitespace'))
6007 if opts.get('rev') and opts.get('remove'):
5957 if opts.get('rev') and opts.get('remove'):
6008 raise util.Abort(_("--rev and --remove are incompatible"))
5958 raise util.Abort(_("--rev and --remove are incompatible"))
6009 if opts.get('rev'):
5959 if opts.get('rev'):
6010 rev_ = opts['rev']
5960 rev_ = opts['rev']
6011 message = opts.get('message')
5961 message = opts.get('message')
6012 if opts.get('remove'):
5962 if opts.get('remove'):
6013 expectedtype = opts.get('local') and 'local' or 'global'
5963 expectedtype = opts.get('local') and 'local' or 'global'
6014 for n in names:
5964 for n in names:
6015 if not repo.tagtype(n):
5965 if not repo.tagtype(n):
6016 raise util.Abort(_("tag '%s' does not exist") % n)
5966 raise util.Abort(_("tag '%s' does not exist") % n)
6017 if repo.tagtype(n) != expectedtype:
5967 if repo.tagtype(n) != expectedtype:
6018 if expectedtype == 'global':
5968 if expectedtype == 'global':
6019 raise util.Abort(_("tag '%s' is not a global tag") % n)
5969 raise util.Abort(_("tag '%s' is not a global tag") % n)
6020 else:
5970 else:
6021 raise util.Abort(_("tag '%s' is not a local tag") % n)
5971 raise util.Abort(_("tag '%s' is not a local tag") % n)
6022 rev_ = nullid
5972 rev_ = nullid
6023 if not message:
5973 if not message:
6024 # we don't translate commit messages
5974 # we don't translate commit messages
6025 message = 'Removed tag %s' % ', '.join(names)
5975 message = 'Removed tag %s' % ', '.join(names)
6026 elif not opts.get('force'):
5976 elif not opts.get('force'):
6027 for n in names:
5977 for n in names:
6028 if n in repo.tags():
5978 if n in repo.tags():
6029 raise util.Abort(_("tag '%s' already exists "
5979 raise util.Abort(_("tag '%s' already exists "
6030 "(use -f to force)") % n)
5980 "(use -f to force)") % n)
6031 if not opts.get('local'):
5981 if not opts.get('local'):
6032 p1, p2 = repo.dirstate.parents()
5982 p1, p2 = repo.dirstate.parents()
6033 if p2 != nullid:
5983 if p2 != nullid:
6034 raise util.Abort(_('uncommitted merge'))
5984 raise util.Abort(_('uncommitted merge'))
6035 bheads = repo.branchheads()
5985 bheads = repo.branchheads()
6036 if not opts.get('force') and bheads and p1 not in bheads:
5986 if not opts.get('force') and bheads and p1 not in bheads:
6037 raise util.Abort(_('not at a branch head (use -f to force)'))
5987 raise util.Abort(_('not at a branch head (use -f to force)'))
6038 r = scmutil.revsingle(repo, rev_).node()
5988 r = scmutil.revsingle(repo, rev_).node()
6039
5989
6040 if not message:
5990 if not message:
6041 # we don't translate commit messages
5991 # we don't translate commit messages
6042 message = ('Added tag %s for changeset %s' %
5992 message = ('Added tag %s for changeset %s' %
6043 (', '.join(names), short(r)))
5993 (', '.join(names), short(r)))
6044
5994
6045 date = opts.get('date')
5995 date = opts.get('date')
6046 if date:
5996 if date:
6047 date = util.parsedate(date)
5997 date = util.parsedate(date)
6048
5998
6049 if opts.get('remove'):
5999 if opts.get('remove'):
6050 editform = 'tag.remove'
6000 editform = 'tag.remove'
6051 else:
6001 else:
6052 editform = 'tag.add'
6002 editform = 'tag.add'
6053 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6003 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6054
6004
6055 # don't allow tagging the null rev
6005 # don't allow tagging the null rev
6056 if (not opts.get('remove') and
6006 if (not opts.get('remove') and
6057 scmutil.revsingle(repo, rev_).rev() == nullrev):
6007 scmutil.revsingle(repo, rev_).rev() == nullrev):
6058 raise util.Abort(_("cannot tag null revision"))
6008 raise util.Abort(_("cannot tag null revision"))
6059
6009
6060 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6010 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6061 editor=editor)
6011 editor=editor)
6062 finally:
6012 finally:
6063 release(lock, wlock)
6013 release(lock, wlock)
6064
6014
6065 @command('tags', formatteropts, '')
6015 @command('tags', formatteropts, '')
6066 def tags(ui, repo, **opts):
6016 def tags(ui, repo, **opts):
6067 """list repository tags
6017 """list repository tags
6068
6018
6069 This lists both regular and local tags. When the -v/--verbose
6019 This lists both regular and local tags. When the -v/--verbose
6070 switch is used, a third column "local" is printed for local tags.
6020 switch is used, a third column "local" is printed for local tags.
6071
6021
6072 Returns 0 on success.
6022 Returns 0 on success.
6073 """
6023 """
6074
6024
6075 fm = ui.formatter('tags', opts)
6025 fm = ui.formatter('tags', opts)
6076 hexfunc = fm.hexfunc
6026 hexfunc = fm.hexfunc
6077 tagtype = ""
6027 tagtype = ""
6078
6028
6079 for t, n in reversed(repo.tagslist()):
6029 for t, n in reversed(repo.tagslist()):
6080 hn = hexfunc(n)
6030 hn = hexfunc(n)
6081 label = 'tags.normal'
6031 label = 'tags.normal'
6082 tagtype = ''
6032 tagtype = ''
6083 if repo.tagtype(t) == 'local':
6033 if repo.tagtype(t) == 'local':
6084 label = 'tags.local'
6034 label = 'tags.local'
6085 tagtype = 'local'
6035 tagtype = 'local'
6086
6036
6087 fm.startitem()
6037 fm.startitem()
6088 fm.write('tag', '%s', t, label=label)
6038 fm.write('tag', '%s', t, label=label)
6089 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6039 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6090 fm.condwrite(not ui.quiet, 'rev node', fmt,
6040 fm.condwrite(not ui.quiet, 'rev node', fmt,
6091 repo.changelog.rev(n), hn, label=label)
6041 repo.changelog.rev(n), hn, label=label)
6092 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6042 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6093 tagtype, label=label)
6043 tagtype, label=label)
6094 fm.plain('\n')
6044 fm.plain('\n')
6095 fm.end()
6045 fm.end()
6096
6046
6097 @command('tip',
6047 @command('tip',
6098 [('p', 'patch', None, _('show patch')),
6048 [('p', 'patch', None, _('show patch')),
6099 ('g', 'git', None, _('use git extended diff format')),
6049 ('g', 'git', None, _('use git extended diff format')),
6100 ] + templateopts,
6050 ] + templateopts,
6101 _('[-p] [-g]'))
6051 _('[-p] [-g]'))
6102 def tip(ui, repo, **opts):
6052 def tip(ui, repo, **opts):
6103 """show the tip revision (DEPRECATED)
6053 """show the tip revision (DEPRECATED)
6104
6054
6105 The tip revision (usually just called the tip) is the changeset
6055 The tip revision (usually just called the tip) is the changeset
6106 most recently added to the repository (and therefore the most
6056 most recently added to the repository (and therefore the most
6107 recently changed head).
6057 recently changed head).
6108
6058
6109 If you have just made a commit, that commit will be the tip. If
6059 If you have just made a commit, that commit will be the tip. If
6110 you have just pulled changes from another repository, the tip of
6060 you have just pulled changes from another repository, the tip of
6111 that repository becomes the current tip. The "tip" tag is special
6061 that repository becomes the current tip. The "tip" tag is special
6112 and cannot be renamed or assigned to a different changeset.
6062 and cannot be renamed or assigned to a different changeset.
6113
6063
6114 This command is deprecated, please use :hg:`heads` instead.
6064 This command is deprecated, please use :hg:`heads` instead.
6115
6065
6116 Returns 0 on success.
6066 Returns 0 on success.
6117 """
6067 """
6118 displayer = cmdutil.show_changeset(ui, repo, opts)
6068 displayer = cmdutil.show_changeset(ui, repo, opts)
6119 displayer.show(repo['tip'])
6069 displayer.show(repo['tip'])
6120 displayer.close()
6070 displayer.close()
6121
6071
6122 @command('unbundle',
6072 @command('unbundle',
6123 [('u', 'update', None,
6073 [('u', 'update', None,
6124 _('update to new branch head if changesets were unbundled'))],
6074 _('update to new branch head if changesets were unbundled'))],
6125 _('[-u] FILE...'))
6075 _('[-u] FILE...'))
6126 def unbundle(ui, repo, fname1, *fnames, **opts):
6076 def unbundle(ui, repo, fname1, *fnames, **opts):
6127 """apply one or more changegroup files
6077 """apply one or more changegroup files
6128
6078
6129 Apply one or more compressed changegroup files generated by the
6079 Apply one or more compressed changegroup files generated by the
6130 bundle command.
6080 bundle command.
6131
6081
6132 Returns 0 on success, 1 if an update has unresolved files.
6082 Returns 0 on success, 1 if an update has unresolved files.
6133 """
6083 """
6134 fnames = (fname1,) + fnames
6084 fnames = (fname1,) + fnames
6135
6085
6136 lock = repo.lock()
6086 lock = repo.lock()
6137 try:
6087 try:
6138 for fname in fnames:
6088 for fname in fnames:
6139 f = hg.openpath(ui, fname)
6089 f = hg.openpath(ui, fname)
6140 gen = exchange.readbundle(ui, f, fname)
6090 gen = exchange.readbundle(ui, f, fname)
6141 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6091 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6142 'bundle:' + fname)
6092 'bundle:' + fname)
6143 finally:
6093 finally:
6144 lock.release()
6094 lock.release()
6145
6095
6146 return postincoming(ui, repo, modheads, opts.get('update'), None)
6096 return postincoming(ui, repo, modheads, opts.get('update'), None)
6147
6097
6148 @command('^update|up|checkout|co',
6098 @command('^update|up|checkout|co',
6149 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6099 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6150 ('c', 'check', None,
6100 ('c', 'check', None,
6151 _('update across branches if no uncommitted changes')),
6101 _('update across branches if no uncommitted changes')),
6152 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6102 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6153 ('r', 'rev', '', _('revision'), _('REV'))
6103 ('r', 'rev', '', _('revision'), _('REV'))
6154 ] + mergetoolopts,
6104 ] + mergetoolopts,
6155 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6105 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6156 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6106 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6157 tool=None):
6107 tool=None):
6158 """update working directory (or switch revisions)
6108 """update working directory (or switch revisions)
6159
6109
6160 Update the repository's working directory to the specified
6110 Update the repository's working directory to the specified
6161 changeset. If no changeset is specified, update to the tip of the
6111 changeset. If no changeset is specified, update to the tip of the
6162 current named branch and move the current bookmark (see :hg:`help
6112 current named branch and move the current bookmark (see :hg:`help
6163 bookmarks`).
6113 bookmarks`).
6164
6114
6165 Update sets the working directory's parent revision to the specified
6115 Update sets the working directory's parent revision to the specified
6166 changeset (see :hg:`help parents`).
6116 changeset (see :hg:`help parents`).
6167
6117
6168 If the changeset is not a descendant or ancestor of the working
6118 If the changeset is not a descendant or ancestor of the working
6169 directory's parent, the update is aborted. With the -c/--check
6119 directory's parent, the update is aborted. With the -c/--check
6170 option, the working directory is checked for uncommitted changes; if
6120 option, the working directory is checked for uncommitted changes; if
6171 none are found, the working directory is updated to the specified
6121 none are found, the working directory is updated to the specified
6172 changeset.
6122 changeset.
6173
6123
6174 .. container:: verbose
6124 .. container:: verbose
6175
6125
6176 The following rules apply when the working directory contains
6126 The following rules apply when the working directory contains
6177 uncommitted changes:
6127 uncommitted changes:
6178
6128
6179 1. If neither -c/--check nor -C/--clean is specified, and if
6129 1. If neither -c/--check nor -C/--clean is specified, and if
6180 the requested changeset is an ancestor or descendant of
6130 the requested changeset is an ancestor or descendant of
6181 the working directory's parent, the uncommitted changes
6131 the working directory's parent, the uncommitted changes
6182 are merged into the requested changeset and the merged
6132 are merged into the requested changeset and the merged
6183 result is left uncommitted. If the requested changeset is
6133 result is left uncommitted. If the requested changeset is
6184 not an ancestor or descendant (that is, it is on another
6134 not an ancestor or descendant (that is, it is on another
6185 branch), the update is aborted and the uncommitted changes
6135 branch), the update is aborted and the uncommitted changes
6186 are preserved.
6136 are preserved.
6187
6137
6188 2. With the -c/--check option, the update is aborted and the
6138 2. With the -c/--check option, the update is aborted and the
6189 uncommitted changes are preserved.
6139 uncommitted changes are preserved.
6190
6140
6191 3. With the -C/--clean option, uncommitted changes are discarded and
6141 3. With the -C/--clean option, uncommitted changes are discarded and
6192 the working directory is updated to the requested changeset.
6142 the working directory is updated to the requested changeset.
6193
6143
6194 To cancel an uncommitted merge (and lose your changes), use
6144 To cancel an uncommitted merge (and lose your changes), use
6195 :hg:`update --clean .`.
6145 :hg:`update --clean .`.
6196
6146
6197 Use null as the changeset to remove the working directory (like
6147 Use null as the changeset to remove the working directory (like
6198 :hg:`clone -U`).
6148 :hg:`clone -U`).
6199
6149
6200 If you want to revert just one file to an older revision, use
6150 If you want to revert just one file to an older revision, use
6201 :hg:`revert [-r REV] NAME`.
6151 :hg:`revert [-r REV] NAME`.
6202
6152
6203 See :hg:`help dates` for a list of formats valid for -d/--date.
6153 See :hg:`help dates` for a list of formats valid for -d/--date.
6204
6154
6205 Returns 0 on success, 1 if there are unresolved files.
6155 Returns 0 on success, 1 if there are unresolved files.
6206 """
6156 """
6207 if rev and node:
6157 if rev and node:
6208 raise util.Abort(_("please specify just one revision"))
6158 raise util.Abort(_("please specify just one revision"))
6209
6159
6210 if rev is None or rev == '':
6160 if rev is None or rev == '':
6211 rev = node
6161 rev = node
6212
6162
6213 cmdutil.clearunfinished(repo)
6163 cmdutil.clearunfinished(repo)
6214
6164
6215 # with no argument, we also move the current bookmark, if any
6165 # with no argument, we also move the current bookmark, if any
6216 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6166 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6217
6167
6218 # if we defined a bookmark, we have to remember the original bookmark name
6168 # if we defined a bookmark, we have to remember the original bookmark name
6219 brev = rev
6169 brev = rev
6220 rev = scmutil.revsingle(repo, rev, rev).rev()
6170 rev = scmutil.revsingle(repo, rev, rev).rev()
6221
6171
6222 if check and clean:
6172 if check and clean:
6223 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6173 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6224
6174
6225 if date:
6175 if date:
6226 if rev is not None:
6176 if rev is not None:
6227 raise util.Abort(_("you can't specify a revision and a date"))
6177 raise util.Abort(_("you can't specify a revision and a date"))
6228 rev = cmdutil.finddate(ui, repo, date)
6178 rev = cmdutil.finddate(ui, repo, date)
6229
6179
6230 if check:
6180 if check:
6231 c = repo[None]
6181 c = repo[None]
6232 if c.dirty(merge=False, branch=False, missing=True):
6182 if c.dirty(merge=False, branch=False, missing=True):
6233 raise util.Abort(_("uncommitted changes"))
6183 raise util.Abort(_("uncommitted changes"))
6234 if rev is None:
6184 if rev is None:
6235 rev = repo[repo[None].branch()].rev()
6185 rev = repo[repo[None].branch()].rev()
6236 mergemod._checkunknown(repo, repo[None], repo[rev])
6186 mergemod._checkunknown(repo, repo[None], repo[rev])
6237
6187
6238 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6188 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6239
6189
6240 if clean:
6190 if clean:
6241 ret = hg.clean(repo, rev)
6191 ret = hg.clean(repo, rev)
6242 else:
6192 else:
6243 ret = hg.update(repo, rev)
6193 ret = hg.update(repo, rev)
6244
6194
6245 if not ret and movemarkfrom:
6195 if not ret and movemarkfrom:
6246 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6196 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6247 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6197 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6248 elif brev in repo._bookmarks:
6198 elif brev in repo._bookmarks:
6249 bookmarks.setcurrent(repo, brev)
6199 bookmarks.setcurrent(repo, brev)
6250 ui.status(_("(activating bookmark %s)\n") % brev)
6200 ui.status(_("(activating bookmark %s)\n") % brev)
6251 elif brev:
6201 elif brev:
6252 if repo._bookmarkcurrent:
6202 if repo._bookmarkcurrent:
6253 ui.status(_("(leaving bookmark %s)\n") %
6203 ui.status(_("(leaving bookmark %s)\n") %
6254 repo._bookmarkcurrent)
6204 repo._bookmarkcurrent)
6255 bookmarks.unsetcurrent(repo)
6205 bookmarks.unsetcurrent(repo)
6256
6206
6257 return ret
6207 return ret
6258
6208
6259 @command('verify', [])
6209 @command('verify', [])
6260 def verify(ui, repo):
6210 def verify(ui, repo):
6261 """verify the integrity of the repository
6211 """verify the integrity of the repository
6262
6212
6263 Verify the integrity of the current repository.
6213 Verify the integrity of the current repository.
6264
6214
6265 This will perform an extensive check of the repository's
6215 This will perform an extensive check of the repository's
6266 integrity, validating the hashes and checksums of each entry in
6216 integrity, validating the hashes and checksums of each entry in
6267 the changelog, manifest, and tracked files, as well as the
6217 the changelog, manifest, and tracked files, as well as the
6268 integrity of their crosslinks and indices.
6218 integrity of their crosslinks and indices.
6269
6219
6270 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6220 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6271 for more information about recovery from corruption of the
6221 for more information about recovery from corruption of the
6272 repository.
6222 repository.
6273
6223
6274 Returns 0 on success, 1 if errors are encountered.
6224 Returns 0 on success, 1 if errors are encountered.
6275 """
6225 """
6276 return hg.verify(repo)
6226 return hg.verify(repo)
6277
6227
6278 @command('version', [], norepo=True)
6228 @command('version', [], norepo=True)
6279 def version_(ui):
6229 def version_(ui):
6280 """output version and copyright information"""
6230 """output version and copyright information"""
6281 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6231 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6282 % util.version())
6232 % util.version())
6283 ui.status(_(
6233 ui.status(_(
6284 "(see http://mercurial.selenic.com for more information)\n"
6234 "(see http://mercurial.selenic.com for more information)\n"
6285 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
6235 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
6286 "This is free software; see the source for copying conditions. "
6236 "This is free software; see the source for copying conditions. "
6287 "There is NO\nwarranty; "
6237 "There is NO\nwarranty; "
6288 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6238 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6289 ))
6239 ))
6290
6240
6291 ui.note(_("\nEnabled extensions:\n\n"))
6241 ui.note(_("\nEnabled extensions:\n\n"))
6292 if ui.verbose:
6242 if ui.verbose:
6293 # format names and versions into columns
6243 # format names and versions into columns
6294 names = []
6244 names = []
6295 vers = []
6245 vers = []
6296 for name, module in extensions.extensions():
6246 for name, module in extensions.extensions():
6297 names.append(name)
6247 names.append(name)
6298 vers.append(extensions.moduleversion(module))
6248 vers.append(extensions.moduleversion(module))
6299 if names:
6249 if names:
6300 maxnamelen = max(len(n) for n in names)
6250 maxnamelen = max(len(n) for n in names)
6301 for i, name in enumerate(names):
6251 for i, name in enumerate(names):
6302 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
6252 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
General Comments 0
You need to be logged in to leave comments. Login now