##// END OF EJS Templates
remove: recurse into subrepositories with --subrepos/-S flag...
Matt Harbison -
r23325:4165cfd6 default
parent child Browse files
Show More
@@ -1,2935 +1,2958 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):
2055 def remove(ui, repo, m, prefix, after, force, subrepos):
2056 join = lambda f: os.path.join(prefix, f)
2056 ret = 0
2057 ret = 0
2057 s = repo.status(match=m, clean=True)
2058 s = repo.status(match=m, clean=True)
2058 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2059 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2059
2060
2061 wctx = repo[None]
2062
2063 if subrepos:
2064 for subpath in sorted(wctx.substate):
2065 sub = wctx.sub(subpath)
2066 try:
2067 submatch = matchmod.narrowmatcher(subpath, m)
2068 if sub.removefiles(ui, submatch, prefix, after, force,
2069 subrepos):
2070 ret = 1
2071 except error.LookupError:
2072 ui.status(_("skipping missing subrepository: %s\n")
2073 % join(subpath))
2074
2060 # warn about failure to delete explicit files/dirs
2075 # warn about failure to delete explicit files/dirs
2061 wctx = repo[None]
2062 for f in m.files():
2076 for f in m.files():
2063 if f in repo.dirstate or f in wctx.dirs():
2077 def insubrepo():
2078 for subpath in wctx.substate:
2079 if f.startswith(subpath):
2080 return True
2081 return False
2082
2083 if f in repo.dirstate or f in wctx.dirs() or (subrepos and insubrepo()):
2064 continue
2084 continue
2065 if os.path.exists(m.rel(f)):
2085
2066 if os.path.isdir(m.rel(f)):
2086 if os.path.exists(m.rel(join(f))):
2067 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
2087 if os.path.isdir(m.rel(join(f))):
2088 ui.warn(_('not removing %s: no tracked files\n')
2089 % m.rel(join(f)))
2068 else:
2090 else:
2069 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2091 ui.warn(_('not removing %s: file is untracked\n')
2092 % m.rel(join(f)))
2070 # missing files will generate a warning elsewhere
2093 # missing files will generate a warning elsewhere
2071 ret = 1
2094 ret = 1
2072
2095
2073 if force:
2096 if force:
2074 list = modified + deleted + clean + added
2097 list = modified + deleted + clean + added
2075 elif after:
2098 elif after:
2076 list = deleted
2099 list = deleted
2077 for f in modified + added + clean:
2100 for f in modified + added + clean:
2078 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
2101 ui.warn(_('not removing %s: file still exists\n') % m.rel(join(f)))
2079 ret = 1
2102 ret = 1
2080 else:
2103 else:
2081 list = deleted + clean
2104 list = deleted + clean
2082 for f in modified:
2105 for f in modified:
2083 ui.warn(_('not removing %s: file is modified (use -f'
2106 ui.warn(_('not removing %s: file is modified (use -f'
2084 ' to force removal)\n') % m.rel(f))
2107 ' to force removal)\n') % m.rel(join(f)))
2085 ret = 1
2108 ret = 1
2086 for f in added:
2109 for f in added:
2087 ui.warn(_('not removing %s: file has been marked for add'
2110 ui.warn(_('not removing %s: file has been marked for add'
2088 ' (use forget to undo)\n') % m.rel(f))
2111 ' (use forget to undo)\n') % m.rel(join(f)))
2089 ret = 1
2112 ret = 1
2090
2113
2091 for f in sorted(list):
2114 for f in sorted(list):
2092 if ui.verbose or not m.exact(f):
2115 if ui.verbose or not m.exact(f):
2093 ui.status(_('removing %s\n') % m.rel(f))
2116 ui.status(_('removing %s\n') % m.rel(join(f)))
2094
2117
2095 wlock = repo.wlock()
2118 wlock = repo.wlock()
2096 try:
2119 try:
2097 if not after:
2120 if not after:
2098 for f in list:
2121 for f in list:
2099 if f in added:
2122 if f in added:
2100 continue # we never unlink added files on remove
2123 continue # we never unlink added files on remove
2101 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
2124 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
2102 repo[None].forget(list)
2125 repo[None].forget(list)
2103 finally:
2126 finally:
2104 wlock.release()
2127 wlock.release()
2105
2128
2106 return ret
2129 return ret
2107
2130
2108 def cat(ui, repo, ctx, matcher, prefix, **opts):
2131 def cat(ui, repo, ctx, matcher, prefix, **opts):
2109 err = 1
2132 err = 1
2110
2133
2111 def write(path):
2134 def write(path):
2112 fp = makefileobj(repo, opts.get('output'), ctx.node(),
2135 fp = makefileobj(repo, opts.get('output'), ctx.node(),
2113 pathname=os.path.join(prefix, path))
2136 pathname=os.path.join(prefix, path))
2114 data = ctx[path].data()
2137 data = ctx[path].data()
2115 if opts.get('decode'):
2138 if opts.get('decode'):
2116 data = repo.wwritedata(path, data)
2139 data = repo.wwritedata(path, data)
2117 fp.write(data)
2140 fp.write(data)
2118 fp.close()
2141 fp.close()
2119
2142
2120 # Automation often uses hg cat on single files, so special case it
2143 # Automation often uses hg cat on single files, so special case it
2121 # for performance to avoid the cost of parsing the manifest.
2144 # for performance to avoid the cost of parsing the manifest.
2122 if len(matcher.files()) == 1 and not matcher.anypats():
2145 if len(matcher.files()) == 1 and not matcher.anypats():
2123 file = matcher.files()[0]
2146 file = matcher.files()[0]
2124 mf = repo.manifest
2147 mf = repo.manifest
2125 mfnode = ctx._changeset[0]
2148 mfnode = ctx._changeset[0]
2126 if mf.find(mfnode, file)[0]:
2149 if mf.find(mfnode, file)[0]:
2127 write(file)
2150 write(file)
2128 return 0
2151 return 0
2129
2152
2130 # Don't warn about "missing" files that are really in subrepos
2153 # Don't warn about "missing" files that are really in subrepos
2131 bad = matcher.bad
2154 bad = matcher.bad
2132
2155
2133 def badfn(path, msg):
2156 def badfn(path, msg):
2134 for subpath in ctx.substate:
2157 for subpath in ctx.substate:
2135 if path.startswith(subpath):
2158 if path.startswith(subpath):
2136 return
2159 return
2137 bad(path, msg)
2160 bad(path, msg)
2138
2161
2139 matcher.bad = badfn
2162 matcher.bad = badfn
2140
2163
2141 for abs in ctx.walk(matcher):
2164 for abs in ctx.walk(matcher):
2142 write(abs)
2165 write(abs)
2143 err = 0
2166 err = 0
2144
2167
2145 matcher.bad = bad
2168 matcher.bad = bad
2146
2169
2147 for subpath in sorted(ctx.substate):
2170 for subpath in sorted(ctx.substate):
2148 sub = ctx.sub(subpath)
2171 sub = ctx.sub(subpath)
2149 try:
2172 try:
2150 submatch = matchmod.narrowmatcher(subpath, matcher)
2173 submatch = matchmod.narrowmatcher(subpath, matcher)
2151
2174
2152 if not sub.cat(ui, submatch, os.path.join(prefix, sub._path),
2175 if not sub.cat(ui, submatch, os.path.join(prefix, sub._path),
2153 **opts):
2176 **opts):
2154 err = 0
2177 err = 0
2155 except error.RepoLookupError:
2178 except error.RepoLookupError:
2156 ui.status(_("skipping missing subrepository: %s\n")
2179 ui.status(_("skipping missing subrepository: %s\n")
2157 % os.path.join(prefix, subpath))
2180 % os.path.join(prefix, subpath))
2158
2181
2159 return err
2182 return err
2160
2183
2161 def commit(ui, repo, commitfunc, pats, opts):
2184 def commit(ui, repo, commitfunc, pats, opts):
2162 '''commit the specified files or all outstanding changes'''
2185 '''commit the specified files or all outstanding changes'''
2163 date = opts.get('date')
2186 date = opts.get('date')
2164 if date:
2187 if date:
2165 opts['date'] = util.parsedate(date)
2188 opts['date'] = util.parsedate(date)
2166 message = logmessage(ui, opts)
2189 message = logmessage(ui, opts)
2167
2190
2168 # extract addremove carefully -- this function can be called from a command
2191 # extract addremove carefully -- this function can be called from a command
2169 # that doesn't support addremove
2192 # that doesn't support addremove
2170 if opts.get('addremove'):
2193 if opts.get('addremove'):
2171 scmutil.addremove(repo, pats, opts)
2194 scmutil.addremove(repo, pats, opts)
2172
2195
2173 return commitfunc(ui, repo, message,
2196 return commitfunc(ui, repo, message,
2174 scmutil.match(repo[None], pats, opts), opts)
2197 scmutil.match(repo[None], pats, opts), opts)
2175
2198
2176 def amend(ui, repo, commitfunc, old, extra, pats, opts):
2199 def amend(ui, repo, commitfunc, old, extra, pats, opts):
2177 # amend will reuse the existing user if not specified, but the obsolete
2200 # amend will reuse the existing user if not specified, but the obsolete
2178 # marker creation requires that the current user's name is specified.
2201 # marker creation requires that the current user's name is specified.
2179 if obsolete._enabled:
2202 if obsolete._enabled:
2180 ui.username() # raise exception if username not set
2203 ui.username() # raise exception if username not set
2181
2204
2182 ui.note(_('amending changeset %s\n') % old)
2205 ui.note(_('amending changeset %s\n') % old)
2183 base = old.p1()
2206 base = old.p1()
2184
2207
2185 wlock = lock = newid = None
2208 wlock = lock = newid = None
2186 try:
2209 try:
2187 wlock = repo.wlock()
2210 wlock = repo.wlock()
2188 lock = repo.lock()
2211 lock = repo.lock()
2189 tr = repo.transaction('amend')
2212 tr = repo.transaction('amend')
2190 try:
2213 try:
2191 # See if we got a message from -m or -l, if not, open the editor
2214 # See if we got a message from -m or -l, if not, open the editor
2192 # with the message of the changeset to amend
2215 # with the message of the changeset to amend
2193 message = logmessage(ui, opts)
2216 message = logmessage(ui, opts)
2194 # ensure logfile does not conflict with later enforcement of the
2217 # ensure logfile does not conflict with later enforcement of the
2195 # message. potential logfile content has been processed by
2218 # message. potential logfile content has been processed by
2196 # `logmessage` anyway.
2219 # `logmessage` anyway.
2197 opts.pop('logfile')
2220 opts.pop('logfile')
2198 # First, do a regular commit to record all changes in the working
2221 # First, do a regular commit to record all changes in the working
2199 # directory (if there are any)
2222 # directory (if there are any)
2200 ui.callhooks = False
2223 ui.callhooks = False
2201 currentbookmark = repo._bookmarkcurrent
2224 currentbookmark = repo._bookmarkcurrent
2202 try:
2225 try:
2203 repo._bookmarkcurrent = None
2226 repo._bookmarkcurrent = None
2204 opts['message'] = 'temporary amend commit for %s' % old
2227 opts['message'] = 'temporary amend commit for %s' % old
2205 node = commit(ui, repo, commitfunc, pats, opts)
2228 node = commit(ui, repo, commitfunc, pats, opts)
2206 finally:
2229 finally:
2207 repo._bookmarkcurrent = currentbookmark
2230 repo._bookmarkcurrent = currentbookmark
2208 ui.callhooks = True
2231 ui.callhooks = True
2209 ctx = repo[node]
2232 ctx = repo[node]
2210
2233
2211 # Participating changesets:
2234 # Participating changesets:
2212 #
2235 #
2213 # node/ctx o - new (intermediate) commit that contains changes
2236 # node/ctx o - new (intermediate) commit that contains changes
2214 # | from working dir to go into amending commit
2237 # | from working dir to go into amending commit
2215 # | (or a workingctx if there were no changes)
2238 # | (or a workingctx if there were no changes)
2216 # |
2239 # |
2217 # old o - changeset to amend
2240 # old o - changeset to amend
2218 # |
2241 # |
2219 # base o - parent of amending changeset
2242 # base o - parent of amending changeset
2220
2243
2221 # Update extra dict from amended commit (e.g. to preserve graft
2244 # Update extra dict from amended commit (e.g. to preserve graft
2222 # source)
2245 # source)
2223 extra.update(old.extra())
2246 extra.update(old.extra())
2224
2247
2225 # Also update it from the intermediate commit or from the wctx
2248 # Also update it from the intermediate commit or from the wctx
2226 extra.update(ctx.extra())
2249 extra.update(ctx.extra())
2227
2250
2228 if len(old.parents()) > 1:
2251 if len(old.parents()) > 1:
2229 # ctx.files() isn't reliable for merges, so fall back to the
2252 # ctx.files() isn't reliable for merges, so fall back to the
2230 # slower repo.status() method
2253 # slower repo.status() method
2231 files = set([fn for st in repo.status(base, old)[:3]
2254 files = set([fn for st in repo.status(base, old)[:3]
2232 for fn in st])
2255 for fn in st])
2233 else:
2256 else:
2234 files = set(old.files())
2257 files = set(old.files())
2235
2258
2236 # Second, we use either the commit we just did, or if there were no
2259 # Second, we use either the commit we just did, or if there were no
2237 # changes the parent of the working directory as the version of the
2260 # changes the parent of the working directory as the version of the
2238 # files in the final amend commit
2261 # files in the final amend commit
2239 if node:
2262 if node:
2240 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
2263 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
2241
2264
2242 user = ctx.user()
2265 user = ctx.user()
2243 date = ctx.date()
2266 date = ctx.date()
2244 # Recompute copies (avoid recording a -> b -> a)
2267 # Recompute copies (avoid recording a -> b -> a)
2245 copied = copies.pathcopies(base, ctx)
2268 copied = copies.pathcopies(base, ctx)
2246
2269
2247 # Prune files which were reverted by the updates: if old
2270 # Prune files which were reverted by the updates: if old
2248 # introduced file X and our intermediate commit, node,
2271 # introduced file X and our intermediate commit, node,
2249 # renamed that file, then those two files are the same and
2272 # renamed that file, then those two files are the same and
2250 # we can discard X from our list of files. Likewise if X
2273 # we can discard X from our list of files. Likewise if X
2251 # was deleted, it's no longer relevant
2274 # was deleted, it's no longer relevant
2252 files.update(ctx.files())
2275 files.update(ctx.files())
2253
2276
2254 def samefile(f):
2277 def samefile(f):
2255 if f in ctx.manifest():
2278 if f in ctx.manifest():
2256 a = ctx.filectx(f)
2279 a = ctx.filectx(f)
2257 if f in base.manifest():
2280 if f in base.manifest():
2258 b = base.filectx(f)
2281 b = base.filectx(f)
2259 return (not a.cmp(b)
2282 return (not a.cmp(b)
2260 and a.flags() == b.flags())
2283 and a.flags() == b.flags())
2261 else:
2284 else:
2262 return False
2285 return False
2263 else:
2286 else:
2264 return f not in base.manifest()
2287 return f not in base.manifest()
2265 files = [f for f in files if not samefile(f)]
2288 files = [f for f in files if not samefile(f)]
2266
2289
2267 def filectxfn(repo, ctx_, path):
2290 def filectxfn(repo, ctx_, path):
2268 try:
2291 try:
2269 fctx = ctx[path]
2292 fctx = ctx[path]
2270 flags = fctx.flags()
2293 flags = fctx.flags()
2271 mctx = context.memfilectx(repo,
2294 mctx = context.memfilectx(repo,
2272 fctx.path(), fctx.data(),
2295 fctx.path(), fctx.data(),
2273 islink='l' in flags,
2296 islink='l' in flags,
2274 isexec='x' in flags,
2297 isexec='x' in flags,
2275 copied=copied.get(path))
2298 copied=copied.get(path))
2276 return mctx
2299 return mctx
2277 except KeyError:
2300 except KeyError:
2278 return None
2301 return None
2279 else:
2302 else:
2280 ui.note(_('copying changeset %s to %s\n') % (old, base))
2303 ui.note(_('copying changeset %s to %s\n') % (old, base))
2281
2304
2282 # Use version of files as in the old cset
2305 # Use version of files as in the old cset
2283 def filectxfn(repo, ctx_, path):
2306 def filectxfn(repo, ctx_, path):
2284 try:
2307 try:
2285 return old.filectx(path)
2308 return old.filectx(path)
2286 except KeyError:
2309 except KeyError:
2287 return None
2310 return None
2288
2311
2289 user = opts.get('user') or old.user()
2312 user = opts.get('user') or old.user()
2290 date = opts.get('date') or old.date()
2313 date = opts.get('date') or old.date()
2291 editform = mergeeditform(old, 'commit.amend')
2314 editform = mergeeditform(old, 'commit.amend')
2292 editor = getcommiteditor(editform=editform, **opts)
2315 editor = getcommiteditor(editform=editform, **opts)
2293 if not message:
2316 if not message:
2294 editor = getcommiteditor(edit=True, editform=editform)
2317 editor = getcommiteditor(edit=True, editform=editform)
2295 message = old.description()
2318 message = old.description()
2296
2319
2297 pureextra = extra.copy()
2320 pureextra = extra.copy()
2298 extra['amend_source'] = old.hex()
2321 extra['amend_source'] = old.hex()
2299
2322
2300 new = context.memctx(repo,
2323 new = context.memctx(repo,
2301 parents=[base.node(), old.p2().node()],
2324 parents=[base.node(), old.p2().node()],
2302 text=message,
2325 text=message,
2303 files=files,
2326 files=files,
2304 filectxfn=filectxfn,
2327 filectxfn=filectxfn,
2305 user=user,
2328 user=user,
2306 date=date,
2329 date=date,
2307 extra=extra,
2330 extra=extra,
2308 editor=editor)
2331 editor=editor)
2309
2332
2310 newdesc = changelog.stripdesc(new.description())
2333 newdesc = changelog.stripdesc(new.description())
2311 if ((not node)
2334 if ((not node)
2312 and newdesc == old.description()
2335 and newdesc == old.description()
2313 and user == old.user()
2336 and user == old.user()
2314 and date == old.date()
2337 and date == old.date()
2315 and pureextra == old.extra()):
2338 and pureextra == old.extra()):
2316 # nothing changed. continuing here would create a new node
2339 # nothing changed. continuing here would create a new node
2317 # anyway because of the amend_source noise.
2340 # anyway because of the amend_source noise.
2318 #
2341 #
2319 # This not what we expect from amend.
2342 # This not what we expect from amend.
2320 return old.node()
2343 return old.node()
2321
2344
2322 ph = repo.ui.config('phases', 'new-commit', phases.draft)
2345 ph = repo.ui.config('phases', 'new-commit', phases.draft)
2323 try:
2346 try:
2324 if opts.get('secret'):
2347 if opts.get('secret'):
2325 commitphase = 'secret'
2348 commitphase = 'secret'
2326 else:
2349 else:
2327 commitphase = old.phase()
2350 commitphase = old.phase()
2328 repo.ui.setconfig('phases', 'new-commit', commitphase, 'amend')
2351 repo.ui.setconfig('phases', 'new-commit', commitphase, 'amend')
2329 newid = repo.commitctx(new)
2352 newid = repo.commitctx(new)
2330 finally:
2353 finally:
2331 repo.ui.setconfig('phases', 'new-commit', ph, 'amend')
2354 repo.ui.setconfig('phases', 'new-commit', ph, 'amend')
2332 if newid != old.node():
2355 if newid != old.node():
2333 # Reroute the working copy parent to the new changeset
2356 # Reroute the working copy parent to the new changeset
2334 repo.setparents(newid, nullid)
2357 repo.setparents(newid, nullid)
2335
2358
2336 # Move bookmarks from old parent to amend commit
2359 # Move bookmarks from old parent to amend commit
2337 bms = repo.nodebookmarks(old.node())
2360 bms = repo.nodebookmarks(old.node())
2338 if bms:
2361 if bms:
2339 marks = repo._bookmarks
2362 marks = repo._bookmarks
2340 for bm in bms:
2363 for bm in bms:
2341 marks[bm] = newid
2364 marks[bm] = newid
2342 marks.write()
2365 marks.write()
2343 #commit the whole amend process
2366 #commit the whole amend process
2344 createmarkers = obsolete.isenabled(repo, obsolete.createmarkersopt)
2367 createmarkers = obsolete.isenabled(repo, obsolete.createmarkersopt)
2345 if createmarkers and newid != old.node():
2368 if createmarkers and newid != old.node():
2346 # mark the new changeset as successor of the rewritten one
2369 # mark the new changeset as successor of the rewritten one
2347 new = repo[newid]
2370 new = repo[newid]
2348 obs = [(old, (new,))]
2371 obs = [(old, (new,))]
2349 if node:
2372 if node:
2350 obs.append((ctx, ()))
2373 obs.append((ctx, ()))
2351
2374
2352 obsolete.createmarkers(repo, obs)
2375 obsolete.createmarkers(repo, obs)
2353 tr.close()
2376 tr.close()
2354 finally:
2377 finally:
2355 tr.release()
2378 tr.release()
2356 if not createmarkers and newid != old.node():
2379 if not createmarkers and newid != old.node():
2357 # Strip the intermediate commit (if there was one) and the amended
2380 # Strip the intermediate commit (if there was one) and the amended
2358 # commit
2381 # commit
2359 if node:
2382 if node:
2360 ui.note(_('stripping intermediate changeset %s\n') % ctx)
2383 ui.note(_('stripping intermediate changeset %s\n') % ctx)
2361 ui.note(_('stripping amended changeset %s\n') % old)
2384 ui.note(_('stripping amended changeset %s\n') % old)
2362 repair.strip(ui, repo, old.node(), topic='amend-backup')
2385 repair.strip(ui, repo, old.node(), topic='amend-backup')
2363 finally:
2386 finally:
2364 if newid is None:
2387 if newid is None:
2365 repo.dirstate.invalidate()
2388 repo.dirstate.invalidate()
2366 lockmod.release(lock, wlock)
2389 lockmod.release(lock, wlock)
2367 return newid
2390 return newid
2368
2391
2369 def commiteditor(repo, ctx, subs, editform=''):
2392 def commiteditor(repo, ctx, subs, editform=''):
2370 if ctx.description():
2393 if ctx.description():
2371 return ctx.description()
2394 return ctx.description()
2372 return commitforceeditor(repo, ctx, subs, editform=editform)
2395 return commitforceeditor(repo, ctx, subs, editform=editform)
2373
2396
2374 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None,
2397 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None,
2375 editform=''):
2398 editform=''):
2376 if not extramsg:
2399 if not extramsg:
2377 extramsg = _("Leave message empty to abort commit.")
2400 extramsg = _("Leave message empty to abort commit.")
2378
2401
2379 forms = [e for e in editform.split('.') if e]
2402 forms = [e for e in editform.split('.') if e]
2380 forms.insert(0, 'changeset')
2403 forms.insert(0, 'changeset')
2381 while forms:
2404 while forms:
2382 tmpl = repo.ui.config('committemplate', '.'.join(forms))
2405 tmpl = repo.ui.config('committemplate', '.'.join(forms))
2383 if tmpl:
2406 if tmpl:
2384 committext = buildcommittemplate(repo, ctx, subs, extramsg, tmpl)
2407 committext = buildcommittemplate(repo, ctx, subs, extramsg, tmpl)
2385 break
2408 break
2386 forms.pop()
2409 forms.pop()
2387 else:
2410 else:
2388 committext = buildcommittext(repo, ctx, subs, extramsg)
2411 committext = buildcommittext(repo, ctx, subs, extramsg)
2389
2412
2390 # run editor in the repository root
2413 # run editor in the repository root
2391 olddir = os.getcwd()
2414 olddir = os.getcwd()
2392 os.chdir(repo.root)
2415 os.chdir(repo.root)
2393 text = repo.ui.edit(committext, ctx.user(), ctx.extra(), editform=editform)
2416 text = repo.ui.edit(committext, ctx.user(), ctx.extra(), editform=editform)
2394 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2417 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2395 os.chdir(olddir)
2418 os.chdir(olddir)
2396
2419
2397 if finishdesc:
2420 if finishdesc:
2398 text = finishdesc(text)
2421 text = finishdesc(text)
2399 if not text.strip():
2422 if not text.strip():
2400 raise util.Abort(_("empty commit message"))
2423 raise util.Abort(_("empty commit message"))
2401
2424
2402 return text
2425 return text
2403
2426
2404 def buildcommittemplate(repo, ctx, subs, extramsg, tmpl):
2427 def buildcommittemplate(repo, ctx, subs, extramsg, tmpl):
2405 ui = repo.ui
2428 ui = repo.ui
2406 tmpl, mapfile = gettemplate(ui, tmpl, None)
2429 tmpl, mapfile = gettemplate(ui, tmpl, None)
2407
2430
2408 try:
2431 try:
2409 t = changeset_templater(ui, repo, None, {}, tmpl, mapfile, False)
2432 t = changeset_templater(ui, repo, None, {}, tmpl, mapfile, False)
2410 except SyntaxError, inst:
2433 except SyntaxError, inst:
2411 raise util.Abort(inst.args[0])
2434 raise util.Abort(inst.args[0])
2412
2435
2413 for k, v in repo.ui.configitems('committemplate'):
2436 for k, v in repo.ui.configitems('committemplate'):
2414 if k != 'changeset':
2437 if k != 'changeset':
2415 t.t.cache[k] = v
2438 t.t.cache[k] = v
2416
2439
2417 if not extramsg:
2440 if not extramsg:
2418 extramsg = '' # ensure that extramsg is string
2441 extramsg = '' # ensure that extramsg is string
2419
2442
2420 ui.pushbuffer()
2443 ui.pushbuffer()
2421 t.show(ctx, extramsg=extramsg)
2444 t.show(ctx, extramsg=extramsg)
2422 return ui.popbuffer()
2445 return ui.popbuffer()
2423
2446
2424 def buildcommittext(repo, ctx, subs, extramsg):
2447 def buildcommittext(repo, ctx, subs, extramsg):
2425 edittext = []
2448 edittext = []
2426 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
2449 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
2427 if ctx.description():
2450 if ctx.description():
2428 edittext.append(ctx.description())
2451 edittext.append(ctx.description())
2429 edittext.append("")
2452 edittext.append("")
2430 edittext.append("") # Empty line between message and comments.
2453 edittext.append("") # Empty line between message and comments.
2431 edittext.append(_("HG: Enter commit message."
2454 edittext.append(_("HG: Enter commit message."
2432 " Lines beginning with 'HG:' are removed."))
2455 " Lines beginning with 'HG:' are removed."))
2433 edittext.append("HG: %s" % extramsg)
2456 edittext.append("HG: %s" % extramsg)
2434 edittext.append("HG: --")
2457 edittext.append("HG: --")
2435 edittext.append(_("HG: user: %s") % ctx.user())
2458 edittext.append(_("HG: user: %s") % ctx.user())
2436 if ctx.p2():
2459 if ctx.p2():
2437 edittext.append(_("HG: branch merge"))
2460 edittext.append(_("HG: branch merge"))
2438 if ctx.branch():
2461 if ctx.branch():
2439 edittext.append(_("HG: branch '%s'") % ctx.branch())
2462 edittext.append(_("HG: branch '%s'") % ctx.branch())
2440 if bookmarks.iscurrent(repo):
2463 if bookmarks.iscurrent(repo):
2441 edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
2464 edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
2442 edittext.extend([_("HG: subrepo %s") % s for s in subs])
2465 edittext.extend([_("HG: subrepo %s") % s for s in subs])
2443 edittext.extend([_("HG: added %s") % f for f in added])
2466 edittext.extend([_("HG: added %s") % f for f in added])
2444 edittext.extend([_("HG: changed %s") % f for f in modified])
2467 edittext.extend([_("HG: changed %s") % f for f in modified])
2445 edittext.extend([_("HG: removed %s") % f for f in removed])
2468 edittext.extend([_("HG: removed %s") % f for f in removed])
2446 if not added and not modified and not removed:
2469 if not added and not modified and not removed:
2447 edittext.append(_("HG: no files changed"))
2470 edittext.append(_("HG: no files changed"))
2448 edittext.append("")
2471 edittext.append("")
2449
2472
2450 return "\n".join(edittext)
2473 return "\n".join(edittext)
2451
2474
2452 def commitstatus(repo, node, branch, bheads=None, opts={}):
2475 def commitstatus(repo, node, branch, bheads=None, opts={}):
2453 ctx = repo[node]
2476 ctx = repo[node]
2454 parents = ctx.parents()
2477 parents = ctx.parents()
2455
2478
2456 if (not opts.get('amend') and bheads and node not in bheads and not
2479 if (not opts.get('amend') and bheads and node not in bheads and not
2457 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2480 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2458 repo.ui.status(_('created new head\n'))
2481 repo.ui.status(_('created new head\n'))
2459 # The message is not printed for initial roots. For the other
2482 # The message is not printed for initial roots. For the other
2460 # changesets, it is printed in the following situations:
2483 # changesets, it is printed in the following situations:
2461 #
2484 #
2462 # Par column: for the 2 parents with ...
2485 # Par column: for the 2 parents with ...
2463 # N: null or no parent
2486 # N: null or no parent
2464 # B: parent is on another named branch
2487 # B: parent is on another named branch
2465 # C: parent is a regular non head changeset
2488 # C: parent is a regular non head changeset
2466 # H: parent was a branch head of the current branch
2489 # H: parent was a branch head of the current branch
2467 # Msg column: whether we print "created new head" message
2490 # Msg column: whether we print "created new head" message
2468 # In the following, it is assumed that there already exists some
2491 # In the following, it is assumed that there already exists some
2469 # initial branch heads of the current branch, otherwise nothing is
2492 # initial branch heads of the current branch, otherwise nothing is
2470 # printed anyway.
2493 # printed anyway.
2471 #
2494 #
2472 # Par Msg Comment
2495 # Par Msg Comment
2473 # N N y additional topo root
2496 # N N y additional topo root
2474 #
2497 #
2475 # B N y additional branch root
2498 # B N y additional branch root
2476 # C N y additional topo head
2499 # C N y additional topo head
2477 # H N n usual case
2500 # H N n usual case
2478 #
2501 #
2479 # B B y weird additional branch root
2502 # B B y weird additional branch root
2480 # C B y branch merge
2503 # C B y branch merge
2481 # H B n merge with named branch
2504 # H B n merge with named branch
2482 #
2505 #
2483 # C C y additional head from merge
2506 # C C y additional head from merge
2484 # C H n merge with a head
2507 # C H n merge with a head
2485 #
2508 #
2486 # H H n head merge: head count decreases
2509 # H H n head merge: head count decreases
2487
2510
2488 if not opts.get('close_branch'):
2511 if not opts.get('close_branch'):
2489 for r in parents:
2512 for r in parents:
2490 if r.closesbranch() and r.branch() == branch:
2513 if r.closesbranch() and r.branch() == branch:
2491 repo.ui.status(_('reopening closed branch head %d\n') % r)
2514 repo.ui.status(_('reopening closed branch head %d\n') % r)
2492
2515
2493 if repo.ui.debugflag:
2516 if repo.ui.debugflag:
2494 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
2517 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
2495 elif repo.ui.verbose:
2518 elif repo.ui.verbose:
2496 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
2519 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
2497
2520
2498 def revert(ui, repo, ctx, parents, *pats, **opts):
2521 def revert(ui, repo, ctx, parents, *pats, **opts):
2499 parent, p2 = parents
2522 parent, p2 = parents
2500 node = ctx.node()
2523 node = ctx.node()
2501
2524
2502 mf = ctx.manifest()
2525 mf = ctx.manifest()
2503 if node == p2:
2526 if node == p2:
2504 parent = p2
2527 parent = p2
2505 if node == parent:
2528 if node == parent:
2506 pmf = mf
2529 pmf = mf
2507 else:
2530 else:
2508 pmf = None
2531 pmf = None
2509
2532
2510 # need all matching names in dirstate and manifest of target rev,
2533 # need all matching names in dirstate and manifest of target rev,
2511 # so have to walk both. do not print errors if files exist in one
2534 # so have to walk both. do not print errors if files exist in one
2512 # but not other.
2535 # but not other.
2513
2536
2514 # `names` is a mapping for all elements in working copy and target revision
2537 # `names` is a mapping for all elements in working copy and target revision
2515 # The mapping is in the form:
2538 # The mapping is in the form:
2516 # <asb path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
2539 # <asb path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
2517 names = {}
2540 names = {}
2518
2541
2519 wlock = repo.wlock()
2542 wlock = repo.wlock()
2520 try:
2543 try:
2521 ## filling of the `names` mapping
2544 ## filling of the `names` mapping
2522 # walk dirstate to fill `names`
2545 # walk dirstate to fill `names`
2523
2546
2524 m = scmutil.match(repo[None], pats, opts)
2547 m = scmutil.match(repo[None], pats, opts)
2525 if not m.always() or node != parent:
2548 if not m.always() or node != parent:
2526 m.bad = lambda x, y: False
2549 m.bad = lambda x, y: False
2527 for abs in repo.walk(m):
2550 for abs in repo.walk(m):
2528 names[abs] = m.rel(abs), m.exact(abs)
2551 names[abs] = m.rel(abs), m.exact(abs)
2529
2552
2530 # walk target manifest to fill `names`
2553 # walk target manifest to fill `names`
2531
2554
2532 def badfn(path, msg):
2555 def badfn(path, msg):
2533 if path in names:
2556 if path in names:
2534 return
2557 return
2535 if path in ctx.substate:
2558 if path in ctx.substate:
2536 return
2559 return
2537 path_ = path + '/'
2560 path_ = path + '/'
2538 for f in names:
2561 for f in names:
2539 if f.startswith(path_):
2562 if f.startswith(path_):
2540 return
2563 return
2541 ui.warn("%s: %s\n" % (m.rel(path), msg))
2564 ui.warn("%s: %s\n" % (m.rel(path), msg))
2542
2565
2543 m = scmutil.match(ctx, pats, opts)
2566 m = scmutil.match(ctx, pats, opts)
2544 m.bad = badfn
2567 m.bad = badfn
2545 for abs in ctx.walk(m):
2568 for abs in ctx.walk(m):
2546 if abs not in names:
2569 if abs not in names:
2547 names[abs] = m.rel(abs), m.exact(abs)
2570 names[abs] = m.rel(abs), m.exact(abs)
2548
2571
2549 # Find status of all file in `names`.
2572 # Find status of all file in `names`.
2550 m = scmutil.matchfiles(repo, names)
2573 m = scmutil.matchfiles(repo, names)
2551
2574
2552 changes = repo.status(node1=node, match=m,
2575 changes = repo.status(node1=node, match=m,
2553 unknown=True, ignored=True, clean=True)
2576 unknown=True, ignored=True, clean=True)
2554 else:
2577 else:
2555 changes = repo.status(match=m)
2578 changes = repo.status(match=m)
2556 for kind in changes:
2579 for kind in changes:
2557 for abs in kind:
2580 for abs in kind:
2558 names[abs] = m.rel(abs), m.exact(abs)
2581 names[abs] = m.rel(abs), m.exact(abs)
2559
2582
2560 m = scmutil.matchfiles(repo, names)
2583 m = scmutil.matchfiles(repo, names)
2561
2584
2562 modified = set(changes[0])
2585 modified = set(changes[0])
2563 added = set(changes[1])
2586 added = set(changes[1])
2564 removed = set(changes[2])
2587 removed = set(changes[2])
2565 _deleted = set(changes[3])
2588 _deleted = set(changes[3])
2566 unknown = set(changes[4])
2589 unknown = set(changes[4])
2567 unknown.update(changes[5])
2590 unknown.update(changes[5])
2568 clean = set(changes[6])
2591 clean = set(changes[6])
2569 modadded = set()
2592 modadded = set()
2570
2593
2571 # split between files known in target manifest and the others
2594 # split between files known in target manifest and the others
2572 smf = set(mf)
2595 smf = set(mf)
2573
2596
2574 # determine the exact nature of the deleted changesets
2597 # determine the exact nature of the deleted changesets
2575 deladded = _deleted - smf
2598 deladded = _deleted - smf
2576 deleted = _deleted - deladded
2599 deleted = _deleted - deladded
2577
2600
2578 # We need to account for the state of file in the dirstate.
2601 # We need to account for the state of file in the dirstate.
2579 #
2602 #
2580 # Even, when we revert against something else than parent. This will
2603 # Even, when we revert against something else than parent. This will
2581 # slightly alter the behavior of revert (doing back up or not, delete
2604 # slightly alter the behavior of revert (doing back up or not, delete
2582 # or just forget etc).
2605 # or just forget etc).
2583 if parent == node:
2606 if parent == node:
2584 dsmodified = modified
2607 dsmodified = modified
2585 dsadded = added
2608 dsadded = added
2586 dsremoved = removed
2609 dsremoved = removed
2587 modified, added, removed = set(), set(), set()
2610 modified, added, removed = set(), set(), set()
2588 else:
2611 else:
2589 changes = repo.status(node1=parent, match=m)
2612 changes = repo.status(node1=parent, match=m)
2590 dsmodified = set(changes[0])
2613 dsmodified = set(changes[0])
2591 dsadded = set(changes[1])
2614 dsadded = set(changes[1])
2592 dsremoved = set(changes[2])
2615 dsremoved = set(changes[2])
2593
2616
2594 # only take into account for removes between wc and target
2617 # only take into account for removes between wc and target
2595 clean |= dsremoved - removed
2618 clean |= dsremoved - removed
2596 dsremoved &= removed
2619 dsremoved &= removed
2597 # distinct between dirstate remove and other
2620 # distinct between dirstate remove and other
2598 removed -= dsremoved
2621 removed -= dsremoved
2599
2622
2600 modadded = added & dsmodified
2623 modadded = added & dsmodified
2601 added -= modadded
2624 added -= modadded
2602
2625
2603 # tell newly modified apart.
2626 # tell newly modified apart.
2604 dsmodified &= modified
2627 dsmodified &= modified
2605 dsmodified |= modified & dsadded # dirstate added may needs backup
2628 dsmodified |= modified & dsadded # dirstate added may needs backup
2606 modified -= dsmodified
2629 modified -= dsmodified
2607
2630
2608 # We need to wait for some post-processing to update this set
2631 # We need to wait for some post-processing to update this set
2609 # before making the distinction. The dirstate will be used for
2632 # before making the distinction. The dirstate will be used for
2610 # that purpose.
2633 # that purpose.
2611 dsadded = added
2634 dsadded = added
2612
2635
2613 # in case of merge, files that are actually added can be reported as
2636 # in case of merge, files that are actually added can be reported as
2614 # modified, we need to post process the result
2637 # modified, we need to post process the result
2615 if p2 != nullid:
2638 if p2 != nullid:
2616 if pmf is None:
2639 if pmf is None:
2617 # only need parent manifest in the merge case,
2640 # only need parent manifest in the merge case,
2618 # so do not read by default
2641 # so do not read by default
2619 pmf = repo[parent].manifest()
2642 pmf = repo[parent].manifest()
2620 mergeadd = dsmodified - set(pmf)
2643 mergeadd = dsmodified - set(pmf)
2621 dsadded |= mergeadd
2644 dsadded |= mergeadd
2622 dsmodified -= mergeadd
2645 dsmodified -= mergeadd
2623
2646
2624 # if f is a rename, update `names` to also revert the source
2647 # if f is a rename, update `names` to also revert the source
2625 cwd = repo.getcwd()
2648 cwd = repo.getcwd()
2626 for f in dsadded:
2649 for f in dsadded:
2627 src = repo.dirstate.copied(f)
2650 src = repo.dirstate.copied(f)
2628 # XXX should we check for rename down to target node?
2651 # XXX should we check for rename down to target node?
2629 if src and src not in names and repo.dirstate[src] == 'r':
2652 if src and src not in names and repo.dirstate[src] == 'r':
2630 dsremoved.add(src)
2653 dsremoved.add(src)
2631 names[src] = (repo.pathto(src, cwd), True)
2654 names[src] = (repo.pathto(src, cwd), True)
2632
2655
2633 # distinguish between file to forget and the other
2656 # distinguish between file to forget and the other
2634 added = set()
2657 added = set()
2635 for abs in dsadded:
2658 for abs in dsadded:
2636 if repo.dirstate[abs] != 'a':
2659 if repo.dirstate[abs] != 'a':
2637 added.add(abs)
2660 added.add(abs)
2638 dsadded -= added
2661 dsadded -= added
2639
2662
2640 for abs in deladded:
2663 for abs in deladded:
2641 if repo.dirstate[abs] == 'a':
2664 if repo.dirstate[abs] == 'a':
2642 dsadded.add(abs)
2665 dsadded.add(abs)
2643 deladded -= dsadded
2666 deladded -= dsadded
2644
2667
2645 # For files marked as removed, we check if an unknown file is present at
2668 # For files marked as removed, we check if an unknown file is present at
2646 # the same path. If a such file exists it may need to be backed up.
2669 # the same path. If a such file exists it may need to be backed up.
2647 # Making the distinction at this stage helps have simpler backup
2670 # Making the distinction at this stage helps have simpler backup
2648 # logic.
2671 # logic.
2649 removunk = set()
2672 removunk = set()
2650 for abs in removed:
2673 for abs in removed:
2651 target = repo.wjoin(abs)
2674 target = repo.wjoin(abs)
2652 if os.path.lexists(target):
2675 if os.path.lexists(target):
2653 removunk.add(abs)
2676 removunk.add(abs)
2654 removed -= removunk
2677 removed -= removunk
2655
2678
2656 dsremovunk = set()
2679 dsremovunk = set()
2657 for abs in dsremoved:
2680 for abs in dsremoved:
2658 target = repo.wjoin(abs)
2681 target = repo.wjoin(abs)
2659 if os.path.lexists(target):
2682 if os.path.lexists(target):
2660 dsremovunk.add(abs)
2683 dsremovunk.add(abs)
2661 dsremoved -= dsremovunk
2684 dsremoved -= dsremovunk
2662
2685
2663 # action to be actually performed by revert
2686 # action to be actually performed by revert
2664 # (<list of file>, message>) tuple
2687 # (<list of file>, message>) tuple
2665 actions = {'revert': ([], _('reverting %s\n')),
2688 actions = {'revert': ([], _('reverting %s\n')),
2666 'add': ([], _('adding %s\n')),
2689 'add': ([], _('adding %s\n')),
2667 'remove': ([], _('removing %s\n')),
2690 'remove': ([], _('removing %s\n')),
2668 'drop': ([], _('removing %s\n')),
2691 'drop': ([], _('removing %s\n')),
2669 'forget': ([], _('forgetting %s\n')),
2692 'forget': ([], _('forgetting %s\n')),
2670 'undelete': ([], _('undeleting %s\n')),
2693 'undelete': ([], _('undeleting %s\n')),
2671 'noop': (None, _('no changes needed to %s\n')),
2694 'noop': (None, _('no changes needed to %s\n')),
2672 'unknown': (None, _('file not managed: %s\n')),
2695 'unknown': (None, _('file not managed: %s\n')),
2673 }
2696 }
2674
2697
2675 # "constant" that convey the backup strategy.
2698 # "constant" that convey the backup strategy.
2676 # All set to `discard` if `no-backup` is set do avoid checking
2699 # All set to `discard` if `no-backup` is set do avoid checking
2677 # no_backup lower in the code.
2700 # no_backup lower in the code.
2678 # These values are ordered for comparison purposes
2701 # These values are ordered for comparison purposes
2679 backup = 2 # unconditionally do backup
2702 backup = 2 # unconditionally do backup
2680 check = 1 # check if the existing file differs from target
2703 check = 1 # check if the existing file differs from target
2681 discard = 0 # never do backup
2704 discard = 0 # never do backup
2682 if opts.get('no_backup'):
2705 if opts.get('no_backup'):
2683 backup = check = discard
2706 backup = check = discard
2684
2707
2685 backupanddel = actions['remove']
2708 backupanddel = actions['remove']
2686 if not opts.get('no_backup'):
2709 if not opts.get('no_backup'):
2687 backupanddel = actions['drop']
2710 backupanddel = actions['drop']
2688
2711
2689 disptable = (
2712 disptable = (
2690 # dispatch table:
2713 # dispatch table:
2691 # file state
2714 # file state
2692 # action
2715 # action
2693 # make backup
2716 # make backup
2694
2717
2695 ## Sets that results that will change file on disk
2718 ## Sets that results that will change file on disk
2696 # Modified compared to target, no local change
2719 # Modified compared to target, no local change
2697 (modified, actions['revert'], discard),
2720 (modified, actions['revert'], discard),
2698 # Modified compared to target, but local file is deleted
2721 # Modified compared to target, but local file is deleted
2699 (deleted, actions['revert'], discard),
2722 (deleted, actions['revert'], discard),
2700 # Modified compared to target, local change
2723 # Modified compared to target, local change
2701 (dsmodified, actions['revert'], backup),
2724 (dsmodified, actions['revert'], backup),
2702 # Added since target
2725 # Added since target
2703 (added, actions['remove'], discard),
2726 (added, actions['remove'], discard),
2704 # Added in working directory
2727 # Added in working directory
2705 (dsadded, actions['forget'], discard),
2728 (dsadded, actions['forget'], discard),
2706 # Added since target, have local modification
2729 # Added since target, have local modification
2707 (modadded, backupanddel, backup),
2730 (modadded, backupanddel, backup),
2708 # Added since target but file is missing in working directory
2731 # Added since target but file is missing in working directory
2709 (deladded, actions['drop'], discard),
2732 (deladded, actions['drop'], discard),
2710 # Removed since target, before working copy parent
2733 # Removed since target, before working copy parent
2711 (removed, actions['add'], discard),
2734 (removed, actions['add'], discard),
2712 # Same as `removed` but an unknown file exists at the same path
2735 # Same as `removed` but an unknown file exists at the same path
2713 (removunk, actions['add'], check),
2736 (removunk, actions['add'], check),
2714 # Removed since targe, marked as such in working copy parent
2737 # Removed since targe, marked as such in working copy parent
2715 (dsremoved, actions['undelete'], discard),
2738 (dsremoved, actions['undelete'], discard),
2716 # Same as `dsremoved` but an unknown file exists at the same path
2739 # Same as `dsremoved` but an unknown file exists at the same path
2717 (dsremovunk, actions['undelete'], check),
2740 (dsremovunk, actions['undelete'], check),
2718 ## the following sets does not result in any file changes
2741 ## the following sets does not result in any file changes
2719 # File with no modification
2742 # File with no modification
2720 (clean, actions['noop'], discard),
2743 (clean, actions['noop'], discard),
2721 # Existing file, not tracked anywhere
2744 # Existing file, not tracked anywhere
2722 (unknown, actions['unknown'], discard),
2745 (unknown, actions['unknown'], discard),
2723 )
2746 )
2724
2747
2725 needdata = ('revert', 'add', 'undelete')
2748 needdata = ('revert', 'add', 'undelete')
2726 _revertprefetch(repo, ctx, *[actions[name][0] for name in needdata])
2749 _revertprefetch(repo, ctx, *[actions[name][0] for name in needdata])
2727
2750
2728 wctx = repo[None]
2751 wctx = repo[None]
2729 for abs, (rel, exact) in sorted(names.items()):
2752 for abs, (rel, exact) in sorted(names.items()):
2730 # target file to be touch on disk (relative to cwd)
2753 # target file to be touch on disk (relative to cwd)
2731 target = repo.wjoin(abs)
2754 target = repo.wjoin(abs)
2732 # search the entry in the dispatch table.
2755 # search the entry in the dispatch table.
2733 # if the file is in any of these sets, it was touched in the working
2756 # if the file is in any of these sets, it was touched in the working
2734 # directory parent and we are sure it needs to be reverted.
2757 # directory parent and we are sure it needs to be reverted.
2735 for table, (xlist, msg), dobackup in disptable:
2758 for table, (xlist, msg), dobackup in disptable:
2736 if abs not in table:
2759 if abs not in table:
2737 continue
2760 continue
2738 if xlist is not None:
2761 if xlist is not None:
2739 xlist.append(abs)
2762 xlist.append(abs)
2740 if dobackup and (backup <= dobackup
2763 if dobackup and (backup <= dobackup
2741 or wctx[abs].cmp(ctx[abs])):
2764 or wctx[abs].cmp(ctx[abs])):
2742 bakname = "%s.orig" % rel
2765 bakname = "%s.orig" % rel
2743 ui.note(_('saving current version of %s as %s\n') %
2766 ui.note(_('saving current version of %s as %s\n') %
2744 (rel, bakname))
2767 (rel, bakname))
2745 if not opts.get('dry_run'):
2768 if not opts.get('dry_run'):
2746 util.rename(target, bakname)
2769 util.rename(target, bakname)
2747 if ui.verbose or not exact:
2770 if ui.verbose or not exact:
2748 if not isinstance(msg, basestring):
2771 if not isinstance(msg, basestring):
2749 msg = msg(abs)
2772 msg = msg(abs)
2750 ui.status(msg % rel)
2773 ui.status(msg % rel)
2751 elif exact:
2774 elif exact:
2752 ui.warn(msg % rel)
2775 ui.warn(msg % rel)
2753 break
2776 break
2754
2777
2755
2778
2756 if not opts.get('dry_run'):
2779 if not opts.get('dry_run'):
2757 _performrevert(repo, parents, ctx, actions)
2780 _performrevert(repo, parents, ctx, actions)
2758
2781
2759 # get the list of subrepos that must be reverted
2782 # get the list of subrepos that must be reverted
2760 subrepomatch = scmutil.match(ctx, pats, opts)
2783 subrepomatch = scmutil.match(ctx, pats, opts)
2761 targetsubs = sorted(s for s in ctx.substate if subrepomatch(s))
2784 targetsubs = sorted(s for s in ctx.substate if subrepomatch(s))
2762
2785
2763 if targetsubs:
2786 if targetsubs:
2764 # Revert the subrepos on the revert list
2787 # Revert the subrepos on the revert list
2765 for sub in targetsubs:
2788 for sub in targetsubs:
2766 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
2789 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
2767 finally:
2790 finally:
2768 wlock.release()
2791 wlock.release()
2769
2792
2770 def _revertprefetch(repo, ctx, *files):
2793 def _revertprefetch(repo, ctx, *files):
2771 """Let extension changing the storage layer prefetch content"""
2794 """Let extension changing the storage layer prefetch content"""
2772 pass
2795 pass
2773
2796
2774 def _performrevert(repo, parents, ctx, actions):
2797 def _performrevert(repo, parents, ctx, actions):
2775 """function that actually perform all the actions computed for revert
2798 """function that actually perform all the actions computed for revert
2776
2799
2777 This is an independent function to let extension to plug in and react to
2800 This is an independent function to let extension to plug in and react to
2778 the imminent revert.
2801 the imminent revert.
2779
2802
2780 Make sure you have the working directory locked when calling this function.
2803 Make sure you have the working directory locked when calling this function.
2781 """
2804 """
2782 parent, p2 = parents
2805 parent, p2 = parents
2783 node = ctx.node()
2806 node = ctx.node()
2784 def checkout(f):
2807 def checkout(f):
2785 fc = ctx[f]
2808 fc = ctx[f]
2786 repo.wwrite(f, fc.data(), fc.flags())
2809 repo.wwrite(f, fc.data(), fc.flags())
2787
2810
2788 audit_path = pathutil.pathauditor(repo.root)
2811 audit_path = pathutil.pathauditor(repo.root)
2789 for f in actions['forget'][0]:
2812 for f in actions['forget'][0]:
2790 repo.dirstate.drop(f)
2813 repo.dirstate.drop(f)
2791 for f in actions['remove'][0]:
2814 for f in actions['remove'][0]:
2792 audit_path(f)
2815 audit_path(f)
2793 util.unlinkpath(repo.wjoin(f))
2816 util.unlinkpath(repo.wjoin(f))
2794 repo.dirstate.remove(f)
2817 repo.dirstate.remove(f)
2795 for f in actions['drop'][0]:
2818 for f in actions['drop'][0]:
2796 audit_path(f)
2819 audit_path(f)
2797 repo.dirstate.remove(f)
2820 repo.dirstate.remove(f)
2798
2821
2799 normal = None
2822 normal = None
2800 if node == parent:
2823 if node == parent:
2801 # We're reverting to our parent. If possible, we'd like status
2824 # We're reverting to our parent. If possible, we'd like status
2802 # to report the file as clean. We have to use normallookup for
2825 # to report the file as clean. We have to use normallookup for
2803 # merges to avoid losing information about merged/dirty files.
2826 # merges to avoid losing information about merged/dirty files.
2804 if p2 != nullid:
2827 if p2 != nullid:
2805 normal = repo.dirstate.normallookup
2828 normal = repo.dirstate.normallookup
2806 else:
2829 else:
2807 normal = repo.dirstate.normal
2830 normal = repo.dirstate.normal
2808 for f in actions['revert'][0]:
2831 for f in actions['revert'][0]:
2809 checkout(f)
2832 checkout(f)
2810 if normal:
2833 if normal:
2811 normal(f)
2834 normal(f)
2812
2835
2813 for f in actions['add'][0]:
2836 for f in actions['add'][0]:
2814 checkout(f)
2837 checkout(f)
2815 repo.dirstate.add(f)
2838 repo.dirstate.add(f)
2816
2839
2817 normal = repo.dirstate.normallookup
2840 normal = repo.dirstate.normallookup
2818 if node == parent and p2 == nullid:
2841 if node == parent and p2 == nullid:
2819 normal = repo.dirstate.normal
2842 normal = repo.dirstate.normal
2820 for f in actions['undelete'][0]:
2843 for f in actions['undelete'][0]:
2821 checkout(f)
2844 checkout(f)
2822 normal(f)
2845 normal(f)
2823
2846
2824 copied = copies.pathcopies(repo[parent], ctx)
2847 copied = copies.pathcopies(repo[parent], ctx)
2825
2848
2826 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
2849 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
2827 if f in copied:
2850 if f in copied:
2828 repo.dirstate.copy(copied[f], f)
2851 repo.dirstate.copy(copied[f], f)
2829
2852
2830 def command(table):
2853 def command(table):
2831 """Returns a function object to be used as a decorator for making commands.
2854 """Returns a function object to be used as a decorator for making commands.
2832
2855
2833 This function receives a command table as its argument. The table should
2856 This function receives a command table as its argument. The table should
2834 be a dict.
2857 be a dict.
2835
2858
2836 The returned function can be used as a decorator for adding commands
2859 The returned function can be used as a decorator for adding commands
2837 to that command table. This function accepts multiple arguments to define
2860 to that command table. This function accepts multiple arguments to define
2838 a command.
2861 a command.
2839
2862
2840 The first argument is the command name.
2863 The first argument is the command name.
2841
2864
2842 The options argument is an iterable of tuples defining command arguments.
2865 The options argument is an iterable of tuples defining command arguments.
2843 See ``mercurial.fancyopts.fancyopts()`` for the format of each tuple.
2866 See ``mercurial.fancyopts.fancyopts()`` for the format of each tuple.
2844
2867
2845 The synopsis argument defines a short, one line summary of how to use the
2868 The synopsis argument defines a short, one line summary of how to use the
2846 command. This shows up in the help output.
2869 command. This shows up in the help output.
2847
2870
2848 The norepo argument defines whether the command does not require a
2871 The norepo argument defines whether the command does not require a
2849 local repository. Most commands operate against a repository, thus the
2872 local repository. Most commands operate against a repository, thus the
2850 default is False.
2873 default is False.
2851
2874
2852 The optionalrepo argument defines whether the command optionally requires
2875 The optionalrepo argument defines whether the command optionally requires
2853 a local repository.
2876 a local repository.
2854
2877
2855 The inferrepo argument defines whether to try to find a repository from the
2878 The inferrepo argument defines whether to try to find a repository from the
2856 command line arguments. If True, arguments will be examined for potential
2879 command line arguments. If True, arguments will be examined for potential
2857 repository locations. See ``findrepo()``. If a repository is found, it
2880 repository locations. See ``findrepo()``. If a repository is found, it
2858 will be used.
2881 will be used.
2859 """
2882 """
2860 def cmd(name, options=(), synopsis=None, norepo=False, optionalrepo=False,
2883 def cmd(name, options=(), synopsis=None, norepo=False, optionalrepo=False,
2861 inferrepo=False):
2884 inferrepo=False):
2862 def decorator(func):
2885 def decorator(func):
2863 if synopsis:
2886 if synopsis:
2864 table[name] = func, list(options), synopsis
2887 table[name] = func, list(options), synopsis
2865 else:
2888 else:
2866 table[name] = func, list(options)
2889 table[name] = func, list(options)
2867
2890
2868 if norepo:
2891 if norepo:
2869 # Avoid import cycle.
2892 # Avoid import cycle.
2870 import commands
2893 import commands
2871 commands.norepo += ' %s' % ' '.join(parsealiases(name))
2894 commands.norepo += ' %s' % ' '.join(parsealiases(name))
2872
2895
2873 if optionalrepo:
2896 if optionalrepo:
2874 import commands
2897 import commands
2875 commands.optionalrepo += ' %s' % ' '.join(parsealiases(name))
2898 commands.optionalrepo += ' %s' % ' '.join(parsealiases(name))
2876
2899
2877 if inferrepo:
2900 if inferrepo:
2878 import commands
2901 import commands
2879 commands.inferrepo += ' %s' % ' '.join(parsealiases(name))
2902 commands.inferrepo += ' %s' % ' '.join(parsealiases(name))
2880
2903
2881 return func
2904 return func
2882 return decorator
2905 return decorator
2883
2906
2884 return cmd
2907 return cmd
2885
2908
2886 # a list of (ui, repo, otherpeer, opts, missing) functions called by
2909 # a list of (ui, repo, otherpeer, opts, missing) functions called by
2887 # commands.outgoing. "missing" is "missing" of the result of
2910 # commands.outgoing. "missing" is "missing" of the result of
2888 # "findcommonoutgoing()"
2911 # "findcommonoutgoing()"
2889 outgoinghooks = util.hooks()
2912 outgoinghooks = util.hooks()
2890
2913
2891 # a list of (ui, repo) functions called by commands.summary
2914 # a list of (ui, repo) functions called by commands.summary
2892 summaryhooks = util.hooks()
2915 summaryhooks = util.hooks()
2893
2916
2894 # a list of (ui, repo, opts, changes) functions called by commands.summary.
2917 # a list of (ui, repo, opts, changes) functions called by commands.summary.
2895 #
2918 #
2896 # functions should return tuple of booleans below, if 'changes' is None:
2919 # functions should return tuple of booleans below, if 'changes' is None:
2897 # (whether-incomings-are-needed, whether-outgoings-are-needed)
2920 # (whether-incomings-are-needed, whether-outgoings-are-needed)
2898 #
2921 #
2899 # otherwise, 'changes' is a tuple of tuples below:
2922 # otherwise, 'changes' is a tuple of tuples below:
2900 # - (sourceurl, sourcebranch, sourcepeer, incoming)
2923 # - (sourceurl, sourcebranch, sourcepeer, incoming)
2901 # - (desturl, destbranch, destpeer, outgoing)
2924 # - (desturl, destbranch, destpeer, outgoing)
2902 summaryremotehooks = util.hooks()
2925 summaryremotehooks = util.hooks()
2903
2926
2904 # A list of state files kept by multistep operations like graft.
2927 # A list of state files kept by multistep operations like graft.
2905 # Since graft cannot be aborted, it is considered 'clearable' by update.
2928 # Since graft cannot be aborted, it is considered 'clearable' by update.
2906 # note: bisect is intentionally excluded
2929 # note: bisect is intentionally excluded
2907 # (state file, clearable, allowcommit, error, hint)
2930 # (state file, clearable, allowcommit, error, hint)
2908 unfinishedstates = [
2931 unfinishedstates = [
2909 ('graftstate', True, False, _('graft in progress'),
2932 ('graftstate', True, False, _('graft in progress'),
2910 _("use 'hg graft --continue' or 'hg update' to abort")),
2933 _("use 'hg graft --continue' or 'hg update' to abort")),
2911 ('updatestate', True, False, _('last update was interrupted'),
2934 ('updatestate', True, False, _('last update was interrupted'),
2912 _("use 'hg update' to get a consistent checkout"))
2935 _("use 'hg update' to get a consistent checkout"))
2913 ]
2936 ]
2914
2937
2915 def checkunfinished(repo, commit=False):
2938 def checkunfinished(repo, commit=False):
2916 '''Look for an unfinished multistep operation, like graft, and abort
2939 '''Look for an unfinished multistep operation, like graft, and abort
2917 if found. It's probably good to check this right before
2940 if found. It's probably good to check this right before
2918 bailifchanged().
2941 bailifchanged().
2919 '''
2942 '''
2920 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2943 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2921 if commit and allowcommit:
2944 if commit and allowcommit:
2922 continue
2945 continue
2923 if repo.vfs.exists(f):
2946 if repo.vfs.exists(f):
2924 raise util.Abort(msg, hint=hint)
2947 raise util.Abort(msg, hint=hint)
2925
2948
2926 def clearunfinished(repo):
2949 def clearunfinished(repo):
2927 '''Check for unfinished operations (as above), and clear the ones
2950 '''Check for unfinished operations (as above), and clear the ones
2928 that are clearable.
2951 that are clearable.
2929 '''
2952 '''
2930 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2953 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2931 if not clearable and repo.vfs.exists(f):
2954 if not clearable and repo.vfs.exists(f):
2932 raise util.Abort(msg, hint=hint)
2955 raise util.Abort(msg, hint=hint)
2933 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2956 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2934 if clearable and repo.vfs.exists(f):
2957 if clearable and repo.vfs.exists(f):
2935 util.unlink(repo.join(f))
2958 util.unlink(repo.join(f))
@@ -1,6253 +1,6254 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 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
144 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
145 ('p', 'show-function', None, _('show which function each change is in')),
145 ('p', 'show-function', None, _('show which function each change is in')),
146 ('', 'reverse', None, _('produce a diff that undoes the changes')),
146 ('', 'reverse', None, _('produce a diff that undoes the changes')),
147 ] + diffwsopts + [
147 ] + diffwsopts + [
148 ('U', 'unified', '',
148 ('U', 'unified', '',
149 _('number of lines of context to show'), _('NUM')),
149 _('number of lines of context to show'), _('NUM')),
150 ('', 'stat', None, _('output diffstat-style summary of changes')),
150 ('', 'stat', None, _('output diffstat-style summary of changes')),
151 ]
151 ]
152
152
153 mergetoolopts = [
153 mergetoolopts = [
154 ('t', 'tool', '', _('specify merge tool')),
154 ('t', 'tool', '', _('specify merge tool')),
155 ]
155 ]
156
156
157 similarityopts = [
157 similarityopts = [
158 ('s', 'similarity', '',
158 ('s', 'similarity', '',
159 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
159 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
160 ]
160 ]
161
161
162 subrepoopts = [
162 subrepoopts = [
163 ('S', 'subrepos', None,
163 ('S', 'subrepos', None,
164 _('recurse into subrepositories'))
164 _('recurse into subrepositories'))
165 ]
165 ]
166
166
167 # Commands start here, listed alphabetically
167 # Commands start here, listed alphabetically
168
168
169 @command('^add',
169 @command('^add',
170 walkopts + subrepoopts + dryrunopts,
170 walkopts + subrepoopts + dryrunopts,
171 _('[OPTION]... [FILE]...'),
171 _('[OPTION]... [FILE]...'),
172 inferrepo=True)
172 inferrepo=True)
173 def add(ui, repo, *pats, **opts):
173 def add(ui, repo, *pats, **opts):
174 """add the specified files on the next commit
174 """add the specified files on the next commit
175
175
176 Schedule files to be version controlled and added to the
176 Schedule files to be version controlled and added to the
177 repository.
177 repository.
178
178
179 The files will be added to the repository at the next commit. To
179 The files will be added to the repository at the next commit. To
180 undo an add before that, see :hg:`forget`.
180 undo an add before that, see :hg:`forget`.
181
181
182 If no names are given, add all files to the repository.
182 If no names are given, add all files to the repository.
183
183
184 .. container:: verbose
184 .. container:: verbose
185
185
186 An example showing how new (unknown) files are added
186 An example showing how new (unknown) files are added
187 automatically by :hg:`add`::
187 automatically by :hg:`add`::
188
188
189 $ ls
189 $ ls
190 foo.c
190 foo.c
191 $ hg status
191 $ hg status
192 ? foo.c
192 ? foo.c
193 $ hg add
193 $ hg add
194 adding foo.c
194 adding foo.c
195 $ hg status
195 $ hg status
196 A foo.c
196 A foo.c
197
197
198 Returns 0 if all files are successfully added.
198 Returns 0 if all files are successfully added.
199 """
199 """
200
200
201 m = scmutil.match(repo[None], pats, opts)
201 m = scmutil.match(repo[None], pats, opts)
202 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
202 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
203 opts.get('subrepos'), prefix="", explicitonly=False)
203 opts.get('subrepos'), prefix="", explicitonly=False)
204 return rejected and 1 or 0
204 return rejected and 1 or 0
205
205
206 @command('addremove',
206 @command('addremove',
207 similarityopts + walkopts + dryrunopts,
207 similarityopts + walkopts + dryrunopts,
208 _('[OPTION]... [FILE]...'),
208 _('[OPTION]... [FILE]...'),
209 inferrepo=True)
209 inferrepo=True)
210 def addremove(ui, repo, *pats, **opts):
210 def addremove(ui, repo, *pats, **opts):
211 """add all new files, delete all missing files
211 """add all new files, delete all missing files
212
212
213 Add all new files and remove all missing files from the
213 Add all new files and remove all missing files from the
214 repository.
214 repository.
215
215
216 New files are ignored if they match any of the patterns in
216 New files are ignored if they match any of the patterns in
217 ``.hgignore``. As with add, these changes take effect at the next
217 ``.hgignore``. As with add, these changes take effect at the next
218 commit.
218 commit.
219
219
220 Use the -s/--similarity option to detect renamed files. This
220 Use the -s/--similarity option to detect renamed files. This
221 option takes a percentage between 0 (disabled) and 100 (files must
221 option takes a percentage between 0 (disabled) and 100 (files must
222 be identical) as its parameter. With a parameter greater than 0,
222 be identical) as its parameter. With a parameter greater than 0,
223 this compares every removed file with every added file and records
223 this compares every removed file with every added file and records
224 those similar enough as renames. Detecting renamed files this way
224 those similar enough as renames. Detecting renamed files this way
225 can be expensive. After using this option, :hg:`status -C` can be
225 can be expensive. After using this option, :hg:`status -C` can be
226 used to check which files were identified as moved or renamed. If
226 used to check which files were identified as moved or renamed. If
227 not specified, -s/--similarity defaults to 100 and only renames of
227 not specified, -s/--similarity defaults to 100 and only renames of
228 identical files are detected.
228 identical files are detected.
229
229
230 Returns 0 if all files are successfully added.
230 Returns 0 if all files are successfully added.
231 """
231 """
232 try:
232 try:
233 sim = float(opts.get('similarity') or 100)
233 sim = float(opts.get('similarity') or 100)
234 except ValueError:
234 except ValueError:
235 raise util.Abort(_('similarity must be a number'))
235 raise util.Abort(_('similarity must be a number'))
236 if sim < 0 or sim > 100:
236 if sim < 0 or sim > 100:
237 raise util.Abort(_('similarity must be between 0 and 100'))
237 raise util.Abort(_('similarity must be between 0 and 100'))
238 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
238 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
239
239
240 @command('^annotate|blame',
240 @command('^annotate|blame',
241 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
241 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
242 ('', 'follow', None,
242 ('', 'follow', None,
243 _('follow copies/renames and list the filename (DEPRECATED)')),
243 _('follow copies/renames and list the filename (DEPRECATED)')),
244 ('', 'no-follow', None, _("don't follow copies and renames")),
244 ('', 'no-follow', None, _("don't follow copies and renames")),
245 ('a', 'text', None, _('treat all files as text')),
245 ('a', 'text', None, _('treat all files as text')),
246 ('u', 'user', None, _('list the author (long with -v)')),
246 ('u', 'user', None, _('list the author (long with -v)')),
247 ('f', 'file', None, _('list the filename')),
247 ('f', 'file', None, _('list the filename')),
248 ('d', 'date', None, _('list the date (short with -q)')),
248 ('d', 'date', None, _('list the date (short with -q)')),
249 ('n', 'number', None, _('list the revision number (default)')),
249 ('n', 'number', None, _('list the revision number (default)')),
250 ('c', 'changeset', None, _('list the changeset')),
250 ('c', 'changeset', None, _('list the changeset')),
251 ('l', 'line-number', None, _('show line number at the first appearance'))
251 ('l', 'line-number', None, _('show line number at the first appearance'))
252 ] + diffwsopts + walkopts + formatteropts,
252 ] + diffwsopts + walkopts + formatteropts,
253 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
253 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
254 inferrepo=True)
254 inferrepo=True)
255 def annotate(ui, repo, *pats, **opts):
255 def annotate(ui, repo, *pats, **opts):
256 """show changeset information by line for each file
256 """show changeset information by line for each file
257
257
258 List changes in files, showing the revision id responsible for
258 List changes in files, showing the revision id responsible for
259 each line
259 each line
260
260
261 This command is useful for discovering when a change was made and
261 This command is useful for discovering when a change was made and
262 by whom.
262 by whom.
263
263
264 Without the -a/--text option, annotate will avoid processing files
264 Without the -a/--text option, annotate will avoid processing files
265 it detects as binary. With -a, annotate will annotate the file
265 it detects as binary. With -a, annotate will annotate the file
266 anyway, although the results will probably be neither useful
266 anyway, although the results will probably be neither useful
267 nor desirable.
267 nor desirable.
268
268
269 Returns 0 on success.
269 Returns 0 on success.
270 """
270 """
271 if not pats:
271 if not pats:
272 raise util.Abort(_('at least one filename or pattern is required'))
272 raise util.Abort(_('at least one filename or pattern is required'))
273
273
274 if opts.get('follow'):
274 if opts.get('follow'):
275 # --follow is deprecated and now just an alias for -f/--file
275 # --follow is deprecated and now just an alias for -f/--file
276 # to mimic the behavior of Mercurial before version 1.5
276 # to mimic the behavior of Mercurial before version 1.5
277 opts['file'] = True
277 opts['file'] = True
278
278
279 fm = ui.formatter('annotate', opts)
279 fm = ui.formatter('annotate', opts)
280 datefunc = ui.quiet and util.shortdate or util.datestr
280 datefunc = ui.quiet and util.shortdate or util.datestr
281 hexfn = fm.hexfunc
281 hexfn = fm.hexfunc
282
282
283 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
283 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
284 ('number', ' ', lambda x: x[0].rev(), str),
284 ('number', ' ', lambda x: x[0].rev(), str),
285 ('changeset', ' ', lambda x: hexfn(x[0].node()), str),
285 ('changeset', ' ', lambda x: hexfn(x[0].node()), str),
286 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
286 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
287 ('file', ' ', lambda x: x[0].path(), str),
287 ('file', ' ', lambda x: x[0].path(), str),
288 ('line_number', ':', lambda x: x[1], str),
288 ('line_number', ':', lambda x: x[1], str),
289 ]
289 ]
290 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
290 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
291
291
292 if (not opts.get('user') and not opts.get('changeset')
292 if (not opts.get('user') and not opts.get('changeset')
293 and not opts.get('date') and not opts.get('file')):
293 and not opts.get('date') and not opts.get('file')):
294 opts['number'] = True
294 opts['number'] = True
295
295
296 linenumber = opts.get('line_number') is not None
296 linenumber = opts.get('line_number') is not None
297 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
297 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
298 raise util.Abort(_('at least one of -n/-c is required for -l'))
298 raise util.Abort(_('at least one of -n/-c is required for -l'))
299
299
300 if fm:
300 if fm:
301 def makefunc(get, fmt):
301 def makefunc(get, fmt):
302 return get
302 return get
303 else:
303 else:
304 def makefunc(get, fmt):
304 def makefunc(get, fmt):
305 return lambda x: fmt(get(x))
305 return lambda x: fmt(get(x))
306 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
306 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
307 if opts.get(op)]
307 if opts.get(op)]
308 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
308 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
309 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
309 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
310 if opts.get(op))
310 if opts.get(op))
311
311
312 def bad(x, y):
312 def bad(x, y):
313 raise util.Abort("%s: %s" % (x, y))
313 raise util.Abort("%s: %s" % (x, y))
314
314
315 ctx = scmutil.revsingle(repo, opts.get('rev'))
315 ctx = scmutil.revsingle(repo, opts.get('rev'))
316 m = scmutil.match(ctx, pats, opts)
316 m = scmutil.match(ctx, pats, opts)
317 m.bad = bad
317 m.bad = bad
318 follow = not opts.get('no_follow')
318 follow = not opts.get('no_follow')
319 diffopts = patch.diffopts(ui, opts, section='annotate')
319 diffopts = patch.diffopts(ui, opts, section='annotate')
320 for abs in ctx.walk(m):
320 for abs in ctx.walk(m):
321 fctx = ctx[abs]
321 fctx = ctx[abs]
322 if not opts.get('text') and util.binary(fctx.data()):
322 if not opts.get('text') and util.binary(fctx.data()):
323 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
323 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
324 continue
324 continue
325
325
326 lines = fctx.annotate(follow=follow, linenumber=linenumber,
326 lines = fctx.annotate(follow=follow, linenumber=linenumber,
327 diffopts=diffopts)
327 diffopts=diffopts)
328 formats = []
328 formats = []
329 pieces = []
329 pieces = []
330
330
331 for f, sep in funcmap:
331 for f, sep in funcmap:
332 l = [f(n) for n, dummy in lines]
332 l = [f(n) for n, dummy in lines]
333 if l:
333 if l:
334 if fm:
334 if fm:
335 formats.append(['%s' for x in l])
335 formats.append(['%s' for x in l])
336 else:
336 else:
337 sizes = [encoding.colwidth(x) for x in l]
337 sizes = [encoding.colwidth(x) for x in l]
338 ml = max(sizes)
338 ml = max(sizes)
339 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
339 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
340 pieces.append(l)
340 pieces.append(l)
341
341
342 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
342 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
343 fm.startitem()
343 fm.startitem()
344 fm.write(fields, "".join(f), *p)
344 fm.write(fields, "".join(f), *p)
345 fm.write('line', ": %s", l[1])
345 fm.write('line', ": %s", l[1])
346
346
347 if lines and not lines[-1][1].endswith('\n'):
347 if lines and not lines[-1][1].endswith('\n'):
348 fm.plain('\n')
348 fm.plain('\n')
349
349
350 fm.end()
350 fm.end()
351
351
352 @command('archive',
352 @command('archive',
353 [('', 'no-decode', None, _('do not pass files through decoders')),
353 [('', 'no-decode', None, _('do not pass files through decoders')),
354 ('p', 'prefix', '', _('directory prefix for files in archive'),
354 ('p', 'prefix', '', _('directory prefix for files in archive'),
355 _('PREFIX')),
355 _('PREFIX')),
356 ('r', 'rev', '', _('revision to distribute'), _('REV')),
356 ('r', 'rev', '', _('revision to distribute'), _('REV')),
357 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
357 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
358 ] + subrepoopts + walkopts,
358 ] + subrepoopts + walkopts,
359 _('[OPTION]... DEST'))
359 _('[OPTION]... DEST'))
360 def archive(ui, repo, dest, **opts):
360 def archive(ui, repo, dest, **opts):
361 '''create an unversioned archive of a repository revision
361 '''create an unversioned archive of a repository revision
362
362
363 By default, the revision used is the parent of the working
363 By default, the revision used is the parent of the working
364 directory; use -r/--rev to specify a different revision.
364 directory; use -r/--rev to specify a different revision.
365
365
366 The archive type is automatically detected based on file
366 The archive type is automatically detected based on file
367 extension (or override using -t/--type).
367 extension (or override using -t/--type).
368
368
369 .. container:: verbose
369 .. container:: verbose
370
370
371 Examples:
371 Examples:
372
372
373 - create a zip file containing the 1.0 release::
373 - create a zip file containing the 1.0 release::
374
374
375 hg archive -r 1.0 project-1.0.zip
375 hg archive -r 1.0 project-1.0.zip
376
376
377 - create a tarball excluding .hg files::
377 - create a tarball excluding .hg files::
378
378
379 hg archive project.tar.gz -X ".hg*"
379 hg archive project.tar.gz -X ".hg*"
380
380
381 Valid types are:
381 Valid types are:
382
382
383 :``files``: a directory full of files (default)
383 :``files``: a directory full of files (default)
384 :``tar``: tar archive, uncompressed
384 :``tar``: tar archive, uncompressed
385 :``tbz2``: tar archive, compressed using bzip2
385 :``tbz2``: tar archive, compressed using bzip2
386 :``tgz``: tar archive, compressed using gzip
386 :``tgz``: tar archive, compressed using gzip
387 :``uzip``: zip archive, uncompressed
387 :``uzip``: zip archive, uncompressed
388 :``zip``: zip archive, compressed using deflate
388 :``zip``: zip archive, compressed using deflate
389
389
390 The exact name of the destination archive or directory is given
390 The exact name of the destination archive or directory is given
391 using a format string; see :hg:`help export` for details.
391 using a format string; see :hg:`help export` for details.
392
392
393 Each member added to an archive file has a directory prefix
393 Each member added to an archive file has a directory prefix
394 prepended. Use -p/--prefix to specify a format string for the
394 prepended. Use -p/--prefix to specify a format string for the
395 prefix. The default is the basename of the archive, with suffixes
395 prefix. The default is the basename of the archive, with suffixes
396 removed.
396 removed.
397
397
398 Returns 0 on success.
398 Returns 0 on success.
399 '''
399 '''
400
400
401 ctx = scmutil.revsingle(repo, opts.get('rev'))
401 ctx = scmutil.revsingle(repo, opts.get('rev'))
402 if not ctx:
402 if not ctx:
403 raise util.Abort(_('no working directory: please specify a revision'))
403 raise util.Abort(_('no working directory: please specify a revision'))
404 node = ctx.node()
404 node = ctx.node()
405 dest = cmdutil.makefilename(repo, dest, node)
405 dest = cmdutil.makefilename(repo, dest, node)
406 if os.path.realpath(dest) == repo.root:
406 if os.path.realpath(dest) == repo.root:
407 raise util.Abort(_('repository root cannot be destination'))
407 raise util.Abort(_('repository root cannot be destination'))
408
408
409 kind = opts.get('type') or archival.guesskind(dest) or 'files'
409 kind = opts.get('type') or archival.guesskind(dest) or 'files'
410 prefix = opts.get('prefix')
410 prefix = opts.get('prefix')
411
411
412 if dest == '-':
412 if dest == '-':
413 if kind == 'files':
413 if kind == 'files':
414 raise util.Abort(_('cannot archive plain files to stdout'))
414 raise util.Abort(_('cannot archive plain files to stdout'))
415 dest = cmdutil.makefileobj(repo, dest)
415 dest = cmdutil.makefileobj(repo, dest)
416 if not prefix:
416 if not prefix:
417 prefix = os.path.basename(repo.root) + '-%h'
417 prefix = os.path.basename(repo.root) + '-%h'
418
418
419 prefix = cmdutil.makefilename(repo, prefix, node)
419 prefix = cmdutil.makefilename(repo, prefix, node)
420 matchfn = scmutil.match(ctx, [], opts)
420 matchfn = scmutil.match(ctx, [], opts)
421 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
421 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
422 matchfn, prefix, subrepos=opts.get('subrepos'))
422 matchfn, prefix, subrepos=opts.get('subrepos'))
423
423
424 @command('backout',
424 @command('backout',
425 [('', 'merge', None, _('merge with old dirstate parent after backout')),
425 [('', 'merge', None, _('merge with old dirstate parent after backout')),
426 ('', 'parent', '',
426 ('', 'parent', '',
427 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
427 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
428 ('r', 'rev', '', _('revision to backout'), _('REV')),
428 ('r', 'rev', '', _('revision to backout'), _('REV')),
429 ('e', 'edit', False, _('invoke editor on commit messages')),
429 ('e', 'edit', False, _('invoke editor on commit messages')),
430 ] + mergetoolopts + walkopts + commitopts + commitopts2,
430 ] + mergetoolopts + walkopts + commitopts + commitopts2,
431 _('[OPTION]... [-r] REV'))
431 _('[OPTION]... [-r] REV'))
432 def backout(ui, repo, node=None, rev=None, **opts):
432 def backout(ui, repo, node=None, rev=None, **opts):
433 '''reverse effect of earlier changeset
433 '''reverse effect of earlier changeset
434
434
435 Prepare a new changeset with the effect of REV undone in the
435 Prepare a new changeset with the effect of REV undone in the
436 current working directory.
436 current working directory.
437
437
438 If REV is the parent of the working directory, then this new changeset
438 If REV is the parent of the working directory, then this new changeset
439 is committed automatically. Otherwise, hg needs to merge the
439 is committed automatically. Otherwise, hg needs to merge the
440 changes and the merged result is left uncommitted.
440 changes and the merged result is left uncommitted.
441
441
442 .. note::
442 .. note::
443
443
444 backout cannot be used to fix either an unwanted or
444 backout cannot be used to fix either an unwanted or
445 incorrect merge.
445 incorrect merge.
446
446
447 .. container:: verbose
447 .. container:: verbose
448
448
449 By default, the pending changeset will have one parent,
449 By default, the pending changeset will have one parent,
450 maintaining a linear history. With --merge, the pending
450 maintaining a linear history. With --merge, the pending
451 changeset will instead have two parents: the old parent of the
451 changeset will instead have two parents: the old parent of the
452 working directory and a new child of REV that simply undoes REV.
452 working directory and a new child of REV that simply undoes REV.
453
453
454 Before version 1.7, the behavior without --merge was equivalent
454 Before version 1.7, the behavior without --merge was equivalent
455 to specifying --merge followed by :hg:`update --clean .` to
455 to specifying --merge followed by :hg:`update --clean .` to
456 cancel the merge and leave the child of REV as a head to be
456 cancel the merge and leave the child of REV as a head to be
457 merged separately.
457 merged separately.
458
458
459 See :hg:`help dates` for a list of formats valid for -d/--date.
459 See :hg:`help dates` for a list of formats valid for -d/--date.
460
460
461 Returns 0 on success, 1 if nothing to backout or there are unresolved
461 Returns 0 on success, 1 if nothing to backout or there are unresolved
462 files.
462 files.
463 '''
463 '''
464 if rev and node:
464 if rev and node:
465 raise util.Abort(_("please specify just one revision"))
465 raise util.Abort(_("please specify just one revision"))
466
466
467 if not rev:
467 if not rev:
468 rev = node
468 rev = node
469
469
470 if not rev:
470 if not rev:
471 raise util.Abort(_("please specify a revision to backout"))
471 raise util.Abort(_("please specify a revision to backout"))
472
472
473 date = opts.get('date')
473 date = opts.get('date')
474 if date:
474 if date:
475 opts['date'] = util.parsedate(date)
475 opts['date'] = util.parsedate(date)
476
476
477 cmdutil.checkunfinished(repo)
477 cmdutil.checkunfinished(repo)
478 cmdutil.bailifchanged(repo)
478 cmdutil.bailifchanged(repo)
479 node = scmutil.revsingle(repo, rev).node()
479 node = scmutil.revsingle(repo, rev).node()
480
480
481 op1, op2 = repo.dirstate.parents()
481 op1, op2 = repo.dirstate.parents()
482 if not repo.changelog.isancestor(node, op1):
482 if not repo.changelog.isancestor(node, op1):
483 raise util.Abort(_('cannot backout change that is not an ancestor'))
483 raise util.Abort(_('cannot backout change that is not an ancestor'))
484
484
485 p1, p2 = repo.changelog.parents(node)
485 p1, p2 = repo.changelog.parents(node)
486 if p1 == nullid:
486 if p1 == nullid:
487 raise util.Abort(_('cannot backout a change with no parents'))
487 raise util.Abort(_('cannot backout a change with no parents'))
488 if p2 != nullid:
488 if p2 != nullid:
489 if not opts.get('parent'):
489 if not opts.get('parent'):
490 raise util.Abort(_('cannot backout a merge changeset'))
490 raise util.Abort(_('cannot backout a merge changeset'))
491 p = repo.lookup(opts['parent'])
491 p = repo.lookup(opts['parent'])
492 if p not in (p1, p2):
492 if p not in (p1, p2):
493 raise util.Abort(_('%s is not a parent of %s') %
493 raise util.Abort(_('%s is not a parent of %s') %
494 (short(p), short(node)))
494 (short(p), short(node)))
495 parent = p
495 parent = p
496 else:
496 else:
497 if opts.get('parent'):
497 if opts.get('parent'):
498 raise util.Abort(_('cannot use --parent on non-merge changeset'))
498 raise util.Abort(_('cannot use --parent on non-merge changeset'))
499 parent = p1
499 parent = p1
500
500
501 # the backout should appear on the same branch
501 # the backout should appear on the same branch
502 wlock = repo.wlock()
502 wlock = repo.wlock()
503 try:
503 try:
504 branch = repo.dirstate.branch()
504 branch = repo.dirstate.branch()
505 bheads = repo.branchheads(branch)
505 bheads = repo.branchheads(branch)
506 rctx = scmutil.revsingle(repo, hex(parent))
506 rctx = scmutil.revsingle(repo, hex(parent))
507 if not opts.get('merge') and op1 != node:
507 if not opts.get('merge') and op1 != node:
508 try:
508 try:
509 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
509 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
510 'backout')
510 'backout')
511 repo.dirstate.beginparentchange()
511 repo.dirstate.beginparentchange()
512 stats = mergemod.update(repo, parent, True, True, False,
512 stats = mergemod.update(repo, parent, True, True, False,
513 node, False)
513 node, False)
514 repo.setparents(op1, op2)
514 repo.setparents(op1, op2)
515 repo.dirstate.endparentchange()
515 repo.dirstate.endparentchange()
516 hg._showstats(repo, stats)
516 hg._showstats(repo, stats)
517 if stats[3]:
517 if stats[3]:
518 repo.ui.status(_("use 'hg resolve' to retry unresolved "
518 repo.ui.status(_("use 'hg resolve' to retry unresolved "
519 "file merges\n"))
519 "file merges\n"))
520 else:
520 else:
521 msg = _("changeset %s backed out, "
521 msg = _("changeset %s backed out, "
522 "don't forget to commit.\n")
522 "don't forget to commit.\n")
523 ui.status(msg % short(node))
523 ui.status(msg % short(node))
524 return stats[3] > 0
524 return stats[3] > 0
525 finally:
525 finally:
526 ui.setconfig('ui', 'forcemerge', '', '')
526 ui.setconfig('ui', 'forcemerge', '', '')
527 else:
527 else:
528 hg.clean(repo, node, show_stats=False)
528 hg.clean(repo, node, show_stats=False)
529 repo.dirstate.setbranch(branch)
529 repo.dirstate.setbranch(branch)
530 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
530 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
531
531
532
532
533 def commitfunc(ui, repo, message, match, opts):
533 def commitfunc(ui, repo, message, match, opts):
534 editform = 'backout'
534 editform = 'backout'
535 e = cmdutil.getcommiteditor(editform=editform, **opts)
535 e = cmdutil.getcommiteditor(editform=editform, **opts)
536 if not message:
536 if not message:
537 # we don't translate commit messages
537 # we don't translate commit messages
538 message = "Backed out changeset %s" % short(node)
538 message = "Backed out changeset %s" % short(node)
539 e = cmdutil.getcommiteditor(edit=True, editform=editform)
539 e = cmdutil.getcommiteditor(edit=True, editform=editform)
540 return repo.commit(message, opts.get('user'), opts.get('date'),
540 return repo.commit(message, opts.get('user'), opts.get('date'),
541 match, editor=e)
541 match, editor=e)
542 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
542 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
543 if not newnode:
543 if not newnode:
544 ui.status(_("nothing changed\n"))
544 ui.status(_("nothing changed\n"))
545 return 1
545 return 1
546 cmdutil.commitstatus(repo, newnode, branch, bheads)
546 cmdutil.commitstatus(repo, newnode, branch, bheads)
547
547
548 def nice(node):
548 def nice(node):
549 return '%d:%s' % (repo.changelog.rev(node), short(node))
549 return '%d:%s' % (repo.changelog.rev(node), short(node))
550 ui.status(_('changeset %s backs out changeset %s\n') %
550 ui.status(_('changeset %s backs out changeset %s\n') %
551 (nice(repo.changelog.tip()), nice(node)))
551 (nice(repo.changelog.tip()), nice(node)))
552 if opts.get('merge') and op1 != node:
552 if opts.get('merge') and op1 != node:
553 hg.clean(repo, op1, show_stats=False)
553 hg.clean(repo, op1, show_stats=False)
554 ui.status(_('merging with changeset %s\n')
554 ui.status(_('merging with changeset %s\n')
555 % nice(repo.changelog.tip()))
555 % nice(repo.changelog.tip()))
556 try:
556 try:
557 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
557 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
558 'backout')
558 'backout')
559 return hg.merge(repo, hex(repo.changelog.tip()))
559 return hg.merge(repo, hex(repo.changelog.tip()))
560 finally:
560 finally:
561 ui.setconfig('ui', 'forcemerge', '', '')
561 ui.setconfig('ui', 'forcemerge', '', '')
562 finally:
562 finally:
563 wlock.release()
563 wlock.release()
564 return 0
564 return 0
565
565
566 @command('bisect',
566 @command('bisect',
567 [('r', 'reset', False, _('reset bisect state')),
567 [('r', 'reset', False, _('reset bisect state')),
568 ('g', 'good', False, _('mark changeset good')),
568 ('g', 'good', False, _('mark changeset good')),
569 ('b', 'bad', False, _('mark changeset bad')),
569 ('b', 'bad', False, _('mark changeset bad')),
570 ('s', 'skip', False, _('skip testing changeset')),
570 ('s', 'skip', False, _('skip testing changeset')),
571 ('e', 'extend', False, _('extend the bisect range')),
571 ('e', 'extend', False, _('extend the bisect range')),
572 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
572 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
573 ('U', 'noupdate', False, _('do not update to target'))],
573 ('U', 'noupdate', False, _('do not update to target'))],
574 _("[-gbsr] [-U] [-c CMD] [REV]"))
574 _("[-gbsr] [-U] [-c CMD] [REV]"))
575 def bisect(ui, repo, rev=None, extra=None, command=None,
575 def bisect(ui, repo, rev=None, extra=None, command=None,
576 reset=None, good=None, bad=None, skip=None, extend=None,
576 reset=None, good=None, bad=None, skip=None, extend=None,
577 noupdate=None):
577 noupdate=None):
578 """subdivision search of changesets
578 """subdivision search of changesets
579
579
580 This command helps to find changesets which introduce problems. To
580 This command helps to find changesets which introduce problems. To
581 use, mark the earliest changeset you know exhibits the problem as
581 use, mark the earliest changeset you know exhibits the problem as
582 bad, then mark the latest changeset which is free from the problem
582 bad, then mark the latest changeset which is free from the problem
583 as good. Bisect will update your working directory to a revision
583 as good. Bisect will update your working directory to a revision
584 for testing (unless the -U/--noupdate option is specified). Once
584 for testing (unless the -U/--noupdate option is specified). Once
585 you have performed tests, mark the working directory as good or
585 you have performed tests, mark the working directory as good or
586 bad, and bisect will either update to another candidate changeset
586 bad, and bisect will either update to another candidate changeset
587 or announce that it has found the bad revision.
587 or announce that it has found the bad revision.
588
588
589 As a shortcut, you can also use the revision argument to mark a
589 As a shortcut, you can also use the revision argument to mark a
590 revision as good or bad without checking it out first.
590 revision as good or bad without checking it out first.
591
591
592 If you supply a command, it will be used for automatic bisection.
592 If you supply a command, it will be used for automatic bisection.
593 The environment variable HG_NODE will contain the ID of the
593 The environment variable HG_NODE will contain the ID of the
594 changeset being tested. The exit status of the command will be
594 changeset being tested. The exit status of the command will be
595 used to mark revisions as good or bad: status 0 means good, 125
595 used to mark revisions as good or bad: status 0 means good, 125
596 means to skip the revision, 127 (command not found) will abort the
596 means to skip the revision, 127 (command not found) will abort the
597 bisection, and any other non-zero exit status means the revision
597 bisection, and any other non-zero exit status means the revision
598 is bad.
598 is bad.
599
599
600 .. container:: verbose
600 .. container:: verbose
601
601
602 Some examples:
602 Some examples:
603
603
604 - start a bisection with known bad revision 34, and good revision 12::
604 - start a bisection with known bad revision 34, and good revision 12::
605
605
606 hg bisect --bad 34
606 hg bisect --bad 34
607 hg bisect --good 12
607 hg bisect --good 12
608
608
609 - advance the current bisection by marking current revision as good or
609 - advance the current bisection by marking current revision as good or
610 bad::
610 bad::
611
611
612 hg bisect --good
612 hg bisect --good
613 hg bisect --bad
613 hg bisect --bad
614
614
615 - mark the current revision, or a known revision, to be skipped (e.g. if
615 - mark the current revision, or a known revision, to be skipped (e.g. if
616 that revision is not usable because of another issue)::
616 that revision is not usable because of another issue)::
617
617
618 hg bisect --skip
618 hg bisect --skip
619 hg bisect --skip 23
619 hg bisect --skip 23
620
620
621 - skip all revisions that do not touch directories ``foo`` or ``bar``::
621 - skip all revisions that do not touch directories ``foo`` or ``bar``::
622
622
623 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
623 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
624
624
625 - forget the current bisection::
625 - forget the current bisection::
626
626
627 hg bisect --reset
627 hg bisect --reset
628
628
629 - use 'make && make tests' to automatically find the first broken
629 - use 'make && make tests' to automatically find the first broken
630 revision::
630 revision::
631
631
632 hg bisect --reset
632 hg bisect --reset
633 hg bisect --bad 34
633 hg bisect --bad 34
634 hg bisect --good 12
634 hg bisect --good 12
635 hg bisect --command "make && make tests"
635 hg bisect --command "make && make tests"
636
636
637 - see all changesets whose states are already known in the current
637 - see all changesets whose states are already known in the current
638 bisection::
638 bisection::
639
639
640 hg log -r "bisect(pruned)"
640 hg log -r "bisect(pruned)"
641
641
642 - see the changeset currently being bisected (especially useful
642 - see the changeset currently being bisected (especially useful
643 if running with -U/--noupdate)::
643 if running with -U/--noupdate)::
644
644
645 hg log -r "bisect(current)"
645 hg log -r "bisect(current)"
646
646
647 - see all changesets that took part in the current bisection::
647 - see all changesets that took part in the current bisection::
648
648
649 hg log -r "bisect(range)"
649 hg log -r "bisect(range)"
650
650
651 - you can even get a nice graph::
651 - you can even get a nice graph::
652
652
653 hg log --graph -r "bisect(range)"
653 hg log --graph -r "bisect(range)"
654
654
655 See :hg:`help revsets` for more about the `bisect()` keyword.
655 See :hg:`help revsets` for more about the `bisect()` keyword.
656
656
657 Returns 0 on success.
657 Returns 0 on success.
658 """
658 """
659 def extendbisectrange(nodes, good):
659 def extendbisectrange(nodes, good):
660 # bisect is incomplete when it ends on a merge node and
660 # bisect is incomplete when it ends on a merge node and
661 # one of the parent was not checked.
661 # one of the parent was not checked.
662 parents = repo[nodes[0]].parents()
662 parents = repo[nodes[0]].parents()
663 if len(parents) > 1:
663 if len(parents) > 1:
664 side = good and state['bad'] or state['good']
664 side = good and state['bad'] or state['good']
665 num = len(set(i.node() for i in parents) & set(side))
665 num = len(set(i.node() for i in parents) & set(side))
666 if num == 1:
666 if num == 1:
667 return parents[0].ancestor(parents[1])
667 return parents[0].ancestor(parents[1])
668 return None
668 return None
669
669
670 def print_result(nodes, good):
670 def print_result(nodes, good):
671 displayer = cmdutil.show_changeset(ui, repo, {})
671 displayer = cmdutil.show_changeset(ui, repo, {})
672 if len(nodes) == 1:
672 if len(nodes) == 1:
673 # narrowed it down to a single revision
673 # narrowed it down to a single revision
674 if good:
674 if good:
675 ui.write(_("The first good revision is:\n"))
675 ui.write(_("The first good revision is:\n"))
676 else:
676 else:
677 ui.write(_("The first bad revision is:\n"))
677 ui.write(_("The first bad revision is:\n"))
678 displayer.show(repo[nodes[0]])
678 displayer.show(repo[nodes[0]])
679 extendnode = extendbisectrange(nodes, good)
679 extendnode = extendbisectrange(nodes, good)
680 if extendnode is not None:
680 if extendnode is not None:
681 ui.write(_('Not all ancestors of this changeset have been'
681 ui.write(_('Not all ancestors of this changeset have been'
682 ' checked.\nUse bisect --extend to continue the '
682 ' checked.\nUse bisect --extend to continue the '
683 'bisection from\nthe common ancestor, %s.\n')
683 'bisection from\nthe common ancestor, %s.\n')
684 % extendnode)
684 % extendnode)
685 else:
685 else:
686 # multiple possible revisions
686 # multiple possible revisions
687 if good:
687 if good:
688 ui.write(_("Due to skipped revisions, the first "
688 ui.write(_("Due to skipped revisions, the first "
689 "good revision could be any of:\n"))
689 "good revision could be any of:\n"))
690 else:
690 else:
691 ui.write(_("Due to skipped revisions, the first "
691 ui.write(_("Due to skipped revisions, the first "
692 "bad revision could be any of:\n"))
692 "bad revision could be any of:\n"))
693 for n in nodes:
693 for n in nodes:
694 displayer.show(repo[n])
694 displayer.show(repo[n])
695 displayer.close()
695 displayer.close()
696
696
697 def check_state(state, interactive=True):
697 def check_state(state, interactive=True):
698 if not state['good'] or not state['bad']:
698 if not state['good'] or not state['bad']:
699 if (good or bad or skip or reset) and interactive:
699 if (good or bad or skip or reset) and interactive:
700 return
700 return
701 if not state['good']:
701 if not state['good']:
702 raise util.Abort(_('cannot bisect (no known good revisions)'))
702 raise util.Abort(_('cannot bisect (no known good revisions)'))
703 else:
703 else:
704 raise util.Abort(_('cannot bisect (no known bad revisions)'))
704 raise util.Abort(_('cannot bisect (no known bad revisions)'))
705 return True
705 return True
706
706
707 # backward compatibility
707 # backward compatibility
708 if rev in "good bad reset init".split():
708 if rev in "good bad reset init".split():
709 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
709 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
710 cmd, rev, extra = rev, extra, None
710 cmd, rev, extra = rev, extra, None
711 if cmd == "good":
711 if cmd == "good":
712 good = True
712 good = True
713 elif cmd == "bad":
713 elif cmd == "bad":
714 bad = True
714 bad = True
715 else:
715 else:
716 reset = True
716 reset = True
717 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
717 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
718 raise util.Abort(_('incompatible arguments'))
718 raise util.Abort(_('incompatible arguments'))
719
719
720 cmdutil.checkunfinished(repo)
720 cmdutil.checkunfinished(repo)
721
721
722 if reset:
722 if reset:
723 p = repo.join("bisect.state")
723 p = repo.join("bisect.state")
724 if os.path.exists(p):
724 if os.path.exists(p):
725 os.unlink(p)
725 os.unlink(p)
726 return
726 return
727
727
728 state = hbisect.load_state(repo)
728 state = hbisect.load_state(repo)
729
729
730 if command:
730 if command:
731 changesets = 1
731 changesets = 1
732 if noupdate:
732 if noupdate:
733 try:
733 try:
734 node = state['current'][0]
734 node = state['current'][0]
735 except LookupError:
735 except LookupError:
736 raise util.Abort(_('current bisect revision is unknown - '
736 raise util.Abort(_('current bisect revision is unknown - '
737 'start a new bisect to fix'))
737 'start a new bisect to fix'))
738 else:
738 else:
739 node, p2 = repo.dirstate.parents()
739 node, p2 = repo.dirstate.parents()
740 if p2 != nullid:
740 if p2 != nullid:
741 raise util.Abort(_('current bisect revision is a merge'))
741 raise util.Abort(_('current bisect revision is a merge'))
742 try:
742 try:
743 while changesets:
743 while changesets:
744 # update state
744 # update state
745 state['current'] = [node]
745 state['current'] = [node]
746 hbisect.save_state(repo, state)
746 hbisect.save_state(repo, state)
747 status = ui.system(command, environ={'HG_NODE': hex(node)})
747 status = ui.system(command, environ={'HG_NODE': hex(node)})
748 if status == 125:
748 if status == 125:
749 transition = "skip"
749 transition = "skip"
750 elif status == 0:
750 elif status == 0:
751 transition = "good"
751 transition = "good"
752 # status < 0 means process was killed
752 # status < 0 means process was killed
753 elif status == 127:
753 elif status == 127:
754 raise util.Abort(_("failed to execute %s") % command)
754 raise util.Abort(_("failed to execute %s") % command)
755 elif status < 0:
755 elif status < 0:
756 raise util.Abort(_("%s killed") % command)
756 raise util.Abort(_("%s killed") % command)
757 else:
757 else:
758 transition = "bad"
758 transition = "bad"
759 ctx = scmutil.revsingle(repo, rev, node)
759 ctx = scmutil.revsingle(repo, rev, node)
760 rev = None # clear for future iterations
760 rev = None # clear for future iterations
761 state[transition].append(ctx.node())
761 state[transition].append(ctx.node())
762 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
762 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
763 check_state(state, interactive=False)
763 check_state(state, interactive=False)
764 # bisect
764 # bisect
765 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
765 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
766 # update to next check
766 # update to next check
767 node = nodes[0]
767 node = nodes[0]
768 if not noupdate:
768 if not noupdate:
769 cmdutil.bailifchanged(repo)
769 cmdutil.bailifchanged(repo)
770 hg.clean(repo, node, show_stats=False)
770 hg.clean(repo, node, show_stats=False)
771 finally:
771 finally:
772 state['current'] = [node]
772 state['current'] = [node]
773 hbisect.save_state(repo, state)
773 hbisect.save_state(repo, state)
774 print_result(nodes, bgood)
774 print_result(nodes, bgood)
775 return
775 return
776
776
777 # update state
777 # update state
778
778
779 if rev:
779 if rev:
780 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
780 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
781 else:
781 else:
782 nodes = [repo.lookup('.')]
782 nodes = [repo.lookup('.')]
783
783
784 if good or bad or skip:
784 if good or bad or skip:
785 if good:
785 if good:
786 state['good'] += nodes
786 state['good'] += nodes
787 elif bad:
787 elif bad:
788 state['bad'] += nodes
788 state['bad'] += nodes
789 elif skip:
789 elif skip:
790 state['skip'] += nodes
790 state['skip'] += nodes
791 hbisect.save_state(repo, state)
791 hbisect.save_state(repo, state)
792
792
793 if not check_state(state):
793 if not check_state(state):
794 return
794 return
795
795
796 # actually bisect
796 # actually bisect
797 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
797 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
798 if extend:
798 if extend:
799 if not changesets:
799 if not changesets:
800 extendnode = extendbisectrange(nodes, good)
800 extendnode = extendbisectrange(nodes, good)
801 if extendnode is not None:
801 if extendnode is not None:
802 ui.write(_("Extending search to changeset %d:%s\n")
802 ui.write(_("Extending search to changeset %d:%s\n")
803 % (extendnode.rev(), extendnode))
803 % (extendnode.rev(), extendnode))
804 state['current'] = [extendnode.node()]
804 state['current'] = [extendnode.node()]
805 hbisect.save_state(repo, state)
805 hbisect.save_state(repo, state)
806 if noupdate:
806 if noupdate:
807 return
807 return
808 cmdutil.bailifchanged(repo)
808 cmdutil.bailifchanged(repo)
809 return hg.clean(repo, extendnode.node())
809 return hg.clean(repo, extendnode.node())
810 raise util.Abort(_("nothing to extend"))
810 raise util.Abort(_("nothing to extend"))
811
811
812 if changesets == 0:
812 if changesets == 0:
813 print_result(nodes, good)
813 print_result(nodes, good)
814 else:
814 else:
815 assert len(nodes) == 1 # only a single node can be tested next
815 assert len(nodes) == 1 # only a single node can be tested next
816 node = nodes[0]
816 node = nodes[0]
817 # compute the approximate number of remaining tests
817 # compute the approximate number of remaining tests
818 tests, size = 0, 2
818 tests, size = 0, 2
819 while size <= changesets:
819 while size <= changesets:
820 tests, size = tests + 1, size * 2
820 tests, size = tests + 1, size * 2
821 rev = repo.changelog.rev(node)
821 rev = repo.changelog.rev(node)
822 ui.write(_("Testing changeset %d:%s "
822 ui.write(_("Testing changeset %d:%s "
823 "(%d changesets remaining, ~%d tests)\n")
823 "(%d changesets remaining, ~%d tests)\n")
824 % (rev, short(node), changesets, tests))
824 % (rev, short(node), changesets, tests))
825 state['current'] = [node]
825 state['current'] = [node]
826 hbisect.save_state(repo, state)
826 hbisect.save_state(repo, state)
827 if not noupdate:
827 if not noupdate:
828 cmdutil.bailifchanged(repo)
828 cmdutil.bailifchanged(repo)
829 return hg.clean(repo, node)
829 return hg.clean(repo, node)
830
830
831 @command('bookmarks|bookmark',
831 @command('bookmarks|bookmark',
832 [('f', 'force', False, _('force')),
832 [('f', 'force', False, _('force')),
833 ('r', 'rev', '', _('revision'), _('REV')),
833 ('r', 'rev', '', _('revision'), _('REV')),
834 ('d', 'delete', False, _('delete a given bookmark')),
834 ('d', 'delete', False, _('delete a given bookmark')),
835 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
835 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
836 ('i', 'inactive', False, _('mark a bookmark inactive')),
836 ('i', 'inactive', False, _('mark a bookmark inactive')),
837 ] + formatteropts,
837 ] + formatteropts,
838 _('hg bookmarks [OPTIONS]... [NAME]...'))
838 _('hg bookmarks [OPTIONS]... [NAME]...'))
839 def bookmark(ui, repo, *names, **opts):
839 def bookmark(ui, repo, *names, **opts):
840 '''create a new bookmark or list existing bookmarks
840 '''create a new bookmark or list existing bookmarks
841
841
842 Bookmarks are labels on changesets to help track lines of development.
842 Bookmarks are labels on changesets to help track lines of development.
843 Bookmarks are unversioned and can be moved, renamed and deleted.
843 Bookmarks are unversioned and can be moved, renamed and deleted.
844 Deleting or moving a bookmark has no effect on the associated changesets.
844 Deleting or moving a bookmark has no effect on the associated changesets.
845
845
846 Creating or updating to a bookmark causes it to be marked as 'active'.
846 Creating or updating to a bookmark causes it to be marked as 'active'.
847 The active bookmark is indicated with a '*'.
847 The active bookmark is indicated with a '*'.
848 When a commit is made, the active bookmark will advance to the new commit.
848 When a commit is made, the active bookmark will advance to the new commit.
849 A plain :hg:`update` will also advance an active bookmark, if possible.
849 A plain :hg:`update` will also advance an active bookmark, if possible.
850 Updating away from a bookmark will cause it to be deactivated.
850 Updating away from a bookmark will cause it to be deactivated.
851
851
852 Bookmarks can be pushed and pulled between repositories (see
852 Bookmarks can be pushed and pulled between repositories (see
853 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
853 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
854 diverged, a new 'divergent bookmark' of the form 'name@path' will
854 diverged, a new 'divergent bookmark' of the form 'name@path' will
855 be created. Using :hg:`merge` will resolve the divergence.
855 be created. Using :hg:`merge` will resolve the divergence.
856
856
857 A bookmark named '@' has the special property that :hg:`clone` will
857 A bookmark named '@' has the special property that :hg:`clone` will
858 check it out by default if it exists.
858 check it out by default if it exists.
859
859
860 .. container:: verbose
860 .. container:: verbose
861
861
862 Examples:
862 Examples:
863
863
864 - create an active bookmark for a new line of development::
864 - create an active bookmark for a new line of development::
865
865
866 hg book new-feature
866 hg book new-feature
867
867
868 - create an inactive bookmark as a place marker::
868 - create an inactive bookmark as a place marker::
869
869
870 hg book -i reviewed
870 hg book -i reviewed
871
871
872 - create an inactive bookmark on another changeset::
872 - create an inactive bookmark on another changeset::
873
873
874 hg book -r .^ tested
874 hg book -r .^ tested
875
875
876 - move the '@' bookmark from another branch::
876 - move the '@' bookmark from another branch::
877
877
878 hg book -f @
878 hg book -f @
879 '''
879 '''
880 force = opts.get('force')
880 force = opts.get('force')
881 rev = opts.get('rev')
881 rev = opts.get('rev')
882 delete = opts.get('delete')
882 delete = opts.get('delete')
883 rename = opts.get('rename')
883 rename = opts.get('rename')
884 inactive = opts.get('inactive')
884 inactive = opts.get('inactive')
885
885
886 def checkformat(mark):
886 def checkformat(mark):
887 mark = mark.strip()
887 mark = mark.strip()
888 if not mark:
888 if not mark:
889 raise util.Abort(_("bookmark names cannot consist entirely of "
889 raise util.Abort(_("bookmark names cannot consist entirely of "
890 "whitespace"))
890 "whitespace"))
891 scmutil.checknewlabel(repo, mark, 'bookmark')
891 scmutil.checknewlabel(repo, mark, 'bookmark')
892 return mark
892 return mark
893
893
894 def checkconflict(repo, mark, cur, force=False, target=None):
894 def checkconflict(repo, mark, cur, force=False, target=None):
895 if mark in marks and not force:
895 if mark in marks and not force:
896 if target:
896 if target:
897 if marks[mark] == target and target == cur:
897 if marks[mark] == target and target == cur:
898 # re-activating a bookmark
898 # re-activating a bookmark
899 return
899 return
900 anc = repo.changelog.ancestors([repo[target].rev()])
900 anc = repo.changelog.ancestors([repo[target].rev()])
901 bmctx = repo[marks[mark]]
901 bmctx = repo[marks[mark]]
902 divs = [repo[b].node() for b in marks
902 divs = [repo[b].node() for b in marks
903 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
903 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
904
904
905 # allow resolving a single divergent bookmark even if moving
905 # allow resolving a single divergent bookmark even if moving
906 # the bookmark across branches when a revision is specified
906 # the bookmark across branches when a revision is specified
907 # that contains a divergent bookmark
907 # that contains a divergent bookmark
908 if bmctx.rev() not in anc and target in divs:
908 if bmctx.rev() not in anc and target in divs:
909 bookmarks.deletedivergent(repo, [target], mark)
909 bookmarks.deletedivergent(repo, [target], mark)
910 return
910 return
911
911
912 deletefrom = [b for b in divs
912 deletefrom = [b for b in divs
913 if repo[b].rev() in anc or b == target]
913 if repo[b].rev() in anc or b == target]
914 bookmarks.deletedivergent(repo, deletefrom, mark)
914 bookmarks.deletedivergent(repo, deletefrom, mark)
915 if bookmarks.validdest(repo, bmctx, repo[target]):
915 if bookmarks.validdest(repo, bmctx, repo[target]):
916 ui.status(_("moving bookmark '%s' forward from %s\n") %
916 ui.status(_("moving bookmark '%s' forward from %s\n") %
917 (mark, short(bmctx.node())))
917 (mark, short(bmctx.node())))
918 return
918 return
919 raise util.Abort(_("bookmark '%s' already exists "
919 raise util.Abort(_("bookmark '%s' already exists "
920 "(use -f to force)") % mark)
920 "(use -f to force)") % mark)
921 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
921 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
922 and not force):
922 and not force):
923 raise util.Abort(
923 raise util.Abort(
924 _("a bookmark cannot have the name of an existing branch"))
924 _("a bookmark cannot have the name of an existing branch"))
925
925
926 if delete and rename:
926 if delete and rename:
927 raise util.Abort(_("--delete and --rename are incompatible"))
927 raise util.Abort(_("--delete and --rename are incompatible"))
928 if delete and rev:
928 if delete and rev:
929 raise util.Abort(_("--rev is incompatible with --delete"))
929 raise util.Abort(_("--rev is incompatible with --delete"))
930 if rename and rev:
930 if rename and rev:
931 raise util.Abort(_("--rev is incompatible with --rename"))
931 raise util.Abort(_("--rev is incompatible with --rename"))
932 if not names and (delete or rev):
932 if not names and (delete or rev):
933 raise util.Abort(_("bookmark name required"))
933 raise util.Abort(_("bookmark name required"))
934
934
935 if delete or rename or names or inactive:
935 if delete or rename or names or inactive:
936 wlock = repo.wlock()
936 wlock = repo.wlock()
937 try:
937 try:
938 cur = repo.changectx('.').node()
938 cur = repo.changectx('.').node()
939 marks = repo._bookmarks
939 marks = repo._bookmarks
940 if delete:
940 if delete:
941 for mark in names:
941 for mark in names:
942 if mark not in marks:
942 if mark not in marks:
943 raise util.Abort(_("bookmark '%s' does not exist") %
943 raise util.Abort(_("bookmark '%s' does not exist") %
944 mark)
944 mark)
945 if mark == repo._bookmarkcurrent:
945 if mark == repo._bookmarkcurrent:
946 bookmarks.unsetcurrent(repo)
946 bookmarks.unsetcurrent(repo)
947 del marks[mark]
947 del marks[mark]
948 marks.write()
948 marks.write()
949
949
950 elif rename:
950 elif rename:
951 if not names:
951 if not names:
952 raise util.Abort(_("new bookmark name required"))
952 raise util.Abort(_("new bookmark name required"))
953 elif len(names) > 1:
953 elif len(names) > 1:
954 raise util.Abort(_("only one new bookmark name allowed"))
954 raise util.Abort(_("only one new bookmark name allowed"))
955 mark = checkformat(names[0])
955 mark = checkformat(names[0])
956 if rename not in marks:
956 if rename not in marks:
957 raise util.Abort(_("bookmark '%s' does not exist") % rename)
957 raise util.Abort(_("bookmark '%s' does not exist") % rename)
958 checkconflict(repo, mark, cur, force)
958 checkconflict(repo, mark, cur, force)
959 marks[mark] = marks[rename]
959 marks[mark] = marks[rename]
960 if repo._bookmarkcurrent == rename and not inactive:
960 if repo._bookmarkcurrent == rename and not inactive:
961 bookmarks.setcurrent(repo, mark)
961 bookmarks.setcurrent(repo, mark)
962 del marks[rename]
962 del marks[rename]
963 marks.write()
963 marks.write()
964
964
965 elif names:
965 elif names:
966 newact = None
966 newact = None
967 for mark in names:
967 for mark in names:
968 mark = checkformat(mark)
968 mark = checkformat(mark)
969 if newact is None:
969 if newact is None:
970 newact = mark
970 newact = mark
971 if inactive and mark == repo._bookmarkcurrent:
971 if inactive and mark == repo._bookmarkcurrent:
972 bookmarks.unsetcurrent(repo)
972 bookmarks.unsetcurrent(repo)
973 return
973 return
974 tgt = cur
974 tgt = cur
975 if rev:
975 if rev:
976 tgt = scmutil.revsingle(repo, rev).node()
976 tgt = scmutil.revsingle(repo, rev).node()
977 checkconflict(repo, mark, cur, force, tgt)
977 checkconflict(repo, mark, cur, force, tgt)
978 marks[mark] = tgt
978 marks[mark] = tgt
979 if not inactive and cur == marks[newact] and not rev:
979 if not inactive and cur == marks[newact] and not rev:
980 bookmarks.setcurrent(repo, newact)
980 bookmarks.setcurrent(repo, newact)
981 elif cur != tgt and newact == repo._bookmarkcurrent:
981 elif cur != tgt and newact == repo._bookmarkcurrent:
982 bookmarks.unsetcurrent(repo)
982 bookmarks.unsetcurrent(repo)
983 marks.write()
983 marks.write()
984
984
985 elif inactive:
985 elif inactive:
986 if len(marks) == 0:
986 if len(marks) == 0:
987 ui.status(_("no bookmarks set\n"))
987 ui.status(_("no bookmarks set\n"))
988 elif not repo._bookmarkcurrent:
988 elif not repo._bookmarkcurrent:
989 ui.status(_("no active bookmark\n"))
989 ui.status(_("no active bookmark\n"))
990 else:
990 else:
991 bookmarks.unsetcurrent(repo)
991 bookmarks.unsetcurrent(repo)
992 finally:
992 finally:
993 wlock.release()
993 wlock.release()
994 else: # show bookmarks
994 else: # show bookmarks
995 fm = ui.formatter('bookmarks', opts)
995 fm = ui.formatter('bookmarks', opts)
996 hexfn = fm.hexfunc
996 hexfn = fm.hexfunc
997 marks = repo._bookmarks
997 marks = repo._bookmarks
998 if len(marks) == 0 and not fm:
998 if len(marks) == 0 and not fm:
999 ui.status(_("no bookmarks set\n"))
999 ui.status(_("no bookmarks set\n"))
1000 for bmark, n in sorted(marks.iteritems()):
1000 for bmark, n in sorted(marks.iteritems()):
1001 current = repo._bookmarkcurrent
1001 current = repo._bookmarkcurrent
1002 if bmark == current:
1002 if bmark == current:
1003 prefix, label = '*', 'bookmarks.current'
1003 prefix, label = '*', 'bookmarks.current'
1004 else:
1004 else:
1005 prefix, label = ' ', ''
1005 prefix, label = ' ', ''
1006
1006
1007 fm.startitem()
1007 fm.startitem()
1008 if not ui.quiet:
1008 if not ui.quiet:
1009 fm.plain(' %s ' % prefix, label=label)
1009 fm.plain(' %s ' % prefix, label=label)
1010 fm.write('bookmark', '%s', bmark, label=label)
1010 fm.write('bookmark', '%s', bmark, label=label)
1011 pad = " " * (25 - encoding.colwidth(bmark))
1011 pad = " " * (25 - encoding.colwidth(bmark))
1012 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1012 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1013 repo.changelog.rev(n), hexfn(n), label=label)
1013 repo.changelog.rev(n), hexfn(n), label=label)
1014 fm.data(active=(bmark == current))
1014 fm.data(active=(bmark == current))
1015 fm.plain('\n')
1015 fm.plain('\n')
1016 fm.end()
1016 fm.end()
1017
1017
1018 @command('branch',
1018 @command('branch',
1019 [('f', 'force', None,
1019 [('f', 'force', None,
1020 _('set branch name even if it shadows an existing branch')),
1020 _('set branch name even if it shadows an existing branch')),
1021 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1021 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1022 _('[-fC] [NAME]'))
1022 _('[-fC] [NAME]'))
1023 def branch(ui, repo, label=None, **opts):
1023 def branch(ui, repo, label=None, **opts):
1024 """set or show the current branch name
1024 """set or show the current branch name
1025
1025
1026 .. note::
1026 .. note::
1027
1027
1028 Branch names are permanent and global. Use :hg:`bookmark` to create a
1028 Branch names are permanent and global. Use :hg:`bookmark` to create a
1029 light-weight bookmark instead. See :hg:`help glossary` for more
1029 light-weight bookmark instead. See :hg:`help glossary` for more
1030 information about named branches and bookmarks.
1030 information about named branches and bookmarks.
1031
1031
1032 With no argument, show the current branch name. With one argument,
1032 With no argument, show the current branch name. With one argument,
1033 set the working directory branch name (the branch will not exist
1033 set the working directory branch name (the branch will not exist
1034 in the repository until the next commit). Standard practice
1034 in the repository until the next commit). Standard practice
1035 recommends that primary development take place on the 'default'
1035 recommends that primary development take place on the 'default'
1036 branch.
1036 branch.
1037
1037
1038 Unless -f/--force is specified, branch will not let you set a
1038 Unless -f/--force is specified, branch will not let you set a
1039 branch name that already exists, even if it's inactive.
1039 branch name that already exists, even if it's inactive.
1040
1040
1041 Use -C/--clean to reset the working directory branch to that of
1041 Use -C/--clean to reset the working directory branch to that of
1042 the parent of the working directory, negating a previous branch
1042 the parent of the working directory, negating a previous branch
1043 change.
1043 change.
1044
1044
1045 Use the command :hg:`update` to switch to an existing branch. Use
1045 Use the command :hg:`update` to switch to an existing branch. Use
1046 :hg:`commit --close-branch` to mark this branch as closed.
1046 :hg:`commit --close-branch` to mark this branch as closed.
1047
1047
1048 Returns 0 on success.
1048 Returns 0 on success.
1049 """
1049 """
1050 if label:
1050 if label:
1051 label = label.strip()
1051 label = label.strip()
1052
1052
1053 if not opts.get('clean') and not label:
1053 if not opts.get('clean') and not label:
1054 ui.write("%s\n" % repo.dirstate.branch())
1054 ui.write("%s\n" % repo.dirstate.branch())
1055 return
1055 return
1056
1056
1057 wlock = repo.wlock()
1057 wlock = repo.wlock()
1058 try:
1058 try:
1059 if opts.get('clean'):
1059 if opts.get('clean'):
1060 label = repo[None].p1().branch()
1060 label = repo[None].p1().branch()
1061 repo.dirstate.setbranch(label)
1061 repo.dirstate.setbranch(label)
1062 ui.status(_('reset working directory to branch %s\n') % label)
1062 ui.status(_('reset working directory to branch %s\n') % label)
1063 elif label:
1063 elif label:
1064 if not opts.get('force') and label in repo.branchmap():
1064 if not opts.get('force') and label in repo.branchmap():
1065 if label not in [p.branch() for p in repo.parents()]:
1065 if label not in [p.branch() for p in repo.parents()]:
1066 raise util.Abort(_('a branch of the same name already'
1066 raise util.Abort(_('a branch of the same name already'
1067 ' exists'),
1067 ' exists'),
1068 # i18n: "it" refers to an existing branch
1068 # i18n: "it" refers to an existing branch
1069 hint=_("use 'hg update' to switch to it"))
1069 hint=_("use 'hg update' to switch to it"))
1070 scmutil.checknewlabel(repo, label, 'branch')
1070 scmutil.checknewlabel(repo, label, 'branch')
1071 repo.dirstate.setbranch(label)
1071 repo.dirstate.setbranch(label)
1072 ui.status(_('marked working directory as branch %s\n') % label)
1072 ui.status(_('marked working directory as branch %s\n') % label)
1073 ui.status(_('(branches are permanent and global, '
1073 ui.status(_('(branches are permanent and global, '
1074 'did you want a bookmark?)\n'))
1074 'did you want a bookmark?)\n'))
1075 finally:
1075 finally:
1076 wlock.release()
1076 wlock.release()
1077
1077
1078 @command('branches',
1078 @command('branches',
1079 [('a', 'active', False, _('show only branches that have unmerged heads')),
1079 [('a', 'active', False, _('show only branches that have unmerged heads')),
1080 ('c', 'closed', False, _('show normal and closed branches')),
1080 ('c', 'closed', False, _('show normal and closed branches')),
1081 ] + formatteropts,
1081 ] + formatteropts,
1082 _('[-ac]'))
1082 _('[-ac]'))
1083 def branches(ui, repo, active=False, closed=False, **opts):
1083 def branches(ui, repo, active=False, closed=False, **opts):
1084 """list repository named branches
1084 """list repository named branches
1085
1085
1086 List the repository's named branches, indicating which ones are
1086 List the repository's named branches, indicating which ones are
1087 inactive. If -c/--closed is specified, also list branches which have
1087 inactive. If -c/--closed is specified, also list branches which have
1088 been marked closed (see :hg:`commit --close-branch`).
1088 been marked closed (see :hg:`commit --close-branch`).
1089
1089
1090 If -a/--active is specified, only show active branches. A branch
1090 If -a/--active is specified, only show active branches. A branch
1091 is considered active if it contains repository heads.
1091 is considered active if it contains repository heads.
1092
1092
1093 Use the command :hg:`update` to switch to an existing branch.
1093 Use the command :hg:`update` to switch to an existing branch.
1094
1094
1095 Returns 0.
1095 Returns 0.
1096 """
1096 """
1097
1097
1098 fm = ui.formatter('branches', opts)
1098 fm = ui.formatter('branches', opts)
1099 hexfunc = fm.hexfunc
1099 hexfunc = fm.hexfunc
1100
1100
1101 allheads = set(repo.heads())
1101 allheads = set(repo.heads())
1102 branches = []
1102 branches = []
1103 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1103 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1104 isactive = not isclosed and bool(set(heads) & allheads)
1104 isactive = not isclosed and bool(set(heads) & allheads)
1105 branches.append((tag, repo[tip], isactive, not isclosed))
1105 branches.append((tag, repo[tip], isactive, not isclosed))
1106 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1106 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1107 reverse=True)
1107 reverse=True)
1108
1108
1109 for tag, ctx, isactive, isopen in branches:
1109 for tag, ctx, isactive, isopen in branches:
1110 if active and not isactive:
1110 if active and not isactive:
1111 continue
1111 continue
1112 if isactive:
1112 if isactive:
1113 label = 'branches.active'
1113 label = 'branches.active'
1114 notice = ''
1114 notice = ''
1115 elif not isopen:
1115 elif not isopen:
1116 if not closed:
1116 if not closed:
1117 continue
1117 continue
1118 label = 'branches.closed'
1118 label = 'branches.closed'
1119 notice = _(' (closed)')
1119 notice = _(' (closed)')
1120 else:
1120 else:
1121 label = 'branches.inactive'
1121 label = 'branches.inactive'
1122 notice = _(' (inactive)')
1122 notice = _(' (inactive)')
1123 current = (tag == repo.dirstate.branch())
1123 current = (tag == repo.dirstate.branch())
1124 if current:
1124 if current:
1125 label = 'branches.current'
1125 label = 'branches.current'
1126
1126
1127 fm.startitem()
1127 fm.startitem()
1128 fm.write('branch', '%s', tag, label=label)
1128 fm.write('branch', '%s', tag, label=label)
1129 rev = ctx.rev()
1129 rev = ctx.rev()
1130 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1130 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1131 fmt = ' ' * padsize + ' %d:%s'
1131 fmt = ' ' * padsize + ' %d:%s'
1132 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1132 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1133 label='log.changeset changeset.%s' % ctx.phasestr())
1133 label='log.changeset changeset.%s' % ctx.phasestr())
1134 fm.data(active=isactive, closed=not isopen, current=current)
1134 fm.data(active=isactive, closed=not isopen, current=current)
1135 if not ui.quiet:
1135 if not ui.quiet:
1136 fm.plain(notice)
1136 fm.plain(notice)
1137 fm.plain('\n')
1137 fm.plain('\n')
1138 fm.end()
1138 fm.end()
1139
1139
1140 @command('bundle',
1140 @command('bundle',
1141 [('f', 'force', None, _('run even when the destination is unrelated')),
1141 [('f', 'force', None, _('run even when the destination is unrelated')),
1142 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1142 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1143 _('REV')),
1143 _('REV')),
1144 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1144 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1145 _('BRANCH')),
1145 _('BRANCH')),
1146 ('', 'base', [],
1146 ('', 'base', [],
1147 _('a base changeset assumed to be available at the destination'),
1147 _('a base changeset assumed to be available at the destination'),
1148 _('REV')),
1148 _('REV')),
1149 ('a', 'all', None, _('bundle all changesets in the repository')),
1149 ('a', 'all', None, _('bundle all changesets in the repository')),
1150 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1150 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1151 ] + remoteopts,
1151 ] + remoteopts,
1152 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1152 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1153 def bundle(ui, repo, fname, dest=None, **opts):
1153 def bundle(ui, repo, fname, dest=None, **opts):
1154 """create a changegroup file
1154 """create a changegroup file
1155
1155
1156 Generate a compressed changegroup file collecting changesets not
1156 Generate a compressed changegroup file collecting changesets not
1157 known to be in another repository.
1157 known to be in another repository.
1158
1158
1159 If you omit the destination repository, then hg assumes the
1159 If you omit the destination repository, then hg assumes the
1160 destination will have all the nodes you specify with --base
1160 destination will have all the nodes you specify with --base
1161 parameters. To create a bundle containing all changesets, use
1161 parameters. To create a bundle containing all changesets, use
1162 -a/--all (or --base null).
1162 -a/--all (or --base null).
1163
1163
1164 You can change compression method with the -t/--type option.
1164 You can change compression method with the -t/--type option.
1165 The available compression methods are: none, bzip2, and
1165 The available compression methods are: none, bzip2, and
1166 gzip (by default, bundles are compressed using bzip2).
1166 gzip (by default, bundles are compressed using bzip2).
1167
1167
1168 The bundle file can then be transferred using conventional means
1168 The bundle file can then be transferred using conventional means
1169 and applied to another repository with the unbundle or pull
1169 and applied to another repository with the unbundle or pull
1170 command. This is useful when direct push and pull are not
1170 command. This is useful when direct push and pull are not
1171 available or when exporting an entire repository is undesirable.
1171 available or when exporting an entire repository is undesirable.
1172
1172
1173 Applying bundles preserves all changeset contents including
1173 Applying bundles preserves all changeset contents including
1174 permissions, copy/rename information, and revision history.
1174 permissions, copy/rename information, and revision history.
1175
1175
1176 Returns 0 on success, 1 if no changes found.
1176 Returns 0 on success, 1 if no changes found.
1177 """
1177 """
1178 revs = None
1178 revs = None
1179 if 'rev' in opts:
1179 if 'rev' in opts:
1180 revs = scmutil.revrange(repo, opts['rev'])
1180 revs = scmutil.revrange(repo, opts['rev'])
1181
1181
1182 bundletype = opts.get('type', 'bzip2').lower()
1182 bundletype = opts.get('type', 'bzip2').lower()
1183 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1183 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1184 bundletype = btypes.get(bundletype)
1184 bundletype = btypes.get(bundletype)
1185 if bundletype not in changegroup.bundletypes:
1185 if bundletype not in changegroup.bundletypes:
1186 raise util.Abort(_('unknown bundle type specified with --type'))
1186 raise util.Abort(_('unknown bundle type specified with --type'))
1187
1187
1188 if opts.get('all'):
1188 if opts.get('all'):
1189 base = ['null']
1189 base = ['null']
1190 else:
1190 else:
1191 base = scmutil.revrange(repo, opts.get('base'))
1191 base = scmutil.revrange(repo, opts.get('base'))
1192 # TODO: get desired bundlecaps from command line.
1192 # TODO: get desired bundlecaps from command line.
1193 bundlecaps = None
1193 bundlecaps = None
1194 if base:
1194 if base:
1195 if dest:
1195 if dest:
1196 raise util.Abort(_("--base is incompatible with specifying "
1196 raise util.Abort(_("--base is incompatible with specifying "
1197 "a destination"))
1197 "a destination"))
1198 common = [repo.lookup(rev) for rev in base]
1198 common = [repo.lookup(rev) for rev in base]
1199 heads = revs and map(repo.lookup, revs) or revs
1199 heads = revs and map(repo.lookup, revs) or revs
1200 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1200 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1201 common=common, bundlecaps=bundlecaps)
1201 common=common, bundlecaps=bundlecaps)
1202 outgoing = None
1202 outgoing = None
1203 else:
1203 else:
1204 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1204 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1205 dest, branches = hg.parseurl(dest, opts.get('branch'))
1205 dest, branches = hg.parseurl(dest, opts.get('branch'))
1206 other = hg.peer(repo, opts, dest)
1206 other = hg.peer(repo, opts, dest)
1207 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1207 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1208 heads = revs and map(repo.lookup, revs) or revs
1208 heads = revs and map(repo.lookup, revs) or revs
1209 outgoing = discovery.findcommonoutgoing(repo, other,
1209 outgoing = discovery.findcommonoutgoing(repo, other,
1210 onlyheads=heads,
1210 onlyheads=heads,
1211 force=opts.get('force'),
1211 force=opts.get('force'),
1212 portable=True)
1212 portable=True)
1213 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1213 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1214 bundlecaps)
1214 bundlecaps)
1215 if not cg:
1215 if not cg:
1216 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1216 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1217 return 1
1217 return 1
1218
1218
1219 changegroup.writebundle(cg, fname, bundletype)
1219 changegroup.writebundle(cg, fname, bundletype)
1220
1220
1221 @command('cat',
1221 @command('cat',
1222 [('o', 'output', '',
1222 [('o', 'output', '',
1223 _('print output to file with formatted name'), _('FORMAT')),
1223 _('print output to file with formatted name'), _('FORMAT')),
1224 ('r', 'rev', '', _('print the given revision'), _('REV')),
1224 ('r', 'rev', '', _('print the given revision'), _('REV')),
1225 ('', 'decode', None, _('apply any matching decode filter')),
1225 ('', 'decode', None, _('apply any matching decode filter')),
1226 ] + walkopts,
1226 ] + walkopts,
1227 _('[OPTION]... FILE...'),
1227 _('[OPTION]... FILE...'),
1228 inferrepo=True)
1228 inferrepo=True)
1229 def cat(ui, repo, file1, *pats, **opts):
1229 def cat(ui, repo, file1, *pats, **opts):
1230 """output the current or given revision of files
1230 """output the current or given revision of files
1231
1231
1232 Print the specified files as they were at the given revision. If
1232 Print the specified files as they were at the given revision. If
1233 no revision is given, the parent of the working directory is used.
1233 no revision is given, the parent of the working directory is used.
1234
1234
1235 Output may be to a file, in which case the name of the file is
1235 Output may be to a file, in which case the name of the file is
1236 given using a format string. The formatting rules as follows:
1236 given using a format string. The formatting rules as follows:
1237
1237
1238 :``%%``: literal "%" character
1238 :``%%``: literal "%" character
1239 :``%s``: basename of file being printed
1239 :``%s``: basename of file being printed
1240 :``%d``: dirname of file being printed, or '.' if in repository root
1240 :``%d``: dirname of file being printed, or '.' if in repository root
1241 :``%p``: root-relative path name of file being printed
1241 :``%p``: root-relative path name of file being printed
1242 :``%H``: changeset hash (40 hexadecimal digits)
1242 :``%H``: changeset hash (40 hexadecimal digits)
1243 :``%R``: changeset revision number
1243 :``%R``: changeset revision number
1244 :``%h``: short-form changeset hash (12 hexadecimal digits)
1244 :``%h``: short-form changeset hash (12 hexadecimal digits)
1245 :``%r``: zero-padded changeset revision number
1245 :``%r``: zero-padded changeset revision number
1246 :``%b``: basename of the exporting repository
1246 :``%b``: basename of the exporting repository
1247
1247
1248 Returns 0 on success.
1248 Returns 0 on success.
1249 """
1249 """
1250 ctx = scmutil.revsingle(repo, opts.get('rev'))
1250 ctx = scmutil.revsingle(repo, opts.get('rev'))
1251 m = scmutil.match(ctx, (file1,) + pats, opts)
1251 m = scmutil.match(ctx, (file1,) + pats, opts)
1252
1252
1253 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1253 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1254
1254
1255 @command('^clone',
1255 @command('^clone',
1256 [('U', 'noupdate', None,
1256 [('U', 'noupdate', None,
1257 _('the clone will include an empty working copy (only a repository)')),
1257 _('the clone will include an empty working copy (only a repository)')),
1258 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1258 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1259 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1259 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1260 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1260 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1261 ('', 'pull', None, _('use pull protocol to copy metadata')),
1261 ('', 'pull', None, _('use pull protocol to copy metadata')),
1262 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1262 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1263 ] + remoteopts,
1263 ] + remoteopts,
1264 _('[OPTION]... SOURCE [DEST]'),
1264 _('[OPTION]... SOURCE [DEST]'),
1265 norepo=True)
1265 norepo=True)
1266 def clone(ui, source, dest=None, **opts):
1266 def clone(ui, source, dest=None, **opts):
1267 """make a copy of an existing repository
1267 """make a copy of an existing repository
1268
1268
1269 Create a copy of an existing repository in a new directory.
1269 Create a copy of an existing repository in a new directory.
1270
1270
1271 If no destination directory name is specified, it defaults to the
1271 If no destination directory name is specified, it defaults to the
1272 basename of the source.
1272 basename of the source.
1273
1273
1274 The location of the source is added to the new repository's
1274 The location of the source is added to the new repository's
1275 ``.hg/hgrc`` file, as the default to be used for future pulls.
1275 ``.hg/hgrc`` file, as the default to be used for future pulls.
1276
1276
1277 Only local paths and ``ssh://`` URLs are supported as
1277 Only local paths and ``ssh://`` URLs are supported as
1278 destinations. For ``ssh://`` destinations, no working directory or
1278 destinations. For ``ssh://`` destinations, no working directory or
1279 ``.hg/hgrc`` will be created on the remote side.
1279 ``.hg/hgrc`` will be created on the remote side.
1280
1280
1281 To pull only a subset of changesets, specify one or more revisions
1281 To pull only a subset of changesets, specify one or more revisions
1282 identifiers with -r/--rev or branches with -b/--branch. The
1282 identifiers with -r/--rev or branches with -b/--branch. The
1283 resulting clone will contain only the specified changesets and
1283 resulting clone will contain only the specified changesets and
1284 their ancestors. These options (or 'clone src#rev dest') imply
1284 their ancestors. These options (or 'clone src#rev dest') imply
1285 --pull, even for local source repositories. Note that specifying a
1285 --pull, even for local source repositories. Note that specifying a
1286 tag will include the tagged changeset but not the changeset
1286 tag will include the tagged changeset but not the changeset
1287 containing the tag.
1287 containing the tag.
1288
1288
1289 If the source repository has a bookmark called '@' set, that
1289 If the source repository has a bookmark called '@' set, that
1290 revision will be checked out in the new repository by default.
1290 revision will be checked out in the new repository by default.
1291
1291
1292 To check out a particular version, use -u/--update, or
1292 To check out a particular version, use -u/--update, or
1293 -U/--noupdate to create a clone with no working directory.
1293 -U/--noupdate to create a clone with no working directory.
1294
1294
1295 .. container:: verbose
1295 .. container:: verbose
1296
1296
1297 For efficiency, hardlinks are used for cloning whenever the
1297 For efficiency, hardlinks are used for cloning whenever the
1298 source and destination are on the same filesystem (note this
1298 source and destination are on the same filesystem (note this
1299 applies only to the repository data, not to the working
1299 applies only to the repository data, not to the working
1300 directory). Some filesystems, such as AFS, implement hardlinking
1300 directory). Some filesystems, such as AFS, implement hardlinking
1301 incorrectly, but do not report errors. In these cases, use the
1301 incorrectly, but do not report errors. In these cases, use the
1302 --pull option to avoid hardlinking.
1302 --pull option to avoid hardlinking.
1303
1303
1304 In some cases, you can clone repositories and the working
1304 In some cases, you can clone repositories and the working
1305 directory using full hardlinks with ::
1305 directory using full hardlinks with ::
1306
1306
1307 $ cp -al REPO REPOCLONE
1307 $ cp -al REPO REPOCLONE
1308
1308
1309 This is the fastest way to clone, but it is not always safe. The
1309 This is the fastest way to clone, but it is not always safe. The
1310 operation is not atomic (making sure REPO is not modified during
1310 operation is not atomic (making sure REPO is not modified during
1311 the operation is up to you) and you have to make sure your
1311 the operation is up to you) and you have to make sure your
1312 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1312 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1313 so). Also, this is not compatible with certain extensions that
1313 so). Also, this is not compatible with certain extensions that
1314 place their metadata under the .hg directory, such as mq.
1314 place their metadata under the .hg directory, such as mq.
1315
1315
1316 Mercurial will update the working directory to the first applicable
1316 Mercurial will update the working directory to the first applicable
1317 revision from this list:
1317 revision from this list:
1318
1318
1319 a) null if -U or the source repository has no changesets
1319 a) null if -U or the source repository has no changesets
1320 b) if -u . and the source repository is local, the first parent of
1320 b) if -u . and the source repository is local, the first parent of
1321 the source repository's working directory
1321 the source repository's working directory
1322 c) the changeset specified with -u (if a branch name, this means the
1322 c) the changeset specified with -u (if a branch name, this means the
1323 latest head of that branch)
1323 latest head of that branch)
1324 d) the changeset specified with -r
1324 d) the changeset specified with -r
1325 e) the tipmost head specified with -b
1325 e) the tipmost head specified with -b
1326 f) the tipmost head specified with the url#branch source syntax
1326 f) the tipmost head specified with the url#branch source syntax
1327 g) the revision marked with the '@' bookmark, if present
1327 g) the revision marked with the '@' bookmark, if present
1328 h) the tipmost head of the default branch
1328 h) the tipmost head of the default branch
1329 i) tip
1329 i) tip
1330
1330
1331 Examples:
1331 Examples:
1332
1332
1333 - clone a remote repository to a new directory named hg/::
1333 - clone a remote repository to a new directory named hg/::
1334
1334
1335 hg clone http://selenic.com/hg
1335 hg clone http://selenic.com/hg
1336
1336
1337 - create a lightweight local clone::
1337 - create a lightweight local clone::
1338
1338
1339 hg clone project/ project-feature/
1339 hg clone project/ project-feature/
1340
1340
1341 - clone from an absolute path on an ssh server (note double-slash)::
1341 - clone from an absolute path on an ssh server (note double-slash)::
1342
1342
1343 hg clone ssh://user@server//home/projects/alpha/
1343 hg clone ssh://user@server//home/projects/alpha/
1344
1344
1345 - do a high-speed clone over a LAN while checking out a
1345 - do a high-speed clone over a LAN while checking out a
1346 specified version::
1346 specified version::
1347
1347
1348 hg clone --uncompressed http://server/repo -u 1.5
1348 hg clone --uncompressed http://server/repo -u 1.5
1349
1349
1350 - create a repository without changesets after a particular revision::
1350 - create a repository without changesets after a particular revision::
1351
1351
1352 hg clone -r 04e544 experimental/ good/
1352 hg clone -r 04e544 experimental/ good/
1353
1353
1354 - clone (and track) a particular named branch::
1354 - clone (and track) a particular named branch::
1355
1355
1356 hg clone http://selenic.com/hg#stable
1356 hg clone http://selenic.com/hg#stable
1357
1357
1358 See :hg:`help urls` for details on specifying URLs.
1358 See :hg:`help urls` for details on specifying URLs.
1359
1359
1360 Returns 0 on success.
1360 Returns 0 on success.
1361 """
1361 """
1362 if opts.get('noupdate') and opts.get('updaterev'):
1362 if opts.get('noupdate') and opts.get('updaterev'):
1363 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1363 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1364
1364
1365 r = hg.clone(ui, opts, source, dest,
1365 r = hg.clone(ui, opts, source, dest,
1366 pull=opts.get('pull'),
1366 pull=opts.get('pull'),
1367 stream=opts.get('uncompressed'),
1367 stream=opts.get('uncompressed'),
1368 rev=opts.get('rev'),
1368 rev=opts.get('rev'),
1369 update=opts.get('updaterev') or not opts.get('noupdate'),
1369 update=opts.get('updaterev') or not opts.get('noupdate'),
1370 branch=opts.get('branch'))
1370 branch=opts.get('branch'))
1371
1371
1372 return r is None
1372 return r is None
1373
1373
1374 @command('^commit|ci',
1374 @command('^commit|ci',
1375 [('A', 'addremove', None,
1375 [('A', 'addremove', None,
1376 _('mark new/missing files as added/removed before committing')),
1376 _('mark new/missing files as added/removed before committing')),
1377 ('', 'close-branch', None,
1377 ('', 'close-branch', None,
1378 _('mark a branch as closed, hiding it from the branch list')),
1378 _('mark a branch as closed, hiding it from the branch list')),
1379 ('', 'amend', None, _('amend the parent of the working dir')),
1379 ('', 'amend', None, _('amend the parent of the working dir')),
1380 ('s', 'secret', None, _('use the secret phase for committing')),
1380 ('s', 'secret', None, _('use the secret phase for committing')),
1381 ('e', 'edit', None, _('invoke editor on commit messages')),
1381 ('e', 'edit', None, _('invoke editor on commit messages')),
1382 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1382 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1383 _('[OPTION]... [FILE]...'),
1383 _('[OPTION]... [FILE]...'),
1384 inferrepo=True)
1384 inferrepo=True)
1385 def commit(ui, repo, *pats, **opts):
1385 def commit(ui, repo, *pats, **opts):
1386 """commit the specified files or all outstanding changes
1386 """commit the specified files or all outstanding changes
1387
1387
1388 Commit changes to the given files into the repository. Unlike a
1388 Commit changes to the given files into the repository. Unlike a
1389 centralized SCM, this operation is a local operation. See
1389 centralized SCM, this operation is a local operation. See
1390 :hg:`push` for a way to actively distribute your changes.
1390 :hg:`push` for a way to actively distribute your changes.
1391
1391
1392 If a list of files is omitted, all changes reported by :hg:`status`
1392 If a list of files is omitted, all changes reported by :hg:`status`
1393 will be committed.
1393 will be committed.
1394
1394
1395 If you are committing the result of a merge, do not provide any
1395 If you are committing the result of a merge, do not provide any
1396 filenames or -I/-X filters.
1396 filenames or -I/-X filters.
1397
1397
1398 If no commit message is specified, Mercurial starts your
1398 If no commit message is specified, Mercurial starts your
1399 configured editor where you can enter a message. In case your
1399 configured editor where you can enter a message. In case your
1400 commit fails, you will find a backup of your message in
1400 commit fails, you will find a backup of your message in
1401 ``.hg/last-message.txt``.
1401 ``.hg/last-message.txt``.
1402
1402
1403 The --amend flag can be used to amend the parent of the
1403 The --amend flag can be used to amend the parent of the
1404 working directory with a new commit that contains the changes
1404 working directory with a new commit that contains the changes
1405 in the parent in addition to those currently reported by :hg:`status`,
1405 in the parent in addition to those currently reported by :hg:`status`,
1406 if there are any. The old commit is stored in a backup bundle in
1406 if there are any. The old commit is stored in a backup bundle in
1407 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1407 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1408 on how to restore it).
1408 on how to restore it).
1409
1409
1410 Message, user and date are taken from the amended commit unless
1410 Message, user and date are taken from the amended commit unless
1411 specified. When a message isn't specified on the command line,
1411 specified. When a message isn't specified on the command line,
1412 the editor will open with the message of the amended commit.
1412 the editor will open with the message of the amended commit.
1413
1413
1414 It is not possible to amend public changesets (see :hg:`help phases`)
1414 It is not possible to amend public changesets (see :hg:`help phases`)
1415 or changesets that have children.
1415 or changesets that have children.
1416
1416
1417 See :hg:`help dates` for a list of formats valid for -d/--date.
1417 See :hg:`help dates` for a list of formats valid for -d/--date.
1418
1418
1419 Returns 0 on success, 1 if nothing changed.
1419 Returns 0 on success, 1 if nothing changed.
1420 """
1420 """
1421 if opts.get('subrepos'):
1421 if opts.get('subrepos'):
1422 if opts.get('amend'):
1422 if opts.get('amend'):
1423 raise util.Abort(_('cannot amend with --subrepos'))
1423 raise util.Abort(_('cannot amend with --subrepos'))
1424 # Let --subrepos on the command line override config setting.
1424 # Let --subrepos on the command line override config setting.
1425 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1425 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1426
1426
1427 cmdutil.checkunfinished(repo, commit=True)
1427 cmdutil.checkunfinished(repo, commit=True)
1428
1428
1429 branch = repo[None].branch()
1429 branch = repo[None].branch()
1430 bheads = repo.branchheads(branch)
1430 bheads = repo.branchheads(branch)
1431
1431
1432 extra = {}
1432 extra = {}
1433 if opts.get('close_branch'):
1433 if opts.get('close_branch'):
1434 extra['close'] = 1
1434 extra['close'] = 1
1435
1435
1436 if not bheads:
1436 if not bheads:
1437 raise util.Abort(_('can only close branch heads'))
1437 raise util.Abort(_('can only close branch heads'))
1438 elif opts.get('amend'):
1438 elif opts.get('amend'):
1439 if repo.parents()[0].p1().branch() != branch and \
1439 if repo.parents()[0].p1().branch() != branch and \
1440 repo.parents()[0].p2().branch() != branch:
1440 repo.parents()[0].p2().branch() != branch:
1441 raise util.Abort(_('can only close branch heads'))
1441 raise util.Abort(_('can only close branch heads'))
1442
1442
1443 if opts.get('amend'):
1443 if opts.get('amend'):
1444 if ui.configbool('ui', 'commitsubrepos'):
1444 if ui.configbool('ui', 'commitsubrepos'):
1445 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1445 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1446
1446
1447 old = repo['.']
1447 old = repo['.']
1448 if not old.mutable():
1448 if not old.mutable():
1449 raise util.Abort(_('cannot amend public changesets'))
1449 raise util.Abort(_('cannot amend public changesets'))
1450 if len(repo[None].parents()) > 1:
1450 if len(repo[None].parents()) > 1:
1451 raise util.Abort(_('cannot amend while merging'))
1451 raise util.Abort(_('cannot amend while merging'))
1452 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1452 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1453 if not allowunstable and old.children():
1453 if not allowunstable and old.children():
1454 raise util.Abort(_('cannot amend changeset with children'))
1454 raise util.Abort(_('cannot amend changeset with children'))
1455
1455
1456 # commitfunc is used only for temporary amend commit by cmdutil.amend
1456 # commitfunc is used only for temporary amend commit by cmdutil.amend
1457 def commitfunc(ui, repo, message, match, opts):
1457 def commitfunc(ui, repo, message, match, opts):
1458 return repo.commit(message,
1458 return repo.commit(message,
1459 opts.get('user') or old.user(),
1459 opts.get('user') or old.user(),
1460 opts.get('date') or old.date(),
1460 opts.get('date') or old.date(),
1461 match,
1461 match,
1462 extra=extra)
1462 extra=extra)
1463
1463
1464 current = repo._bookmarkcurrent
1464 current = repo._bookmarkcurrent
1465 marks = old.bookmarks()
1465 marks = old.bookmarks()
1466 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1466 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1467 if node == old.node():
1467 if node == old.node():
1468 ui.status(_("nothing changed\n"))
1468 ui.status(_("nothing changed\n"))
1469 return 1
1469 return 1
1470 elif marks:
1470 elif marks:
1471 ui.debug('moving bookmarks %r from %s to %s\n' %
1471 ui.debug('moving bookmarks %r from %s to %s\n' %
1472 (marks, old.hex(), hex(node)))
1472 (marks, old.hex(), hex(node)))
1473 newmarks = repo._bookmarks
1473 newmarks = repo._bookmarks
1474 for bm in marks:
1474 for bm in marks:
1475 newmarks[bm] = node
1475 newmarks[bm] = node
1476 if bm == current:
1476 if bm == current:
1477 bookmarks.setcurrent(repo, bm)
1477 bookmarks.setcurrent(repo, bm)
1478 newmarks.write()
1478 newmarks.write()
1479 else:
1479 else:
1480 def commitfunc(ui, repo, message, match, opts):
1480 def commitfunc(ui, repo, message, match, opts):
1481 backup = ui.backupconfig('phases', 'new-commit')
1481 backup = ui.backupconfig('phases', 'new-commit')
1482 baseui = repo.baseui
1482 baseui = repo.baseui
1483 basebackup = baseui.backupconfig('phases', 'new-commit')
1483 basebackup = baseui.backupconfig('phases', 'new-commit')
1484 try:
1484 try:
1485 if opts.get('secret'):
1485 if opts.get('secret'):
1486 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1486 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1487 # Propagate to subrepos
1487 # Propagate to subrepos
1488 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1488 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1489
1489
1490 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1490 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1491 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1491 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1492 return repo.commit(message, opts.get('user'), opts.get('date'),
1492 return repo.commit(message, opts.get('user'), opts.get('date'),
1493 match,
1493 match,
1494 editor=editor,
1494 editor=editor,
1495 extra=extra)
1495 extra=extra)
1496 finally:
1496 finally:
1497 ui.restoreconfig(backup)
1497 ui.restoreconfig(backup)
1498 repo.baseui.restoreconfig(basebackup)
1498 repo.baseui.restoreconfig(basebackup)
1499
1499
1500
1500
1501 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1501 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1502
1502
1503 if not node:
1503 if not node:
1504 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1504 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1505 if stat[3]:
1505 if stat[3]:
1506 ui.status(_("nothing changed (%d missing files, see "
1506 ui.status(_("nothing changed (%d missing files, see "
1507 "'hg status')\n") % len(stat[3]))
1507 "'hg status')\n") % len(stat[3]))
1508 else:
1508 else:
1509 ui.status(_("nothing changed\n"))
1509 ui.status(_("nothing changed\n"))
1510 return 1
1510 return 1
1511
1511
1512 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1512 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1513
1513
1514 @command('config|showconfig|debugconfig',
1514 @command('config|showconfig|debugconfig',
1515 [('u', 'untrusted', None, _('show untrusted configuration options')),
1515 [('u', 'untrusted', None, _('show untrusted configuration options')),
1516 ('e', 'edit', None, _('edit user config')),
1516 ('e', 'edit', None, _('edit user config')),
1517 ('l', 'local', None, _('edit repository config')),
1517 ('l', 'local', None, _('edit repository config')),
1518 ('g', 'global', None, _('edit global config'))],
1518 ('g', 'global', None, _('edit global config'))],
1519 _('[-u] [NAME]...'),
1519 _('[-u] [NAME]...'),
1520 optionalrepo=True)
1520 optionalrepo=True)
1521 def config(ui, repo, *values, **opts):
1521 def config(ui, repo, *values, **opts):
1522 """show combined config settings from all hgrc files
1522 """show combined config settings from all hgrc files
1523
1523
1524 With no arguments, print names and values of all config items.
1524 With no arguments, print names and values of all config items.
1525
1525
1526 With one argument of the form section.name, print just the value
1526 With one argument of the form section.name, print just the value
1527 of that config item.
1527 of that config item.
1528
1528
1529 With multiple arguments, print names and values of all config
1529 With multiple arguments, print names and values of all config
1530 items with matching section names.
1530 items with matching section names.
1531
1531
1532 With --edit, start an editor on the user-level config file. With
1532 With --edit, start an editor on the user-level config file. With
1533 --global, edit the system-wide config file. With --local, edit the
1533 --global, edit the system-wide config file. With --local, edit the
1534 repository-level config file.
1534 repository-level config file.
1535
1535
1536 With --debug, the source (filename and line number) is printed
1536 With --debug, the source (filename and line number) is printed
1537 for each config item.
1537 for each config item.
1538
1538
1539 See :hg:`help config` for more information about config files.
1539 See :hg:`help config` for more information about config files.
1540
1540
1541 Returns 0 on success, 1 if NAME does not exist.
1541 Returns 0 on success, 1 if NAME does not exist.
1542
1542
1543 """
1543 """
1544
1544
1545 if opts.get('edit') or opts.get('local') or opts.get('global'):
1545 if opts.get('edit') or opts.get('local') or opts.get('global'):
1546 if opts.get('local') and opts.get('global'):
1546 if opts.get('local') and opts.get('global'):
1547 raise util.Abort(_("can't use --local and --global together"))
1547 raise util.Abort(_("can't use --local and --global together"))
1548
1548
1549 if opts.get('local'):
1549 if opts.get('local'):
1550 if not repo:
1550 if not repo:
1551 raise util.Abort(_("can't use --local outside a repository"))
1551 raise util.Abort(_("can't use --local outside a repository"))
1552 paths = [repo.join('hgrc')]
1552 paths = [repo.join('hgrc')]
1553 elif opts.get('global'):
1553 elif opts.get('global'):
1554 paths = scmutil.systemrcpath()
1554 paths = scmutil.systemrcpath()
1555 else:
1555 else:
1556 paths = scmutil.userrcpath()
1556 paths = scmutil.userrcpath()
1557
1557
1558 for f in paths:
1558 for f in paths:
1559 if os.path.exists(f):
1559 if os.path.exists(f):
1560 break
1560 break
1561 else:
1561 else:
1562 if opts.get('global'):
1562 if opts.get('global'):
1563 samplehgrc = uimod.samplehgrcs['global']
1563 samplehgrc = uimod.samplehgrcs['global']
1564 elif opts.get('local'):
1564 elif opts.get('local'):
1565 samplehgrc = uimod.samplehgrcs['local']
1565 samplehgrc = uimod.samplehgrcs['local']
1566 else:
1566 else:
1567 samplehgrc = uimod.samplehgrcs['user']
1567 samplehgrc = uimod.samplehgrcs['user']
1568
1568
1569 f = paths[0]
1569 f = paths[0]
1570 fp = open(f, "w")
1570 fp = open(f, "w")
1571 fp.write(samplehgrc)
1571 fp.write(samplehgrc)
1572 fp.close()
1572 fp.close()
1573
1573
1574 editor = ui.geteditor()
1574 editor = ui.geteditor()
1575 ui.system("%s \"%s\"" % (editor, f),
1575 ui.system("%s \"%s\"" % (editor, f),
1576 onerr=util.Abort, errprefix=_("edit failed"))
1576 onerr=util.Abort, errprefix=_("edit failed"))
1577 return
1577 return
1578
1578
1579 for f in scmutil.rcpath():
1579 for f in scmutil.rcpath():
1580 ui.debug('read config from: %s\n' % f)
1580 ui.debug('read config from: %s\n' % f)
1581 untrusted = bool(opts.get('untrusted'))
1581 untrusted = bool(opts.get('untrusted'))
1582 if values:
1582 if values:
1583 sections = [v for v in values if '.' not in v]
1583 sections = [v for v in values if '.' not in v]
1584 items = [v for v in values if '.' in v]
1584 items = [v for v in values if '.' in v]
1585 if len(items) > 1 or items and sections:
1585 if len(items) > 1 or items and sections:
1586 raise util.Abort(_('only one config item permitted'))
1586 raise util.Abort(_('only one config item permitted'))
1587 matched = False
1587 matched = False
1588 for section, name, value in ui.walkconfig(untrusted=untrusted):
1588 for section, name, value in ui.walkconfig(untrusted=untrusted):
1589 value = str(value).replace('\n', '\\n')
1589 value = str(value).replace('\n', '\\n')
1590 sectname = section + '.' + name
1590 sectname = section + '.' + name
1591 if values:
1591 if values:
1592 for v in values:
1592 for v in values:
1593 if v == section:
1593 if v == section:
1594 ui.debug('%s: ' %
1594 ui.debug('%s: ' %
1595 ui.configsource(section, name, untrusted))
1595 ui.configsource(section, name, untrusted))
1596 ui.write('%s=%s\n' % (sectname, value))
1596 ui.write('%s=%s\n' % (sectname, value))
1597 matched = True
1597 matched = True
1598 elif v == sectname:
1598 elif v == sectname:
1599 ui.debug('%s: ' %
1599 ui.debug('%s: ' %
1600 ui.configsource(section, name, untrusted))
1600 ui.configsource(section, name, untrusted))
1601 ui.write(value, '\n')
1601 ui.write(value, '\n')
1602 matched = True
1602 matched = True
1603 else:
1603 else:
1604 ui.debug('%s: ' %
1604 ui.debug('%s: ' %
1605 ui.configsource(section, name, untrusted))
1605 ui.configsource(section, name, untrusted))
1606 ui.write('%s=%s\n' % (sectname, value))
1606 ui.write('%s=%s\n' % (sectname, value))
1607 matched = True
1607 matched = True
1608 if matched:
1608 if matched:
1609 return 0
1609 return 0
1610 return 1
1610 return 1
1611
1611
1612 @command('copy|cp',
1612 @command('copy|cp',
1613 [('A', 'after', None, _('record a copy that has already occurred')),
1613 [('A', 'after', None, _('record a copy that has already occurred')),
1614 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1614 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1615 ] + walkopts + dryrunopts,
1615 ] + walkopts + dryrunopts,
1616 _('[OPTION]... [SOURCE]... DEST'))
1616 _('[OPTION]... [SOURCE]... DEST'))
1617 def copy(ui, repo, *pats, **opts):
1617 def copy(ui, repo, *pats, **opts):
1618 """mark files as copied for the next commit
1618 """mark files as copied for the next commit
1619
1619
1620 Mark dest as having copies of source files. If dest is a
1620 Mark dest as having copies of source files. If dest is a
1621 directory, copies are put in that directory. If dest is a file,
1621 directory, copies are put in that directory. If dest is a file,
1622 the source must be a single file.
1622 the source must be a single file.
1623
1623
1624 By default, this command copies the contents of files as they
1624 By default, this command copies the contents of files as they
1625 exist in the working directory. If invoked with -A/--after, the
1625 exist in the working directory. If invoked with -A/--after, the
1626 operation is recorded, but no copying is performed.
1626 operation is recorded, but no copying is performed.
1627
1627
1628 This command takes effect with the next commit. To undo a copy
1628 This command takes effect with the next commit. To undo a copy
1629 before that, see :hg:`revert`.
1629 before that, see :hg:`revert`.
1630
1630
1631 Returns 0 on success, 1 if errors are encountered.
1631 Returns 0 on success, 1 if errors are encountered.
1632 """
1632 """
1633 wlock = repo.wlock(False)
1633 wlock = repo.wlock(False)
1634 try:
1634 try:
1635 return cmdutil.copy(ui, repo, pats, opts)
1635 return cmdutil.copy(ui, repo, pats, opts)
1636 finally:
1636 finally:
1637 wlock.release()
1637 wlock.release()
1638
1638
1639 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1639 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1640 def debugancestor(ui, repo, *args):
1640 def debugancestor(ui, repo, *args):
1641 """find the ancestor revision of two revisions in a given index"""
1641 """find the ancestor revision of two revisions in a given index"""
1642 if len(args) == 3:
1642 if len(args) == 3:
1643 index, rev1, rev2 = args
1643 index, rev1, rev2 = args
1644 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1644 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1645 lookup = r.lookup
1645 lookup = r.lookup
1646 elif len(args) == 2:
1646 elif len(args) == 2:
1647 if not repo:
1647 if not repo:
1648 raise util.Abort(_("there is no Mercurial repository here "
1648 raise util.Abort(_("there is no Mercurial repository here "
1649 "(.hg not found)"))
1649 "(.hg not found)"))
1650 rev1, rev2 = args
1650 rev1, rev2 = args
1651 r = repo.changelog
1651 r = repo.changelog
1652 lookup = repo.lookup
1652 lookup = repo.lookup
1653 else:
1653 else:
1654 raise util.Abort(_('either two or three arguments required'))
1654 raise util.Abort(_('either two or three arguments required'))
1655 a = r.ancestor(lookup(rev1), lookup(rev2))
1655 a = r.ancestor(lookup(rev1), lookup(rev2))
1656 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1656 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1657
1657
1658 @command('debugbuilddag',
1658 @command('debugbuilddag',
1659 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1659 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1660 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1660 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1661 ('n', 'new-file', None, _('add new file at each rev'))],
1661 ('n', 'new-file', None, _('add new file at each rev'))],
1662 _('[OPTION]... [TEXT]'))
1662 _('[OPTION]... [TEXT]'))
1663 def debugbuilddag(ui, repo, text=None,
1663 def debugbuilddag(ui, repo, text=None,
1664 mergeable_file=False,
1664 mergeable_file=False,
1665 overwritten_file=False,
1665 overwritten_file=False,
1666 new_file=False):
1666 new_file=False):
1667 """builds a repo with a given DAG from scratch in the current empty repo
1667 """builds a repo with a given DAG from scratch in the current empty repo
1668
1668
1669 The description of the DAG is read from stdin if not given on the
1669 The description of the DAG is read from stdin if not given on the
1670 command line.
1670 command line.
1671
1671
1672 Elements:
1672 Elements:
1673
1673
1674 - "+n" is a linear run of n nodes based on the current default parent
1674 - "+n" is a linear run of n nodes based on the current default parent
1675 - "." is a single node based on the current default parent
1675 - "." is a single node based on the current default parent
1676 - "$" resets the default parent to null (implied at the start);
1676 - "$" resets the default parent to null (implied at the start);
1677 otherwise the default parent is always the last node created
1677 otherwise the default parent is always the last node created
1678 - "<p" sets the default parent to the backref p
1678 - "<p" sets the default parent to the backref p
1679 - "*p" is a fork at parent p, which is a backref
1679 - "*p" is a fork at parent p, which is a backref
1680 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1680 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1681 - "/p2" is a merge of the preceding node and p2
1681 - "/p2" is a merge of the preceding node and p2
1682 - ":tag" defines a local tag for the preceding node
1682 - ":tag" defines a local tag for the preceding node
1683 - "@branch" sets the named branch for subsequent nodes
1683 - "@branch" sets the named branch for subsequent nodes
1684 - "#...\\n" is a comment up to the end of the line
1684 - "#...\\n" is a comment up to the end of the line
1685
1685
1686 Whitespace between the above elements is ignored.
1686 Whitespace between the above elements is ignored.
1687
1687
1688 A backref is either
1688 A backref is either
1689
1689
1690 - a number n, which references the node curr-n, where curr is the current
1690 - a number n, which references the node curr-n, where curr is the current
1691 node, or
1691 node, or
1692 - the name of a local tag you placed earlier using ":tag", or
1692 - the name of a local tag you placed earlier using ":tag", or
1693 - empty to denote the default parent.
1693 - empty to denote the default parent.
1694
1694
1695 All string valued-elements are either strictly alphanumeric, or must
1695 All string valued-elements are either strictly alphanumeric, or must
1696 be enclosed in double quotes ("..."), with "\\" as escape character.
1696 be enclosed in double quotes ("..."), with "\\" as escape character.
1697 """
1697 """
1698
1698
1699 if text is None:
1699 if text is None:
1700 ui.status(_("reading DAG from stdin\n"))
1700 ui.status(_("reading DAG from stdin\n"))
1701 text = ui.fin.read()
1701 text = ui.fin.read()
1702
1702
1703 cl = repo.changelog
1703 cl = repo.changelog
1704 if len(cl) > 0:
1704 if len(cl) > 0:
1705 raise util.Abort(_('repository is not empty'))
1705 raise util.Abort(_('repository is not empty'))
1706
1706
1707 # determine number of revs in DAG
1707 # determine number of revs in DAG
1708 total = 0
1708 total = 0
1709 for type, data in dagparser.parsedag(text):
1709 for type, data in dagparser.parsedag(text):
1710 if type == 'n':
1710 if type == 'n':
1711 total += 1
1711 total += 1
1712
1712
1713 if mergeable_file:
1713 if mergeable_file:
1714 linesperrev = 2
1714 linesperrev = 2
1715 # make a file with k lines per rev
1715 # make a file with k lines per rev
1716 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1716 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1717 initialmergedlines.append("")
1717 initialmergedlines.append("")
1718
1718
1719 tags = []
1719 tags = []
1720
1720
1721 lock = tr = None
1721 lock = tr = None
1722 try:
1722 try:
1723 lock = repo.lock()
1723 lock = repo.lock()
1724 tr = repo.transaction("builddag")
1724 tr = repo.transaction("builddag")
1725
1725
1726 at = -1
1726 at = -1
1727 atbranch = 'default'
1727 atbranch = 'default'
1728 nodeids = []
1728 nodeids = []
1729 id = 0
1729 id = 0
1730 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1730 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1731 for type, data in dagparser.parsedag(text):
1731 for type, data in dagparser.parsedag(text):
1732 if type == 'n':
1732 if type == 'n':
1733 ui.note(('node %s\n' % str(data)))
1733 ui.note(('node %s\n' % str(data)))
1734 id, ps = data
1734 id, ps = data
1735
1735
1736 files = []
1736 files = []
1737 fctxs = {}
1737 fctxs = {}
1738
1738
1739 p2 = None
1739 p2 = None
1740 if mergeable_file:
1740 if mergeable_file:
1741 fn = "mf"
1741 fn = "mf"
1742 p1 = repo[ps[0]]
1742 p1 = repo[ps[0]]
1743 if len(ps) > 1:
1743 if len(ps) > 1:
1744 p2 = repo[ps[1]]
1744 p2 = repo[ps[1]]
1745 pa = p1.ancestor(p2)
1745 pa = p1.ancestor(p2)
1746 base, local, other = [x[fn].data() for x in (pa, p1,
1746 base, local, other = [x[fn].data() for x in (pa, p1,
1747 p2)]
1747 p2)]
1748 m3 = simplemerge.Merge3Text(base, local, other)
1748 m3 = simplemerge.Merge3Text(base, local, other)
1749 ml = [l.strip() for l in m3.merge_lines()]
1749 ml = [l.strip() for l in m3.merge_lines()]
1750 ml.append("")
1750 ml.append("")
1751 elif at > 0:
1751 elif at > 0:
1752 ml = p1[fn].data().split("\n")
1752 ml = p1[fn].data().split("\n")
1753 else:
1753 else:
1754 ml = initialmergedlines
1754 ml = initialmergedlines
1755 ml[id * linesperrev] += " r%i" % id
1755 ml[id * linesperrev] += " r%i" % id
1756 mergedtext = "\n".join(ml)
1756 mergedtext = "\n".join(ml)
1757 files.append(fn)
1757 files.append(fn)
1758 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1758 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1759
1759
1760 if overwritten_file:
1760 if overwritten_file:
1761 fn = "of"
1761 fn = "of"
1762 files.append(fn)
1762 files.append(fn)
1763 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1763 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1764
1764
1765 if new_file:
1765 if new_file:
1766 fn = "nf%i" % id
1766 fn = "nf%i" % id
1767 files.append(fn)
1767 files.append(fn)
1768 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1768 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1769 if len(ps) > 1:
1769 if len(ps) > 1:
1770 if not p2:
1770 if not p2:
1771 p2 = repo[ps[1]]
1771 p2 = repo[ps[1]]
1772 for fn in p2:
1772 for fn in p2:
1773 if fn.startswith("nf"):
1773 if fn.startswith("nf"):
1774 files.append(fn)
1774 files.append(fn)
1775 fctxs[fn] = p2[fn]
1775 fctxs[fn] = p2[fn]
1776
1776
1777 def fctxfn(repo, cx, path):
1777 def fctxfn(repo, cx, path):
1778 return fctxs.get(path)
1778 return fctxs.get(path)
1779
1779
1780 if len(ps) == 0 or ps[0] < 0:
1780 if len(ps) == 0 or ps[0] < 0:
1781 pars = [None, None]
1781 pars = [None, None]
1782 elif len(ps) == 1:
1782 elif len(ps) == 1:
1783 pars = [nodeids[ps[0]], None]
1783 pars = [nodeids[ps[0]], None]
1784 else:
1784 else:
1785 pars = [nodeids[p] for p in ps]
1785 pars = [nodeids[p] for p in ps]
1786 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1786 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1787 date=(id, 0),
1787 date=(id, 0),
1788 user="debugbuilddag",
1788 user="debugbuilddag",
1789 extra={'branch': atbranch})
1789 extra={'branch': atbranch})
1790 nodeid = repo.commitctx(cx)
1790 nodeid = repo.commitctx(cx)
1791 nodeids.append(nodeid)
1791 nodeids.append(nodeid)
1792 at = id
1792 at = id
1793 elif type == 'l':
1793 elif type == 'l':
1794 id, name = data
1794 id, name = data
1795 ui.note(('tag %s\n' % name))
1795 ui.note(('tag %s\n' % name))
1796 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1796 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1797 elif type == 'a':
1797 elif type == 'a':
1798 ui.note(('branch %s\n' % data))
1798 ui.note(('branch %s\n' % data))
1799 atbranch = data
1799 atbranch = data
1800 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1800 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1801 tr.close()
1801 tr.close()
1802
1802
1803 if tags:
1803 if tags:
1804 repo.opener.write("localtags", "".join(tags))
1804 repo.opener.write("localtags", "".join(tags))
1805 finally:
1805 finally:
1806 ui.progress(_('building'), None)
1806 ui.progress(_('building'), None)
1807 release(tr, lock)
1807 release(tr, lock)
1808
1808
1809 @command('debugbundle',
1809 @command('debugbundle',
1810 [('a', 'all', None, _('show all details'))],
1810 [('a', 'all', None, _('show all details'))],
1811 _('FILE'),
1811 _('FILE'),
1812 norepo=True)
1812 norepo=True)
1813 def debugbundle(ui, bundlepath, all=None, **opts):
1813 def debugbundle(ui, bundlepath, all=None, **opts):
1814 """lists the contents of a bundle"""
1814 """lists the contents of a bundle"""
1815 f = hg.openpath(ui, bundlepath)
1815 f = hg.openpath(ui, bundlepath)
1816 try:
1816 try:
1817 gen = exchange.readbundle(ui, f, bundlepath)
1817 gen = exchange.readbundle(ui, f, bundlepath)
1818 if all:
1818 if all:
1819 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1819 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1820
1820
1821 def showchunks(named):
1821 def showchunks(named):
1822 ui.write("\n%s\n" % named)
1822 ui.write("\n%s\n" % named)
1823 chain = None
1823 chain = None
1824 while True:
1824 while True:
1825 chunkdata = gen.deltachunk(chain)
1825 chunkdata = gen.deltachunk(chain)
1826 if not chunkdata:
1826 if not chunkdata:
1827 break
1827 break
1828 node = chunkdata['node']
1828 node = chunkdata['node']
1829 p1 = chunkdata['p1']
1829 p1 = chunkdata['p1']
1830 p2 = chunkdata['p2']
1830 p2 = chunkdata['p2']
1831 cs = chunkdata['cs']
1831 cs = chunkdata['cs']
1832 deltabase = chunkdata['deltabase']
1832 deltabase = chunkdata['deltabase']
1833 delta = chunkdata['delta']
1833 delta = chunkdata['delta']
1834 ui.write("%s %s %s %s %s %s\n" %
1834 ui.write("%s %s %s %s %s %s\n" %
1835 (hex(node), hex(p1), hex(p2),
1835 (hex(node), hex(p1), hex(p2),
1836 hex(cs), hex(deltabase), len(delta)))
1836 hex(cs), hex(deltabase), len(delta)))
1837 chain = node
1837 chain = node
1838
1838
1839 chunkdata = gen.changelogheader()
1839 chunkdata = gen.changelogheader()
1840 showchunks("changelog")
1840 showchunks("changelog")
1841 chunkdata = gen.manifestheader()
1841 chunkdata = gen.manifestheader()
1842 showchunks("manifest")
1842 showchunks("manifest")
1843 while True:
1843 while True:
1844 chunkdata = gen.filelogheader()
1844 chunkdata = gen.filelogheader()
1845 if not chunkdata:
1845 if not chunkdata:
1846 break
1846 break
1847 fname = chunkdata['filename']
1847 fname = chunkdata['filename']
1848 showchunks(fname)
1848 showchunks(fname)
1849 else:
1849 else:
1850 chunkdata = gen.changelogheader()
1850 chunkdata = gen.changelogheader()
1851 chain = None
1851 chain = None
1852 while True:
1852 while True:
1853 chunkdata = gen.deltachunk(chain)
1853 chunkdata = gen.deltachunk(chain)
1854 if not chunkdata:
1854 if not chunkdata:
1855 break
1855 break
1856 node = chunkdata['node']
1856 node = chunkdata['node']
1857 ui.write("%s\n" % hex(node))
1857 ui.write("%s\n" % hex(node))
1858 chain = node
1858 chain = node
1859 finally:
1859 finally:
1860 f.close()
1860 f.close()
1861
1861
1862 @command('debugcheckstate', [], '')
1862 @command('debugcheckstate', [], '')
1863 def debugcheckstate(ui, repo):
1863 def debugcheckstate(ui, repo):
1864 """validate the correctness of the current dirstate"""
1864 """validate the correctness of the current dirstate"""
1865 parent1, parent2 = repo.dirstate.parents()
1865 parent1, parent2 = repo.dirstate.parents()
1866 m1 = repo[parent1].manifest()
1866 m1 = repo[parent1].manifest()
1867 m2 = repo[parent2].manifest()
1867 m2 = repo[parent2].manifest()
1868 errors = 0
1868 errors = 0
1869 for f in repo.dirstate:
1869 for f in repo.dirstate:
1870 state = repo.dirstate[f]
1870 state = repo.dirstate[f]
1871 if state in "nr" and f not in m1:
1871 if state in "nr" and f not in m1:
1872 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1872 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1873 errors += 1
1873 errors += 1
1874 if state in "a" and f in m1:
1874 if state in "a" and f in m1:
1875 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1875 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1876 errors += 1
1876 errors += 1
1877 if state in "m" and f not in m1 and f not in m2:
1877 if state in "m" and f not in m1 and f not in m2:
1878 ui.warn(_("%s in state %s, but not in either manifest\n") %
1878 ui.warn(_("%s in state %s, but not in either manifest\n") %
1879 (f, state))
1879 (f, state))
1880 errors += 1
1880 errors += 1
1881 for f in m1:
1881 for f in m1:
1882 state = repo.dirstate[f]
1882 state = repo.dirstate[f]
1883 if state not in "nrm":
1883 if state not in "nrm":
1884 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1884 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1885 errors += 1
1885 errors += 1
1886 if errors:
1886 if errors:
1887 error = _(".hg/dirstate inconsistent with current parent's manifest")
1887 error = _(".hg/dirstate inconsistent with current parent's manifest")
1888 raise util.Abort(error)
1888 raise util.Abort(error)
1889
1889
1890 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1890 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1891 def debugcommands(ui, cmd='', *args):
1891 def debugcommands(ui, cmd='', *args):
1892 """list all available commands and options"""
1892 """list all available commands and options"""
1893 for cmd, vals in sorted(table.iteritems()):
1893 for cmd, vals in sorted(table.iteritems()):
1894 cmd = cmd.split('|')[0].strip('^')
1894 cmd = cmd.split('|')[0].strip('^')
1895 opts = ', '.join([i[1] for i in vals[1]])
1895 opts = ', '.join([i[1] for i in vals[1]])
1896 ui.write('%s: %s\n' % (cmd, opts))
1896 ui.write('%s: %s\n' % (cmd, opts))
1897
1897
1898 @command('debugcomplete',
1898 @command('debugcomplete',
1899 [('o', 'options', None, _('show the command options'))],
1899 [('o', 'options', None, _('show the command options'))],
1900 _('[-o] CMD'),
1900 _('[-o] CMD'),
1901 norepo=True)
1901 norepo=True)
1902 def debugcomplete(ui, cmd='', **opts):
1902 def debugcomplete(ui, cmd='', **opts):
1903 """returns the completion list associated with the given command"""
1903 """returns the completion list associated with the given command"""
1904
1904
1905 if opts.get('options'):
1905 if opts.get('options'):
1906 options = []
1906 options = []
1907 otables = [globalopts]
1907 otables = [globalopts]
1908 if cmd:
1908 if cmd:
1909 aliases, entry = cmdutil.findcmd(cmd, table, False)
1909 aliases, entry = cmdutil.findcmd(cmd, table, False)
1910 otables.append(entry[1])
1910 otables.append(entry[1])
1911 for t in otables:
1911 for t in otables:
1912 for o in t:
1912 for o in t:
1913 if "(DEPRECATED)" in o[3]:
1913 if "(DEPRECATED)" in o[3]:
1914 continue
1914 continue
1915 if o[0]:
1915 if o[0]:
1916 options.append('-%s' % o[0])
1916 options.append('-%s' % o[0])
1917 options.append('--%s' % o[1])
1917 options.append('--%s' % o[1])
1918 ui.write("%s\n" % "\n".join(options))
1918 ui.write("%s\n" % "\n".join(options))
1919 return
1919 return
1920
1920
1921 cmdlist = cmdutil.findpossible(cmd, table)
1921 cmdlist = cmdutil.findpossible(cmd, table)
1922 if ui.verbose:
1922 if ui.verbose:
1923 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1923 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1924 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1924 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1925
1925
1926 @command('debugdag',
1926 @command('debugdag',
1927 [('t', 'tags', None, _('use tags as labels')),
1927 [('t', 'tags', None, _('use tags as labels')),
1928 ('b', 'branches', None, _('annotate with branch names')),
1928 ('b', 'branches', None, _('annotate with branch names')),
1929 ('', 'dots', None, _('use dots for runs')),
1929 ('', 'dots', None, _('use dots for runs')),
1930 ('s', 'spaces', None, _('separate elements by spaces'))],
1930 ('s', 'spaces', None, _('separate elements by spaces'))],
1931 _('[OPTION]... [FILE [REV]...]'),
1931 _('[OPTION]... [FILE [REV]...]'),
1932 optionalrepo=True)
1932 optionalrepo=True)
1933 def debugdag(ui, repo, file_=None, *revs, **opts):
1933 def debugdag(ui, repo, file_=None, *revs, **opts):
1934 """format the changelog or an index DAG as a concise textual description
1934 """format the changelog or an index DAG as a concise textual description
1935
1935
1936 If you pass a revlog index, the revlog's DAG is emitted. If you list
1936 If you pass a revlog index, the revlog's DAG is emitted. If you list
1937 revision numbers, they get labeled in the output as rN.
1937 revision numbers, they get labeled in the output as rN.
1938
1938
1939 Otherwise, the changelog DAG of the current repo is emitted.
1939 Otherwise, the changelog DAG of the current repo is emitted.
1940 """
1940 """
1941 spaces = opts.get('spaces')
1941 spaces = opts.get('spaces')
1942 dots = opts.get('dots')
1942 dots = opts.get('dots')
1943 if file_:
1943 if file_:
1944 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1944 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1945 revs = set((int(r) for r in revs))
1945 revs = set((int(r) for r in revs))
1946 def events():
1946 def events():
1947 for r in rlog:
1947 for r in rlog:
1948 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1948 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1949 if p != -1))
1949 if p != -1))
1950 if r in revs:
1950 if r in revs:
1951 yield 'l', (r, "r%i" % r)
1951 yield 'l', (r, "r%i" % r)
1952 elif repo:
1952 elif repo:
1953 cl = repo.changelog
1953 cl = repo.changelog
1954 tags = opts.get('tags')
1954 tags = opts.get('tags')
1955 branches = opts.get('branches')
1955 branches = opts.get('branches')
1956 if tags:
1956 if tags:
1957 labels = {}
1957 labels = {}
1958 for l, n in repo.tags().items():
1958 for l, n in repo.tags().items():
1959 labels.setdefault(cl.rev(n), []).append(l)
1959 labels.setdefault(cl.rev(n), []).append(l)
1960 def events():
1960 def events():
1961 b = "default"
1961 b = "default"
1962 for r in cl:
1962 for r in cl:
1963 if branches:
1963 if branches:
1964 newb = cl.read(cl.node(r))[5]['branch']
1964 newb = cl.read(cl.node(r))[5]['branch']
1965 if newb != b:
1965 if newb != b:
1966 yield 'a', newb
1966 yield 'a', newb
1967 b = newb
1967 b = newb
1968 yield 'n', (r, list(p for p in cl.parentrevs(r)
1968 yield 'n', (r, list(p for p in cl.parentrevs(r)
1969 if p != -1))
1969 if p != -1))
1970 if tags:
1970 if tags:
1971 ls = labels.get(r)
1971 ls = labels.get(r)
1972 if ls:
1972 if ls:
1973 for l in ls:
1973 for l in ls:
1974 yield 'l', (r, l)
1974 yield 'l', (r, l)
1975 else:
1975 else:
1976 raise util.Abort(_('need repo for changelog dag'))
1976 raise util.Abort(_('need repo for changelog dag'))
1977
1977
1978 for line in dagparser.dagtextlines(events(),
1978 for line in dagparser.dagtextlines(events(),
1979 addspaces=spaces,
1979 addspaces=spaces,
1980 wraplabels=True,
1980 wraplabels=True,
1981 wrapannotations=True,
1981 wrapannotations=True,
1982 wrapnonlinear=dots,
1982 wrapnonlinear=dots,
1983 usedots=dots,
1983 usedots=dots,
1984 maxlinewidth=70):
1984 maxlinewidth=70):
1985 ui.write(line)
1985 ui.write(line)
1986 ui.write("\n")
1986 ui.write("\n")
1987
1987
1988 @command('debugdata',
1988 @command('debugdata',
1989 [('c', 'changelog', False, _('open changelog')),
1989 [('c', 'changelog', False, _('open changelog')),
1990 ('m', 'manifest', False, _('open manifest'))],
1990 ('m', 'manifest', False, _('open manifest'))],
1991 _('-c|-m|FILE REV'))
1991 _('-c|-m|FILE REV'))
1992 def debugdata(ui, repo, file_, rev=None, **opts):
1992 def debugdata(ui, repo, file_, rev=None, **opts):
1993 """dump the contents of a data file revision"""
1993 """dump the contents of a data file revision"""
1994 if opts.get('changelog') or opts.get('manifest'):
1994 if opts.get('changelog') or opts.get('manifest'):
1995 file_, rev = None, file_
1995 file_, rev = None, file_
1996 elif rev is None:
1996 elif rev is None:
1997 raise error.CommandError('debugdata', _('invalid arguments'))
1997 raise error.CommandError('debugdata', _('invalid arguments'))
1998 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1998 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1999 try:
1999 try:
2000 ui.write(r.revision(r.lookup(rev)))
2000 ui.write(r.revision(r.lookup(rev)))
2001 except KeyError:
2001 except KeyError:
2002 raise util.Abort(_('invalid revision identifier %s') % rev)
2002 raise util.Abort(_('invalid revision identifier %s') % rev)
2003
2003
2004 @command('debugdate',
2004 @command('debugdate',
2005 [('e', 'extended', None, _('try extended date formats'))],
2005 [('e', 'extended', None, _('try extended date formats'))],
2006 _('[-e] DATE [RANGE]'),
2006 _('[-e] DATE [RANGE]'),
2007 norepo=True, optionalrepo=True)
2007 norepo=True, optionalrepo=True)
2008 def debugdate(ui, date, range=None, **opts):
2008 def debugdate(ui, date, range=None, **opts):
2009 """parse and display a date"""
2009 """parse and display a date"""
2010 if opts["extended"]:
2010 if opts["extended"]:
2011 d = util.parsedate(date, util.extendeddateformats)
2011 d = util.parsedate(date, util.extendeddateformats)
2012 else:
2012 else:
2013 d = util.parsedate(date)
2013 d = util.parsedate(date)
2014 ui.write(("internal: %s %s\n") % d)
2014 ui.write(("internal: %s %s\n") % d)
2015 ui.write(("standard: %s\n") % util.datestr(d))
2015 ui.write(("standard: %s\n") % util.datestr(d))
2016 if range:
2016 if range:
2017 m = util.matchdate(range)
2017 m = util.matchdate(range)
2018 ui.write(("match: %s\n") % m(d[0]))
2018 ui.write(("match: %s\n") % m(d[0]))
2019
2019
2020 @command('debugdiscovery',
2020 @command('debugdiscovery',
2021 [('', 'old', None, _('use old-style discovery')),
2021 [('', 'old', None, _('use old-style discovery')),
2022 ('', 'nonheads', None,
2022 ('', 'nonheads', None,
2023 _('use old-style discovery with non-heads included')),
2023 _('use old-style discovery with non-heads included')),
2024 ] + remoteopts,
2024 ] + remoteopts,
2025 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2025 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2026 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2026 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2027 """runs the changeset discovery protocol in isolation"""
2027 """runs the changeset discovery protocol in isolation"""
2028 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2028 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2029 opts.get('branch'))
2029 opts.get('branch'))
2030 remote = hg.peer(repo, opts, remoteurl)
2030 remote = hg.peer(repo, opts, remoteurl)
2031 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2031 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2032
2032
2033 # make sure tests are repeatable
2033 # make sure tests are repeatable
2034 random.seed(12323)
2034 random.seed(12323)
2035
2035
2036 def doit(localheads, remoteheads, remote=remote):
2036 def doit(localheads, remoteheads, remote=remote):
2037 if opts.get('old'):
2037 if opts.get('old'):
2038 if localheads:
2038 if localheads:
2039 raise util.Abort('cannot use localheads with old style '
2039 raise util.Abort('cannot use localheads with old style '
2040 'discovery')
2040 'discovery')
2041 if not util.safehasattr(remote, 'branches'):
2041 if not util.safehasattr(remote, 'branches'):
2042 # enable in-client legacy support
2042 # enable in-client legacy support
2043 remote = localrepo.locallegacypeer(remote.local())
2043 remote = localrepo.locallegacypeer(remote.local())
2044 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2044 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2045 force=True)
2045 force=True)
2046 common = set(common)
2046 common = set(common)
2047 if not opts.get('nonheads'):
2047 if not opts.get('nonheads'):
2048 ui.write(("unpruned common: %s\n") %
2048 ui.write(("unpruned common: %s\n") %
2049 " ".join(sorted(short(n) for n in common)))
2049 " ".join(sorted(short(n) for n in common)))
2050 dag = dagutil.revlogdag(repo.changelog)
2050 dag = dagutil.revlogdag(repo.changelog)
2051 all = dag.ancestorset(dag.internalizeall(common))
2051 all = dag.ancestorset(dag.internalizeall(common))
2052 common = dag.externalizeall(dag.headsetofconnecteds(all))
2052 common = dag.externalizeall(dag.headsetofconnecteds(all))
2053 else:
2053 else:
2054 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2054 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2055 common = set(common)
2055 common = set(common)
2056 rheads = set(hds)
2056 rheads = set(hds)
2057 lheads = set(repo.heads())
2057 lheads = set(repo.heads())
2058 ui.write(("common heads: %s\n") %
2058 ui.write(("common heads: %s\n") %
2059 " ".join(sorted(short(n) for n in common)))
2059 " ".join(sorted(short(n) for n in common)))
2060 if lheads <= common:
2060 if lheads <= common:
2061 ui.write(("local is subset\n"))
2061 ui.write(("local is subset\n"))
2062 elif rheads <= common:
2062 elif rheads <= common:
2063 ui.write(("remote is subset\n"))
2063 ui.write(("remote is subset\n"))
2064
2064
2065 serverlogs = opts.get('serverlog')
2065 serverlogs = opts.get('serverlog')
2066 if serverlogs:
2066 if serverlogs:
2067 for filename in serverlogs:
2067 for filename in serverlogs:
2068 logfile = open(filename, 'r')
2068 logfile = open(filename, 'r')
2069 try:
2069 try:
2070 line = logfile.readline()
2070 line = logfile.readline()
2071 while line:
2071 while line:
2072 parts = line.strip().split(';')
2072 parts = line.strip().split(';')
2073 op = parts[1]
2073 op = parts[1]
2074 if op == 'cg':
2074 if op == 'cg':
2075 pass
2075 pass
2076 elif op == 'cgss':
2076 elif op == 'cgss':
2077 doit(parts[2].split(' '), parts[3].split(' '))
2077 doit(parts[2].split(' '), parts[3].split(' '))
2078 elif op == 'unb':
2078 elif op == 'unb':
2079 doit(parts[3].split(' '), parts[2].split(' '))
2079 doit(parts[3].split(' '), parts[2].split(' '))
2080 line = logfile.readline()
2080 line = logfile.readline()
2081 finally:
2081 finally:
2082 logfile.close()
2082 logfile.close()
2083
2083
2084 else:
2084 else:
2085 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2085 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2086 opts.get('remote_head'))
2086 opts.get('remote_head'))
2087 localrevs = opts.get('local_head')
2087 localrevs = opts.get('local_head')
2088 doit(localrevs, remoterevs)
2088 doit(localrevs, remoterevs)
2089
2089
2090 @command('debugfileset',
2090 @command('debugfileset',
2091 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2091 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2092 _('[-r REV] FILESPEC'))
2092 _('[-r REV] FILESPEC'))
2093 def debugfileset(ui, repo, expr, **opts):
2093 def debugfileset(ui, repo, expr, **opts):
2094 '''parse and apply a fileset specification'''
2094 '''parse and apply a fileset specification'''
2095 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2095 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2096 if ui.verbose:
2096 if ui.verbose:
2097 tree = fileset.parse(expr)[0]
2097 tree = fileset.parse(expr)[0]
2098 ui.note(tree, "\n")
2098 ui.note(tree, "\n")
2099
2099
2100 for f in ctx.getfileset(expr):
2100 for f in ctx.getfileset(expr):
2101 ui.write("%s\n" % f)
2101 ui.write("%s\n" % f)
2102
2102
2103 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2103 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2104 def debugfsinfo(ui, path="."):
2104 def debugfsinfo(ui, path="."):
2105 """show information detected about current filesystem"""
2105 """show information detected about current filesystem"""
2106 util.writefile('.debugfsinfo', '')
2106 util.writefile('.debugfsinfo', '')
2107 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2107 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2108 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2108 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2109 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2109 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2110 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2110 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2111 and 'yes' or 'no'))
2111 and 'yes' or 'no'))
2112 os.unlink('.debugfsinfo')
2112 os.unlink('.debugfsinfo')
2113
2113
2114 @command('debuggetbundle',
2114 @command('debuggetbundle',
2115 [('H', 'head', [], _('id of head node'), _('ID')),
2115 [('H', 'head', [], _('id of head node'), _('ID')),
2116 ('C', 'common', [], _('id of common node'), _('ID')),
2116 ('C', 'common', [], _('id of common node'), _('ID')),
2117 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2117 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2118 _('REPO FILE [-H|-C ID]...'),
2118 _('REPO FILE [-H|-C ID]...'),
2119 norepo=True)
2119 norepo=True)
2120 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2120 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2121 """retrieves a bundle from a repo
2121 """retrieves a bundle from a repo
2122
2122
2123 Every ID must be a full-length hex node id string. Saves the bundle to the
2123 Every ID must be a full-length hex node id string. Saves the bundle to the
2124 given file.
2124 given file.
2125 """
2125 """
2126 repo = hg.peer(ui, opts, repopath)
2126 repo = hg.peer(ui, opts, repopath)
2127 if not repo.capable('getbundle'):
2127 if not repo.capable('getbundle'):
2128 raise util.Abort("getbundle() not supported by target repository")
2128 raise util.Abort("getbundle() not supported by target repository")
2129 args = {}
2129 args = {}
2130 if common:
2130 if common:
2131 args['common'] = [bin(s) for s in common]
2131 args['common'] = [bin(s) for s in common]
2132 if head:
2132 if head:
2133 args['heads'] = [bin(s) for s in head]
2133 args['heads'] = [bin(s) for s in head]
2134 # TODO: get desired bundlecaps from command line.
2134 # TODO: get desired bundlecaps from command line.
2135 args['bundlecaps'] = None
2135 args['bundlecaps'] = None
2136 bundle = repo.getbundle('debug', **args)
2136 bundle = repo.getbundle('debug', **args)
2137
2137
2138 bundletype = opts.get('type', 'bzip2').lower()
2138 bundletype = opts.get('type', 'bzip2').lower()
2139 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2139 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2140 bundletype = btypes.get(bundletype)
2140 bundletype = btypes.get(bundletype)
2141 if bundletype not in changegroup.bundletypes:
2141 if bundletype not in changegroup.bundletypes:
2142 raise util.Abort(_('unknown bundle type specified with --type'))
2142 raise util.Abort(_('unknown bundle type specified with --type'))
2143 changegroup.writebundle(bundle, bundlepath, bundletype)
2143 changegroup.writebundle(bundle, bundlepath, bundletype)
2144
2144
2145 @command('debugignore', [], '')
2145 @command('debugignore', [], '')
2146 def debugignore(ui, repo, *values, **opts):
2146 def debugignore(ui, repo, *values, **opts):
2147 """display the combined ignore pattern"""
2147 """display the combined ignore pattern"""
2148 ignore = repo.dirstate._ignore
2148 ignore = repo.dirstate._ignore
2149 includepat = getattr(ignore, 'includepat', None)
2149 includepat = getattr(ignore, 'includepat', None)
2150 if includepat is not None:
2150 if includepat is not None:
2151 ui.write("%s\n" % includepat)
2151 ui.write("%s\n" % includepat)
2152 else:
2152 else:
2153 raise util.Abort(_("no ignore patterns found"))
2153 raise util.Abort(_("no ignore patterns found"))
2154
2154
2155 @command('debugindex',
2155 @command('debugindex',
2156 [('c', 'changelog', False, _('open changelog')),
2156 [('c', 'changelog', False, _('open changelog')),
2157 ('m', 'manifest', False, _('open manifest')),
2157 ('m', 'manifest', False, _('open manifest')),
2158 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2158 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2159 _('[-f FORMAT] -c|-m|FILE'),
2159 _('[-f FORMAT] -c|-m|FILE'),
2160 optionalrepo=True)
2160 optionalrepo=True)
2161 def debugindex(ui, repo, file_=None, **opts):
2161 def debugindex(ui, repo, file_=None, **opts):
2162 """dump the contents of an index file"""
2162 """dump the contents of an index file"""
2163 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2163 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2164 format = opts.get('format', 0)
2164 format = opts.get('format', 0)
2165 if format not in (0, 1):
2165 if format not in (0, 1):
2166 raise util.Abort(_("unknown format %d") % format)
2166 raise util.Abort(_("unknown format %d") % format)
2167
2167
2168 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2168 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2169 if generaldelta:
2169 if generaldelta:
2170 basehdr = ' delta'
2170 basehdr = ' delta'
2171 else:
2171 else:
2172 basehdr = ' base'
2172 basehdr = ' base'
2173
2173
2174 if format == 0:
2174 if format == 0:
2175 ui.write(" rev offset length " + basehdr + " linkrev"
2175 ui.write(" rev offset length " + basehdr + " linkrev"
2176 " nodeid p1 p2\n")
2176 " nodeid p1 p2\n")
2177 elif format == 1:
2177 elif format == 1:
2178 ui.write(" rev flag offset length"
2178 ui.write(" rev flag offset length"
2179 " size " + basehdr + " link p1 p2"
2179 " size " + basehdr + " link p1 p2"
2180 " nodeid\n")
2180 " nodeid\n")
2181
2181
2182 for i in r:
2182 for i in r:
2183 node = r.node(i)
2183 node = r.node(i)
2184 if generaldelta:
2184 if generaldelta:
2185 base = r.deltaparent(i)
2185 base = r.deltaparent(i)
2186 else:
2186 else:
2187 base = r.chainbase(i)
2187 base = r.chainbase(i)
2188 if format == 0:
2188 if format == 0:
2189 try:
2189 try:
2190 pp = r.parents(node)
2190 pp = r.parents(node)
2191 except Exception:
2191 except Exception:
2192 pp = [nullid, nullid]
2192 pp = [nullid, nullid]
2193 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2193 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2194 i, r.start(i), r.length(i), base, r.linkrev(i),
2194 i, r.start(i), r.length(i), base, r.linkrev(i),
2195 short(node), short(pp[0]), short(pp[1])))
2195 short(node), short(pp[0]), short(pp[1])))
2196 elif format == 1:
2196 elif format == 1:
2197 pr = r.parentrevs(i)
2197 pr = r.parentrevs(i)
2198 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2198 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2199 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2199 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2200 base, r.linkrev(i), pr[0], pr[1], short(node)))
2200 base, r.linkrev(i), pr[0], pr[1], short(node)))
2201
2201
2202 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2202 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2203 def debugindexdot(ui, repo, file_):
2203 def debugindexdot(ui, repo, file_):
2204 """dump an index DAG as a graphviz dot file"""
2204 """dump an index DAG as a graphviz dot file"""
2205 r = None
2205 r = None
2206 if repo:
2206 if repo:
2207 filelog = repo.file(file_)
2207 filelog = repo.file(file_)
2208 if len(filelog):
2208 if len(filelog):
2209 r = filelog
2209 r = filelog
2210 if not r:
2210 if not r:
2211 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2211 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2212 ui.write(("digraph G {\n"))
2212 ui.write(("digraph G {\n"))
2213 for i in r:
2213 for i in r:
2214 node = r.node(i)
2214 node = r.node(i)
2215 pp = r.parents(node)
2215 pp = r.parents(node)
2216 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2216 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2217 if pp[1] != nullid:
2217 if pp[1] != nullid:
2218 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2218 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2219 ui.write("}\n")
2219 ui.write("}\n")
2220
2220
2221 @command('debuginstall', [], '', norepo=True)
2221 @command('debuginstall', [], '', norepo=True)
2222 def debuginstall(ui):
2222 def debuginstall(ui):
2223 '''test Mercurial installation
2223 '''test Mercurial installation
2224
2224
2225 Returns 0 on success.
2225 Returns 0 on success.
2226 '''
2226 '''
2227
2227
2228 def writetemp(contents):
2228 def writetemp(contents):
2229 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2229 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2230 f = os.fdopen(fd, "wb")
2230 f = os.fdopen(fd, "wb")
2231 f.write(contents)
2231 f.write(contents)
2232 f.close()
2232 f.close()
2233 return name
2233 return name
2234
2234
2235 problems = 0
2235 problems = 0
2236
2236
2237 # encoding
2237 # encoding
2238 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2238 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2239 try:
2239 try:
2240 encoding.fromlocal("test")
2240 encoding.fromlocal("test")
2241 except util.Abort, inst:
2241 except util.Abort, inst:
2242 ui.write(" %s\n" % inst)
2242 ui.write(" %s\n" % inst)
2243 ui.write(_(" (check that your locale is properly set)\n"))
2243 ui.write(_(" (check that your locale is properly set)\n"))
2244 problems += 1
2244 problems += 1
2245
2245
2246 # Python
2246 # Python
2247 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2247 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2248 ui.status(_("checking Python version (%s)\n")
2248 ui.status(_("checking Python version (%s)\n")
2249 % ("%s.%s.%s" % sys.version_info[:3]))
2249 % ("%s.%s.%s" % sys.version_info[:3]))
2250 ui.status(_("checking Python lib (%s)...\n")
2250 ui.status(_("checking Python lib (%s)...\n")
2251 % os.path.dirname(os.__file__))
2251 % os.path.dirname(os.__file__))
2252
2252
2253 # compiled modules
2253 # compiled modules
2254 ui.status(_("checking installed modules (%s)...\n")
2254 ui.status(_("checking installed modules (%s)...\n")
2255 % os.path.dirname(__file__))
2255 % os.path.dirname(__file__))
2256 try:
2256 try:
2257 import bdiff, mpatch, base85, osutil
2257 import bdiff, mpatch, base85, osutil
2258 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2258 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2259 except Exception, inst:
2259 except Exception, inst:
2260 ui.write(" %s\n" % inst)
2260 ui.write(" %s\n" % inst)
2261 ui.write(_(" One or more extensions could not be found"))
2261 ui.write(_(" One or more extensions could not be found"))
2262 ui.write(_(" (check that you compiled the extensions)\n"))
2262 ui.write(_(" (check that you compiled the extensions)\n"))
2263 problems += 1
2263 problems += 1
2264
2264
2265 # templates
2265 # templates
2266 import templater
2266 import templater
2267 p = templater.templatepaths()
2267 p = templater.templatepaths()
2268 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2268 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2269 if p:
2269 if p:
2270 m = templater.templatepath("map-cmdline.default")
2270 m = templater.templatepath("map-cmdline.default")
2271 if m:
2271 if m:
2272 # template found, check if it is working
2272 # template found, check if it is working
2273 try:
2273 try:
2274 templater.templater(m)
2274 templater.templater(m)
2275 except Exception, inst:
2275 except Exception, inst:
2276 ui.write(" %s\n" % inst)
2276 ui.write(" %s\n" % inst)
2277 p = None
2277 p = None
2278 else:
2278 else:
2279 ui.write(_(" template 'default' not found\n"))
2279 ui.write(_(" template 'default' not found\n"))
2280 p = None
2280 p = None
2281 else:
2281 else:
2282 ui.write(_(" no template directories found\n"))
2282 ui.write(_(" no template directories found\n"))
2283 if not p:
2283 if not p:
2284 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2284 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2285 problems += 1
2285 problems += 1
2286
2286
2287 # editor
2287 # editor
2288 ui.status(_("checking commit editor...\n"))
2288 ui.status(_("checking commit editor...\n"))
2289 editor = ui.geteditor()
2289 editor = ui.geteditor()
2290 cmdpath = util.findexe(shlex.split(editor)[0])
2290 cmdpath = util.findexe(shlex.split(editor)[0])
2291 if not cmdpath:
2291 if not cmdpath:
2292 if editor == 'vi':
2292 if editor == 'vi':
2293 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2293 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2294 ui.write(_(" (specify a commit editor in your configuration"
2294 ui.write(_(" (specify a commit editor in your configuration"
2295 " file)\n"))
2295 " file)\n"))
2296 else:
2296 else:
2297 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2297 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2298 ui.write(_(" (specify a commit editor in your configuration"
2298 ui.write(_(" (specify a commit editor in your configuration"
2299 " file)\n"))
2299 " file)\n"))
2300 problems += 1
2300 problems += 1
2301
2301
2302 # check username
2302 # check username
2303 ui.status(_("checking username...\n"))
2303 ui.status(_("checking username...\n"))
2304 try:
2304 try:
2305 ui.username()
2305 ui.username()
2306 except util.Abort, e:
2306 except util.Abort, e:
2307 ui.write(" %s\n" % e)
2307 ui.write(" %s\n" % e)
2308 ui.write(_(" (specify a username in your configuration file)\n"))
2308 ui.write(_(" (specify a username in your configuration file)\n"))
2309 problems += 1
2309 problems += 1
2310
2310
2311 if not problems:
2311 if not problems:
2312 ui.status(_("no problems detected\n"))
2312 ui.status(_("no problems detected\n"))
2313 else:
2313 else:
2314 ui.write(_("%s problems detected,"
2314 ui.write(_("%s problems detected,"
2315 " please check your install!\n") % problems)
2315 " please check your install!\n") % problems)
2316
2316
2317 return problems
2317 return problems
2318
2318
2319 @command('debugknown', [], _('REPO ID...'), norepo=True)
2319 @command('debugknown', [], _('REPO ID...'), norepo=True)
2320 def debugknown(ui, repopath, *ids, **opts):
2320 def debugknown(ui, repopath, *ids, **opts):
2321 """test whether node ids are known to a repo
2321 """test whether node ids are known to a repo
2322
2322
2323 Every ID must be a full-length hex node id string. Returns a list of 0s
2323 Every ID must be a full-length hex node id string. Returns a list of 0s
2324 and 1s indicating unknown/known.
2324 and 1s indicating unknown/known.
2325 """
2325 """
2326 repo = hg.peer(ui, opts, repopath)
2326 repo = hg.peer(ui, opts, repopath)
2327 if not repo.capable('known'):
2327 if not repo.capable('known'):
2328 raise util.Abort("known() not supported by target repository")
2328 raise util.Abort("known() not supported by target repository")
2329 flags = repo.known([bin(s) for s in ids])
2329 flags = repo.known([bin(s) for s in ids])
2330 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2330 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2331
2331
2332 @command('debuglabelcomplete', [], _('LABEL...'))
2332 @command('debuglabelcomplete', [], _('LABEL...'))
2333 def debuglabelcomplete(ui, repo, *args):
2333 def debuglabelcomplete(ui, repo, *args):
2334 '''complete "labels" - tags, open branch names, bookmark names'''
2334 '''complete "labels" - tags, open branch names, bookmark names'''
2335
2335
2336 labels = set()
2336 labels = set()
2337 labels.update(t[0] for t in repo.tagslist())
2337 labels.update(t[0] for t in repo.tagslist())
2338 labels.update(repo._bookmarks.keys())
2338 labels.update(repo._bookmarks.keys())
2339 labels.update(tag for (tag, heads, tip, closed)
2339 labels.update(tag for (tag, heads, tip, closed)
2340 in repo.branchmap().iterbranches() if not closed)
2340 in repo.branchmap().iterbranches() if not closed)
2341 completions = set()
2341 completions = set()
2342 if not args:
2342 if not args:
2343 args = ['']
2343 args = ['']
2344 for a in args:
2344 for a in args:
2345 completions.update(l for l in labels if l.startswith(a))
2345 completions.update(l for l in labels if l.startswith(a))
2346 ui.write('\n'.join(sorted(completions)))
2346 ui.write('\n'.join(sorted(completions)))
2347 ui.write('\n')
2347 ui.write('\n')
2348
2348
2349 @command('debuglocks',
2349 @command('debuglocks',
2350 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2350 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2351 ('W', 'force-wlock', None,
2351 ('W', 'force-wlock', None,
2352 _('free the working state lock (DANGEROUS)'))],
2352 _('free the working state lock (DANGEROUS)'))],
2353 _('[OPTION]...'))
2353 _('[OPTION]...'))
2354 def debuglocks(ui, repo, **opts):
2354 def debuglocks(ui, repo, **opts):
2355 """show or modify state of locks
2355 """show or modify state of locks
2356
2356
2357 By default, this command will show which locks are held. This
2357 By default, this command will show which locks are held. This
2358 includes the user and process holding the lock, the amount of time
2358 includes the user and process holding the lock, the amount of time
2359 the lock has been held, and the machine name where the process is
2359 the lock has been held, and the machine name where the process is
2360 running if it's not local.
2360 running if it's not local.
2361
2361
2362 Locks protect the integrity of Mercurial's data, so should be
2362 Locks protect the integrity of Mercurial's data, so should be
2363 treated with care. System crashes or other interruptions may cause
2363 treated with care. System crashes or other interruptions may cause
2364 locks to not be properly released, though Mercurial will usually
2364 locks to not be properly released, though Mercurial will usually
2365 detect and remove such stale locks automatically.
2365 detect and remove such stale locks automatically.
2366
2366
2367 However, detecting stale locks may not always be possible (for
2367 However, detecting stale locks may not always be possible (for
2368 instance, on a shared filesystem). Removing locks may also be
2368 instance, on a shared filesystem). Removing locks may also be
2369 blocked by filesystem permissions.
2369 blocked by filesystem permissions.
2370
2370
2371 Returns 0 if no locks are held.
2371 Returns 0 if no locks are held.
2372
2372
2373 """
2373 """
2374
2374
2375 if opts.get('force_lock'):
2375 if opts.get('force_lock'):
2376 repo.svfs.unlink('lock')
2376 repo.svfs.unlink('lock')
2377 if opts.get('force_wlock'):
2377 if opts.get('force_wlock'):
2378 repo.vfs.unlink('wlock')
2378 repo.vfs.unlink('wlock')
2379 if opts.get('force_lock') or opts.get('force_lock'):
2379 if opts.get('force_lock') or opts.get('force_lock'):
2380 return 0
2380 return 0
2381
2381
2382 now = time.time()
2382 now = time.time()
2383 held = 0
2383 held = 0
2384
2384
2385 def report(vfs, name, method):
2385 def report(vfs, name, method):
2386 # this causes stale locks to get reaped for more accurate reporting
2386 # this causes stale locks to get reaped for more accurate reporting
2387 try:
2387 try:
2388 l = method(False)
2388 l = method(False)
2389 except error.LockHeld:
2389 except error.LockHeld:
2390 l = None
2390 l = None
2391
2391
2392 if l:
2392 if l:
2393 l.release()
2393 l.release()
2394 else:
2394 else:
2395 try:
2395 try:
2396 stat = repo.svfs.lstat(name)
2396 stat = repo.svfs.lstat(name)
2397 age = now - stat.st_mtime
2397 age = now - stat.st_mtime
2398 user = util.username(stat.st_uid)
2398 user = util.username(stat.st_uid)
2399 locker = vfs.readlock(name)
2399 locker = vfs.readlock(name)
2400 if ":" in locker:
2400 if ":" in locker:
2401 host, pid = locker.split(':')
2401 host, pid = locker.split(':')
2402 if host == socket.gethostname():
2402 if host == socket.gethostname():
2403 locker = 'user %s, process %s' % (user, pid)
2403 locker = 'user %s, process %s' % (user, pid)
2404 else:
2404 else:
2405 locker = 'user %s, process %s, host %s' \
2405 locker = 'user %s, process %s, host %s' \
2406 % (user, pid, host)
2406 % (user, pid, host)
2407 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2407 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2408 return 1
2408 return 1
2409 except OSError, e:
2409 except OSError, e:
2410 if e.errno != errno.ENOENT:
2410 if e.errno != errno.ENOENT:
2411 raise
2411 raise
2412
2412
2413 ui.write("%-6s free\n" % (name + ":"))
2413 ui.write("%-6s free\n" % (name + ":"))
2414 return 0
2414 return 0
2415
2415
2416 held += report(repo.svfs, "lock", repo.lock)
2416 held += report(repo.svfs, "lock", repo.lock)
2417 held += report(repo.vfs, "wlock", repo.wlock)
2417 held += report(repo.vfs, "wlock", repo.wlock)
2418
2418
2419 return held
2419 return held
2420
2420
2421 @command('debugobsolete',
2421 @command('debugobsolete',
2422 [('', 'flags', 0, _('markers flag')),
2422 [('', 'flags', 0, _('markers flag')),
2423 ('', 'record-parents', False,
2423 ('', 'record-parents', False,
2424 _('record parent information for the precursor')),
2424 _('record parent information for the precursor')),
2425 ('r', 'rev', [], _('display markers relevant to REV')),
2425 ('r', 'rev', [], _('display markers relevant to REV')),
2426 ] + commitopts2,
2426 ] + commitopts2,
2427 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2427 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2428 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2428 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2429 """create arbitrary obsolete marker
2429 """create arbitrary obsolete marker
2430
2430
2431 With no arguments, displays the list of obsolescence markers."""
2431 With no arguments, displays the list of obsolescence markers."""
2432
2432
2433 def parsenodeid(s):
2433 def parsenodeid(s):
2434 try:
2434 try:
2435 # We do not use revsingle/revrange functions here to accept
2435 # We do not use revsingle/revrange functions here to accept
2436 # arbitrary node identifiers, possibly not present in the
2436 # arbitrary node identifiers, possibly not present in the
2437 # local repository.
2437 # local repository.
2438 n = bin(s)
2438 n = bin(s)
2439 if len(n) != len(nullid):
2439 if len(n) != len(nullid):
2440 raise TypeError()
2440 raise TypeError()
2441 return n
2441 return n
2442 except TypeError:
2442 except TypeError:
2443 raise util.Abort('changeset references must be full hexadecimal '
2443 raise util.Abort('changeset references must be full hexadecimal '
2444 'node identifiers')
2444 'node identifiers')
2445
2445
2446 if precursor is not None:
2446 if precursor is not None:
2447 if opts['rev']:
2447 if opts['rev']:
2448 raise util.Abort('cannot select revision when creating marker')
2448 raise util.Abort('cannot select revision when creating marker')
2449 metadata = {}
2449 metadata = {}
2450 metadata['user'] = opts['user'] or ui.username()
2450 metadata['user'] = opts['user'] or ui.username()
2451 succs = tuple(parsenodeid(succ) for succ in successors)
2451 succs = tuple(parsenodeid(succ) for succ in successors)
2452 l = repo.lock()
2452 l = repo.lock()
2453 try:
2453 try:
2454 tr = repo.transaction('debugobsolete')
2454 tr = repo.transaction('debugobsolete')
2455 try:
2455 try:
2456 try:
2456 try:
2457 date = opts.get('date')
2457 date = opts.get('date')
2458 if date:
2458 if date:
2459 date = util.parsedate(date)
2459 date = util.parsedate(date)
2460 else:
2460 else:
2461 date = None
2461 date = None
2462 prec = parsenodeid(precursor)
2462 prec = parsenodeid(precursor)
2463 parents = None
2463 parents = None
2464 if opts['record_parents']:
2464 if opts['record_parents']:
2465 if prec not in repo.unfiltered():
2465 if prec not in repo.unfiltered():
2466 raise util.Abort('cannot used --record-parents on '
2466 raise util.Abort('cannot used --record-parents on '
2467 'unknown changesets')
2467 'unknown changesets')
2468 parents = repo.unfiltered()[prec].parents()
2468 parents = repo.unfiltered()[prec].parents()
2469 parents = tuple(p.node() for p in parents)
2469 parents = tuple(p.node() for p in parents)
2470 repo.obsstore.create(tr, prec, succs, opts['flags'],
2470 repo.obsstore.create(tr, prec, succs, opts['flags'],
2471 parents=parents, date=date,
2471 parents=parents, date=date,
2472 metadata=metadata)
2472 metadata=metadata)
2473 tr.close()
2473 tr.close()
2474 except ValueError, exc:
2474 except ValueError, exc:
2475 raise util.Abort(_('bad obsmarker input: %s') % exc)
2475 raise util.Abort(_('bad obsmarker input: %s') % exc)
2476 finally:
2476 finally:
2477 tr.release()
2477 tr.release()
2478 finally:
2478 finally:
2479 l.release()
2479 l.release()
2480 else:
2480 else:
2481 if opts['rev']:
2481 if opts['rev']:
2482 revs = scmutil.revrange(repo, opts['rev'])
2482 revs = scmutil.revrange(repo, opts['rev'])
2483 nodes = [repo[r].node() for r in revs]
2483 nodes = [repo[r].node() for r in revs]
2484 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2484 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2485 markers.sort(key=lambda x: x._data)
2485 markers.sort(key=lambda x: x._data)
2486 else:
2486 else:
2487 markers = obsolete.getmarkers(repo)
2487 markers = obsolete.getmarkers(repo)
2488
2488
2489 for m in markers:
2489 for m in markers:
2490 cmdutil.showmarker(ui, m)
2490 cmdutil.showmarker(ui, m)
2491
2491
2492 @command('debugpathcomplete',
2492 @command('debugpathcomplete',
2493 [('f', 'full', None, _('complete an entire path')),
2493 [('f', 'full', None, _('complete an entire path')),
2494 ('n', 'normal', None, _('show only normal files')),
2494 ('n', 'normal', None, _('show only normal files')),
2495 ('a', 'added', None, _('show only added files')),
2495 ('a', 'added', None, _('show only added files')),
2496 ('r', 'removed', None, _('show only removed files'))],
2496 ('r', 'removed', None, _('show only removed files'))],
2497 _('FILESPEC...'))
2497 _('FILESPEC...'))
2498 def debugpathcomplete(ui, repo, *specs, **opts):
2498 def debugpathcomplete(ui, repo, *specs, **opts):
2499 '''complete part or all of a tracked path
2499 '''complete part or all of a tracked path
2500
2500
2501 This command supports shells that offer path name completion. It
2501 This command supports shells that offer path name completion. It
2502 currently completes only files already known to the dirstate.
2502 currently completes only files already known to the dirstate.
2503
2503
2504 Completion extends only to the next path segment unless
2504 Completion extends only to the next path segment unless
2505 --full is specified, in which case entire paths are used.'''
2505 --full is specified, in which case entire paths are used.'''
2506
2506
2507 def complete(path, acceptable):
2507 def complete(path, acceptable):
2508 dirstate = repo.dirstate
2508 dirstate = repo.dirstate
2509 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2509 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2510 rootdir = repo.root + os.sep
2510 rootdir = repo.root + os.sep
2511 if spec != repo.root and not spec.startswith(rootdir):
2511 if spec != repo.root and not spec.startswith(rootdir):
2512 return [], []
2512 return [], []
2513 if os.path.isdir(spec):
2513 if os.path.isdir(spec):
2514 spec += '/'
2514 spec += '/'
2515 spec = spec[len(rootdir):]
2515 spec = spec[len(rootdir):]
2516 fixpaths = os.sep != '/'
2516 fixpaths = os.sep != '/'
2517 if fixpaths:
2517 if fixpaths:
2518 spec = spec.replace(os.sep, '/')
2518 spec = spec.replace(os.sep, '/')
2519 speclen = len(spec)
2519 speclen = len(spec)
2520 fullpaths = opts['full']
2520 fullpaths = opts['full']
2521 files, dirs = set(), set()
2521 files, dirs = set(), set()
2522 adddir, addfile = dirs.add, files.add
2522 adddir, addfile = dirs.add, files.add
2523 for f, st in dirstate.iteritems():
2523 for f, st in dirstate.iteritems():
2524 if f.startswith(spec) and st[0] in acceptable:
2524 if f.startswith(spec) and st[0] in acceptable:
2525 if fixpaths:
2525 if fixpaths:
2526 f = f.replace('/', os.sep)
2526 f = f.replace('/', os.sep)
2527 if fullpaths:
2527 if fullpaths:
2528 addfile(f)
2528 addfile(f)
2529 continue
2529 continue
2530 s = f.find(os.sep, speclen)
2530 s = f.find(os.sep, speclen)
2531 if s >= 0:
2531 if s >= 0:
2532 adddir(f[:s])
2532 adddir(f[:s])
2533 else:
2533 else:
2534 addfile(f)
2534 addfile(f)
2535 return files, dirs
2535 return files, dirs
2536
2536
2537 acceptable = ''
2537 acceptable = ''
2538 if opts['normal']:
2538 if opts['normal']:
2539 acceptable += 'nm'
2539 acceptable += 'nm'
2540 if opts['added']:
2540 if opts['added']:
2541 acceptable += 'a'
2541 acceptable += 'a'
2542 if opts['removed']:
2542 if opts['removed']:
2543 acceptable += 'r'
2543 acceptable += 'r'
2544 cwd = repo.getcwd()
2544 cwd = repo.getcwd()
2545 if not specs:
2545 if not specs:
2546 specs = ['.']
2546 specs = ['.']
2547
2547
2548 files, dirs = set(), set()
2548 files, dirs = set(), set()
2549 for spec in specs:
2549 for spec in specs:
2550 f, d = complete(spec, acceptable or 'nmar')
2550 f, d = complete(spec, acceptable or 'nmar')
2551 files.update(f)
2551 files.update(f)
2552 dirs.update(d)
2552 dirs.update(d)
2553 files.update(dirs)
2553 files.update(dirs)
2554 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2554 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2555 ui.write('\n')
2555 ui.write('\n')
2556
2556
2557 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2557 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2558 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2558 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2559 '''access the pushkey key/value protocol
2559 '''access the pushkey key/value protocol
2560
2560
2561 With two args, list the keys in the given namespace.
2561 With two args, list the keys in the given namespace.
2562
2562
2563 With five args, set a key to new if it currently is set to old.
2563 With five args, set a key to new if it currently is set to old.
2564 Reports success or failure.
2564 Reports success or failure.
2565 '''
2565 '''
2566
2566
2567 target = hg.peer(ui, {}, repopath)
2567 target = hg.peer(ui, {}, repopath)
2568 if keyinfo:
2568 if keyinfo:
2569 key, old, new = keyinfo
2569 key, old, new = keyinfo
2570 r = target.pushkey(namespace, key, old, new)
2570 r = target.pushkey(namespace, key, old, new)
2571 ui.status(str(r) + '\n')
2571 ui.status(str(r) + '\n')
2572 return not r
2572 return not r
2573 else:
2573 else:
2574 for k, v in sorted(target.listkeys(namespace).iteritems()):
2574 for k, v in sorted(target.listkeys(namespace).iteritems()):
2575 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2575 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2576 v.encode('string-escape')))
2576 v.encode('string-escape')))
2577
2577
2578 @command('debugpvec', [], _('A B'))
2578 @command('debugpvec', [], _('A B'))
2579 def debugpvec(ui, repo, a, b=None):
2579 def debugpvec(ui, repo, a, b=None):
2580 ca = scmutil.revsingle(repo, a)
2580 ca = scmutil.revsingle(repo, a)
2581 cb = scmutil.revsingle(repo, b)
2581 cb = scmutil.revsingle(repo, b)
2582 pa = pvec.ctxpvec(ca)
2582 pa = pvec.ctxpvec(ca)
2583 pb = pvec.ctxpvec(cb)
2583 pb = pvec.ctxpvec(cb)
2584 if pa == pb:
2584 if pa == pb:
2585 rel = "="
2585 rel = "="
2586 elif pa > pb:
2586 elif pa > pb:
2587 rel = ">"
2587 rel = ">"
2588 elif pa < pb:
2588 elif pa < pb:
2589 rel = "<"
2589 rel = "<"
2590 elif pa | pb:
2590 elif pa | pb:
2591 rel = "|"
2591 rel = "|"
2592 ui.write(_("a: %s\n") % pa)
2592 ui.write(_("a: %s\n") % pa)
2593 ui.write(_("b: %s\n") % pb)
2593 ui.write(_("b: %s\n") % pb)
2594 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2594 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2595 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2595 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2596 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2596 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2597 pa.distance(pb), rel))
2597 pa.distance(pb), rel))
2598
2598
2599 @command('debugrebuilddirstate|debugrebuildstate',
2599 @command('debugrebuilddirstate|debugrebuildstate',
2600 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2600 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2601 _('[-r REV]'))
2601 _('[-r REV]'))
2602 def debugrebuilddirstate(ui, repo, rev):
2602 def debugrebuilddirstate(ui, repo, rev):
2603 """rebuild the dirstate as it would look like for the given revision
2603 """rebuild the dirstate as it would look like for the given revision
2604
2604
2605 If no revision is specified the first current parent will be used.
2605 If no revision is specified the first current parent will be used.
2606
2606
2607 The dirstate will be set to the files of the given revision.
2607 The dirstate will be set to the files of the given revision.
2608 The actual working directory content or existing dirstate
2608 The actual working directory content or existing dirstate
2609 information such as adds or removes is not considered.
2609 information such as adds or removes is not considered.
2610
2610
2611 One use of this command is to make the next :hg:`status` invocation
2611 One use of this command is to make the next :hg:`status` invocation
2612 check the actual file content.
2612 check the actual file content.
2613 """
2613 """
2614 ctx = scmutil.revsingle(repo, rev)
2614 ctx = scmutil.revsingle(repo, rev)
2615 wlock = repo.wlock()
2615 wlock = repo.wlock()
2616 try:
2616 try:
2617 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2617 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2618 finally:
2618 finally:
2619 wlock.release()
2619 wlock.release()
2620
2620
2621 @command('debugrename',
2621 @command('debugrename',
2622 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2622 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2623 _('[-r REV] FILE'))
2623 _('[-r REV] FILE'))
2624 def debugrename(ui, repo, file1, *pats, **opts):
2624 def debugrename(ui, repo, file1, *pats, **opts):
2625 """dump rename information"""
2625 """dump rename information"""
2626
2626
2627 ctx = scmutil.revsingle(repo, opts.get('rev'))
2627 ctx = scmutil.revsingle(repo, opts.get('rev'))
2628 m = scmutil.match(ctx, (file1,) + pats, opts)
2628 m = scmutil.match(ctx, (file1,) + pats, opts)
2629 for abs in ctx.walk(m):
2629 for abs in ctx.walk(m):
2630 fctx = ctx[abs]
2630 fctx = ctx[abs]
2631 o = fctx.filelog().renamed(fctx.filenode())
2631 o = fctx.filelog().renamed(fctx.filenode())
2632 rel = m.rel(abs)
2632 rel = m.rel(abs)
2633 if o:
2633 if o:
2634 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2634 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2635 else:
2635 else:
2636 ui.write(_("%s not renamed\n") % rel)
2636 ui.write(_("%s not renamed\n") % rel)
2637
2637
2638 @command('debugrevlog',
2638 @command('debugrevlog',
2639 [('c', 'changelog', False, _('open changelog')),
2639 [('c', 'changelog', False, _('open changelog')),
2640 ('m', 'manifest', False, _('open manifest')),
2640 ('m', 'manifest', False, _('open manifest')),
2641 ('d', 'dump', False, _('dump index data'))],
2641 ('d', 'dump', False, _('dump index data'))],
2642 _('-c|-m|FILE'),
2642 _('-c|-m|FILE'),
2643 optionalrepo=True)
2643 optionalrepo=True)
2644 def debugrevlog(ui, repo, file_=None, **opts):
2644 def debugrevlog(ui, repo, file_=None, **opts):
2645 """show data and statistics about a revlog"""
2645 """show data and statistics about a revlog"""
2646 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2646 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2647
2647
2648 if opts.get("dump"):
2648 if opts.get("dump"):
2649 numrevs = len(r)
2649 numrevs = len(r)
2650 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2650 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2651 " rawsize totalsize compression heads chainlen\n")
2651 " rawsize totalsize compression heads chainlen\n")
2652 ts = 0
2652 ts = 0
2653 heads = set()
2653 heads = set()
2654
2654
2655 for rev in xrange(numrevs):
2655 for rev in xrange(numrevs):
2656 dbase = r.deltaparent(rev)
2656 dbase = r.deltaparent(rev)
2657 if dbase == -1:
2657 if dbase == -1:
2658 dbase = rev
2658 dbase = rev
2659 cbase = r.chainbase(rev)
2659 cbase = r.chainbase(rev)
2660 clen = r.chainlen(rev)
2660 clen = r.chainlen(rev)
2661 p1, p2 = r.parentrevs(rev)
2661 p1, p2 = r.parentrevs(rev)
2662 rs = r.rawsize(rev)
2662 rs = r.rawsize(rev)
2663 ts = ts + rs
2663 ts = ts + rs
2664 heads -= set(r.parentrevs(rev))
2664 heads -= set(r.parentrevs(rev))
2665 heads.add(rev)
2665 heads.add(rev)
2666 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2666 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2667 "%11d %5d %8d\n" %
2667 "%11d %5d %8d\n" %
2668 (rev, p1, p2, r.start(rev), r.end(rev),
2668 (rev, p1, p2, r.start(rev), r.end(rev),
2669 r.start(dbase), r.start(cbase),
2669 r.start(dbase), r.start(cbase),
2670 r.start(p1), r.start(p2),
2670 r.start(p1), r.start(p2),
2671 rs, ts, ts / r.end(rev), len(heads), clen))
2671 rs, ts, ts / r.end(rev), len(heads), clen))
2672 return 0
2672 return 0
2673
2673
2674 v = r.version
2674 v = r.version
2675 format = v & 0xFFFF
2675 format = v & 0xFFFF
2676 flags = []
2676 flags = []
2677 gdelta = False
2677 gdelta = False
2678 if v & revlog.REVLOGNGINLINEDATA:
2678 if v & revlog.REVLOGNGINLINEDATA:
2679 flags.append('inline')
2679 flags.append('inline')
2680 if v & revlog.REVLOGGENERALDELTA:
2680 if v & revlog.REVLOGGENERALDELTA:
2681 gdelta = True
2681 gdelta = True
2682 flags.append('generaldelta')
2682 flags.append('generaldelta')
2683 if not flags:
2683 if not flags:
2684 flags = ['(none)']
2684 flags = ['(none)']
2685
2685
2686 nummerges = 0
2686 nummerges = 0
2687 numfull = 0
2687 numfull = 0
2688 numprev = 0
2688 numprev = 0
2689 nump1 = 0
2689 nump1 = 0
2690 nump2 = 0
2690 nump2 = 0
2691 numother = 0
2691 numother = 0
2692 nump1prev = 0
2692 nump1prev = 0
2693 nump2prev = 0
2693 nump2prev = 0
2694 chainlengths = []
2694 chainlengths = []
2695
2695
2696 datasize = [None, 0, 0L]
2696 datasize = [None, 0, 0L]
2697 fullsize = [None, 0, 0L]
2697 fullsize = [None, 0, 0L]
2698 deltasize = [None, 0, 0L]
2698 deltasize = [None, 0, 0L]
2699
2699
2700 def addsize(size, l):
2700 def addsize(size, l):
2701 if l[0] is None or size < l[0]:
2701 if l[0] is None or size < l[0]:
2702 l[0] = size
2702 l[0] = size
2703 if size > l[1]:
2703 if size > l[1]:
2704 l[1] = size
2704 l[1] = size
2705 l[2] += size
2705 l[2] += size
2706
2706
2707 numrevs = len(r)
2707 numrevs = len(r)
2708 for rev in xrange(numrevs):
2708 for rev in xrange(numrevs):
2709 p1, p2 = r.parentrevs(rev)
2709 p1, p2 = r.parentrevs(rev)
2710 delta = r.deltaparent(rev)
2710 delta = r.deltaparent(rev)
2711 if format > 0:
2711 if format > 0:
2712 addsize(r.rawsize(rev), datasize)
2712 addsize(r.rawsize(rev), datasize)
2713 if p2 != nullrev:
2713 if p2 != nullrev:
2714 nummerges += 1
2714 nummerges += 1
2715 size = r.length(rev)
2715 size = r.length(rev)
2716 if delta == nullrev:
2716 if delta == nullrev:
2717 chainlengths.append(0)
2717 chainlengths.append(0)
2718 numfull += 1
2718 numfull += 1
2719 addsize(size, fullsize)
2719 addsize(size, fullsize)
2720 else:
2720 else:
2721 chainlengths.append(chainlengths[delta] + 1)
2721 chainlengths.append(chainlengths[delta] + 1)
2722 addsize(size, deltasize)
2722 addsize(size, deltasize)
2723 if delta == rev - 1:
2723 if delta == rev - 1:
2724 numprev += 1
2724 numprev += 1
2725 if delta == p1:
2725 if delta == p1:
2726 nump1prev += 1
2726 nump1prev += 1
2727 elif delta == p2:
2727 elif delta == p2:
2728 nump2prev += 1
2728 nump2prev += 1
2729 elif delta == p1:
2729 elif delta == p1:
2730 nump1 += 1
2730 nump1 += 1
2731 elif delta == p2:
2731 elif delta == p2:
2732 nump2 += 1
2732 nump2 += 1
2733 elif delta != nullrev:
2733 elif delta != nullrev:
2734 numother += 1
2734 numother += 1
2735
2735
2736 # Adjust size min value for empty cases
2736 # Adjust size min value for empty cases
2737 for size in (datasize, fullsize, deltasize):
2737 for size in (datasize, fullsize, deltasize):
2738 if size[0] is None:
2738 if size[0] is None:
2739 size[0] = 0
2739 size[0] = 0
2740
2740
2741 numdeltas = numrevs - numfull
2741 numdeltas = numrevs - numfull
2742 numoprev = numprev - nump1prev - nump2prev
2742 numoprev = numprev - nump1prev - nump2prev
2743 totalrawsize = datasize[2]
2743 totalrawsize = datasize[2]
2744 datasize[2] /= numrevs
2744 datasize[2] /= numrevs
2745 fulltotal = fullsize[2]
2745 fulltotal = fullsize[2]
2746 fullsize[2] /= numfull
2746 fullsize[2] /= numfull
2747 deltatotal = deltasize[2]
2747 deltatotal = deltasize[2]
2748 if numrevs - numfull > 0:
2748 if numrevs - numfull > 0:
2749 deltasize[2] /= numrevs - numfull
2749 deltasize[2] /= numrevs - numfull
2750 totalsize = fulltotal + deltatotal
2750 totalsize = fulltotal + deltatotal
2751 avgchainlen = sum(chainlengths) / numrevs
2751 avgchainlen = sum(chainlengths) / numrevs
2752 compratio = totalrawsize / totalsize
2752 compratio = totalrawsize / totalsize
2753
2753
2754 basedfmtstr = '%%%dd\n'
2754 basedfmtstr = '%%%dd\n'
2755 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2755 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2756
2756
2757 def dfmtstr(max):
2757 def dfmtstr(max):
2758 return basedfmtstr % len(str(max))
2758 return basedfmtstr % len(str(max))
2759 def pcfmtstr(max, padding=0):
2759 def pcfmtstr(max, padding=0):
2760 return basepcfmtstr % (len(str(max)), ' ' * padding)
2760 return basepcfmtstr % (len(str(max)), ' ' * padding)
2761
2761
2762 def pcfmt(value, total):
2762 def pcfmt(value, total):
2763 return (value, 100 * float(value) / total)
2763 return (value, 100 * float(value) / total)
2764
2764
2765 ui.write(('format : %d\n') % format)
2765 ui.write(('format : %d\n') % format)
2766 ui.write(('flags : %s\n') % ', '.join(flags))
2766 ui.write(('flags : %s\n') % ', '.join(flags))
2767
2767
2768 ui.write('\n')
2768 ui.write('\n')
2769 fmt = pcfmtstr(totalsize)
2769 fmt = pcfmtstr(totalsize)
2770 fmt2 = dfmtstr(totalsize)
2770 fmt2 = dfmtstr(totalsize)
2771 ui.write(('revisions : ') + fmt2 % numrevs)
2771 ui.write(('revisions : ') + fmt2 % numrevs)
2772 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2772 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2773 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2773 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2774 ui.write(('revisions : ') + fmt2 % numrevs)
2774 ui.write(('revisions : ') + fmt2 % numrevs)
2775 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2775 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2776 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2776 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2777 ui.write(('revision size : ') + fmt2 % totalsize)
2777 ui.write(('revision size : ') + fmt2 % totalsize)
2778 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2778 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2779 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2779 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2780
2780
2781 ui.write('\n')
2781 ui.write('\n')
2782 fmt = dfmtstr(max(avgchainlen, compratio))
2782 fmt = dfmtstr(max(avgchainlen, compratio))
2783 ui.write(('avg chain length : ') + fmt % avgchainlen)
2783 ui.write(('avg chain length : ') + fmt % avgchainlen)
2784 ui.write(('compression ratio : ') + fmt % compratio)
2784 ui.write(('compression ratio : ') + fmt % compratio)
2785
2785
2786 if format > 0:
2786 if format > 0:
2787 ui.write('\n')
2787 ui.write('\n')
2788 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2788 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2789 % tuple(datasize))
2789 % tuple(datasize))
2790 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2790 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2791 % tuple(fullsize))
2791 % tuple(fullsize))
2792 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2792 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2793 % tuple(deltasize))
2793 % tuple(deltasize))
2794
2794
2795 if numdeltas > 0:
2795 if numdeltas > 0:
2796 ui.write('\n')
2796 ui.write('\n')
2797 fmt = pcfmtstr(numdeltas)
2797 fmt = pcfmtstr(numdeltas)
2798 fmt2 = pcfmtstr(numdeltas, 4)
2798 fmt2 = pcfmtstr(numdeltas, 4)
2799 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2799 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2800 if numprev > 0:
2800 if numprev > 0:
2801 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2801 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2802 numprev))
2802 numprev))
2803 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2803 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2804 numprev))
2804 numprev))
2805 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2805 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2806 numprev))
2806 numprev))
2807 if gdelta:
2807 if gdelta:
2808 ui.write(('deltas against p1 : ')
2808 ui.write(('deltas against p1 : ')
2809 + fmt % pcfmt(nump1, numdeltas))
2809 + fmt % pcfmt(nump1, numdeltas))
2810 ui.write(('deltas against p2 : ')
2810 ui.write(('deltas against p2 : ')
2811 + fmt % pcfmt(nump2, numdeltas))
2811 + fmt % pcfmt(nump2, numdeltas))
2812 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2812 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2813 numdeltas))
2813 numdeltas))
2814
2814
2815 @command('debugrevspec',
2815 @command('debugrevspec',
2816 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2816 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2817 ('REVSPEC'))
2817 ('REVSPEC'))
2818 def debugrevspec(ui, repo, expr, **opts):
2818 def debugrevspec(ui, repo, expr, **opts):
2819 """parse and apply a revision specification
2819 """parse and apply a revision specification
2820
2820
2821 Use --verbose to print the parsed tree before and after aliases
2821 Use --verbose to print the parsed tree before and after aliases
2822 expansion.
2822 expansion.
2823 """
2823 """
2824 if ui.verbose:
2824 if ui.verbose:
2825 tree = revset.parse(expr)[0]
2825 tree = revset.parse(expr)[0]
2826 ui.note(revset.prettyformat(tree), "\n")
2826 ui.note(revset.prettyformat(tree), "\n")
2827 newtree = revset.findaliases(ui, tree)
2827 newtree = revset.findaliases(ui, tree)
2828 if newtree != tree:
2828 if newtree != tree:
2829 ui.note(revset.prettyformat(newtree), "\n")
2829 ui.note(revset.prettyformat(newtree), "\n")
2830 if opts["optimize"]:
2830 if opts["optimize"]:
2831 weight, optimizedtree = revset.optimize(newtree, True)
2831 weight, optimizedtree = revset.optimize(newtree, True)
2832 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2832 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2833 func = revset.match(ui, expr)
2833 func = revset.match(ui, expr)
2834 for c in func(repo, revset.spanset(repo)):
2834 for c in func(repo, revset.spanset(repo)):
2835 ui.write("%s\n" % c)
2835 ui.write("%s\n" % c)
2836
2836
2837 @command('debugsetparents', [], _('REV1 [REV2]'))
2837 @command('debugsetparents', [], _('REV1 [REV2]'))
2838 def debugsetparents(ui, repo, rev1, rev2=None):
2838 def debugsetparents(ui, repo, rev1, rev2=None):
2839 """manually set the parents of the current working directory
2839 """manually set the parents of the current working directory
2840
2840
2841 This is useful for writing repository conversion tools, but should
2841 This is useful for writing repository conversion tools, but should
2842 be used with care.
2842 be used with care.
2843
2843
2844 Returns 0 on success.
2844 Returns 0 on success.
2845 """
2845 """
2846
2846
2847 r1 = scmutil.revsingle(repo, rev1).node()
2847 r1 = scmutil.revsingle(repo, rev1).node()
2848 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2848 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2849
2849
2850 wlock = repo.wlock()
2850 wlock = repo.wlock()
2851 try:
2851 try:
2852 repo.dirstate.beginparentchange()
2852 repo.dirstate.beginparentchange()
2853 repo.setparents(r1, r2)
2853 repo.setparents(r1, r2)
2854 repo.dirstate.endparentchange()
2854 repo.dirstate.endparentchange()
2855 finally:
2855 finally:
2856 wlock.release()
2856 wlock.release()
2857
2857
2858 @command('debugdirstate|debugstate',
2858 @command('debugdirstate|debugstate',
2859 [('', 'nodates', None, _('do not display the saved mtime')),
2859 [('', 'nodates', None, _('do not display the saved mtime')),
2860 ('', 'datesort', None, _('sort by saved mtime'))],
2860 ('', 'datesort', None, _('sort by saved mtime'))],
2861 _('[OPTION]...'))
2861 _('[OPTION]...'))
2862 def debugstate(ui, repo, nodates=None, datesort=None):
2862 def debugstate(ui, repo, nodates=None, datesort=None):
2863 """show the contents of the current dirstate"""
2863 """show the contents of the current dirstate"""
2864 timestr = ""
2864 timestr = ""
2865 showdate = not nodates
2865 showdate = not nodates
2866 if datesort:
2866 if datesort:
2867 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2867 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2868 else:
2868 else:
2869 keyfunc = None # sort by filename
2869 keyfunc = None # sort by filename
2870 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2870 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2871 if showdate:
2871 if showdate:
2872 if ent[3] == -1:
2872 if ent[3] == -1:
2873 # Pad or slice to locale representation
2873 # Pad or slice to locale representation
2874 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2874 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2875 time.localtime(0)))
2875 time.localtime(0)))
2876 timestr = 'unset'
2876 timestr = 'unset'
2877 timestr = (timestr[:locale_len] +
2877 timestr = (timestr[:locale_len] +
2878 ' ' * (locale_len - len(timestr)))
2878 ' ' * (locale_len - len(timestr)))
2879 else:
2879 else:
2880 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2880 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2881 time.localtime(ent[3]))
2881 time.localtime(ent[3]))
2882 if ent[1] & 020000:
2882 if ent[1] & 020000:
2883 mode = 'lnk'
2883 mode = 'lnk'
2884 else:
2884 else:
2885 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2885 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2886 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2886 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2887 for f in repo.dirstate.copies():
2887 for f in repo.dirstate.copies():
2888 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2888 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2889
2889
2890 @command('debugsub',
2890 @command('debugsub',
2891 [('r', 'rev', '',
2891 [('r', 'rev', '',
2892 _('revision to check'), _('REV'))],
2892 _('revision to check'), _('REV'))],
2893 _('[-r REV] [REV]'))
2893 _('[-r REV] [REV]'))
2894 def debugsub(ui, repo, rev=None):
2894 def debugsub(ui, repo, rev=None):
2895 ctx = scmutil.revsingle(repo, rev, None)
2895 ctx = scmutil.revsingle(repo, rev, None)
2896 for k, v in sorted(ctx.substate.items()):
2896 for k, v in sorted(ctx.substate.items()):
2897 ui.write(('path %s\n') % k)
2897 ui.write(('path %s\n') % k)
2898 ui.write((' source %s\n') % v[0])
2898 ui.write((' source %s\n') % v[0])
2899 ui.write((' revision %s\n') % v[1])
2899 ui.write((' revision %s\n') % v[1])
2900
2900
2901 @command('debugsuccessorssets',
2901 @command('debugsuccessorssets',
2902 [],
2902 [],
2903 _('[REV]'))
2903 _('[REV]'))
2904 def debugsuccessorssets(ui, repo, *revs):
2904 def debugsuccessorssets(ui, repo, *revs):
2905 """show set of successors for revision
2905 """show set of successors for revision
2906
2906
2907 A successors set of changeset A is a consistent group of revisions that
2907 A successors set of changeset A is a consistent group of revisions that
2908 succeed A. It contains non-obsolete changesets only.
2908 succeed A. It contains non-obsolete changesets only.
2909
2909
2910 In most cases a changeset A has a single successors set containing a single
2910 In most cases a changeset A has a single successors set containing a single
2911 successor (changeset A replaced by A').
2911 successor (changeset A replaced by A').
2912
2912
2913 A changeset that is made obsolete with no successors are called "pruned".
2913 A changeset that is made obsolete with no successors are called "pruned".
2914 Such changesets have no successors sets at all.
2914 Such changesets have no successors sets at all.
2915
2915
2916 A changeset that has been "split" will have a successors set containing
2916 A changeset that has been "split" will have a successors set containing
2917 more than one successor.
2917 more than one successor.
2918
2918
2919 A changeset that has been rewritten in multiple different ways is called
2919 A changeset that has been rewritten in multiple different ways is called
2920 "divergent". Such changesets have multiple successor sets (each of which
2920 "divergent". Such changesets have multiple successor sets (each of which
2921 may also be split, i.e. have multiple successors).
2921 may also be split, i.e. have multiple successors).
2922
2922
2923 Results are displayed as follows::
2923 Results are displayed as follows::
2924
2924
2925 <rev1>
2925 <rev1>
2926 <successors-1A>
2926 <successors-1A>
2927 <rev2>
2927 <rev2>
2928 <successors-2A>
2928 <successors-2A>
2929 <successors-2B1> <successors-2B2> <successors-2B3>
2929 <successors-2B1> <successors-2B2> <successors-2B3>
2930
2930
2931 Here rev2 has two possible (i.e. divergent) successors sets. The first
2931 Here rev2 has two possible (i.e. divergent) successors sets. The first
2932 holds one element, whereas the second holds three (i.e. the changeset has
2932 holds one element, whereas the second holds three (i.e. the changeset has
2933 been split).
2933 been split).
2934 """
2934 """
2935 # passed to successorssets caching computation from one call to another
2935 # passed to successorssets caching computation from one call to another
2936 cache = {}
2936 cache = {}
2937 ctx2str = str
2937 ctx2str = str
2938 node2str = short
2938 node2str = short
2939 if ui.debug():
2939 if ui.debug():
2940 def ctx2str(ctx):
2940 def ctx2str(ctx):
2941 return ctx.hex()
2941 return ctx.hex()
2942 node2str = hex
2942 node2str = hex
2943 for rev in scmutil.revrange(repo, revs):
2943 for rev in scmutil.revrange(repo, revs):
2944 ctx = repo[rev]
2944 ctx = repo[rev]
2945 ui.write('%s\n'% ctx2str(ctx))
2945 ui.write('%s\n'% ctx2str(ctx))
2946 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2946 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2947 if succsset:
2947 if succsset:
2948 ui.write(' ')
2948 ui.write(' ')
2949 ui.write(node2str(succsset[0]))
2949 ui.write(node2str(succsset[0]))
2950 for node in succsset[1:]:
2950 for node in succsset[1:]:
2951 ui.write(' ')
2951 ui.write(' ')
2952 ui.write(node2str(node))
2952 ui.write(node2str(node))
2953 ui.write('\n')
2953 ui.write('\n')
2954
2954
2955 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2955 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2956 def debugwalk(ui, repo, *pats, **opts):
2956 def debugwalk(ui, repo, *pats, **opts):
2957 """show how files match on given patterns"""
2957 """show how files match on given patterns"""
2958 m = scmutil.match(repo[None], pats, opts)
2958 m = scmutil.match(repo[None], pats, opts)
2959 items = list(repo.walk(m))
2959 items = list(repo.walk(m))
2960 if not items:
2960 if not items:
2961 return
2961 return
2962 f = lambda fn: fn
2962 f = lambda fn: fn
2963 if ui.configbool('ui', 'slash') and os.sep != '/':
2963 if ui.configbool('ui', 'slash') and os.sep != '/':
2964 f = lambda fn: util.normpath(fn)
2964 f = lambda fn: util.normpath(fn)
2965 fmt = 'f %%-%ds %%-%ds %%s' % (
2965 fmt = 'f %%-%ds %%-%ds %%s' % (
2966 max([len(abs) for abs in items]),
2966 max([len(abs) for abs in items]),
2967 max([len(m.rel(abs)) for abs in items]))
2967 max([len(m.rel(abs)) for abs in items]))
2968 for abs in items:
2968 for abs in items:
2969 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2969 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2970 ui.write("%s\n" % line.rstrip())
2970 ui.write("%s\n" % line.rstrip())
2971
2971
2972 @command('debugwireargs',
2972 @command('debugwireargs',
2973 [('', 'three', '', 'three'),
2973 [('', 'three', '', 'three'),
2974 ('', 'four', '', 'four'),
2974 ('', 'four', '', 'four'),
2975 ('', 'five', '', 'five'),
2975 ('', 'five', '', 'five'),
2976 ] + remoteopts,
2976 ] + remoteopts,
2977 _('REPO [OPTIONS]... [ONE [TWO]]'),
2977 _('REPO [OPTIONS]... [ONE [TWO]]'),
2978 norepo=True)
2978 norepo=True)
2979 def debugwireargs(ui, repopath, *vals, **opts):
2979 def debugwireargs(ui, repopath, *vals, **opts):
2980 repo = hg.peer(ui, opts, repopath)
2980 repo = hg.peer(ui, opts, repopath)
2981 for opt in remoteopts:
2981 for opt in remoteopts:
2982 del opts[opt[1]]
2982 del opts[opt[1]]
2983 args = {}
2983 args = {}
2984 for k, v in opts.iteritems():
2984 for k, v in opts.iteritems():
2985 if v:
2985 if v:
2986 args[k] = v
2986 args[k] = v
2987 # run twice to check that we don't mess up the stream for the next command
2987 # run twice to check that we don't mess up the stream for the next command
2988 res1 = repo.debugwireargs(*vals, **args)
2988 res1 = repo.debugwireargs(*vals, **args)
2989 res2 = repo.debugwireargs(*vals, **args)
2989 res2 = repo.debugwireargs(*vals, **args)
2990 ui.write("%s\n" % res1)
2990 ui.write("%s\n" % res1)
2991 if res1 != res2:
2991 if res1 != res2:
2992 ui.warn("%s\n" % res2)
2992 ui.warn("%s\n" % res2)
2993
2993
2994 @command('^diff',
2994 @command('^diff',
2995 [('r', 'rev', [], _('revision'), _('REV')),
2995 [('r', 'rev', [], _('revision'), _('REV')),
2996 ('c', 'change', '', _('change made by revision'), _('REV'))
2996 ('c', 'change', '', _('change made by revision'), _('REV'))
2997 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2997 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2998 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2998 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2999 inferrepo=True)
2999 inferrepo=True)
3000 def diff(ui, repo, *pats, **opts):
3000 def diff(ui, repo, *pats, **opts):
3001 """diff repository (or selected files)
3001 """diff repository (or selected files)
3002
3002
3003 Show differences between revisions for the specified files.
3003 Show differences between revisions for the specified files.
3004
3004
3005 Differences between files are shown using the unified diff format.
3005 Differences between files are shown using the unified diff format.
3006
3006
3007 .. note::
3007 .. note::
3008
3008
3009 diff may generate unexpected results for merges, as it will
3009 diff may generate unexpected results for merges, as it will
3010 default to comparing against the working directory's first
3010 default to comparing against the working directory's first
3011 parent changeset if no revisions are specified.
3011 parent changeset if no revisions are specified.
3012
3012
3013 When two revision arguments are given, then changes are shown
3013 When two revision arguments are given, then changes are shown
3014 between those revisions. If only one revision is specified then
3014 between those revisions. If only one revision is specified then
3015 that revision is compared to the working directory, and, when no
3015 that revision is compared to the working directory, and, when no
3016 revisions are specified, the working directory files are compared
3016 revisions are specified, the working directory files are compared
3017 to its parent.
3017 to its parent.
3018
3018
3019 Alternatively you can specify -c/--change with a revision to see
3019 Alternatively you can specify -c/--change with a revision to see
3020 the changes in that changeset relative to its first parent.
3020 the changes in that changeset relative to its first parent.
3021
3021
3022 Without the -a/--text option, diff will avoid generating diffs of
3022 Without the -a/--text option, diff will avoid generating diffs of
3023 files it detects as binary. With -a, diff will generate a diff
3023 files it detects as binary. With -a, diff will generate a diff
3024 anyway, probably with undesirable results.
3024 anyway, probably with undesirable results.
3025
3025
3026 Use the -g/--git option to generate diffs in the git extended diff
3026 Use the -g/--git option to generate diffs in the git extended diff
3027 format. For more information, read :hg:`help diffs`.
3027 format. For more information, read :hg:`help diffs`.
3028
3028
3029 .. container:: verbose
3029 .. container:: verbose
3030
3030
3031 Examples:
3031 Examples:
3032
3032
3033 - compare a file in the current working directory to its parent::
3033 - compare a file in the current working directory to its parent::
3034
3034
3035 hg diff foo.c
3035 hg diff foo.c
3036
3036
3037 - compare two historical versions of a directory, with rename info::
3037 - compare two historical versions of a directory, with rename info::
3038
3038
3039 hg diff --git -r 1.0:1.2 lib/
3039 hg diff --git -r 1.0:1.2 lib/
3040
3040
3041 - get change stats relative to the last change on some date::
3041 - get change stats relative to the last change on some date::
3042
3042
3043 hg diff --stat -r "date('may 2')"
3043 hg diff --stat -r "date('may 2')"
3044
3044
3045 - diff all newly-added files that contain a keyword::
3045 - diff all newly-added files that contain a keyword::
3046
3046
3047 hg diff "set:added() and grep(GNU)"
3047 hg diff "set:added() and grep(GNU)"
3048
3048
3049 - compare a revision and its parents::
3049 - compare a revision and its parents::
3050
3050
3051 hg diff -c 9353 # compare against first parent
3051 hg diff -c 9353 # compare against first parent
3052 hg diff -r 9353^:9353 # same using revset syntax
3052 hg diff -r 9353^:9353 # same using revset syntax
3053 hg diff -r 9353^2:9353 # compare against the second parent
3053 hg diff -r 9353^2:9353 # compare against the second parent
3054
3054
3055 Returns 0 on success.
3055 Returns 0 on success.
3056 """
3056 """
3057
3057
3058 revs = opts.get('rev')
3058 revs = opts.get('rev')
3059 change = opts.get('change')
3059 change = opts.get('change')
3060 stat = opts.get('stat')
3060 stat = opts.get('stat')
3061 reverse = opts.get('reverse')
3061 reverse = opts.get('reverse')
3062
3062
3063 if revs and change:
3063 if revs and change:
3064 msg = _('cannot specify --rev and --change at the same time')
3064 msg = _('cannot specify --rev and --change at the same time')
3065 raise util.Abort(msg)
3065 raise util.Abort(msg)
3066 elif change:
3066 elif change:
3067 node2 = scmutil.revsingle(repo, change, None).node()
3067 node2 = scmutil.revsingle(repo, change, None).node()
3068 node1 = repo[node2].p1().node()
3068 node1 = repo[node2].p1().node()
3069 else:
3069 else:
3070 node1, node2 = scmutil.revpair(repo, revs)
3070 node1, node2 = scmutil.revpair(repo, revs)
3071
3071
3072 if reverse:
3072 if reverse:
3073 node1, node2 = node2, node1
3073 node1, node2 = node2, node1
3074
3074
3075 diffopts = patch.diffopts(ui, opts)
3075 diffopts = patch.diffopts(ui, opts)
3076 m = scmutil.match(repo[node2], pats, opts)
3076 m = scmutil.match(repo[node2], pats, opts)
3077 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3077 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3078 listsubrepos=opts.get('subrepos'))
3078 listsubrepos=opts.get('subrepos'))
3079
3079
3080 @command('^export',
3080 @command('^export',
3081 [('o', 'output', '',
3081 [('o', 'output', '',
3082 _('print output to file with formatted name'), _('FORMAT')),
3082 _('print output to file with formatted name'), _('FORMAT')),
3083 ('', 'switch-parent', None, _('diff against the second parent')),
3083 ('', 'switch-parent', None, _('diff against the second parent')),
3084 ('r', 'rev', [], _('revisions to export'), _('REV')),
3084 ('r', 'rev', [], _('revisions to export'), _('REV')),
3085 ] + diffopts,
3085 ] + diffopts,
3086 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3086 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3087 def export(ui, repo, *changesets, **opts):
3087 def export(ui, repo, *changesets, **opts):
3088 """dump the header and diffs for one or more changesets
3088 """dump the header and diffs for one or more changesets
3089
3089
3090 Print the changeset header and diffs for one or more revisions.
3090 Print the changeset header and diffs for one or more revisions.
3091 If no revision is given, the parent of the working directory is used.
3091 If no revision is given, the parent of the working directory is used.
3092
3092
3093 The information shown in the changeset header is: author, date,
3093 The information shown in the changeset header is: author, date,
3094 branch name (if non-default), changeset hash, parent(s) and commit
3094 branch name (if non-default), changeset hash, parent(s) and commit
3095 comment.
3095 comment.
3096
3096
3097 .. note::
3097 .. note::
3098
3098
3099 export may generate unexpected diff output for merge
3099 export may generate unexpected diff output for merge
3100 changesets, as it will compare the merge changeset against its
3100 changesets, as it will compare the merge changeset against its
3101 first parent only.
3101 first parent only.
3102
3102
3103 Output may be to a file, in which case the name of the file is
3103 Output may be to a file, in which case the name of the file is
3104 given using a format string. The formatting rules are as follows:
3104 given using a format string. The formatting rules are as follows:
3105
3105
3106 :``%%``: literal "%" character
3106 :``%%``: literal "%" character
3107 :``%H``: changeset hash (40 hexadecimal digits)
3107 :``%H``: changeset hash (40 hexadecimal digits)
3108 :``%N``: number of patches being generated
3108 :``%N``: number of patches being generated
3109 :``%R``: changeset revision number
3109 :``%R``: changeset revision number
3110 :``%b``: basename of the exporting repository
3110 :``%b``: basename of the exporting repository
3111 :``%h``: short-form changeset hash (12 hexadecimal digits)
3111 :``%h``: short-form changeset hash (12 hexadecimal digits)
3112 :``%m``: first line of the commit message (only alphanumeric characters)
3112 :``%m``: first line of the commit message (only alphanumeric characters)
3113 :``%n``: zero-padded sequence number, starting at 1
3113 :``%n``: zero-padded sequence number, starting at 1
3114 :``%r``: zero-padded changeset revision number
3114 :``%r``: zero-padded changeset revision number
3115
3115
3116 Without the -a/--text option, export will avoid generating diffs
3116 Without the -a/--text option, export will avoid generating diffs
3117 of files it detects as binary. With -a, export will generate a
3117 of files it detects as binary. With -a, export will generate a
3118 diff anyway, probably with undesirable results.
3118 diff anyway, probably with undesirable results.
3119
3119
3120 Use the -g/--git option to generate diffs in the git extended diff
3120 Use the -g/--git option to generate diffs in the git extended diff
3121 format. See :hg:`help diffs` for more information.
3121 format. See :hg:`help diffs` for more information.
3122
3122
3123 With the --switch-parent option, the diff will be against the
3123 With the --switch-parent option, the diff will be against the
3124 second parent. It can be useful to review a merge.
3124 second parent. It can be useful to review a merge.
3125
3125
3126 .. container:: verbose
3126 .. container:: verbose
3127
3127
3128 Examples:
3128 Examples:
3129
3129
3130 - use export and import to transplant a bugfix to the current
3130 - use export and import to transplant a bugfix to the current
3131 branch::
3131 branch::
3132
3132
3133 hg export -r 9353 | hg import -
3133 hg export -r 9353 | hg import -
3134
3134
3135 - export all the changesets between two revisions to a file with
3135 - export all the changesets between two revisions to a file with
3136 rename information::
3136 rename information::
3137
3137
3138 hg export --git -r 123:150 > changes.txt
3138 hg export --git -r 123:150 > changes.txt
3139
3139
3140 - split outgoing changes into a series of patches with
3140 - split outgoing changes into a series of patches with
3141 descriptive names::
3141 descriptive names::
3142
3142
3143 hg export -r "outgoing()" -o "%n-%m.patch"
3143 hg export -r "outgoing()" -o "%n-%m.patch"
3144
3144
3145 Returns 0 on success.
3145 Returns 0 on success.
3146 """
3146 """
3147 changesets += tuple(opts.get('rev', []))
3147 changesets += tuple(opts.get('rev', []))
3148 if not changesets:
3148 if not changesets:
3149 changesets = ['.']
3149 changesets = ['.']
3150 revs = scmutil.revrange(repo, changesets)
3150 revs = scmutil.revrange(repo, changesets)
3151 if not revs:
3151 if not revs:
3152 raise util.Abort(_("export requires at least one changeset"))
3152 raise util.Abort(_("export requires at least one changeset"))
3153 if len(revs) > 1:
3153 if len(revs) > 1:
3154 ui.note(_('exporting patches:\n'))
3154 ui.note(_('exporting patches:\n'))
3155 else:
3155 else:
3156 ui.note(_('exporting patch:\n'))
3156 ui.note(_('exporting patch:\n'))
3157 cmdutil.export(repo, revs, template=opts.get('output'),
3157 cmdutil.export(repo, revs, template=opts.get('output'),
3158 switch_parent=opts.get('switch_parent'),
3158 switch_parent=opts.get('switch_parent'),
3159 opts=patch.diffopts(ui, opts))
3159 opts=patch.diffopts(ui, opts))
3160
3160
3161 @command('files',
3161 @command('files',
3162 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3162 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3163 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3163 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3164 ] + walkopts + formatteropts,
3164 ] + walkopts + formatteropts,
3165 _('[OPTION]... [PATTERN]...'))
3165 _('[OPTION]... [PATTERN]...'))
3166 def files(ui, repo, *pats, **opts):
3166 def files(ui, repo, *pats, **opts):
3167 """list tracked files
3167 """list tracked files
3168
3168
3169 Print files under Mercurial control in the working directory or
3169 Print files under Mercurial control in the working directory or
3170 specified revision whose names match the given patterns (excluding
3170 specified revision whose names match the given patterns (excluding
3171 removed files).
3171 removed files).
3172
3172
3173 If no patterns are given to match, this command prints the names
3173 If no patterns are given to match, this command prints the names
3174 of all files under Mercurial control in the working copy.
3174 of all files under Mercurial control in the working copy.
3175
3175
3176 .. container:: verbose
3176 .. container:: verbose
3177
3177
3178 Examples:
3178 Examples:
3179
3179
3180 - list all files under the current directory::
3180 - list all files under the current directory::
3181
3181
3182 hg files .
3182 hg files .
3183
3183
3184 - shows sizes and flags for current revision::
3184 - shows sizes and flags for current revision::
3185
3185
3186 hg files -vr .
3186 hg files -vr .
3187
3187
3188 - list all files named README::
3188 - list all files named README::
3189
3189
3190 hg files -I "**/README"
3190 hg files -I "**/README"
3191
3191
3192 - list all binary files::
3192 - list all binary files::
3193
3193
3194 hg files "set:binary()"
3194 hg files "set:binary()"
3195
3195
3196 - find files containing a regular expression::
3196 - find files containing a regular expression::
3197
3197
3198 hg files "set:grep('bob')"
3198 hg files "set:grep('bob')"
3199
3199
3200 - search tracked file contents with xargs and grep::
3200 - search tracked file contents with xargs and grep::
3201
3201
3202 hg files -0 | xargs -0 grep foo
3202 hg files -0 | xargs -0 grep foo
3203
3203
3204 See :hg:`help pattern` and :hg:`help filesets` for more information
3204 See :hg:`help pattern` and :hg:`help filesets` for more information
3205 on specifying file patterns.
3205 on specifying file patterns.
3206
3206
3207 Returns 0 if a match is found, 1 otherwise.
3207 Returns 0 if a match is found, 1 otherwise.
3208
3208
3209 """
3209 """
3210 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3210 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3211 rev = ctx.rev()
3211 rev = ctx.rev()
3212 ret = 1
3212 ret = 1
3213
3213
3214 end = '\n'
3214 end = '\n'
3215 if opts.get('print0'):
3215 if opts.get('print0'):
3216 end = '\0'
3216 end = '\0'
3217 fm = ui.formatter('files', opts)
3217 fm = ui.formatter('files', opts)
3218 fmt = '%s' + end
3218 fmt = '%s' + end
3219
3219
3220 m = scmutil.match(ctx, pats, opts)
3220 m = scmutil.match(ctx, pats, opts)
3221 ds = repo.dirstate
3221 ds = repo.dirstate
3222 for f in ctx.matches(m):
3222 for f in ctx.matches(m):
3223 if rev is None and ds[f] == 'r':
3223 if rev is None and ds[f] == 'r':
3224 continue
3224 continue
3225 fm.startitem()
3225 fm.startitem()
3226 if ui.verbose:
3226 if ui.verbose:
3227 fc = ctx[f]
3227 fc = ctx[f]
3228 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
3228 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
3229 fm.data(abspath=f)
3229 fm.data(abspath=f)
3230 fm.write('path', fmt, m.rel(f))
3230 fm.write('path', fmt, m.rel(f))
3231 ret = 0
3231 ret = 0
3232
3232
3233 fm.end()
3233 fm.end()
3234
3234
3235 return ret
3235 return ret
3236
3236
3237 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3237 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3238 def forget(ui, repo, *pats, **opts):
3238 def forget(ui, repo, *pats, **opts):
3239 """forget the specified files on the next commit
3239 """forget the specified files on the next commit
3240
3240
3241 Mark the specified files so they will no longer be tracked
3241 Mark the specified files so they will no longer be tracked
3242 after the next commit.
3242 after the next commit.
3243
3243
3244 This only removes files from the current branch, not from the
3244 This only removes files from the current branch, not from the
3245 entire project history, and it does not delete them from the
3245 entire project history, and it does not delete them from the
3246 working directory.
3246 working directory.
3247
3247
3248 To undo a forget before the next commit, see :hg:`add`.
3248 To undo a forget before the next commit, see :hg:`add`.
3249
3249
3250 .. container:: verbose
3250 .. container:: verbose
3251
3251
3252 Examples:
3252 Examples:
3253
3253
3254 - forget newly-added binary files::
3254 - forget newly-added binary files::
3255
3255
3256 hg forget "set:added() and binary()"
3256 hg forget "set:added() and binary()"
3257
3257
3258 - forget files that would be excluded by .hgignore::
3258 - forget files that would be excluded by .hgignore::
3259
3259
3260 hg forget "set:hgignore()"
3260 hg forget "set:hgignore()"
3261
3261
3262 Returns 0 on success.
3262 Returns 0 on success.
3263 """
3263 """
3264
3264
3265 if not pats:
3265 if not pats:
3266 raise util.Abort(_('no files specified'))
3266 raise util.Abort(_('no files specified'))
3267
3267
3268 m = scmutil.match(repo[None], pats, opts)
3268 m = scmutil.match(repo[None], pats, opts)
3269 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3269 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3270 return rejected and 1 or 0
3270 return rejected and 1 or 0
3271
3271
3272 @command(
3272 @command(
3273 'graft',
3273 'graft',
3274 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3274 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3275 ('c', 'continue', False, _('resume interrupted graft')),
3275 ('c', 'continue', False, _('resume interrupted graft')),
3276 ('e', 'edit', False, _('invoke editor on commit messages')),
3276 ('e', 'edit', False, _('invoke editor on commit messages')),
3277 ('', 'log', None, _('append graft info to log message')),
3277 ('', 'log', None, _('append graft info to log message')),
3278 ('f', 'force', False, _('force graft')),
3278 ('f', 'force', False, _('force graft')),
3279 ('D', 'currentdate', False,
3279 ('D', 'currentdate', False,
3280 _('record the current date as commit date')),
3280 _('record the current date as commit date')),
3281 ('U', 'currentuser', False,
3281 ('U', 'currentuser', False,
3282 _('record the current user as committer'), _('DATE'))]
3282 _('record the current user as committer'), _('DATE'))]
3283 + commitopts2 + mergetoolopts + dryrunopts,
3283 + commitopts2 + mergetoolopts + dryrunopts,
3284 _('[OPTION]... [-r] REV...'))
3284 _('[OPTION]... [-r] REV...'))
3285 def graft(ui, repo, *revs, **opts):
3285 def graft(ui, repo, *revs, **opts):
3286 '''copy changes from other branches onto the current branch
3286 '''copy changes from other branches onto the current branch
3287
3287
3288 This command uses Mercurial's merge logic to copy individual
3288 This command uses Mercurial's merge logic to copy individual
3289 changes from other branches without merging branches in the
3289 changes from other branches without merging branches in the
3290 history graph. This is sometimes known as 'backporting' or
3290 history graph. This is sometimes known as 'backporting' or
3291 'cherry-picking'. By default, graft will copy user, date, and
3291 'cherry-picking'. By default, graft will copy user, date, and
3292 description from the source changesets.
3292 description from the source changesets.
3293
3293
3294 Changesets that are ancestors of the current revision, that have
3294 Changesets that are ancestors of the current revision, that have
3295 already been grafted, or that are merges will be skipped.
3295 already been grafted, or that are merges will be skipped.
3296
3296
3297 If --log is specified, log messages will have a comment appended
3297 If --log is specified, log messages will have a comment appended
3298 of the form::
3298 of the form::
3299
3299
3300 (grafted from CHANGESETHASH)
3300 (grafted from CHANGESETHASH)
3301
3301
3302 If --force is specified, revisions will be grafted even if they
3302 If --force is specified, revisions will be grafted even if they
3303 are already ancestors of or have been grafted to the destination.
3303 are already ancestors of or have been grafted to the destination.
3304 This is useful when the revisions have since been backed out.
3304 This is useful when the revisions have since been backed out.
3305
3305
3306 If a graft merge results in conflicts, the graft process is
3306 If a graft merge results in conflicts, the graft process is
3307 interrupted so that the current merge can be manually resolved.
3307 interrupted so that the current merge can be manually resolved.
3308 Once all conflicts are addressed, the graft process can be
3308 Once all conflicts are addressed, the graft process can be
3309 continued with the -c/--continue option.
3309 continued with the -c/--continue option.
3310
3310
3311 .. note::
3311 .. note::
3312
3312
3313 The -c/--continue option does not reapply earlier options, except
3313 The -c/--continue option does not reapply earlier options, except
3314 for --force.
3314 for --force.
3315
3315
3316 .. container:: verbose
3316 .. container:: verbose
3317
3317
3318 Examples:
3318 Examples:
3319
3319
3320 - copy a single change to the stable branch and edit its description::
3320 - copy a single change to the stable branch and edit its description::
3321
3321
3322 hg update stable
3322 hg update stable
3323 hg graft --edit 9393
3323 hg graft --edit 9393
3324
3324
3325 - graft a range of changesets with one exception, updating dates::
3325 - graft a range of changesets with one exception, updating dates::
3326
3326
3327 hg graft -D "2085::2093 and not 2091"
3327 hg graft -D "2085::2093 and not 2091"
3328
3328
3329 - continue a graft after resolving conflicts::
3329 - continue a graft after resolving conflicts::
3330
3330
3331 hg graft -c
3331 hg graft -c
3332
3332
3333 - show the source of a grafted changeset::
3333 - show the source of a grafted changeset::
3334
3334
3335 hg log --debug -r .
3335 hg log --debug -r .
3336
3336
3337 See :hg:`help revisions` and :hg:`help revsets` for more about
3337 See :hg:`help revisions` and :hg:`help revsets` for more about
3338 specifying revisions.
3338 specifying revisions.
3339
3339
3340 Returns 0 on successful completion.
3340 Returns 0 on successful completion.
3341 '''
3341 '''
3342
3342
3343 revs = list(revs)
3343 revs = list(revs)
3344 revs.extend(opts['rev'])
3344 revs.extend(opts['rev'])
3345
3345
3346 if not opts.get('user') and opts.get('currentuser'):
3346 if not opts.get('user') and opts.get('currentuser'):
3347 opts['user'] = ui.username()
3347 opts['user'] = ui.username()
3348 if not opts.get('date') and opts.get('currentdate'):
3348 if not opts.get('date') and opts.get('currentdate'):
3349 opts['date'] = "%d %d" % util.makedate()
3349 opts['date'] = "%d %d" % util.makedate()
3350
3350
3351 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3351 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3352
3352
3353 cont = False
3353 cont = False
3354 if opts['continue']:
3354 if opts['continue']:
3355 cont = True
3355 cont = True
3356 if revs:
3356 if revs:
3357 raise util.Abort(_("can't specify --continue and revisions"))
3357 raise util.Abort(_("can't specify --continue and revisions"))
3358 # read in unfinished revisions
3358 # read in unfinished revisions
3359 try:
3359 try:
3360 nodes = repo.opener.read('graftstate').splitlines()
3360 nodes = repo.opener.read('graftstate').splitlines()
3361 revs = [repo[node].rev() for node in nodes]
3361 revs = [repo[node].rev() for node in nodes]
3362 except IOError, inst:
3362 except IOError, inst:
3363 if inst.errno != errno.ENOENT:
3363 if inst.errno != errno.ENOENT:
3364 raise
3364 raise
3365 raise util.Abort(_("no graft state found, can't continue"))
3365 raise util.Abort(_("no graft state found, can't continue"))
3366 else:
3366 else:
3367 cmdutil.checkunfinished(repo)
3367 cmdutil.checkunfinished(repo)
3368 cmdutil.bailifchanged(repo)
3368 cmdutil.bailifchanged(repo)
3369 if not revs:
3369 if not revs:
3370 raise util.Abort(_('no revisions specified'))
3370 raise util.Abort(_('no revisions specified'))
3371 revs = scmutil.revrange(repo, revs)
3371 revs = scmutil.revrange(repo, revs)
3372
3372
3373 skipped = set()
3373 skipped = set()
3374 # check for merges
3374 # check for merges
3375 for rev in repo.revs('%ld and merge()', revs):
3375 for rev in repo.revs('%ld and merge()', revs):
3376 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3376 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3377 skipped.add(rev)
3377 skipped.add(rev)
3378 revs = [r for r in revs if r not in skipped]
3378 revs = [r for r in revs if r not in skipped]
3379 if not revs:
3379 if not revs:
3380 return -1
3380 return -1
3381
3381
3382 # Don't check in the --continue case, in effect retaining --force across
3382 # Don't check in the --continue case, in effect retaining --force across
3383 # --continues. That's because without --force, any revisions we decided to
3383 # --continues. That's because without --force, any revisions we decided to
3384 # skip would have been filtered out here, so they wouldn't have made their
3384 # skip would have been filtered out here, so they wouldn't have made their
3385 # way to the graftstate. With --force, any revisions we would have otherwise
3385 # way to the graftstate. With --force, any revisions we would have otherwise
3386 # skipped would not have been filtered out, and if they hadn't been applied
3386 # skipped would not have been filtered out, and if they hadn't been applied
3387 # already, they'd have been in the graftstate.
3387 # already, they'd have been in the graftstate.
3388 if not (cont or opts.get('force')):
3388 if not (cont or opts.get('force')):
3389 # check for ancestors of dest branch
3389 # check for ancestors of dest branch
3390 crev = repo['.'].rev()
3390 crev = repo['.'].rev()
3391 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3391 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3392 # Cannot use x.remove(y) on smart set, this has to be a list.
3392 # Cannot use x.remove(y) on smart set, this has to be a list.
3393 # XXX make this lazy in the future
3393 # XXX make this lazy in the future
3394 revs = list(revs)
3394 revs = list(revs)
3395 # don't mutate while iterating, create a copy
3395 # don't mutate while iterating, create a copy
3396 for rev in list(revs):
3396 for rev in list(revs):
3397 if rev in ancestors:
3397 if rev in ancestors:
3398 ui.warn(_('skipping ancestor revision %s\n') % rev)
3398 ui.warn(_('skipping ancestor revision %s\n') % rev)
3399 # XXX remove on list is slow
3399 # XXX remove on list is slow
3400 revs.remove(rev)
3400 revs.remove(rev)
3401 if not revs:
3401 if not revs:
3402 return -1
3402 return -1
3403
3403
3404 # analyze revs for earlier grafts
3404 # analyze revs for earlier grafts
3405 ids = {}
3405 ids = {}
3406 for ctx in repo.set("%ld", revs):
3406 for ctx in repo.set("%ld", revs):
3407 ids[ctx.hex()] = ctx.rev()
3407 ids[ctx.hex()] = ctx.rev()
3408 n = ctx.extra().get('source')
3408 n = ctx.extra().get('source')
3409 if n:
3409 if n:
3410 ids[n] = ctx.rev()
3410 ids[n] = ctx.rev()
3411
3411
3412 # check ancestors for earlier grafts
3412 # check ancestors for earlier grafts
3413 ui.debug('scanning for duplicate grafts\n')
3413 ui.debug('scanning for duplicate grafts\n')
3414
3414
3415 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3415 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3416 ctx = repo[rev]
3416 ctx = repo[rev]
3417 n = ctx.extra().get('source')
3417 n = ctx.extra().get('source')
3418 if n in ids:
3418 if n in ids:
3419 try:
3419 try:
3420 r = repo[n].rev()
3420 r = repo[n].rev()
3421 except error.RepoLookupError:
3421 except error.RepoLookupError:
3422 r = None
3422 r = None
3423 if r in revs:
3423 if r in revs:
3424 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3424 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3425 % (r, rev))
3425 % (r, rev))
3426 revs.remove(r)
3426 revs.remove(r)
3427 elif ids[n] in revs:
3427 elif ids[n] in revs:
3428 if r is None:
3428 if r is None:
3429 ui.warn(_('skipping already grafted revision %s '
3429 ui.warn(_('skipping already grafted revision %s '
3430 '(%s also has unknown origin %s)\n')
3430 '(%s also has unknown origin %s)\n')
3431 % (ids[n], rev, n))
3431 % (ids[n], rev, n))
3432 else:
3432 else:
3433 ui.warn(_('skipping already grafted revision %s '
3433 ui.warn(_('skipping already grafted revision %s '
3434 '(%s also has origin %d)\n')
3434 '(%s also has origin %d)\n')
3435 % (ids[n], rev, r))
3435 % (ids[n], rev, r))
3436 revs.remove(ids[n])
3436 revs.remove(ids[n])
3437 elif ctx.hex() in ids:
3437 elif ctx.hex() in ids:
3438 r = ids[ctx.hex()]
3438 r = ids[ctx.hex()]
3439 ui.warn(_('skipping already grafted revision %s '
3439 ui.warn(_('skipping already grafted revision %s '
3440 '(was grafted from %d)\n') % (r, rev))
3440 '(was grafted from %d)\n') % (r, rev))
3441 revs.remove(r)
3441 revs.remove(r)
3442 if not revs:
3442 if not revs:
3443 return -1
3443 return -1
3444
3444
3445 wlock = repo.wlock()
3445 wlock = repo.wlock()
3446 try:
3446 try:
3447 for pos, ctx in enumerate(repo.set("%ld", revs)):
3447 for pos, ctx in enumerate(repo.set("%ld", revs)):
3448
3448
3449 ui.status(_('grafting revision %s\n') % ctx.rev())
3449 ui.status(_('grafting revision %s\n') % ctx.rev())
3450 if opts.get('dry_run'):
3450 if opts.get('dry_run'):
3451 continue
3451 continue
3452
3452
3453 source = ctx.extra().get('source')
3453 source = ctx.extra().get('source')
3454 if not source:
3454 if not source:
3455 source = ctx.hex()
3455 source = ctx.hex()
3456 extra = {'source': source}
3456 extra = {'source': source}
3457 user = ctx.user()
3457 user = ctx.user()
3458 if opts.get('user'):
3458 if opts.get('user'):
3459 user = opts['user']
3459 user = opts['user']
3460 date = ctx.date()
3460 date = ctx.date()
3461 if opts.get('date'):
3461 if opts.get('date'):
3462 date = opts['date']
3462 date = opts['date']
3463 message = ctx.description()
3463 message = ctx.description()
3464 if opts.get('log'):
3464 if opts.get('log'):
3465 message += '\n(grafted from %s)' % ctx.hex()
3465 message += '\n(grafted from %s)' % ctx.hex()
3466
3466
3467 # we don't merge the first commit when continuing
3467 # we don't merge the first commit when continuing
3468 if not cont:
3468 if not cont:
3469 # perform the graft merge with p1(rev) as 'ancestor'
3469 # perform the graft merge with p1(rev) as 'ancestor'
3470 try:
3470 try:
3471 # ui.forcemerge is an internal variable, do not document
3471 # ui.forcemerge is an internal variable, do not document
3472 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3472 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3473 'graft')
3473 'graft')
3474 stats = mergemod.graft(repo, ctx, ctx.p1(),
3474 stats = mergemod.graft(repo, ctx, ctx.p1(),
3475 ['local', 'graft'])
3475 ['local', 'graft'])
3476 finally:
3476 finally:
3477 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3477 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3478 # report any conflicts
3478 # report any conflicts
3479 if stats and stats[3] > 0:
3479 if stats and stats[3] > 0:
3480 # write out state for --continue
3480 # write out state for --continue
3481 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3481 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3482 repo.opener.write('graftstate', ''.join(nodelines))
3482 repo.opener.write('graftstate', ''.join(nodelines))
3483 raise util.Abort(
3483 raise util.Abort(
3484 _("unresolved conflicts, can't continue"),
3484 _("unresolved conflicts, can't continue"),
3485 hint=_('use hg resolve and hg graft --continue'))
3485 hint=_('use hg resolve and hg graft --continue'))
3486 else:
3486 else:
3487 cont = False
3487 cont = False
3488
3488
3489 # commit
3489 # commit
3490 node = repo.commit(text=message, user=user,
3490 node = repo.commit(text=message, user=user,
3491 date=date, extra=extra, editor=editor)
3491 date=date, extra=extra, editor=editor)
3492 if node is None:
3492 if node is None:
3493 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3493 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3494 finally:
3494 finally:
3495 wlock.release()
3495 wlock.release()
3496
3496
3497 # remove state when we complete successfully
3497 # remove state when we complete successfully
3498 if not opts.get('dry_run'):
3498 if not opts.get('dry_run'):
3499 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3499 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3500
3500
3501 return 0
3501 return 0
3502
3502
3503 @command('grep',
3503 @command('grep',
3504 [('0', 'print0', None, _('end fields with NUL')),
3504 [('0', 'print0', None, _('end fields with NUL')),
3505 ('', 'all', None, _('print all revisions that match')),
3505 ('', 'all', None, _('print all revisions that match')),
3506 ('a', 'text', None, _('treat all files as text')),
3506 ('a', 'text', None, _('treat all files as text')),
3507 ('f', 'follow', None,
3507 ('f', 'follow', None,
3508 _('follow changeset history,'
3508 _('follow changeset history,'
3509 ' or file history across copies and renames')),
3509 ' or file history across copies and renames')),
3510 ('i', 'ignore-case', None, _('ignore case when matching')),
3510 ('i', 'ignore-case', None, _('ignore case when matching')),
3511 ('l', 'files-with-matches', None,
3511 ('l', 'files-with-matches', None,
3512 _('print only filenames and revisions that match')),
3512 _('print only filenames and revisions that match')),
3513 ('n', 'line-number', None, _('print matching line numbers')),
3513 ('n', 'line-number', None, _('print matching line numbers')),
3514 ('r', 'rev', [],
3514 ('r', 'rev', [],
3515 _('only search files changed within revision range'), _('REV')),
3515 _('only search files changed within revision range'), _('REV')),
3516 ('u', 'user', None, _('list the author (long with -v)')),
3516 ('u', 'user', None, _('list the author (long with -v)')),
3517 ('d', 'date', None, _('list the date (short with -q)')),
3517 ('d', 'date', None, _('list the date (short with -q)')),
3518 ] + walkopts,
3518 ] + walkopts,
3519 _('[OPTION]... PATTERN [FILE]...'),
3519 _('[OPTION]... PATTERN [FILE]...'),
3520 inferrepo=True)
3520 inferrepo=True)
3521 def grep(ui, repo, pattern, *pats, **opts):
3521 def grep(ui, repo, pattern, *pats, **opts):
3522 """search for a pattern in specified files and revisions
3522 """search for a pattern in specified files and revisions
3523
3523
3524 Search revisions of files for a regular expression.
3524 Search revisions of files for a regular expression.
3525
3525
3526 This command behaves differently than Unix grep. It only accepts
3526 This command behaves differently than Unix grep. It only accepts
3527 Python/Perl regexps. It searches repository history, not the
3527 Python/Perl regexps. It searches repository history, not the
3528 working directory. It always prints the revision number in which a
3528 working directory. It always prints the revision number in which a
3529 match appears.
3529 match appears.
3530
3530
3531 By default, grep only prints output for the first revision of a
3531 By default, grep only prints output for the first revision of a
3532 file in which it finds a match. To get it to print every revision
3532 file in which it finds a match. To get it to print every revision
3533 that contains a change in match status ("-" for a match that
3533 that contains a change in match status ("-" for a match that
3534 becomes a non-match, or "+" for a non-match that becomes a match),
3534 becomes a non-match, or "+" for a non-match that becomes a match),
3535 use the --all flag.
3535 use the --all flag.
3536
3536
3537 Returns 0 if a match is found, 1 otherwise.
3537 Returns 0 if a match is found, 1 otherwise.
3538 """
3538 """
3539 reflags = re.M
3539 reflags = re.M
3540 if opts.get('ignore_case'):
3540 if opts.get('ignore_case'):
3541 reflags |= re.I
3541 reflags |= re.I
3542 try:
3542 try:
3543 regexp = util.re.compile(pattern, reflags)
3543 regexp = util.re.compile(pattern, reflags)
3544 except re.error, inst:
3544 except re.error, inst:
3545 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3545 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3546 return 1
3546 return 1
3547 sep, eol = ':', '\n'
3547 sep, eol = ':', '\n'
3548 if opts.get('print0'):
3548 if opts.get('print0'):
3549 sep = eol = '\0'
3549 sep = eol = '\0'
3550
3550
3551 getfile = util.lrucachefunc(repo.file)
3551 getfile = util.lrucachefunc(repo.file)
3552
3552
3553 def matchlines(body):
3553 def matchlines(body):
3554 begin = 0
3554 begin = 0
3555 linenum = 0
3555 linenum = 0
3556 while begin < len(body):
3556 while begin < len(body):
3557 match = regexp.search(body, begin)
3557 match = regexp.search(body, begin)
3558 if not match:
3558 if not match:
3559 break
3559 break
3560 mstart, mend = match.span()
3560 mstart, mend = match.span()
3561 linenum += body.count('\n', begin, mstart) + 1
3561 linenum += body.count('\n', begin, mstart) + 1
3562 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3562 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3563 begin = body.find('\n', mend) + 1 or len(body) + 1
3563 begin = body.find('\n', mend) + 1 or len(body) + 1
3564 lend = begin - 1
3564 lend = begin - 1
3565 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3565 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3566
3566
3567 class linestate(object):
3567 class linestate(object):
3568 def __init__(self, line, linenum, colstart, colend):
3568 def __init__(self, line, linenum, colstart, colend):
3569 self.line = line
3569 self.line = line
3570 self.linenum = linenum
3570 self.linenum = linenum
3571 self.colstart = colstart
3571 self.colstart = colstart
3572 self.colend = colend
3572 self.colend = colend
3573
3573
3574 def __hash__(self):
3574 def __hash__(self):
3575 return hash((self.linenum, self.line))
3575 return hash((self.linenum, self.line))
3576
3576
3577 def __eq__(self, other):
3577 def __eq__(self, other):
3578 return self.line == other.line
3578 return self.line == other.line
3579
3579
3580 def __iter__(self):
3580 def __iter__(self):
3581 yield (self.line[:self.colstart], '')
3581 yield (self.line[:self.colstart], '')
3582 yield (self.line[self.colstart:self.colend], 'grep.match')
3582 yield (self.line[self.colstart:self.colend], 'grep.match')
3583 rest = self.line[self.colend:]
3583 rest = self.line[self.colend:]
3584 while rest != '':
3584 while rest != '':
3585 match = regexp.search(rest)
3585 match = regexp.search(rest)
3586 if not match:
3586 if not match:
3587 yield (rest, '')
3587 yield (rest, '')
3588 break
3588 break
3589 mstart, mend = match.span()
3589 mstart, mend = match.span()
3590 yield (rest[:mstart], '')
3590 yield (rest[:mstart], '')
3591 yield (rest[mstart:mend], 'grep.match')
3591 yield (rest[mstart:mend], 'grep.match')
3592 rest = rest[mend:]
3592 rest = rest[mend:]
3593
3593
3594 matches = {}
3594 matches = {}
3595 copies = {}
3595 copies = {}
3596 def grepbody(fn, rev, body):
3596 def grepbody(fn, rev, body):
3597 matches[rev].setdefault(fn, [])
3597 matches[rev].setdefault(fn, [])
3598 m = matches[rev][fn]
3598 m = matches[rev][fn]
3599 for lnum, cstart, cend, line in matchlines(body):
3599 for lnum, cstart, cend, line in matchlines(body):
3600 s = linestate(line, lnum, cstart, cend)
3600 s = linestate(line, lnum, cstart, cend)
3601 m.append(s)
3601 m.append(s)
3602
3602
3603 def difflinestates(a, b):
3603 def difflinestates(a, b):
3604 sm = difflib.SequenceMatcher(None, a, b)
3604 sm = difflib.SequenceMatcher(None, a, b)
3605 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3605 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3606 if tag == 'insert':
3606 if tag == 'insert':
3607 for i in xrange(blo, bhi):
3607 for i in xrange(blo, bhi):
3608 yield ('+', b[i])
3608 yield ('+', b[i])
3609 elif tag == 'delete':
3609 elif tag == 'delete':
3610 for i in xrange(alo, ahi):
3610 for i in xrange(alo, ahi):
3611 yield ('-', a[i])
3611 yield ('-', a[i])
3612 elif tag == 'replace':
3612 elif tag == 'replace':
3613 for i in xrange(alo, ahi):
3613 for i in xrange(alo, ahi):
3614 yield ('-', a[i])
3614 yield ('-', a[i])
3615 for i in xrange(blo, bhi):
3615 for i in xrange(blo, bhi):
3616 yield ('+', b[i])
3616 yield ('+', b[i])
3617
3617
3618 def display(fn, ctx, pstates, states):
3618 def display(fn, ctx, pstates, states):
3619 rev = ctx.rev()
3619 rev = ctx.rev()
3620 datefunc = ui.quiet and util.shortdate or util.datestr
3620 datefunc = ui.quiet and util.shortdate or util.datestr
3621 found = False
3621 found = False
3622 @util.cachefunc
3622 @util.cachefunc
3623 def binary():
3623 def binary():
3624 flog = getfile(fn)
3624 flog = getfile(fn)
3625 return util.binary(flog.read(ctx.filenode(fn)))
3625 return util.binary(flog.read(ctx.filenode(fn)))
3626
3626
3627 if opts.get('all'):
3627 if opts.get('all'):
3628 iter = difflinestates(pstates, states)
3628 iter = difflinestates(pstates, states)
3629 else:
3629 else:
3630 iter = [('', l) for l in states]
3630 iter = [('', l) for l in states]
3631 for change, l in iter:
3631 for change, l in iter:
3632 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3632 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3633
3633
3634 if opts.get('line_number'):
3634 if opts.get('line_number'):
3635 cols.append((str(l.linenum), 'grep.linenumber'))
3635 cols.append((str(l.linenum), 'grep.linenumber'))
3636 if opts.get('all'):
3636 if opts.get('all'):
3637 cols.append((change, 'grep.change'))
3637 cols.append((change, 'grep.change'))
3638 if opts.get('user'):
3638 if opts.get('user'):
3639 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3639 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3640 if opts.get('date'):
3640 if opts.get('date'):
3641 cols.append((datefunc(ctx.date()), 'grep.date'))
3641 cols.append((datefunc(ctx.date()), 'grep.date'))
3642 for col, label in cols[:-1]:
3642 for col, label in cols[:-1]:
3643 ui.write(col, label=label)
3643 ui.write(col, label=label)
3644 ui.write(sep, label='grep.sep')
3644 ui.write(sep, label='grep.sep')
3645 ui.write(cols[-1][0], label=cols[-1][1])
3645 ui.write(cols[-1][0], label=cols[-1][1])
3646 if not opts.get('files_with_matches'):
3646 if not opts.get('files_with_matches'):
3647 ui.write(sep, label='grep.sep')
3647 ui.write(sep, label='grep.sep')
3648 if not opts.get('text') and binary():
3648 if not opts.get('text') and binary():
3649 ui.write(" Binary file matches")
3649 ui.write(" Binary file matches")
3650 else:
3650 else:
3651 for s, label in l:
3651 for s, label in l:
3652 ui.write(s, label=label)
3652 ui.write(s, label=label)
3653 ui.write(eol)
3653 ui.write(eol)
3654 found = True
3654 found = True
3655 if opts.get('files_with_matches'):
3655 if opts.get('files_with_matches'):
3656 break
3656 break
3657 return found
3657 return found
3658
3658
3659 skip = {}
3659 skip = {}
3660 revfiles = {}
3660 revfiles = {}
3661 matchfn = scmutil.match(repo[None], pats, opts)
3661 matchfn = scmutil.match(repo[None], pats, opts)
3662 found = False
3662 found = False
3663 follow = opts.get('follow')
3663 follow = opts.get('follow')
3664
3664
3665 def prep(ctx, fns):
3665 def prep(ctx, fns):
3666 rev = ctx.rev()
3666 rev = ctx.rev()
3667 pctx = ctx.p1()
3667 pctx = ctx.p1()
3668 parent = pctx.rev()
3668 parent = pctx.rev()
3669 matches.setdefault(rev, {})
3669 matches.setdefault(rev, {})
3670 matches.setdefault(parent, {})
3670 matches.setdefault(parent, {})
3671 files = revfiles.setdefault(rev, [])
3671 files = revfiles.setdefault(rev, [])
3672 for fn in fns:
3672 for fn in fns:
3673 flog = getfile(fn)
3673 flog = getfile(fn)
3674 try:
3674 try:
3675 fnode = ctx.filenode(fn)
3675 fnode = ctx.filenode(fn)
3676 except error.LookupError:
3676 except error.LookupError:
3677 continue
3677 continue
3678
3678
3679 copied = flog.renamed(fnode)
3679 copied = flog.renamed(fnode)
3680 copy = follow and copied and copied[0]
3680 copy = follow and copied and copied[0]
3681 if copy:
3681 if copy:
3682 copies.setdefault(rev, {})[fn] = copy
3682 copies.setdefault(rev, {})[fn] = copy
3683 if fn in skip:
3683 if fn in skip:
3684 if copy:
3684 if copy:
3685 skip[copy] = True
3685 skip[copy] = True
3686 continue
3686 continue
3687 files.append(fn)
3687 files.append(fn)
3688
3688
3689 if fn not in matches[rev]:
3689 if fn not in matches[rev]:
3690 grepbody(fn, rev, flog.read(fnode))
3690 grepbody(fn, rev, flog.read(fnode))
3691
3691
3692 pfn = copy or fn
3692 pfn = copy or fn
3693 if pfn not in matches[parent]:
3693 if pfn not in matches[parent]:
3694 try:
3694 try:
3695 fnode = pctx.filenode(pfn)
3695 fnode = pctx.filenode(pfn)
3696 grepbody(pfn, parent, flog.read(fnode))
3696 grepbody(pfn, parent, flog.read(fnode))
3697 except error.LookupError:
3697 except error.LookupError:
3698 pass
3698 pass
3699
3699
3700 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3700 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3701 rev = ctx.rev()
3701 rev = ctx.rev()
3702 parent = ctx.p1().rev()
3702 parent = ctx.p1().rev()
3703 for fn in sorted(revfiles.get(rev, [])):
3703 for fn in sorted(revfiles.get(rev, [])):
3704 states = matches[rev][fn]
3704 states = matches[rev][fn]
3705 copy = copies.get(rev, {}).get(fn)
3705 copy = copies.get(rev, {}).get(fn)
3706 if fn in skip:
3706 if fn in skip:
3707 if copy:
3707 if copy:
3708 skip[copy] = True
3708 skip[copy] = True
3709 continue
3709 continue
3710 pstates = matches.get(parent, {}).get(copy or fn, [])
3710 pstates = matches.get(parent, {}).get(copy or fn, [])
3711 if pstates or states:
3711 if pstates or states:
3712 r = display(fn, ctx, pstates, states)
3712 r = display(fn, ctx, pstates, states)
3713 found = found or r
3713 found = found or r
3714 if r and not opts.get('all'):
3714 if r and not opts.get('all'):
3715 skip[fn] = True
3715 skip[fn] = True
3716 if copy:
3716 if copy:
3717 skip[copy] = True
3717 skip[copy] = True
3718 del matches[rev]
3718 del matches[rev]
3719 del revfiles[rev]
3719 del revfiles[rev]
3720
3720
3721 return not found
3721 return not found
3722
3722
3723 @command('heads',
3723 @command('heads',
3724 [('r', 'rev', '',
3724 [('r', 'rev', '',
3725 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3725 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3726 ('t', 'topo', False, _('show topological heads only')),
3726 ('t', 'topo', False, _('show topological heads only')),
3727 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3727 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3728 ('c', 'closed', False, _('show normal and closed branch heads')),
3728 ('c', 'closed', False, _('show normal and closed branch heads')),
3729 ] + templateopts,
3729 ] + templateopts,
3730 _('[-ct] [-r STARTREV] [REV]...'))
3730 _('[-ct] [-r STARTREV] [REV]...'))
3731 def heads(ui, repo, *branchrevs, **opts):
3731 def heads(ui, repo, *branchrevs, **opts):
3732 """show branch heads
3732 """show branch heads
3733
3733
3734 With no arguments, show all open branch heads in the repository.
3734 With no arguments, show all open branch heads in the repository.
3735 Branch heads are changesets that have no descendants on the
3735 Branch heads are changesets that have no descendants on the
3736 same branch. They are where development generally takes place and
3736 same branch. They are where development generally takes place and
3737 are the usual targets for update and merge operations.
3737 are the usual targets for update and merge operations.
3738
3738
3739 If one or more REVs are given, only open branch heads on the
3739 If one or more REVs are given, only open branch heads on the
3740 branches associated with the specified changesets are shown. This
3740 branches associated with the specified changesets are shown. This
3741 means that you can use :hg:`heads .` to see the heads on the
3741 means that you can use :hg:`heads .` to see the heads on the
3742 currently checked-out branch.
3742 currently checked-out branch.
3743
3743
3744 If -c/--closed is specified, also show branch heads marked closed
3744 If -c/--closed is specified, also show branch heads marked closed
3745 (see :hg:`commit --close-branch`).
3745 (see :hg:`commit --close-branch`).
3746
3746
3747 If STARTREV is specified, only those heads that are descendants of
3747 If STARTREV is specified, only those heads that are descendants of
3748 STARTREV will be displayed.
3748 STARTREV will be displayed.
3749
3749
3750 If -t/--topo is specified, named branch mechanics will be ignored and only
3750 If -t/--topo is specified, named branch mechanics will be ignored and only
3751 topological heads (changesets with no children) will be shown.
3751 topological heads (changesets with no children) will be shown.
3752
3752
3753 Returns 0 if matching heads are found, 1 if not.
3753 Returns 0 if matching heads are found, 1 if not.
3754 """
3754 """
3755
3755
3756 start = None
3756 start = None
3757 if 'rev' in opts:
3757 if 'rev' in opts:
3758 start = scmutil.revsingle(repo, opts['rev'], None).node()
3758 start = scmutil.revsingle(repo, opts['rev'], None).node()
3759
3759
3760 if opts.get('topo'):
3760 if opts.get('topo'):
3761 heads = [repo[h] for h in repo.heads(start)]
3761 heads = [repo[h] for h in repo.heads(start)]
3762 else:
3762 else:
3763 heads = []
3763 heads = []
3764 for branch in repo.branchmap():
3764 for branch in repo.branchmap():
3765 heads += repo.branchheads(branch, start, opts.get('closed'))
3765 heads += repo.branchheads(branch, start, opts.get('closed'))
3766 heads = [repo[h] for h in heads]
3766 heads = [repo[h] for h in heads]
3767
3767
3768 if branchrevs:
3768 if branchrevs:
3769 branches = set(repo[br].branch() for br in branchrevs)
3769 branches = set(repo[br].branch() for br in branchrevs)
3770 heads = [h for h in heads if h.branch() in branches]
3770 heads = [h for h in heads if h.branch() in branches]
3771
3771
3772 if opts.get('active') and branchrevs:
3772 if opts.get('active') and branchrevs:
3773 dagheads = repo.heads(start)
3773 dagheads = repo.heads(start)
3774 heads = [h for h in heads if h.node() in dagheads]
3774 heads = [h for h in heads if h.node() in dagheads]
3775
3775
3776 if branchrevs:
3776 if branchrevs:
3777 haveheads = set(h.branch() for h in heads)
3777 haveheads = set(h.branch() for h in heads)
3778 if branches - haveheads:
3778 if branches - haveheads:
3779 headless = ', '.join(b for b in branches - haveheads)
3779 headless = ', '.join(b for b in branches - haveheads)
3780 msg = _('no open branch heads found on branches %s')
3780 msg = _('no open branch heads found on branches %s')
3781 if opts.get('rev'):
3781 if opts.get('rev'):
3782 msg += _(' (started at %s)') % opts['rev']
3782 msg += _(' (started at %s)') % opts['rev']
3783 ui.warn((msg + '\n') % headless)
3783 ui.warn((msg + '\n') % headless)
3784
3784
3785 if not heads:
3785 if not heads:
3786 return 1
3786 return 1
3787
3787
3788 heads = sorted(heads, key=lambda x: -x.rev())
3788 heads = sorted(heads, key=lambda x: -x.rev())
3789 displayer = cmdutil.show_changeset(ui, repo, opts)
3789 displayer = cmdutil.show_changeset(ui, repo, opts)
3790 for ctx in heads:
3790 for ctx in heads:
3791 displayer.show(ctx)
3791 displayer.show(ctx)
3792 displayer.close()
3792 displayer.close()
3793
3793
3794 @command('help',
3794 @command('help',
3795 [('e', 'extension', None, _('show only help for extensions')),
3795 [('e', 'extension', None, _('show only help for extensions')),
3796 ('c', 'command', None, _('show only help for commands')),
3796 ('c', 'command', None, _('show only help for commands')),
3797 ('k', 'keyword', '', _('show topics matching keyword')),
3797 ('k', 'keyword', '', _('show topics matching keyword')),
3798 ],
3798 ],
3799 _('[-ec] [TOPIC]'),
3799 _('[-ec] [TOPIC]'),
3800 norepo=True)
3800 norepo=True)
3801 def help_(ui, name=None, **opts):
3801 def help_(ui, name=None, **opts):
3802 """show help for a given topic or a help overview
3802 """show help for a given topic or a help overview
3803
3803
3804 With no arguments, print a list of commands with short help messages.
3804 With no arguments, print a list of commands with short help messages.
3805
3805
3806 Given a topic, extension, or command name, print help for that
3806 Given a topic, extension, or command name, print help for that
3807 topic.
3807 topic.
3808
3808
3809 Returns 0 if successful.
3809 Returns 0 if successful.
3810 """
3810 """
3811
3811
3812 textwidth = min(ui.termwidth(), 80) - 2
3812 textwidth = min(ui.termwidth(), 80) - 2
3813
3813
3814 keep = []
3814 keep = []
3815 if ui.verbose:
3815 if ui.verbose:
3816 keep.append('verbose')
3816 keep.append('verbose')
3817 if sys.platform.startswith('win'):
3817 if sys.platform.startswith('win'):
3818 keep.append('windows')
3818 keep.append('windows')
3819 elif sys.platform == 'OpenVMS':
3819 elif sys.platform == 'OpenVMS':
3820 keep.append('vms')
3820 keep.append('vms')
3821 elif sys.platform == 'plan9':
3821 elif sys.platform == 'plan9':
3822 keep.append('plan9')
3822 keep.append('plan9')
3823 else:
3823 else:
3824 keep.append('unix')
3824 keep.append('unix')
3825 keep.append(sys.platform.lower())
3825 keep.append(sys.platform.lower())
3826
3826
3827 section = None
3827 section = None
3828 if name and '.' in name:
3828 if name and '.' in name:
3829 name, section = name.split('.', 1)
3829 name, section = name.split('.', 1)
3830
3830
3831 text = help.help_(ui, name, **opts)
3831 text = help.help_(ui, name, **opts)
3832
3832
3833 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3833 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3834 section=section)
3834 section=section)
3835 if section and not formatted:
3835 if section and not formatted:
3836 raise util.Abort(_("help section not found"))
3836 raise util.Abort(_("help section not found"))
3837
3837
3838 if 'verbose' in pruned:
3838 if 'verbose' in pruned:
3839 keep.append('omitted')
3839 keep.append('omitted')
3840 else:
3840 else:
3841 keep.append('notomitted')
3841 keep.append('notomitted')
3842 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3842 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3843 section=section)
3843 section=section)
3844 ui.write(formatted)
3844 ui.write(formatted)
3845
3845
3846
3846
3847 @command('identify|id',
3847 @command('identify|id',
3848 [('r', 'rev', '',
3848 [('r', 'rev', '',
3849 _('identify the specified revision'), _('REV')),
3849 _('identify the specified revision'), _('REV')),
3850 ('n', 'num', None, _('show local revision number')),
3850 ('n', 'num', None, _('show local revision number')),
3851 ('i', 'id', None, _('show global revision id')),
3851 ('i', 'id', None, _('show global revision id')),
3852 ('b', 'branch', None, _('show branch')),
3852 ('b', 'branch', None, _('show branch')),
3853 ('t', 'tags', None, _('show tags')),
3853 ('t', 'tags', None, _('show tags')),
3854 ('B', 'bookmarks', None, _('show bookmarks')),
3854 ('B', 'bookmarks', None, _('show bookmarks')),
3855 ] + remoteopts,
3855 ] + remoteopts,
3856 _('[-nibtB] [-r REV] [SOURCE]'),
3856 _('[-nibtB] [-r REV] [SOURCE]'),
3857 optionalrepo=True)
3857 optionalrepo=True)
3858 def identify(ui, repo, source=None, rev=None,
3858 def identify(ui, repo, source=None, rev=None,
3859 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3859 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3860 """identify the working copy or specified revision
3860 """identify the working copy or specified revision
3861
3861
3862 Print a summary identifying the repository state at REV using one or
3862 Print a summary identifying the repository state at REV using one or
3863 two parent hash identifiers, followed by a "+" if the working
3863 two parent hash identifiers, followed by a "+" if the working
3864 directory has uncommitted changes, the branch name (if not default),
3864 directory has uncommitted changes, the branch name (if not default),
3865 a list of tags, and a list of bookmarks.
3865 a list of tags, and a list of bookmarks.
3866
3866
3867 When REV is not given, print a summary of the current state of the
3867 When REV is not given, print a summary of the current state of the
3868 repository.
3868 repository.
3869
3869
3870 Specifying a path to a repository root or Mercurial bundle will
3870 Specifying a path to a repository root or Mercurial bundle will
3871 cause lookup to operate on that repository/bundle.
3871 cause lookup to operate on that repository/bundle.
3872
3872
3873 .. container:: verbose
3873 .. container:: verbose
3874
3874
3875 Examples:
3875 Examples:
3876
3876
3877 - generate a build identifier for the working directory::
3877 - generate a build identifier for the working directory::
3878
3878
3879 hg id --id > build-id.dat
3879 hg id --id > build-id.dat
3880
3880
3881 - find the revision corresponding to a tag::
3881 - find the revision corresponding to a tag::
3882
3882
3883 hg id -n -r 1.3
3883 hg id -n -r 1.3
3884
3884
3885 - check the most recent revision of a remote repository::
3885 - check the most recent revision of a remote repository::
3886
3886
3887 hg id -r tip http://selenic.com/hg/
3887 hg id -r tip http://selenic.com/hg/
3888
3888
3889 Returns 0 if successful.
3889 Returns 0 if successful.
3890 """
3890 """
3891
3891
3892 if not repo and not source:
3892 if not repo and not source:
3893 raise util.Abort(_("there is no Mercurial repository here "
3893 raise util.Abort(_("there is no Mercurial repository here "
3894 "(.hg not found)"))
3894 "(.hg not found)"))
3895
3895
3896 hexfunc = ui.debugflag and hex or short
3896 hexfunc = ui.debugflag and hex or short
3897 default = not (num or id or branch or tags or bookmarks)
3897 default = not (num or id or branch or tags or bookmarks)
3898 output = []
3898 output = []
3899 revs = []
3899 revs = []
3900
3900
3901 if source:
3901 if source:
3902 source, branches = hg.parseurl(ui.expandpath(source))
3902 source, branches = hg.parseurl(ui.expandpath(source))
3903 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3903 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3904 repo = peer.local()
3904 repo = peer.local()
3905 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3905 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3906
3906
3907 if not repo:
3907 if not repo:
3908 if num or branch or tags:
3908 if num or branch or tags:
3909 raise util.Abort(
3909 raise util.Abort(
3910 _("can't query remote revision number, branch, or tags"))
3910 _("can't query remote revision number, branch, or tags"))
3911 if not rev and revs:
3911 if not rev and revs:
3912 rev = revs[0]
3912 rev = revs[0]
3913 if not rev:
3913 if not rev:
3914 rev = "tip"
3914 rev = "tip"
3915
3915
3916 remoterev = peer.lookup(rev)
3916 remoterev = peer.lookup(rev)
3917 if default or id:
3917 if default or id:
3918 output = [hexfunc(remoterev)]
3918 output = [hexfunc(remoterev)]
3919
3919
3920 def getbms():
3920 def getbms():
3921 bms = []
3921 bms = []
3922
3922
3923 if 'bookmarks' in peer.listkeys('namespaces'):
3923 if 'bookmarks' in peer.listkeys('namespaces'):
3924 hexremoterev = hex(remoterev)
3924 hexremoterev = hex(remoterev)
3925 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3925 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3926 if bmr == hexremoterev]
3926 if bmr == hexremoterev]
3927
3927
3928 return sorted(bms)
3928 return sorted(bms)
3929
3929
3930 if bookmarks:
3930 if bookmarks:
3931 output.extend(getbms())
3931 output.extend(getbms())
3932 elif default and not ui.quiet:
3932 elif default and not ui.quiet:
3933 # multiple bookmarks for a single parent separated by '/'
3933 # multiple bookmarks for a single parent separated by '/'
3934 bm = '/'.join(getbms())
3934 bm = '/'.join(getbms())
3935 if bm:
3935 if bm:
3936 output.append(bm)
3936 output.append(bm)
3937 else:
3937 else:
3938 if not rev:
3938 if not rev:
3939 ctx = repo[None]
3939 ctx = repo[None]
3940 parents = ctx.parents()
3940 parents = ctx.parents()
3941 changed = ""
3941 changed = ""
3942 if default or id or num:
3942 if default or id or num:
3943 if (util.any(repo.status())
3943 if (util.any(repo.status())
3944 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3944 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3945 changed = '+'
3945 changed = '+'
3946 if default or id:
3946 if default or id:
3947 output = ["%s%s" %
3947 output = ["%s%s" %
3948 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3948 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3949 if num:
3949 if num:
3950 output.append("%s%s" %
3950 output.append("%s%s" %
3951 ('+'.join([str(p.rev()) for p in parents]), changed))
3951 ('+'.join([str(p.rev()) for p in parents]), changed))
3952 else:
3952 else:
3953 ctx = scmutil.revsingle(repo, rev)
3953 ctx = scmutil.revsingle(repo, rev)
3954 if default or id:
3954 if default or id:
3955 output = [hexfunc(ctx.node())]
3955 output = [hexfunc(ctx.node())]
3956 if num:
3956 if num:
3957 output.append(str(ctx.rev()))
3957 output.append(str(ctx.rev()))
3958
3958
3959 if default and not ui.quiet:
3959 if default and not ui.quiet:
3960 b = ctx.branch()
3960 b = ctx.branch()
3961 if b != 'default':
3961 if b != 'default':
3962 output.append("(%s)" % b)
3962 output.append("(%s)" % b)
3963
3963
3964 # multiple tags for a single parent separated by '/'
3964 # multiple tags for a single parent separated by '/'
3965 t = '/'.join(ctx.tags())
3965 t = '/'.join(ctx.tags())
3966 if t:
3966 if t:
3967 output.append(t)
3967 output.append(t)
3968
3968
3969 # multiple bookmarks for a single parent separated by '/'
3969 # multiple bookmarks for a single parent separated by '/'
3970 bm = '/'.join(ctx.bookmarks())
3970 bm = '/'.join(ctx.bookmarks())
3971 if bm:
3971 if bm:
3972 output.append(bm)
3972 output.append(bm)
3973 else:
3973 else:
3974 if branch:
3974 if branch:
3975 output.append(ctx.branch())
3975 output.append(ctx.branch())
3976
3976
3977 if tags:
3977 if tags:
3978 output.extend(ctx.tags())
3978 output.extend(ctx.tags())
3979
3979
3980 if bookmarks:
3980 if bookmarks:
3981 output.extend(ctx.bookmarks())
3981 output.extend(ctx.bookmarks())
3982
3982
3983 ui.write("%s\n" % ' '.join(output))
3983 ui.write("%s\n" % ' '.join(output))
3984
3984
3985 @command('import|patch',
3985 @command('import|patch',
3986 [('p', 'strip', 1,
3986 [('p', 'strip', 1,
3987 _('directory strip option for patch. This has the same '
3987 _('directory strip option for patch. This has the same '
3988 'meaning as the corresponding patch option'), _('NUM')),
3988 'meaning as the corresponding patch option'), _('NUM')),
3989 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3989 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3990 ('e', 'edit', False, _('invoke editor on commit messages')),
3990 ('e', 'edit', False, _('invoke editor on commit messages')),
3991 ('f', 'force', None,
3991 ('f', 'force', None,
3992 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3992 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3993 ('', 'no-commit', None,
3993 ('', 'no-commit', None,
3994 _("don't commit, just update the working directory")),
3994 _("don't commit, just update the working directory")),
3995 ('', 'bypass', None,
3995 ('', 'bypass', None,
3996 _("apply patch without touching the working directory")),
3996 _("apply patch without touching the working directory")),
3997 ('', 'partial', None,
3997 ('', 'partial', None,
3998 _('commit even if some hunks fail')),
3998 _('commit even if some hunks fail')),
3999 ('', 'exact', None,
3999 ('', 'exact', None,
4000 _('apply patch to the nodes from which it was generated')),
4000 _('apply patch to the nodes from which it was generated')),
4001 ('', 'import-branch', None,
4001 ('', 'import-branch', None,
4002 _('use any branch information in patch (implied by --exact)'))] +
4002 _('use any branch information in patch (implied by --exact)'))] +
4003 commitopts + commitopts2 + similarityopts,
4003 commitopts + commitopts2 + similarityopts,
4004 _('[OPTION]... PATCH...'))
4004 _('[OPTION]... PATCH...'))
4005 def import_(ui, repo, patch1=None, *patches, **opts):
4005 def import_(ui, repo, patch1=None, *patches, **opts):
4006 """import an ordered set of patches
4006 """import an ordered set of patches
4007
4007
4008 Import a list of patches and commit them individually (unless
4008 Import a list of patches and commit them individually (unless
4009 --no-commit is specified).
4009 --no-commit is specified).
4010
4010
4011 Because import first applies changes to the working directory,
4011 Because import first applies changes to the working directory,
4012 import will abort if there are outstanding changes.
4012 import will abort if there are outstanding changes.
4013
4013
4014 You can import a patch straight from a mail message. Even patches
4014 You can import a patch straight from a mail message. Even patches
4015 as attachments work (to use the body part, it must have type
4015 as attachments work (to use the body part, it must have type
4016 text/plain or text/x-patch). From and Subject headers of email
4016 text/plain or text/x-patch). From and Subject headers of email
4017 message are used as default committer and commit message. All
4017 message are used as default committer and commit message. All
4018 text/plain body parts before first diff are added to commit
4018 text/plain body parts before first diff are added to commit
4019 message.
4019 message.
4020
4020
4021 If the imported patch was generated by :hg:`export`, user and
4021 If the imported patch was generated by :hg:`export`, user and
4022 description from patch override values from message headers and
4022 description from patch override values from message headers and
4023 body. Values given on command line with -m/--message and -u/--user
4023 body. Values given on command line with -m/--message and -u/--user
4024 override these.
4024 override these.
4025
4025
4026 If --exact is specified, import will set the working directory to
4026 If --exact is specified, import will set the working directory to
4027 the parent of each patch before applying it, and will abort if the
4027 the parent of each patch before applying it, and will abort if the
4028 resulting changeset has a different ID than the one recorded in
4028 resulting changeset has a different ID than the one recorded in
4029 the patch. This may happen due to character set problems or other
4029 the patch. This may happen due to character set problems or other
4030 deficiencies in the text patch format.
4030 deficiencies in the text patch format.
4031
4031
4032 Use --bypass to apply and commit patches directly to the
4032 Use --bypass to apply and commit patches directly to the
4033 repository, not touching the working directory. Without --exact,
4033 repository, not touching the working directory. Without --exact,
4034 patches will be applied on top of the working directory parent
4034 patches will be applied on top of the working directory parent
4035 revision.
4035 revision.
4036
4036
4037 With -s/--similarity, hg will attempt to discover renames and
4037 With -s/--similarity, hg will attempt to discover renames and
4038 copies in the patch in the same way as :hg:`addremove`.
4038 copies in the patch in the same way as :hg:`addremove`.
4039
4039
4040 Use --partial to ensure a changeset will be created from the patch
4040 Use --partial to ensure a changeset will be created from the patch
4041 even if some hunks fail to apply. Hunks that fail to apply will be
4041 even if some hunks fail to apply. Hunks that fail to apply will be
4042 written to a <target-file>.rej file. Conflicts can then be resolved
4042 written to a <target-file>.rej file. Conflicts can then be resolved
4043 by hand before :hg:`commit --amend` is run to update the created
4043 by hand before :hg:`commit --amend` is run to update the created
4044 changeset. This flag exists to let people import patches that
4044 changeset. This flag exists to let people import patches that
4045 partially apply without losing the associated metadata (author,
4045 partially apply without losing the associated metadata (author,
4046 date, description, ...). Note that when none of the hunk applies
4046 date, description, ...). Note that when none of the hunk applies
4047 cleanly, :hg:`import --partial` will create an empty changeset,
4047 cleanly, :hg:`import --partial` will create an empty changeset,
4048 importing only the patch metadata.
4048 importing only the patch metadata.
4049
4049
4050 To read a patch from standard input, use "-" as the patch name. If
4050 To read a patch from standard input, use "-" as the patch name. If
4051 a URL is specified, the patch will be downloaded from it.
4051 a URL is specified, the patch will be downloaded from it.
4052 See :hg:`help dates` for a list of formats valid for -d/--date.
4052 See :hg:`help dates` for a list of formats valid for -d/--date.
4053
4053
4054 .. container:: verbose
4054 .. container:: verbose
4055
4055
4056 Examples:
4056 Examples:
4057
4057
4058 - import a traditional patch from a website and detect renames::
4058 - import a traditional patch from a website and detect renames::
4059
4059
4060 hg import -s 80 http://example.com/bugfix.patch
4060 hg import -s 80 http://example.com/bugfix.patch
4061
4061
4062 - import a changeset from an hgweb server::
4062 - import a changeset from an hgweb server::
4063
4063
4064 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4064 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4065
4065
4066 - import all the patches in an Unix-style mbox::
4066 - import all the patches in an Unix-style mbox::
4067
4067
4068 hg import incoming-patches.mbox
4068 hg import incoming-patches.mbox
4069
4069
4070 - attempt to exactly restore an exported changeset (not always
4070 - attempt to exactly restore an exported changeset (not always
4071 possible)::
4071 possible)::
4072
4072
4073 hg import --exact proposed-fix.patch
4073 hg import --exact proposed-fix.patch
4074
4074
4075 Returns 0 on success, 1 on partial success (see --partial).
4075 Returns 0 on success, 1 on partial success (see --partial).
4076 """
4076 """
4077
4077
4078 if not patch1:
4078 if not patch1:
4079 raise util.Abort(_('need at least one patch to import'))
4079 raise util.Abort(_('need at least one patch to import'))
4080
4080
4081 patches = (patch1,) + patches
4081 patches = (patch1,) + patches
4082
4082
4083 date = opts.get('date')
4083 date = opts.get('date')
4084 if date:
4084 if date:
4085 opts['date'] = util.parsedate(date)
4085 opts['date'] = util.parsedate(date)
4086
4086
4087 update = not opts.get('bypass')
4087 update = not opts.get('bypass')
4088 if not update and opts.get('no_commit'):
4088 if not update and opts.get('no_commit'):
4089 raise util.Abort(_('cannot use --no-commit with --bypass'))
4089 raise util.Abort(_('cannot use --no-commit with --bypass'))
4090 try:
4090 try:
4091 sim = float(opts.get('similarity') or 0)
4091 sim = float(opts.get('similarity') or 0)
4092 except ValueError:
4092 except ValueError:
4093 raise util.Abort(_('similarity must be a number'))
4093 raise util.Abort(_('similarity must be a number'))
4094 if sim < 0 or sim > 100:
4094 if sim < 0 or sim > 100:
4095 raise util.Abort(_('similarity must be between 0 and 100'))
4095 raise util.Abort(_('similarity must be between 0 and 100'))
4096 if sim and not update:
4096 if sim and not update:
4097 raise util.Abort(_('cannot use --similarity with --bypass'))
4097 raise util.Abort(_('cannot use --similarity with --bypass'))
4098 if opts.get('exact') and opts.get('edit'):
4098 if opts.get('exact') and opts.get('edit'):
4099 raise util.Abort(_('cannot use --exact with --edit'))
4099 raise util.Abort(_('cannot use --exact with --edit'))
4100
4100
4101 if update:
4101 if update:
4102 cmdutil.checkunfinished(repo)
4102 cmdutil.checkunfinished(repo)
4103 if (opts.get('exact') or not opts.get('force')) and update:
4103 if (opts.get('exact') or not opts.get('force')) and update:
4104 cmdutil.bailifchanged(repo)
4104 cmdutil.bailifchanged(repo)
4105
4105
4106 base = opts["base"]
4106 base = opts["base"]
4107 wlock = lock = tr = None
4107 wlock = lock = tr = None
4108 msgs = []
4108 msgs = []
4109 ret = 0
4109 ret = 0
4110
4110
4111
4111
4112 try:
4112 try:
4113 try:
4113 try:
4114 wlock = repo.wlock()
4114 wlock = repo.wlock()
4115 repo.dirstate.beginparentchange()
4115 repo.dirstate.beginparentchange()
4116 if not opts.get('no_commit'):
4116 if not opts.get('no_commit'):
4117 lock = repo.lock()
4117 lock = repo.lock()
4118 tr = repo.transaction('import')
4118 tr = repo.transaction('import')
4119 parents = repo.parents()
4119 parents = repo.parents()
4120 for patchurl in patches:
4120 for patchurl in patches:
4121 if patchurl == '-':
4121 if patchurl == '-':
4122 ui.status(_('applying patch from stdin\n'))
4122 ui.status(_('applying patch from stdin\n'))
4123 patchfile = ui.fin
4123 patchfile = ui.fin
4124 patchurl = 'stdin' # for error message
4124 patchurl = 'stdin' # for error message
4125 else:
4125 else:
4126 patchurl = os.path.join(base, patchurl)
4126 patchurl = os.path.join(base, patchurl)
4127 ui.status(_('applying %s\n') % patchurl)
4127 ui.status(_('applying %s\n') % patchurl)
4128 patchfile = hg.openpath(ui, patchurl)
4128 patchfile = hg.openpath(ui, patchurl)
4129
4129
4130 haspatch = False
4130 haspatch = False
4131 for hunk in patch.split(patchfile):
4131 for hunk in patch.split(patchfile):
4132 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4132 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4133 parents, opts,
4133 parents, opts,
4134 msgs, hg.clean)
4134 msgs, hg.clean)
4135 if msg:
4135 if msg:
4136 haspatch = True
4136 haspatch = True
4137 ui.note(msg + '\n')
4137 ui.note(msg + '\n')
4138 if update or opts.get('exact'):
4138 if update or opts.get('exact'):
4139 parents = repo.parents()
4139 parents = repo.parents()
4140 else:
4140 else:
4141 parents = [repo[node]]
4141 parents = [repo[node]]
4142 if rej:
4142 if rej:
4143 ui.write_err(_("patch applied partially\n"))
4143 ui.write_err(_("patch applied partially\n"))
4144 ui.write_err(_("(fix the .rej files and run "
4144 ui.write_err(_("(fix the .rej files and run "
4145 "`hg commit --amend`)\n"))
4145 "`hg commit --amend`)\n"))
4146 ret = 1
4146 ret = 1
4147 break
4147 break
4148
4148
4149 if not haspatch:
4149 if not haspatch:
4150 raise util.Abort(_('%s: no diffs found') % patchurl)
4150 raise util.Abort(_('%s: no diffs found') % patchurl)
4151
4151
4152 if tr:
4152 if tr:
4153 tr.close()
4153 tr.close()
4154 if msgs:
4154 if msgs:
4155 repo.savecommitmessage('\n* * *\n'.join(msgs))
4155 repo.savecommitmessage('\n* * *\n'.join(msgs))
4156 repo.dirstate.endparentchange()
4156 repo.dirstate.endparentchange()
4157 return ret
4157 return ret
4158 except: # re-raises
4158 except: # re-raises
4159 # wlock.release() indirectly calls dirstate.write(): since
4159 # wlock.release() indirectly calls dirstate.write(): since
4160 # we're crashing, we do not want to change the working dir
4160 # we're crashing, we do not want to change the working dir
4161 # parent after all, so make sure it writes nothing
4161 # parent after all, so make sure it writes nothing
4162 repo.dirstate.invalidate()
4162 repo.dirstate.invalidate()
4163 raise
4163 raise
4164 finally:
4164 finally:
4165 if tr:
4165 if tr:
4166 tr.release()
4166 tr.release()
4167 release(lock, wlock)
4167 release(lock, wlock)
4168
4168
4169 @command('incoming|in',
4169 @command('incoming|in',
4170 [('f', 'force', None,
4170 [('f', 'force', None,
4171 _('run even if remote repository is unrelated')),
4171 _('run even if remote repository is unrelated')),
4172 ('n', 'newest-first', None, _('show newest record first')),
4172 ('n', 'newest-first', None, _('show newest record first')),
4173 ('', 'bundle', '',
4173 ('', 'bundle', '',
4174 _('file to store the bundles into'), _('FILE')),
4174 _('file to store the bundles into'), _('FILE')),
4175 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4175 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4176 ('B', 'bookmarks', False, _("compare bookmarks")),
4176 ('B', 'bookmarks', False, _("compare bookmarks")),
4177 ('b', 'branch', [],
4177 ('b', 'branch', [],
4178 _('a specific branch you would like to pull'), _('BRANCH')),
4178 _('a specific branch you would like to pull'), _('BRANCH')),
4179 ] + logopts + remoteopts + subrepoopts,
4179 ] + logopts + remoteopts + subrepoopts,
4180 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4180 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4181 def incoming(ui, repo, source="default", **opts):
4181 def incoming(ui, repo, source="default", **opts):
4182 """show new changesets found in source
4182 """show new changesets found in source
4183
4183
4184 Show new changesets found in the specified path/URL or the default
4184 Show new changesets found in the specified path/URL or the default
4185 pull location. These are the changesets that would have been pulled
4185 pull location. These are the changesets that would have been pulled
4186 if a pull at the time you issued this command.
4186 if a pull at the time you issued this command.
4187
4187
4188 For remote repository, using --bundle avoids downloading the
4188 For remote repository, using --bundle avoids downloading the
4189 changesets twice if the incoming is followed by a pull.
4189 changesets twice if the incoming is followed by a pull.
4190
4190
4191 See pull for valid source format details.
4191 See pull for valid source format details.
4192
4192
4193 .. container:: verbose
4193 .. container:: verbose
4194
4194
4195 Examples:
4195 Examples:
4196
4196
4197 - show incoming changes with patches and full description::
4197 - show incoming changes with patches and full description::
4198
4198
4199 hg incoming -vp
4199 hg incoming -vp
4200
4200
4201 - show incoming changes excluding merges, store a bundle::
4201 - show incoming changes excluding merges, store a bundle::
4202
4202
4203 hg in -vpM --bundle incoming.hg
4203 hg in -vpM --bundle incoming.hg
4204 hg pull incoming.hg
4204 hg pull incoming.hg
4205
4205
4206 - briefly list changes inside a bundle::
4206 - briefly list changes inside a bundle::
4207
4207
4208 hg in changes.hg -T "{desc|firstline}\\n"
4208 hg in changes.hg -T "{desc|firstline}\\n"
4209
4209
4210 Returns 0 if there are incoming changes, 1 otherwise.
4210 Returns 0 if there are incoming changes, 1 otherwise.
4211 """
4211 """
4212 if opts.get('graph'):
4212 if opts.get('graph'):
4213 cmdutil.checkunsupportedgraphflags([], opts)
4213 cmdutil.checkunsupportedgraphflags([], opts)
4214 def display(other, chlist, displayer):
4214 def display(other, chlist, displayer):
4215 revdag = cmdutil.graphrevs(other, chlist, opts)
4215 revdag = cmdutil.graphrevs(other, chlist, opts)
4216 showparents = [ctx.node() for ctx in repo[None].parents()]
4216 showparents = [ctx.node() for ctx in repo[None].parents()]
4217 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4217 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4218 graphmod.asciiedges)
4218 graphmod.asciiedges)
4219
4219
4220 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4220 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4221 return 0
4221 return 0
4222
4222
4223 if opts.get('bundle') and opts.get('subrepos'):
4223 if opts.get('bundle') and opts.get('subrepos'):
4224 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4224 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4225
4225
4226 if opts.get('bookmarks'):
4226 if opts.get('bookmarks'):
4227 source, branches = hg.parseurl(ui.expandpath(source),
4227 source, branches = hg.parseurl(ui.expandpath(source),
4228 opts.get('branch'))
4228 opts.get('branch'))
4229 other = hg.peer(repo, opts, source)
4229 other = hg.peer(repo, opts, source)
4230 if 'bookmarks' not in other.listkeys('namespaces'):
4230 if 'bookmarks' not in other.listkeys('namespaces'):
4231 ui.warn(_("remote doesn't support bookmarks\n"))
4231 ui.warn(_("remote doesn't support bookmarks\n"))
4232 return 0
4232 return 0
4233 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4233 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4234 return bookmarks.diff(ui, repo, other)
4234 return bookmarks.diff(ui, repo, other)
4235
4235
4236 repo._subtoppath = ui.expandpath(source)
4236 repo._subtoppath = ui.expandpath(source)
4237 try:
4237 try:
4238 return hg.incoming(ui, repo, source, opts)
4238 return hg.incoming(ui, repo, source, opts)
4239 finally:
4239 finally:
4240 del repo._subtoppath
4240 del repo._subtoppath
4241
4241
4242
4242
4243 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4243 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4244 norepo=True)
4244 norepo=True)
4245 def init(ui, dest=".", **opts):
4245 def init(ui, dest=".", **opts):
4246 """create a new repository in the given directory
4246 """create a new repository in the given directory
4247
4247
4248 Initialize a new repository in the given directory. If the given
4248 Initialize a new repository in the given directory. If the given
4249 directory does not exist, it will be created.
4249 directory does not exist, it will be created.
4250
4250
4251 If no directory is given, the current directory is used.
4251 If no directory is given, the current directory is used.
4252
4252
4253 It is possible to specify an ``ssh://`` URL as the destination.
4253 It is possible to specify an ``ssh://`` URL as the destination.
4254 See :hg:`help urls` for more information.
4254 See :hg:`help urls` for more information.
4255
4255
4256 Returns 0 on success.
4256 Returns 0 on success.
4257 """
4257 """
4258 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4258 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4259
4259
4260 @command('locate',
4260 @command('locate',
4261 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4261 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4262 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4262 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4263 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4263 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4264 ] + walkopts,
4264 ] + walkopts,
4265 _('[OPTION]... [PATTERN]...'))
4265 _('[OPTION]... [PATTERN]...'))
4266 def locate(ui, repo, *pats, **opts):
4266 def locate(ui, repo, *pats, **opts):
4267 """locate files matching specific patterns (DEPRECATED)
4267 """locate files matching specific patterns (DEPRECATED)
4268
4268
4269 Print files under Mercurial control in the working directory whose
4269 Print files under Mercurial control in the working directory whose
4270 names match the given patterns.
4270 names match the given patterns.
4271
4271
4272 By default, this command searches all directories in the working
4272 By default, this command searches all directories in the working
4273 directory. To search just the current directory and its
4273 directory. To search just the current directory and its
4274 subdirectories, use "--include .".
4274 subdirectories, use "--include .".
4275
4275
4276 If no patterns are given to match, this command prints the names
4276 If no patterns are given to match, this command prints the names
4277 of all files under Mercurial control in the working directory.
4277 of all files under Mercurial control in the working directory.
4278
4278
4279 If you want to feed the output of this command into the "xargs"
4279 If you want to feed the output of this command into the "xargs"
4280 command, use the -0 option to both this command and "xargs". This
4280 command, use the -0 option to both this command and "xargs". This
4281 will avoid the problem of "xargs" treating single filenames that
4281 will avoid the problem of "xargs" treating single filenames that
4282 contain whitespace as multiple filenames.
4282 contain whitespace as multiple filenames.
4283
4283
4284 See :hg:`help files` for a more versatile command.
4284 See :hg:`help files` for a more versatile command.
4285
4285
4286 Returns 0 if a match is found, 1 otherwise.
4286 Returns 0 if a match is found, 1 otherwise.
4287 """
4287 """
4288 end = opts.get('print0') and '\0' or '\n'
4288 end = opts.get('print0') and '\0' or '\n'
4289 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4289 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4290
4290
4291 ret = 1
4291 ret = 1
4292 ctx = repo[rev]
4292 ctx = repo[rev]
4293 m = scmutil.match(ctx, pats, opts, default='relglob')
4293 m = scmutil.match(ctx, pats, opts, default='relglob')
4294 m.bad = lambda x, y: False
4294 m.bad = lambda x, y: False
4295
4295
4296 for abs in ctx.matches(m):
4296 for abs in ctx.matches(m):
4297 if opts.get('fullpath'):
4297 if opts.get('fullpath'):
4298 ui.write(repo.wjoin(abs), end)
4298 ui.write(repo.wjoin(abs), end)
4299 else:
4299 else:
4300 ui.write(((pats and m.rel(abs)) or abs), end)
4300 ui.write(((pats and m.rel(abs)) or abs), end)
4301 ret = 0
4301 ret = 0
4302
4302
4303 return ret
4303 return ret
4304
4304
4305 @command('^log|history',
4305 @command('^log|history',
4306 [('f', 'follow', None,
4306 [('f', 'follow', None,
4307 _('follow changeset history, or file history across copies and renames')),
4307 _('follow changeset history, or file history across copies and renames')),
4308 ('', 'follow-first', None,
4308 ('', 'follow-first', None,
4309 _('only follow the first parent of merge changesets (DEPRECATED)')),
4309 _('only follow the first parent of merge changesets (DEPRECATED)')),
4310 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4310 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4311 ('C', 'copies', None, _('show copied files')),
4311 ('C', 'copies', None, _('show copied files')),
4312 ('k', 'keyword', [],
4312 ('k', 'keyword', [],
4313 _('do case-insensitive search for a given text'), _('TEXT')),
4313 _('do case-insensitive search for a given text'), _('TEXT')),
4314 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4314 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4315 ('', 'removed', None, _('include revisions where files were removed')),
4315 ('', 'removed', None, _('include revisions where files were removed')),
4316 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4316 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4317 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4317 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4318 ('', 'only-branch', [],
4318 ('', 'only-branch', [],
4319 _('show only changesets within the given named branch (DEPRECATED)'),
4319 _('show only changesets within the given named branch (DEPRECATED)'),
4320 _('BRANCH')),
4320 _('BRANCH')),
4321 ('b', 'branch', [],
4321 ('b', 'branch', [],
4322 _('show changesets within the given named branch'), _('BRANCH')),
4322 _('show changesets within the given named branch'), _('BRANCH')),
4323 ('P', 'prune', [],
4323 ('P', 'prune', [],
4324 _('do not display revision or any of its ancestors'), _('REV')),
4324 _('do not display revision or any of its ancestors'), _('REV')),
4325 ] + logopts + walkopts,
4325 ] + logopts + walkopts,
4326 _('[OPTION]... [FILE]'),
4326 _('[OPTION]... [FILE]'),
4327 inferrepo=True)
4327 inferrepo=True)
4328 def log(ui, repo, *pats, **opts):
4328 def log(ui, repo, *pats, **opts):
4329 """show revision history of entire repository or files
4329 """show revision history of entire repository or files
4330
4330
4331 Print the revision history of the specified files or the entire
4331 Print the revision history of the specified files or the entire
4332 project.
4332 project.
4333
4333
4334 If no revision range is specified, the default is ``tip:0`` unless
4334 If no revision range is specified, the default is ``tip:0`` unless
4335 --follow is set, in which case the working directory parent is
4335 --follow is set, in which case the working directory parent is
4336 used as the starting revision.
4336 used as the starting revision.
4337
4337
4338 File history is shown without following rename or copy history of
4338 File history is shown without following rename or copy history of
4339 files. Use -f/--follow with a filename to follow history across
4339 files. Use -f/--follow with a filename to follow history across
4340 renames and copies. --follow without a filename will only show
4340 renames and copies. --follow without a filename will only show
4341 ancestors or descendants of the starting revision.
4341 ancestors or descendants of the starting revision.
4342
4342
4343 By default this command prints revision number and changeset id,
4343 By default this command prints revision number and changeset id,
4344 tags, non-trivial parents, user, date and time, and a summary for
4344 tags, non-trivial parents, user, date and time, and a summary for
4345 each commit. When the -v/--verbose switch is used, the list of
4345 each commit. When the -v/--verbose switch is used, the list of
4346 changed files and full commit message are shown.
4346 changed files and full commit message are shown.
4347
4347
4348 With --graph the revisions are shown as an ASCII art DAG with the most
4348 With --graph the revisions are shown as an ASCII art DAG with the most
4349 recent changeset at the top.
4349 recent changeset at the top.
4350 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4350 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4351 and '+' represents a fork where the changeset from the lines below is a
4351 and '+' represents a fork where the changeset from the lines below is a
4352 parent of the 'o' merge on the same line.
4352 parent of the 'o' merge on the same line.
4353
4353
4354 .. note::
4354 .. note::
4355
4355
4356 log -p/--patch may generate unexpected diff output for merge
4356 log -p/--patch may generate unexpected diff output for merge
4357 changesets, as it will only compare the merge changeset against
4357 changesets, as it will only compare the merge changeset against
4358 its first parent. Also, only files different from BOTH parents
4358 its first parent. Also, only files different from BOTH parents
4359 will appear in files:.
4359 will appear in files:.
4360
4360
4361 .. note::
4361 .. note::
4362
4362
4363 for performance reasons, log FILE may omit duplicate changes
4363 for performance reasons, log FILE may omit duplicate changes
4364 made on branches and will not show removals or mode changes. To
4364 made on branches and will not show removals or mode changes. To
4365 see all such changes, use the --removed switch.
4365 see all such changes, use the --removed switch.
4366
4366
4367 .. container:: verbose
4367 .. container:: verbose
4368
4368
4369 Some examples:
4369 Some examples:
4370
4370
4371 - changesets with full descriptions and file lists::
4371 - changesets with full descriptions and file lists::
4372
4372
4373 hg log -v
4373 hg log -v
4374
4374
4375 - changesets ancestral to the working directory::
4375 - changesets ancestral to the working directory::
4376
4376
4377 hg log -f
4377 hg log -f
4378
4378
4379 - last 10 commits on the current branch::
4379 - last 10 commits on the current branch::
4380
4380
4381 hg log -l 10 -b .
4381 hg log -l 10 -b .
4382
4382
4383 - changesets showing all modifications of a file, including removals::
4383 - changesets showing all modifications of a file, including removals::
4384
4384
4385 hg log --removed file.c
4385 hg log --removed file.c
4386
4386
4387 - all changesets that touch a directory, with diffs, excluding merges::
4387 - all changesets that touch a directory, with diffs, excluding merges::
4388
4388
4389 hg log -Mp lib/
4389 hg log -Mp lib/
4390
4390
4391 - all revision numbers that match a keyword::
4391 - all revision numbers that match a keyword::
4392
4392
4393 hg log -k bug --template "{rev}\\n"
4393 hg log -k bug --template "{rev}\\n"
4394
4394
4395 - list available log templates::
4395 - list available log templates::
4396
4396
4397 hg log -T list
4397 hg log -T list
4398
4398
4399 - check if a given changeset is included in a tagged release::
4399 - check if a given changeset is included in a tagged release::
4400
4400
4401 hg log -r "a21ccf and ancestor(1.9)"
4401 hg log -r "a21ccf and ancestor(1.9)"
4402
4402
4403 - find all changesets by some user in a date range::
4403 - find all changesets by some user in a date range::
4404
4404
4405 hg log -k alice -d "may 2008 to jul 2008"
4405 hg log -k alice -d "may 2008 to jul 2008"
4406
4406
4407 - summary of all changesets after the last tag::
4407 - summary of all changesets after the last tag::
4408
4408
4409 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4409 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4410
4410
4411 See :hg:`help dates` for a list of formats valid for -d/--date.
4411 See :hg:`help dates` for a list of formats valid for -d/--date.
4412
4412
4413 See :hg:`help revisions` and :hg:`help revsets` for more about
4413 See :hg:`help revisions` and :hg:`help revsets` for more about
4414 specifying revisions.
4414 specifying revisions.
4415
4415
4416 See :hg:`help templates` for more about pre-packaged styles and
4416 See :hg:`help templates` for more about pre-packaged styles and
4417 specifying custom templates.
4417 specifying custom templates.
4418
4418
4419 Returns 0 on success.
4419 Returns 0 on success.
4420
4420
4421 """
4421 """
4422 if opts.get('graph'):
4422 if opts.get('graph'):
4423 return cmdutil.graphlog(ui, repo, *pats, **opts)
4423 return cmdutil.graphlog(ui, repo, *pats, **opts)
4424
4424
4425 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4425 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4426 limit = cmdutil.loglimit(opts)
4426 limit = cmdutil.loglimit(opts)
4427 count = 0
4427 count = 0
4428
4428
4429 getrenamed = None
4429 getrenamed = None
4430 if opts.get('copies'):
4430 if opts.get('copies'):
4431 endrev = None
4431 endrev = None
4432 if opts.get('rev'):
4432 if opts.get('rev'):
4433 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4433 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4434 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4434 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4435
4435
4436 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4436 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4437 for rev in revs:
4437 for rev in revs:
4438 if count == limit:
4438 if count == limit:
4439 break
4439 break
4440 ctx = repo[rev]
4440 ctx = repo[rev]
4441 copies = None
4441 copies = None
4442 if getrenamed is not None and rev:
4442 if getrenamed is not None and rev:
4443 copies = []
4443 copies = []
4444 for fn in ctx.files():
4444 for fn in ctx.files():
4445 rename = getrenamed(fn, rev)
4445 rename = getrenamed(fn, rev)
4446 if rename:
4446 if rename:
4447 copies.append((fn, rename[0]))
4447 copies.append((fn, rename[0]))
4448 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4448 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4449 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4449 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4450 if displayer.flush(rev):
4450 if displayer.flush(rev):
4451 count += 1
4451 count += 1
4452
4452
4453 displayer.close()
4453 displayer.close()
4454
4454
4455 @command('manifest',
4455 @command('manifest',
4456 [('r', 'rev', '', _('revision to display'), _('REV')),
4456 [('r', 'rev', '', _('revision to display'), _('REV')),
4457 ('', 'all', False, _("list files from all revisions"))]
4457 ('', 'all', False, _("list files from all revisions"))]
4458 + formatteropts,
4458 + formatteropts,
4459 _('[-r REV]'))
4459 _('[-r REV]'))
4460 def manifest(ui, repo, node=None, rev=None, **opts):
4460 def manifest(ui, repo, node=None, rev=None, **opts):
4461 """output the current or given revision of the project manifest
4461 """output the current or given revision of the project manifest
4462
4462
4463 Print a list of version controlled files for the given revision.
4463 Print a list of version controlled files for the given revision.
4464 If no revision is given, the first parent of the working directory
4464 If no revision is given, the first parent of the working directory
4465 is used, or the null revision if no revision is checked out.
4465 is used, or the null revision if no revision is checked out.
4466
4466
4467 With -v, print file permissions, symlink and executable bits.
4467 With -v, print file permissions, symlink and executable bits.
4468 With --debug, print file revision hashes.
4468 With --debug, print file revision hashes.
4469
4469
4470 If option --all is specified, the list of all files from all revisions
4470 If option --all is specified, the list of all files from all revisions
4471 is printed. This includes deleted and renamed files.
4471 is printed. This includes deleted and renamed files.
4472
4472
4473 Returns 0 on success.
4473 Returns 0 on success.
4474 """
4474 """
4475
4475
4476 fm = ui.formatter('manifest', opts)
4476 fm = ui.formatter('manifest', opts)
4477
4477
4478 if opts.get('all'):
4478 if opts.get('all'):
4479 if rev or node:
4479 if rev or node:
4480 raise util.Abort(_("can't specify a revision with --all"))
4480 raise util.Abort(_("can't specify a revision with --all"))
4481
4481
4482 res = []
4482 res = []
4483 prefix = "data/"
4483 prefix = "data/"
4484 suffix = ".i"
4484 suffix = ".i"
4485 plen = len(prefix)
4485 plen = len(prefix)
4486 slen = len(suffix)
4486 slen = len(suffix)
4487 lock = repo.lock()
4487 lock = repo.lock()
4488 try:
4488 try:
4489 for fn, b, size in repo.store.datafiles():
4489 for fn, b, size in repo.store.datafiles():
4490 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4490 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4491 res.append(fn[plen:-slen])
4491 res.append(fn[plen:-slen])
4492 finally:
4492 finally:
4493 lock.release()
4493 lock.release()
4494 for f in res:
4494 for f in res:
4495 fm.startitem()
4495 fm.startitem()
4496 fm.write("path", '%s\n', f)
4496 fm.write("path", '%s\n', f)
4497 fm.end()
4497 fm.end()
4498 return
4498 return
4499
4499
4500 if rev and node:
4500 if rev and node:
4501 raise util.Abort(_("please specify just one revision"))
4501 raise util.Abort(_("please specify just one revision"))
4502
4502
4503 if not node:
4503 if not node:
4504 node = rev
4504 node = rev
4505
4505
4506 char = {'l': '@', 'x': '*', '': ''}
4506 char = {'l': '@', 'x': '*', '': ''}
4507 mode = {'l': '644', 'x': '755', '': '644'}
4507 mode = {'l': '644', 'x': '755', '': '644'}
4508 ctx = scmutil.revsingle(repo, node)
4508 ctx = scmutil.revsingle(repo, node)
4509 mf = ctx.manifest()
4509 mf = ctx.manifest()
4510 for f in ctx:
4510 for f in ctx:
4511 fm.startitem()
4511 fm.startitem()
4512 fl = ctx[f].flags()
4512 fl = ctx[f].flags()
4513 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4513 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4514 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4514 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4515 fm.write('path', '%s\n', f)
4515 fm.write('path', '%s\n', f)
4516 fm.end()
4516 fm.end()
4517
4517
4518 @command('^merge',
4518 @command('^merge',
4519 [('f', 'force', None,
4519 [('f', 'force', None,
4520 _('force a merge including outstanding changes (DEPRECATED)')),
4520 _('force a merge including outstanding changes (DEPRECATED)')),
4521 ('r', 'rev', '', _('revision to merge'), _('REV')),
4521 ('r', 'rev', '', _('revision to merge'), _('REV')),
4522 ('P', 'preview', None,
4522 ('P', 'preview', None,
4523 _('review revisions to merge (no merge is performed)'))
4523 _('review revisions to merge (no merge is performed)'))
4524 ] + mergetoolopts,
4524 ] + mergetoolopts,
4525 _('[-P] [-f] [[-r] REV]'))
4525 _('[-P] [-f] [[-r] REV]'))
4526 def merge(ui, repo, node=None, **opts):
4526 def merge(ui, repo, node=None, **opts):
4527 """merge working directory with another revision
4527 """merge working directory with another revision
4528
4528
4529 The current working directory is updated with all changes made in
4529 The current working directory is updated with all changes made in
4530 the requested revision since the last common predecessor revision.
4530 the requested revision since the last common predecessor revision.
4531
4531
4532 Files that changed between either parent are marked as changed for
4532 Files that changed between either parent are marked as changed for
4533 the next commit and a commit must be performed before any further
4533 the next commit and a commit must be performed before any further
4534 updates to the repository are allowed. The next commit will have
4534 updates to the repository are allowed. The next commit will have
4535 two parents.
4535 two parents.
4536
4536
4537 ``--tool`` can be used to specify the merge tool used for file
4537 ``--tool`` can be used to specify the merge tool used for file
4538 merges. It overrides the HGMERGE environment variable and your
4538 merges. It overrides the HGMERGE environment variable and your
4539 configuration files. See :hg:`help merge-tools` for options.
4539 configuration files. See :hg:`help merge-tools` for options.
4540
4540
4541 If no revision is specified, the working directory's parent is a
4541 If no revision is specified, the working directory's parent is a
4542 head revision, and the current branch contains exactly one other
4542 head revision, and the current branch contains exactly one other
4543 head, the other head is merged with by default. Otherwise, an
4543 head, the other head is merged with by default. Otherwise, an
4544 explicit revision with which to merge with must be provided.
4544 explicit revision with which to merge with must be provided.
4545
4545
4546 :hg:`resolve` must be used to resolve unresolved files.
4546 :hg:`resolve` must be used to resolve unresolved files.
4547
4547
4548 To undo an uncommitted merge, use :hg:`update --clean .` which
4548 To undo an uncommitted merge, use :hg:`update --clean .` which
4549 will check out a clean copy of the original merge parent, losing
4549 will check out a clean copy of the original merge parent, losing
4550 all changes.
4550 all changes.
4551
4551
4552 Returns 0 on success, 1 if there are unresolved files.
4552 Returns 0 on success, 1 if there are unresolved files.
4553 """
4553 """
4554
4554
4555 if opts.get('rev') and node:
4555 if opts.get('rev') and node:
4556 raise util.Abort(_("please specify just one revision"))
4556 raise util.Abort(_("please specify just one revision"))
4557 if not node:
4557 if not node:
4558 node = opts.get('rev')
4558 node = opts.get('rev')
4559
4559
4560 if node:
4560 if node:
4561 node = scmutil.revsingle(repo, node).node()
4561 node = scmutil.revsingle(repo, node).node()
4562
4562
4563 if not node and repo._bookmarkcurrent:
4563 if not node and repo._bookmarkcurrent:
4564 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4564 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4565 curhead = repo[repo._bookmarkcurrent].node()
4565 curhead = repo[repo._bookmarkcurrent].node()
4566 if len(bmheads) == 2:
4566 if len(bmheads) == 2:
4567 if curhead == bmheads[0]:
4567 if curhead == bmheads[0]:
4568 node = bmheads[1]
4568 node = bmheads[1]
4569 else:
4569 else:
4570 node = bmheads[0]
4570 node = bmheads[0]
4571 elif len(bmheads) > 2:
4571 elif len(bmheads) > 2:
4572 raise util.Abort(_("multiple matching bookmarks to merge - "
4572 raise util.Abort(_("multiple matching bookmarks to merge - "
4573 "please merge with an explicit rev or bookmark"),
4573 "please merge with an explicit rev or bookmark"),
4574 hint=_("run 'hg heads' to see all heads"))
4574 hint=_("run 'hg heads' to see all heads"))
4575 elif len(bmheads) <= 1:
4575 elif len(bmheads) <= 1:
4576 raise util.Abort(_("no matching bookmark to merge - "
4576 raise util.Abort(_("no matching bookmark to merge - "
4577 "please merge with an explicit rev or bookmark"),
4577 "please merge with an explicit rev or bookmark"),
4578 hint=_("run 'hg heads' to see all heads"))
4578 hint=_("run 'hg heads' to see all heads"))
4579
4579
4580 if not node and not repo._bookmarkcurrent:
4580 if not node and not repo._bookmarkcurrent:
4581 branch = repo[None].branch()
4581 branch = repo[None].branch()
4582 bheads = repo.branchheads(branch)
4582 bheads = repo.branchheads(branch)
4583 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4583 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4584
4584
4585 if len(nbhs) > 2:
4585 if len(nbhs) > 2:
4586 raise util.Abort(_("branch '%s' has %d heads - "
4586 raise util.Abort(_("branch '%s' has %d heads - "
4587 "please merge with an explicit rev")
4587 "please merge with an explicit rev")
4588 % (branch, len(bheads)),
4588 % (branch, len(bheads)),
4589 hint=_("run 'hg heads .' to see heads"))
4589 hint=_("run 'hg heads .' to see heads"))
4590
4590
4591 parent = repo.dirstate.p1()
4591 parent = repo.dirstate.p1()
4592 if len(nbhs) <= 1:
4592 if len(nbhs) <= 1:
4593 if len(bheads) > 1:
4593 if len(bheads) > 1:
4594 raise util.Abort(_("heads are bookmarked - "
4594 raise util.Abort(_("heads are bookmarked - "
4595 "please merge with an explicit rev"),
4595 "please merge with an explicit rev"),
4596 hint=_("run 'hg heads' to see all heads"))
4596 hint=_("run 'hg heads' to see all heads"))
4597 if len(repo.heads()) > 1:
4597 if len(repo.heads()) > 1:
4598 raise util.Abort(_("branch '%s' has one head - "
4598 raise util.Abort(_("branch '%s' has one head - "
4599 "please merge with an explicit rev")
4599 "please merge with an explicit rev")
4600 % branch,
4600 % branch,
4601 hint=_("run 'hg heads' to see all heads"))
4601 hint=_("run 'hg heads' to see all heads"))
4602 msg, hint = _('nothing to merge'), None
4602 msg, hint = _('nothing to merge'), None
4603 if parent != repo.lookup(branch):
4603 if parent != repo.lookup(branch):
4604 hint = _("use 'hg update' instead")
4604 hint = _("use 'hg update' instead")
4605 raise util.Abort(msg, hint=hint)
4605 raise util.Abort(msg, hint=hint)
4606
4606
4607 if parent not in bheads:
4607 if parent not in bheads:
4608 raise util.Abort(_('working directory not at a head revision'),
4608 raise util.Abort(_('working directory not at a head revision'),
4609 hint=_("use 'hg update' or merge with an "
4609 hint=_("use 'hg update' or merge with an "
4610 "explicit revision"))
4610 "explicit revision"))
4611 if parent == nbhs[0]:
4611 if parent == nbhs[0]:
4612 node = nbhs[-1]
4612 node = nbhs[-1]
4613 else:
4613 else:
4614 node = nbhs[0]
4614 node = nbhs[0]
4615
4615
4616 if opts.get('preview'):
4616 if opts.get('preview'):
4617 # find nodes that are ancestors of p2 but not of p1
4617 # find nodes that are ancestors of p2 but not of p1
4618 p1 = repo.lookup('.')
4618 p1 = repo.lookup('.')
4619 p2 = repo.lookup(node)
4619 p2 = repo.lookup(node)
4620 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4620 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4621
4621
4622 displayer = cmdutil.show_changeset(ui, repo, opts)
4622 displayer = cmdutil.show_changeset(ui, repo, opts)
4623 for node in nodes:
4623 for node in nodes:
4624 displayer.show(repo[node])
4624 displayer.show(repo[node])
4625 displayer.close()
4625 displayer.close()
4626 return 0
4626 return 0
4627
4627
4628 try:
4628 try:
4629 # ui.forcemerge is an internal variable, do not document
4629 # ui.forcemerge is an internal variable, do not document
4630 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4630 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4631 return hg.merge(repo, node, force=opts.get('force'))
4631 return hg.merge(repo, node, force=opts.get('force'))
4632 finally:
4632 finally:
4633 ui.setconfig('ui', 'forcemerge', '', 'merge')
4633 ui.setconfig('ui', 'forcemerge', '', 'merge')
4634
4634
4635 @command('outgoing|out',
4635 @command('outgoing|out',
4636 [('f', 'force', None, _('run even when the destination is unrelated')),
4636 [('f', 'force', None, _('run even when the destination is unrelated')),
4637 ('r', 'rev', [],
4637 ('r', 'rev', [],
4638 _('a changeset intended to be included in the destination'), _('REV')),
4638 _('a changeset intended to be included in the destination'), _('REV')),
4639 ('n', 'newest-first', None, _('show newest record first')),
4639 ('n', 'newest-first', None, _('show newest record first')),
4640 ('B', 'bookmarks', False, _('compare bookmarks')),
4640 ('B', 'bookmarks', False, _('compare bookmarks')),
4641 ('b', 'branch', [], _('a specific branch you would like to push'),
4641 ('b', 'branch', [], _('a specific branch you would like to push'),
4642 _('BRANCH')),
4642 _('BRANCH')),
4643 ] + logopts + remoteopts + subrepoopts,
4643 ] + logopts + remoteopts + subrepoopts,
4644 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4644 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4645 def outgoing(ui, repo, dest=None, **opts):
4645 def outgoing(ui, repo, dest=None, **opts):
4646 """show changesets not found in the destination
4646 """show changesets not found in the destination
4647
4647
4648 Show changesets not found in the specified destination repository
4648 Show changesets not found in the specified destination repository
4649 or the default push location. These are the changesets that would
4649 or the default push location. These are the changesets that would
4650 be pushed if a push was requested.
4650 be pushed if a push was requested.
4651
4651
4652 See pull for details of valid destination formats.
4652 See pull for details of valid destination formats.
4653
4653
4654 Returns 0 if there are outgoing changes, 1 otherwise.
4654 Returns 0 if there are outgoing changes, 1 otherwise.
4655 """
4655 """
4656 if opts.get('graph'):
4656 if opts.get('graph'):
4657 cmdutil.checkunsupportedgraphflags([], opts)
4657 cmdutil.checkunsupportedgraphflags([], opts)
4658 o, other = hg._outgoing(ui, repo, dest, opts)
4658 o, other = hg._outgoing(ui, repo, dest, opts)
4659 if not o:
4659 if not o:
4660 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4660 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4661 return
4661 return
4662
4662
4663 revdag = cmdutil.graphrevs(repo, o, opts)
4663 revdag = cmdutil.graphrevs(repo, o, opts)
4664 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4664 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4665 showparents = [ctx.node() for ctx in repo[None].parents()]
4665 showparents = [ctx.node() for ctx in repo[None].parents()]
4666 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4666 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4667 graphmod.asciiedges)
4667 graphmod.asciiedges)
4668 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4668 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4669 return 0
4669 return 0
4670
4670
4671 if opts.get('bookmarks'):
4671 if opts.get('bookmarks'):
4672 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4672 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4673 dest, branches = hg.parseurl(dest, opts.get('branch'))
4673 dest, branches = hg.parseurl(dest, opts.get('branch'))
4674 other = hg.peer(repo, opts, dest)
4674 other = hg.peer(repo, opts, dest)
4675 if 'bookmarks' not in other.listkeys('namespaces'):
4675 if 'bookmarks' not in other.listkeys('namespaces'):
4676 ui.warn(_("remote doesn't support bookmarks\n"))
4676 ui.warn(_("remote doesn't support bookmarks\n"))
4677 return 0
4677 return 0
4678 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4678 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4679 return bookmarks.diff(ui, other, repo)
4679 return bookmarks.diff(ui, other, repo)
4680
4680
4681 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4681 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4682 try:
4682 try:
4683 return hg.outgoing(ui, repo, dest, opts)
4683 return hg.outgoing(ui, repo, dest, opts)
4684 finally:
4684 finally:
4685 del repo._subtoppath
4685 del repo._subtoppath
4686
4686
4687 @command('parents',
4687 @command('parents',
4688 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4688 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4689 ] + templateopts,
4689 ] + templateopts,
4690 _('[-r REV] [FILE]'),
4690 _('[-r REV] [FILE]'),
4691 inferrepo=True)
4691 inferrepo=True)
4692 def parents(ui, repo, file_=None, **opts):
4692 def parents(ui, repo, file_=None, **opts):
4693 """show the parents of the working directory or revision (DEPRECATED)
4693 """show the parents of the working directory or revision (DEPRECATED)
4694
4694
4695 Print the working directory's parent revisions. If a revision is
4695 Print the working directory's parent revisions. If a revision is
4696 given via -r/--rev, the parent of that revision will be printed.
4696 given via -r/--rev, the parent of that revision will be printed.
4697 If a file argument is given, the revision in which the file was
4697 If a file argument is given, the revision in which the file was
4698 last changed (before the working directory revision or the
4698 last changed (before the working directory revision or the
4699 argument to --rev if given) is printed.
4699 argument to --rev if given) is printed.
4700
4700
4701 See :hg:`summary` and :hg:`help revsets` for related information.
4701 See :hg:`summary` and :hg:`help revsets` for related information.
4702
4702
4703 Returns 0 on success.
4703 Returns 0 on success.
4704 """
4704 """
4705
4705
4706 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4706 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4707
4707
4708 if file_:
4708 if file_:
4709 m = scmutil.match(ctx, (file_,), opts)
4709 m = scmutil.match(ctx, (file_,), opts)
4710 if m.anypats() or len(m.files()) != 1:
4710 if m.anypats() or len(m.files()) != 1:
4711 raise util.Abort(_('can only specify an explicit filename'))
4711 raise util.Abort(_('can only specify an explicit filename'))
4712 file_ = m.files()[0]
4712 file_ = m.files()[0]
4713 filenodes = []
4713 filenodes = []
4714 for cp in ctx.parents():
4714 for cp in ctx.parents():
4715 if not cp:
4715 if not cp:
4716 continue
4716 continue
4717 try:
4717 try:
4718 filenodes.append(cp.filenode(file_))
4718 filenodes.append(cp.filenode(file_))
4719 except error.LookupError:
4719 except error.LookupError:
4720 pass
4720 pass
4721 if not filenodes:
4721 if not filenodes:
4722 raise util.Abort(_("'%s' not found in manifest!") % file_)
4722 raise util.Abort(_("'%s' not found in manifest!") % file_)
4723 p = []
4723 p = []
4724 for fn in filenodes:
4724 for fn in filenodes:
4725 fctx = repo.filectx(file_, fileid=fn)
4725 fctx = repo.filectx(file_, fileid=fn)
4726 p.append(fctx.node())
4726 p.append(fctx.node())
4727 else:
4727 else:
4728 p = [cp.node() for cp in ctx.parents()]
4728 p = [cp.node() for cp in ctx.parents()]
4729
4729
4730 displayer = cmdutil.show_changeset(ui, repo, opts)
4730 displayer = cmdutil.show_changeset(ui, repo, opts)
4731 for n in p:
4731 for n in p:
4732 if n != nullid:
4732 if n != nullid:
4733 displayer.show(repo[n])
4733 displayer.show(repo[n])
4734 displayer.close()
4734 displayer.close()
4735
4735
4736 @command('paths', [], _('[NAME]'), optionalrepo=True)
4736 @command('paths', [], _('[NAME]'), optionalrepo=True)
4737 def paths(ui, repo, search=None):
4737 def paths(ui, repo, search=None):
4738 """show aliases for remote repositories
4738 """show aliases for remote repositories
4739
4739
4740 Show definition of symbolic path name NAME. If no name is given,
4740 Show definition of symbolic path name NAME. If no name is given,
4741 show definition of all available names.
4741 show definition of all available names.
4742
4742
4743 Option -q/--quiet suppresses all output when searching for NAME
4743 Option -q/--quiet suppresses all output when searching for NAME
4744 and shows only the path names when listing all definitions.
4744 and shows only the path names when listing all definitions.
4745
4745
4746 Path names are defined in the [paths] section of your
4746 Path names are defined in the [paths] section of your
4747 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4747 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4748 repository, ``.hg/hgrc`` is used, too.
4748 repository, ``.hg/hgrc`` is used, too.
4749
4749
4750 The path names ``default`` and ``default-push`` have a special
4750 The path names ``default`` and ``default-push`` have a special
4751 meaning. When performing a push or pull operation, they are used
4751 meaning. When performing a push or pull operation, they are used
4752 as fallbacks if no location is specified on the command-line.
4752 as fallbacks if no location is specified on the command-line.
4753 When ``default-push`` is set, it will be used for push and
4753 When ``default-push`` is set, it will be used for push and
4754 ``default`` will be used for pull; otherwise ``default`` is used
4754 ``default`` will be used for pull; otherwise ``default`` is used
4755 as the fallback for both. When cloning a repository, the clone
4755 as the fallback for both. When cloning a repository, the clone
4756 source is written as ``default`` in ``.hg/hgrc``. Note that
4756 source is written as ``default`` in ``.hg/hgrc``. Note that
4757 ``default`` and ``default-push`` apply to all inbound (e.g.
4757 ``default`` and ``default-push`` apply to all inbound (e.g.
4758 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4758 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4759 :hg:`bundle`) operations.
4759 :hg:`bundle`) operations.
4760
4760
4761 See :hg:`help urls` for more information.
4761 See :hg:`help urls` for more information.
4762
4762
4763 Returns 0 on success.
4763 Returns 0 on success.
4764 """
4764 """
4765 if search:
4765 if search:
4766 for name, path in ui.configitems("paths"):
4766 for name, path in ui.configitems("paths"):
4767 if name == search:
4767 if name == search:
4768 ui.status("%s\n" % util.hidepassword(path))
4768 ui.status("%s\n" % util.hidepassword(path))
4769 return
4769 return
4770 if not ui.quiet:
4770 if not ui.quiet:
4771 ui.warn(_("not found!\n"))
4771 ui.warn(_("not found!\n"))
4772 return 1
4772 return 1
4773 else:
4773 else:
4774 for name, path in ui.configitems("paths"):
4774 for name, path in ui.configitems("paths"):
4775 if ui.quiet:
4775 if ui.quiet:
4776 ui.write("%s\n" % name)
4776 ui.write("%s\n" % name)
4777 else:
4777 else:
4778 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4778 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4779
4779
4780 @command('phase',
4780 @command('phase',
4781 [('p', 'public', False, _('set changeset phase to public')),
4781 [('p', 'public', False, _('set changeset phase to public')),
4782 ('d', 'draft', False, _('set changeset phase to draft')),
4782 ('d', 'draft', False, _('set changeset phase to draft')),
4783 ('s', 'secret', False, _('set changeset phase to secret')),
4783 ('s', 'secret', False, _('set changeset phase to secret')),
4784 ('f', 'force', False, _('allow to move boundary backward')),
4784 ('f', 'force', False, _('allow to move boundary backward')),
4785 ('r', 'rev', [], _('target revision'), _('REV')),
4785 ('r', 'rev', [], _('target revision'), _('REV')),
4786 ],
4786 ],
4787 _('[-p|-d|-s] [-f] [-r] REV...'))
4787 _('[-p|-d|-s] [-f] [-r] REV...'))
4788 def phase(ui, repo, *revs, **opts):
4788 def phase(ui, repo, *revs, **opts):
4789 """set or show the current phase name
4789 """set or show the current phase name
4790
4790
4791 With no argument, show the phase name of specified revisions.
4791 With no argument, show the phase name of specified revisions.
4792
4792
4793 With one of -p/--public, -d/--draft or -s/--secret, change the
4793 With one of -p/--public, -d/--draft or -s/--secret, change the
4794 phase value of the specified revisions.
4794 phase value of the specified revisions.
4795
4795
4796 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4796 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4797 lower phase to an higher phase. Phases are ordered as follows::
4797 lower phase to an higher phase. Phases are ordered as follows::
4798
4798
4799 public < draft < secret
4799 public < draft < secret
4800
4800
4801 Returns 0 on success, 1 if no phases were changed or some could not
4801 Returns 0 on success, 1 if no phases were changed or some could not
4802 be changed.
4802 be changed.
4803 """
4803 """
4804 # search for a unique phase argument
4804 # search for a unique phase argument
4805 targetphase = None
4805 targetphase = None
4806 for idx, name in enumerate(phases.phasenames):
4806 for idx, name in enumerate(phases.phasenames):
4807 if opts[name]:
4807 if opts[name]:
4808 if targetphase is not None:
4808 if targetphase is not None:
4809 raise util.Abort(_('only one phase can be specified'))
4809 raise util.Abort(_('only one phase can be specified'))
4810 targetphase = idx
4810 targetphase = idx
4811
4811
4812 # look for specified revision
4812 # look for specified revision
4813 revs = list(revs)
4813 revs = list(revs)
4814 revs.extend(opts['rev'])
4814 revs.extend(opts['rev'])
4815 if not revs:
4815 if not revs:
4816 raise util.Abort(_('no revisions specified'))
4816 raise util.Abort(_('no revisions specified'))
4817
4817
4818 revs = scmutil.revrange(repo, revs)
4818 revs = scmutil.revrange(repo, revs)
4819
4819
4820 lock = None
4820 lock = None
4821 ret = 0
4821 ret = 0
4822 if targetphase is None:
4822 if targetphase is None:
4823 # display
4823 # display
4824 for r in revs:
4824 for r in revs:
4825 ctx = repo[r]
4825 ctx = repo[r]
4826 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4826 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4827 else:
4827 else:
4828 tr = None
4828 tr = None
4829 lock = repo.lock()
4829 lock = repo.lock()
4830 try:
4830 try:
4831 tr = repo.transaction("phase")
4831 tr = repo.transaction("phase")
4832 # set phase
4832 # set phase
4833 if not revs:
4833 if not revs:
4834 raise util.Abort(_('empty revision set'))
4834 raise util.Abort(_('empty revision set'))
4835 nodes = [repo[r].node() for r in revs]
4835 nodes = [repo[r].node() for r in revs]
4836 # moving revision from public to draft may hide them
4836 # moving revision from public to draft may hide them
4837 # We have to check result on an unfiltered repository
4837 # We have to check result on an unfiltered repository
4838 unfi = repo.unfiltered()
4838 unfi = repo.unfiltered()
4839 getphase = unfi._phasecache.phase
4839 getphase = unfi._phasecache.phase
4840 olddata = [getphase(unfi, r) for r in unfi]
4840 olddata = [getphase(unfi, r) for r in unfi]
4841 phases.advanceboundary(repo, tr, targetphase, nodes)
4841 phases.advanceboundary(repo, tr, targetphase, nodes)
4842 if opts['force']:
4842 if opts['force']:
4843 phases.retractboundary(repo, tr, targetphase, nodes)
4843 phases.retractboundary(repo, tr, targetphase, nodes)
4844 tr.close()
4844 tr.close()
4845 finally:
4845 finally:
4846 if tr is not None:
4846 if tr is not None:
4847 tr.release()
4847 tr.release()
4848 lock.release()
4848 lock.release()
4849 getphase = unfi._phasecache.phase
4849 getphase = unfi._phasecache.phase
4850 newdata = [getphase(unfi, r) for r in unfi]
4850 newdata = [getphase(unfi, r) for r in unfi]
4851 changes = sum(newdata[r] != olddata[r] for r in unfi)
4851 changes = sum(newdata[r] != olddata[r] for r in unfi)
4852 cl = unfi.changelog
4852 cl = unfi.changelog
4853 rejected = [n for n in nodes
4853 rejected = [n for n in nodes
4854 if newdata[cl.rev(n)] < targetphase]
4854 if newdata[cl.rev(n)] < targetphase]
4855 if rejected:
4855 if rejected:
4856 ui.warn(_('cannot move %i changesets to a higher '
4856 ui.warn(_('cannot move %i changesets to a higher '
4857 'phase, use --force\n') % len(rejected))
4857 'phase, use --force\n') % len(rejected))
4858 ret = 1
4858 ret = 1
4859 if changes:
4859 if changes:
4860 msg = _('phase changed for %i changesets\n') % changes
4860 msg = _('phase changed for %i changesets\n') % changes
4861 if ret:
4861 if ret:
4862 ui.status(msg)
4862 ui.status(msg)
4863 else:
4863 else:
4864 ui.note(msg)
4864 ui.note(msg)
4865 else:
4865 else:
4866 ui.warn(_('no phases changed\n'))
4866 ui.warn(_('no phases changed\n'))
4867 ret = 1
4867 ret = 1
4868 return ret
4868 return ret
4869
4869
4870 def postincoming(ui, repo, modheads, optupdate, checkout):
4870 def postincoming(ui, repo, modheads, optupdate, checkout):
4871 if modheads == 0:
4871 if modheads == 0:
4872 return
4872 return
4873 if optupdate:
4873 if optupdate:
4874 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4874 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4875 try:
4875 try:
4876 ret = hg.update(repo, checkout)
4876 ret = hg.update(repo, checkout)
4877 except util.Abort, inst:
4877 except util.Abort, inst:
4878 ui.warn(_("not updating: %s\n") % str(inst))
4878 ui.warn(_("not updating: %s\n") % str(inst))
4879 if inst.hint:
4879 if inst.hint:
4880 ui.warn(_("(%s)\n") % inst.hint)
4880 ui.warn(_("(%s)\n") % inst.hint)
4881 return 0
4881 return 0
4882 if not ret and not checkout:
4882 if not ret and not checkout:
4883 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4883 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4884 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4884 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4885 return ret
4885 return ret
4886 if modheads > 1:
4886 if modheads > 1:
4887 currentbranchheads = len(repo.branchheads())
4887 currentbranchheads = len(repo.branchheads())
4888 if currentbranchheads == modheads:
4888 if currentbranchheads == modheads:
4889 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4889 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4890 elif currentbranchheads > 1:
4890 elif currentbranchheads > 1:
4891 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4891 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4892 "merge)\n"))
4892 "merge)\n"))
4893 else:
4893 else:
4894 ui.status(_("(run 'hg heads' to see heads)\n"))
4894 ui.status(_("(run 'hg heads' to see heads)\n"))
4895 else:
4895 else:
4896 ui.status(_("(run 'hg update' to get a working copy)\n"))
4896 ui.status(_("(run 'hg update' to get a working copy)\n"))
4897
4897
4898 @command('^pull',
4898 @command('^pull',
4899 [('u', 'update', None,
4899 [('u', 'update', None,
4900 _('update to new branch head if changesets were pulled')),
4900 _('update to new branch head if changesets were pulled')),
4901 ('f', 'force', None, _('run even when remote repository is unrelated')),
4901 ('f', 'force', None, _('run even when remote repository is unrelated')),
4902 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4902 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4903 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4903 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4904 ('b', 'branch', [], _('a specific branch you would like to pull'),
4904 ('b', 'branch', [], _('a specific branch you would like to pull'),
4905 _('BRANCH')),
4905 _('BRANCH')),
4906 ] + remoteopts,
4906 ] + remoteopts,
4907 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4907 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4908 def pull(ui, repo, source="default", **opts):
4908 def pull(ui, repo, source="default", **opts):
4909 """pull changes from the specified source
4909 """pull changes from the specified source
4910
4910
4911 Pull changes from a remote repository to a local one.
4911 Pull changes from a remote repository to a local one.
4912
4912
4913 This finds all changes from the repository at the specified path
4913 This finds all changes from the repository at the specified path
4914 or URL and adds them to a local repository (the current one unless
4914 or URL and adds them to a local repository (the current one unless
4915 -R is specified). By default, this does not update the copy of the
4915 -R is specified). By default, this does not update the copy of the
4916 project in the working directory.
4916 project in the working directory.
4917
4917
4918 Use :hg:`incoming` if you want to see what would have been added
4918 Use :hg:`incoming` if you want to see what would have been added
4919 by a pull at the time you issued this command. If you then decide
4919 by a pull at the time you issued this command. If you then decide
4920 to add those changes to the repository, you should use :hg:`pull
4920 to add those changes to the repository, you should use :hg:`pull
4921 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4921 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4922
4922
4923 If SOURCE is omitted, the 'default' path will be used.
4923 If SOURCE is omitted, the 'default' path will be used.
4924 See :hg:`help urls` for more information.
4924 See :hg:`help urls` for more information.
4925
4925
4926 Returns 0 on success, 1 if an update had unresolved files.
4926 Returns 0 on success, 1 if an update had unresolved files.
4927 """
4927 """
4928 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4928 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4929 other = hg.peer(repo, opts, source)
4929 other = hg.peer(repo, opts, source)
4930 try:
4930 try:
4931 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4931 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4932 revs, checkout = hg.addbranchrevs(repo, other, branches,
4932 revs, checkout = hg.addbranchrevs(repo, other, branches,
4933 opts.get('rev'))
4933 opts.get('rev'))
4934
4934
4935 remotebookmarks = other.listkeys('bookmarks')
4935 remotebookmarks = other.listkeys('bookmarks')
4936
4936
4937 if opts.get('bookmark'):
4937 if opts.get('bookmark'):
4938 if not revs:
4938 if not revs:
4939 revs = []
4939 revs = []
4940 for b in opts['bookmark']:
4940 for b in opts['bookmark']:
4941 if b not in remotebookmarks:
4941 if b not in remotebookmarks:
4942 raise util.Abort(_('remote bookmark %s not found!') % b)
4942 raise util.Abort(_('remote bookmark %s not found!') % b)
4943 revs.append(remotebookmarks[b])
4943 revs.append(remotebookmarks[b])
4944
4944
4945 if revs:
4945 if revs:
4946 try:
4946 try:
4947 revs = [other.lookup(rev) for rev in revs]
4947 revs = [other.lookup(rev) for rev in revs]
4948 except error.CapabilityError:
4948 except error.CapabilityError:
4949 err = _("other repository doesn't support revision lookup, "
4949 err = _("other repository doesn't support revision lookup, "
4950 "so a rev cannot be specified.")
4950 "so a rev cannot be specified.")
4951 raise util.Abort(err)
4951 raise util.Abort(err)
4952
4952
4953 modheads = exchange.pull(repo, other, heads=revs,
4953 modheads = exchange.pull(repo, other, heads=revs,
4954 force=opts.get('force'),
4954 force=opts.get('force'),
4955 bookmarks=opts.get('bookmark', ())).cgresult
4955 bookmarks=opts.get('bookmark', ())).cgresult
4956 if checkout:
4956 if checkout:
4957 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4957 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4958 repo._subtoppath = source
4958 repo._subtoppath = source
4959 try:
4959 try:
4960 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4960 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4961
4961
4962 finally:
4962 finally:
4963 del repo._subtoppath
4963 del repo._subtoppath
4964
4964
4965 finally:
4965 finally:
4966 other.close()
4966 other.close()
4967 return ret
4967 return ret
4968
4968
4969 @command('^push',
4969 @command('^push',
4970 [('f', 'force', None, _('force push')),
4970 [('f', 'force', None, _('force push')),
4971 ('r', 'rev', [],
4971 ('r', 'rev', [],
4972 _('a changeset intended to be included in the destination'),
4972 _('a changeset intended to be included in the destination'),
4973 _('REV')),
4973 _('REV')),
4974 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4974 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4975 ('b', 'branch', [],
4975 ('b', 'branch', [],
4976 _('a specific branch you would like to push'), _('BRANCH')),
4976 _('a specific branch you would like to push'), _('BRANCH')),
4977 ('', 'new-branch', False, _('allow pushing a new branch')),
4977 ('', 'new-branch', False, _('allow pushing a new branch')),
4978 ] + remoteopts,
4978 ] + remoteopts,
4979 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4979 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4980 def push(ui, repo, dest=None, **opts):
4980 def push(ui, repo, dest=None, **opts):
4981 """push changes to the specified destination
4981 """push changes to the specified destination
4982
4982
4983 Push changesets from the local repository to the specified
4983 Push changesets from the local repository to the specified
4984 destination.
4984 destination.
4985
4985
4986 This operation is symmetrical to pull: it is identical to a pull
4986 This operation is symmetrical to pull: it is identical to a pull
4987 in the destination repository from the current one.
4987 in the destination repository from the current one.
4988
4988
4989 By default, push will not allow creation of new heads at the
4989 By default, push will not allow creation of new heads at the
4990 destination, since multiple heads would make it unclear which head
4990 destination, since multiple heads would make it unclear which head
4991 to use. In this situation, it is recommended to pull and merge
4991 to use. In this situation, it is recommended to pull and merge
4992 before pushing.
4992 before pushing.
4993
4993
4994 Use --new-branch if you want to allow push to create a new named
4994 Use --new-branch if you want to allow push to create a new named
4995 branch that is not present at the destination. This allows you to
4995 branch that is not present at the destination. This allows you to
4996 only create a new branch without forcing other changes.
4996 only create a new branch without forcing other changes.
4997
4997
4998 .. note::
4998 .. note::
4999
4999
5000 Extra care should be taken with the -f/--force option,
5000 Extra care should be taken with the -f/--force option,
5001 which will push all new heads on all branches, an action which will
5001 which will push all new heads on all branches, an action which will
5002 almost always cause confusion for collaborators.
5002 almost always cause confusion for collaborators.
5003
5003
5004 If -r/--rev is used, the specified revision and all its ancestors
5004 If -r/--rev is used, the specified revision and all its ancestors
5005 will be pushed to the remote repository.
5005 will be pushed to the remote repository.
5006
5006
5007 If -B/--bookmark is used, the specified bookmarked revision, its
5007 If -B/--bookmark is used, the specified bookmarked revision, its
5008 ancestors, and the bookmark will be pushed to the remote
5008 ancestors, and the bookmark will be pushed to the remote
5009 repository.
5009 repository.
5010
5010
5011 Please see :hg:`help urls` for important details about ``ssh://``
5011 Please see :hg:`help urls` for important details about ``ssh://``
5012 URLs. If DESTINATION is omitted, a default path will be used.
5012 URLs. If DESTINATION is omitted, a default path will be used.
5013
5013
5014 Returns 0 if push was successful, 1 if nothing to push.
5014 Returns 0 if push was successful, 1 if nothing to push.
5015 """
5015 """
5016
5016
5017 if opts.get('bookmark'):
5017 if opts.get('bookmark'):
5018 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5018 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5019 for b in opts['bookmark']:
5019 for b in opts['bookmark']:
5020 # translate -B options to -r so changesets get pushed
5020 # translate -B options to -r so changesets get pushed
5021 if b in repo._bookmarks:
5021 if b in repo._bookmarks:
5022 opts.setdefault('rev', []).append(b)
5022 opts.setdefault('rev', []).append(b)
5023 else:
5023 else:
5024 # if we try to push a deleted bookmark, translate it to null
5024 # if we try to push a deleted bookmark, translate it to null
5025 # this lets simultaneous -r, -b options continue working
5025 # this lets simultaneous -r, -b options continue working
5026 opts.setdefault('rev', []).append("null")
5026 opts.setdefault('rev', []).append("null")
5027
5027
5028 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5028 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5029 dest, branches = hg.parseurl(dest, opts.get('branch'))
5029 dest, branches = hg.parseurl(dest, opts.get('branch'))
5030 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5030 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5031 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5031 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5032 try:
5032 try:
5033 other = hg.peer(repo, opts, dest)
5033 other = hg.peer(repo, opts, dest)
5034 except error.RepoError:
5034 except error.RepoError:
5035 if dest == "default-push":
5035 if dest == "default-push":
5036 raise util.Abort(_("default repository not configured!"),
5036 raise util.Abort(_("default repository not configured!"),
5037 hint=_('see the "path" section in "hg help config"'))
5037 hint=_('see the "path" section in "hg help config"'))
5038 else:
5038 else:
5039 raise
5039 raise
5040
5040
5041 if revs:
5041 if revs:
5042 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5042 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5043
5043
5044 repo._subtoppath = dest
5044 repo._subtoppath = dest
5045 try:
5045 try:
5046 # push subrepos depth-first for coherent ordering
5046 # push subrepos depth-first for coherent ordering
5047 c = repo['']
5047 c = repo['']
5048 subs = c.substate # only repos that are committed
5048 subs = c.substate # only repos that are committed
5049 for s in sorted(subs):
5049 for s in sorted(subs):
5050 result = c.sub(s).push(opts)
5050 result = c.sub(s).push(opts)
5051 if result == 0:
5051 if result == 0:
5052 return not result
5052 return not result
5053 finally:
5053 finally:
5054 del repo._subtoppath
5054 del repo._subtoppath
5055 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5055 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5056 newbranch=opts.get('new_branch'),
5056 newbranch=opts.get('new_branch'),
5057 bookmarks=opts.get('bookmark', ()))
5057 bookmarks=opts.get('bookmark', ()))
5058
5058
5059 result = not pushop.cgresult
5059 result = not pushop.cgresult
5060
5060
5061 if pushop.bkresult is not None:
5061 if pushop.bkresult is not None:
5062 if pushop.bkresult == 2:
5062 if pushop.bkresult == 2:
5063 result = 2
5063 result = 2
5064 elif not result and pushop.bkresult:
5064 elif not result and pushop.bkresult:
5065 result = 2
5065 result = 2
5066
5066
5067 return result
5067 return result
5068
5068
5069 @command('recover', [])
5069 @command('recover', [])
5070 def recover(ui, repo):
5070 def recover(ui, repo):
5071 """roll back an interrupted transaction
5071 """roll back an interrupted transaction
5072
5072
5073 Recover from an interrupted commit or pull.
5073 Recover from an interrupted commit or pull.
5074
5074
5075 This command tries to fix the repository status after an
5075 This command tries to fix the repository status after an
5076 interrupted operation. It should only be necessary when Mercurial
5076 interrupted operation. It should only be necessary when Mercurial
5077 suggests it.
5077 suggests it.
5078
5078
5079 Returns 0 if successful, 1 if nothing to recover or verify fails.
5079 Returns 0 if successful, 1 if nothing to recover or verify fails.
5080 """
5080 """
5081 if repo.recover():
5081 if repo.recover():
5082 return hg.verify(repo)
5082 return hg.verify(repo)
5083 return 1
5083 return 1
5084
5084
5085 @command('^remove|rm',
5085 @command('^remove|rm',
5086 [('A', 'after', None, _('record delete for missing files')),
5086 [('A', 'after', None, _('record delete for missing files')),
5087 ('f', 'force', None,
5087 ('f', 'force', None,
5088 _('remove (and delete) file even if added or modified')),
5088 _('remove (and delete) file even if added or modified')),
5089 ] + walkopts,
5089 ] + subrepoopts + walkopts,
5090 _('[OPTION]... FILE...'),
5090 _('[OPTION]... FILE...'),
5091 inferrepo=True)
5091 inferrepo=True)
5092 def remove(ui, repo, *pats, **opts):
5092 def remove(ui, repo, *pats, **opts):
5093 """remove the specified files on the next commit
5093 """remove the specified files on the next commit
5094
5094
5095 Schedule the indicated files for removal from the current branch.
5095 Schedule the indicated files for removal from the current branch.
5096
5096
5097 This command schedules the files to be removed at the next commit.
5097 This command schedules the files to be removed at the next commit.
5098 To undo a remove before that, see :hg:`revert`. To undo added
5098 To undo a remove before that, see :hg:`revert`. To undo added
5099 files, see :hg:`forget`.
5099 files, see :hg:`forget`.
5100
5100
5101 .. container:: verbose
5101 .. container:: verbose
5102
5102
5103 -A/--after can be used to remove only files that have already
5103 -A/--after can be used to remove only files that have already
5104 been deleted, -f/--force can be used to force deletion, and -Af
5104 been deleted, -f/--force can be used to force deletion, and -Af
5105 can be used to remove files from the next revision without
5105 can be used to remove files from the next revision without
5106 deleting them from the working directory.
5106 deleting them from the working directory.
5107
5107
5108 The following table details the behavior of remove for different
5108 The following table details the behavior of remove for different
5109 file states (columns) and option combinations (rows). The file
5109 file states (columns) and option combinations (rows). The file
5110 states are Added [A], Clean [C], Modified [M] and Missing [!]
5110 states are Added [A], Clean [C], Modified [M] and Missing [!]
5111 (as reported by :hg:`status`). The actions are Warn, Remove
5111 (as reported by :hg:`status`). The actions are Warn, Remove
5112 (from branch) and Delete (from disk):
5112 (from branch) and Delete (from disk):
5113
5113
5114 ========= == == == ==
5114 ========= == == == ==
5115 opt/state A C M !
5115 opt/state A C M !
5116 ========= == == == ==
5116 ========= == == == ==
5117 none W RD W R
5117 none W RD W R
5118 -f R RD RD R
5118 -f R RD RD R
5119 -A W W W R
5119 -A W W W R
5120 -Af R R R R
5120 -Af R R R R
5121 ========= == == == ==
5121 ========= == == == ==
5122
5122
5123 Note that remove never deletes files in Added [A] state from the
5123 Note that remove never deletes files in Added [A] state from the
5124 working directory, not even if option --force is specified.
5124 working directory, not even if option --force is specified.
5125
5125
5126 Returns 0 on success, 1 if any warnings encountered.
5126 Returns 0 on success, 1 if any warnings encountered.
5127 """
5127 """
5128
5128
5129 after, force = opts.get('after'), opts.get('force')
5129 after, force = opts.get('after'), opts.get('force')
5130 if not pats and not after:
5130 if not pats and not after:
5131 raise util.Abort(_('no files specified'))
5131 raise util.Abort(_('no files specified'))
5132
5132
5133 m = scmutil.match(repo[None], pats, opts)
5133 m = scmutil.match(repo[None], pats, opts)
5134 return cmdutil.remove(ui, repo, m, after, force)
5134 subrepos = opts.get('subrepos')
5135 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5135
5136
5136 @command('rename|move|mv',
5137 @command('rename|move|mv',
5137 [('A', 'after', None, _('record a rename that has already occurred')),
5138 [('A', 'after', None, _('record a rename that has already occurred')),
5138 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5139 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5139 ] + walkopts + dryrunopts,
5140 ] + walkopts + dryrunopts,
5140 _('[OPTION]... SOURCE... DEST'))
5141 _('[OPTION]... SOURCE... DEST'))
5141 def rename(ui, repo, *pats, **opts):
5142 def rename(ui, repo, *pats, **opts):
5142 """rename files; equivalent of copy + remove
5143 """rename files; equivalent of copy + remove
5143
5144
5144 Mark dest as copies of sources; mark sources for deletion. If dest
5145 Mark dest as copies of sources; mark sources for deletion. If dest
5145 is a directory, copies are put in that directory. If dest is a
5146 is a directory, copies are put in that directory. If dest is a
5146 file, there can only be one source.
5147 file, there can only be one source.
5147
5148
5148 By default, this command copies the contents of files as they
5149 By default, this command copies the contents of files as they
5149 exist in the working directory. If invoked with -A/--after, the
5150 exist in the working directory. If invoked with -A/--after, the
5150 operation is recorded, but no copying is performed.
5151 operation is recorded, but no copying is performed.
5151
5152
5152 This command takes effect at the next commit. To undo a rename
5153 This command takes effect at the next commit. To undo a rename
5153 before that, see :hg:`revert`.
5154 before that, see :hg:`revert`.
5154
5155
5155 Returns 0 on success, 1 if errors are encountered.
5156 Returns 0 on success, 1 if errors are encountered.
5156 """
5157 """
5157 wlock = repo.wlock(False)
5158 wlock = repo.wlock(False)
5158 try:
5159 try:
5159 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5160 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5160 finally:
5161 finally:
5161 wlock.release()
5162 wlock.release()
5162
5163
5163 @command('resolve',
5164 @command('resolve',
5164 [('a', 'all', None, _('select all unresolved files')),
5165 [('a', 'all', None, _('select all unresolved files')),
5165 ('l', 'list', None, _('list state of files needing merge')),
5166 ('l', 'list', None, _('list state of files needing merge')),
5166 ('m', 'mark', None, _('mark files as resolved')),
5167 ('m', 'mark', None, _('mark files as resolved')),
5167 ('u', 'unmark', None, _('mark files as unresolved')),
5168 ('u', 'unmark', None, _('mark files as unresolved')),
5168 ('n', 'no-status', None, _('hide status prefix'))]
5169 ('n', 'no-status', None, _('hide status prefix'))]
5169 + mergetoolopts + walkopts,
5170 + mergetoolopts + walkopts,
5170 _('[OPTION]... [FILE]...'),
5171 _('[OPTION]... [FILE]...'),
5171 inferrepo=True)
5172 inferrepo=True)
5172 def resolve(ui, repo, *pats, **opts):
5173 def resolve(ui, repo, *pats, **opts):
5173 """redo merges or set/view the merge status of files
5174 """redo merges or set/view the merge status of files
5174
5175
5175 Merges with unresolved conflicts are often the result of
5176 Merges with unresolved conflicts are often the result of
5176 non-interactive merging using the ``internal:merge`` configuration
5177 non-interactive merging using the ``internal:merge`` configuration
5177 setting, or a command-line merge tool like ``diff3``. The resolve
5178 setting, or a command-line merge tool like ``diff3``. The resolve
5178 command is used to manage the files involved in a merge, after
5179 command is used to manage the files involved in a merge, after
5179 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5180 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5180 working directory must have two parents). See :hg:`help
5181 working directory must have two parents). See :hg:`help
5181 merge-tools` for information on configuring merge tools.
5182 merge-tools` for information on configuring merge tools.
5182
5183
5183 The resolve command can be used in the following ways:
5184 The resolve command can be used in the following ways:
5184
5185
5185 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5186 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5186 files, discarding any previous merge attempts. Re-merging is not
5187 files, discarding any previous merge attempts. Re-merging is not
5187 performed for files already marked as resolved. Use ``--all/-a``
5188 performed for files already marked as resolved. Use ``--all/-a``
5188 to select all unresolved files. ``--tool`` can be used to specify
5189 to select all unresolved files. ``--tool`` can be used to specify
5189 the merge tool used for the given files. It overrides the HGMERGE
5190 the merge tool used for the given files. It overrides the HGMERGE
5190 environment variable and your configuration files. Previous file
5191 environment variable and your configuration files. Previous file
5191 contents are saved with a ``.orig`` suffix.
5192 contents are saved with a ``.orig`` suffix.
5192
5193
5193 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5194 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5194 (e.g. after having manually fixed-up the files). The default is
5195 (e.g. after having manually fixed-up the files). The default is
5195 to mark all unresolved files.
5196 to mark all unresolved files.
5196
5197
5197 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5198 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5198 default is to mark all resolved files.
5199 default is to mark all resolved files.
5199
5200
5200 - :hg:`resolve -l`: list files which had or still have conflicts.
5201 - :hg:`resolve -l`: list files which had or still have conflicts.
5201 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5202 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5202
5203
5203 Note that Mercurial will not let you commit files with unresolved
5204 Note that Mercurial will not let you commit files with unresolved
5204 merge conflicts. You must use :hg:`resolve -m ...` before you can
5205 merge conflicts. You must use :hg:`resolve -m ...` before you can
5205 commit after a conflicting merge.
5206 commit after a conflicting merge.
5206
5207
5207 Returns 0 on success, 1 if any files fail a resolve attempt.
5208 Returns 0 on success, 1 if any files fail a resolve attempt.
5208 """
5209 """
5209
5210
5210 all, mark, unmark, show, nostatus = \
5211 all, mark, unmark, show, nostatus = \
5211 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5212 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5212
5213
5213 if (show and (mark or unmark)) or (mark and unmark):
5214 if (show and (mark or unmark)) or (mark and unmark):
5214 raise util.Abort(_("too many options specified"))
5215 raise util.Abort(_("too many options specified"))
5215 if pats and all:
5216 if pats and all:
5216 raise util.Abort(_("can't specify --all and patterns"))
5217 raise util.Abort(_("can't specify --all and patterns"))
5217 if not (all or pats or show or mark or unmark):
5218 if not (all or pats or show or mark or unmark):
5218 raise util.Abort(_('no files or directories specified'),
5219 raise util.Abort(_('no files or directories specified'),
5219 hint=('use --all to remerge all files'))
5220 hint=('use --all to remerge all files'))
5220
5221
5221 wlock = repo.wlock()
5222 wlock = repo.wlock()
5222 try:
5223 try:
5223 ms = mergemod.mergestate(repo)
5224 ms = mergemod.mergestate(repo)
5224
5225
5225 if not (ms.active() or repo.dirstate.p2() != nullid) and not show:
5226 if not (ms.active() or repo.dirstate.p2() != nullid) and not show:
5226 raise util.Abort(
5227 raise util.Abort(
5227 _('resolve command not applicable when not merging'))
5228 _('resolve command not applicable when not merging'))
5228
5229
5229 m = scmutil.match(repo[None], pats, opts)
5230 m = scmutil.match(repo[None], pats, opts)
5230 ret = 0
5231 ret = 0
5231 didwork = False
5232 didwork = False
5232
5233
5233 for f in ms:
5234 for f in ms:
5234 if not m(f):
5235 if not m(f):
5235 continue
5236 continue
5236
5237
5237 didwork = True
5238 didwork = True
5238
5239
5239 if show:
5240 if show:
5240 if nostatus:
5241 if nostatus:
5241 ui.write("%s\n" % f)
5242 ui.write("%s\n" % f)
5242 else:
5243 else:
5243 ui.write("%s %s\n" % (ms[f].upper(), f),
5244 ui.write("%s %s\n" % (ms[f].upper(), f),
5244 label='resolve.' +
5245 label='resolve.' +
5245 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5246 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5246 elif mark:
5247 elif mark:
5247 ms.mark(f, "r")
5248 ms.mark(f, "r")
5248 elif unmark:
5249 elif unmark:
5249 ms.mark(f, "u")
5250 ms.mark(f, "u")
5250 else:
5251 else:
5251 wctx = repo[None]
5252 wctx = repo[None]
5252
5253
5253 # backup pre-resolve (merge uses .orig for its own purposes)
5254 # backup pre-resolve (merge uses .orig for its own purposes)
5254 a = repo.wjoin(f)
5255 a = repo.wjoin(f)
5255 util.copyfile(a, a + ".resolve")
5256 util.copyfile(a, a + ".resolve")
5256
5257
5257 try:
5258 try:
5258 # resolve file
5259 # resolve file
5259 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5260 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5260 'resolve')
5261 'resolve')
5261 if ms.resolve(f, wctx):
5262 if ms.resolve(f, wctx):
5262 ret = 1
5263 ret = 1
5263 finally:
5264 finally:
5264 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5265 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5265 ms.commit()
5266 ms.commit()
5266
5267
5267 # replace filemerge's .orig file with our resolve file
5268 # replace filemerge's .orig file with our resolve file
5268 util.rename(a + ".resolve", a + ".orig")
5269 util.rename(a + ".resolve", a + ".orig")
5269
5270
5270 ms.commit()
5271 ms.commit()
5271
5272
5272 if not didwork and pats:
5273 if not didwork and pats:
5273 ui.warn(_("arguments do not match paths that need resolving\n"))
5274 ui.warn(_("arguments do not match paths that need resolving\n"))
5274
5275
5275 finally:
5276 finally:
5276 wlock.release()
5277 wlock.release()
5277
5278
5278 # Nudge users into finishing an unfinished operation. We don't print
5279 # Nudge users into finishing an unfinished operation. We don't print
5279 # this with the list/show operation because we want list/show to remain
5280 # this with the list/show operation because we want list/show to remain
5280 # machine readable.
5281 # machine readable.
5281 if not list(ms.unresolved()) and not show:
5282 if not list(ms.unresolved()) and not show:
5282 ui.status(_('(no more unresolved files)\n'))
5283 ui.status(_('(no more unresolved files)\n'))
5283
5284
5284 return ret
5285 return ret
5285
5286
5286 @command('revert',
5287 @command('revert',
5287 [('a', 'all', None, _('revert all changes when no arguments given')),
5288 [('a', 'all', None, _('revert all changes when no arguments given')),
5288 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5289 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5289 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5290 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5290 ('C', 'no-backup', None, _('do not save backup copies of files')),
5291 ('C', 'no-backup', None, _('do not save backup copies of files')),
5291 ] + walkopts + dryrunopts,
5292 ] + walkopts + dryrunopts,
5292 _('[OPTION]... [-r REV] [NAME]...'))
5293 _('[OPTION]... [-r REV] [NAME]...'))
5293 def revert(ui, repo, *pats, **opts):
5294 def revert(ui, repo, *pats, **opts):
5294 """restore files to their checkout state
5295 """restore files to their checkout state
5295
5296
5296 .. note::
5297 .. note::
5297
5298
5298 To check out earlier revisions, you should use :hg:`update REV`.
5299 To check out earlier revisions, you should use :hg:`update REV`.
5299 To cancel an uncommitted merge (and lose your changes),
5300 To cancel an uncommitted merge (and lose your changes),
5300 use :hg:`update --clean .`.
5301 use :hg:`update --clean .`.
5301
5302
5302 With no revision specified, revert the specified files or directories
5303 With no revision specified, revert the specified files or directories
5303 to the contents they had in the parent of the working directory.
5304 to the contents they had in the parent of the working directory.
5304 This restores the contents of files to an unmodified
5305 This restores the contents of files to an unmodified
5305 state and unschedules adds, removes, copies, and renames. If the
5306 state and unschedules adds, removes, copies, and renames. If the
5306 working directory has two parents, you must explicitly specify a
5307 working directory has two parents, you must explicitly specify a
5307 revision.
5308 revision.
5308
5309
5309 Using the -r/--rev or -d/--date options, revert the given files or
5310 Using the -r/--rev or -d/--date options, revert the given files or
5310 directories to their states as of a specific revision. Because
5311 directories to their states as of a specific revision. Because
5311 revert does not change the working directory parents, this will
5312 revert does not change the working directory parents, this will
5312 cause these files to appear modified. This can be helpful to "back
5313 cause these files to appear modified. This can be helpful to "back
5313 out" some or all of an earlier change. See :hg:`backout` for a
5314 out" some or all of an earlier change. See :hg:`backout` for a
5314 related method.
5315 related method.
5315
5316
5316 Modified files are saved with a .orig suffix before reverting.
5317 Modified files are saved with a .orig suffix before reverting.
5317 To disable these backups, use --no-backup.
5318 To disable these backups, use --no-backup.
5318
5319
5319 See :hg:`help dates` for a list of formats valid for -d/--date.
5320 See :hg:`help dates` for a list of formats valid for -d/--date.
5320
5321
5321 Returns 0 on success.
5322 Returns 0 on success.
5322 """
5323 """
5323
5324
5324 if opts.get("date"):
5325 if opts.get("date"):
5325 if opts.get("rev"):
5326 if opts.get("rev"):
5326 raise util.Abort(_("you can't specify a revision and a date"))
5327 raise util.Abort(_("you can't specify a revision and a date"))
5327 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5328 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5328
5329
5329 parent, p2 = repo.dirstate.parents()
5330 parent, p2 = repo.dirstate.parents()
5330 if not opts.get('rev') and p2 != nullid:
5331 if not opts.get('rev') and p2 != nullid:
5331 # revert after merge is a trap for new users (issue2915)
5332 # revert after merge is a trap for new users (issue2915)
5332 raise util.Abort(_('uncommitted merge with no revision specified'),
5333 raise util.Abort(_('uncommitted merge with no revision specified'),
5333 hint=_('use "hg update" or see "hg help revert"'))
5334 hint=_('use "hg update" or see "hg help revert"'))
5334
5335
5335 ctx = scmutil.revsingle(repo, opts.get('rev'))
5336 ctx = scmutil.revsingle(repo, opts.get('rev'))
5336
5337
5337 if not pats and not opts.get('all'):
5338 if not pats and not opts.get('all'):
5338 msg = _("no files or directories specified")
5339 msg = _("no files or directories specified")
5339 if p2 != nullid:
5340 if p2 != nullid:
5340 hint = _("uncommitted merge, use --all to discard all changes,"
5341 hint = _("uncommitted merge, use --all to discard all changes,"
5341 " or 'hg update -C .' to abort the merge")
5342 " or 'hg update -C .' to abort the merge")
5342 raise util.Abort(msg, hint=hint)
5343 raise util.Abort(msg, hint=hint)
5343 dirty = util.any(repo.status())
5344 dirty = util.any(repo.status())
5344 node = ctx.node()
5345 node = ctx.node()
5345 if node != parent:
5346 if node != parent:
5346 if dirty:
5347 if dirty:
5347 hint = _("uncommitted changes, use --all to discard all"
5348 hint = _("uncommitted changes, use --all to discard all"
5348 " changes, or 'hg update %s' to update") % ctx.rev()
5349 " changes, or 'hg update %s' to update") % ctx.rev()
5349 else:
5350 else:
5350 hint = _("use --all to revert all files,"
5351 hint = _("use --all to revert all files,"
5351 " or 'hg update %s' to update") % ctx.rev()
5352 " or 'hg update %s' to update") % ctx.rev()
5352 elif dirty:
5353 elif dirty:
5353 hint = _("uncommitted changes, use --all to discard all changes")
5354 hint = _("uncommitted changes, use --all to discard all changes")
5354 else:
5355 else:
5355 hint = _("use --all to revert all files")
5356 hint = _("use --all to revert all files")
5356 raise util.Abort(msg, hint=hint)
5357 raise util.Abort(msg, hint=hint)
5357
5358
5358 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5359 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5359
5360
5360 @command('rollback', dryrunopts +
5361 @command('rollback', dryrunopts +
5361 [('f', 'force', False, _('ignore safety measures'))])
5362 [('f', 'force', False, _('ignore safety measures'))])
5362 def rollback(ui, repo, **opts):
5363 def rollback(ui, repo, **opts):
5363 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5364 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5364
5365
5365 Please use :hg:`commit --amend` instead of rollback to correct
5366 Please use :hg:`commit --amend` instead of rollback to correct
5366 mistakes in the last commit.
5367 mistakes in the last commit.
5367
5368
5368 This command should be used with care. There is only one level of
5369 This command should be used with care. There is only one level of
5369 rollback, and there is no way to undo a rollback. It will also
5370 rollback, and there is no way to undo a rollback. It will also
5370 restore the dirstate at the time of the last transaction, losing
5371 restore the dirstate at the time of the last transaction, losing
5371 any dirstate changes since that time. This command does not alter
5372 any dirstate changes since that time. This command does not alter
5372 the working directory.
5373 the working directory.
5373
5374
5374 Transactions are used to encapsulate the effects of all commands
5375 Transactions are used to encapsulate the effects of all commands
5375 that create new changesets or propagate existing changesets into a
5376 that create new changesets or propagate existing changesets into a
5376 repository.
5377 repository.
5377
5378
5378 .. container:: verbose
5379 .. container:: verbose
5379
5380
5380 For example, the following commands are transactional, and their
5381 For example, the following commands are transactional, and their
5381 effects can be rolled back:
5382 effects can be rolled back:
5382
5383
5383 - commit
5384 - commit
5384 - import
5385 - import
5385 - pull
5386 - pull
5386 - push (with this repository as the destination)
5387 - push (with this repository as the destination)
5387 - unbundle
5388 - unbundle
5388
5389
5389 To avoid permanent data loss, rollback will refuse to rollback a
5390 To avoid permanent data loss, rollback will refuse to rollback a
5390 commit transaction if it isn't checked out. Use --force to
5391 commit transaction if it isn't checked out. Use --force to
5391 override this protection.
5392 override this protection.
5392
5393
5393 This command is not intended for use on public repositories. Once
5394 This command is not intended for use on public repositories. Once
5394 changes are visible for pull by other users, rolling a transaction
5395 changes are visible for pull by other users, rolling a transaction
5395 back locally is ineffective (someone else may already have pulled
5396 back locally is ineffective (someone else may already have pulled
5396 the changes). Furthermore, a race is possible with readers of the
5397 the changes). Furthermore, a race is possible with readers of the
5397 repository; for example an in-progress pull from the repository
5398 repository; for example an in-progress pull from the repository
5398 may fail if a rollback is performed.
5399 may fail if a rollback is performed.
5399
5400
5400 Returns 0 on success, 1 if no rollback data is available.
5401 Returns 0 on success, 1 if no rollback data is available.
5401 """
5402 """
5402 return repo.rollback(dryrun=opts.get('dry_run'),
5403 return repo.rollback(dryrun=opts.get('dry_run'),
5403 force=opts.get('force'))
5404 force=opts.get('force'))
5404
5405
5405 @command('root', [])
5406 @command('root', [])
5406 def root(ui, repo):
5407 def root(ui, repo):
5407 """print the root (top) of the current working directory
5408 """print the root (top) of the current working directory
5408
5409
5409 Print the root directory of the current repository.
5410 Print the root directory of the current repository.
5410
5411
5411 Returns 0 on success.
5412 Returns 0 on success.
5412 """
5413 """
5413 ui.write(repo.root + "\n")
5414 ui.write(repo.root + "\n")
5414
5415
5415 @command('^serve',
5416 @command('^serve',
5416 [('A', 'accesslog', '', _('name of access log file to write to'),
5417 [('A', 'accesslog', '', _('name of access log file to write to'),
5417 _('FILE')),
5418 _('FILE')),
5418 ('d', 'daemon', None, _('run server in background')),
5419 ('d', 'daemon', None, _('run server in background')),
5419 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5420 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5420 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5421 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5421 # use string type, then we can check if something was passed
5422 # use string type, then we can check if something was passed
5422 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5423 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5423 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5424 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5424 _('ADDR')),
5425 _('ADDR')),
5425 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5426 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5426 _('PREFIX')),
5427 _('PREFIX')),
5427 ('n', 'name', '',
5428 ('n', 'name', '',
5428 _('name to show in web pages (default: working directory)'), _('NAME')),
5429 _('name to show in web pages (default: working directory)'), _('NAME')),
5429 ('', 'web-conf', '',
5430 ('', 'web-conf', '',
5430 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5431 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5431 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5432 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5432 _('FILE')),
5433 _('FILE')),
5433 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5434 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5434 ('', 'stdio', None, _('for remote clients')),
5435 ('', 'stdio', None, _('for remote clients')),
5435 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5436 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5436 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5437 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5437 ('', 'style', '', _('template style to use'), _('STYLE')),
5438 ('', 'style', '', _('template style to use'), _('STYLE')),
5438 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5439 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5439 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5440 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5440 _('[OPTION]...'),
5441 _('[OPTION]...'),
5441 optionalrepo=True)
5442 optionalrepo=True)
5442 def serve(ui, repo, **opts):
5443 def serve(ui, repo, **opts):
5443 """start stand-alone webserver
5444 """start stand-alone webserver
5444
5445
5445 Start a local HTTP repository browser and pull server. You can use
5446 Start a local HTTP repository browser and pull server. You can use
5446 this for ad-hoc sharing and browsing of repositories. It is
5447 this for ad-hoc sharing and browsing of repositories. It is
5447 recommended to use a real web server to serve a repository for
5448 recommended to use a real web server to serve a repository for
5448 longer periods of time.
5449 longer periods of time.
5449
5450
5450 Please note that the server does not implement access control.
5451 Please note that the server does not implement access control.
5451 This means that, by default, anybody can read from the server and
5452 This means that, by default, anybody can read from the server and
5452 nobody can write to it by default. Set the ``web.allow_push``
5453 nobody can write to it by default. Set the ``web.allow_push``
5453 option to ``*`` to allow everybody to push to the server. You
5454 option to ``*`` to allow everybody to push to the server. You
5454 should use a real web server if you need to authenticate users.
5455 should use a real web server if you need to authenticate users.
5455
5456
5456 By default, the server logs accesses to stdout and errors to
5457 By default, the server logs accesses to stdout and errors to
5457 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5458 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5458 files.
5459 files.
5459
5460
5460 To have the server choose a free port number to listen on, specify
5461 To have the server choose a free port number to listen on, specify
5461 a port number of 0; in this case, the server will print the port
5462 a port number of 0; in this case, the server will print the port
5462 number it uses.
5463 number it uses.
5463
5464
5464 Returns 0 on success.
5465 Returns 0 on success.
5465 """
5466 """
5466
5467
5467 if opts["stdio"] and opts["cmdserver"]:
5468 if opts["stdio"] and opts["cmdserver"]:
5468 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5469 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5469
5470
5470 if opts["stdio"]:
5471 if opts["stdio"]:
5471 if repo is None:
5472 if repo is None:
5472 raise error.RepoError(_("there is no Mercurial repository here"
5473 raise error.RepoError(_("there is no Mercurial repository here"
5473 " (.hg not found)"))
5474 " (.hg not found)"))
5474 s = sshserver.sshserver(ui, repo)
5475 s = sshserver.sshserver(ui, repo)
5475 s.serve_forever()
5476 s.serve_forever()
5476
5477
5477 if opts["cmdserver"]:
5478 if opts["cmdserver"]:
5478 service = commandserver.createservice(ui, repo, opts)
5479 service = commandserver.createservice(ui, repo, opts)
5479 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5480 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5480
5481
5481 # this way we can check if something was given in the command-line
5482 # this way we can check if something was given in the command-line
5482 if opts.get('port'):
5483 if opts.get('port'):
5483 opts['port'] = util.getport(opts.get('port'))
5484 opts['port'] = util.getport(opts.get('port'))
5484
5485
5485 baseui = repo and repo.baseui or ui
5486 baseui = repo and repo.baseui or ui
5486 optlist = ("name templates style address port prefix ipv6"
5487 optlist = ("name templates style address port prefix ipv6"
5487 " accesslog errorlog certificate encoding")
5488 " accesslog errorlog certificate encoding")
5488 for o in optlist.split():
5489 for o in optlist.split():
5489 val = opts.get(o, '')
5490 val = opts.get(o, '')
5490 if val in (None, ''): # should check against default options instead
5491 if val in (None, ''): # should check against default options instead
5491 continue
5492 continue
5492 baseui.setconfig("web", o, val, 'serve')
5493 baseui.setconfig("web", o, val, 'serve')
5493 if repo and repo.ui != baseui:
5494 if repo and repo.ui != baseui:
5494 repo.ui.setconfig("web", o, val, 'serve')
5495 repo.ui.setconfig("web", o, val, 'serve')
5495
5496
5496 o = opts.get('web_conf') or opts.get('webdir_conf')
5497 o = opts.get('web_conf') or opts.get('webdir_conf')
5497 if not o:
5498 if not o:
5498 if not repo:
5499 if not repo:
5499 raise error.RepoError(_("there is no Mercurial repository"
5500 raise error.RepoError(_("there is no Mercurial repository"
5500 " here (.hg not found)"))
5501 " here (.hg not found)"))
5501 o = repo
5502 o = repo
5502
5503
5503 app = hgweb.hgweb(o, baseui=baseui)
5504 app = hgweb.hgweb(o, baseui=baseui)
5504 service = httpservice(ui, app, opts)
5505 service = httpservice(ui, app, opts)
5505 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5506 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5506
5507
5507 class httpservice(object):
5508 class httpservice(object):
5508 def __init__(self, ui, app, opts):
5509 def __init__(self, ui, app, opts):
5509 self.ui = ui
5510 self.ui = ui
5510 self.app = app
5511 self.app = app
5511 self.opts = opts
5512 self.opts = opts
5512
5513
5513 def init(self):
5514 def init(self):
5514 util.setsignalhandler()
5515 util.setsignalhandler()
5515 self.httpd = hgweb_server.create_server(self.ui, self.app)
5516 self.httpd = hgweb_server.create_server(self.ui, self.app)
5516
5517
5517 if self.opts['port'] and not self.ui.verbose:
5518 if self.opts['port'] and not self.ui.verbose:
5518 return
5519 return
5519
5520
5520 if self.httpd.prefix:
5521 if self.httpd.prefix:
5521 prefix = self.httpd.prefix.strip('/') + '/'
5522 prefix = self.httpd.prefix.strip('/') + '/'
5522 else:
5523 else:
5523 prefix = ''
5524 prefix = ''
5524
5525
5525 port = ':%d' % self.httpd.port
5526 port = ':%d' % self.httpd.port
5526 if port == ':80':
5527 if port == ':80':
5527 port = ''
5528 port = ''
5528
5529
5529 bindaddr = self.httpd.addr
5530 bindaddr = self.httpd.addr
5530 if bindaddr == '0.0.0.0':
5531 if bindaddr == '0.0.0.0':
5531 bindaddr = '*'
5532 bindaddr = '*'
5532 elif ':' in bindaddr: # IPv6
5533 elif ':' in bindaddr: # IPv6
5533 bindaddr = '[%s]' % bindaddr
5534 bindaddr = '[%s]' % bindaddr
5534
5535
5535 fqaddr = self.httpd.fqaddr
5536 fqaddr = self.httpd.fqaddr
5536 if ':' in fqaddr:
5537 if ':' in fqaddr:
5537 fqaddr = '[%s]' % fqaddr
5538 fqaddr = '[%s]' % fqaddr
5538 if self.opts['port']:
5539 if self.opts['port']:
5539 write = self.ui.status
5540 write = self.ui.status
5540 else:
5541 else:
5541 write = self.ui.write
5542 write = self.ui.write
5542 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5543 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5543 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5544 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5544 self.ui.flush() # avoid buffering of status message
5545 self.ui.flush() # avoid buffering of status message
5545
5546
5546 def run(self):
5547 def run(self):
5547 self.httpd.serve_forever()
5548 self.httpd.serve_forever()
5548
5549
5549
5550
5550 @command('^status|st',
5551 @command('^status|st',
5551 [('A', 'all', None, _('show status of all files')),
5552 [('A', 'all', None, _('show status of all files')),
5552 ('m', 'modified', None, _('show only modified files')),
5553 ('m', 'modified', None, _('show only modified files')),
5553 ('a', 'added', None, _('show only added files')),
5554 ('a', 'added', None, _('show only added files')),
5554 ('r', 'removed', None, _('show only removed files')),
5555 ('r', 'removed', None, _('show only removed files')),
5555 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5556 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5556 ('c', 'clean', None, _('show only files without changes')),
5557 ('c', 'clean', None, _('show only files without changes')),
5557 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5558 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5558 ('i', 'ignored', None, _('show only ignored files')),
5559 ('i', 'ignored', None, _('show only ignored files')),
5559 ('n', 'no-status', None, _('hide status prefix')),
5560 ('n', 'no-status', None, _('hide status prefix')),
5560 ('C', 'copies', None, _('show source of copied files')),
5561 ('C', 'copies', None, _('show source of copied files')),
5561 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5562 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5562 ('', 'rev', [], _('show difference from revision'), _('REV')),
5563 ('', 'rev', [], _('show difference from revision'), _('REV')),
5563 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5564 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5564 ] + walkopts + subrepoopts + formatteropts,
5565 ] + walkopts + subrepoopts + formatteropts,
5565 _('[OPTION]... [FILE]...'),
5566 _('[OPTION]... [FILE]...'),
5566 inferrepo=True)
5567 inferrepo=True)
5567 def status(ui, repo, *pats, **opts):
5568 def status(ui, repo, *pats, **opts):
5568 """show changed files in the working directory
5569 """show changed files in the working directory
5569
5570
5570 Show status of files in the repository. If names are given, only
5571 Show status of files in the repository. If names are given, only
5571 files that match are shown. Files that are clean or ignored or
5572 files that match are shown. Files that are clean or ignored or
5572 the source of a copy/move operation, are not listed unless
5573 the source of a copy/move operation, are not listed unless
5573 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5574 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5574 Unless options described with "show only ..." are given, the
5575 Unless options described with "show only ..." are given, the
5575 options -mardu are used.
5576 options -mardu are used.
5576
5577
5577 Option -q/--quiet hides untracked (unknown and ignored) files
5578 Option -q/--quiet hides untracked (unknown and ignored) files
5578 unless explicitly requested with -u/--unknown or -i/--ignored.
5579 unless explicitly requested with -u/--unknown or -i/--ignored.
5579
5580
5580 .. note::
5581 .. note::
5581
5582
5582 status may appear to disagree with diff if permissions have
5583 status may appear to disagree with diff if permissions have
5583 changed or a merge has occurred. The standard diff format does
5584 changed or a merge has occurred. The standard diff format does
5584 not report permission changes and diff only reports changes
5585 not report permission changes and diff only reports changes
5585 relative to one merge parent.
5586 relative to one merge parent.
5586
5587
5587 If one revision is given, it is used as the base revision.
5588 If one revision is given, it is used as the base revision.
5588 If two revisions are given, the differences between them are
5589 If two revisions are given, the differences between them are
5589 shown. The --change option can also be used as a shortcut to list
5590 shown. The --change option can also be used as a shortcut to list
5590 the changed files of a revision from its first parent.
5591 the changed files of a revision from its first parent.
5591
5592
5592 The codes used to show the status of files are::
5593 The codes used to show the status of files are::
5593
5594
5594 M = modified
5595 M = modified
5595 A = added
5596 A = added
5596 R = removed
5597 R = removed
5597 C = clean
5598 C = clean
5598 ! = missing (deleted by non-hg command, but still tracked)
5599 ! = missing (deleted by non-hg command, but still tracked)
5599 ? = not tracked
5600 ? = not tracked
5600 I = ignored
5601 I = ignored
5601 = origin of the previous file (with --copies)
5602 = origin of the previous file (with --copies)
5602
5603
5603 .. container:: verbose
5604 .. container:: verbose
5604
5605
5605 Examples:
5606 Examples:
5606
5607
5607 - show changes in the working directory relative to a
5608 - show changes in the working directory relative to a
5608 changeset::
5609 changeset::
5609
5610
5610 hg status --rev 9353
5611 hg status --rev 9353
5611
5612
5612 - show all changes including copies in an existing changeset::
5613 - show all changes including copies in an existing changeset::
5613
5614
5614 hg status --copies --change 9353
5615 hg status --copies --change 9353
5615
5616
5616 - get a NUL separated list of added files, suitable for xargs::
5617 - get a NUL separated list of added files, suitable for xargs::
5617
5618
5618 hg status -an0
5619 hg status -an0
5619
5620
5620 Returns 0 on success.
5621 Returns 0 on success.
5621 """
5622 """
5622
5623
5623 revs = opts.get('rev')
5624 revs = opts.get('rev')
5624 change = opts.get('change')
5625 change = opts.get('change')
5625
5626
5626 if revs and change:
5627 if revs and change:
5627 msg = _('cannot specify --rev and --change at the same time')
5628 msg = _('cannot specify --rev and --change at the same time')
5628 raise util.Abort(msg)
5629 raise util.Abort(msg)
5629 elif change:
5630 elif change:
5630 node2 = scmutil.revsingle(repo, change, None).node()
5631 node2 = scmutil.revsingle(repo, change, None).node()
5631 node1 = repo[node2].p1().node()
5632 node1 = repo[node2].p1().node()
5632 else:
5633 else:
5633 node1, node2 = scmutil.revpair(repo, revs)
5634 node1, node2 = scmutil.revpair(repo, revs)
5634
5635
5635 cwd = (pats and repo.getcwd()) or ''
5636 cwd = (pats and repo.getcwd()) or ''
5636 end = opts.get('print0') and '\0' or '\n'
5637 end = opts.get('print0') and '\0' or '\n'
5637 copy = {}
5638 copy = {}
5638 states = 'modified added removed deleted unknown ignored clean'.split()
5639 states = 'modified added removed deleted unknown ignored clean'.split()
5639 show = [k for k in states if opts.get(k)]
5640 show = [k for k in states if opts.get(k)]
5640 if opts.get('all'):
5641 if opts.get('all'):
5641 show += ui.quiet and (states[:4] + ['clean']) or states
5642 show += ui.quiet and (states[:4] + ['clean']) or states
5642 if not show:
5643 if not show:
5643 show = ui.quiet and states[:4] or states[:5]
5644 show = ui.quiet and states[:4] or states[:5]
5644
5645
5645 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5646 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5646 'ignored' in show, 'clean' in show, 'unknown' in show,
5647 'ignored' in show, 'clean' in show, 'unknown' in show,
5647 opts.get('subrepos'))
5648 opts.get('subrepos'))
5648 changestates = zip(states, 'MAR!?IC', stat)
5649 changestates = zip(states, 'MAR!?IC', stat)
5649
5650
5650 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5651 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5651 copy = copies.pathcopies(repo[node1], repo[node2])
5652 copy = copies.pathcopies(repo[node1], repo[node2])
5652
5653
5653 fm = ui.formatter('status', opts)
5654 fm = ui.formatter('status', opts)
5654 fmt = '%s' + end
5655 fmt = '%s' + end
5655 showchar = not opts.get('no_status')
5656 showchar = not opts.get('no_status')
5656
5657
5657 for state, char, files in changestates:
5658 for state, char, files in changestates:
5658 if state in show:
5659 if state in show:
5659 label = 'status.' + state
5660 label = 'status.' + state
5660 for f in files:
5661 for f in files:
5661 fm.startitem()
5662 fm.startitem()
5662 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5663 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5663 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5664 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5664 if f in copy:
5665 if f in copy:
5665 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5666 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5666 label='status.copied')
5667 label='status.copied')
5667 fm.end()
5668 fm.end()
5668
5669
5669 @command('^summary|sum',
5670 @command('^summary|sum',
5670 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5671 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5671 def summary(ui, repo, **opts):
5672 def summary(ui, repo, **opts):
5672 """summarize working directory state
5673 """summarize working directory state
5673
5674
5674 This generates a brief summary of the working directory state,
5675 This generates a brief summary of the working directory state,
5675 including parents, branch, commit status, and available updates.
5676 including parents, branch, commit status, and available updates.
5676
5677
5677 With the --remote option, this will check the default paths for
5678 With the --remote option, this will check the default paths for
5678 incoming and outgoing changes. This can be time-consuming.
5679 incoming and outgoing changes. This can be time-consuming.
5679
5680
5680 Returns 0 on success.
5681 Returns 0 on success.
5681 """
5682 """
5682
5683
5683 ctx = repo[None]
5684 ctx = repo[None]
5684 parents = ctx.parents()
5685 parents = ctx.parents()
5685 pnode = parents[0].node()
5686 pnode = parents[0].node()
5686 marks = []
5687 marks = []
5687
5688
5688 for p in parents:
5689 for p in parents:
5689 # label with log.changeset (instead of log.parent) since this
5690 # label with log.changeset (instead of log.parent) since this
5690 # shows a working directory parent *changeset*:
5691 # shows a working directory parent *changeset*:
5691 # i18n: column positioning for "hg summary"
5692 # i18n: column positioning for "hg summary"
5692 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5693 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5693 label='log.changeset changeset.%s' % p.phasestr())
5694 label='log.changeset changeset.%s' % p.phasestr())
5694 ui.write(' '.join(p.tags()), label='log.tag')
5695 ui.write(' '.join(p.tags()), label='log.tag')
5695 if p.bookmarks():
5696 if p.bookmarks():
5696 marks.extend(p.bookmarks())
5697 marks.extend(p.bookmarks())
5697 if p.rev() == -1:
5698 if p.rev() == -1:
5698 if not len(repo):
5699 if not len(repo):
5699 ui.write(_(' (empty repository)'))
5700 ui.write(_(' (empty repository)'))
5700 else:
5701 else:
5701 ui.write(_(' (no revision checked out)'))
5702 ui.write(_(' (no revision checked out)'))
5702 ui.write('\n')
5703 ui.write('\n')
5703 if p.description():
5704 if p.description():
5704 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5705 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5705 label='log.summary')
5706 label='log.summary')
5706
5707
5707 branch = ctx.branch()
5708 branch = ctx.branch()
5708 bheads = repo.branchheads(branch)
5709 bheads = repo.branchheads(branch)
5709 # i18n: column positioning for "hg summary"
5710 # i18n: column positioning for "hg summary"
5710 m = _('branch: %s\n') % branch
5711 m = _('branch: %s\n') % branch
5711 if branch != 'default':
5712 if branch != 'default':
5712 ui.write(m, label='log.branch')
5713 ui.write(m, label='log.branch')
5713 else:
5714 else:
5714 ui.status(m, label='log.branch')
5715 ui.status(m, label='log.branch')
5715
5716
5716 if marks:
5717 if marks:
5717 current = repo._bookmarkcurrent
5718 current = repo._bookmarkcurrent
5718 # i18n: column positioning for "hg summary"
5719 # i18n: column positioning for "hg summary"
5719 ui.write(_('bookmarks:'), label='log.bookmark')
5720 ui.write(_('bookmarks:'), label='log.bookmark')
5720 if current is not None:
5721 if current is not None:
5721 if current in marks:
5722 if current in marks:
5722 ui.write(' *' + current, label='bookmarks.current')
5723 ui.write(' *' + current, label='bookmarks.current')
5723 marks.remove(current)
5724 marks.remove(current)
5724 else:
5725 else:
5725 ui.write(' [%s]' % current, label='bookmarks.current')
5726 ui.write(' [%s]' % current, label='bookmarks.current')
5726 for m in marks:
5727 for m in marks:
5727 ui.write(' ' + m, label='log.bookmark')
5728 ui.write(' ' + m, label='log.bookmark')
5728 ui.write('\n', label='log.bookmark')
5729 ui.write('\n', label='log.bookmark')
5729
5730
5730 status = repo.status(unknown=True)
5731 status = repo.status(unknown=True)
5731
5732
5732 c = repo.dirstate.copies()
5733 c = repo.dirstate.copies()
5733 copied, renamed = [], []
5734 copied, renamed = [], []
5734 for d, s in c.iteritems():
5735 for d, s in c.iteritems():
5735 if s in status.removed:
5736 if s in status.removed:
5736 status.removed.remove(s)
5737 status.removed.remove(s)
5737 renamed.append(d)
5738 renamed.append(d)
5738 else:
5739 else:
5739 copied.append(d)
5740 copied.append(d)
5740 if d in status.added:
5741 if d in status.added:
5741 status.added.remove(d)
5742 status.added.remove(d)
5742
5743
5743 ms = mergemod.mergestate(repo)
5744 ms = mergemod.mergestate(repo)
5744 unresolved = [f for f in ms if ms[f] == 'u']
5745 unresolved = [f for f in ms if ms[f] == 'u']
5745
5746
5746 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5747 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5747
5748
5748 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5749 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5749 (ui.label(_('%d added'), 'status.added'), status.added),
5750 (ui.label(_('%d added'), 'status.added'), status.added),
5750 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5751 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5751 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5752 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5752 (ui.label(_('%d copied'), 'status.copied'), copied),
5753 (ui.label(_('%d copied'), 'status.copied'), copied),
5753 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5754 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5754 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5755 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5755 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5756 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5756 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5757 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5757 t = []
5758 t = []
5758 for l, s in labels:
5759 for l, s in labels:
5759 if s:
5760 if s:
5760 t.append(l % len(s))
5761 t.append(l % len(s))
5761
5762
5762 t = ', '.join(t)
5763 t = ', '.join(t)
5763 cleanworkdir = False
5764 cleanworkdir = False
5764
5765
5765 if repo.vfs.exists('updatestate'):
5766 if repo.vfs.exists('updatestate'):
5766 t += _(' (interrupted update)')
5767 t += _(' (interrupted update)')
5767 elif len(parents) > 1:
5768 elif len(parents) > 1:
5768 t += _(' (merge)')
5769 t += _(' (merge)')
5769 elif branch != parents[0].branch():
5770 elif branch != parents[0].branch():
5770 t += _(' (new branch)')
5771 t += _(' (new branch)')
5771 elif (parents[0].closesbranch() and
5772 elif (parents[0].closesbranch() and
5772 pnode in repo.branchheads(branch, closed=True)):
5773 pnode in repo.branchheads(branch, closed=True)):
5773 t += _(' (head closed)')
5774 t += _(' (head closed)')
5774 elif not (status.modified or status.added or status.removed or renamed or
5775 elif not (status.modified or status.added or status.removed or renamed or
5775 copied or subs):
5776 copied or subs):
5776 t += _(' (clean)')
5777 t += _(' (clean)')
5777 cleanworkdir = True
5778 cleanworkdir = True
5778 elif pnode not in bheads:
5779 elif pnode not in bheads:
5779 t += _(' (new branch head)')
5780 t += _(' (new branch head)')
5780
5781
5781 if cleanworkdir:
5782 if cleanworkdir:
5782 # i18n: column positioning for "hg summary"
5783 # i18n: column positioning for "hg summary"
5783 ui.status(_('commit: %s\n') % t.strip())
5784 ui.status(_('commit: %s\n') % t.strip())
5784 else:
5785 else:
5785 # i18n: column positioning for "hg summary"
5786 # i18n: column positioning for "hg summary"
5786 ui.write(_('commit: %s\n') % t.strip())
5787 ui.write(_('commit: %s\n') % t.strip())
5787
5788
5788 # all ancestors of branch heads - all ancestors of parent = new csets
5789 # all ancestors of branch heads - all ancestors of parent = new csets
5789 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5790 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5790 bheads))
5791 bheads))
5791
5792
5792 if new == 0:
5793 if new == 0:
5793 # i18n: column positioning for "hg summary"
5794 # i18n: column positioning for "hg summary"
5794 ui.status(_('update: (current)\n'))
5795 ui.status(_('update: (current)\n'))
5795 elif pnode not in bheads:
5796 elif pnode not in bheads:
5796 # i18n: column positioning for "hg summary"
5797 # i18n: column positioning for "hg summary"
5797 ui.write(_('update: %d new changesets (update)\n') % new)
5798 ui.write(_('update: %d new changesets (update)\n') % new)
5798 else:
5799 else:
5799 # i18n: column positioning for "hg summary"
5800 # i18n: column positioning for "hg summary"
5800 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5801 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5801 (new, len(bheads)))
5802 (new, len(bheads)))
5802
5803
5803 cmdutil.summaryhooks(ui, repo)
5804 cmdutil.summaryhooks(ui, repo)
5804
5805
5805 if opts.get('remote'):
5806 if opts.get('remote'):
5806 needsincoming, needsoutgoing = True, True
5807 needsincoming, needsoutgoing = True, True
5807 else:
5808 else:
5808 needsincoming, needsoutgoing = False, False
5809 needsincoming, needsoutgoing = False, False
5809 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5810 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5810 if i:
5811 if i:
5811 needsincoming = True
5812 needsincoming = True
5812 if o:
5813 if o:
5813 needsoutgoing = True
5814 needsoutgoing = True
5814 if not needsincoming and not needsoutgoing:
5815 if not needsincoming and not needsoutgoing:
5815 return
5816 return
5816
5817
5817 def getincoming():
5818 def getincoming():
5818 source, branches = hg.parseurl(ui.expandpath('default'))
5819 source, branches = hg.parseurl(ui.expandpath('default'))
5819 sbranch = branches[0]
5820 sbranch = branches[0]
5820 try:
5821 try:
5821 other = hg.peer(repo, {}, source)
5822 other = hg.peer(repo, {}, source)
5822 except error.RepoError:
5823 except error.RepoError:
5823 if opts.get('remote'):
5824 if opts.get('remote'):
5824 raise
5825 raise
5825 return source, sbranch, None, None, None
5826 return source, sbranch, None, None, None
5826 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5827 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5827 if revs:
5828 if revs:
5828 revs = [other.lookup(rev) for rev in revs]
5829 revs = [other.lookup(rev) for rev in revs]
5829 ui.debug('comparing with %s\n' % util.hidepassword(source))
5830 ui.debug('comparing with %s\n' % util.hidepassword(source))
5830 repo.ui.pushbuffer()
5831 repo.ui.pushbuffer()
5831 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5832 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5832 repo.ui.popbuffer()
5833 repo.ui.popbuffer()
5833 return source, sbranch, other, commoninc, commoninc[1]
5834 return source, sbranch, other, commoninc, commoninc[1]
5834
5835
5835 if needsincoming:
5836 if needsincoming:
5836 source, sbranch, sother, commoninc, incoming = getincoming()
5837 source, sbranch, sother, commoninc, incoming = getincoming()
5837 else:
5838 else:
5838 source = sbranch = sother = commoninc = incoming = None
5839 source = sbranch = sother = commoninc = incoming = None
5839
5840
5840 def getoutgoing():
5841 def getoutgoing():
5841 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5842 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5842 dbranch = branches[0]
5843 dbranch = branches[0]
5843 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5844 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5844 if source != dest:
5845 if source != dest:
5845 try:
5846 try:
5846 dother = hg.peer(repo, {}, dest)
5847 dother = hg.peer(repo, {}, dest)
5847 except error.RepoError:
5848 except error.RepoError:
5848 if opts.get('remote'):
5849 if opts.get('remote'):
5849 raise
5850 raise
5850 return dest, dbranch, None, None
5851 return dest, dbranch, None, None
5851 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5852 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5852 elif sother is None:
5853 elif sother is None:
5853 # there is no explicit destination peer, but source one is invalid
5854 # there is no explicit destination peer, but source one is invalid
5854 return dest, dbranch, None, None
5855 return dest, dbranch, None, None
5855 else:
5856 else:
5856 dother = sother
5857 dother = sother
5857 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5858 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5858 common = None
5859 common = None
5859 else:
5860 else:
5860 common = commoninc
5861 common = commoninc
5861 if revs:
5862 if revs:
5862 revs = [repo.lookup(rev) for rev in revs]
5863 revs = [repo.lookup(rev) for rev in revs]
5863 repo.ui.pushbuffer()
5864 repo.ui.pushbuffer()
5864 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5865 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5865 commoninc=common)
5866 commoninc=common)
5866 repo.ui.popbuffer()
5867 repo.ui.popbuffer()
5867 return dest, dbranch, dother, outgoing
5868 return dest, dbranch, dother, outgoing
5868
5869
5869 if needsoutgoing:
5870 if needsoutgoing:
5870 dest, dbranch, dother, outgoing = getoutgoing()
5871 dest, dbranch, dother, outgoing = getoutgoing()
5871 else:
5872 else:
5872 dest = dbranch = dother = outgoing = None
5873 dest = dbranch = dother = outgoing = None
5873
5874
5874 if opts.get('remote'):
5875 if opts.get('remote'):
5875 t = []
5876 t = []
5876 if incoming:
5877 if incoming:
5877 t.append(_('1 or more incoming'))
5878 t.append(_('1 or more incoming'))
5878 o = outgoing.missing
5879 o = outgoing.missing
5879 if o:
5880 if o:
5880 t.append(_('%d outgoing') % len(o))
5881 t.append(_('%d outgoing') % len(o))
5881 other = dother or sother
5882 other = dother or sother
5882 if 'bookmarks' in other.listkeys('namespaces'):
5883 if 'bookmarks' in other.listkeys('namespaces'):
5883 lmarks = repo.listkeys('bookmarks')
5884 lmarks = repo.listkeys('bookmarks')
5884 rmarks = other.listkeys('bookmarks')
5885 rmarks = other.listkeys('bookmarks')
5885 diff = set(rmarks) - set(lmarks)
5886 diff = set(rmarks) - set(lmarks)
5886 if len(diff) > 0:
5887 if len(diff) > 0:
5887 t.append(_('%d incoming bookmarks') % len(diff))
5888 t.append(_('%d incoming bookmarks') % len(diff))
5888 diff = set(lmarks) - set(rmarks)
5889 diff = set(lmarks) - set(rmarks)
5889 if len(diff) > 0:
5890 if len(diff) > 0:
5890 t.append(_('%d outgoing bookmarks') % len(diff))
5891 t.append(_('%d outgoing bookmarks') % len(diff))
5891
5892
5892 if t:
5893 if t:
5893 # i18n: column positioning for "hg summary"
5894 # i18n: column positioning for "hg summary"
5894 ui.write(_('remote: %s\n') % (', '.join(t)))
5895 ui.write(_('remote: %s\n') % (', '.join(t)))
5895 else:
5896 else:
5896 # i18n: column positioning for "hg summary"
5897 # i18n: column positioning for "hg summary"
5897 ui.status(_('remote: (synced)\n'))
5898 ui.status(_('remote: (synced)\n'))
5898
5899
5899 cmdutil.summaryremotehooks(ui, repo, opts,
5900 cmdutil.summaryremotehooks(ui, repo, opts,
5900 ((source, sbranch, sother, commoninc),
5901 ((source, sbranch, sother, commoninc),
5901 (dest, dbranch, dother, outgoing)))
5902 (dest, dbranch, dother, outgoing)))
5902
5903
5903 @command('tag',
5904 @command('tag',
5904 [('f', 'force', None, _('force tag')),
5905 [('f', 'force', None, _('force tag')),
5905 ('l', 'local', None, _('make the tag local')),
5906 ('l', 'local', None, _('make the tag local')),
5906 ('r', 'rev', '', _('revision to tag'), _('REV')),
5907 ('r', 'rev', '', _('revision to tag'), _('REV')),
5907 ('', 'remove', None, _('remove a tag')),
5908 ('', 'remove', None, _('remove a tag')),
5908 # -l/--local is already there, commitopts cannot be used
5909 # -l/--local is already there, commitopts cannot be used
5909 ('e', 'edit', None, _('invoke editor on commit messages')),
5910 ('e', 'edit', None, _('invoke editor on commit messages')),
5910 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5911 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5911 ] + commitopts2,
5912 ] + commitopts2,
5912 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5913 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5913 def tag(ui, repo, name1, *names, **opts):
5914 def tag(ui, repo, name1, *names, **opts):
5914 """add one or more tags for the current or given revision
5915 """add one or more tags for the current or given revision
5915
5916
5916 Name a particular revision using <name>.
5917 Name a particular revision using <name>.
5917
5918
5918 Tags are used to name particular revisions of the repository and are
5919 Tags are used to name particular revisions of the repository and are
5919 very useful to compare different revisions, to go back to significant
5920 very useful to compare different revisions, to go back to significant
5920 earlier versions or to mark branch points as releases, etc. Changing
5921 earlier versions or to mark branch points as releases, etc. Changing
5921 an existing tag is normally disallowed; use -f/--force to override.
5922 an existing tag is normally disallowed; use -f/--force to override.
5922
5923
5923 If no revision is given, the parent of the working directory is
5924 If no revision is given, the parent of the working directory is
5924 used.
5925 used.
5925
5926
5926 To facilitate version control, distribution, and merging of tags,
5927 To facilitate version control, distribution, and merging of tags,
5927 they are stored as a file named ".hgtags" which is managed similarly
5928 they are stored as a file named ".hgtags" which is managed similarly
5928 to other project files and can be hand-edited if necessary. This
5929 to other project files and can be hand-edited if necessary. This
5929 also means that tagging creates a new commit. The file
5930 also means that tagging creates a new commit. The file
5930 ".hg/localtags" is used for local tags (not shared among
5931 ".hg/localtags" is used for local tags (not shared among
5931 repositories).
5932 repositories).
5932
5933
5933 Tag commits are usually made at the head of a branch. If the parent
5934 Tag commits are usually made at the head of a branch. If the parent
5934 of the working directory is not a branch head, :hg:`tag` aborts; use
5935 of the working directory is not a branch head, :hg:`tag` aborts; use
5935 -f/--force to force the tag commit to be based on a non-head
5936 -f/--force to force the tag commit to be based on a non-head
5936 changeset.
5937 changeset.
5937
5938
5938 See :hg:`help dates` for a list of formats valid for -d/--date.
5939 See :hg:`help dates` for a list of formats valid for -d/--date.
5939
5940
5940 Since tag names have priority over branch names during revision
5941 Since tag names have priority over branch names during revision
5941 lookup, using an existing branch name as a tag name is discouraged.
5942 lookup, using an existing branch name as a tag name is discouraged.
5942
5943
5943 Returns 0 on success.
5944 Returns 0 on success.
5944 """
5945 """
5945 wlock = lock = None
5946 wlock = lock = None
5946 try:
5947 try:
5947 wlock = repo.wlock()
5948 wlock = repo.wlock()
5948 lock = repo.lock()
5949 lock = repo.lock()
5949 rev_ = "."
5950 rev_ = "."
5950 names = [t.strip() for t in (name1,) + names]
5951 names = [t.strip() for t in (name1,) + names]
5951 if len(names) != len(set(names)):
5952 if len(names) != len(set(names)):
5952 raise util.Abort(_('tag names must be unique'))
5953 raise util.Abort(_('tag names must be unique'))
5953 for n in names:
5954 for n in names:
5954 scmutil.checknewlabel(repo, n, 'tag')
5955 scmutil.checknewlabel(repo, n, 'tag')
5955 if not n:
5956 if not n:
5956 raise util.Abort(_('tag names cannot consist entirely of '
5957 raise util.Abort(_('tag names cannot consist entirely of '
5957 'whitespace'))
5958 'whitespace'))
5958 if opts.get('rev') and opts.get('remove'):
5959 if opts.get('rev') and opts.get('remove'):
5959 raise util.Abort(_("--rev and --remove are incompatible"))
5960 raise util.Abort(_("--rev and --remove are incompatible"))
5960 if opts.get('rev'):
5961 if opts.get('rev'):
5961 rev_ = opts['rev']
5962 rev_ = opts['rev']
5962 message = opts.get('message')
5963 message = opts.get('message')
5963 if opts.get('remove'):
5964 if opts.get('remove'):
5964 expectedtype = opts.get('local') and 'local' or 'global'
5965 expectedtype = opts.get('local') and 'local' or 'global'
5965 for n in names:
5966 for n in names:
5966 if not repo.tagtype(n):
5967 if not repo.tagtype(n):
5967 raise util.Abort(_("tag '%s' does not exist") % n)
5968 raise util.Abort(_("tag '%s' does not exist") % n)
5968 if repo.tagtype(n) != expectedtype:
5969 if repo.tagtype(n) != expectedtype:
5969 if expectedtype == 'global':
5970 if expectedtype == 'global':
5970 raise util.Abort(_("tag '%s' is not a global tag") % n)
5971 raise util.Abort(_("tag '%s' is not a global tag") % n)
5971 else:
5972 else:
5972 raise util.Abort(_("tag '%s' is not a local tag") % n)
5973 raise util.Abort(_("tag '%s' is not a local tag") % n)
5973 rev_ = nullid
5974 rev_ = nullid
5974 if not message:
5975 if not message:
5975 # we don't translate commit messages
5976 # we don't translate commit messages
5976 message = 'Removed tag %s' % ', '.join(names)
5977 message = 'Removed tag %s' % ', '.join(names)
5977 elif not opts.get('force'):
5978 elif not opts.get('force'):
5978 for n in names:
5979 for n in names:
5979 if n in repo.tags():
5980 if n in repo.tags():
5980 raise util.Abort(_("tag '%s' already exists "
5981 raise util.Abort(_("tag '%s' already exists "
5981 "(use -f to force)") % n)
5982 "(use -f to force)") % n)
5982 if not opts.get('local'):
5983 if not opts.get('local'):
5983 p1, p2 = repo.dirstate.parents()
5984 p1, p2 = repo.dirstate.parents()
5984 if p2 != nullid:
5985 if p2 != nullid:
5985 raise util.Abort(_('uncommitted merge'))
5986 raise util.Abort(_('uncommitted merge'))
5986 bheads = repo.branchheads()
5987 bheads = repo.branchheads()
5987 if not opts.get('force') and bheads and p1 not in bheads:
5988 if not opts.get('force') and bheads and p1 not in bheads:
5988 raise util.Abort(_('not at a branch head (use -f to force)'))
5989 raise util.Abort(_('not at a branch head (use -f to force)'))
5989 r = scmutil.revsingle(repo, rev_).node()
5990 r = scmutil.revsingle(repo, rev_).node()
5990
5991
5991 if not message:
5992 if not message:
5992 # we don't translate commit messages
5993 # we don't translate commit messages
5993 message = ('Added tag %s for changeset %s' %
5994 message = ('Added tag %s for changeset %s' %
5994 (', '.join(names), short(r)))
5995 (', '.join(names), short(r)))
5995
5996
5996 date = opts.get('date')
5997 date = opts.get('date')
5997 if date:
5998 if date:
5998 date = util.parsedate(date)
5999 date = util.parsedate(date)
5999
6000
6000 if opts.get('remove'):
6001 if opts.get('remove'):
6001 editform = 'tag.remove'
6002 editform = 'tag.remove'
6002 else:
6003 else:
6003 editform = 'tag.add'
6004 editform = 'tag.add'
6004 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6005 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6005
6006
6006 # don't allow tagging the null rev
6007 # don't allow tagging the null rev
6007 if (not opts.get('remove') and
6008 if (not opts.get('remove') and
6008 scmutil.revsingle(repo, rev_).rev() == nullrev):
6009 scmutil.revsingle(repo, rev_).rev() == nullrev):
6009 raise util.Abort(_("cannot tag null revision"))
6010 raise util.Abort(_("cannot tag null revision"))
6010
6011
6011 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6012 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6012 editor=editor)
6013 editor=editor)
6013 finally:
6014 finally:
6014 release(lock, wlock)
6015 release(lock, wlock)
6015
6016
6016 @command('tags', formatteropts, '')
6017 @command('tags', formatteropts, '')
6017 def tags(ui, repo, **opts):
6018 def tags(ui, repo, **opts):
6018 """list repository tags
6019 """list repository tags
6019
6020
6020 This lists both regular and local tags. When the -v/--verbose
6021 This lists both regular and local tags. When the -v/--verbose
6021 switch is used, a third column "local" is printed for local tags.
6022 switch is used, a third column "local" is printed for local tags.
6022
6023
6023 Returns 0 on success.
6024 Returns 0 on success.
6024 """
6025 """
6025
6026
6026 fm = ui.formatter('tags', opts)
6027 fm = ui.formatter('tags', opts)
6027 hexfunc = fm.hexfunc
6028 hexfunc = fm.hexfunc
6028 tagtype = ""
6029 tagtype = ""
6029
6030
6030 for t, n in reversed(repo.tagslist()):
6031 for t, n in reversed(repo.tagslist()):
6031 hn = hexfunc(n)
6032 hn = hexfunc(n)
6032 label = 'tags.normal'
6033 label = 'tags.normal'
6033 tagtype = ''
6034 tagtype = ''
6034 if repo.tagtype(t) == 'local':
6035 if repo.tagtype(t) == 'local':
6035 label = 'tags.local'
6036 label = 'tags.local'
6036 tagtype = 'local'
6037 tagtype = 'local'
6037
6038
6038 fm.startitem()
6039 fm.startitem()
6039 fm.write('tag', '%s', t, label=label)
6040 fm.write('tag', '%s', t, label=label)
6040 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6041 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6041 fm.condwrite(not ui.quiet, 'rev node', fmt,
6042 fm.condwrite(not ui.quiet, 'rev node', fmt,
6042 repo.changelog.rev(n), hn, label=label)
6043 repo.changelog.rev(n), hn, label=label)
6043 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6044 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6044 tagtype, label=label)
6045 tagtype, label=label)
6045 fm.plain('\n')
6046 fm.plain('\n')
6046 fm.end()
6047 fm.end()
6047
6048
6048 @command('tip',
6049 @command('tip',
6049 [('p', 'patch', None, _('show patch')),
6050 [('p', 'patch', None, _('show patch')),
6050 ('g', 'git', None, _('use git extended diff format')),
6051 ('g', 'git', None, _('use git extended diff format')),
6051 ] + templateopts,
6052 ] + templateopts,
6052 _('[-p] [-g]'))
6053 _('[-p] [-g]'))
6053 def tip(ui, repo, **opts):
6054 def tip(ui, repo, **opts):
6054 """show the tip revision (DEPRECATED)
6055 """show the tip revision (DEPRECATED)
6055
6056
6056 The tip revision (usually just called the tip) is the changeset
6057 The tip revision (usually just called the tip) is the changeset
6057 most recently added to the repository (and therefore the most
6058 most recently added to the repository (and therefore the most
6058 recently changed head).
6059 recently changed head).
6059
6060
6060 If you have just made a commit, that commit will be the tip. If
6061 If you have just made a commit, that commit will be the tip. If
6061 you have just pulled changes from another repository, the tip of
6062 you have just pulled changes from another repository, the tip of
6062 that repository becomes the current tip. The "tip" tag is special
6063 that repository becomes the current tip. The "tip" tag is special
6063 and cannot be renamed or assigned to a different changeset.
6064 and cannot be renamed or assigned to a different changeset.
6064
6065
6065 This command is deprecated, please use :hg:`heads` instead.
6066 This command is deprecated, please use :hg:`heads` instead.
6066
6067
6067 Returns 0 on success.
6068 Returns 0 on success.
6068 """
6069 """
6069 displayer = cmdutil.show_changeset(ui, repo, opts)
6070 displayer = cmdutil.show_changeset(ui, repo, opts)
6070 displayer.show(repo['tip'])
6071 displayer.show(repo['tip'])
6071 displayer.close()
6072 displayer.close()
6072
6073
6073 @command('unbundle',
6074 @command('unbundle',
6074 [('u', 'update', None,
6075 [('u', 'update', None,
6075 _('update to new branch head if changesets were unbundled'))],
6076 _('update to new branch head if changesets were unbundled'))],
6076 _('[-u] FILE...'))
6077 _('[-u] FILE...'))
6077 def unbundle(ui, repo, fname1, *fnames, **opts):
6078 def unbundle(ui, repo, fname1, *fnames, **opts):
6078 """apply one or more changegroup files
6079 """apply one or more changegroup files
6079
6080
6080 Apply one or more compressed changegroup files generated by the
6081 Apply one or more compressed changegroup files generated by the
6081 bundle command.
6082 bundle command.
6082
6083
6083 Returns 0 on success, 1 if an update has unresolved files.
6084 Returns 0 on success, 1 if an update has unresolved files.
6084 """
6085 """
6085 fnames = (fname1,) + fnames
6086 fnames = (fname1,) + fnames
6086
6087
6087 lock = repo.lock()
6088 lock = repo.lock()
6088 try:
6089 try:
6089 for fname in fnames:
6090 for fname in fnames:
6090 f = hg.openpath(ui, fname)
6091 f = hg.openpath(ui, fname)
6091 gen = exchange.readbundle(ui, f, fname)
6092 gen = exchange.readbundle(ui, f, fname)
6092 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6093 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6093 'bundle:' + fname)
6094 'bundle:' + fname)
6094 finally:
6095 finally:
6095 lock.release()
6096 lock.release()
6096
6097
6097 return postincoming(ui, repo, modheads, opts.get('update'), None)
6098 return postincoming(ui, repo, modheads, opts.get('update'), None)
6098
6099
6099 @command('^update|up|checkout|co',
6100 @command('^update|up|checkout|co',
6100 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6101 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6101 ('c', 'check', None,
6102 ('c', 'check', None,
6102 _('update across branches if no uncommitted changes')),
6103 _('update across branches if no uncommitted changes')),
6103 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6104 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6104 ('r', 'rev', '', _('revision'), _('REV'))
6105 ('r', 'rev', '', _('revision'), _('REV'))
6105 ] + mergetoolopts,
6106 ] + mergetoolopts,
6106 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6107 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6107 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6108 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6108 tool=None):
6109 tool=None):
6109 """update working directory (or switch revisions)
6110 """update working directory (or switch revisions)
6110
6111
6111 Update the repository's working directory to the specified
6112 Update the repository's working directory to the specified
6112 changeset. If no changeset is specified, update to the tip of the
6113 changeset. If no changeset is specified, update to the tip of the
6113 current named branch and move the current bookmark (see :hg:`help
6114 current named branch and move the current bookmark (see :hg:`help
6114 bookmarks`).
6115 bookmarks`).
6115
6116
6116 Update sets the working directory's parent revision to the specified
6117 Update sets the working directory's parent revision to the specified
6117 changeset (see :hg:`help parents`).
6118 changeset (see :hg:`help parents`).
6118
6119
6119 If the changeset is not a descendant or ancestor of the working
6120 If the changeset is not a descendant or ancestor of the working
6120 directory's parent, the update is aborted. With the -c/--check
6121 directory's parent, the update is aborted. With the -c/--check
6121 option, the working directory is checked for uncommitted changes; if
6122 option, the working directory is checked for uncommitted changes; if
6122 none are found, the working directory is updated to the specified
6123 none are found, the working directory is updated to the specified
6123 changeset.
6124 changeset.
6124
6125
6125 .. container:: verbose
6126 .. container:: verbose
6126
6127
6127 The following rules apply when the working directory contains
6128 The following rules apply when the working directory contains
6128 uncommitted changes:
6129 uncommitted changes:
6129
6130
6130 1. If neither -c/--check nor -C/--clean is specified, and if
6131 1. If neither -c/--check nor -C/--clean is specified, and if
6131 the requested changeset is an ancestor or descendant of
6132 the requested changeset is an ancestor or descendant of
6132 the working directory's parent, the uncommitted changes
6133 the working directory's parent, the uncommitted changes
6133 are merged into the requested changeset and the merged
6134 are merged into the requested changeset and the merged
6134 result is left uncommitted. If the requested changeset is
6135 result is left uncommitted. If the requested changeset is
6135 not an ancestor or descendant (that is, it is on another
6136 not an ancestor or descendant (that is, it is on another
6136 branch), the update is aborted and the uncommitted changes
6137 branch), the update is aborted and the uncommitted changes
6137 are preserved.
6138 are preserved.
6138
6139
6139 2. With the -c/--check option, the update is aborted and the
6140 2. With the -c/--check option, the update is aborted and the
6140 uncommitted changes are preserved.
6141 uncommitted changes are preserved.
6141
6142
6142 3. With the -C/--clean option, uncommitted changes are discarded and
6143 3. With the -C/--clean option, uncommitted changes are discarded and
6143 the working directory is updated to the requested changeset.
6144 the working directory is updated to the requested changeset.
6144
6145
6145 To cancel an uncommitted merge (and lose your changes), use
6146 To cancel an uncommitted merge (and lose your changes), use
6146 :hg:`update --clean .`.
6147 :hg:`update --clean .`.
6147
6148
6148 Use null as the changeset to remove the working directory (like
6149 Use null as the changeset to remove the working directory (like
6149 :hg:`clone -U`).
6150 :hg:`clone -U`).
6150
6151
6151 If you want to revert just one file to an older revision, use
6152 If you want to revert just one file to an older revision, use
6152 :hg:`revert [-r REV] NAME`.
6153 :hg:`revert [-r REV] NAME`.
6153
6154
6154 See :hg:`help dates` for a list of formats valid for -d/--date.
6155 See :hg:`help dates` for a list of formats valid for -d/--date.
6155
6156
6156 Returns 0 on success, 1 if there are unresolved files.
6157 Returns 0 on success, 1 if there are unresolved files.
6157 """
6158 """
6158 if rev and node:
6159 if rev and node:
6159 raise util.Abort(_("please specify just one revision"))
6160 raise util.Abort(_("please specify just one revision"))
6160
6161
6161 if rev is None or rev == '':
6162 if rev is None or rev == '':
6162 rev = node
6163 rev = node
6163
6164
6164 cmdutil.clearunfinished(repo)
6165 cmdutil.clearunfinished(repo)
6165
6166
6166 # with no argument, we also move the current bookmark, if any
6167 # with no argument, we also move the current bookmark, if any
6167 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6168 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6168
6169
6169 # if we defined a bookmark, we have to remember the original bookmark name
6170 # if we defined a bookmark, we have to remember the original bookmark name
6170 brev = rev
6171 brev = rev
6171 rev = scmutil.revsingle(repo, rev, rev).rev()
6172 rev = scmutil.revsingle(repo, rev, rev).rev()
6172
6173
6173 if check and clean:
6174 if check and clean:
6174 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6175 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6175
6176
6176 if date:
6177 if date:
6177 if rev is not None:
6178 if rev is not None:
6178 raise util.Abort(_("you can't specify a revision and a date"))
6179 raise util.Abort(_("you can't specify a revision and a date"))
6179 rev = cmdutil.finddate(ui, repo, date)
6180 rev = cmdutil.finddate(ui, repo, date)
6180
6181
6181 if check:
6182 if check:
6182 c = repo[None]
6183 c = repo[None]
6183 if c.dirty(merge=False, branch=False, missing=True):
6184 if c.dirty(merge=False, branch=False, missing=True):
6184 raise util.Abort(_("uncommitted changes"))
6185 raise util.Abort(_("uncommitted changes"))
6185 if rev is None:
6186 if rev is None:
6186 rev = repo[repo[None].branch()].rev()
6187 rev = repo[repo[None].branch()].rev()
6187 mergemod.checkunknown(repo, repo[None], repo[rev])
6188 mergemod.checkunknown(repo, repo[None], repo[rev])
6188
6189
6189 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6190 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6190
6191
6191 if clean:
6192 if clean:
6192 ret = hg.clean(repo, rev)
6193 ret = hg.clean(repo, rev)
6193 else:
6194 else:
6194 ret = hg.update(repo, rev)
6195 ret = hg.update(repo, rev)
6195
6196
6196 if not ret and movemarkfrom:
6197 if not ret and movemarkfrom:
6197 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6198 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6198 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6199 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6199 elif brev in repo._bookmarks:
6200 elif brev in repo._bookmarks:
6200 bookmarks.setcurrent(repo, brev)
6201 bookmarks.setcurrent(repo, brev)
6201 ui.status(_("(activating bookmark %s)\n") % brev)
6202 ui.status(_("(activating bookmark %s)\n") % brev)
6202 elif brev:
6203 elif brev:
6203 if repo._bookmarkcurrent:
6204 if repo._bookmarkcurrent:
6204 ui.status(_("(leaving bookmark %s)\n") %
6205 ui.status(_("(leaving bookmark %s)\n") %
6205 repo._bookmarkcurrent)
6206 repo._bookmarkcurrent)
6206 bookmarks.unsetcurrent(repo)
6207 bookmarks.unsetcurrent(repo)
6207
6208
6208 return ret
6209 return ret
6209
6210
6210 @command('verify', [])
6211 @command('verify', [])
6211 def verify(ui, repo):
6212 def verify(ui, repo):
6212 """verify the integrity of the repository
6213 """verify the integrity of the repository
6213
6214
6214 Verify the integrity of the current repository.
6215 Verify the integrity of the current repository.
6215
6216
6216 This will perform an extensive check of the repository's
6217 This will perform an extensive check of the repository's
6217 integrity, validating the hashes and checksums of each entry in
6218 integrity, validating the hashes and checksums of each entry in
6218 the changelog, manifest, and tracked files, as well as the
6219 the changelog, manifest, and tracked files, as well as the
6219 integrity of their crosslinks and indices.
6220 integrity of their crosslinks and indices.
6220
6221
6221 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6222 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6222 for more information about recovery from corruption of the
6223 for more information about recovery from corruption of the
6223 repository.
6224 repository.
6224
6225
6225 Returns 0 on success, 1 if errors are encountered.
6226 Returns 0 on success, 1 if errors are encountered.
6226 """
6227 """
6227 return hg.verify(repo)
6228 return hg.verify(repo)
6228
6229
6229 @command('version', [], norepo=True)
6230 @command('version', [], norepo=True)
6230 def version_(ui):
6231 def version_(ui):
6231 """output version and copyright information"""
6232 """output version and copyright information"""
6232 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6233 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6233 % util.version())
6234 % util.version())
6234 ui.status(_(
6235 ui.status(_(
6235 "(see http://mercurial.selenic.com for more information)\n"
6236 "(see http://mercurial.selenic.com for more information)\n"
6236 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
6237 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
6237 "This is free software; see the source for copying conditions. "
6238 "This is free software; see the source for copying conditions. "
6238 "There is NO\nwarranty; "
6239 "There is NO\nwarranty; "
6239 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6240 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6240 ))
6241 ))
6241
6242
6242 ui.note(_("\nEnabled extensions:\n\n"))
6243 ui.note(_("\nEnabled extensions:\n\n"))
6243 if ui.verbose:
6244 if ui.verbose:
6244 # format names and versions into columns
6245 # format names and versions into columns
6245 names = []
6246 names = []
6246 vers = []
6247 vers = []
6247 for name, module in extensions.extensions():
6248 for name, module in extensions.extensions():
6248 names.append(name)
6249 names.append(name)
6249 vers.append(extensions.moduleversion(module))
6250 vers.append(extensions.moduleversion(module))
6250 if names:
6251 if names:
6251 maxnamelen = max(len(n) for n in names)
6252 maxnamelen = max(len(n) for n in names)
6252 for i, name in enumerate(names):
6253 for i, name in enumerate(names):
6253 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
6254 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
@@ -1,146 +1,150 b''
1 Subrepositories let you nest external repositories or projects into a
1 Subrepositories let you nest external repositories or projects into a
2 parent Mercurial repository, and make commands operate on them as a
2 parent Mercurial repository, and make commands operate on them as a
3 group.
3 group.
4
4
5 Mercurial currently supports Mercurial, Git, and Subversion
5 Mercurial currently supports Mercurial, Git, and Subversion
6 subrepositories.
6 subrepositories.
7
7
8 Subrepositories are made of three components:
8 Subrepositories are made of three components:
9
9
10 1. Nested repository checkouts. They can appear anywhere in the
10 1. Nested repository checkouts. They can appear anywhere in the
11 parent working directory.
11 parent working directory.
12
12
13 2. Nested repository references. They are defined in ``.hgsub``, which
13 2. Nested repository references. They are defined in ``.hgsub``, which
14 should be placed in the root of working directory, and
14 should be placed in the root of working directory, and
15 tell where the subrepository checkouts come from. Mercurial
15 tell where the subrepository checkouts come from. Mercurial
16 subrepositories are referenced like::
16 subrepositories are referenced like::
17
17
18 path/to/nested = https://example.com/nested/repo/path
18 path/to/nested = https://example.com/nested/repo/path
19
19
20 Git and Subversion subrepos are also supported::
20 Git and Subversion subrepos are also supported::
21
21
22 path/to/nested = [git]git://example.com/nested/repo/path
22 path/to/nested = [git]git://example.com/nested/repo/path
23 path/to/nested = [svn]https://example.com/nested/trunk/path
23 path/to/nested = [svn]https://example.com/nested/trunk/path
24
24
25 where ``path/to/nested`` is the checkout location relatively to the
25 where ``path/to/nested`` is the checkout location relatively to the
26 parent Mercurial root, and ``https://example.com/nested/repo/path``
26 parent Mercurial root, and ``https://example.com/nested/repo/path``
27 is the source repository path. The source can also reference a
27 is the source repository path. The source can also reference a
28 filesystem path.
28 filesystem path.
29
29
30 Note that ``.hgsub`` does not exist by default in Mercurial
30 Note that ``.hgsub`` does not exist by default in Mercurial
31 repositories, you have to create and add it to the parent
31 repositories, you have to create and add it to the parent
32 repository before using subrepositories.
32 repository before using subrepositories.
33
33
34 3. Nested repository states. They are defined in ``.hgsubstate``, which
34 3. Nested repository states. They are defined in ``.hgsubstate``, which
35 is placed in the root of working directory, and
35 is placed in the root of working directory, and
36 capture whatever information is required to restore the
36 capture whatever information is required to restore the
37 subrepositories to the state they were committed in a parent
37 subrepositories to the state they were committed in a parent
38 repository changeset. Mercurial automatically record the nested
38 repository changeset. Mercurial automatically record the nested
39 repositories states when committing in the parent repository.
39 repositories states when committing in the parent repository.
40
40
41 .. note::
41 .. note::
42
42
43 The ``.hgsubstate`` file should not be edited manually.
43 The ``.hgsubstate`` file should not be edited manually.
44
44
45
45
46 Adding a Subrepository
46 Adding a Subrepository
47 ======================
47 ======================
48
48
49 If ``.hgsub`` does not exist, create it and add it to the parent
49 If ``.hgsub`` does not exist, create it and add it to the parent
50 repository. Clone or checkout the external projects where you want it
50 repository. Clone or checkout the external projects where you want it
51 to live in the parent repository. Edit ``.hgsub`` and add the
51 to live in the parent repository. Edit ``.hgsub`` and add the
52 subrepository entry as described above. At this point, the
52 subrepository entry as described above. At this point, the
53 subrepository is tracked and the next commit will record its state in
53 subrepository is tracked and the next commit will record its state in
54 ``.hgsubstate`` and bind it to the committed changeset.
54 ``.hgsubstate`` and bind it to the committed changeset.
55
55
56 Synchronizing a Subrepository
56 Synchronizing a Subrepository
57 =============================
57 =============================
58
58
59 Subrepos do not automatically track the latest changeset of their
59 Subrepos do not automatically track the latest changeset of their
60 sources. Instead, they are updated to the changeset that corresponds
60 sources. Instead, they are updated to the changeset that corresponds
61 with the changeset checked out in the top-level changeset. This is so
61 with the changeset checked out in the top-level changeset. This is so
62 developers always get a consistent set of compatible code and
62 developers always get a consistent set of compatible code and
63 libraries when they update.
63 libraries when they update.
64
64
65 Thus, updating subrepos is a manual process. Simply check out target
65 Thus, updating subrepos is a manual process. Simply check out target
66 subrepo at the desired revision, test in the top-level repo, then
66 subrepo at the desired revision, test in the top-level repo, then
67 commit in the parent repository to record the new combination.
67 commit in the parent repository to record the new combination.
68
68
69 Deleting a Subrepository
69 Deleting a Subrepository
70 ========================
70 ========================
71
71
72 To remove a subrepository from the parent repository, delete its
72 To remove a subrepository from the parent repository, delete its
73 reference from ``.hgsub``, then remove its files.
73 reference from ``.hgsub``, then remove its files.
74
74
75 Interaction with Mercurial Commands
75 Interaction with Mercurial Commands
76 ===================================
76 ===================================
77
77
78 :add: add does not recurse in subrepos unless -S/--subrepos is
78 :add: add does not recurse in subrepos unless -S/--subrepos is
79 specified. However, if you specify the full path of a file in a
79 specified. However, if you specify the full path of a file in a
80 subrepo, it will be added even without -S/--subrepos specified.
80 subrepo, it will be added even without -S/--subrepos specified.
81 Git and Subversion subrepositories are currently silently
81 Git and Subversion subrepositories are currently silently
82 ignored.
82 ignored.
83
83
84 :archive: archive does not recurse in subrepositories unless
84 :archive: archive does not recurse in subrepositories unless
85 -S/--subrepos is specified.
85 -S/--subrepos is specified.
86
86
87 :cat: cat currently only handles exact file matches in subrepos.
87 :cat: cat currently only handles exact file matches in subrepos.
88 Git and Subversion subrepositories are currently ignored.
88 Git and Subversion subrepositories are currently ignored.
89
89
90 :commit: commit creates a consistent snapshot of the state of the
90 :commit: commit creates a consistent snapshot of the state of the
91 entire project and its subrepositories. If any subrepositories
91 entire project and its subrepositories. If any subrepositories
92 have been modified, Mercurial will abort. Mercurial can be made
92 have been modified, Mercurial will abort. Mercurial can be made
93 to instead commit all modified subrepositories by specifying
93 to instead commit all modified subrepositories by specifying
94 -S/--subrepos, or setting "ui.commitsubrepos=True" in a
94 -S/--subrepos, or setting "ui.commitsubrepos=True" in a
95 configuration file (see :hg:`help config`). After there are no
95 configuration file (see :hg:`help config`). After there are no
96 longer any modified subrepositories, it records their state and
96 longer any modified subrepositories, it records their state and
97 finally commits it in the parent repository.
97 finally commits it in the parent repository.
98
98
99 :diff: diff does not recurse in subrepos unless -S/--subrepos is
99 :diff: diff does not recurse in subrepos unless -S/--subrepos is
100 specified. Changes are displayed as usual, on the subrepositories
100 specified. Changes are displayed as usual, on the subrepositories
101 elements. Git and Subversion subrepositories are currently
101 elements. Git and Subversion subrepositories are currently
102 silently ignored.
102 silently ignored.
103
103
104 :forget: forget currently only handles exact file matches in subrepos.
104 :forget: forget currently only handles exact file matches in subrepos.
105 Git and Subversion subrepositories are currently silently ignored.
105 Git and Subversion subrepositories are currently silently ignored.
106
106
107 :incoming: incoming does not recurse in subrepos unless -S/--subrepos
107 :incoming: incoming does not recurse in subrepos unless -S/--subrepos
108 is specified. Git and Subversion subrepositories are currently
108 is specified. Git and Subversion subrepositories are currently
109 silently ignored.
109 silently ignored.
110
110
111 :outgoing: outgoing does not recurse in subrepos unless -S/--subrepos
111 :outgoing: outgoing does not recurse in subrepos unless -S/--subrepos
112 is specified. Git and Subversion subrepositories are currently
112 is specified. Git and Subversion subrepositories are currently
113 silently ignored.
113 silently ignored.
114
114
115 :pull: pull is not recursive since it is not clear what to pull prior
115 :pull: pull is not recursive since it is not clear what to pull prior
116 to running :hg:`update`. Listing and retrieving all
116 to running :hg:`update`. Listing and retrieving all
117 subrepositories changes referenced by the parent repository pulled
117 subrepositories changes referenced by the parent repository pulled
118 changesets is expensive at best, impossible in the Subversion
118 changesets is expensive at best, impossible in the Subversion
119 case.
119 case.
120
120
121 :push: Mercurial will automatically push all subrepositories first
121 :push: Mercurial will automatically push all subrepositories first
122 when the parent repository is being pushed. This ensures new
122 when the parent repository is being pushed. This ensures new
123 subrepository changes are available when referenced by top-level
123 subrepository changes are available when referenced by top-level
124 repositories. Push is a no-op for Subversion subrepositories.
124 repositories. Push is a no-op for Subversion subrepositories.
125
125
126 :status: status does not recurse into subrepositories unless
126 :status: status does not recurse into subrepositories unless
127 -S/--subrepos is specified. Subrepository changes are displayed as
127 -S/--subrepos is specified. Subrepository changes are displayed as
128 regular Mercurial changes on the subrepository
128 regular Mercurial changes on the subrepository
129 elements. Subversion subrepositories are currently silently
129 elements. Subversion subrepositories are currently silently
130 ignored.
130 ignored.
131
131
132 :remove: remove does not recurse into subrepositories unless
133 -S/--subrepos is specified. Git and Subversion subrepositories
134 are currently silently ignored.
135
132 :update: update restores the subrepos in the state they were
136 :update: update restores the subrepos in the state they were
133 originally committed in target changeset. If the recorded
137 originally committed in target changeset. If the recorded
134 changeset is not available in the current subrepository, Mercurial
138 changeset is not available in the current subrepository, Mercurial
135 will pull it in first before updating. This means that updating
139 will pull it in first before updating. This means that updating
136 can require network access when using subrepositories.
140 can require network access when using subrepositories.
137
141
138 Remapping Subrepositories Sources
142 Remapping Subrepositories Sources
139 =================================
143 =================================
140
144
141 A subrepository source location may change during a project life,
145 A subrepository source location may change during a project life,
142 invalidating references stored in the parent repository history. To
146 invalidating references stored in the parent repository history. To
143 fix this, rewriting rules can be defined in parent repository ``hgrc``
147 fix this, rewriting rules can be defined in parent repository ``hgrc``
144 file or in Mercurial configuration. See the ``[subpaths]`` section in
148 file or in Mercurial configuration. See the ``[subpaths]`` section in
145 hgrc(5) for more details.
149 hgrc(5) for more details.
146
150
@@ -1,1596 +1,1609 b''
1 # subrepo.py - sub-repository handling for Mercurial
1 # subrepo.py - sub-repository handling for Mercurial
2 #
2 #
3 # Copyright 2009-2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2009-2010 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 import errno, os, re, shutil, posixpath, sys
8 import errno, os, re, shutil, posixpath, sys
9 import xml.dom.minidom
9 import xml.dom.minidom
10 import stat, subprocess, tarfile
10 import stat, subprocess, tarfile
11 from i18n import _
11 from i18n import _
12 import config, util, node, error, cmdutil, scmutil, match as matchmod
12 import config, util, node, error, cmdutil, scmutil, match as matchmod
13 import phases
13 import phases
14 import pathutil
14 import pathutil
15 import exchange
15 import exchange
16 hg = None
16 hg = None
17 propertycache = util.propertycache
17 propertycache = util.propertycache
18
18
19 nullstate = ('', '', 'empty')
19 nullstate = ('', '', 'empty')
20
20
21 def _expandedabspath(path):
21 def _expandedabspath(path):
22 '''
22 '''
23 get a path or url and if it is a path expand it and return an absolute path
23 get a path or url and if it is a path expand it and return an absolute path
24 '''
24 '''
25 expandedpath = util.urllocalpath(util.expandpath(path))
25 expandedpath = util.urllocalpath(util.expandpath(path))
26 u = util.url(expandedpath)
26 u = util.url(expandedpath)
27 if not u.scheme:
27 if not u.scheme:
28 path = util.normpath(os.path.abspath(u.path))
28 path = util.normpath(os.path.abspath(u.path))
29 return path
29 return path
30
30
31 def _getstorehashcachename(remotepath):
31 def _getstorehashcachename(remotepath):
32 '''get a unique filename for the store hash cache of a remote repository'''
32 '''get a unique filename for the store hash cache of a remote repository'''
33 return util.sha1(_expandedabspath(remotepath)).hexdigest()[0:12]
33 return util.sha1(_expandedabspath(remotepath)).hexdigest()[0:12]
34
34
35 def _calcfilehash(filename):
35 def _calcfilehash(filename):
36 data = ''
36 data = ''
37 if os.path.exists(filename):
37 if os.path.exists(filename):
38 fd = open(filename, 'rb')
38 fd = open(filename, 'rb')
39 try:
39 try:
40 data = fd.read()
40 data = fd.read()
41 finally:
41 finally:
42 fd.close()
42 fd.close()
43 return util.sha1(data).hexdigest()
43 return util.sha1(data).hexdigest()
44
44
45 class SubrepoAbort(error.Abort):
45 class SubrepoAbort(error.Abort):
46 """Exception class used to avoid handling a subrepo error more than once"""
46 """Exception class used to avoid handling a subrepo error more than once"""
47 def __init__(self, *args, **kw):
47 def __init__(self, *args, **kw):
48 error.Abort.__init__(self, *args, **kw)
48 error.Abort.__init__(self, *args, **kw)
49 self.subrepo = kw.get('subrepo')
49 self.subrepo = kw.get('subrepo')
50 self.cause = kw.get('cause')
50 self.cause = kw.get('cause')
51
51
52 def annotatesubrepoerror(func):
52 def annotatesubrepoerror(func):
53 def decoratedmethod(self, *args, **kargs):
53 def decoratedmethod(self, *args, **kargs):
54 try:
54 try:
55 res = func(self, *args, **kargs)
55 res = func(self, *args, **kargs)
56 except SubrepoAbort, ex:
56 except SubrepoAbort, ex:
57 # This exception has already been handled
57 # This exception has already been handled
58 raise ex
58 raise ex
59 except error.Abort, ex:
59 except error.Abort, ex:
60 subrepo = subrelpath(self)
60 subrepo = subrelpath(self)
61 errormsg = str(ex) + ' ' + _('(in subrepo %s)') % subrepo
61 errormsg = str(ex) + ' ' + _('(in subrepo %s)') % subrepo
62 # avoid handling this exception by raising a SubrepoAbort exception
62 # avoid handling this exception by raising a SubrepoAbort exception
63 raise SubrepoAbort(errormsg, hint=ex.hint, subrepo=subrepo,
63 raise SubrepoAbort(errormsg, hint=ex.hint, subrepo=subrepo,
64 cause=sys.exc_info())
64 cause=sys.exc_info())
65 return res
65 return res
66 return decoratedmethod
66 return decoratedmethod
67
67
68 def state(ctx, ui):
68 def state(ctx, ui):
69 """return a state dict, mapping subrepo paths configured in .hgsub
69 """return a state dict, mapping subrepo paths configured in .hgsub
70 to tuple: (source from .hgsub, revision from .hgsubstate, kind
70 to tuple: (source from .hgsub, revision from .hgsubstate, kind
71 (key in types dict))
71 (key in types dict))
72 """
72 """
73 p = config.config()
73 p = config.config()
74 def read(f, sections=None, remap=None):
74 def read(f, sections=None, remap=None):
75 if f in ctx:
75 if f in ctx:
76 try:
76 try:
77 data = ctx[f].data()
77 data = ctx[f].data()
78 except IOError, err:
78 except IOError, err:
79 if err.errno != errno.ENOENT:
79 if err.errno != errno.ENOENT:
80 raise
80 raise
81 # handle missing subrepo spec files as removed
81 # handle missing subrepo spec files as removed
82 ui.warn(_("warning: subrepo spec file %s not found\n") % f)
82 ui.warn(_("warning: subrepo spec file %s not found\n") % f)
83 return
83 return
84 p.parse(f, data, sections, remap, read)
84 p.parse(f, data, sections, remap, read)
85 else:
85 else:
86 raise util.Abort(_("subrepo spec file %s not found") % f)
86 raise util.Abort(_("subrepo spec file %s not found") % f)
87
87
88 if '.hgsub' in ctx:
88 if '.hgsub' in ctx:
89 read('.hgsub')
89 read('.hgsub')
90
90
91 for path, src in ui.configitems('subpaths'):
91 for path, src in ui.configitems('subpaths'):
92 p.set('subpaths', path, src, ui.configsource('subpaths', path))
92 p.set('subpaths', path, src, ui.configsource('subpaths', path))
93
93
94 rev = {}
94 rev = {}
95 if '.hgsubstate' in ctx:
95 if '.hgsubstate' in ctx:
96 try:
96 try:
97 for i, l in enumerate(ctx['.hgsubstate'].data().splitlines()):
97 for i, l in enumerate(ctx['.hgsubstate'].data().splitlines()):
98 l = l.lstrip()
98 l = l.lstrip()
99 if not l:
99 if not l:
100 continue
100 continue
101 try:
101 try:
102 revision, path = l.split(" ", 1)
102 revision, path = l.split(" ", 1)
103 except ValueError:
103 except ValueError:
104 raise util.Abort(_("invalid subrepository revision "
104 raise util.Abort(_("invalid subrepository revision "
105 "specifier in .hgsubstate line %d")
105 "specifier in .hgsubstate line %d")
106 % (i + 1))
106 % (i + 1))
107 rev[path] = revision
107 rev[path] = revision
108 except IOError, err:
108 except IOError, err:
109 if err.errno != errno.ENOENT:
109 if err.errno != errno.ENOENT:
110 raise
110 raise
111
111
112 def remap(src):
112 def remap(src):
113 for pattern, repl in p.items('subpaths'):
113 for pattern, repl in p.items('subpaths'):
114 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
114 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
115 # does a string decode.
115 # does a string decode.
116 repl = repl.encode('string-escape')
116 repl = repl.encode('string-escape')
117 # However, we still want to allow back references to go
117 # However, we still want to allow back references to go
118 # through unharmed, so we turn r'\\1' into r'\1'. Again,
118 # through unharmed, so we turn r'\\1' into r'\1'. Again,
119 # extra escapes are needed because re.sub string decodes.
119 # extra escapes are needed because re.sub string decodes.
120 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl)
120 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl)
121 try:
121 try:
122 src = re.sub(pattern, repl, src, 1)
122 src = re.sub(pattern, repl, src, 1)
123 except re.error, e:
123 except re.error, e:
124 raise util.Abort(_("bad subrepository pattern in %s: %s")
124 raise util.Abort(_("bad subrepository pattern in %s: %s")
125 % (p.source('subpaths', pattern), e))
125 % (p.source('subpaths', pattern), e))
126 return src
126 return src
127
127
128 state = {}
128 state = {}
129 for path, src in p[''].items():
129 for path, src in p[''].items():
130 kind = 'hg'
130 kind = 'hg'
131 if src.startswith('['):
131 if src.startswith('['):
132 if ']' not in src:
132 if ']' not in src:
133 raise util.Abort(_('missing ] in subrepo source'))
133 raise util.Abort(_('missing ] in subrepo source'))
134 kind, src = src.split(']', 1)
134 kind, src = src.split(']', 1)
135 kind = kind[1:]
135 kind = kind[1:]
136 src = src.lstrip() # strip any extra whitespace after ']'
136 src = src.lstrip() # strip any extra whitespace after ']'
137
137
138 if not util.url(src).isabs():
138 if not util.url(src).isabs():
139 parent = _abssource(ctx._repo, abort=False)
139 parent = _abssource(ctx._repo, abort=False)
140 if parent:
140 if parent:
141 parent = util.url(parent)
141 parent = util.url(parent)
142 parent.path = posixpath.join(parent.path or '', src)
142 parent.path = posixpath.join(parent.path or '', src)
143 parent.path = posixpath.normpath(parent.path)
143 parent.path = posixpath.normpath(parent.path)
144 joined = str(parent)
144 joined = str(parent)
145 # Remap the full joined path and use it if it changes,
145 # Remap the full joined path and use it if it changes,
146 # else remap the original source.
146 # else remap the original source.
147 remapped = remap(joined)
147 remapped = remap(joined)
148 if remapped == joined:
148 if remapped == joined:
149 src = remap(src)
149 src = remap(src)
150 else:
150 else:
151 src = remapped
151 src = remapped
152
152
153 src = remap(src)
153 src = remap(src)
154 state[util.pconvert(path)] = (src.strip(), rev.get(path, ''), kind)
154 state[util.pconvert(path)] = (src.strip(), rev.get(path, ''), kind)
155
155
156 return state
156 return state
157
157
158 def writestate(repo, state):
158 def writestate(repo, state):
159 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
159 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
160 lines = ['%s %s\n' % (state[s][1], s) for s in sorted(state)]
160 lines = ['%s %s\n' % (state[s][1], s) for s in sorted(state)]
161 repo.wwrite('.hgsubstate', ''.join(lines), '')
161 repo.wwrite('.hgsubstate', ''.join(lines), '')
162
162
163 def submerge(repo, wctx, mctx, actx, overwrite):
163 def submerge(repo, wctx, mctx, actx, overwrite):
164 """delegated from merge.applyupdates: merging of .hgsubstate file
164 """delegated from merge.applyupdates: merging of .hgsubstate file
165 in working context, merging context and ancestor context"""
165 in working context, merging context and ancestor context"""
166 if mctx == actx: # backwards?
166 if mctx == actx: # backwards?
167 actx = wctx.p1()
167 actx = wctx.p1()
168 s1 = wctx.substate
168 s1 = wctx.substate
169 s2 = mctx.substate
169 s2 = mctx.substate
170 sa = actx.substate
170 sa = actx.substate
171 sm = {}
171 sm = {}
172
172
173 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
173 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
174
174
175 def debug(s, msg, r=""):
175 def debug(s, msg, r=""):
176 if r:
176 if r:
177 r = "%s:%s:%s" % r
177 r = "%s:%s:%s" % r
178 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
178 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
179
179
180 for s, l in sorted(s1.iteritems()):
180 for s, l in sorted(s1.iteritems()):
181 a = sa.get(s, nullstate)
181 a = sa.get(s, nullstate)
182 ld = l # local state with possible dirty flag for compares
182 ld = l # local state with possible dirty flag for compares
183 if wctx.sub(s).dirty():
183 if wctx.sub(s).dirty():
184 ld = (l[0], l[1] + "+")
184 ld = (l[0], l[1] + "+")
185 if wctx == actx: # overwrite
185 if wctx == actx: # overwrite
186 a = ld
186 a = ld
187
187
188 if s in s2:
188 if s in s2:
189 r = s2[s]
189 r = s2[s]
190 if ld == r or r == a: # no change or local is newer
190 if ld == r or r == a: # no change or local is newer
191 sm[s] = l
191 sm[s] = l
192 continue
192 continue
193 elif ld == a: # other side changed
193 elif ld == a: # other side changed
194 debug(s, "other changed, get", r)
194 debug(s, "other changed, get", r)
195 wctx.sub(s).get(r, overwrite)
195 wctx.sub(s).get(r, overwrite)
196 sm[s] = r
196 sm[s] = r
197 elif ld[0] != r[0]: # sources differ
197 elif ld[0] != r[0]: # sources differ
198 if repo.ui.promptchoice(
198 if repo.ui.promptchoice(
199 _(' subrepository sources for %s differ\n'
199 _(' subrepository sources for %s differ\n'
200 'use (l)ocal source (%s) or (r)emote source (%s)?'
200 'use (l)ocal source (%s) or (r)emote source (%s)?'
201 '$$ &Local $$ &Remote') % (s, l[0], r[0]), 0):
201 '$$ &Local $$ &Remote') % (s, l[0], r[0]), 0):
202 debug(s, "prompt changed, get", r)
202 debug(s, "prompt changed, get", r)
203 wctx.sub(s).get(r, overwrite)
203 wctx.sub(s).get(r, overwrite)
204 sm[s] = r
204 sm[s] = r
205 elif ld[1] == a[1]: # local side is unchanged
205 elif ld[1] == a[1]: # local side is unchanged
206 debug(s, "other side changed, get", r)
206 debug(s, "other side changed, get", r)
207 wctx.sub(s).get(r, overwrite)
207 wctx.sub(s).get(r, overwrite)
208 sm[s] = r
208 sm[s] = r
209 else:
209 else:
210 debug(s, "both sides changed")
210 debug(s, "both sides changed")
211 srepo = wctx.sub(s)
211 srepo = wctx.sub(s)
212 option = repo.ui.promptchoice(
212 option = repo.ui.promptchoice(
213 _(' subrepository %s diverged (local revision: %s, '
213 _(' subrepository %s diverged (local revision: %s, '
214 'remote revision: %s)\n'
214 'remote revision: %s)\n'
215 '(M)erge, keep (l)ocal or keep (r)emote?'
215 '(M)erge, keep (l)ocal or keep (r)emote?'
216 '$$ &Merge $$ &Local $$ &Remote')
216 '$$ &Merge $$ &Local $$ &Remote')
217 % (s, srepo.shortid(l[1]), srepo.shortid(r[1])), 0)
217 % (s, srepo.shortid(l[1]), srepo.shortid(r[1])), 0)
218 if option == 0:
218 if option == 0:
219 wctx.sub(s).merge(r)
219 wctx.sub(s).merge(r)
220 sm[s] = l
220 sm[s] = l
221 debug(s, "merge with", r)
221 debug(s, "merge with", r)
222 elif option == 1:
222 elif option == 1:
223 sm[s] = l
223 sm[s] = l
224 debug(s, "keep local subrepo revision", l)
224 debug(s, "keep local subrepo revision", l)
225 else:
225 else:
226 wctx.sub(s).get(r, overwrite)
226 wctx.sub(s).get(r, overwrite)
227 sm[s] = r
227 sm[s] = r
228 debug(s, "get remote subrepo revision", r)
228 debug(s, "get remote subrepo revision", r)
229 elif ld == a: # remote removed, local unchanged
229 elif ld == a: # remote removed, local unchanged
230 debug(s, "remote removed, remove")
230 debug(s, "remote removed, remove")
231 wctx.sub(s).remove()
231 wctx.sub(s).remove()
232 elif a == nullstate: # not present in remote or ancestor
232 elif a == nullstate: # not present in remote or ancestor
233 debug(s, "local added, keep")
233 debug(s, "local added, keep")
234 sm[s] = l
234 sm[s] = l
235 continue
235 continue
236 else:
236 else:
237 if repo.ui.promptchoice(
237 if repo.ui.promptchoice(
238 _(' local changed subrepository %s which remote removed\n'
238 _(' local changed subrepository %s which remote removed\n'
239 'use (c)hanged version or (d)elete?'
239 'use (c)hanged version or (d)elete?'
240 '$$ &Changed $$ &Delete') % s, 0):
240 '$$ &Changed $$ &Delete') % s, 0):
241 debug(s, "prompt remove")
241 debug(s, "prompt remove")
242 wctx.sub(s).remove()
242 wctx.sub(s).remove()
243
243
244 for s, r in sorted(s2.items()):
244 for s, r in sorted(s2.items()):
245 if s in s1:
245 if s in s1:
246 continue
246 continue
247 elif s not in sa:
247 elif s not in sa:
248 debug(s, "remote added, get", r)
248 debug(s, "remote added, get", r)
249 mctx.sub(s).get(r)
249 mctx.sub(s).get(r)
250 sm[s] = r
250 sm[s] = r
251 elif r != sa[s]:
251 elif r != sa[s]:
252 if repo.ui.promptchoice(
252 if repo.ui.promptchoice(
253 _(' remote changed subrepository %s which local removed\n'
253 _(' remote changed subrepository %s which local removed\n'
254 'use (c)hanged version or (d)elete?'
254 'use (c)hanged version or (d)elete?'
255 '$$ &Changed $$ &Delete') % s, 0) == 0:
255 '$$ &Changed $$ &Delete') % s, 0) == 0:
256 debug(s, "prompt recreate", r)
256 debug(s, "prompt recreate", r)
257 wctx.sub(s).get(r)
257 wctx.sub(s).get(r)
258 sm[s] = r
258 sm[s] = r
259
259
260 # record merged .hgsubstate
260 # record merged .hgsubstate
261 writestate(repo, sm)
261 writestate(repo, sm)
262 return sm
262 return sm
263
263
264 def _updateprompt(ui, sub, dirty, local, remote):
264 def _updateprompt(ui, sub, dirty, local, remote):
265 if dirty:
265 if dirty:
266 msg = (_(' subrepository sources for %s differ\n'
266 msg = (_(' subrepository sources for %s differ\n'
267 'use (l)ocal source (%s) or (r)emote source (%s)?'
267 'use (l)ocal source (%s) or (r)emote source (%s)?'
268 '$$ &Local $$ &Remote')
268 '$$ &Local $$ &Remote')
269 % (subrelpath(sub), local, remote))
269 % (subrelpath(sub), local, remote))
270 else:
270 else:
271 msg = (_(' subrepository sources for %s differ (in checked out '
271 msg = (_(' subrepository sources for %s differ (in checked out '
272 'version)\n'
272 'version)\n'
273 'use (l)ocal source (%s) or (r)emote source (%s)?'
273 'use (l)ocal source (%s) or (r)emote source (%s)?'
274 '$$ &Local $$ &Remote')
274 '$$ &Local $$ &Remote')
275 % (subrelpath(sub), local, remote))
275 % (subrelpath(sub), local, remote))
276 return ui.promptchoice(msg, 0)
276 return ui.promptchoice(msg, 0)
277
277
278 def reporelpath(repo):
278 def reporelpath(repo):
279 """return path to this (sub)repo as seen from outermost repo"""
279 """return path to this (sub)repo as seen from outermost repo"""
280 parent = repo
280 parent = repo
281 while util.safehasattr(parent, '_subparent'):
281 while util.safehasattr(parent, '_subparent'):
282 parent = parent._subparent
282 parent = parent._subparent
283 return repo.root[len(pathutil.normasprefix(parent.root)):]
283 return repo.root[len(pathutil.normasprefix(parent.root)):]
284
284
285 def subrelpath(sub):
285 def subrelpath(sub):
286 """return path to this subrepo as seen from outermost repo"""
286 """return path to this subrepo as seen from outermost repo"""
287 if util.safehasattr(sub, '_relpath'):
287 if util.safehasattr(sub, '_relpath'):
288 return sub._relpath
288 return sub._relpath
289 if not util.safehasattr(sub, '_repo'):
289 if not util.safehasattr(sub, '_repo'):
290 return sub._path
290 return sub._path
291 return reporelpath(sub._repo)
291 return reporelpath(sub._repo)
292
292
293 def _abssource(repo, push=False, abort=True):
293 def _abssource(repo, push=False, abort=True):
294 """return pull/push path of repo - either based on parent repo .hgsub info
294 """return pull/push path of repo - either based on parent repo .hgsub info
295 or on the top repo config. Abort or return None if no source found."""
295 or on the top repo config. Abort or return None if no source found."""
296 if util.safehasattr(repo, '_subparent'):
296 if util.safehasattr(repo, '_subparent'):
297 source = util.url(repo._subsource)
297 source = util.url(repo._subsource)
298 if source.isabs():
298 if source.isabs():
299 return str(source)
299 return str(source)
300 source.path = posixpath.normpath(source.path)
300 source.path = posixpath.normpath(source.path)
301 parent = _abssource(repo._subparent, push, abort=False)
301 parent = _abssource(repo._subparent, push, abort=False)
302 if parent:
302 if parent:
303 parent = util.url(util.pconvert(parent))
303 parent = util.url(util.pconvert(parent))
304 parent.path = posixpath.join(parent.path or '', source.path)
304 parent.path = posixpath.join(parent.path or '', source.path)
305 parent.path = posixpath.normpath(parent.path)
305 parent.path = posixpath.normpath(parent.path)
306 return str(parent)
306 return str(parent)
307 else: # recursion reached top repo
307 else: # recursion reached top repo
308 if util.safehasattr(repo, '_subtoppath'):
308 if util.safehasattr(repo, '_subtoppath'):
309 return repo._subtoppath
309 return repo._subtoppath
310 if push and repo.ui.config('paths', 'default-push'):
310 if push and repo.ui.config('paths', 'default-push'):
311 return repo.ui.config('paths', 'default-push')
311 return repo.ui.config('paths', 'default-push')
312 if repo.ui.config('paths', 'default'):
312 if repo.ui.config('paths', 'default'):
313 return repo.ui.config('paths', 'default')
313 return repo.ui.config('paths', 'default')
314 if repo.sharedpath != repo.path:
314 if repo.sharedpath != repo.path:
315 # chop off the .hg component to get the default path form
315 # chop off the .hg component to get the default path form
316 return os.path.dirname(repo.sharedpath)
316 return os.path.dirname(repo.sharedpath)
317 if abort:
317 if abort:
318 raise util.Abort(_("default path for subrepository not found"))
318 raise util.Abort(_("default path for subrepository not found"))
319
319
320 def _sanitize(ui, path, ignore):
320 def _sanitize(ui, path, ignore):
321 for dirname, dirs, names in os.walk(path):
321 for dirname, dirs, names in os.walk(path):
322 for i, d in enumerate(dirs):
322 for i, d in enumerate(dirs):
323 if d.lower() == ignore:
323 if d.lower() == ignore:
324 del dirs[i]
324 del dirs[i]
325 break
325 break
326 if os.path.basename(dirname).lower() != '.hg':
326 if os.path.basename(dirname).lower() != '.hg':
327 continue
327 continue
328 for f in names:
328 for f in names:
329 if f.lower() == 'hgrc':
329 if f.lower() == 'hgrc':
330 ui.warn(_("warning: removing potentially hostile 'hgrc' "
330 ui.warn(_("warning: removing potentially hostile 'hgrc' "
331 "in '%s'\n") % dirname)
331 "in '%s'\n") % dirname)
332 os.unlink(os.path.join(dirname, f))
332 os.unlink(os.path.join(dirname, f))
333
333
334 def subrepo(ctx, path):
334 def subrepo(ctx, path):
335 """return instance of the right subrepo class for subrepo in path"""
335 """return instance of the right subrepo class for subrepo in path"""
336 # subrepo inherently violates our import layering rules
336 # subrepo inherently violates our import layering rules
337 # because it wants to make repo objects from deep inside the stack
337 # because it wants to make repo objects from deep inside the stack
338 # so we manually delay the circular imports to not break
338 # so we manually delay the circular imports to not break
339 # scripts that don't use our demand-loading
339 # scripts that don't use our demand-loading
340 global hg
340 global hg
341 import hg as h
341 import hg as h
342 hg = h
342 hg = h
343
343
344 pathutil.pathauditor(ctx._repo.root)(path)
344 pathutil.pathauditor(ctx._repo.root)(path)
345 state = ctx.substate[path]
345 state = ctx.substate[path]
346 if state[2] not in types:
346 if state[2] not in types:
347 raise util.Abort(_('unknown subrepo type %s') % state[2])
347 raise util.Abort(_('unknown subrepo type %s') % state[2])
348 return types[state[2]](ctx, path, state[:2])
348 return types[state[2]](ctx, path, state[:2])
349
349
350 def newcommitphase(ui, ctx):
350 def newcommitphase(ui, ctx):
351 commitphase = phases.newcommitphase(ui)
351 commitphase = phases.newcommitphase(ui)
352 substate = getattr(ctx, "substate", None)
352 substate = getattr(ctx, "substate", None)
353 if not substate:
353 if not substate:
354 return commitphase
354 return commitphase
355 check = ui.config('phases', 'checksubrepos', 'follow')
355 check = ui.config('phases', 'checksubrepos', 'follow')
356 if check not in ('ignore', 'follow', 'abort'):
356 if check not in ('ignore', 'follow', 'abort'):
357 raise util.Abort(_('invalid phases.checksubrepos configuration: %s')
357 raise util.Abort(_('invalid phases.checksubrepos configuration: %s')
358 % (check))
358 % (check))
359 if check == 'ignore':
359 if check == 'ignore':
360 return commitphase
360 return commitphase
361 maxphase = phases.public
361 maxphase = phases.public
362 maxsub = None
362 maxsub = None
363 for s in sorted(substate):
363 for s in sorted(substate):
364 sub = ctx.sub(s)
364 sub = ctx.sub(s)
365 subphase = sub.phase(substate[s][1])
365 subphase = sub.phase(substate[s][1])
366 if maxphase < subphase:
366 if maxphase < subphase:
367 maxphase = subphase
367 maxphase = subphase
368 maxsub = s
368 maxsub = s
369 if commitphase < maxphase:
369 if commitphase < maxphase:
370 if check == 'abort':
370 if check == 'abort':
371 raise util.Abort(_("can't commit in %s phase"
371 raise util.Abort(_("can't commit in %s phase"
372 " conflicting %s from subrepository %s") %
372 " conflicting %s from subrepository %s") %
373 (phases.phasenames[commitphase],
373 (phases.phasenames[commitphase],
374 phases.phasenames[maxphase], maxsub))
374 phases.phasenames[maxphase], maxsub))
375 ui.warn(_("warning: changes are committed in"
375 ui.warn(_("warning: changes are committed in"
376 " %s phase from subrepository %s\n") %
376 " %s phase from subrepository %s\n") %
377 (phases.phasenames[maxphase], maxsub))
377 (phases.phasenames[maxphase], maxsub))
378 return maxphase
378 return maxphase
379 return commitphase
379 return commitphase
380
380
381 # subrepo classes need to implement the following abstract class:
381 # subrepo classes need to implement the following abstract class:
382
382
383 class abstractsubrepo(object):
383 class abstractsubrepo(object):
384
384
385 def storeclean(self, path):
385 def storeclean(self, path):
386 """
386 """
387 returns true if the repository has not changed since it was last
387 returns true if the repository has not changed since it was last
388 cloned from or pushed to a given repository.
388 cloned from or pushed to a given repository.
389 """
389 """
390 return False
390 return False
391
391
392 def dirty(self, ignoreupdate=False):
392 def dirty(self, ignoreupdate=False):
393 """returns true if the dirstate of the subrepo is dirty or does not
393 """returns true if the dirstate of the subrepo is dirty or does not
394 match current stored state. If ignoreupdate is true, only check
394 match current stored state. If ignoreupdate is true, only check
395 whether the subrepo has uncommitted changes in its dirstate.
395 whether the subrepo has uncommitted changes in its dirstate.
396 """
396 """
397 raise NotImplementedError
397 raise NotImplementedError
398
398
399 def basestate(self):
399 def basestate(self):
400 """current working directory base state, disregarding .hgsubstate
400 """current working directory base state, disregarding .hgsubstate
401 state and working directory modifications"""
401 state and working directory modifications"""
402 raise NotImplementedError
402 raise NotImplementedError
403
403
404 def checknested(self, path):
404 def checknested(self, path):
405 """check if path is a subrepository within this repository"""
405 """check if path is a subrepository within this repository"""
406 return False
406 return False
407
407
408 def commit(self, text, user, date):
408 def commit(self, text, user, date):
409 """commit the current changes to the subrepo with the given
409 """commit the current changes to the subrepo with the given
410 log message. Use given user and date if possible. Return the
410 log message. Use given user and date if possible. Return the
411 new state of the subrepo.
411 new state of the subrepo.
412 """
412 """
413 raise NotImplementedError
413 raise NotImplementedError
414
414
415 def phase(self, state):
415 def phase(self, state):
416 """returns phase of specified state in the subrepository.
416 """returns phase of specified state in the subrepository.
417 """
417 """
418 return phases.public
418 return phases.public
419
419
420 def remove(self):
420 def remove(self):
421 """remove the subrepo
421 """remove the subrepo
422
422
423 (should verify the dirstate is not dirty first)
423 (should verify the dirstate is not dirty first)
424 """
424 """
425 raise NotImplementedError
425 raise NotImplementedError
426
426
427 def get(self, state, overwrite=False):
427 def get(self, state, overwrite=False):
428 """run whatever commands are needed to put the subrepo into
428 """run whatever commands are needed to put the subrepo into
429 this state
429 this state
430 """
430 """
431 raise NotImplementedError
431 raise NotImplementedError
432
432
433 def merge(self, state):
433 def merge(self, state):
434 """merge currently-saved state with the new state."""
434 """merge currently-saved state with the new state."""
435 raise NotImplementedError
435 raise NotImplementedError
436
436
437 def push(self, opts):
437 def push(self, opts):
438 """perform whatever action is analogous to 'hg push'
438 """perform whatever action is analogous to 'hg push'
439
439
440 This may be a no-op on some systems.
440 This may be a no-op on some systems.
441 """
441 """
442 raise NotImplementedError
442 raise NotImplementedError
443
443
444 def add(self, ui, match, dryrun, listsubrepos, prefix, explicitonly):
444 def add(self, ui, match, dryrun, listsubrepos, prefix, explicitonly):
445 return []
445 return []
446
446
447 def cat(self, ui, match, prefix, **opts):
447 def cat(self, ui, match, prefix, **opts):
448 return 1
448 return 1
449
449
450 def status(self, rev2, **opts):
450 def status(self, rev2, **opts):
451 return scmutil.status([], [], [], [], [], [], [])
451 return scmutil.status([], [], [], [], [], [], [])
452
452
453 def diff(self, ui, diffopts, node2, match, prefix, **opts):
453 def diff(self, ui, diffopts, node2, match, prefix, **opts):
454 pass
454 pass
455
455
456 def outgoing(self, ui, dest, opts):
456 def outgoing(self, ui, dest, opts):
457 return 1
457 return 1
458
458
459 def incoming(self, ui, source, opts):
459 def incoming(self, ui, source, opts):
460 return 1
460 return 1
461
461
462 def files(self):
462 def files(self):
463 """return filename iterator"""
463 """return filename iterator"""
464 raise NotImplementedError
464 raise NotImplementedError
465
465
466 def filedata(self, name):
466 def filedata(self, name):
467 """return file data"""
467 """return file data"""
468 raise NotImplementedError
468 raise NotImplementedError
469
469
470 def fileflags(self, name):
470 def fileflags(self, name):
471 """return file flags"""
471 """return file flags"""
472 return ''
472 return ''
473
473
474 def archive(self, ui, archiver, prefix, match=None):
474 def archive(self, ui, archiver, prefix, match=None):
475 if match is not None:
475 if match is not None:
476 files = [f for f in self.files() if match(f)]
476 files = [f for f in self.files() if match(f)]
477 else:
477 else:
478 files = self.files()
478 files = self.files()
479 total = len(files)
479 total = len(files)
480 relpath = subrelpath(self)
480 relpath = subrelpath(self)
481 ui.progress(_('archiving (%s)') % relpath, 0,
481 ui.progress(_('archiving (%s)') % relpath, 0,
482 unit=_('files'), total=total)
482 unit=_('files'), total=total)
483 for i, name in enumerate(files):
483 for i, name in enumerate(files):
484 flags = self.fileflags(name)
484 flags = self.fileflags(name)
485 mode = 'x' in flags and 0755 or 0644
485 mode = 'x' in flags and 0755 or 0644
486 symlink = 'l' in flags
486 symlink = 'l' in flags
487 archiver.addfile(os.path.join(prefix, self._path, name),
487 archiver.addfile(os.path.join(prefix, self._path, name),
488 mode, symlink, self.filedata(name))
488 mode, symlink, self.filedata(name))
489 ui.progress(_('archiving (%s)') % relpath, i + 1,
489 ui.progress(_('archiving (%s)') % relpath, i + 1,
490 unit=_('files'), total=total)
490 unit=_('files'), total=total)
491 ui.progress(_('archiving (%s)') % relpath, None)
491 ui.progress(_('archiving (%s)') % relpath, None)
492 return total
492 return total
493
493
494 def walk(self, match):
494 def walk(self, match):
495 '''
495 '''
496 walk recursively through the directory tree, finding all files
496 walk recursively through the directory tree, finding all files
497 matched by the match function
497 matched by the match function
498 '''
498 '''
499 pass
499 pass
500
500
501 def forget(self, ui, match, prefix):
501 def forget(self, ui, match, prefix):
502 return ([], [])
502 return ([], [])
503
503
504 def removefiles(self, ui, matcher, prefix, after, force, subrepos):
505 """remove the matched files from the subrepository and the filesystem,
506 possibly by force and/or after the file has been removed from the
507 filesystem. Return 0 on success, 1 on any warning.
508 """
509 return 1
510
504 def revert(self, ui, substate, *pats, **opts):
511 def revert(self, ui, substate, *pats, **opts):
505 ui.warn('%s: reverting %s subrepos is unsupported\n' \
512 ui.warn('%s: reverting %s subrepos is unsupported\n' \
506 % (substate[0], substate[2]))
513 % (substate[0], substate[2]))
507 return []
514 return []
508
515
509 def shortid(self, revid):
516 def shortid(self, revid):
510 return revid
517 return revid
511
518
512 class hgsubrepo(abstractsubrepo):
519 class hgsubrepo(abstractsubrepo):
513 def __init__(self, ctx, path, state):
520 def __init__(self, ctx, path, state):
514 self._path = path
521 self._path = path
515 self._state = state
522 self._state = state
516 r = ctx._repo
523 r = ctx._repo
517 root = r.wjoin(path)
524 root = r.wjoin(path)
518 create = False
525 create = False
519 if not os.path.exists(os.path.join(root, '.hg')):
526 if not os.path.exists(os.path.join(root, '.hg')):
520 create = True
527 create = True
521 util.makedirs(root)
528 util.makedirs(root)
522 self._repo = hg.repository(r.baseui, root, create=create)
529 self._repo = hg.repository(r.baseui, root, create=create)
523 for s, k in [('ui', 'commitsubrepos')]:
530 for s, k in [('ui', 'commitsubrepos')]:
524 v = r.ui.config(s, k)
531 v = r.ui.config(s, k)
525 if v:
532 if v:
526 self._repo.ui.setconfig(s, k, v, 'subrepo')
533 self._repo.ui.setconfig(s, k, v, 'subrepo')
527 self._repo.ui.setconfig('ui', '_usedassubrepo', 'True', 'subrepo')
534 self._repo.ui.setconfig('ui', '_usedassubrepo', 'True', 'subrepo')
528 self._initrepo(r, state[0], create)
535 self._initrepo(r, state[0], create)
529
536
530 def storeclean(self, path):
537 def storeclean(self, path):
531 lock = self._repo.lock()
538 lock = self._repo.lock()
532 try:
539 try:
533 return self._storeclean(path)
540 return self._storeclean(path)
534 finally:
541 finally:
535 lock.release()
542 lock.release()
536
543
537 def _storeclean(self, path):
544 def _storeclean(self, path):
538 clean = True
545 clean = True
539 itercache = self._calcstorehash(path)
546 itercache = self._calcstorehash(path)
540 try:
547 try:
541 for filehash in self._readstorehashcache(path):
548 for filehash in self._readstorehashcache(path):
542 if filehash != itercache.next():
549 if filehash != itercache.next():
543 clean = False
550 clean = False
544 break
551 break
545 except StopIteration:
552 except StopIteration:
546 # the cached and current pull states have a different size
553 # the cached and current pull states have a different size
547 clean = False
554 clean = False
548 if clean:
555 if clean:
549 try:
556 try:
550 itercache.next()
557 itercache.next()
551 # the cached and current pull states have a different size
558 # the cached and current pull states have a different size
552 clean = False
559 clean = False
553 except StopIteration:
560 except StopIteration:
554 pass
561 pass
555 return clean
562 return clean
556
563
557 def _calcstorehash(self, remotepath):
564 def _calcstorehash(self, remotepath):
558 '''calculate a unique "store hash"
565 '''calculate a unique "store hash"
559
566
560 This method is used to to detect when there are changes that may
567 This method is used to to detect when there are changes that may
561 require a push to a given remote path.'''
568 require a push to a given remote path.'''
562 # sort the files that will be hashed in increasing (likely) file size
569 # sort the files that will be hashed in increasing (likely) file size
563 filelist = ('bookmarks', 'store/phaseroots', 'store/00changelog.i')
570 filelist = ('bookmarks', 'store/phaseroots', 'store/00changelog.i')
564 yield '# %s\n' % _expandedabspath(remotepath)
571 yield '# %s\n' % _expandedabspath(remotepath)
565 for relname in filelist:
572 for relname in filelist:
566 absname = os.path.normpath(self._repo.join(relname))
573 absname = os.path.normpath(self._repo.join(relname))
567 yield '%s = %s\n' % (relname, _calcfilehash(absname))
574 yield '%s = %s\n' % (relname, _calcfilehash(absname))
568
575
569 def _getstorehashcachepath(self, remotepath):
576 def _getstorehashcachepath(self, remotepath):
570 '''get a unique path for the store hash cache'''
577 '''get a unique path for the store hash cache'''
571 return self._repo.join(os.path.join(
578 return self._repo.join(os.path.join(
572 'cache', 'storehash', _getstorehashcachename(remotepath)))
579 'cache', 'storehash', _getstorehashcachename(remotepath)))
573
580
574 def _readstorehashcache(self, remotepath):
581 def _readstorehashcache(self, remotepath):
575 '''read the store hash cache for a given remote repository'''
582 '''read the store hash cache for a given remote repository'''
576 cachefile = self._getstorehashcachepath(remotepath)
583 cachefile = self._getstorehashcachepath(remotepath)
577 if not os.path.exists(cachefile):
584 if not os.path.exists(cachefile):
578 return ''
585 return ''
579 fd = open(cachefile, 'r')
586 fd = open(cachefile, 'r')
580 try:
587 try:
581 pullstate = fd.readlines()
588 pullstate = fd.readlines()
582 finally:
589 finally:
583 fd.close()
590 fd.close()
584 return pullstate
591 return pullstate
585
592
586 def _cachestorehash(self, remotepath):
593 def _cachestorehash(self, remotepath):
587 '''cache the current store hash
594 '''cache the current store hash
588
595
589 Each remote repo requires its own store hash cache, because a subrepo
596 Each remote repo requires its own store hash cache, because a subrepo
590 store may be "clean" versus a given remote repo, but not versus another
597 store may be "clean" versus a given remote repo, but not versus another
591 '''
598 '''
592 cachefile = self._getstorehashcachepath(remotepath)
599 cachefile = self._getstorehashcachepath(remotepath)
593 lock = self._repo.lock()
600 lock = self._repo.lock()
594 try:
601 try:
595 storehash = list(self._calcstorehash(remotepath))
602 storehash = list(self._calcstorehash(remotepath))
596 cachedir = os.path.dirname(cachefile)
603 cachedir = os.path.dirname(cachefile)
597 if not os.path.exists(cachedir):
604 if not os.path.exists(cachedir):
598 util.makedirs(cachedir, notindexed=True)
605 util.makedirs(cachedir, notindexed=True)
599 fd = open(cachefile, 'w')
606 fd = open(cachefile, 'w')
600 try:
607 try:
601 fd.writelines(storehash)
608 fd.writelines(storehash)
602 finally:
609 finally:
603 fd.close()
610 fd.close()
604 finally:
611 finally:
605 lock.release()
612 lock.release()
606
613
607 @annotatesubrepoerror
614 @annotatesubrepoerror
608 def _initrepo(self, parentrepo, source, create):
615 def _initrepo(self, parentrepo, source, create):
609 self._repo._subparent = parentrepo
616 self._repo._subparent = parentrepo
610 self._repo._subsource = source
617 self._repo._subsource = source
611
618
612 if create:
619 if create:
613 lines = ['[paths]\n']
620 lines = ['[paths]\n']
614
621
615 def addpathconfig(key, value):
622 def addpathconfig(key, value):
616 if value:
623 if value:
617 lines.append('%s = %s\n' % (key, value))
624 lines.append('%s = %s\n' % (key, value))
618 self._repo.ui.setconfig('paths', key, value, 'subrepo')
625 self._repo.ui.setconfig('paths', key, value, 'subrepo')
619
626
620 defpath = _abssource(self._repo, abort=False)
627 defpath = _abssource(self._repo, abort=False)
621 defpushpath = _abssource(self._repo, True, abort=False)
628 defpushpath = _abssource(self._repo, True, abort=False)
622 addpathconfig('default', defpath)
629 addpathconfig('default', defpath)
623 if defpath != defpushpath:
630 if defpath != defpushpath:
624 addpathconfig('default-push', defpushpath)
631 addpathconfig('default-push', defpushpath)
625
632
626 fp = self._repo.opener("hgrc", "w", text=True)
633 fp = self._repo.opener("hgrc", "w", text=True)
627 try:
634 try:
628 fp.write(''.join(lines))
635 fp.write(''.join(lines))
629 finally:
636 finally:
630 fp.close()
637 fp.close()
631
638
632 @annotatesubrepoerror
639 @annotatesubrepoerror
633 def add(self, ui, match, dryrun, listsubrepos, prefix, explicitonly):
640 def add(self, ui, match, dryrun, listsubrepos, prefix, explicitonly):
634 return cmdutil.add(ui, self._repo, match, dryrun, listsubrepos,
641 return cmdutil.add(ui, self._repo, match, dryrun, listsubrepos,
635 os.path.join(prefix, self._path), explicitonly)
642 os.path.join(prefix, self._path), explicitonly)
636
643
637 @annotatesubrepoerror
644 @annotatesubrepoerror
638 def cat(self, ui, match, prefix, **opts):
645 def cat(self, ui, match, prefix, **opts):
639 rev = self._state[1]
646 rev = self._state[1]
640 ctx = self._repo[rev]
647 ctx = self._repo[rev]
641 return cmdutil.cat(ui, self._repo, ctx, match, prefix, **opts)
648 return cmdutil.cat(ui, self._repo, ctx, match, prefix, **opts)
642
649
643 @annotatesubrepoerror
650 @annotatesubrepoerror
644 def status(self, rev2, **opts):
651 def status(self, rev2, **opts):
645 try:
652 try:
646 rev1 = self._state[1]
653 rev1 = self._state[1]
647 ctx1 = self._repo[rev1]
654 ctx1 = self._repo[rev1]
648 ctx2 = self._repo[rev2]
655 ctx2 = self._repo[rev2]
649 return self._repo.status(ctx1, ctx2, **opts)
656 return self._repo.status(ctx1, ctx2, **opts)
650 except error.RepoLookupError, inst:
657 except error.RepoLookupError, inst:
651 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
658 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
652 % (inst, subrelpath(self)))
659 % (inst, subrelpath(self)))
653 return scmutil.status([], [], [], [], [], [], [])
660 return scmutil.status([], [], [], [], [], [], [])
654
661
655 @annotatesubrepoerror
662 @annotatesubrepoerror
656 def diff(self, ui, diffopts, node2, match, prefix, **opts):
663 def diff(self, ui, diffopts, node2, match, prefix, **opts):
657 try:
664 try:
658 node1 = node.bin(self._state[1])
665 node1 = node.bin(self._state[1])
659 # We currently expect node2 to come from substate and be
666 # We currently expect node2 to come from substate and be
660 # in hex format
667 # in hex format
661 if node2 is not None:
668 if node2 is not None:
662 node2 = node.bin(node2)
669 node2 = node.bin(node2)
663 cmdutil.diffordiffstat(ui, self._repo, diffopts,
670 cmdutil.diffordiffstat(ui, self._repo, diffopts,
664 node1, node2, match,
671 node1, node2, match,
665 prefix=posixpath.join(prefix, self._path),
672 prefix=posixpath.join(prefix, self._path),
666 listsubrepos=True, **opts)
673 listsubrepos=True, **opts)
667 except error.RepoLookupError, inst:
674 except error.RepoLookupError, inst:
668 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
675 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
669 % (inst, subrelpath(self)))
676 % (inst, subrelpath(self)))
670
677
671 @annotatesubrepoerror
678 @annotatesubrepoerror
672 def archive(self, ui, archiver, prefix, match=None):
679 def archive(self, ui, archiver, prefix, match=None):
673 self._get(self._state + ('hg',))
680 self._get(self._state + ('hg',))
674 total = abstractsubrepo.archive(self, ui, archiver, prefix, match)
681 total = abstractsubrepo.archive(self, ui, archiver, prefix, match)
675 rev = self._state[1]
682 rev = self._state[1]
676 ctx = self._repo[rev]
683 ctx = self._repo[rev]
677 for subpath in ctx.substate:
684 for subpath in ctx.substate:
678 s = subrepo(ctx, subpath)
685 s = subrepo(ctx, subpath)
679 submatch = matchmod.narrowmatcher(subpath, match)
686 submatch = matchmod.narrowmatcher(subpath, match)
680 total += s.archive(
687 total += s.archive(
681 ui, archiver, os.path.join(prefix, self._path), submatch)
688 ui, archiver, os.path.join(prefix, self._path), submatch)
682 return total
689 return total
683
690
684 @annotatesubrepoerror
691 @annotatesubrepoerror
685 def dirty(self, ignoreupdate=False):
692 def dirty(self, ignoreupdate=False):
686 r = self._state[1]
693 r = self._state[1]
687 if r == '' and not ignoreupdate: # no state recorded
694 if r == '' and not ignoreupdate: # no state recorded
688 return True
695 return True
689 w = self._repo[None]
696 w = self._repo[None]
690 if r != w.p1().hex() and not ignoreupdate:
697 if r != w.p1().hex() and not ignoreupdate:
691 # different version checked out
698 # different version checked out
692 return True
699 return True
693 return w.dirty() # working directory changed
700 return w.dirty() # working directory changed
694
701
695 def basestate(self):
702 def basestate(self):
696 return self._repo['.'].hex()
703 return self._repo['.'].hex()
697
704
698 def checknested(self, path):
705 def checknested(self, path):
699 return self._repo._checknested(self._repo.wjoin(path))
706 return self._repo._checknested(self._repo.wjoin(path))
700
707
701 @annotatesubrepoerror
708 @annotatesubrepoerror
702 def commit(self, text, user, date):
709 def commit(self, text, user, date):
703 # don't bother committing in the subrepo if it's only been
710 # don't bother committing in the subrepo if it's only been
704 # updated
711 # updated
705 if not self.dirty(True):
712 if not self.dirty(True):
706 return self._repo['.'].hex()
713 return self._repo['.'].hex()
707 self._repo.ui.debug("committing subrepo %s\n" % subrelpath(self))
714 self._repo.ui.debug("committing subrepo %s\n" % subrelpath(self))
708 n = self._repo.commit(text, user, date)
715 n = self._repo.commit(text, user, date)
709 if not n:
716 if not n:
710 return self._repo['.'].hex() # different version checked out
717 return self._repo['.'].hex() # different version checked out
711 return node.hex(n)
718 return node.hex(n)
712
719
713 @annotatesubrepoerror
720 @annotatesubrepoerror
714 def phase(self, state):
721 def phase(self, state):
715 return self._repo[state].phase()
722 return self._repo[state].phase()
716
723
717 @annotatesubrepoerror
724 @annotatesubrepoerror
718 def remove(self):
725 def remove(self):
719 # we can't fully delete the repository as it may contain
726 # we can't fully delete the repository as it may contain
720 # local-only history
727 # local-only history
721 self._repo.ui.note(_('removing subrepo %s\n') % subrelpath(self))
728 self._repo.ui.note(_('removing subrepo %s\n') % subrelpath(self))
722 hg.clean(self._repo, node.nullid, False)
729 hg.clean(self._repo, node.nullid, False)
723
730
724 def _get(self, state):
731 def _get(self, state):
725 source, revision, kind = state
732 source, revision, kind = state
726 if revision in self._repo.unfiltered():
733 if revision in self._repo.unfiltered():
727 return True
734 return True
728 self._repo._subsource = source
735 self._repo._subsource = source
729 srcurl = _abssource(self._repo)
736 srcurl = _abssource(self._repo)
730 other = hg.peer(self._repo, {}, srcurl)
737 other = hg.peer(self._repo, {}, srcurl)
731 if len(self._repo) == 0:
738 if len(self._repo) == 0:
732 self._repo.ui.status(_('cloning subrepo %s from %s\n')
739 self._repo.ui.status(_('cloning subrepo %s from %s\n')
733 % (subrelpath(self), srcurl))
740 % (subrelpath(self), srcurl))
734 parentrepo = self._repo._subparent
741 parentrepo = self._repo._subparent
735 shutil.rmtree(self._repo.path)
742 shutil.rmtree(self._repo.path)
736 other, cloned = hg.clone(self._repo._subparent.baseui, {},
743 other, cloned = hg.clone(self._repo._subparent.baseui, {},
737 other, self._repo.root,
744 other, self._repo.root,
738 update=False)
745 update=False)
739 self._repo = cloned.local()
746 self._repo = cloned.local()
740 self._initrepo(parentrepo, source, create=True)
747 self._initrepo(parentrepo, source, create=True)
741 self._cachestorehash(srcurl)
748 self._cachestorehash(srcurl)
742 else:
749 else:
743 self._repo.ui.status(_('pulling subrepo %s from %s\n')
750 self._repo.ui.status(_('pulling subrepo %s from %s\n')
744 % (subrelpath(self), srcurl))
751 % (subrelpath(self), srcurl))
745 cleansub = self.storeclean(srcurl)
752 cleansub = self.storeclean(srcurl)
746 exchange.pull(self._repo, other)
753 exchange.pull(self._repo, other)
747 if cleansub:
754 if cleansub:
748 # keep the repo clean after pull
755 # keep the repo clean after pull
749 self._cachestorehash(srcurl)
756 self._cachestorehash(srcurl)
750 return False
757 return False
751
758
752 @annotatesubrepoerror
759 @annotatesubrepoerror
753 def get(self, state, overwrite=False):
760 def get(self, state, overwrite=False):
754 inrepo = self._get(state)
761 inrepo = self._get(state)
755 source, revision, kind = state
762 source, revision, kind = state
756 repo = self._repo
763 repo = self._repo
757 repo.ui.debug("getting subrepo %s\n" % self._path)
764 repo.ui.debug("getting subrepo %s\n" % self._path)
758 if inrepo:
765 if inrepo:
759 urepo = repo.unfiltered()
766 urepo = repo.unfiltered()
760 ctx = urepo[revision]
767 ctx = urepo[revision]
761 if ctx.hidden():
768 if ctx.hidden():
762 urepo.ui.warn(
769 urepo.ui.warn(
763 _('revision %s in subrepo %s is hidden\n') \
770 _('revision %s in subrepo %s is hidden\n') \
764 % (revision[0:12], self._path))
771 % (revision[0:12], self._path))
765 repo = urepo
772 repo = urepo
766 hg.updaterepo(repo, revision, overwrite)
773 hg.updaterepo(repo, revision, overwrite)
767
774
768 @annotatesubrepoerror
775 @annotatesubrepoerror
769 def merge(self, state):
776 def merge(self, state):
770 self._get(state)
777 self._get(state)
771 cur = self._repo['.']
778 cur = self._repo['.']
772 dst = self._repo[state[1]]
779 dst = self._repo[state[1]]
773 anc = dst.ancestor(cur)
780 anc = dst.ancestor(cur)
774
781
775 def mergefunc():
782 def mergefunc():
776 if anc == cur and dst.branch() == cur.branch():
783 if anc == cur and dst.branch() == cur.branch():
777 self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
784 self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
778 hg.update(self._repo, state[1])
785 hg.update(self._repo, state[1])
779 elif anc == dst:
786 elif anc == dst:
780 self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
787 self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
781 else:
788 else:
782 self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
789 self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
783 hg.merge(self._repo, state[1], remind=False)
790 hg.merge(self._repo, state[1], remind=False)
784
791
785 wctx = self._repo[None]
792 wctx = self._repo[None]
786 if self.dirty():
793 if self.dirty():
787 if anc != dst:
794 if anc != dst:
788 if _updateprompt(self._repo.ui, self, wctx.dirty(), cur, dst):
795 if _updateprompt(self._repo.ui, self, wctx.dirty(), cur, dst):
789 mergefunc()
796 mergefunc()
790 else:
797 else:
791 mergefunc()
798 mergefunc()
792 else:
799 else:
793 mergefunc()
800 mergefunc()
794
801
795 @annotatesubrepoerror
802 @annotatesubrepoerror
796 def push(self, opts):
803 def push(self, opts):
797 force = opts.get('force')
804 force = opts.get('force')
798 newbranch = opts.get('new_branch')
805 newbranch = opts.get('new_branch')
799 ssh = opts.get('ssh')
806 ssh = opts.get('ssh')
800
807
801 # push subrepos depth-first for coherent ordering
808 # push subrepos depth-first for coherent ordering
802 c = self._repo['']
809 c = self._repo['']
803 subs = c.substate # only repos that are committed
810 subs = c.substate # only repos that are committed
804 for s in sorted(subs):
811 for s in sorted(subs):
805 if c.sub(s).push(opts) == 0:
812 if c.sub(s).push(opts) == 0:
806 return False
813 return False
807
814
808 dsturl = _abssource(self._repo, True)
815 dsturl = _abssource(self._repo, True)
809 if not force:
816 if not force:
810 if self.storeclean(dsturl):
817 if self.storeclean(dsturl):
811 self._repo.ui.status(
818 self._repo.ui.status(
812 _('no changes made to subrepo %s since last push to %s\n')
819 _('no changes made to subrepo %s since last push to %s\n')
813 % (subrelpath(self), dsturl))
820 % (subrelpath(self), dsturl))
814 return None
821 return None
815 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
822 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
816 (subrelpath(self), dsturl))
823 (subrelpath(self), dsturl))
817 other = hg.peer(self._repo, {'ssh': ssh}, dsturl)
824 other = hg.peer(self._repo, {'ssh': ssh}, dsturl)
818 res = exchange.push(self._repo, other, force, newbranch=newbranch)
825 res = exchange.push(self._repo, other, force, newbranch=newbranch)
819
826
820 # the repo is now clean
827 # the repo is now clean
821 self._cachestorehash(dsturl)
828 self._cachestorehash(dsturl)
822 return res.cgresult
829 return res.cgresult
823
830
824 @annotatesubrepoerror
831 @annotatesubrepoerror
825 def outgoing(self, ui, dest, opts):
832 def outgoing(self, ui, dest, opts):
826 return hg.outgoing(ui, self._repo, _abssource(self._repo, True), opts)
833 return hg.outgoing(ui, self._repo, _abssource(self._repo, True), opts)
827
834
828 @annotatesubrepoerror
835 @annotatesubrepoerror
829 def incoming(self, ui, source, opts):
836 def incoming(self, ui, source, opts):
830 return hg.incoming(ui, self._repo, _abssource(self._repo, False), opts)
837 return hg.incoming(ui, self._repo, _abssource(self._repo, False), opts)
831
838
832 @annotatesubrepoerror
839 @annotatesubrepoerror
833 def files(self):
840 def files(self):
834 rev = self._state[1]
841 rev = self._state[1]
835 ctx = self._repo[rev]
842 ctx = self._repo[rev]
836 return ctx.manifest()
843 return ctx.manifest()
837
844
838 def filedata(self, name):
845 def filedata(self, name):
839 rev = self._state[1]
846 rev = self._state[1]
840 return self._repo[rev][name].data()
847 return self._repo[rev][name].data()
841
848
842 def fileflags(self, name):
849 def fileflags(self, name):
843 rev = self._state[1]
850 rev = self._state[1]
844 ctx = self._repo[rev]
851 ctx = self._repo[rev]
845 return ctx.flags(name)
852 return ctx.flags(name)
846
853
847 def walk(self, match):
854 def walk(self, match):
848 ctx = self._repo[None]
855 ctx = self._repo[None]
849 return ctx.walk(match)
856 return ctx.walk(match)
850
857
851 @annotatesubrepoerror
858 @annotatesubrepoerror
852 def forget(self, ui, match, prefix):
859 def forget(self, ui, match, prefix):
853 return cmdutil.forget(ui, self._repo, match,
860 return cmdutil.forget(ui, self._repo, match,
854 os.path.join(prefix, self._path), True)
861 os.path.join(prefix, self._path), True)
855
862
856 @annotatesubrepoerror
863 @annotatesubrepoerror
864 def removefiles(self, ui, matcher, prefix, after, force, subrepos):
865 return cmdutil.remove(ui, self._repo, matcher,
866 os.path.join(prefix, self._path), after, force,
867 subrepos)
868
869 @annotatesubrepoerror
857 def revert(self, ui, substate, *pats, **opts):
870 def revert(self, ui, substate, *pats, **opts):
858 # reverting a subrepo is a 2 step process:
871 # reverting a subrepo is a 2 step process:
859 # 1. if the no_backup is not set, revert all modified
872 # 1. if the no_backup is not set, revert all modified
860 # files inside the subrepo
873 # files inside the subrepo
861 # 2. update the subrepo to the revision specified in
874 # 2. update the subrepo to the revision specified in
862 # the corresponding substate dictionary
875 # the corresponding substate dictionary
863 ui.status(_('reverting subrepo %s\n') % substate[0])
876 ui.status(_('reverting subrepo %s\n') % substate[0])
864 if not opts.get('no_backup'):
877 if not opts.get('no_backup'):
865 # Revert all files on the subrepo, creating backups
878 # Revert all files on the subrepo, creating backups
866 # Note that this will not recursively revert subrepos
879 # Note that this will not recursively revert subrepos
867 # We could do it if there was a set:subrepos() predicate
880 # We could do it if there was a set:subrepos() predicate
868 opts = opts.copy()
881 opts = opts.copy()
869 opts['date'] = None
882 opts['date'] = None
870 opts['rev'] = substate[1]
883 opts['rev'] = substate[1]
871
884
872 pats = []
885 pats = []
873 if not opts.get('all'):
886 if not opts.get('all'):
874 pats = ['set:modified()']
887 pats = ['set:modified()']
875 self.filerevert(ui, *pats, **opts)
888 self.filerevert(ui, *pats, **opts)
876
889
877 # Update the repo to the revision specified in the given substate
890 # Update the repo to the revision specified in the given substate
878 self.get(substate, overwrite=True)
891 self.get(substate, overwrite=True)
879
892
880 def filerevert(self, ui, *pats, **opts):
893 def filerevert(self, ui, *pats, **opts):
881 ctx = self._repo[opts['rev']]
894 ctx = self._repo[opts['rev']]
882 parents = self._repo.dirstate.parents()
895 parents = self._repo.dirstate.parents()
883 if opts.get('all'):
896 if opts.get('all'):
884 pats = ['set:modified()']
897 pats = ['set:modified()']
885 else:
898 else:
886 pats = []
899 pats = []
887 cmdutil.revert(ui, self._repo, ctx, parents, *pats, **opts)
900 cmdutil.revert(ui, self._repo, ctx, parents, *pats, **opts)
888
901
889 def shortid(self, revid):
902 def shortid(self, revid):
890 return revid[:12]
903 return revid[:12]
891
904
892 class svnsubrepo(abstractsubrepo):
905 class svnsubrepo(abstractsubrepo):
893 def __init__(self, ctx, path, state):
906 def __init__(self, ctx, path, state):
894 self._path = path
907 self._path = path
895 self._state = state
908 self._state = state
896 self._ctx = ctx
909 self._ctx = ctx
897 self._ui = ctx._repo.ui
910 self._ui = ctx._repo.ui
898 self._exe = util.findexe('svn')
911 self._exe = util.findexe('svn')
899 if not self._exe:
912 if not self._exe:
900 raise util.Abort(_("'svn' executable not found for subrepo '%s'")
913 raise util.Abort(_("'svn' executable not found for subrepo '%s'")
901 % self._path)
914 % self._path)
902
915
903 def _svncommand(self, commands, filename='', failok=False):
916 def _svncommand(self, commands, filename='', failok=False):
904 cmd = [self._exe]
917 cmd = [self._exe]
905 extrakw = {}
918 extrakw = {}
906 if not self._ui.interactive():
919 if not self._ui.interactive():
907 # Making stdin be a pipe should prevent svn from behaving
920 # Making stdin be a pipe should prevent svn from behaving
908 # interactively even if we can't pass --non-interactive.
921 # interactively even if we can't pass --non-interactive.
909 extrakw['stdin'] = subprocess.PIPE
922 extrakw['stdin'] = subprocess.PIPE
910 # Starting in svn 1.5 --non-interactive is a global flag
923 # Starting in svn 1.5 --non-interactive is a global flag
911 # instead of being per-command, but we need to support 1.4 so
924 # instead of being per-command, but we need to support 1.4 so
912 # we have to be intelligent about what commands take
925 # we have to be intelligent about what commands take
913 # --non-interactive.
926 # --non-interactive.
914 if commands[0] in ('update', 'checkout', 'commit'):
927 if commands[0] in ('update', 'checkout', 'commit'):
915 cmd.append('--non-interactive')
928 cmd.append('--non-interactive')
916 cmd.extend(commands)
929 cmd.extend(commands)
917 if filename is not None:
930 if filename is not None:
918 path = os.path.join(self._ctx._repo.origroot, self._path, filename)
931 path = os.path.join(self._ctx._repo.origroot, self._path, filename)
919 cmd.append(path)
932 cmd.append(path)
920 env = dict(os.environ)
933 env = dict(os.environ)
921 # Avoid localized output, preserve current locale for everything else.
934 # Avoid localized output, preserve current locale for everything else.
922 lc_all = env.get('LC_ALL')
935 lc_all = env.get('LC_ALL')
923 if lc_all:
936 if lc_all:
924 env['LANG'] = lc_all
937 env['LANG'] = lc_all
925 del env['LC_ALL']
938 del env['LC_ALL']
926 env['LC_MESSAGES'] = 'C'
939 env['LC_MESSAGES'] = 'C'
927 p = subprocess.Popen(cmd, bufsize=-1, close_fds=util.closefds,
940 p = subprocess.Popen(cmd, bufsize=-1, close_fds=util.closefds,
928 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
941 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
929 universal_newlines=True, env=env, **extrakw)
942 universal_newlines=True, env=env, **extrakw)
930 stdout, stderr = p.communicate()
943 stdout, stderr = p.communicate()
931 stderr = stderr.strip()
944 stderr = stderr.strip()
932 if not failok:
945 if not failok:
933 if p.returncode:
946 if p.returncode:
934 raise util.Abort(stderr or 'exited with code %d' % p.returncode)
947 raise util.Abort(stderr or 'exited with code %d' % p.returncode)
935 if stderr:
948 if stderr:
936 self._ui.warn(stderr + '\n')
949 self._ui.warn(stderr + '\n')
937 return stdout, stderr
950 return stdout, stderr
938
951
939 @propertycache
952 @propertycache
940 def _svnversion(self):
953 def _svnversion(self):
941 output, err = self._svncommand(['--version', '--quiet'], filename=None)
954 output, err = self._svncommand(['--version', '--quiet'], filename=None)
942 m = re.search(r'^(\d+)\.(\d+)', output)
955 m = re.search(r'^(\d+)\.(\d+)', output)
943 if not m:
956 if not m:
944 raise util.Abort(_('cannot retrieve svn tool version'))
957 raise util.Abort(_('cannot retrieve svn tool version'))
945 return (int(m.group(1)), int(m.group(2)))
958 return (int(m.group(1)), int(m.group(2)))
946
959
947 def _wcrevs(self):
960 def _wcrevs(self):
948 # Get the working directory revision as well as the last
961 # Get the working directory revision as well as the last
949 # commit revision so we can compare the subrepo state with
962 # commit revision so we can compare the subrepo state with
950 # both. We used to store the working directory one.
963 # both. We used to store the working directory one.
951 output, err = self._svncommand(['info', '--xml'])
964 output, err = self._svncommand(['info', '--xml'])
952 doc = xml.dom.minidom.parseString(output)
965 doc = xml.dom.minidom.parseString(output)
953 entries = doc.getElementsByTagName('entry')
966 entries = doc.getElementsByTagName('entry')
954 lastrev, rev = '0', '0'
967 lastrev, rev = '0', '0'
955 if entries:
968 if entries:
956 rev = str(entries[0].getAttribute('revision')) or '0'
969 rev = str(entries[0].getAttribute('revision')) or '0'
957 commits = entries[0].getElementsByTagName('commit')
970 commits = entries[0].getElementsByTagName('commit')
958 if commits:
971 if commits:
959 lastrev = str(commits[0].getAttribute('revision')) or '0'
972 lastrev = str(commits[0].getAttribute('revision')) or '0'
960 return (lastrev, rev)
973 return (lastrev, rev)
961
974
962 def _wcrev(self):
975 def _wcrev(self):
963 return self._wcrevs()[0]
976 return self._wcrevs()[0]
964
977
965 def _wcchanged(self):
978 def _wcchanged(self):
966 """Return (changes, extchanges, missing) where changes is True
979 """Return (changes, extchanges, missing) where changes is True
967 if the working directory was changed, extchanges is
980 if the working directory was changed, extchanges is
968 True if any of these changes concern an external entry and missing
981 True if any of these changes concern an external entry and missing
969 is True if any change is a missing entry.
982 is True if any change is a missing entry.
970 """
983 """
971 output, err = self._svncommand(['status', '--xml'])
984 output, err = self._svncommand(['status', '--xml'])
972 externals, changes, missing = [], [], []
985 externals, changes, missing = [], [], []
973 doc = xml.dom.minidom.parseString(output)
986 doc = xml.dom.minidom.parseString(output)
974 for e in doc.getElementsByTagName('entry'):
987 for e in doc.getElementsByTagName('entry'):
975 s = e.getElementsByTagName('wc-status')
988 s = e.getElementsByTagName('wc-status')
976 if not s:
989 if not s:
977 continue
990 continue
978 item = s[0].getAttribute('item')
991 item = s[0].getAttribute('item')
979 props = s[0].getAttribute('props')
992 props = s[0].getAttribute('props')
980 path = e.getAttribute('path')
993 path = e.getAttribute('path')
981 if item == 'external':
994 if item == 'external':
982 externals.append(path)
995 externals.append(path)
983 elif item == 'missing':
996 elif item == 'missing':
984 missing.append(path)
997 missing.append(path)
985 if (item not in ('', 'normal', 'unversioned', 'external')
998 if (item not in ('', 'normal', 'unversioned', 'external')
986 or props not in ('', 'none', 'normal')):
999 or props not in ('', 'none', 'normal')):
987 changes.append(path)
1000 changes.append(path)
988 for path in changes:
1001 for path in changes:
989 for ext in externals:
1002 for ext in externals:
990 if path == ext or path.startswith(ext + os.sep):
1003 if path == ext or path.startswith(ext + os.sep):
991 return True, True, bool(missing)
1004 return True, True, bool(missing)
992 return bool(changes), False, bool(missing)
1005 return bool(changes), False, bool(missing)
993
1006
994 def dirty(self, ignoreupdate=False):
1007 def dirty(self, ignoreupdate=False):
995 if not self._wcchanged()[0]:
1008 if not self._wcchanged()[0]:
996 if self._state[1] in self._wcrevs() or ignoreupdate:
1009 if self._state[1] in self._wcrevs() or ignoreupdate:
997 return False
1010 return False
998 return True
1011 return True
999
1012
1000 def basestate(self):
1013 def basestate(self):
1001 lastrev, rev = self._wcrevs()
1014 lastrev, rev = self._wcrevs()
1002 if lastrev != rev:
1015 if lastrev != rev:
1003 # Last committed rev is not the same than rev. We would
1016 # Last committed rev is not the same than rev. We would
1004 # like to take lastrev but we do not know if the subrepo
1017 # like to take lastrev but we do not know if the subrepo
1005 # URL exists at lastrev. Test it and fallback to rev it
1018 # URL exists at lastrev. Test it and fallback to rev it
1006 # is not there.
1019 # is not there.
1007 try:
1020 try:
1008 self._svncommand(['list', '%s@%s' % (self._state[0], lastrev)])
1021 self._svncommand(['list', '%s@%s' % (self._state[0], lastrev)])
1009 return lastrev
1022 return lastrev
1010 except error.Abort:
1023 except error.Abort:
1011 pass
1024 pass
1012 return rev
1025 return rev
1013
1026
1014 @annotatesubrepoerror
1027 @annotatesubrepoerror
1015 def commit(self, text, user, date):
1028 def commit(self, text, user, date):
1016 # user and date are out of our hands since svn is centralized
1029 # user and date are out of our hands since svn is centralized
1017 changed, extchanged, missing = self._wcchanged()
1030 changed, extchanged, missing = self._wcchanged()
1018 if not changed:
1031 if not changed:
1019 return self.basestate()
1032 return self.basestate()
1020 if extchanged:
1033 if extchanged:
1021 # Do not try to commit externals
1034 # Do not try to commit externals
1022 raise util.Abort(_('cannot commit svn externals'))
1035 raise util.Abort(_('cannot commit svn externals'))
1023 if missing:
1036 if missing:
1024 # svn can commit with missing entries but aborting like hg
1037 # svn can commit with missing entries but aborting like hg
1025 # seems a better approach.
1038 # seems a better approach.
1026 raise util.Abort(_('cannot commit missing svn entries'))
1039 raise util.Abort(_('cannot commit missing svn entries'))
1027 commitinfo, err = self._svncommand(['commit', '-m', text])
1040 commitinfo, err = self._svncommand(['commit', '-m', text])
1028 self._ui.status(commitinfo)
1041 self._ui.status(commitinfo)
1029 newrev = re.search('Committed revision ([0-9]+).', commitinfo)
1042 newrev = re.search('Committed revision ([0-9]+).', commitinfo)
1030 if not newrev:
1043 if not newrev:
1031 if not commitinfo.strip():
1044 if not commitinfo.strip():
1032 # Sometimes, our definition of "changed" differs from
1045 # Sometimes, our definition of "changed" differs from
1033 # svn one. For instance, svn ignores missing files
1046 # svn one. For instance, svn ignores missing files
1034 # when committing. If there are only missing files, no
1047 # when committing. If there are only missing files, no
1035 # commit is made, no output and no error code.
1048 # commit is made, no output and no error code.
1036 raise util.Abort(_('failed to commit svn changes'))
1049 raise util.Abort(_('failed to commit svn changes'))
1037 raise util.Abort(commitinfo.splitlines()[-1])
1050 raise util.Abort(commitinfo.splitlines()[-1])
1038 newrev = newrev.groups()[0]
1051 newrev = newrev.groups()[0]
1039 self._ui.status(self._svncommand(['update', '-r', newrev])[0])
1052 self._ui.status(self._svncommand(['update', '-r', newrev])[0])
1040 return newrev
1053 return newrev
1041
1054
1042 @annotatesubrepoerror
1055 @annotatesubrepoerror
1043 def remove(self):
1056 def remove(self):
1044 if self.dirty():
1057 if self.dirty():
1045 self._ui.warn(_('not removing repo %s because '
1058 self._ui.warn(_('not removing repo %s because '
1046 'it has changes.\n') % self._path)
1059 'it has changes.\n') % self._path)
1047 return
1060 return
1048 self._ui.note(_('removing subrepo %s\n') % self._path)
1061 self._ui.note(_('removing subrepo %s\n') % self._path)
1049
1062
1050 def onerror(function, path, excinfo):
1063 def onerror(function, path, excinfo):
1051 if function is not os.remove:
1064 if function is not os.remove:
1052 raise
1065 raise
1053 # read-only files cannot be unlinked under Windows
1066 # read-only files cannot be unlinked under Windows
1054 s = os.stat(path)
1067 s = os.stat(path)
1055 if (s.st_mode & stat.S_IWRITE) != 0:
1068 if (s.st_mode & stat.S_IWRITE) != 0:
1056 raise
1069 raise
1057 os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
1070 os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
1058 os.remove(path)
1071 os.remove(path)
1059
1072
1060 path = self._ctx._repo.wjoin(self._path)
1073 path = self._ctx._repo.wjoin(self._path)
1061 shutil.rmtree(path, onerror=onerror)
1074 shutil.rmtree(path, onerror=onerror)
1062 try:
1075 try:
1063 os.removedirs(os.path.dirname(path))
1076 os.removedirs(os.path.dirname(path))
1064 except OSError:
1077 except OSError:
1065 pass
1078 pass
1066
1079
1067 @annotatesubrepoerror
1080 @annotatesubrepoerror
1068 def get(self, state, overwrite=False):
1081 def get(self, state, overwrite=False):
1069 if overwrite:
1082 if overwrite:
1070 self._svncommand(['revert', '--recursive'])
1083 self._svncommand(['revert', '--recursive'])
1071 args = ['checkout']
1084 args = ['checkout']
1072 if self._svnversion >= (1, 5):
1085 if self._svnversion >= (1, 5):
1073 args.append('--force')
1086 args.append('--force')
1074 # The revision must be specified at the end of the URL to properly
1087 # The revision must be specified at the end of the URL to properly
1075 # update to a directory which has since been deleted and recreated.
1088 # update to a directory which has since been deleted and recreated.
1076 args.append('%s@%s' % (state[0], state[1]))
1089 args.append('%s@%s' % (state[0], state[1]))
1077 status, err = self._svncommand(args, failok=True)
1090 status, err = self._svncommand(args, failok=True)
1078 _sanitize(self._ui, self._ctx._repo.wjoin(self._path), '.svn')
1091 _sanitize(self._ui, self._ctx._repo.wjoin(self._path), '.svn')
1079 if not re.search('Checked out revision [0-9]+.', status):
1092 if not re.search('Checked out revision [0-9]+.', status):
1080 if ('is already a working copy for a different URL' in err
1093 if ('is already a working copy for a different URL' in err
1081 and (self._wcchanged()[:2] == (False, False))):
1094 and (self._wcchanged()[:2] == (False, False))):
1082 # obstructed but clean working copy, so just blow it away.
1095 # obstructed but clean working copy, so just blow it away.
1083 self.remove()
1096 self.remove()
1084 self.get(state, overwrite=False)
1097 self.get(state, overwrite=False)
1085 return
1098 return
1086 raise util.Abort((status or err).splitlines()[-1])
1099 raise util.Abort((status or err).splitlines()[-1])
1087 self._ui.status(status)
1100 self._ui.status(status)
1088
1101
1089 @annotatesubrepoerror
1102 @annotatesubrepoerror
1090 def merge(self, state):
1103 def merge(self, state):
1091 old = self._state[1]
1104 old = self._state[1]
1092 new = state[1]
1105 new = state[1]
1093 wcrev = self._wcrev()
1106 wcrev = self._wcrev()
1094 if new != wcrev:
1107 if new != wcrev:
1095 dirty = old == wcrev or self._wcchanged()[0]
1108 dirty = old == wcrev or self._wcchanged()[0]
1096 if _updateprompt(self._ui, self, dirty, wcrev, new):
1109 if _updateprompt(self._ui, self, dirty, wcrev, new):
1097 self.get(state, False)
1110 self.get(state, False)
1098
1111
1099 def push(self, opts):
1112 def push(self, opts):
1100 # push is a no-op for SVN
1113 # push is a no-op for SVN
1101 return True
1114 return True
1102
1115
1103 @annotatesubrepoerror
1116 @annotatesubrepoerror
1104 def files(self):
1117 def files(self):
1105 output = self._svncommand(['list', '--recursive', '--xml'])[0]
1118 output = self._svncommand(['list', '--recursive', '--xml'])[0]
1106 doc = xml.dom.minidom.parseString(output)
1119 doc = xml.dom.minidom.parseString(output)
1107 paths = []
1120 paths = []
1108 for e in doc.getElementsByTagName('entry'):
1121 for e in doc.getElementsByTagName('entry'):
1109 kind = str(e.getAttribute('kind'))
1122 kind = str(e.getAttribute('kind'))
1110 if kind != 'file':
1123 if kind != 'file':
1111 continue
1124 continue
1112 name = ''.join(c.data for c
1125 name = ''.join(c.data for c
1113 in e.getElementsByTagName('name')[0].childNodes
1126 in e.getElementsByTagName('name')[0].childNodes
1114 if c.nodeType == c.TEXT_NODE)
1127 if c.nodeType == c.TEXT_NODE)
1115 paths.append(name.encode('utf-8'))
1128 paths.append(name.encode('utf-8'))
1116 return paths
1129 return paths
1117
1130
1118 def filedata(self, name):
1131 def filedata(self, name):
1119 return self._svncommand(['cat'], name)[0]
1132 return self._svncommand(['cat'], name)[0]
1120
1133
1121
1134
1122 class gitsubrepo(abstractsubrepo):
1135 class gitsubrepo(abstractsubrepo):
1123 def __init__(self, ctx, path, state):
1136 def __init__(self, ctx, path, state):
1124 self._state = state
1137 self._state = state
1125 self._ctx = ctx
1138 self._ctx = ctx
1126 self._path = path
1139 self._path = path
1127 self._relpath = os.path.join(reporelpath(ctx._repo), path)
1140 self._relpath = os.path.join(reporelpath(ctx._repo), path)
1128 self._abspath = ctx._repo.wjoin(path)
1141 self._abspath = ctx._repo.wjoin(path)
1129 self._subparent = ctx._repo
1142 self._subparent = ctx._repo
1130 self._ui = ctx._repo.ui
1143 self._ui = ctx._repo.ui
1131 self._ensuregit()
1144 self._ensuregit()
1132
1145
1133 def _ensuregit(self):
1146 def _ensuregit(self):
1134 try:
1147 try:
1135 self._gitexecutable = 'git'
1148 self._gitexecutable = 'git'
1136 out, err = self._gitnodir(['--version'])
1149 out, err = self._gitnodir(['--version'])
1137 except OSError, e:
1150 except OSError, e:
1138 if e.errno != 2 or os.name != 'nt':
1151 if e.errno != 2 or os.name != 'nt':
1139 raise
1152 raise
1140 self._gitexecutable = 'git.cmd'
1153 self._gitexecutable = 'git.cmd'
1141 out, err = self._gitnodir(['--version'])
1154 out, err = self._gitnodir(['--version'])
1142 versionstatus = self._checkversion(out)
1155 versionstatus = self._checkversion(out)
1143 if versionstatus == 'unknown':
1156 if versionstatus == 'unknown':
1144 self._ui.warn(_('cannot retrieve git version\n'))
1157 self._ui.warn(_('cannot retrieve git version\n'))
1145 elif versionstatus == 'abort':
1158 elif versionstatus == 'abort':
1146 raise util.Abort(_('git subrepo requires at least 1.6.0 or later'))
1159 raise util.Abort(_('git subrepo requires at least 1.6.0 or later'))
1147 elif versionstatus == 'warning':
1160 elif versionstatus == 'warning':
1148 self._ui.warn(_('git subrepo requires at least 1.6.0 or later\n'))
1161 self._ui.warn(_('git subrepo requires at least 1.6.0 or later\n'))
1149
1162
1150 @staticmethod
1163 @staticmethod
1151 def _checkversion(out):
1164 def _checkversion(out):
1152 '''ensure git version is new enough
1165 '''ensure git version is new enough
1153
1166
1154 >>> _checkversion = gitsubrepo._checkversion
1167 >>> _checkversion = gitsubrepo._checkversion
1155 >>> _checkversion('git version 1.6.0')
1168 >>> _checkversion('git version 1.6.0')
1156 'ok'
1169 'ok'
1157 >>> _checkversion('git version 1.8.5')
1170 >>> _checkversion('git version 1.8.5')
1158 'ok'
1171 'ok'
1159 >>> _checkversion('git version 1.4.0')
1172 >>> _checkversion('git version 1.4.0')
1160 'abort'
1173 'abort'
1161 >>> _checkversion('git version 1.5.0')
1174 >>> _checkversion('git version 1.5.0')
1162 'warning'
1175 'warning'
1163 >>> _checkversion('git version 1.9-rc0')
1176 >>> _checkversion('git version 1.9-rc0')
1164 'ok'
1177 'ok'
1165 >>> _checkversion('git version 1.9.0.265.g81cdec2')
1178 >>> _checkversion('git version 1.9.0.265.g81cdec2')
1166 'ok'
1179 'ok'
1167 >>> _checkversion('git version 1.9.0.GIT')
1180 >>> _checkversion('git version 1.9.0.GIT')
1168 'ok'
1181 'ok'
1169 >>> _checkversion('git version 12345')
1182 >>> _checkversion('git version 12345')
1170 'unknown'
1183 'unknown'
1171 >>> _checkversion('no')
1184 >>> _checkversion('no')
1172 'unknown'
1185 'unknown'
1173 '''
1186 '''
1174 m = re.search(r'^git version (\d+)\.(\d+)', out)
1187 m = re.search(r'^git version (\d+)\.(\d+)', out)
1175 if not m:
1188 if not m:
1176 return 'unknown'
1189 return 'unknown'
1177 version = (int(m.group(1)), int(m.group(2)))
1190 version = (int(m.group(1)), int(m.group(2)))
1178 # git 1.4.0 can't work at all, but 1.5.X can in at least some cases,
1191 # git 1.4.0 can't work at all, but 1.5.X can in at least some cases,
1179 # despite the docstring comment. For now, error on 1.4.0, warn on
1192 # despite the docstring comment. For now, error on 1.4.0, warn on
1180 # 1.5.0 but attempt to continue.
1193 # 1.5.0 but attempt to continue.
1181 if version < (1, 5):
1194 if version < (1, 5):
1182 return 'abort'
1195 return 'abort'
1183 elif version < (1, 6):
1196 elif version < (1, 6):
1184 return 'warning'
1197 return 'warning'
1185 return 'ok'
1198 return 'ok'
1186
1199
1187 def _gitcommand(self, commands, env=None, stream=False):
1200 def _gitcommand(self, commands, env=None, stream=False):
1188 return self._gitdir(commands, env=env, stream=stream)[0]
1201 return self._gitdir(commands, env=env, stream=stream)[0]
1189
1202
1190 def _gitdir(self, commands, env=None, stream=False):
1203 def _gitdir(self, commands, env=None, stream=False):
1191 return self._gitnodir(commands, env=env, stream=stream,
1204 return self._gitnodir(commands, env=env, stream=stream,
1192 cwd=self._abspath)
1205 cwd=self._abspath)
1193
1206
1194 def _gitnodir(self, commands, env=None, stream=False, cwd=None):
1207 def _gitnodir(self, commands, env=None, stream=False, cwd=None):
1195 """Calls the git command
1208 """Calls the git command
1196
1209
1197 The methods tries to call the git command. versions prior to 1.6.0
1210 The methods tries to call the git command. versions prior to 1.6.0
1198 are not supported and very probably fail.
1211 are not supported and very probably fail.
1199 """
1212 """
1200 self._ui.debug('%s: git %s\n' % (self._relpath, ' '.join(commands)))
1213 self._ui.debug('%s: git %s\n' % (self._relpath, ' '.join(commands)))
1201 # unless ui.quiet is set, print git's stderr,
1214 # unless ui.quiet is set, print git's stderr,
1202 # which is mostly progress and useful info
1215 # which is mostly progress and useful info
1203 errpipe = None
1216 errpipe = None
1204 if self._ui.quiet:
1217 if self._ui.quiet:
1205 errpipe = open(os.devnull, 'w')
1218 errpipe = open(os.devnull, 'w')
1206 p = subprocess.Popen([self._gitexecutable] + commands, bufsize=-1,
1219 p = subprocess.Popen([self._gitexecutable] + commands, bufsize=-1,
1207 cwd=cwd, env=env, close_fds=util.closefds,
1220 cwd=cwd, env=env, close_fds=util.closefds,
1208 stdout=subprocess.PIPE, stderr=errpipe)
1221 stdout=subprocess.PIPE, stderr=errpipe)
1209 if stream:
1222 if stream:
1210 return p.stdout, None
1223 return p.stdout, None
1211
1224
1212 retdata = p.stdout.read().strip()
1225 retdata = p.stdout.read().strip()
1213 # wait for the child to exit to avoid race condition.
1226 # wait for the child to exit to avoid race condition.
1214 p.wait()
1227 p.wait()
1215
1228
1216 if p.returncode != 0 and p.returncode != 1:
1229 if p.returncode != 0 and p.returncode != 1:
1217 # there are certain error codes that are ok
1230 # there are certain error codes that are ok
1218 command = commands[0]
1231 command = commands[0]
1219 if command in ('cat-file', 'symbolic-ref'):
1232 if command in ('cat-file', 'symbolic-ref'):
1220 return retdata, p.returncode
1233 return retdata, p.returncode
1221 # for all others, abort
1234 # for all others, abort
1222 raise util.Abort('git %s error %d in %s' %
1235 raise util.Abort('git %s error %d in %s' %
1223 (command, p.returncode, self._relpath))
1236 (command, p.returncode, self._relpath))
1224
1237
1225 return retdata, p.returncode
1238 return retdata, p.returncode
1226
1239
1227 def _gitmissing(self):
1240 def _gitmissing(self):
1228 return not os.path.exists(os.path.join(self._abspath, '.git'))
1241 return not os.path.exists(os.path.join(self._abspath, '.git'))
1229
1242
1230 def _gitstate(self):
1243 def _gitstate(self):
1231 return self._gitcommand(['rev-parse', 'HEAD'])
1244 return self._gitcommand(['rev-parse', 'HEAD'])
1232
1245
1233 def _gitcurrentbranch(self):
1246 def _gitcurrentbranch(self):
1234 current, err = self._gitdir(['symbolic-ref', 'HEAD', '--quiet'])
1247 current, err = self._gitdir(['symbolic-ref', 'HEAD', '--quiet'])
1235 if err:
1248 if err:
1236 current = None
1249 current = None
1237 return current
1250 return current
1238
1251
1239 def _gitremote(self, remote):
1252 def _gitremote(self, remote):
1240 out = self._gitcommand(['remote', 'show', '-n', remote])
1253 out = self._gitcommand(['remote', 'show', '-n', remote])
1241 line = out.split('\n')[1]
1254 line = out.split('\n')[1]
1242 i = line.index('URL: ') + len('URL: ')
1255 i = line.index('URL: ') + len('URL: ')
1243 return line[i:]
1256 return line[i:]
1244
1257
1245 def _githavelocally(self, revision):
1258 def _githavelocally(self, revision):
1246 out, code = self._gitdir(['cat-file', '-e', revision])
1259 out, code = self._gitdir(['cat-file', '-e', revision])
1247 return code == 0
1260 return code == 0
1248
1261
1249 def _gitisancestor(self, r1, r2):
1262 def _gitisancestor(self, r1, r2):
1250 base = self._gitcommand(['merge-base', r1, r2])
1263 base = self._gitcommand(['merge-base', r1, r2])
1251 return base == r1
1264 return base == r1
1252
1265
1253 def _gitisbare(self):
1266 def _gitisbare(self):
1254 return self._gitcommand(['config', '--bool', 'core.bare']) == 'true'
1267 return self._gitcommand(['config', '--bool', 'core.bare']) == 'true'
1255
1268
1256 def _gitupdatestat(self):
1269 def _gitupdatestat(self):
1257 """This must be run before git diff-index.
1270 """This must be run before git diff-index.
1258 diff-index only looks at changes to file stat;
1271 diff-index only looks at changes to file stat;
1259 this command looks at file contents and updates the stat."""
1272 this command looks at file contents and updates the stat."""
1260 self._gitcommand(['update-index', '-q', '--refresh'])
1273 self._gitcommand(['update-index', '-q', '--refresh'])
1261
1274
1262 def _gitbranchmap(self):
1275 def _gitbranchmap(self):
1263 '''returns 2 things:
1276 '''returns 2 things:
1264 a map from git branch to revision
1277 a map from git branch to revision
1265 a map from revision to branches'''
1278 a map from revision to branches'''
1266 branch2rev = {}
1279 branch2rev = {}
1267 rev2branch = {}
1280 rev2branch = {}
1268
1281
1269 out = self._gitcommand(['for-each-ref', '--format',
1282 out = self._gitcommand(['for-each-ref', '--format',
1270 '%(objectname) %(refname)'])
1283 '%(objectname) %(refname)'])
1271 for line in out.split('\n'):
1284 for line in out.split('\n'):
1272 revision, ref = line.split(' ')
1285 revision, ref = line.split(' ')
1273 if (not ref.startswith('refs/heads/') and
1286 if (not ref.startswith('refs/heads/') and
1274 not ref.startswith('refs/remotes/')):
1287 not ref.startswith('refs/remotes/')):
1275 continue
1288 continue
1276 if ref.startswith('refs/remotes/') and ref.endswith('/HEAD'):
1289 if ref.startswith('refs/remotes/') and ref.endswith('/HEAD'):
1277 continue # ignore remote/HEAD redirects
1290 continue # ignore remote/HEAD redirects
1278 branch2rev[ref] = revision
1291 branch2rev[ref] = revision
1279 rev2branch.setdefault(revision, []).append(ref)
1292 rev2branch.setdefault(revision, []).append(ref)
1280 return branch2rev, rev2branch
1293 return branch2rev, rev2branch
1281
1294
1282 def _gittracking(self, branches):
1295 def _gittracking(self, branches):
1283 'return map of remote branch to local tracking branch'
1296 'return map of remote branch to local tracking branch'
1284 # assumes no more than one local tracking branch for each remote
1297 # assumes no more than one local tracking branch for each remote
1285 tracking = {}
1298 tracking = {}
1286 for b in branches:
1299 for b in branches:
1287 if b.startswith('refs/remotes/'):
1300 if b.startswith('refs/remotes/'):
1288 continue
1301 continue
1289 bname = b.split('/', 2)[2]
1302 bname = b.split('/', 2)[2]
1290 remote = self._gitcommand(['config', 'branch.%s.remote' % bname])
1303 remote = self._gitcommand(['config', 'branch.%s.remote' % bname])
1291 if remote:
1304 if remote:
1292 ref = self._gitcommand(['config', 'branch.%s.merge' % bname])
1305 ref = self._gitcommand(['config', 'branch.%s.merge' % bname])
1293 tracking['refs/remotes/%s/%s' %
1306 tracking['refs/remotes/%s/%s' %
1294 (remote, ref.split('/', 2)[2])] = b
1307 (remote, ref.split('/', 2)[2])] = b
1295 return tracking
1308 return tracking
1296
1309
1297 def _abssource(self, source):
1310 def _abssource(self, source):
1298 if '://' not in source:
1311 if '://' not in source:
1299 # recognize the scp syntax as an absolute source
1312 # recognize the scp syntax as an absolute source
1300 colon = source.find(':')
1313 colon = source.find(':')
1301 if colon != -1 and '/' not in source[:colon]:
1314 if colon != -1 and '/' not in source[:colon]:
1302 return source
1315 return source
1303 self._subsource = source
1316 self._subsource = source
1304 return _abssource(self)
1317 return _abssource(self)
1305
1318
1306 def _fetch(self, source, revision):
1319 def _fetch(self, source, revision):
1307 if self._gitmissing():
1320 if self._gitmissing():
1308 source = self._abssource(source)
1321 source = self._abssource(source)
1309 self._ui.status(_('cloning subrepo %s from %s\n') %
1322 self._ui.status(_('cloning subrepo %s from %s\n') %
1310 (self._relpath, source))
1323 (self._relpath, source))
1311 self._gitnodir(['clone', source, self._abspath])
1324 self._gitnodir(['clone', source, self._abspath])
1312 if self._githavelocally(revision):
1325 if self._githavelocally(revision):
1313 return
1326 return
1314 self._ui.status(_('pulling subrepo %s from %s\n') %
1327 self._ui.status(_('pulling subrepo %s from %s\n') %
1315 (self._relpath, self._gitremote('origin')))
1328 (self._relpath, self._gitremote('origin')))
1316 # try only origin: the originally cloned repo
1329 # try only origin: the originally cloned repo
1317 self._gitcommand(['fetch'])
1330 self._gitcommand(['fetch'])
1318 if not self._githavelocally(revision):
1331 if not self._githavelocally(revision):
1319 raise util.Abort(_("revision %s does not exist in subrepo %s\n") %
1332 raise util.Abort(_("revision %s does not exist in subrepo %s\n") %
1320 (revision, self._relpath))
1333 (revision, self._relpath))
1321
1334
1322 @annotatesubrepoerror
1335 @annotatesubrepoerror
1323 def dirty(self, ignoreupdate=False):
1336 def dirty(self, ignoreupdate=False):
1324 if self._gitmissing():
1337 if self._gitmissing():
1325 return self._state[1] != ''
1338 return self._state[1] != ''
1326 if self._gitisbare():
1339 if self._gitisbare():
1327 return True
1340 return True
1328 if not ignoreupdate and self._state[1] != self._gitstate():
1341 if not ignoreupdate and self._state[1] != self._gitstate():
1329 # different version checked out
1342 # different version checked out
1330 return True
1343 return True
1331 # check for staged changes or modified files; ignore untracked files
1344 # check for staged changes or modified files; ignore untracked files
1332 self._gitupdatestat()
1345 self._gitupdatestat()
1333 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
1346 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
1334 return code == 1
1347 return code == 1
1335
1348
1336 def basestate(self):
1349 def basestate(self):
1337 return self._gitstate()
1350 return self._gitstate()
1338
1351
1339 @annotatesubrepoerror
1352 @annotatesubrepoerror
1340 def get(self, state, overwrite=False):
1353 def get(self, state, overwrite=False):
1341 source, revision, kind = state
1354 source, revision, kind = state
1342 if not revision:
1355 if not revision:
1343 self.remove()
1356 self.remove()
1344 return
1357 return
1345 self._fetch(source, revision)
1358 self._fetch(source, revision)
1346 # if the repo was set to be bare, unbare it
1359 # if the repo was set to be bare, unbare it
1347 if self._gitisbare():
1360 if self._gitisbare():
1348 self._gitcommand(['config', 'core.bare', 'false'])
1361 self._gitcommand(['config', 'core.bare', 'false'])
1349 if self._gitstate() == revision:
1362 if self._gitstate() == revision:
1350 self._gitcommand(['reset', '--hard', 'HEAD'])
1363 self._gitcommand(['reset', '--hard', 'HEAD'])
1351 return
1364 return
1352 elif self._gitstate() == revision:
1365 elif self._gitstate() == revision:
1353 if overwrite:
1366 if overwrite:
1354 # first reset the index to unmark new files for commit, because
1367 # first reset the index to unmark new files for commit, because
1355 # reset --hard will otherwise throw away files added for commit,
1368 # reset --hard will otherwise throw away files added for commit,
1356 # not just unmark them.
1369 # not just unmark them.
1357 self._gitcommand(['reset', 'HEAD'])
1370 self._gitcommand(['reset', 'HEAD'])
1358 self._gitcommand(['reset', '--hard', 'HEAD'])
1371 self._gitcommand(['reset', '--hard', 'HEAD'])
1359 return
1372 return
1360 branch2rev, rev2branch = self._gitbranchmap()
1373 branch2rev, rev2branch = self._gitbranchmap()
1361
1374
1362 def checkout(args):
1375 def checkout(args):
1363 cmd = ['checkout']
1376 cmd = ['checkout']
1364 if overwrite:
1377 if overwrite:
1365 # first reset the index to unmark new files for commit, because
1378 # first reset the index to unmark new files for commit, because
1366 # the -f option will otherwise throw away files added for
1379 # the -f option will otherwise throw away files added for
1367 # commit, not just unmark them.
1380 # commit, not just unmark them.
1368 self._gitcommand(['reset', 'HEAD'])
1381 self._gitcommand(['reset', 'HEAD'])
1369 cmd.append('-f')
1382 cmd.append('-f')
1370 self._gitcommand(cmd + args)
1383 self._gitcommand(cmd + args)
1371 _sanitize(self._ui, self._abspath, '.git')
1384 _sanitize(self._ui, self._abspath, '.git')
1372
1385
1373 def rawcheckout():
1386 def rawcheckout():
1374 # no branch to checkout, check it out with no branch
1387 # no branch to checkout, check it out with no branch
1375 self._ui.warn(_('checking out detached HEAD in subrepo %s\n') %
1388 self._ui.warn(_('checking out detached HEAD in subrepo %s\n') %
1376 self._relpath)
1389 self._relpath)
1377 self._ui.warn(_('check out a git branch if you intend '
1390 self._ui.warn(_('check out a git branch if you intend '
1378 'to make changes\n'))
1391 'to make changes\n'))
1379 checkout(['-q', revision])
1392 checkout(['-q', revision])
1380
1393
1381 if revision not in rev2branch:
1394 if revision not in rev2branch:
1382 rawcheckout()
1395 rawcheckout()
1383 return
1396 return
1384 branches = rev2branch[revision]
1397 branches = rev2branch[revision]
1385 firstlocalbranch = None
1398 firstlocalbranch = None
1386 for b in branches:
1399 for b in branches:
1387 if b == 'refs/heads/master':
1400 if b == 'refs/heads/master':
1388 # master trumps all other branches
1401 # master trumps all other branches
1389 checkout(['refs/heads/master'])
1402 checkout(['refs/heads/master'])
1390 return
1403 return
1391 if not firstlocalbranch and not b.startswith('refs/remotes/'):
1404 if not firstlocalbranch and not b.startswith('refs/remotes/'):
1392 firstlocalbranch = b
1405 firstlocalbranch = b
1393 if firstlocalbranch:
1406 if firstlocalbranch:
1394 checkout([firstlocalbranch])
1407 checkout([firstlocalbranch])
1395 return
1408 return
1396
1409
1397 tracking = self._gittracking(branch2rev.keys())
1410 tracking = self._gittracking(branch2rev.keys())
1398 # choose a remote branch already tracked if possible
1411 # choose a remote branch already tracked if possible
1399 remote = branches[0]
1412 remote = branches[0]
1400 if remote not in tracking:
1413 if remote not in tracking:
1401 for b in branches:
1414 for b in branches:
1402 if b in tracking:
1415 if b in tracking:
1403 remote = b
1416 remote = b
1404 break
1417 break
1405
1418
1406 if remote not in tracking:
1419 if remote not in tracking:
1407 # create a new local tracking branch
1420 # create a new local tracking branch
1408 local = remote.split('/', 3)[3]
1421 local = remote.split('/', 3)[3]
1409 checkout(['-b', local, remote])
1422 checkout(['-b', local, remote])
1410 elif self._gitisancestor(branch2rev[tracking[remote]], remote):
1423 elif self._gitisancestor(branch2rev[tracking[remote]], remote):
1411 # When updating to a tracked remote branch,
1424 # When updating to a tracked remote branch,
1412 # if the local tracking branch is downstream of it,
1425 # if the local tracking branch is downstream of it,
1413 # a normal `git pull` would have performed a "fast-forward merge"
1426 # a normal `git pull` would have performed a "fast-forward merge"
1414 # which is equivalent to updating the local branch to the remote.
1427 # which is equivalent to updating the local branch to the remote.
1415 # Since we are only looking at branching at update, we need to
1428 # Since we are only looking at branching at update, we need to
1416 # detect this situation and perform this action lazily.
1429 # detect this situation and perform this action lazily.
1417 if tracking[remote] != self._gitcurrentbranch():
1430 if tracking[remote] != self._gitcurrentbranch():
1418 checkout([tracking[remote]])
1431 checkout([tracking[remote]])
1419 self._gitcommand(['merge', '--ff', remote])
1432 self._gitcommand(['merge', '--ff', remote])
1420 _sanitize(self._ui, self._abspath, '.git')
1433 _sanitize(self._ui, self._abspath, '.git')
1421 else:
1434 else:
1422 # a real merge would be required, just checkout the revision
1435 # a real merge would be required, just checkout the revision
1423 rawcheckout()
1436 rawcheckout()
1424
1437
1425 @annotatesubrepoerror
1438 @annotatesubrepoerror
1426 def commit(self, text, user, date):
1439 def commit(self, text, user, date):
1427 if self._gitmissing():
1440 if self._gitmissing():
1428 raise util.Abort(_("subrepo %s is missing") % self._relpath)
1441 raise util.Abort(_("subrepo %s is missing") % self._relpath)
1429 cmd = ['commit', '-a', '-m', text]
1442 cmd = ['commit', '-a', '-m', text]
1430 env = os.environ.copy()
1443 env = os.environ.copy()
1431 if user:
1444 if user:
1432 cmd += ['--author', user]
1445 cmd += ['--author', user]
1433 if date:
1446 if date:
1434 # git's date parser silently ignores when seconds < 1e9
1447 # git's date parser silently ignores when seconds < 1e9
1435 # convert to ISO8601
1448 # convert to ISO8601
1436 env['GIT_AUTHOR_DATE'] = util.datestr(date,
1449 env['GIT_AUTHOR_DATE'] = util.datestr(date,
1437 '%Y-%m-%dT%H:%M:%S %1%2')
1450 '%Y-%m-%dT%H:%M:%S %1%2')
1438 self._gitcommand(cmd, env=env)
1451 self._gitcommand(cmd, env=env)
1439 # make sure commit works otherwise HEAD might not exist under certain
1452 # make sure commit works otherwise HEAD might not exist under certain
1440 # circumstances
1453 # circumstances
1441 return self._gitstate()
1454 return self._gitstate()
1442
1455
1443 @annotatesubrepoerror
1456 @annotatesubrepoerror
1444 def merge(self, state):
1457 def merge(self, state):
1445 source, revision, kind = state
1458 source, revision, kind = state
1446 self._fetch(source, revision)
1459 self._fetch(source, revision)
1447 base = self._gitcommand(['merge-base', revision, self._state[1]])
1460 base = self._gitcommand(['merge-base', revision, self._state[1]])
1448 self._gitupdatestat()
1461 self._gitupdatestat()
1449 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
1462 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
1450
1463
1451 def mergefunc():
1464 def mergefunc():
1452 if base == revision:
1465 if base == revision:
1453 self.get(state) # fast forward merge
1466 self.get(state) # fast forward merge
1454 elif base != self._state[1]:
1467 elif base != self._state[1]:
1455 self._gitcommand(['merge', '--no-commit', revision])
1468 self._gitcommand(['merge', '--no-commit', revision])
1456 _sanitize(self._ui, self._abspath, '.git')
1469 _sanitize(self._ui, self._abspath, '.git')
1457
1470
1458 if self.dirty():
1471 if self.dirty():
1459 if self._gitstate() != revision:
1472 if self._gitstate() != revision:
1460 dirty = self._gitstate() == self._state[1] or code != 0
1473 dirty = self._gitstate() == self._state[1] or code != 0
1461 if _updateprompt(self._ui, self, dirty,
1474 if _updateprompt(self._ui, self, dirty,
1462 self._state[1][:7], revision[:7]):
1475 self._state[1][:7], revision[:7]):
1463 mergefunc()
1476 mergefunc()
1464 else:
1477 else:
1465 mergefunc()
1478 mergefunc()
1466
1479
1467 @annotatesubrepoerror
1480 @annotatesubrepoerror
1468 def push(self, opts):
1481 def push(self, opts):
1469 force = opts.get('force')
1482 force = opts.get('force')
1470
1483
1471 if not self._state[1]:
1484 if not self._state[1]:
1472 return True
1485 return True
1473 if self._gitmissing():
1486 if self._gitmissing():
1474 raise util.Abort(_("subrepo %s is missing") % self._relpath)
1487 raise util.Abort(_("subrepo %s is missing") % self._relpath)
1475 # if a branch in origin contains the revision, nothing to do
1488 # if a branch in origin contains the revision, nothing to do
1476 branch2rev, rev2branch = self._gitbranchmap()
1489 branch2rev, rev2branch = self._gitbranchmap()
1477 if self._state[1] in rev2branch:
1490 if self._state[1] in rev2branch:
1478 for b in rev2branch[self._state[1]]:
1491 for b in rev2branch[self._state[1]]:
1479 if b.startswith('refs/remotes/origin/'):
1492 if b.startswith('refs/remotes/origin/'):
1480 return True
1493 return True
1481 for b, revision in branch2rev.iteritems():
1494 for b, revision in branch2rev.iteritems():
1482 if b.startswith('refs/remotes/origin/'):
1495 if b.startswith('refs/remotes/origin/'):
1483 if self._gitisancestor(self._state[1], revision):
1496 if self._gitisancestor(self._state[1], revision):
1484 return True
1497 return True
1485 # otherwise, try to push the currently checked out branch
1498 # otherwise, try to push the currently checked out branch
1486 cmd = ['push']
1499 cmd = ['push']
1487 if force:
1500 if force:
1488 cmd.append('--force')
1501 cmd.append('--force')
1489
1502
1490 current = self._gitcurrentbranch()
1503 current = self._gitcurrentbranch()
1491 if current:
1504 if current:
1492 # determine if the current branch is even useful
1505 # determine if the current branch is even useful
1493 if not self._gitisancestor(self._state[1], current):
1506 if not self._gitisancestor(self._state[1], current):
1494 self._ui.warn(_('unrelated git branch checked out '
1507 self._ui.warn(_('unrelated git branch checked out '
1495 'in subrepo %s\n') % self._relpath)
1508 'in subrepo %s\n') % self._relpath)
1496 return False
1509 return False
1497 self._ui.status(_('pushing branch %s of subrepo %s\n') %
1510 self._ui.status(_('pushing branch %s of subrepo %s\n') %
1498 (current.split('/', 2)[2], self._relpath))
1511 (current.split('/', 2)[2], self._relpath))
1499 ret = self._gitdir(cmd + ['origin', current])
1512 ret = self._gitdir(cmd + ['origin', current])
1500 return ret[1] == 0
1513 return ret[1] == 0
1501 else:
1514 else:
1502 self._ui.warn(_('no branch checked out in subrepo %s\n'
1515 self._ui.warn(_('no branch checked out in subrepo %s\n'
1503 'cannot push revision %s\n') %
1516 'cannot push revision %s\n') %
1504 (self._relpath, self._state[1]))
1517 (self._relpath, self._state[1]))
1505 return False
1518 return False
1506
1519
1507 @annotatesubrepoerror
1520 @annotatesubrepoerror
1508 def remove(self):
1521 def remove(self):
1509 if self._gitmissing():
1522 if self._gitmissing():
1510 return
1523 return
1511 if self.dirty():
1524 if self.dirty():
1512 self._ui.warn(_('not removing repo %s because '
1525 self._ui.warn(_('not removing repo %s because '
1513 'it has changes.\n') % self._relpath)
1526 'it has changes.\n') % self._relpath)
1514 return
1527 return
1515 # we can't fully delete the repository as it may contain
1528 # we can't fully delete the repository as it may contain
1516 # local-only history
1529 # local-only history
1517 self._ui.note(_('removing subrepo %s\n') % self._relpath)
1530 self._ui.note(_('removing subrepo %s\n') % self._relpath)
1518 self._gitcommand(['config', 'core.bare', 'true'])
1531 self._gitcommand(['config', 'core.bare', 'true'])
1519 for f in os.listdir(self._abspath):
1532 for f in os.listdir(self._abspath):
1520 if f == '.git':
1533 if f == '.git':
1521 continue
1534 continue
1522 path = os.path.join(self._abspath, f)
1535 path = os.path.join(self._abspath, f)
1523 if os.path.isdir(path) and not os.path.islink(path):
1536 if os.path.isdir(path) and not os.path.islink(path):
1524 shutil.rmtree(path)
1537 shutil.rmtree(path)
1525 else:
1538 else:
1526 os.remove(path)
1539 os.remove(path)
1527
1540
1528 def archive(self, ui, archiver, prefix, match=None):
1541 def archive(self, ui, archiver, prefix, match=None):
1529 total = 0
1542 total = 0
1530 source, revision = self._state
1543 source, revision = self._state
1531 if not revision:
1544 if not revision:
1532 return total
1545 return total
1533 self._fetch(source, revision)
1546 self._fetch(source, revision)
1534
1547
1535 # Parse git's native archive command.
1548 # Parse git's native archive command.
1536 # This should be much faster than manually traversing the trees
1549 # This should be much faster than manually traversing the trees
1537 # and objects with many subprocess calls.
1550 # and objects with many subprocess calls.
1538 tarstream = self._gitcommand(['archive', revision], stream=True)
1551 tarstream = self._gitcommand(['archive', revision], stream=True)
1539 tar = tarfile.open(fileobj=tarstream, mode='r|')
1552 tar = tarfile.open(fileobj=tarstream, mode='r|')
1540 relpath = subrelpath(self)
1553 relpath = subrelpath(self)
1541 ui.progress(_('archiving (%s)') % relpath, 0, unit=_('files'))
1554 ui.progress(_('archiving (%s)') % relpath, 0, unit=_('files'))
1542 for i, info in enumerate(tar):
1555 for i, info in enumerate(tar):
1543 if info.isdir():
1556 if info.isdir():
1544 continue
1557 continue
1545 if match and not match(info.name):
1558 if match and not match(info.name):
1546 continue
1559 continue
1547 if info.issym():
1560 if info.issym():
1548 data = info.linkname
1561 data = info.linkname
1549 else:
1562 else:
1550 data = tar.extractfile(info).read()
1563 data = tar.extractfile(info).read()
1551 archiver.addfile(os.path.join(prefix, self._path, info.name),
1564 archiver.addfile(os.path.join(prefix, self._path, info.name),
1552 info.mode, info.issym(), data)
1565 info.mode, info.issym(), data)
1553 total += 1
1566 total += 1
1554 ui.progress(_('archiving (%s)') % relpath, i + 1,
1567 ui.progress(_('archiving (%s)') % relpath, i + 1,
1555 unit=_('files'))
1568 unit=_('files'))
1556 ui.progress(_('archiving (%s)') % relpath, None)
1569 ui.progress(_('archiving (%s)') % relpath, None)
1557 return total
1570 return total
1558
1571
1559
1572
1560 @annotatesubrepoerror
1573 @annotatesubrepoerror
1561 def status(self, rev2, **opts):
1574 def status(self, rev2, **opts):
1562 rev1 = self._state[1]
1575 rev1 = self._state[1]
1563 if self._gitmissing() or not rev1:
1576 if self._gitmissing() or not rev1:
1564 # if the repo is missing, return no results
1577 # if the repo is missing, return no results
1565 return [], [], [], [], [], [], []
1578 return [], [], [], [], [], [], []
1566 modified, added, removed = [], [], []
1579 modified, added, removed = [], [], []
1567 self._gitupdatestat()
1580 self._gitupdatestat()
1568 if rev2:
1581 if rev2:
1569 command = ['diff-tree', rev1, rev2]
1582 command = ['diff-tree', rev1, rev2]
1570 else:
1583 else:
1571 command = ['diff-index', rev1]
1584 command = ['diff-index', rev1]
1572 out = self._gitcommand(command)
1585 out = self._gitcommand(command)
1573 for line in out.split('\n'):
1586 for line in out.split('\n'):
1574 tab = line.find('\t')
1587 tab = line.find('\t')
1575 if tab == -1:
1588 if tab == -1:
1576 continue
1589 continue
1577 status, f = line[tab - 1], line[tab + 1:]
1590 status, f = line[tab - 1], line[tab + 1:]
1578 if status == 'M':
1591 if status == 'M':
1579 modified.append(f)
1592 modified.append(f)
1580 elif status == 'A':
1593 elif status == 'A':
1581 added.append(f)
1594 added.append(f)
1582 elif status == 'D':
1595 elif status == 'D':
1583 removed.append(f)
1596 removed.append(f)
1584
1597
1585 deleted, unknown, ignored, clean = [], [], [], []
1598 deleted, unknown, ignored, clean = [], [], [], []
1586 return scmutil.status(modified, added, removed, deleted,
1599 return scmutil.status(modified, added, removed, deleted,
1587 unknown, ignored, clean)
1600 unknown, ignored, clean)
1588
1601
1589 def shortid(self, revid):
1602 def shortid(self, revid):
1590 return revid[:7]
1603 return revid[:7]
1591
1604
1592 types = {
1605 types = {
1593 'hg': hgsubrepo,
1606 'hg': hgsubrepo,
1594 'svn': svnsubrepo,
1607 'svn': svnsubrepo,
1595 'git': gitsubrepo,
1608 'git': gitsubrepo,
1596 }
1609 }
@@ -1,336 +1,336 b''
1 Show all commands except debug commands
1 Show all commands except debug commands
2 $ hg debugcomplete
2 $ hg debugcomplete
3 add
3 add
4 addremove
4 addremove
5 annotate
5 annotate
6 archive
6 archive
7 backout
7 backout
8 bisect
8 bisect
9 bookmarks
9 bookmarks
10 branch
10 branch
11 branches
11 branches
12 bundle
12 bundle
13 cat
13 cat
14 clone
14 clone
15 commit
15 commit
16 config
16 config
17 copy
17 copy
18 diff
18 diff
19 export
19 export
20 files
20 files
21 forget
21 forget
22 graft
22 graft
23 grep
23 grep
24 heads
24 heads
25 help
25 help
26 identify
26 identify
27 import
27 import
28 incoming
28 incoming
29 init
29 init
30 locate
30 locate
31 log
31 log
32 manifest
32 manifest
33 merge
33 merge
34 outgoing
34 outgoing
35 parents
35 parents
36 paths
36 paths
37 phase
37 phase
38 pull
38 pull
39 push
39 push
40 recover
40 recover
41 remove
41 remove
42 rename
42 rename
43 resolve
43 resolve
44 revert
44 revert
45 rollback
45 rollback
46 root
46 root
47 serve
47 serve
48 status
48 status
49 summary
49 summary
50 tag
50 tag
51 tags
51 tags
52 tip
52 tip
53 unbundle
53 unbundle
54 update
54 update
55 verify
55 verify
56 version
56 version
57
57
58 Show all commands that start with "a"
58 Show all commands that start with "a"
59 $ hg debugcomplete a
59 $ hg debugcomplete a
60 add
60 add
61 addremove
61 addremove
62 annotate
62 annotate
63 archive
63 archive
64
64
65 Do not show debug commands if there are other candidates
65 Do not show debug commands if there are other candidates
66 $ hg debugcomplete d
66 $ hg debugcomplete d
67 diff
67 diff
68
68
69 Show debug commands if there are no other candidates
69 Show debug commands if there are no other candidates
70 $ hg debugcomplete debug
70 $ hg debugcomplete debug
71 debugancestor
71 debugancestor
72 debugbuilddag
72 debugbuilddag
73 debugbundle
73 debugbundle
74 debugcheckstate
74 debugcheckstate
75 debugcommands
75 debugcommands
76 debugcomplete
76 debugcomplete
77 debugconfig
77 debugconfig
78 debugdag
78 debugdag
79 debugdata
79 debugdata
80 debugdate
80 debugdate
81 debugdirstate
81 debugdirstate
82 debugdiscovery
82 debugdiscovery
83 debugfileset
83 debugfileset
84 debugfsinfo
84 debugfsinfo
85 debuggetbundle
85 debuggetbundle
86 debugignore
86 debugignore
87 debugindex
87 debugindex
88 debugindexdot
88 debugindexdot
89 debuginstall
89 debuginstall
90 debugknown
90 debugknown
91 debuglabelcomplete
91 debuglabelcomplete
92 debuglocks
92 debuglocks
93 debugobsolete
93 debugobsolete
94 debugpathcomplete
94 debugpathcomplete
95 debugpushkey
95 debugpushkey
96 debugpvec
96 debugpvec
97 debugrebuilddirstate
97 debugrebuilddirstate
98 debugrename
98 debugrename
99 debugrevlog
99 debugrevlog
100 debugrevspec
100 debugrevspec
101 debugsetparents
101 debugsetparents
102 debugsub
102 debugsub
103 debugsuccessorssets
103 debugsuccessorssets
104 debugwalk
104 debugwalk
105 debugwireargs
105 debugwireargs
106
106
107 Do not show the alias of a debug command if there are other candidates
107 Do not show the alias of a debug command if there are other candidates
108 (this should hide rawcommit)
108 (this should hide rawcommit)
109 $ hg debugcomplete r
109 $ hg debugcomplete r
110 recover
110 recover
111 remove
111 remove
112 rename
112 rename
113 resolve
113 resolve
114 revert
114 revert
115 rollback
115 rollback
116 root
116 root
117 Show the alias of a debug command if there are no other candidates
117 Show the alias of a debug command if there are no other candidates
118 $ hg debugcomplete rawc
118 $ hg debugcomplete rawc
119
119
120
120
121 Show the global options
121 Show the global options
122 $ hg debugcomplete --options | sort
122 $ hg debugcomplete --options | sort
123 --config
123 --config
124 --cwd
124 --cwd
125 --debug
125 --debug
126 --debugger
126 --debugger
127 --encoding
127 --encoding
128 --encodingmode
128 --encodingmode
129 --help
129 --help
130 --hidden
130 --hidden
131 --noninteractive
131 --noninteractive
132 --profile
132 --profile
133 --quiet
133 --quiet
134 --repository
134 --repository
135 --time
135 --time
136 --traceback
136 --traceback
137 --verbose
137 --verbose
138 --version
138 --version
139 -R
139 -R
140 -h
140 -h
141 -q
141 -q
142 -v
142 -v
143 -y
143 -y
144
144
145 Show the options for the "serve" command
145 Show the options for the "serve" command
146 $ hg debugcomplete --options serve | sort
146 $ hg debugcomplete --options serve | sort
147 --accesslog
147 --accesslog
148 --address
148 --address
149 --certificate
149 --certificate
150 --cmdserver
150 --cmdserver
151 --config
151 --config
152 --cwd
152 --cwd
153 --daemon
153 --daemon
154 --daemon-pipefds
154 --daemon-pipefds
155 --debug
155 --debug
156 --debugger
156 --debugger
157 --encoding
157 --encoding
158 --encodingmode
158 --encodingmode
159 --errorlog
159 --errorlog
160 --help
160 --help
161 --hidden
161 --hidden
162 --ipv6
162 --ipv6
163 --name
163 --name
164 --noninteractive
164 --noninteractive
165 --pid-file
165 --pid-file
166 --port
166 --port
167 --prefix
167 --prefix
168 --profile
168 --profile
169 --quiet
169 --quiet
170 --repository
170 --repository
171 --stdio
171 --stdio
172 --style
172 --style
173 --templates
173 --templates
174 --time
174 --time
175 --traceback
175 --traceback
176 --verbose
176 --verbose
177 --version
177 --version
178 --web-conf
178 --web-conf
179 -6
179 -6
180 -A
180 -A
181 -E
181 -E
182 -R
182 -R
183 -a
183 -a
184 -d
184 -d
185 -h
185 -h
186 -n
186 -n
187 -p
187 -p
188 -q
188 -q
189 -t
189 -t
190 -v
190 -v
191 -y
191 -y
192
192
193 Show an error if we use --options with an ambiguous abbreviation
193 Show an error if we use --options with an ambiguous abbreviation
194 $ hg debugcomplete --options s
194 $ hg debugcomplete --options s
195 hg: command 's' is ambiguous:
195 hg: command 's' is ambiguous:
196 serve showconfig status summary
196 serve showconfig status summary
197 [255]
197 [255]
198
198
199 Show all commands + options
199 Show all commands + options
200 $ hg debugcommands
200 $ hg debugcommands
201 add: include, exclude, subrepos, dry-run
201 add: include, exclude, subrepos, dry-run
202 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, include, exclude, template
202 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, include, exclude, template
203 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
203 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
204 commit: addremove, close-branch, amend, secret, edit, include, exclude, message, logfile, date, user, subrepos
204 commit: addremove, close-branch, amend, secret, edit, include, exclude, message, logfile, date, user, subrepos
205 diff: rev, change, text, git, nodates, noprefix, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
205 diff: rev, change, text, git, nodates, noprefix, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
206 export: output, switch-parent, rev, text, git, nodates
206 export: output, switch-parent, rev, text, git, nodates
207 forget: include, exclude
207 forget: include, exclude
208 init: ssh, remotecmd, insecure
208 init: ssh, remotecmd, insecure
209 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
209 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
210 merge: force, rev, preview, tool
210 merge: force, rev, preview, tool
211 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
211 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
212 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
212 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
213 remove: after, force, include, exclude
213 remove: after, force, subrepos, include, exclude
214 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
214 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
215 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos, template
215 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos, template
216 summary: remote
216 summary: remote
217 update: clean, check, date, rev, tool
217 update: clean, check, date, rev, tool
218 addremove: similarity, include, exclude, dry-run
218 addremove: similarity, include, exclude, dry-run
219 archive: no-decode, prefix, rev, type, subrepos, include, exclude
219 archive: no-decode, prefix, rev, type, subrepos, include, exclude
220 backout: merge, parent, rev, edit, tool, include, exclude, message, logfile, date, user
220 backout: merge, parent, rev, edit, tool, include, exclude, message, logfile, date, user
221 bisect: reset, good, bad, skip, extend, command, noupdate
221 bisect: reset, good, bad, skip, extend, command, noupdate
222 bookmarks: force, rev, delete, rename, inactive, template
222 bookmarks: force, rev, delete, rename, inactive, template
223 branch: force, clean
223 branch: force, clean
224 branches: active, closed, template
224 branches: active, closed, template
225 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
225 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
226 cat: output, rev, decode, include, exclude
226 cat: output, rev, decode, include, exclude
227 config: untrusted, edit, local, global
227 config: untrusted, edit, local, global
228 copy: after, force, include, exclude, dry-run
228 copy: after, force, include, exclude, dry-run
229 debugancestor:
229 debugancestor:
230 debugbuilddag: mergeable-file, overwritten-file, new-file
230 debugbuilddag: mergeable-file, overwritten-file, new-file
231 debugbundle: all
231 debugbundle: all
232 debugcheckstate:
232 debugcheckstate:
233 debugcommands:
233 debugcommands:
234 debugcomplete: options
234 debugcomplete: options
235 debugdag: tags, branches, dots, spaces
235 debugdag: tags, branches, dots, spaces
236 debugdata: changelog, manifest
236 debugdata: changelog, manifest
237 debugdate: extended
237 debugdate: extended
238 debugdirstate: nodates, datesort
238 debugdirstate: nodates, datesort
239 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
239 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
240 debugfileset: rev
240 debugfileset: rev
241 debugfsinfo:
241 debugfsinfo:
242 debuggetbundle: head, common, type
242 debuggetbundle: head, common, type
243 debugignore:
243 debugignore:
244 debugindex: changelog, manifest, format
244 debugindex: changelog, manifest, format
245 debugindexdot:
245 debugindexdot:
246 debuginstall:
246 debuginstall:
247 debugknown:
247 debugknown:
248 debuglabelcomplete:
248 debuglabelcomplete:
249 debuglocks: force-lock, force-wlock
249 debuglocks: force-lock, force-wlock
250 debugobsolete: flags, record-parents, rev, date, user
250 debugobsolete: flags, record-parents, rev, date, user
251 debugpathcomplete: full, normal, added, removed
251 debugpathcomplete: full, normal, added, removed
252 debugpushkey:
252 debugpushkey:
253 debugpvec:
253 debugpvec:
254 debugrebuilddirstate: rev
254 debugrebuilddirstate: rev
255 debugrename: rev
255 debugrename: rev
256 debugrevlog: changelog, manifest, dump
256 debugrevlog: changelog, manifest, dump
257 debugrevspec: optimize
257 debugrevspec: optimize
258 debugsetparents:
258 debugsetparents:
259 debugsub: rev
259 debugsub: rev
260 debugsuccessorssets:
260 debugsuccessorssets:
261 debugwalk: include, exclude
261 debugwalk: include, exclude
262 debugwireargs: three, four, five, ssh, remotecmd, insecure
262 debugwireargs: three, four, five, ssh, remotecmd, insecure
263 files: rev, print0, include, exclude, template
263 files: rev, print0, include, exclude, template
264 graft: rev, continue, edit, log, force, currentdate, currentuser, date, user, tool, dry-run
264 graft: rev, continue, edit, log, force, currentdate, currentuser, date, user, tool, dry-run
265 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
265 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
266 heads: rev, topo, active, closed, style, template
266 heads: rev, topo, active, closed, style, template
267 help: extension, command, keyword
267 help: extension, command, keyword
268 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure
268 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure
269 import: strip, base, edit, force, no-commit, bypass, partial, exact, import-branch, message, logfile, date, user, similarity
269 import: strip, base, edit, force, no-commit, bypass, partial, exact, import-branch, message, logfile, date, user, similarity
270 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
270 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
271 locate: rev, print0, fullpath, include, exclude
271 locate: rev, print0, fullpath, include, exclude
272 manifest: rev, all, template
272 manifest: rev, all, template
273 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
273 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
274 parents: rev, style, template
274 parents: rev, style, template
275 paths:
275 paths:
276 phase: public, draft, secret, force, rev
276 phase: public, draft, secret, force, rev
277 recover:
277 recover:
278 rename: after, force, include, exclude, dry-run
278 rename: after, force, include, exclude, dry-run
279 resolve: all, list, mark, unmark, no-status, tool, include, exclude
279 resolve: all, list, mark, unmark, no-status, tool, include, exclude
280 revert: all, date, rev, no-backup, include, exclude, dry-run
280 revert: all, date, rev, no-backup, include, exclude, dry-run
281 rollback: dry-run, force
281 rollback: dry-run, force
282 root:
282 root:
283 tag: force, local, rev, remove, edit, message, date, user
283 tag: force, local, rev, remove, edit, message, date, user
284 tags: template
284 tags: template
285 tip: patch, git, style, template
285 tip: patch, git, style, template
286 unbundle: update
286 unbundle: update
287 verify:
287 verify:
288 version:
288 version:
289
289
290 $ hg init a
290 $ hg init a
291 $ cd a
291 $ cd a
292 $ echo fee > fee
292 $ echo fee > fee
293 $ hg ci -q -Amfee
293 $ hg ci -q -Amfee
294 $ hg tag fee
294 $ hg tag fee
295 $ mkdir fie
295 $ mkdir fie
296 $ echo dead > fie/dead
296 $ echo dead > fie/dead
297 $ echo live > fie/live
297 $ echo live > fie/live
298 $ hg bookmark fo
298 $ hg bookmark fo
299 $ hg branch -q fie
299 $ hg branch -q fie
300 $ hg ci -q -Amfie
300 $ hg ci -q -Amfie
301 $ echo fo > fo
301 $ echo fo > fo
302 $ hg branch -qf default
302 $ hg branch -qf default
303 $ hg ci -q -Amfo
303 $ hg ci -q -Amfo
304 $ echo Fum > Fum
304 $ echo Fum > Fum
305 $ hg ci -q -AmFum
305 $ hg ci -q -AmFum
306 $ hg bookmark Fum
306 $ hg bookmark Fum
307
307
308 Test debugpathcomplete
308 Test debugpathcomplete
309
309
310 $ hg debugpathcomplete f
310 $ hg debugpathcomplete f
311 fee
311 fee
312 fie
312 fie
313 fo
313 fo
314 $ hg debugpathcomplete -f f
314 $ hg debugpathcomplete -f f
315 fee
315 fee
316 fie/dead
316 fie/dead
317 fie/live
317 fie/live
318 fo
318 fo
319
319
320 $ hg rm Fum
320 $ hg rm Fum
321 $ hg debugpathcomplete -r F
321 $ hg debugpathcomplete -r F
322 Fum
322 Fum
323
323
324 Test debuglabelcomplete
324 Test debuglabelcomplete
325
325
326 $ hg debuglabelcomplete
326 $ hg debuglabelcomplete
327 Fum
327 Fum
328 default
328 default
329 fee
329 fee
330 fie
330 fie
331 fo
331 fo
332 tip
332 tip
333 $ hg debuglabelcomplete f
333 $ hg debuglabelcomplete f
334 fee
334 fee
335 fie
335 fie
336 fo
336 fo
@@ -1,2116 +1,2119 b''
1 Short help:
1 Short help:
2
2
3 $ hg
3 $ hg
4 Mercurial Distributed SCM
4 Mercurial Distributed SCM
5
5
6 basic commands:
6 basic commands:
7
7
8 add add the specified files on the next commit
8 add add the specified files on the next commit
9 annotate show changeset information by line for each file
9 annotate show changeset information by line for each file
10 clone make a copy of an existing repository
10 clone make a copy of an existing repository
11 commit commit the specified files or all outstanding changes
11 commit commit the specified files or all outstanding changes
12 diff diff repository (or selected files)
12 diff diff repository (or selected files)
13 export dump the header and diffs for one or more changesets
13 export dump the header and diffs for one or more changesets
14 forget forget the specified files on the next commit
14 forget forget the specified files on the next commit
15 init create a new repository in the given directory
15 init create a new repository in the given directory
16 log show revision history of entire repository or files
16 log show revision history of entire repository or files
17 merge merge working directory with another revision
17 merge merge working directory with another revision
18 pull pull changes from the specified source
18 pull pull changes from the specified source
19 push push changes to the specified destination
19 push push changes to the specified destination
20 remove remove the specified files on the next commit
20 remove remove the specified files on the next commit
21 serve start stand-alone webserver
21 serve start stand-alone webserver
22 status show changed files in the working directory
22 status show changed files in the working directory
23 summary summarize working directory state
23 summary summarize working directory state
24 update update working directory (or switch revisions)
24 update update working directory (or switch revisions)
25
25
26 (use "hg help" for the full list of commands or "hg -v" for details)
26 (use "hg help" for the full list of commands or "hg -v" for details)
27
27
28 $ hg -q
28 $ hg -q
29 add add the specified files on the next commit
29 add add the specified files on the next commit
30 annotate show changeset information by line for each file
30 annotate show changeset information by line for each file
31 clone make a copy of an existing repository
31 clone make a copy of an existing repository
32 commit commit the specified files or all outstanding changes
32 commit commit the specified files or all outstanding changes
33 diff diff repository (or selected files)
33 diff diff repository (or selected files)
34 export dump the header and diffs for one or more changesets
34 export dump the header and diffs for one or more changesets
35 forget forget the specified files on the next commit
35 forget forget the specified files on the next commit
36 init create a new repository in the given directory
36 init create a new repository in the given directory
37 log show revision history of entire repository or files
37 log show revision history of entire repository or files
38 merge merge working directory with another revision
38 merge merge working directory with another revision
39 pull pull changes from the specified source
39 pull pull changes from the specified source
40 push push changes to the specified destination
40 push push changes to the specified destination
41 remove remove the specified files on the next commit
41 remove remove the specified files on the next commit
42 serve start stand-alone webserver
42 serve start stand-alone webserver
43 status show changed files in the working directory
43 status show changed files in the working directory
44 summary summarize working directory state
44 summary summarize working directory state
45 update update working directory (or switch revisions)
45 update update working directory (or switch revisions)
46
46
47 $ hg help
47 $ hg help
48 Mercurial Distributed SCM
48 Mercurial Distributed SCM
49
49
50 list of commands:
50 list of commands:
51
51
52 add add the specified files on the next commit
52 add add the specified files on the next commit
53 addremove add all new files, delete all missing files
53 addremove add all new files, delete all missing files
54 annotate show changeset information by line for each file
54 annotate show changeset information by line for each file
55 archive create an unversioned archive of a repository revision
55 archive create an unversioned archive of a repository revision
56 backout reverse effect of earlier changeset
56 backout reverse effect of earlier changeset
57 bisect subdivision search of changesets
57 bisect subdivision search of changesets
58 bookmarks create a new bookmark or list existing bookmarks
58 bookmarks create a new bookmark or list existing bookmarks
59 branch set or show the current branch name
59 branch set or show the current branch name
60 branches list repository named branches
60 branches list repository named branches
61 bundle create a changegroup file
61 bundle create a changegroup file
62 cat output the current or given revision of files
62 cat output the current or given revision of files
63 clone make a copy of an existing repository
63 clone make a copy of an existing repository
64 commit commit the specified files or all outstanding changes
64 commit commit the specified files or all outstanding changes
65 config show combined config settings from all hgrc files
65 config show combined config settings from all hgrc files
66 copy mark files as copied for the next commit
66 copy mark files as copied for the next commit
67 diff diff repository (or selected files)
67 diff diff repository (or selected files)
68 export dump the header and diffs for one or more changesets
68 export dump the header and diffs for one or more changesets
69 files list tracked files
69 files list tracked files
70 forget forget the specified files on the next commit
70 forget forget the specified files on the next commit
71 graft copy changes from other branches onto the current branch
71 graft copy changes from other branches onto the current branch
72 grep search for a pattern in specified files and revisions
72 grep search for a pattern in specified files and revisions
73 heads show branch heads
73 heads show branch heads
74 help show help for a given topic or a help overview
74 help show help for a given topic or a help overview
75 identify identify the working copy or specified revision
75 identify identify the working copy or specified revision
76 import import an ordered set of patches
76 import import an ordered set of patches
77 incoming show new changesets found in source
77 incoming show new changesets found in source
78 init create a new repository in the given directory
78 init create a new repository in the given directory
79 log show revision history of entire repository or files
79 log show revision history of entire repository or files
80 manifest output the current or given revision of the project manifest
80 manifest output the current or given revision of the project manifest
81 merge merge working directory with another revision
81 merge merge working directory with another revision
82 outgoing show changesets not found in the destination
82 outgoing show changesets not found in the destination
83 paths show aliases for remote repositories
83 paths show aliases for remote repositories
84 phase set or show the current phase name
84 phase set or show the current phase name
85 pull pull changes from the specified source
85 pull pull changes from the specified source
86 push push changes to the specified destination
86 push push changes to the specified destination
87 recover roll back an interrupted transaction
87 recover roll back an interrupted transaction
88 remove remove the specified files on the next commit
88 remove remove the specified files on the next commit
89 rename rename files; equivalent of copy + remove
89 rename rename files; equivalent of copy + remove
90 resolve redo merges or set/view the merge status of files
90 resolve redo merges or set/view the merge status of files
91 revert restore files to their checkout state
91 revert restore files to their checkout state
92 root print the root (top) of the current working directory
92 root print the root (top) of the current working directory
93 serve start stand-alone webserver
93 serve start stand-alone webserver
94 status show changed files in the working directory
94 status show changed files in the working directory
95 summary summarize working directory state
95 summary summarize working directory state
96 tag add one or more tags for the current or given revision
96 tag add one or more tags for the current or given revision
97 tags list repository tags
97 tags list repository tags
98 unbundle apply one or more changegroup files
98 unbundle apply one or more changegroup files
99 update update working directory (or switch revisions)
99 update update working directory (or switch revisions)
100 verify verify the integrity of the repository
100 verify verify the integrity of the repository
101 version output version and copyright information
101 version output version and copyright information
102
102
103 additional help topics:
103 additional help topics:
104
104
105 config Configuration Files
105 config Configuration Files
106 dates Date Formats
106 dates Date Formats
107 diffs Diff Formats
107 diffs Diff Formats
108 environment Environment Variables
108 environment Environment Variables
109 extensions Using Additional Features
109 extensions Using Additional Features
110 filesets Specifying File Sets
110 filesets Specifying File Sets
111 glossary Glossary
111 glossary Glossary
112 hgignore Syntax for Mercurial Ignore Files
112 hgignore Syntax for Mercurial Ignore Files
113 hgweb Configuring hgweb
113 hgweb Configuring hgweb
114 merge-tools Merge Tools
114 merge-tools Merge Tools
115 multirevs Specifying Multiple Revisions
115 multirevs Specifying Multiple Revisions
116 patterns File Name Patterns
116 patterns File Name Patterns
117 phases Working with Phases
117 phases Working with Phases
118 revisions Specifying Single Revisions
118 revisions Specifying Single Revisions
119 revsets Specifying Revision Sets
119 revsets Specifying Revision Sets
120 subrepos Subrepositories
120 subrepos Subrepositories
121 templating Template Usage
121 templating Template Usage
122 urls URL Paths
122 urls URL Paths
123
123
124 (use "hg help -v" to show built-in aliases and global options)
124 (use "hg help -v" to show built-in aliases and global options)
125
125
126 $ hg -q help
126 $ hg -q help
127 add add the specified files on the next commit
127 add add the specified files on the next commit
128 addremove add all new files, delete all missing files
128 addremove add all new files, delete all missing files
129 annotate show changeset information by line for each file
129 annotate show changeset information by line for each file
130 archive create an unversioned archive of a repository revision
130 archive create an unversioned archive of a repository revision
131 backout reverse effect of earlier changeset
131 backout reverse effect of earlier changeset
132 bisect subdivision search of changesets
132 bisect subdivision search of changesets
133 bookmarks create a new bookmark or list existing bookmarks
133 bookmarks create a new bookmark or list existing bookmarks
134 branch set or show the current branch name
134 branch set or show the current branch name
135 branches list repository named branches
135 branches list repository named branches
136 bundle create a changegroup file
136 bundle create a changegroup file
137 cat output the current or given revision of files
137 cat output the current or given revision of files
138 clone make a copy of an existing repository
138 clone make a copy of an existing repository
139 commit commit the specified files or all outstanding changes
139 commit commit the specified files or all outstanding changes
140 config show combined config settings from all hgrc files
140 config show combined config settings from all hgrc files
141 copy mark files as copied for the next commit
141 copy mark files as copied for the next commit
142 diff diff repository (or selected files)
142 diff diff repository (or selected files)
143 export dump the header and diffs for one or more changesets
143 export dump the header and diffs for one or more changesets
144 files list tracked files
144 files list tracked files
145 forget forget the specified files on the next commit
145 forget forget the specified files on the next commit
146 graft copy changes from other branches onto the current branch
146 graft copy changes from other branches onto the current branch
147 grep search for a pattern in specified files and revisions
147 grep search for a pattern in specified files and revisions
148 heads show branch heads
148 heads show branch heads
149 help show help for a given topic or a help overview
149 help show help for a given topic or a help overview
150 identify identify the working copy or specified revision
150 identify identify the working copy or specified revision
151 import import an ordered set of patches
151 import import an ordered set of patches
152 incoming show new changesets found in source
152 incoming show new changesets found in source
153 init create a new repository in the given directory
153 init create a new repository in the given directory
154 log show revision history of entire repository or files
154 log show revision history of entire repository or files
155 manifest output the current or given revision of the project manifest
155 manifest output the current or given revision of the project manifest
156 merge merge working directory with another revision
156 merge merge working directory with another revision
157 outgoing show changesets not found in the destination
157 outgoing show changesets not found in the destination
158 paths show aliases for remote repositories
158 paths show aliases for remote repositories
159 phase set or show the current phase name
159 phase set or show the current phase name
160 pull pull changes from the specified source
160 pull pull changes from the specified source
161 push push changes to the specified destination
161 push push changes to the specified destination
162 recover roll back an interrupted transaction
162 recover roll back an interrupted transaction
163 remove remove the specified files on the next commit
163 remove remove the specified files on the next commit
164 rename rename files; equivalent of copy + remove
164 rename rename files; equivalent of copy + remove
165 resolve redo merges or set/view the merge status of files
165 resolve redo merges or set/view the merge status of files
166 revert restore files to their checkout state
166 revert restore files to their checkout state
167 root print the root (top) of the current working directory
167 root print the root (top) of the current working directory
168 serve start stand-alone webserver
168 serve start stand-alone webserver
169 status show changed files in the working directory
169 status show changed files in the working directory
170 summary summarize working directory state
170 summary summarize working directory state
171 tag add one or more tags for the current or given revision
171 tag add one or more tags for the current or given revision
172 tags list repository tags
172 tags list repository tags
173 unbundle apply one or more changegroup files
173 unbundle apply one or more changegroup files
174 update update working directory (or switch revisions)
174 update update working directory (or switch revisions)
175 verify verify the integrity of the repository
175 verify verify the integrity of the repository
176 version output version and copyright information
176 version output version and copyright information
177
177
178 additional help topics:
178 additional help topics:
179
179
180 config Configuration Files
180 config Configuration Files
181 dates Date Formats
181 dates Date Formats
182 diffs Diff Formats
182 diffs Diff Formats
183 environment Environment Variables
183 environment Environment Variables
184 extensions Using Additional Features
184 extensions Using Additional Features
185 filesets Specifying File Sets
185 filesets Specifying File Sets
186 glossary Glossary
186 glossary Glossary
187 hgignore Syntax for Mercurial Ignore Files
187 hgignore Syntax for Mercurial Ignore Files
188 hgweb Configuring hgweb
188 hgweb Configuring hgweb
189 merge-tools Merge Tools
189 merge-tools Merge Tools
190 multirevs Specifying Multiple Revisions
190 multirevs Specifying Multiple Revisions
191 patterns File Name Patterns
191 patterns File Name Patterns
192 phases Working with Phases
192 phases Working with Phases
193 revisions Specifying Single Revisions
193 revisions Specifying Single Revisions
194 revsets Specifying Revision Sets
194 revsets Specifying Revision Sets
195 subrepos Subrepositories
195 subrepos Subrepositories
196 templating Template Usage
196 templating Template Usage
197 urls URL Paths
197 urls URL Paths
198
198
199 Test extension help:
199 Test extension help:
200 $ hg help extensions --config extensions.rebase= --config extensions.children=
200 $ hg help extensions --config extensions.rebase= --config extensions.children=
201 Using Additional Features
201 Using Additional Features
202 """""""""""""""""""""""""
202 """""""""""""""""""""""""
203
203
204 Mercurial has the ability to add new features through the use of
204 Mercurial has the ability to add new features through the use of
205 extensions. Extensions may add new commands, add options to existing
205 extensions. Extensions may add new commands, add options to existing
206 commands, change the default behavior of commands, or implement hooks.
206 commands, change the default behavior of commands, or implement hooks.
207
207
208 To enable the "foo" extension, either shipped with Mercurial or in the
208 To enable the "foo" extension, either shipped with Mercurial or in the
209 Python search path, create an entry for it in your configuration file,
209 Python search path, create an entry for it in your configuration file,
210 like this:
210 like this:
211
211
212 [extensions]
212 [extensions]
213 foo =
213 foo =
214
214
215 You may also specify the full path to an extension:
215 You may also specify the full path to an extension:
216
216
217 [extensions]
217 [extensions]
218 myfeature = ~/.hgext/myfeature.py
218 myfeature = ~/.hgext/myfeature.py
219
219
220 See "hg help config" for more information on configuration files.
220 See "hg help config" for more information on configuration files.
221
221
222 Extensions are not loaded by default for a variety of reasons: they can
222 Extensions are not loaded by default for a variety of reasons: they can
223 increase startup overhead; they may be meant for advanced usage only; they
223 increase startup overhead; they may be meant for advanced usage only; they
224 may provide potentially dangerous abilities (such as letting you destroy
224 may provide potentially dangerous abilities (such as letting you destroy
225 or modify history); they might not be ready for prime time; or they may
225 or modify history); they might not be ready for prime time; or they may
226 alter some usual behaviors of stock Mercurial. It is thus up to the user
226 alter some usual behaviors of stock Mercurial. It is thus up to the user
227 to activate extensions as needed.
227 to activate extensions as needed.
228
228
229 To explicitly disable an extension enabled in a configuration file of
229 To explicitly disable an extension enabled in a configuration file of
230 broader scope, prepend its path with !:
230 broader scope, prepend its path with !:
231
231
232 [extensions]
232 [extensions]
233 # disabling extension bar residing in /path/to/extension/bar.py
233 # disabling extension bar residing in /path/to/extension/bar.py
234 bar = !/path/to/extension/bar.py
234 bar = !/path/to/extension/bar.py
235 # ditto, but no path was supplied for extension baz
235 # ditto, but no path was supplied for extension baz
236 baz = !
236 baz = !
237
237
238 enabled extensions:
238 enabled extensions:
239
239
240 children command to display child changesets (DEPRECATED)
240 children command to display child changesets (DEPRECATED)
241 rebase command to move sets of revisions to a different ancestor
241 rebase command to move sets of revisions to a different ancestor
242
242
243 disabled extensions:
243 disabled extensions:
244
244
245 acl hooks for controlling repository access
245 acl hooks for controlling repository access
246 blackbox log repository events to a blackbox for debugging
246 blackbox log repository events to a blackbox for debugging
247 bugzilla hooks for integrating with the Bugzilla bug tracker
247 bugzilla hooks for integrating with the Bugzilla bug tracker
248 churn command to display statistics about repository history
248 churn command to display statistics about repository history
249 color colorize output from some commands
249 color colorize output from some commands
250 convert import revisions from foreign VCS repositories into
250 convert import revisions from foreign VCS repositories into
251 Mercurial
251 Mercurial
252 eol automatically manage newlines in repository files
252 eol automatically manage newlines in repository files
253 extdiff command to allow external programs to compare revisions
253 extdiff command to allow external programs to compare revisions
254 factotum http authentication with factotum
254 factotum http authentication with factotum
255 gpg commands to sign and verify changesets
255 gpg commands to sign and verify changesets
256 hgcia hooks for integrating with the CIA.vc notification service
256 hgcia hooks for integrating with the CIA.vc notification service
257 hgk browse the repository in a graphical way
257 hgk browse the repository in a graphical way
258 highlight syntax highlighting for hgweb (requires Pygments)
258 highlight syntax highlighting for hgweb (requires Pygments)
259 histedit interactive history editing
259 histedit interactive history editing
260 keyword expand keywords in tracked files
260 keyword expand keywords in tracked files
261 largefiles track large binary files
261 largefiles track large binary files
262 mq manage a stack of patches
262 mq manage a stack of patches
263 notify hooks for sending email push notifications
263 notify hooks for sending email push notifications
264 pager browse command output with an external pager
264 pager browse command output with an external pager
265 patchbomb command to send changesets as (a series of) patch emails
265 patchbomb command to send changesets as (a series of) patch emails
266 progress show progress bars for some actions
266 progress show progress bars for some actions
267 purge command to delete untracked files from the working
267 purge command to delete untracked files from the working
268 directory
268 directory
269 record commands to interactively select changes for
269 record commands to interactively select changes for
270 commit/qrefresh
270 commit/qrefresh
271 relink recreates hardlinks between repository clones
271 relink recreates hardlinks between repository clones
272 schemes extend schemes with shortcuts to repository swarms
272 schemes extend schemes with shortcuts to repository swarms
273 share share a common history between several working directories
273 share share a common history between several working directories
274 shelve save and restore changes to the working directory
274 shelve save and restore changes to the working directory
275 strip strip changesets and their descendants from history
275 strip strip changesets and their descendants from history
276 transplant command to transplant changesets from another branch
276 transplant command to transplant changesets from another branch
277 win32mbcs allow the use of MBCS paths with problematic encodings
277 win32mbcs allow the use of MBCS paths with problematic encodings
278 zeroconf discover and advertise repositories on the local network
278 zeroconf discover and advertise repositories on the local network
279 Test short command list with verbose option
279 Test short command list with verbose option
280
280
281 $ hg -v help shortlist
281 $ hg -v help shortlist
282 Mercurial Distributed SCM
282 Mercurial Distributed SCM
283
283
284 basic commands:
284 basic commands:
285
285
286 add add the specified files on the next commit
286 add add the specified files on the next commit
287 annotate, blame
287 annotate, blame
288 show changeset information by line for each file
288 show changeset information by line for each file
289 clone make a copy of an existing repository
289 clone make a copy of an existing repository
290 commit, ci commit the specified files or all outstanding changes
290 commit, ci commit the specified files or all outstanding changes
291 diff diff repository (or selected files)
291 diff diff repository (or selected files)
292 export dump the header and diffs for one or more changesets
292 export dump the header and diffs for one or more changesets
293 forget forget the specified files on the next commit
293 forget forget the specified files on the next commit
294 init create a new repository in the given directory
294 init create a new repository in the given directory
295 log, history show revision history of entire repository or files
295 log, history show revision history of entire repository or files
296 merge merge working directory with another revision
296 merge merge working directory with another revision
297 pull pull changes from the specified source
297 pull pull changes from the specified source
298 push push changes to the specified destination
298 push push changes to the specified destination
299 remove, rm remove the specified files on the next commit
299 remove, rm remove the specified files on the next commit
300 serve start stand-alone webserver
300 serve start stand-alone webserver
301 status, st show changed files in the working directory
301 status, st show changed files in the working directory
302 summary, sum summarize working directory state
302 summary, sum summarize working directory state
303 update, up, checkout, co
303 update, up, checkout, co
304 update working directory (or switch revisions)
304 update working directory (or switch revisions)
305
305
306 global options ([+] can be repeated):
306 global options ([+] can be repeated):
307
307
308 -R --repository REPO repository root directory or name of overlay bundle
308 -R --repository REPO repository root directory or name of overlay bundle
309 file
309 file
310 --cwd DIR change working directory
310 --cwd DIR change working directory
311 -y --noninteractive do not prompt, automatically pick the first choice for
311 -y --noninteractive do not prompt, automatically pick the first choice for
312 all prompts
312 all prompts
313 -q --quiet suppress output
313 -q --quiet suppress output
314 -v --verbose enable additional output
314 -v --verbose enable additional output
315 --config CONFIG [+] set/override config option (use 'section.name=value')
315 --config CONFIG [+] set/override config option (use 'section.name=value')
316 --debug enable debugging output
316 --debug enable debugging output
317 --debugger start debugger
317 --debugger start debugger
318 --encoding ENCODE set the charset encoding (default: ascii)
318 --encoding ENCODE set the charset encoding (default: ascii)
319 --encodingmode MODE set the charset encoding mode (default: strict)
319 --encodingmode MODE set the charset encoding mode (default: strict)
320 --traceback always print a traceback on exception
320 --traceback always print a traceback on exception
321 --time time how long the command takes
321 --time time how long the command takes
322 --profile print command execution profile
322 --profile print command execution profile
323 --version output version information and exit
323 --version output version information and exit
324 -h --help display help and exit
324 -h --help display help and exit
325 --hidden consider hidden changesets
325 --hidden consider hidden changesets
326
326
327 (use "hg help" for the full list of commands)
327 (use "hg help" for the full list of commands)
328
328
329 $ hg add -h
329 $ hg add -h
330 hg add [OPTION]... [FILE]...
330 hg add [OPTION]... [FILE]...
331
331
332 add the specified files on the next commit
332 add the specified files on the next commit
333
333
334 Schedule files to be version controlled and added to the repository.
334 Schedule files to be version controlled and added to the repository.
335
335
336 The files will be added to the repository at the next commit. To undo an
336 The files will be added to the repository at the next commit. To undo an
337 add before that, see "hg forget".
337 add before that, see "hg forget".
338
338
339 If no names are given, add all files to the repository.
339 If no names are given, add all files to the repository.
340
340
341 Returns 0 if all files are successfully added.
341 Returns 0 if all files are successfully added.
342
342
343 options ([+] can be repeated):
343 options ([+] can be repeated):
344
344
345 -I --include PATTERN [+] include names matching the given patterns
345 -I --include PATTERN [+] include names matching the given patterns
346 -X --exclude PATTERN [+] exclude names matching the given patterns
346 -X --exclude PATTERN [+] exclude names matching the given patterns
347 -S --subrepos recurse into subrepositories
347 -S --subrepos recurse into subrepositories
348 -n --dry-run do not perform actions, just print output
348 -n --dry-run do not perform actions, just print output
349
349
350 (some details hidden, use --verbose to show complete help)
350 (some details hidden, use --verbose to show complete help)
351
351
352 Verbose help for add
352 Verbose help for add
353
353
354 $ hg add -hv
354 $ hg add -hv
355 hg add [OPTION]... [FILE]...
355 hg add [OPTION]... [FILE]...
356
356
357 add the specified files on the next commit
357 add the specified files on the next commit
358
358
359 Schedule files to be version controlled and added to the repository.
359 Schedule files to be version controlled and added to the repository.
360
360
361 The files will be added to the repository at the next commit. To undo an
361 The files will be added to the repository at the next commit. To undo an
362 add before that, see "hg forget".
362 add before that, see "hg forget".
363
363
364 If no names are given, add all files to the repository.
364 If no names are given, add all files to the repository.
365
365
366 An example showing how new (unknown) files are added automatically by "hg
366 An example showing how new (unknown) files are added automatically by "hg
367 add":
367 add":
368
368
369 $ ls
369 $ ls
370 foo.c
370 foo.c
371 $ hg status
371 $ hg status
372 ? foo.c
372 ? foo.c
373 $ hg add
373 $ hg add
374 adding foo.c
374 adding foo.c
375 $ hg status
375 $ hg status
376 A foo.c
376 A foo.c
377
377
378 Returns 0 if all files are successfully added.
378 Returns 0 if all files are successfully added.
379
379
380 options ([+] can be repeated):
380 options ([+] can be repeated):
381
381
382 -I --include PATTERN [+] include names matching the given patterns
382 -I --include PATTERN [+] include names matching the given patterns
383 -X --exclude PATTERN [+] exclude names matching the given patterns
383 -X --exclude PATTERN [+] exclude names matching the given patterns
384 -S --subrepos recurse into subrepositories
384 -S --subrepos recurse into subrepositories
385 -n --dry-run do not perform actions, just print output
385 -n --dry-run do not perform actions, just print output
386
386
387 global options ([+] can be repeated):
387 global options ([+] can be repeated):
388
388
389 -R --repository REPO repository root directory or name of overlay bundle
389 -R --repository REPO repository root directory or name of overlay bundle
390 file
390 file
391 --cwd DIR change working directory
391 --cwd DIR change working directory
392 -y --noninteractive do not prompt, automatically pick the first choice for
392 -y --noninteractive do not prompt, automatically pick the first choice for
393 all prompts
393 all prompts
394 -q --quiet suppress output
394 -q --quiet suppress output
395 -v --verbose enable additional output
395 -v --verbose enable additional output
396 --config CONFIG [+] set/override config option (use 'section.name=value')
396 --config CONFIG [+] set/override config option (use 'section.name=value')
397 --debug enable debugging output
397 --debug enable debugging output
398 --debugger start debugger
398 --debugger start debugger
399 --encoding ENCODE set the charset encoding (default: ascii)
399 --encoding ENCODE set the charset encoding (default: ascii)
400 --encodingmode MODE set the charset encoding mode (default: strict)
400 --encodingmode MODE set the charset encoding mode (default: strict)
401 --traceback always print a traceback on exception
401 --traceback always print a traceback on exception
402 --time time how long the command takes
402 --time time how long the command takes
403 --profile print command execution profile
403 --profile print command execution profile
404 --version output version information and exit
404 --version output version information and exit
405 -h --help display help and exit
405 -h --help display help and exit
406 --hidden consider hidden changesets
406 --hidden consider hidden changesets
407
407
408 Test help option with version option
408 Test help option with version option
409
409
410 $ hg add -h --version
410 $ hg add -h --version
411 Mercurial Distributed SCM (version *) (glob)
411 Mercurial Distributed SCM (version *) (glob)
412 (see http://mercurial.selenic.com for more information)
412 (see http://mercurial.selenic.com for more information)
413
413
414 Copyright (C) 2005-2014 Matt Mackall and others
414 Copyright (C) 2005-2014 Matt Mackall and others
415 This is free software; see the source for copying conditions. There is NO
415 This is free software; see the source for copying conditions. There is NO
416 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
416 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
417
417
418 $ hg add --skjdfks
418 $ hg add --skjdfks
419 hg add: option --skjdfks not recognized
419 hg add: option --skjdfks not recognized
420 hg add [OPTION]... [FILE]...
420 hg add [OPTION]... [FILE]...
421
421
422 add the specified files on the next commit
422 add the specified files on the next commit
423
423
424 options ([+] can be repeated):
424 options ([+] can be repeated):
425
425
426 -I --include PATTERN [+] include names matching the given patterns
426 -I --include PATTERN [+] include names matching the given patterns
427 -X --exclude PATTERN [+] exclude names matching the given patterns
427 -X --exclude PATTERN [+] exclude names matching the given patterns
428 -S --subrepos recurse into subrepositories
428 -S --subrepos recurse into subrepositories
429 -n --dry-run do not perform actions, just print output
429 -n --dry-run do not perform actions, just print output
430
430
431 (use "hg add -h" to show more help)
431 (use "hg add -h" to show more help)
432 [255]
432 [255]
433
433
434 Test ambiguous command help
434 Test ambiguous command help
435
435
436 $ hg help ad
436 $ hg help ad
437 list of commands:
437 list of commands:
438
438
439 add add the specified files on the next commit
439 add add the specified files on the next commit
440 addremove add all new files, delete all missing files
440 addremove add all new files, delete all missing files
441
441
442 (use "hg help -v ad" to show built-in aliases and global options)
442 (use "hg help -v ad" to show built-in aliases and global options)
443
443
444 Test command without options
444 Test command without options
445
445
446 $ hg help verify
446 $ hg help verify
447 hg verify
447 hg verify
448
448
449 verify the integrity of the repository
449 verify the integrity of the repository
450
450
451 Verify the integrity of the current repository.
451 Verify the integrity of the current repository.
452
452
453 This will perform an extensive check of the repository's integrity,
453 This will perform an extensive check of the repository's integrity,
454 validating the hashes and checksums of each entry in the changelog,
454 validating the hashes and checksums of each entry in the changelog,
455 manifest, and tracked files, as well as the integrity of their crosslinks
455 manifest, and tracked files, as well as the integrity of their crosslinks
456 and indices.
456 and indices.
457
457
458 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption for more
458 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption for more
459 information about recovery from corruption of the repository.
459 information about recovery from corruption of the repository.
460
460
461 Returns 0 on success, 1 if errors are encountered.
461 Returns 0 on success, 1 if errors are encountered.
462
462
463 (some details hidden, use --verbose to show complete help)
463 (some details hidden, use --verbose to show complete help)
464
464
465 $ hg help diff
465 $ hg help diff
466 hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...
466 hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...
467
467
468 diff repository (or selected files)
468 diff repository (or selected files)
469
469
470 Show differences between revisions for the specified files.
470 Show differences between revisions for the specified files.
471
471
472 Differences between files are shown using the unified diff format.
472 Differences between files are shown using the unified diff format.
473
473
474 Note:
474 Note:
475 diff may generate unexpected results for merges, as it will default to
475 diff may generate unexpected results for merges, as it will default to
476 comparing against the working directory's first parent changeset if no
476 comparing against the working directory's first parent changeset if no
477 revisions are specified.
477 revisions are specified.
478
478
479 When two revision arguments are given, then changes are shown between
479 When two revision arguments are given, then changes are shown between
480 those revisions. If only one revision is specified then that revision is
480 those revisions. If only one revision is specified then that revision is
481 compared to the working directory, and, when no revisions are specified,
481 compared to the working directory, and, when no revisions are specified,
482 the working directory files are compared to its parent.
482 the working directory files are compared to its parent.
483
483
484 Alternatively you can specify -c/--change with a revision to see the
484 Alternatively you can specify -c/--change with a revision to see the
485 changes in that changeset relative to its first parent.
485 changes in that changeset relative to its first parent.
486
486
487 Without the -a/--text option, diff will avoid generating diffs of files it
487 Without the -a/--text option, diff will avoid generating diffs of files it
488 detects as binary. With -a, diff will generate a diff anyway, probably
488 detects as binary. With -a, diff will generate a diff anyway, probably
489 with undesirable results.
489 with undesirable results.
490
490
491 Use the -g/--git option to generate diffs in the git extended diff format.
491 Use the -g/--git option to generate diffs in the git extended diff format.
492 For more information, read "hg help diffs".
492 For more information, read "hg help diffs".
493
493
494 Returns 0 on success.
494 Returns 0 on success.
495
495
496 options ([+] can be repeated):
496 options ([+] can be repeated):
497
497
498 -r --rev REV [+] revision
498 -r --rev REV [+] revision
499 -c --change REV change made by revision
499 -c --change REV change made by revision
500 -a --text treat all files as text
500 -a --text treat all files as text
501 -g --git use git extended diff format
501 -g --git use git extended diff format
502 --nodates omit dates from diff headers
502 --nodates omit dates from diff headers
503 --noprefix omit a/ and b/ prefixes from filenames
503 --noprefix omit a/ and b/ prefixes from filenames
504 -p --show-function show which function each change is in
504 -p --show-function show which function each change is in
505 --reverse produce a diff that undoes the changes
505 --reverse produce a diff that undoes the changes
506 -w --ignore-all-space ignore white space when comparing lines
506 -w --ignore-all-space ignore white space when comparing lines
507 -b --ignore-space-change ignore changes in the amount of white space
507 -b --ignore-space-change ignore changes in the amount of white space
508 -B --ignore-blank-lines ignore changes whose lines are all blank
508 -B --ignore-blank-lines ignore changes whose lines are all blank
509 -U --unified NUM number of lines of context to show
509 -U --unified NUM number of lines of context to show
510 --stat output diffstat-style summary of changes
510 --stat output diffstat-style summary of changes
511 -I --include PATTERN [+] include names matching the given patterns
511 -I --include PATTERN [+] include names matching the given patterns
512 -X --exclude PATTERN [+] exclude names matching the given patterns
512 -X --exclude PATTERN [+] exclude names matching the given patterns
513 -S --subrepos recurse into subrepositories
513 -S --subrepos recurse into subrepositories
514
514
515 (some details hidden, use --verbose to show complete help)
515 (some details hidden, use --verbose to show complete help)
516
516
517 $ hg help status
517 $ hg help status
518 hg status [OPTION]... [FILE]...
518 hg status [OPTION]... [FILE]...
519
519
520 aliases: st
520 aliases: st
521
521
522 show changed files in the working directory
522 show changed files in the working directory
523
523
524 Show status of files in the repository. If names are given, only files
524 Show status of files in the repository. If names are given, only files
525 that match are shown. Files that are clean or ignored or the source of a
525 that match are shown. Files that are clean or ignored or the source of a
526 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
526 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
527 -C/--copies or -A/--all are given. Unless options described with "show
527 -C/--copies or -A/--all are given. Unless options described with "show
528 only ..." are given, the options -mardu are used.
528 only ..." are given, the options -mardu are used.
529
529
530 Option -q/--quiet hides untracked (unknown and ignored) files unless
530 Option -q/--quiet hides untracked (unknown and ignored) files unless
531 explicitly requested with -u/--unknown or -i/--ignored.
531 explicitly requested with -u/--unknown or -i/--ignored.
532
532
533 Note:
533 Note:
534 status may appear to disagree with diff if permissions have changed or
534 status may appear to disagree with diff if permissions have changed or
535 a merge has occurred. The standard diff format does not report
535 a merge has occurred. The standard diff format does not report
536 permission changes and diff only reports changes relative to one merge
536 permission changes and diff only reports changes relative to one merge
537 parent.
537 parent.
538
538
539 If one revision is given, it is used as the base revision. If two
539 If one revision is given, it is used as the base revision. If two
540 revisions are given, the differences between them are shown. The --change
540 revisions are given, the differences between them are shown. The --change
541 option can also be used as a shortcut to list the changed files of a
541 option can also be used as a shortcut to list the changed files of a
542 revision from its first parent.
542 revision from its first parent.
543
543
544 The codes used to show the status of files are:
544 The codes used to show the status of files are:
545
545
546 M = modified
546 M = modified
547 A = added
547 A = added
548 R = removed
548 R = removed
549 C = clean
549 C = clean
550 ! = missing (deleted by non-hg command, but still tracked)
550 ! = missing (deleted by non-hg command, but still tracked)
551 ? = not tracked
551 ? = not tracked
552 I = ignored
552 I = ignored
553 = origin of the previous file (with --copies)
553 = origin of the previous file (with --copies)
554
554
555 Returns 0 on success.
555 Returns 0 on success.
556
556
557 options ([+] can be repeated):
557 options ([+] can be repeated):
558
558
559 -A --all show status of all files
559 -A --all show status of all files
560 -m --modified show only modified files
560 -m --modified show only modified files
561 -a --added show only added files
561 -a --added show only added files
562 -r --removed show only removed files
562 -r --removed show only removed files
563 -d --deleted show only deleted (but tracked) files
563 -d --deleted show only deleted (but tracked) files
564 -c --clean show only files without changes
564 -c --clean show only files without changes
565 -u --unknown show only unknown (not tracked) files
565 -u --unknown show only unknown (not tracked) files
566 -i --ignored show only ignored files
566 -i --ignored show only ignored files
567 -n --no-status hide status prefix
567 -n --no-status hide status prefix
568 -C --copies show source of copied files
568 -C --copies show source of copied files
569 -0 --print0 end filenames with NUL, for use with xargs
569 -0 --print0 end filenames with NUL, for use with xargs
570 --rev REV [+] show difference from revision
570 --rev REV [+] show difference from revision
571 --change REV list the changed files of a revision
571 --change REV list the changed files of a revision
572 -I --include PATTERN [+] include names matching the given patterns
572 -I --include PATTERN [+] include names matching the given patterns
573 -X --exclude PATTERN [+] exclude names matching the given patterns
573 -X --exclude PATTERN [+] exclude names matching the given patterns
574 -S --subrepos recurse into subrepositories
574 -S --subrepos recurse into subrepositories
575
575
576 (some details hidden, use --verbose to show complete help)
576 (some details hidden, use --verbose to show complete help)
577
577
578 $ hg -q help status
578 $ hg -q help status
579 hg status [OPTION]... [FILE]...
579 hg status [OPTION]... [FILE]...
580
580
581 show changed files in the working directory
581 show changed files in the working directory
582
582
583 $ hg help foo
583 $ hg help foo
584 abort: no such help topic: foo
584 abort: no such help topic: foo
585 (try "hg help --keyword foo")
585 (try "hg help --keyword foo")
586 [255]
586 [255]
587
587
588 $ hg skjdfks
588 $ hg skjdfks
589 hg: unknown command 'skjdfks'
589 hg: unknown command 'skjdfks'
590 Mercurial Distributed SCM
590 Mercurial Distributed SCM
591
591
592 basic commands:
592 basic commands:
593
593
594 add add the specified files on the next commit
594 add add the specified files on the next commit
595 annotate show changeset information by line for each file
595 annotate show changeset information by line for each file
596 clone make a copy of an existing repository
596 clone make a copy of an existing repository
597 commit commit the specified files or all outstanding changes
597 commit commit the specified files or all outstanding changes
598 diff diff repository (or selected files)
598 diff diff repository (or selected files)
599 export dump the header and diffs for one or more changesets
599 export dump the header and diffs for one or more changesets
600 forget forget the specified files on the next commit
600 forget forget the specified files on the next commit
601 init create a new repository in the given directory
601 init create a new repository in the given directory
602 log show revision history of entire repository or files
602 log show revision history of entire repository or files
603 merge merge working directory with another revision
603 merge merge working directory with another revision
604 pull pull changes from the specified source
604 pull pull changes from the specified source
605 push push changes to the specified destination
605 push push changes to the specified destination
606 remove remove the specified files on the next commit
606 remove remove the specified files on the next commit
607 serve start stand-alone webserver
607 serve start stand-alone webserver
608 status show changed files in the working directory
608 status show changed files in the working directory
609 summary summarize working directory state
609 summary summarize working directory state
610 update update working directory (or switch revisions)
610 update update working directory (or switch revisions)
611
611
612 (use "hg help" for the full list of commands or "hg -v" for details)
612 (use "hg help" for the full list of commands or "hg -v" for details)
613 [255]
613 [255]
614
614
615
615
616 $ cat > helpext.py <<EOF
616 $ cat > helpext.py <<EOF
617 > import os
617 > import os
618 > from mercurial import cmdutil, commands
618 > from mercurial import cmdutil, commands
619 >
619 >
620 > cmdtable = {}
620 > cmdtable = {}
621 > command = cmdutil.command(cmdtable)
621 > command = cmdutil.command(cmdtable)
622 >
622 >
623 > @command('nohelp',
623 > @command('nohelp',
624 > [('', 'longdesc', 3, 'x'*90),
624 > [('', 'longdesc', 3, 'x'*90),
625 > ('n', '', None, 'normal desc'),
625 > ('n', '', None, 'normal desc'),
626 > ('', 'newline', '', 'line1\nline2')],
626 > ('', 'newline', '', 'line1\nline2')],
627 > 'hg nohelp',
627 > 'hg nohelp',
628 > norepo=True)
628 > norepo=True)
629 > @command('debugoptDEP', [('', 'dopt', None, 'option is DEPRECATED')])
629 > @command('debugoptDEP', [('', 'dopt', None, 'option is DEPRECATED')])
630 > def nohelp(ui, *args, **kwargs):
630 > def nohelp(ui, *args, **kwargs):
631 > pass
631 > pass
632 >
632 >
633 > EOF
633 > EOF
634 $ echo '[extensions]' >> $HGRCPATH
634 $ echo '[extensions]' >> $HGRCPATH
635 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
635 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
636
636
637 Test command with no help text
637 Test command with no help text
638
638
639 $ hg help nohelp
639 $ hg help nohelp
640 hg nohelp
640 hg nohelp
641
641
642 (no help text available)
642 (no help text available)
643
643
644 options:
644 options:
645
645
646 --longdesc VALUE xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
646 --longdesc VALUE xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
647 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (default: 3)
647 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (default: 3)
648 -n -- normal desc
648 -n -- normal desc
649 --newline VALUE line1 line2
649 --newline VALUE line1 line2
650
650
651 (some details hidden, use --verbose to show complete help)
651 (some details hidden, use --verbose to show complete help)
652
652
653 $ hg help -k nohelp
653 $ hg help -k nohelp
654 Commands:
654 Commands:
655
655
656 nohelp hg nohelp
656 nohelp hg nohelp
657
657
658 Extension Commands:
658 Extension Commands:
659
659
660 nohelp (no help text available)
660 nohelp (no help text available)
661
661
662 Test that default list of commands omits extension commands
662 Test that default list of commands omits extension commands
663
663
664 $ hg help
664 $ hg help
665 Mercurial Distributed SCM
665 Mercurial Distributed SCM
666
666
667 list of commands:
667 list of commands:
668
668
669 add add the specified files on the next commit
669 add add the specified files on the next commit
670 addremove add all new files, delete all missing files
670 addremove add all new files, delete all missing files
671 annotate show changeset information by line for each file
671 annotate show changeset information by line for each file
672 archive create an unversioned archive of a repository revision
672 archive create an unversioned archive of a repository revision
673 backout reverse effect of earlier changeset
673 backout reverse effect of earlier changeset
674 bisect subdivision search of changesets
674 bisect subdivision search of changesets
675 bookmarks create a new bookmark or list existing bookmarks
675 bookmarks create a new bookmark or list existing bookmarks
676 branch set or show the current branch name
676 branch set or show the current branch name
677 branches list repository named branches
677 branches list repository named branches
678 bundle create a changegroup file
678 bundle create a changegroup file
679 cat output the current or given revision of files
679 cat output the current or given revision of files
680 clone make a copy of an existing repository
680 clone make a copy of an existing repository
681 commit commit the specified files or all outstanding changes
681 commit commit the specified files or all outstanding changes
682 config show combined config settings from all hgrc files
682 config show combined config settings from all hgrc files
683 copy mark files as copied for the next commit
683 copy mark files as copied for the next commit
684 diff diff repository (or selected files)
684 diff diff repository (or selected files)
685 export dump the header and diffs for one or more changesets
685 export dump the header and diffs for one or more changesets
686 files list tracked files
686 files list tracked files
687 forget forget the specified files on the next commit
687 forget forget the specified files on the next commit
688 graft copy changes from other branches onto the current branch
688 graft copy changes from other branches onto the current branch
689 grep search for a pattern in specified files and revisions
689 grep search for a pattern in specified files and revisions
690 heads show branch heads
690 heads show branch heads
691 help show help for a given topic or a help overview
691 help show help for a given topic or a help overview
692 identify identify the working copy or specified revision
692 identify identify the working copy or specified revision
693 import import an ordered set of patches
693 import import an ordered set of patches
694 incoming show new changesets found in source
694 incoming show new changesets found in source
695 init create a new repository in the given directory
695 init create a new repository in the given directory
696 log show revision history of entire repository or files
696 log show revision history of entire repository or files
697 manifest output the current or given revision of the project manifest
697 manifest output the current or given revision of the project manifest
698 merge merge working directory with another revision
698 merge merge working directory with another revision
699 outgoing show changesets not found in the destination
699 outgoing show changesets not found in the destination
700 paths show aliases for remote repositories
700 paths show aliases for remote repositories
701 phase set or show the current phase name
701 phase set or show the current phase name
702 pull pull changes from the specified source
702 pull pull changes from the specified source
703 push push changes to the specified destination
703 push push changes to the specified destination
704 recover roll back an interrupted transaction
704 recover roll back an interrupted transaction
705 remove remove the specified files on the next commit
705 remove remove the specified files on the next commit
706 rename rename files; equivalent of copy + remove
706 rename rename files; equivalent of copy + remove
707 resolve redo merges or set/view the merge status of files
707 resolve redo merges or set/view the merge status of files
708 revert restore files to their checkout state
708 revert restore files to their checkout state
709 root print the root (top) of the current working directory
709 root print the root (top) of the current working directory
710 serve start stand-alone webserver
710 serve start stand-alone webserver
711 status show changed files in the working directory
711 status show changed files in the working directory
712 summary summarize working directory state
712 summary summarize working directory state
713 tag add one or more tags for the current or given revision
713 tag add one or more tags for the current or given revision
714 tags list repository tags
714 tags list repository tags
715 unbundle apply one or more changegroup files
715 unbundle apply one or more changegroup files
716 update update working directory (or switch revisions)
716 update update working directory (or switch revisions)
717 verify verify the integrity of the repository
717 verify verify the integrity of the repository
718 version output version and copyright information
718 version output version and copyright information
719
719
720 enabled extensions:
720 enabled extensions:
721
721
722 helpext (no help text available)
722 helpext (no help text available)
723
723
724 additional help topics:
724 additional help topics:
725
725
726 config Configuration Files
726 config Configuration Files
727 dates Date Formats
727 dates Date Formats
728 diffs Diff Formats
728 diffs Diff Formats
729 environment Environment Variables
729 environment Environment Variables
730 extensions Using Additional Features
730 extensions Using Additional Features
731 filesets Specifying File Sets
731 filesets Specifying File Sets
732 glossary Glossary
732 glossary Glossary
733 hgignore Syntax for Mercurial Ignore Files
733 hgignore Syntax for Mercurial Ignore Files
734 hgweb Configuring hgweb
734 hgweb Configuring hgweb
735 merge-tools Merge Tools
735 merge-tools Merge Tools
736 multirevs Specifying Multiple Revisions
736 multirevs Specifying Multiple Revisions
737 patterns File Name Patterns
737 patterns File Name Patterns
738 phases Working with Phases
738 phases Working with Phases
739 revisions Specifying Single Revisions
739 revisions Specifying Single Revisions
740 revsets Specifying Revision Sets
740 revsets Specifying Revision Sets
741 subrepos Subrepositories
741 subrepos Subrepositories
742 templating Template Usage
742 templating Template Usage
743 urls URL Paths
743 urls URL Paths
744
744
745 (use "hg help -v" to show built-in aliases and global options)
745 (use "hg help -v" to show built-in aliases and global options)
746
746
747
747
748 Test list of internal help commands
748 Test list of internal help commands
749
749
750 $ hg help debug
750 $ hg help debug
751 debug commands (internal and unsupported):
751 debug commands (internal and unsupported):
752
752
753 debugancestor
753 debugancestor
754 find the ancestor revision of two revisions in a given index
754 find the ancestor revision of two revisions in a given index
755 debugbuilddag
755 debugbuilddag
756 builds a repo with a given DAG from scratch in the current
756 builds a repo with a given DAG from scratch in the current
757 empty repo
757 empty repo
758 debugbundle lists the contents of a bundle
758 debugbundle lists the contents of a bundle
759 debugcheckstate
759 debugcheckstate
760 validate the correctness of the current dirstate
760 validate the correctness of the current dirstate
761 debugcommands
761 debugcommands
762 list all available commands and options
762 list all available commands and options
763 debugcomplete
763 debugcomplete
764 returns the completion list associated with the given command
764 returns the completion list associated with the given command
765 debugdag format the changelog or an index DAG as a concise textual
765 debugdag format the changelog or an index DAG as a concise textual
766 description
766 description
767 debugdata dump the contents of a data file revision
767 debugdata dump the contents of a data file revision
768 debugdate parse and display a date
768 debugdate parse and display a date
769 debugdirstate
769 debugdirstate
770 show the contents of the current dirstate
770 show the contents of the current dirstate
771 debugdiscovery
771 debugdiscovery
772 runs the changeset discovery protocol in isolation
772 runs the changeset discovery protocol in isolation
773 debugfileset parse and apply a fileset specification
773 debugfileset parse and apply a fileset specification
774 debugfsinfo show information detected about current filesystem
774 debugfsinfo show information detected about current filesystem
775 debuggetbundle
775 debuggetbundle
776 retrieves a bundle from a repo
776 retrieves a bundle from a repo
777 debugignore display the combined ignore pattern
777 debugignore display the combined ignore pattern
778 debugindex dump the contents of an index file
778 debugindex dump the contents of an index file
779 debugindexdot
779 debugindexdot
780 dump an index DAG as a graphviz dot file
780 dump an index DAG as a graphviz dot file
781 debuginstall test Mercurial installation
781 debuginstall test Mercurial installation
782 debugknown test whether node ids are known to a repo
782 debugknown test whether node ids are known to a repo
783 debuglabelcomplete
783 debuglabelcomplete
784 complete "labels" - tags, open branch names, bookmark names
784 complete "labels" - tags, open branch names, bookmark names
785 debuglocks show or modify state of locks
785 debuglocks show or modify state of locks
786 debugobsolete
786 debugobsolete
787 create arbitrary obsolete marker
787 create arbitrary obsolete marker
788 debugoptDEP (no help text available)
788 debugoptDEP (no help text available)
789 debugpathcomplete
789 debugpathcomplete
790 complete part or all of a tracked path
790 complete part or all of a tracked path
791 debugpushkey access the pushkey key/value protocol
791 debugpushkey access the pushkey key/value protocol
792 debugpvec (no help text available)
792 debugpvec (no help text available)
793 debugrebuilddirstate
793 debugrebuilddirstate
794 rebuild the dirstate as it would look like for the given
794 rebuild the dirstate as it would look like for the given
795 revision
795 revision
796 debugrename dump rename information
796 debugrename dump rename information
797 debugrevlog show data and statistics about a revlog
797 debugrevlog show data and statistics about a revlog
798 debugrevspec parse and apply a revision specification
798 debugrevspec parse and apply a revision specification
799 debugsetparents
799 debugsetparents
800 manually set the parents of the current working directory
800 manually set the parents of the current working directory
801 debugsub (no help text available)
801 debugsub (no help text available)
802 debugsuccessorssets
802 debugsuccessorssets
803 show set of successors for revision
803 show set of successors for revision
804 debugwalk show how files match on given patterns
804 debugwalk show how files match on given patterns
805 debugwireargs
805 debugwireargs
806 (no help text available)
806 (no help text available)
807
807
808 (use "hg help -v debug" to show built-in aliases and global options)
808 (use "hg help -v debug" to show built-in aliases and global options)
809
809
810
810
811 Test list of commands with command with no help text
811 Test list of commands with command with no help text
812
812
813 $ hg help helpext
813 $ hg help helpext
814 helpext extension - no help text available
814 helpext extension - no help text available
815
815
816 list of commands:
816 list of commands:
817
817
818 nohelp (no help text available)
818 nohelp (no help text available)
819
819
820 (use "hg help -v helpext" to show built-in aliases and global options)
820 (use "hg help -v helpext" to show built-in aliases and global options)
821
821
822
822
823 test deprecated option is hidden in command help
823 test deprecated option is hidden in command help
824 $ hg help debugoptDEP
824 $ hg help debugoptDEP
825 hg debugoptDEP
825 hg debugoptDEP
826
826
827 (no help text available)
827 (no help text available)
828
828
829 options:
829 options:
830
830
831 (some details hidden, use --verbose to show complete help)
831 (some details hidden, use --verbose to show complete help)
832
832
833 test deprecated option is shown with -v
833 test deprecated option is shown with -v
834 $ hg help -v debugoptDEP | grep dopt
834 $ hg help -v debugoptDEP | grep dopt
835 --dopt option is DEPRECATED
835 --dopt option is DEPRECATED
836
836
837 #if gettext
837 #if gettext
838 test deprecated option is hidden with translation with untranslated description
838 test deprecated option is hidden with translation with untranslated description
839 (use many globy for not failing on changed transaction)
839 (use many globy for not failing on changed transaction)
840 $ LANGUAGE=sv hg help debugoptDEP
840 $ LANGUAGE=sv hg help debugoptDEP
841 hg debugoptDEP
841 hg debugoptDEP
842
842
843 (*) (glob)
843 (*) (glob)
844
844
845 options:
845 options:
846
846
847 (some details hidden, use --verbose to show complete help)
847 (some details hidden, use --verbose to show complete help)
848 #endif
848 #endif
849
849
850 Test commands that collide with topics (issue4240)
850 Test commands that collide with topics (issue4240)
851
851
852 $ hg config -hq
852 $ hg config -hq
853 hg config [-u] [NAME]...
853 hg config [-u] [NAME]...
854
854
855 show combined config settings from all hgrc files
855 show combined config settings from all hgrc files
856 $ hg showconfig -hq
856 $ hg showconfig -hq
857 hg config [-u] [NAME]...
857 hg config [-u] [NAME]...
858
858
859 show combined config settings from all hgrc files
859 show combined config settings from all hgrc files
860
860
861 Test a help topic
861 Test a help topic
862
862
863 $ hg help revs
863 $ hg help revs
864 Specifying Single Revisions
864 Specifying Single Revisions
865 """""""""""""""""""""""""""
865 """""""""""""""""""""""""""
866
866
867 Mercurial supports several ways to specify individual revisions.
867 Mercurial supports several ways to specify individual revisions.
868
868
869 A plain integer is treated as a revision number. Negative integers are
869 A plain integer is treated as a revision number. Negative integers are
870 treated as sequential offsets from the tip, with -1 denoting the tip, -2
870 treated as sequential offsets from the tip, with -1 denoting the tip, -2
871 denoting the revision prior to the tip, and so forth.
871 denoting the revision prior to the tip, and so forth.
872
872
873 A 40-digit hexadecimal string is treated as a unique revision identifier.
873 A 40-digit hexadecimal string is treated as a unique revision identifier.
874
874
875 A hexadecimal string less than 40 characters long is treated as a unique
875 A hexadecimal string less than 40 characters long is treated as a unique
876 revision identifier and is referred to as a short-form identifier. A
876 revision identifier and is referred to as a short-form identifier. A
877 short-form identifier is only valid if it is the prefix of exactly one
877 short-form identifier is only valid if it is the prefix of exactly one
878 full-length identifier.
878 full-length identifier.
879
879
880 Any other string is treated as a bookmark, tag, or branch name. A bookmark
880 Any other string is treated as a bookmark, tag, or branch name. A bookmark
881 is a movable pointer to a revision. A tag is a permanent name associated
881 is a movable pointer to a revision. A tag is a permanent name associated
882 with a revision. A branch name denotes the tipmost open branch head of
882 with a revision. A branch name denotes the tipmost open branch head of
883 that branch - or if they are all closed, the tipmost closed head of the
883 that branch - or if they are all closed, the tipmost closed head of the
884 branch. Bookmark, tag, and branch names must not contain the ":"
884 branch. Bookmark, tag, and branch names must not contain the ":"
885 character.
885 character.
886
886
887 The reserved name "tip" always identifies the most recent revision.
887 The reserved name "tip" always identifies the most recent revision.
888
888
889 The reserved name "null" indicates the null revision. This is the revision
889 The reserved name "null" indicates the null revision. This is the revision
890 of an empty repository, and the parent of revision 0.
890 of an empty repository, and the parent of revision 0.
891
891
892 The reserved name "." indicates the working directory parent. If no
892 The reserved name "." indicates the working directory parent. If no
893 working directory is checked out, it is equivalent to null. If an
893 working directory is checked out, it is equivalent to null. If an
894 uncommitted merge is in progress, "." is the revision of the first parent.
894 uncommitted merge is in progress, "." is the revision of the first parent.
895
895
896 Test templating help
896 Test templating help
897
897
898 $ hg help templating | egrep '(desc|diffstat|firstline|nonempty) '
898 $ hg help templating | egrep '(desc|diffstat|firstline|nonempty) '
899 desc String. The text of the changeset description.
899 desc String. The text of the changeset description.
900 diffstat String. Statistics of changes with the following format:
900 diffstat String. Statistics of changes with the following format:
901 firstline Any text. Returns the first line of text.
901 firstline Any text. Returns the first line of text.
902 nonempty Any text. Returns '(none)' if the string is empty.
902 nonempty Any text. Returns '(none)' if the string is empty.
903
903
904 Test help hooks
904 Test help hooks
905
905
906 $ cat > helphook1.py <<EOF
906 $ cat > helphook1.py <<EOF
907 > from mercurial import help
907 > from mercurial import help
908 >
908 >
909 > def rewrite(topic, doc):
909 > def rewrite(topic, doc):
910 > return doc + '\nhelphook1\n'
910 > return doc + '\nhelphook1\n'
911 >
911 >
912 > def extsetup(ui):
912 > def extsetup(ui):
913 > help.addtopichook('revsets', rewrite)
913 > help.addtopichook('revsets', rewrite)
914 > EOF
914 > EOF
915 $ cat > helphook2.py <<EOF
915 $ cat > helphook2.py <<EOF
916 > from mercurial import help
916 > from mercurial import help
917 >
917 >
918 > def rewrite(topic, doc):
918 > def rewrite(topic, doc):
919 > return doc + '\nhelphook2\n'
919 > return doc + '\nhelphook2\n'
920 >
920 >
921 > def extsetup(ui):
921 > def extsetup(ui):
922 > help.addtopichook('revsets', rewrite)
922 > help.addtopichook('revsets', rewrite)
923 > EOF
923 > EOF
924 $ echo '[extensions]' >> $HGRCPATH
924 $ echo '[extensions]' >> $HGRCPATH
925 $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
925 $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
926 $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
926 $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
927 $ hg help revsets | grep helphook
927 $ hg help revsets | grep helphook
928 helphook1
928 helphook1
929 helphook2
929 helphook2
930
930
931 Test keyword search help
931 Test keyword search help
932
932
933 $ cat > prefixedname.py <<EOF
933 $ cat > prefixedname.py <<EOF
934 > '''matched against word "clone"
934 > '''matched against word "clone"
935 > '''
935 > '''
936 > EOF
936 > EOF
937 $ echo '[extensions]' >> $HGRCPATH
937 $ echo '[extensions]' >> $HGRCPATH
938 $ echo "dot.dot.prefixedname = `pwd`/prefixedname.py" >> $HGRCPATH
938 $ echo "dot.dot.prefixedname = `pwd`/prefixedname.py" >> $HGRCPATH
939 $ hg help -k clone
939 $ hg help -k clone
940 Topics:
940 Topics:
941
941
942 config Configuration Files
942 config Configuration Files
943 extensions Using Additional Features
943 extensions Using Additional Features
944 glossary Glossary
944 glossary Glossary
945 phases Working with Phases
945 phases Working with Phases
946 subrepos Subrepositories
946 subrepos Subrepositories
947 urls URL Paths
947 urls URL Paths
948
948
949 Commands:
949 Commands:
950
950
951 bookmarks create a new bookmark or list existing bookmarks
951 bookmarks create a new bookmark or list existing bookmarks
952 clone make a copy of an existing repository
952 clone make a copy of an existing repository
953 paths show aliases for remote repositories
953 paths show aliases for remote repositories
954 update update working directory (or switch revisions)
954 update update working directory (or switch revisions)
955
955
956 Extensions:
956 Extensions:
957
957
958 prefixedname matched against word "clone"
958 prefixedname matched against word "clone"
959 relink recreates hardlinks between repository clones
959 relink recreates hardlinks between repository clones
960
960
961 Extension Commands:
961 Extension Commands:
962
962
963 qclone clone main and patch repository at same time
963 qclone clone main and patch repository at same time
964
964
965 Test unfound topic
965 Test unfound topic
966
966
967 $ hg help nonexistingtopicthatwillneverexisteverever
967 $ hg help nonexistingtopicthatwillneverexisteverever
968 abort: no such help topic: nonexistingtopicthatwillneverexisteverever
968 abort: no such help topic: nonexistingtopicthatwillneverexisteverever
969 (try "hg help --keyword nonexistingtopicthatwillneverexisteverever")
969 (try "hg help --keyword nonexistingtopicthatwillneverexisteverever")
970 [255]
970 [255]
971
971
972 Test unfound keyword
972 Test unfound keyword
973
973
974 $ hg help --keyword nonexistingwordthatwillneverexisteverever
974 $ hg help --keyword nonexistingwordthatwillneverexisteverever
975 abort: no matches
975 abort: no matches
976 (try "hg help" for a list of topics)
976 (try "hg help" for a list of topics)
977 [255]
977 [255]
978
978
979 Test omit indicating for help
979 Test omit indicating for help
980
980
981 $ cat > addverboseitems.py <<EOF
981 $ cat > addverboseitems.py <<EOF
982 > '''extension to test omit indicating.
982 > '''extension to test omit indicating.
983 >
983 >
984 > This paragraph is never omitted (for extension)
984 > This paragraph is never omitted (for extension)
985 >
985 >
986 > .. container:: verbose
986 > .. container:: verbose
987 >
987 >
988 > This paragraph is omitted,
988 > This paragraph is omitted,
989 > if :hg:\`help\` is invoked witout \`\`-v\`\` (for extension)
989 > if :hg:\`help\` is invoked witout \`\`-v\`\` (for extension)
990 >
990 >
991 > This paragraph is never omitted, too (for extension)
991 > This paragraph is never omitted, too (for extension)
992 > '''
992 > '''
993 >
993 >
994 > from mercurial import help, commands
994 > from mercurial import help, commands
995 > testtopic = """This paragraph is never omitted (for topic).
995 > testtopic = """This paragraph is never omitted (for topic).
996 >
996 >
997 > .. container:: verbose
997 > .. container:: verbose
998 >
998 >
999 > This paragraph is omitted,
999 > This paragraph is omitted,
1000 > if :hg:\`help\` is invoked witout \`\`-v\`\` (for topic)
1000 > if :hg:\`help\` is invoked witout \`\`-v\`\` (for topic)
1001 >
1001 >
1002 > This paragraph is never omitted, too (for topic)
1002 > This paragraph is never omitted, too (for topic)
1003 > """
1003 > """
1004 > def extsetup(ui):
1004 > def extsetup(ui):
1005 > help.helptable.append((["topic-containing-verbose"],
1005 > help.helptable.append((["topic-containing-verbose"],
1006 > "This is the topic to test omit indicating.",
1006 > "This is the topic to test omit indicating.",
1007 > lambda : testtopic))
1007 > lambda : testtopic))
1008 > EOF
1008 > EOF
1009 $ echo '[extensions]' >> $HGRCPATH
1009 $ echo '[extensions]' >> $HGRCPATH
1010 $ echo "addverboseitems = `pwd`/addverboseitems.py" >> $HGRCPATH
1010 $ echo "addverboseitems = `pwd`/addverboseitems.py" >> $HGRCPATH
1011 $ hg help addverboseitems
1011 $ hg help addverboseitems
1012 addverboseitems extension - extension to test omit indicating.
1012 addverboseitems extension - extension to test omit indicating.
1013
1013
1014 This paragraph is never omitted (for extension)
1014 This paragraph is never omitted (for extension)
1015
1015
1016 This paragraph is never omitted, too (for extension)
1016 This paragraph is never omitted, too (for extension)
1017
1017
1018 (some details hidden, use --verbose to show complete help)
1018 (some details hidden, use --verbose to show complete help)
1019
1019
1020 no commands defined
1020 no commands defined
1021 $ hg help -v addverboseitems
1021 $ hg help -v addverboseitems
1022 addverboseitems extension - extension to test omit indicating.
1022 addverboseitems extension - extension to test omit indicating.
1023
1023
1024 This paragraph is never omitted (for extension)
1024 This paragraph is never omitted (for extension)
1025
1025
1026 This paragraph is omitted, if "hg help" is invoked witout "-v" (for extension)
1026 This paragraph is omitted, if "hg help" is invoked witout "-v" (for extension)
1027
1027
1028 This paragraph is never omitted, too (for extension)
1028 This paragraph is never omitted, too (for extension)
1029
1029
1030 no commands defined
1030 no commands defined
1031 $ hg help topic-containing-verbose
1031 $ hg help topic-containing-verbose
1032 This is the topic to test omit indicating.
1032 This is the topic to test omit indicating.
1033 """"""""""""""""""""""""""""""""""""""""""
1033 """"""""""""""""""""""""""""""""""""""""""
1034
1034
1035 This paragraph is never omitted (for topic).
1035 This paragraph is never omitted (for topic).
1036
1036
1037 This paragraph is never omitted, too (for topic)
1037 This paragraph is never omitted, too (for topic)
1038
1038
1039 (some details hidden, use --verbose to show complete help)
1039 (some details hidden, use --verbose to show complete help)
1040 $ hg help -v topic-containing-verbose
1040 $ hg help -v topic-containing-verbose
1041 This is the topic to test omit indicating.
1041 This is the topic to test omit indicating.
1042 """"""""""""""""""""""""""""""""""""""""""
1042 """"""""""""""""""""""""""""""""""""""""""
1043
1043
1044 This paragraph is never omitted (for topic).
1044 This paragraph is never omitted (for topic).
1045
1045
1046 This paragraph is omitted, if "hg help" is invoked witout "-v" (for topic)
1046 This paragraph is omitted, if "hg help" is invoked witout "-v" (for topic)
1047
1047
1048 This paragraph is never omitted, too (for topic)
1048 This paragraph is never omitted, too (for topic)
1049
1049
1050 Test section lookup
1050 Test section lookup
1051
1051
1052 $ hg help revset.merge
1052 $ hg help revset.merge
1053 "merge()"
1053 "merge()"
1054 Changeset is a merge changeset.
1054 Changeset is a merge changeset.
1055
1055
1056 $ hg help glossary.dag
1056 $ hg help glossary.dag
1057 DAG
1057 DAG
1058 The repository of changesets of a distributed version control system
1058 The repository of changesets of a distributed version control system
1059 (DVCS) can be described as a directed acyclic graph (DAG), consisting
1059 (DVCS) can be described as a directed acyclic graph (DAG), consisting
1060 of nodes and edges, where nodes correspond to changesets and edges
1060 of nodes and edges, where nodes correspond to changesets and edges
1061 imply a parent -> child relation. This graph can be visualized by
1061 imply a parent -> child relation. This graph can be visualized by
1062 graphical tools such as "hg log --graph". In Mercurial, the DAG is
1062 graphical tools such as "hg log --graph". In Mercurial, the DAG is
1063 limited by the requirement for children to have at most two parents.
1063 limited by the requirement for children to have at most two parents.
1064
1064
1065
1065
1066 $ hg help hgrc.paths
1066 $ hg help hgrc.paths
1067 "paths"
1067 "paths"
1068 -------
1068 -------
1069
1069
1070 Assigns symbolic names to repositories. The left side is the symbolic
1070 Assigns symbolic names to repositories. The left side is the symbolic
1071 name, and the right gives the directory or URL that is the location of the
1071 name, and the right gives the directory or URL that is the location of the
1072 repository. Default paths can be declared by setting the following
1072 repository. Default paths can be declared by setting the following
1073 entries.
1073 entries.
1074
1074
1075 "default"
1075 "default"
1076 Directory or URL to use when pulling if no source is specified.
1076 Directory or URL to use when pulling if no source is specified.
1077 Default is set to repository from which the current repository was
1077 Default is set to repository from which the current repository was
1078 cloned.
1078 cloned.
1079
1079
1080 "default-push"
1080 "default-push"
1081 Optional. Directory or URL to use when pushing if no destination is
1081 Optional. Directory or URL to use when pushing if no destination is
1082 specified.
1082 specified.
1083
1083
1084 Custom paths can be defined by assigning the path to a name that later can
1084 Custom paths can be defined by assigning the path to a name that later can
1085 be used from the command line. Example:
1085 be used from the command line. Example:
1086
1086
1087 [paths]
1087 [paths]
1088 my_path = http://example.com/path
1088 my_path = http://example.com/path
1089
1089
1090 To push to the path defined in "my_path" run the command:
1090 To push to the path defined in "my_path" run the command:
1091
1091
1092 hg push my_path
1092 hg push my_path
1093
1093
1094 $ hg help glossary.mcguffin
1094 $ hg help glossary.mcguffin
1095 abort: help section not found
1095 abort: help section not found
1096 [255]
1096 [255]
1097
1097
1098 $ hg help glossary.mc.guffin
1098 $ hg help glossary.mc.guffin
1099 abort: help section not found
1099 abort: help section not found
1100 [255]
1100 [255]
1101
1101
1102 Test usage of section marks in help documents
1102 Test usage of section marks in help documents
1103
1103
1104 $ cd "$TESTDIR"/../doc
1104 $ cd "$TESTDIR"/../doc
1105 $ python check-seclevel.py
1105 $ python check-seclevel.py
1106 $ cd $TESTTMP
1106 $ cd $TESTTMP
1107
1107
1108 #if serve
1108 #if serve
1109
1109
1110 Test the help pages in hgweb.
1110 Test the help pages in hgweb.
1111
1111
1112 Dish up an empty repo; serve it cold.
1112 Dish up an empty repo; serve it cold.
1113
1113
1114 $ hg init "$TESTTMP/test"
1114 $ hg init "$TESTTMP/test"
1115 $ hg serve -R "$TESTTMP/test" -n test -p $HGPORT -d --pid-file=hg.pid
1115 $ hg serve -R "$TESTTMP/test" -n test -p $HGPORT -d --pid-file=hg.pid
1116 $ cat hg.pid >> $DAEMON_PIDS
1116 $ cat hg.pid >> $DAEMON_PIDS
1117
1117
1118 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help"
1118 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help"
1119 200 Script output follows
1119 200 Script output follows
1120
1120
1121 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1121 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1122 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1122 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1123 <head>
1123 <head>
1124 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1124 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1125 <meta name="robots" content="index, nofollow" />
1125 <meta name="robots" content="index, nofollow" />
1126 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1126 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1127 <script type="text/javascript" src="/static/mercurial.js"></script>
1127 <script type="text/javascript" src="/static/mercurial.js"></script>
1128
1128
1129 <title>Help: Index</title>
1129 <title>Help: Index</title>
1130 </head>
1130 </head>
1131 <body>
1131 <body>
1132
1132
1133 <div class="container">
1133 <div class="container">
1134 <div class="menu">
1134 <div class="menu">
1135 <div class="logo">
1135 <div class="logo">
1136 <a href="http://mercurial.selenic.com/">
1136 <a href="http://mercurial.selenic.com/">
1137 <img src="/static/hglogo.png" alt="mercurial" /></a>
1137 <img src="/static/hglogo.png" alt="mercurial" /></a>
1138 </div>
1138 </div>
1139 <ul>
1139 <ul>
1140 <li><a href="/shortlog">log</a></li>
1140 <li><a href="/shortlog">log</a></li>
1141 <li><a href="/graph">graph</a></li>
1141 <li><a href="/graph">graph</a></li>
1142 <li><a href="/tags">tags</a></li>
1142 <li><a href="/tags">tags</a></li>
1143 <li><a href="/bookmarks">bookmarks</a></li>
1143 <li><a href="/bookmarks">bookmarks</a></li>
1144 <li><a href="/branches">branches</a></li>
1144 <li><a href="/branches">branches</a></li>
1145 </ul>
1145 </ul>
1146 <ul>
1146 <ul>
1147 <li class="active">help</li>
1147 <li class="active">help</li>
1148 </ul>
1148 </ul>
1149 </div>
1149 </div>
1150
1150
1151 <div class="main">
1151 <div class="main">
1152 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1152 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1153 <form class="search" action="/log">
1153 <form class="search" action="/log">
1154
1154
1155 <p><input name="rev" id="search1" type="text" size="30" /></p>
1155 <p><input name="rev" id="search1" type="text" size="30" /></p>
1156 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1156 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1157 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1157 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1158 </form>
1158 </form>
1159 <table class="bigtable">
1159 <table class="bigtable">
1160 <tr><td colspan="2"><h2><a name="main" href="#topics">Topics</a></h2></td></tr>
1160 <tr><td colspan="2"><h2><a name="main" href="#topics">Topics</a></h2></td></tr>
1161
1161
1162 <tr><td>
1162 <tr><td>
1163 <a href="/help/config">
1163 <a href="/help/config">
1164 config
1164 config
1165 </a>
1165 </a>
1166 </td><td>
1166 </td><td>
1167 Configuration Files
1167 Configuration Files
1168 </td></tr>
1168 </td></tr>
1169 <tr><td>
1169 <tr><td>
1170 <a href="/help/dates">
1170 <a href="/help/dates">
1171 dates
1171 dates
1172 </a>
1172 </a>
1173 </td><td>
1173 </td><td>
1174 Date Formats
1174 Date Formats
1175 </td></tr>
1175 </td></tr>
1176 <tr><td>
1176 <tr><td>
1177 <a href="/help/diffs">
1177 <a href="/help/diffs">
1178 diffs
1178 diffs
1179 </a>
1179 </a>
1180 </td><td>
1180 </td><td>
1181 Diff Formats
1181 Diff Formats
1182 </td></tr>
1182 </td></tr>
1183 <tr><td>
1183 <tr><td>
1184 <a href="/help/environment">
1184 <a href="/help/environment">
1185 environment
1185 environment
1186 </a>
1186 </a>
1187 </td><td>
1187 </td><td>
1188 Environment Variables
1188 Environment Variables
1189 </td></tr>
1189 </td></tr>
1190 <tr><td>
1190 <tr><td>
1191 <a href="/help/extensions">
1191 <a href="/help/extensions">
1192 extensions
1192 extensions
1193 </a>
1193 </a>
1194 </td><td>
1194 </td><td>
1195 Using Additional Features
1195 Using Additional Features
1196 </td></tr>
1196 </td></tr>
1197 <tr><td>
1197 <tr><td>
1198 <a href="/help/filesets">
1198 <a href="/help/filesets">
1199 filesets
1199 filesets
1200 </a>
1200 </a>
1201 </td><td>
1201 </td><td>
1202 Specifying File Sets
1202 Specifying File Sets
1203 </td></tr>
1203 </td></tr>
1204 <tr><td>
1204 <tr><td>
1205 <a href="/help/glossary">
1205 <a href="/help/glossary">
1206 glossary
1206 glossary
1207 </a>
1207 </a>
1208 </td><td>
1208 </td><td>
1209 Glossary
1209 Glossary
1210 </td></tr>
1210 </td></tr>
1211 <tr><td>
1211 <tr><td>
1212 <a href="/help/hgignore">
1212 <a href="/help/hgignore">
1213 hgignore
1213 hgignore
1214 </a>
1214 </a>
1215 </td><td>
1215 </td><td>
1216 Syntax for Mercurial Ignore Files
1216 Syntax for Mercurial Ignore Files
1217 </td></tr>
1217 </td></tr>
1218 <tr><td>
1218 <tr><td>
1219 <a href="/help/hgweb">
1219 <a href="/help/hgweb">
1220 hgweb
1220 hgweb
1221 </a>
1221 </a>
1222 </td><td>
1222 </td><td>
1223 Configuring hgweb
1223 Configuring hgweb
1224 </td></tr>
1224 </td></tr>
1225 <tr><td>
1225 <tr><td>
1226 <a href="/help/merge-tools">
1226 <a href="/help/merge-tools">
1227 merge-tools
1227 merge-tools
1228 </a>
1228 </a>
1229 </td><td>
1229 </td><td>
1230 Merge Tools
1230 Merge Tools
1231 </td></tr>
1231 </td></tr>
1232 <tr><td>
1232 <tr><td>
1233 <a href="/help/multirevs">
1233 <a href="/help/multirevs">
1234 multirevs
1234 multirevs
1235 </a>
1235 </a>
1236 </td><td>
1236 </td><td>
1237 Specifying Multiple Revisions
1237 Specifying Multiple Revisions
1238 </td></tr>
1238 </td></tr>
1239 <tr><td>
1239 <tr><td>
1240 <a href="/help/patterns">
1240 <a href="/help/patterns">
1241 patterns
1241 patterns
1242 </a>
1242 </a>
1243 </td><td>
1243 </td><td>
1244 File Name Patterns
1244 File Name Patterns
1245 </td></tr>
1245 </td></tr>
1246 <tr><td>
1246 <tr><td>
1247 <a href="/help/phases">
1247 <a href="/help/phases">
1248 phases
1248 phases
1249 </a>
1249 </a>
1250 </td><td>
1250 </td><td>
1251 Working with Phases
1251 Working with Phases
1252 </td></tr>
1252 </td></tr>
1253 <tr><td>
1253 <tr><td>
1254 <a href="/help/revisions">
1254 <a href="/help/revisions">
1255 revisions
1255 revisions
1256 </a>
1256 </a>
1257 </td><td>
1257 </td><td>
1258 Specifying Single Revisions
1258 Specifying Single Revisions
1259 </td></tr>
1259 </td></tr>
1260 <tr><td>
1260 <tr><td>
1261 <a href="/help/revsets">
1261 <a href="/help/revsets">
1262 revsets
1262 revsets
1263 </a>
1263 </a>
1264 </td><td>
1264 </td><td>
1265 Specifying Revision Sets
1265 Specifying Revision Sets
1266 </td></tr>
1266 </td></tr>
1267 <tr><td>
1267 <tr><td>
1268 <a href="/help/subrepos">
1268 <a href="/help/subrepos">
1269 subrepos
1269 subrepos
1270 </a>
1270 </a>
1271 </td><td>
1271 </td><td>
1272 Subrepositories
1272 Subrepositories
1273 </td></tr>
1273 </td></tr>
1274 <tr><td>
1274 <tr><td>
1275 <a href="/help/templating">
1275 <a href="/help/templating">
1276 templating
1276 templating
1277 </a>
1277 </a>
1278 </td><td>
1278 </td><td>
1279 Template Usage
1279 Template Usage
1280 </td></tr>
1280 </td></tr>
1281 <tr><td>
1281 <tr><td>
1282 <a href="/help/urls">
1282 <a href="/help/urls">
1283 urls
1283 urls
1284 </a>
1284 </a>
1285 </td><td>
1285 </td><td>
1286 URL Paths
1286 URL Paths
1287 </td></tr>
1287 </td></tr>
1288 <tr><td>
1288 <tr><td>
1289 <a href="/help/topic-containing-verbose">
1289 <a href="/help/topic-containing-verbose">
1290 topic-containing-verbose
1290 topic-containing-verbose
1291 </a>
1291 </a>
1292 </td><td>
1292 </td><td>
1293 This is the topic to test omit indicating.
1293 This is the topic to test omit indicating.
1294 </td></tr>
1294 </td></tr>
1295
1295
1296 <tr><td colspan="2"><h2><a name="main" href="#main">Main Commands</a></h2></td></tr>
1296 <tr><td colspan="2"><h2><a name="main" href="#main">Main Commands</a></h2></td></tr>
1297
1297
1298 <tr><td>
1298 <tr><td>
1299 <a href="/help/add">
1299 <a href="/help/add">
1300 add
1300 add
1301 </a>
1301 </a>
1302 </td><td>
1302 </td><td>
1303 add the specified files on the next commit
1303 add the specified files on the next commit
1304 </td></tr>
1304 </td></tr>
1305 <tr><td>
1305 <tr><td>
1306 <a href="/help/annotate">
1306 <a href="/help/annotate">
1307 annotate
1307 annotate
1308 </a>
1308 </a>
1309 </td><td>
1309 </td><td>
1310 show changeset information by line for each file
1310 show changeset information by line for each file
1311 </td></tr>
1311 </td></tr>
1312 <tr><td>
1312 <tr><td>
1313 <a href="/help/clone">
1313 <a href="/help/clone">
1314 clone
1314 clone
1315 </a>
1315 </a>
1316 </td><td>
1316 </td><td>
1317 make a copy of an existing repository
1317 make a copy of an existing repository
1318 </td></tr>
1318 </td></tr>
1319 <tr><td>
1319 <tr><td>
1320 <a href="/help/commit">
1320 <a href="/help/commit">
1321 commit
1321 commit
1322 </a>
1322 </a>
1323 </td><td>
1323 </td><td>
1324 commit the specified files or all outstanding changes
1324 commit the specified files or all outstanding changes
1325 </td></tr>
1325 </td></tr>
1326 <tr><td>
1326 <tr><td>
1327 <a href="/help/diff">
1327 <a href="/help/diff">
1328 diff
1328 diff
1329 </a>
1329 </a>
1330 </td><td>
1330 </td><td>
1331 diff repository (or selected files)
1331 diff repository (or selected files)
1332 </td></tr>
1332 </td></tr>
1333 <tr><td>
1333 <tr><td>
1334 <a href="/help/export">
1334 <a href="/help/export">
1335 export
1335 export
1336 </a>
1336 </a>
1337 </td><td>
1337 </td><td>
1338 dump the header and diffs for one or more changesets
1338 dump the header and diffs for one or more changesets
1339 </td></tr>
1339 </td></tr>
1340 <tr><td>
1340 <tr><td>
1341 <a href="/help/forget">
1341 <a href="/help/forget">
1342 forget
1342 forget
1343 </a>
1343 </a>
1344 </td><td>
1344 </td><td>
1345 forget the specified files on the next commit
1345 forget the specified files on the next commit
1346 </td></tr>
1346 </td></tr>
1347 <tr><td>
1347 <tr><td>
1348 <a href="/help/init">
1348 <a href="/help/init">
1349 init
1349 init
1350 </a>
1350 </a>
1351 </td><td>
1351 </td><td>
1352 create a new repository in the given directory
1352 create a new repository in the given directory
1353 </td></tr>
1353 </td></tr>
1354 <tr><td>
1354 <tr><td>
1355 <a href="/help/log">
1355 <a href="/help/log">
1356 log
1356 log
1357 </a>
1357 </a>
1358 </td><td>
1358 </td><td>
1359 show revision history of entire repository or files
1359 show revision history of entire repository or files
1360 </td></tr>
1360 </td></tr>
1361 <tr><td>
1361 <tr><td>
1362 <a href="/help/merge">
1362 <a href="/help/merge">
1363 merge
1363 merge
1364 </a>
1364 </a>
1365 </td><td>
1365 </td><td>
1366 merge working directory with another revision
1366 merge working directory with another revision
1367 </td></tr>
1367 </td></tr>
1368 <tr><td>
1368 <tr><td>
1369 <a href="/help/pull">
1369 <a href="/help/pull">
1370 pull
1370 pull
1371 </a>
1371 </a>
1372 </td><td>
1372 </td><td>
1373 pull changes from the specified source
1373 pull changes from the specified source
1374 </td></tr>
1374 </td></tr>
1375 <tr><td>
1375 <tr><td>
1376 <a href="/help/push">
1376 <a href="/help/push">
1377 push
1377 push
1378 </a>
1378 </a>
1379 </td><td>
1379 </td><td>
1380 push changes to the specified destination
1380 push changes to the specified destination
1381 </td></tr>
1381 </td></tr>
1382 <tr><td>
1382 <tr><td>
1383 <a href="/help/remove">
1383 <a href="/help/remove">
1384 remove
1384 remove
1385 </a>
1385 </a>
1386 </td><td>
1386 </td><td>
1387 remove the specified files on the next commit
1387 remove the specified files on the next commit
1388 </td></tr>
1388 </td></tr>
1389 <tr><td>
1389 <tr><td>
1390 <a href="/help/serve">
1390 <a href="/help/serve">
1391 serve
1391 serve
1392 </a>
1392 </a>
1393 </td><td>
1393 </td><td>
1394 start stand-alone webserver
1394 start stand-alone webserver
1395 </td></tr>
1395 </td></tr>
1396 <tr><td>
1396 <tr><td>
1397 <a href="/help/status">
1397 <a href="/help/status">
1398 status
1398 status
1399 </a>
1399 </a>
1400 </td><td>
1400 </td><td>
1401 show changed files in the working directory
1401 show changed files in the working directory
1402 </td></tr>
1402 </td></tr>
1403 <tr><td>
1403 <tr><td>
1404 <a href="/help/summary">
1404 <a href="/help/summary">
1405 summary
1405 summary
1406 </a>
1406 </a>
1407 </td><td>
1407 </td><td>
1408 summarize working directory state
1408 summarize working directory state
1409 </td></tr>
1409 </td></tr>
1410 <tr><td>
1410 <tr><td>
1411 <a href="/help/update">
1411 <a href="/help/update">
1412 update
1412 update
1413 </a>
1413 </a>
1414 </td><td>
1414 </td><td>
1415 update working directory (or switch revisions)
1415 update working directory (or switch revisions)
1416 </td></tr>
1416 </td></tr>
1417
1417
1418 <tr><td colspan="2"><h2><a name="other" href="#other">Other Commands</a></h2></td></tr>
1418 <tr><td colspan="2"><h2><a name="other" href="#other">Other Commands</a></h2></td></tr>
1419
1419
1420 <tr><td>
1420 <tr><td>
1421 <a href="/help/addremove">
1421 <a href="/help/addremove">
1422 addremove
1422 addremove
1423 </a>
1423 </a>
1424 </td><td>
1424 </td><td>
1425 add all new files, delete all missing files
1425 add all new files, delete all missing files
1426 </td></tr>
1426 </td></tr>
1427 <tr><td>
1427 <tr><td>
1428 <a href="/help/archive">
1428 <a href="/help/archive">
1429 archive
1429 archive
1430 </a>
1430 </a>
1431 </td><td>
1431 </td><td>
1432 create an unversioned archive of a repository revision
1432 create an unversioned archive of a repository revision
1433 </td></tr>
1433 </td></tr>
1434 <tr><td>
1434 <tr><td>
1435 <a href="/help/backout">
1435 <a href="/help/backout">
1436 backout
1436 backout
1437 </a>
1437 </a>
1438 </td><td>
1438 </td><td>
1439 reverse effect of earlier changeset
1439 reverse effect of earlier changeset
1440 </td></tr>
1440 </td></tr>
1441 <tr><td>
1441 <tr><td>
1442 <a href="/help/bisect">
1442 <a href="/help/bisect">
1443 bisect
1443 bisect
1444 </a>
1444 </a>
1445 </td><td>
1445 </td><td>
1446 subdivision search of changesets
1446 subdivision search of changesets
1447 </td></tr>
1447 </td></tr>
1448 <tr><td>
1448 <tr><td>
1449 <a href="/help/bookmarks">
1449 <a href="/help/bookmarks">
1450 bookmarks
1450 bookmarks
1451 </a>
1451 </a>
1452 </td><td>
1452 </td><td>
1453 create a new bookmark or list existing bookmarks
1453 create a new bookmark or list existing bookmarks
1454 </td></tr>
1454 </td></tr>
1455 <tr><td>
1455 <tr><td>
1456 <a href="/help/branch">
1456 <a href="/help/branch">
1457 branch
1457 branch
1458 </a>
1458 </a>
1459 </td><td>
1459 </td><td>
1460 set or show the current branch name
1460 set or show the current branch name
1461 </td></tr>
1461 </td></tr>
1462 <tr><td>
1462 <tr><td>
1463 <a href="/help/branches">
1463 <a href="/help/branches">
1464 branches
1464 branches
1465 </a>
1465 </a>
1466 </td><td>
1466 </td><td>
1467 list repository named branches
1467 list repository named branches
1468 </td></tr>
1468 </td></tr>
1469 <tr><td>
1469 <tr><td>
1470 <a href="/help/bundle">
1470 <a href="/help/bundle">
1471 bundle
1471 bundle
1472 </a>
1472 </a>
1473 </td><td>
1473 </td><td>
1474 create a changegroup file
1474 create a changegroup file
1475 </td></tr>
1475 </td></tr>
1476 <tr><td>
1476 <tr><td>
1477 <a href="/help/cat">
1477 <a href="/help/cat">
1478 cat
1478 cat
1479 </a>
1479 </a>
1480 </td><td>
1480 </td><td>
1481 output the current or given revision of files
1481 output the current or given revision of files
1482 </td></tr>
1482 </td></tr>
1483 <tr><td>
1483 <tr><td>
1484 <a href="/help/config">
1484 <a href="/help/config">
1485 config
1485 config
1486 </a>
1486 </a>
1487 </td><td>
1487 </td><td>
1488 show combined config settings from all hgrc files
1488 show combined config settings from all hgrc files
1489 </td></tr>
1489 </td></tr>
1490 <tr><td>
1490 <tr><td>
1491 <a href="/help/copy">
1491 <a href="/help/copy">
1492 copy
1492 copy
1493 </a>
1493 </a>
1494 </td><td>
1494 </td><td>
1495 mark files as copied for the next commit
1495 mark files as copied for the next commit
1496 </td></tr>
1496 </td></tr>
1497 <tr><td>
1497 <tr><td>
1498 <a href="/help/files">
1498 <a href="/help/files">
1499 files
1499 files
1500 </a>
1500 </a>
1501 </td><td>
1501 </td><td>
1502 list tracked files
1502 list tracked files
1503 </td></tr>
1503 </td></tr>
1504 <tr><td>
1504 <tr><td>
1505 <a href="/help/graft">
1505 <a href="/help/graft">
1506 graft
1506 graft
1507 </a>
1507 </a>
1508 </td><td>
1508 </td><td>
1509 copy changes from other branches onto the current branch
1509 copy changes from other branches onto the current branch
1510 </td></tr>
1510 </td></tr>
1511 <tr><td>
1511 <tr><td>
1512 <a href="/help/grep">
1512 <a href="/help/grep">
1513 grep
1513 grep
1514 </a>
1514 </a>
1515 </td><td>
1515 </td><td>
1516 search for a pattern in specified files and revisions
1516 search for a pattern in specified files and revisions
1517 </td></tr>
1517 </td></tr>
1518 <tr><td>
1518 <tr><td>
1519 <a href="/help/heads">
1519 <a href="/help/heads">
1520 heads
1520 heads
1521 </a>
1521 </a>
1522 </td><td>
1522 </td><td>
1523 show branch heads
1523 show branch heads
1524 </td></tr>
1524 </td></tr>
1525 <tr><td>
1525 <tr><td>
1526 <a href="/help/help">
1526 <a href="/help/help">
1527 help
1527 help
1528 </a>
1528 </a>
1529 </td><td>
1529 </td><td>
1530 show help for a given topic or a help overview
1530 show help for a given topic or a help overview
1531 </td></tr>
1531 </td></tr>
1532 <tr><td>
1532 <tr><td>
1533 <a href="/help/identify">
1533 <a href="/help/identify">
1534 identify
1534 identify
1535 </a>
1535 </a>
1536 </td><td>
1536 </td><td>
1537 identify the working copy or specified revision
1537 identify the working copy or specified revision
1538 </td></tr>
1538 </td></tr>
1539 <tr><td>
1539 <tr><td>
1540 <a href="/help/import">
1540 <a href="/help/import">
1541 import
1541 import
1542 </a>
1542 </a>
1543 </td><td>
1543 </td><td>
1544 import an ordered set of patches
1544 import an ordered set of patches
1545 </td></tr>
1545 </td></tr>
1546 <tr><td>
1546 <tr><td>
1547 <a href="/help/incoming">
1547 <a href="/help/incoming">
1548 incoming
1548 incoming
1549 </a>
1549 </a>
1550 </td><td>
1550 </td><td>
1551 show new changesets found in source
1551 show new changesets found in source
1552 </td></tr>
1552 </td></tr>
1553 <tr><td>
1553 <tr><td>
1554 <a href="/help/manifest">
1554 <a href="/help/manifest">
1555 manifest
1555 manifest
1556 </a>
1556 </a>
1557 </td><td>
1557 </td><td>
1558 output the current or given revision of the project manifest
1558 output the current or given revision of the project manifest
1559 </td></tr>
1559 </td></tr>
1560 <tr><td>
1560 <tr><td>
1561 <a href="/help/nohelp">
1561 <a href="/help/nohelp">
1562 nohelp
1562 nohelp
1563 </a>
1563 </a>
1564 </td><td>
1564 </td><td>
1565 (no help text available)
1565 (no help text available)
1566 </td></tr>
1566 </td></tr>
1567 <tr><td>
1567 <tr><td>
1568 <a href="/help/outgoing">
1568 <a href="/help/outgoing">
1569 outgoing
1569 outgoing
1570 </a>
1570 </a>
1571 </td><td>
1571 </td><td>
1572 show changesets not found in the destination
1572 show changesets not found in the destination
1573 </td></tr>
1573 </td></tr>
1574 <tr><td>
1574 <tr><td>
1575 <a href="/help/paths">
1575 <a href="/help/paths">
1576 paths
1576 paths
1577 </a>
1577 </a>
1578 </td><td>
1578 </td><td>
1579 show aliases for remote repositories
1579 show aliases for remote repositories
1580 </td></tr>
1580 </td></tr>
1581 <tr><td>
1581 <tr><td>
1582 <a href="/help/phase">
1582 <a href="/help/phase">
1583 phase
1583 phase
1584 </a>
1584 </a>
1585 </td><td>
1585 </td><td>
1586 set or show the current phase name
1586 set or show the current phase name
1587 </td></tr>
1587 </td></tr>
1588 <tr><td>
1588 <tr><td>
1589 <a href="/help/recover">
1589 <a href="/help/recover">
1590 recover
1590 recover
1591 </a>
1591 </a>
1592 </td><td>
1592 </td><td>
1593 roll back an interrupted transaction
1593 roll back an interrupted transaction
1594 </td></tr>
1594 </td></tr>
1595 <tr><td>
1595 <tr><td>
1596 <a href="/help/rename">
1596 <a href="/help/rename">
1597 rename
1597 rename
1598 </a>
1598 </a>
1599 </td><td>
1599 </td><td>
1600 rename files; equivalent of copy + remove
1600 rename files; equivalent of copy + remove
1601 </td></tr>
1601 </td></tr>
1602 <tr><td>
1602 <tr><td>
1603 <a href="/help/resolve">
1603 <a href="/help/resolve">
1604 resolve
1604 resolve
1605 </a>
1605 </a>
1606 </td><td>
1606 </td><td>
1607 redo merges or set/view the merge status of files
1607 redo merges or set/view the merge status of files
1608 </td></tr>
1608 </td></tr>
1609 <tr><td>
1609 <tr><td>
1610 <a href="/help/revert">
1610 <a href="/help/revert">
1611 revert
1611 revert
1612 </a>
1612 </a>
1613 </td><td>
1613 </td><td>
1614 restore files to their checkout state
1614 restore files to their checkout state
1615 </td></tr>
1615 </td></tr>
1616 <tr><td>
1616 <tr><td>
1617 <a href="/help/root">
1617 <a href="/help/root">
1618 root
1618 root
1619 </a>
1619 </a>
1620 </td><td>
1620 </td><td>
1621 print the root (top) of the current working directory
1621 print the root (top) of the current working directory
1622 </td></tr>
1622 </td></tr>
1623 <tr><td>
1623 <tr><td>
1624 <a href="/help/tag">
1624 <a href="/help/tag">
1625 tag
1625 tag
1626 </a>
1626 </a>
1627 </td><td>
1627 </td><td>
1628 add one or more tags for the current or given revision
1628 add one or more tags for the current or given revision
1629 </td></tr>
1629 </td></tr>
1630 <tr><td>
1630 <tr><td>
1631 <a href="/help/tags">
1631 <a href="/help/tags">
1632 tags
1632 tags
1633 </a>
1633 </a>
1634 </td><td>
1634 </td><td>
1635 list repository tags
1635 list repository tags
1636 </td></tr>
1636 </td></tr>
1637 <tr><td>
1637 <tr><td>
1638 <a href="/help/unbundle">
1638 <a href="/help/unbundle">
1639 unbundle
1639 unbundle
1640 </a>
1640 </a>
1641 </td><td>
1641 </td><td>
1642 apply one or more changegroup files
1642 apply one or more changegroup files
1643 </td></tr>
1643 </td></tr>
1644 <tr><td>
1644 <tr><td>
1645 <a href="/help/verify">
1645 <a href="/help/verify">
1646 verify
1646 verify
1647 </a>
1647 </a>
1648 </td><td>
1648 </td><td>
1649 verify the integrity of the repository
1649 verify the integrity of the repository
1650 </td></tr>
1650 </td></tr>
1651 <tr><td>
1651 <tr><td>
1652 <a href="/help/version">
1652 <a href="/help/version">
1653 version
1653 version
1654 </a>
1654 </a>
1655 </td><td>
1655 </td><td>
1656 output version and copyright information
1656 output version and copyright information
1657 </td></tr>
1657 </td></tr>
1658 </table>
1658 </table>
1659 </div>
1659 </div>
1660 </div>
1660 </div>
1661
1661
1662 <script type="text/javascript">process_dates()</script>
1662 <script type="text/javascript">process_dates()</script>
1663
1663
1664
1664
1665 </body>
1665 </body>
1666 </html>
1666 </html>
1667
1667
1668
1668
1669 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help/add"
1669 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help/add"
1670 200 Script output follows
1670 200 Script output follows
1671
1671
1672 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1672 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1673 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1673 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1674 <head>
1674 <head>
1675 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1675 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1676 <meta name="robots" content="index, nofollow" />
1676 <meta name="robots" content="index, nofollow" />
1677 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1677 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1678 <script type="text/javascript" src="/static/mercurial.js"></script>
1678 <script type="text/javascript" src="/static/mercurial.js"></script>
1679
1679
1680 <title>Help: add</title>
1680 <title>Help: add</title>
1681 </head>
1681 </head>
1682 <body>
1682 <body>
1683
1683
1684 <div class="container">
1684 <div class="container">
1685 <div class="menu">
1685 <div class="menu">
1686 <div class="logo">
1686 <div class="logo">
1687 <a href="http://mercurial.selenic.com/">
1687 <a href="http://mercurial.selenic.com/">
1688 <img src="/static/hglogo.png" alt="mercurial" /></a>
1688 <img src="/static/hglogo.png" alt="mercurial" /></a>
1689 </div>
1689 </div>
1690 <ul>
1690 <ul>
1691 <li><a href="/shortlog">log</a></li>
1691 <li><a href="/shortlog">log</a></li>
1692 <li><a href="/graph">graph</a></li>
1692 <li><a href="/graph">graph</a></li>
1693 <li><a href="/tags">tags</a></li>
1693 <li><a href="/tags">tags</a></li>
1694 <li><a href="/bookmarks">bookmarks</a></li>
1694 <li><a href="/bookmarks">bookmarks</a></li>
1695 <li><a href="/branches">branches</a></li>
1695 <li><a href="/branches">branches</a></li>
1696 </ul>
1696 </ul>
1697 <ul>
1697 <ul>
1698 <li class="active"><a href="/help">help</a></li>
1698 <li class="active"><a href="/help">help</a></li>
1699 </ul>
1699 </ul>
1700 </div>
1700 </div>
1701
1701
1702 <div class="main">
1702 <div class="main">
1703 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1703 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1704 <h3>Help: add</h3>
1704 <h3>Help: add</h3>
1705
1705
1706 <form class="search" action="/log">
1706 <form class="search" action="/log">
1707
1707
1708 <p><input name="rev" id="search1" type="text" size="30" /></p>
1708 <p><input name="rev" id="search1" type="text" size="30" /></p>
1709 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1709 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1710 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1710 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1711 </form>
1711 </form>
1712 <div id="doc">
1712 <div id="doc">
1713 <p>
1713 <p>
1714 hg add [OPTION]... [FILE]...
1714 hg add [OPTION]... [FILE]...
1715 </p>
1715 </p>
1716 <p>
1716 <p>
1717 add the specified files on the next commit
1717 add the specified files on the next commit
1718 </p>
1718 </p>
1719 <p>
1719 <p>
1720 Schedule files to be version controlled and added to the
1720 Schedule files to be version controlled and added to the
1721 repository.
1721 repository.
1722 </p>
1722 </p>
1723 <p>
1723 <p>
1724 The files will be added to the repository at the next commit. To
1724 The files will be added to the repository at the next commit. To
1725 undo an add before that, see &quot;hg forget&quot;.
1725 undo an add before that, see &quot;hg forget&quot;.
1726 </p>
1726 </p>
1727 <p>
1727 <p>
1728 If no names are given, add all files to the repository.
1728 If no names are given, add all files to the repository.
1729 </p>
1729 </p>
1730 <p>
1730 <p>
1731 An example showing how new (unknown) files are added
1731 An example showing how new (unknown) files are added
1732 automatically by &quot;hg add&quot;:
1732 automatically by &quot;hg add&quot;:
1733 </p>
1733 </p>
1734 <pre>
1734 <pre>
1735 \$ ls (re)
1735 \$ ls (re)
1736 foo.c
1736 foo.c
1737 \$ hg status (re)
1737 \$ hg status (re)
1738 ? foo.c
1738 ? foo.c
1739 \$ hg add (re)
1739 \$ hg add (re)
1740 adding foo.c
1740 adding foo.c
1741 \$ hg status (re)
1741 \$ hg status (re)
1742 A foo.c
1742 A foo.c
1743 </pre>
1743 </pre>
1744 <p>
1744 <p>
1745 Returns 0 if all files are successfully added.
1745 Returns 0 if all files are successfully added.
1746 </p>
1746 </p>
1747 <p>
1747 <p>
1748 options ([+] can be repeated):
1748 options ([+] can be repeated):
1749 </p>
1749 </p>
1750 <table>
1750 <table>
1751 <tr><td>-I</td>
1751 <tr><td>-I</td>
1752 <td>--include PATTERN [+]</td>
1752 <td>--include PATTERN [+]</td>
1753 <td>include names matching the given patterns</td></tr>
1753 <td>include names matching the given patterns</td></tr>
1754 <tr><td>-X</td>
1754 <tr><td>-X</td>
1755 <td>--exclude PATTERN [+]</td>
1755 <td>--exclude PATTERN [+]</td>
1756 <td>exclude names matching the given patterns</td></tr>
1756 <td>exclude names matching the given patterns</td></tr>
1757 <tr><td>-S</td>
1757 <tr><td>-S</td>
1758 <td>--subrepos</td>
1758 <td>--subrepos</td>
1759 <td>recurse into subrepositories</td></tr>
1759 <td>recurse into subrepositories</td></tr>
1760 <tr><td>-n</td>
1760 <tr><td>-n</td>
1761 <td>--dry-run</td>
1761 <td>--dry-run</td>
1762 <td>do not perform actions, just print output</td></tr>
1762 <td>do not perform actions, just print output</td></tr>
1763 </table>
1763 </table>
1764 <p>
1764 <p>
1765 global options ([+] can be repeated):
1765 global options ([+] can be repeated):
1766 </p>
1766 </p>
1767 <table>
1767 <table>
1768 <tr><td>-R</td>
1768 <tr><td>-R</td>
1769 <td>--repository REPO</td>
1769 <td>--repository REPO</td>
1770 <td>repository root directory or name of overlay bundle file</td></tr>
1770 <td>repository root directory or name of overlay bundle file</td></tr>
1771 <tr><td></td>
1771 <tr><td></td>
1772 <td>--cwd DIR</td>
1772 <td>--cwd DIR</td>
1773 <td>change working directory</td></tr>
1773 <td>change working directory</td></tr>
1774 <tr><td>-y</td>
1774 <tr><td>-y</td>
1775 <td>--noninteractive</td>
1775 <td>--noninteractive</td>
1776 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
1776 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
1777 <tr><td>-q</td>
1777 <tr><td>-q</td>
1778 <td>--quiet</td>
1778 <td>--quiet</td>
1779 <td>suppress output</td></tr>
1779 <td>suppress output</td></tr>
1780 <tr><td>-v</td>
1780 <tr><td>-v</td>
1781 <td>--verbose</td>
1781 <td>--verbose</td>
1782 <td>enable additional output</td></tr>
1782 <td>enable additional output</td></tr>
1783 <tr><td></td>
1783 <tr><td></td>
1784 <td>--config CONFIG [+]</td>
1784 <td>--config CONFIG [+]</td>
1785 <td>set/override config option (use 'section.name=value')</td></tr>
1785 <td>set/override config option (use 'section.name=value')</td></tr>
1786 <tr><td></td>
1786 <tr><td></td>
1787 <td>--debug</td>
1787 <td>--debug</td>
1788 <td>enable debugging output</td></tr>
1788 <td>enable debugging output</td></tr>
1789 <tr><td></td>
1789 <tr><td></td>
1790 <td>--debugger</td>
1790 <td>--debugger</td>
1791 <td>start debugger</td></tr>
1791 <td>start debugger</td></tr>
1792 <tr><td></td>
1792 <tr><td></td>
1793 <td>--encoding ENCODE</td>
1793 <td>--encoding ENCODE</td>
1794 <td>set the charset encoding (default: ascii)</td></tr>
1794 <td>set the charset encoding (default: ascii)</td></tr>
1795 <tr><td></td>
1795 <tr><td></td>
1796 <td>--encodingmode MODE</td>
1796 <td>--encodingmode MODE</td>
1797 <td>set the charset encoding mode (default: strict)</td></tr>
1797 <td>set the charset encoding mode (default: strict)</td></tr>
1798 <tr><td></td>
1798 <tr><td></td>
1799 <td>--traceback</td>
1799 <td>--traceback</td>
1800 <td>always print a traceback on exception</td></tr>
1800 <td>always print a traceback on exception</td></tr>
1801 <tr><td></td>
1801 <tr><td></td>
1802 <td>--time</td>
1802 <td>--time</td>
1803 <td>time how long the command takes</td></tr>
1803 <td>time how long the command takes</td></tr>
1804 <tr><td></td>
1804 <tr><td></td>
1805 <td>--profile</td>
1805 <td>--profile</td>
1806 <td>print command execution profile</td></tr>
1806 <td>print command execution profile</td></tr>
1807 <tr><td></td>
1807 <tr><td></td>
1808 <td>--version</td>
1808 <td>--version</td>
1809 <td>output version information and exit</td></tr>
1809 <td>output version information and exit</td></tr>
1810 <tr><td>-h</td>
1810 <tr><td>-h</td>
1811 <td>--help</td>
1811 <td>--help</td>
1812 <td>display help and exit</td></tr>
1812 <td>display help and exit</td></tr>
1813 <tr><td></td>
1813 <tr><td></td>
1814 <td>--hidden</td>
1814 <td>--hidden</td>
1815 <td>consider hidden changesets</td></tr>
1815 <td>consider hidden changesets</td></tr>
1816 </table>
1816 </table>
1817
1817
1818 </div>
1818 </div>
1819 </div>
1819 </div>
1820 </div>
1820 </div>
1821
1821
1822 <script type="text/javascript">process_dates()</script>
1822 <script type="text/javascript">process_dates()</script>
1823
1823
1824
1824
1825 </body>
1825 </body>
1826 </html>
1826 </html>
1827
1827
1828
1828
1829 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help/remove"
1829 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help/remove"
1830 200 Script output follows
1830 200 Script output follows
1831
1831
1832 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1832 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1833 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1833 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1834 <head>
1834 <head>
1835 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1835 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1836 <meta name="robots" content="index, nofollow" />
1836 <meta name="robots" content="index, nofollow" />
1837 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1837 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1838 <script type="text/javascript" src="/static/mercurial.js"></script>
1838 <script type="text/javascript" src="/static/mercurial.js"></script>
1839
1839
1840 <title>Help: remove</title>
1840 <title>Help: remove</title>
1841 </head>
1841 </head>
1842 <body>
1842 <body>
1843
1843
1844 <div class="container">
1844 <div class="container">
1845 <div class="menu">
1845 <div class="menu">
1846 <div class="logo">
1846 <div class="logo">
1847 <a href="http://mercurial.selenic.com/">
1847 <a href="http://mercurial.selenic.com/">
1848 <img src="/static/hglogo.png" alt="mercurial" /></a>
1848 <img src="/static/hglogo.png" alt="mercurial" /></a>
1849 </div>
1849 </div>
1850 <ul>
1850 <ul>
1851 <li><a href="/shortlog">log</a></li>
1851 <li><a href="/shortlog">log</a></li>
1852 <li><a href="/graph">graph</a></li>
1852 <li><a href="/graph">graph</a></li>
1853 <li><a href="/tags">tags</a></li>
1853 <li><a href="/tags">tags</a></li>
1854 <li><a href="/bookmarks">bookmarks</a></li>
1854 <li><a href="/bookmarks">bookmarks</a></li>
1855 <li><a href="/branches">branches</a></li>
1855 <li><a href="/branches">branches</a></li>
1856 </ul>
1856 </ul>
1857 <ul>
1857 <ul>
1858 <li class="active"><a href="/help">help</a></li>
1858 <li class="active"><a href="/help">help</a></li>
1859 </ul>
1859 </ul>
1860 </div>
1860 </div>
1861
1861
1862 <div class="main">
1862 <div class="main">
1863 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1863 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1864 <h3>Help: remove</h3>
1864 <h3>Help: remove</h3>
1865
1865
1866 <form class="search" action="/log">
1866 <form class="search" action="/log">
1867
1867
1868 <p><input name="rev" id="search1" type="text" size="30" /></p>
1868 <p><input name="rev" id="search1" type="text" size="30" /></p>
1869 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1869 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1870 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1870 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1871 </form>
1871 </form>
1872 <div id="doc">
1872 <div id="doc">
1873 <p>
1873 <p>
1874 hg remove [OPTION]... FILE...
1874 hg remove [OPTION]... FILE...
1875 </p>
1875 </p>
1876 <p>
1876 <p>
1877 aliases: rm
1877 aliases: rm
1878 </p>
1878 </p>
1879 <p>
1879 <p>
1880 remove the specified files on the next commit
1880 remove the specified files on the next commit
1881 </p>
1881 </p>
1882 <p>
1882 <p>
1883 Schedule the indicated files for removal from the current branch.
1883 Schedule the indicated files for removal from the current branch.
1884 </p>
1884 </p>
1885 <p>
1885 <p>
1886 This command schedules the files to be removed at the next commit.
1886 This command schedules the files to be removed at the next commit.
1887 To undo a remove before that, see &quot;hg revert&quot;. To undo added
1887 To undo a remove before that, see &quot;hg revert&quot;. To undo added
1888 files, see &quot;hg forget&quot;.
1888 files, see &quot;hg forget&quot;.
1889 </p>
1889 </p>
1890 <p>
1890 <p>
1891 -A/--after can be used to remove only files that have already
1891 -A/--after can be used to remove only files that have already
1892 been deleted, -f/--force can be used to force deletion, and -Af
1892 been deleted, -f/--force can be used to force deletion, and -Af
1893 can be used to remove files from the next revision without
1893 can be used to remove files from the next revision without
1894 deleting them from the working directory.
1894 deleting them from the working directory.
1895 </p>
1895 </p>
1896 <p>
1896 <p>
1897 The following table details the behavior of remove for different
1897 The following table details the behavior of remove for different
1898 file states (columns) and option combinations (rows). The file
1898 file states (columns) and option combinations (rows). The file
1899 states are Added [A], Clean [C], Modified [M] and Missing [!]
1899 states are Added [A], Clean [C], Modified [M] and Missing [!]
1900 (as reported by &quot;hg status&quot;). The actions are Warn, Remove
1900 (as reported by &quot;hg status&quot;). The actions are Warn, Remove
1901 (from branch) and Delete (from disk):
1901 (from branch) and Delete (from disk):
1902 </p>
1902 </p>
1903 <table>
1903 <table>
1904 <tr><td>opt/state</td>
1904 <tr><td>opt/state</td>
1905 <td>A</td>
1905 <td>A</td>
1906 <td>C</td>
1906 <td>C</td>
1907 <td>M</td>
1907 <td>M</td>
1908 <td>!</td></tr>
1908 <td>!</td></tr>
1909 <tr><td>none</td>
1909 <tr><td>none</td>
1910 <td>W</td>
1910 <td>W</td>
1911 <td>RD</td>
1911 <td>RD</td>
1912 <td>W</td>
1912 <td>W</td>
1913 <td>R</td></tr>
1913 <td>R</td></tr>
1914 <tr><td>-f</td>
1914 <tr><td>-f</td>
1915 <td>R</td>
1915 <td>R</td>
1916 <td>RD</td>
1916 <td>RD</td>
1917 <td>RD</td>
1917 <td>RD</td>
1918 <td>R</td></tr>
1918 <td>R</td></tr>
1919 <tr><td>-A</td>
1919 <tr><td>-A</td>
1920 <td>W</td>
1920 <td>W</td>
1921 <td>W</td>
1921 <td>W</td>
1922 <td>W</td>
1922 <td>W</td>
1923 <td>R</td></tr>
1923 <td>R</td></tr>
1924 <tr><td>-Af</td>
1924 <tr><td>-Af</td>
1925 <td>R</td>
1925 <td>R</td>
1926 <td>R</td>
1926 <td>R</td>
1927 <td>R</td>
1927 <td>R</td>
1928 <td>R</td></tr>
1928 <td>R</td></tr>
1929 </table>
1929 </table>
1930 <p>
1930 <p>
1931 Note that remove never deletes files in Added [A] state from the
1931 Note that remove never deletes files in Added [A] state from the
1932 working directory, not even if option --force is specified.
1932 working directory, not even if option --force is specified.
1933 </p>
1933 </p>
1934 <p>
1934 <p>
1935 Returns 0 on success, 1 if any warnings encountered.
1935 Returns 0 on success, 1 if any warnings encountered.
1936 </p>
1936 </p>
1937 <p>
1937 <p>
1938 options ([+] can be repeated):
1938 options ([+] can be repeated):
1939 </p>
1939 </p>
1940 <table>
1940 <table>
1941 <tr><td>-A</td>
1941 <tr><td>-A</td>
1942 <td>--after</td>
1942 <td>--after</td>
1943 <td>record delete for missing files</td></tr>
1943 <td>record delete for missing files</td></tr>
1944 <tr><td>-f</td>
1944 <tr><td>-f</td>
1945 <td>--force</td>
1945 <td>--force</td>
1946 <td>remove (and delete) file even if added or modified</td></tr>
1946 <td>remove (and delete) file even if added or modified</td></tr>
1947 <tr><td>-S</td>
1948 <td>--subrepos</td>
1949 <td>recurse into subrepositories</td></tr>
1947 <tr><td>-I</td>
1950 <tr><td>-I</td>
1948 <td>--include PATTERN [+]</td>
1951 <td>--include PATTERN [+]</td>
1949 <td>include names matching the given patterns</td></tr>
1952 <td>include names matching the given patterns</td></tr>
1950 <tr><td>-X</td>
1953 <tr><td>-X</td>
1951 <td>--exclude PATTERN [+]</td>
1954 <td>--exclude PATTERN [+]</td>
1952 <td>exclude names matching the given patterns</td></tr>
1955 <td>exclude names matching the given patterns</td></tr>
1953 </table>
1956 </table>
1954 <p>
1957 <p>
1955 global options ([+] can be repeated):
1958 global options ([+] can be repeated):
1956 </p>
1959 </p>
1957 <table>
1960 <table>
1958 <tr><td>-R</td>
1961 <tr><td>-R</td>
1959 <td>--repository REPO</td>
1962 <td>--repository REPO</td>
1960 <td>repository root directory or name of overlay bundle file</td></tr>
1963 <td>repository root directory or name of overlay bundle file</td></tr>
1961 <tr><td></td>
1964 <tr><td></td>
1962 <td>--cwd DIR</td>
1965 <td>--cwd DIR</td>
1963 <td>change working directory</td></tr>
1966 <td>change working directory</td></tr>
1964 <tr><td>-y</td>
1967 <tr><td>-y</td>
1965 <td>--noninteractive</td>
1968 <td>--noninteractive</td>
1966 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
1969 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
1967 <tr><td>-q</td>
1970 <tr><td>-q</td>
1968 <td>--quiet</td>
1971 <td>--quiet</td>
1969 <td>suppress output</td></tr>
1972 <td>suppress output</td></tr>
1970 <tr><td>-v</td>
1973 <tr><td>-v</td>
1971 <td>--verbose</td>
1974 <td>--verbose</td>
1972 <td>enable additional output</td></tr>
1975 <td>enable additional output</td></tr>
1973 <tr><td></td>
1976 <tr><td></td>
1974 <td>--config CONFIG [+]</td>
1977 <td>--config CONFIG [+]</td>
1975 <td>set/override config option (use 'section.name=value')</td></tr>
1978 <td>set/override config option (use 'section.name=value')</td></tr>
1976 <tr><td></td>
1979 <tr><td></td>
1977 <td>--debug</td>
1980 <td>--debug</td>
1978 <td>enable debugging output</td></tr>
1981 <td>enable debugging output</td></tr>
1979 <tr><td></td>
1982 <tr><td></td>
1980 <td>--debugger</td>
1983 <td>--debugger</td>
1981 <td>start debugger</td></tr>
1984 <td>start debugger</td></tr>
1982 <tr><td></td>
1985 <tr><td></td>
1983 <td>--encoding ENCODE</td>
1986 <td>--encoding ENCODE</td>
1984 <td>set the charset encoding (default: ascii)</td></tr>
1987 <td>set the charset encoding (default: ascii)</td></tr>
1985 <tr><td></td>
1988 <tr><td></td>
1986 <td>--encodingmode MODE</td>
1989 <td>--encodingmode MODE</td>
1987 <td>set the charset encoding mode (default: strict)</td></tr>
1990 <td>set the charset encoding mode (default: strict)</td></tr>
1988 <tr><td></td>
1991 <tr><td></td>
1989 <td>--traceback</td>
1992 <td>--traceback</td>
1990 <td>always print a traceback on exception</td></tr>
1993 <td>always print a traceback on exception</td></tr>
1991 <tr><td></td>
1994 <tr><td></td>
1992 <td>--time</td>
1995 <td>--time</td>
1993 <td>time how long the command takes</td></tr>
1996 <td>time how long the command takes</td></tr>
1994 <tr><td></td>
1997 <tr><td></td>
1995 <td>--profile</td>
1998 <td>--profile</td>
1996 <td>print command execution profile</td></tr>
1999 <td>print command execution profile</td></tr>
1997 <tr><td></td>
2000 <tr><td></td>
1998 <td>--version</td>
2001 <td>--version</td>
1999 <td>output version information and exit</td></tr>
2002 <td>output version information and exit</td></tr>
2000 <tr><td>-h</td>
2003 <tr><td>-h</td>
2001 <td>--help</td>
2004 <td>--help</td>
2002 <td>display help and exit</td></tr>
2005 <td>display help and exit</td></tr>
2003 <tr><td></td>
2006 <tr><td></td>
2004 <td>--hidden</td>
2007 <td>--hidden</td>
2005 <td>consider hidden changesets</td></tr>
2008 <td>consider hidden changesets</td></tr>
2006 </table>
2009 </table>
2007
2010
2008 </div>
2011 </div>
2009 </div>
2012 </div>
2010 </div>
2013 </div>
2011
2014
2012 <script type="text/javascript">process_dates()</script>
2015 <script type="text/javascript">process_dates()</script>
2013
2016
2014
2017
2015 </body>
2018 </body>
2016 </html>
2019 </html>
2017
2020
2018
2021
2019 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help/revisions"
2022 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help/revisions"
2020 200 Script output follows
2023 200 Script output follows
2021
2024
2022 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2025 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2023 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2026 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2024 <head>
2027 <head>
2025 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2028 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2026 <meta name="robots" content="index, nofollow" />
2029 <meta name="robots" content="index, nofollow" />
2027 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2030 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2028 <script type="text/javascript" src="/static/mercurial.js"></script>
2031 <script type="text/javascript" src="/static/mercurial.js"></script>
2029
2032
2030 <title>Help: revisions</title>
2033 <title>Help: revisions</title>
2031 </head>
2034 </head>
2032 <body>
2035 <body>
2033
2036
2034 <div class="container">
2037 <div class="container">
2035 <div class="menu">
2038 <div class="menu">
2036 <div class="logo">
2039 <div class="logo">
2037 <a href="http://mercurial.selenic.com/">
2040 <a href="http://mercurial.selenic.com/">
2038 <img src="/static/hglogo.png" alt="mercurial" /></a>
2041 <img src="/static/hglogo.png" alt="mercurial" /></a>
2039 </div>
2042 </div>
2040 <ul>
2043 <ul>
2041 <li><a href="/shortlog">log</a></li>
2044 <li><a href="/shortlog">log</a></li>
2042 <li><a href="/graph">graph</a></li>
2045 <li><a href="/graph">graph</a></li>
2043 <li><a href="/tags">tags</a></li>
2046 <li><a href="/tags">tags</a></li>
2044 <li><a href="/bookmarks">bookmarks</a></li>
2047 <li><a href="/bookmarks">bookmarks</a></li>
2045 <li><a href="/branches">branches</a></li>
2048 <li><a href="/branches">branches</a></li>
2046 </ul>
2049 </ul>
2047 <ul>
2050 <ul>
2048 <li class="active"><a href="/help">help</a></li>
2051 <li class="active"><a href="/help">help</a></li>
2049 </ul>
2052 </ul>
2050 </div>
2053 </div>
2051
2054
2052 <div class="main">
2055 <div class="main">
2053 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2056 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2054 <h3>Help: revisions</h3>
2057 <h3>Help: revisions</h3>
2055
2058
2056 <form class="search" action="/log">
2059 <form class="search" action="/log">
2057
2060
2058 <p><input name="rev" id="search1" type="text" size="30" /></p>
2061 <p><input name="rev" id="search1" type="text" size="30" /></p>
2059 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2062 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2060 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2063 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2061 </form>
2064 </form>
2062 <div id="doc">
2065 <div id="doc">
2063 <h1>Specifying Single Revisions</h1>
2066 <h1>Specifying Single Revisions</h1>
2064 <p>
2067 <p>
2065 Mercurial supports several ways to specify individual revisions.
2068 Mercurial supports several ways to specify individual revisions.
2066 </p>
2069 </p>
2067 <p>
2070 <p>
2068 A plain integer is treated as a revision number. Negative integers are
2071 A plain integer is treated as a revision number. Negative integers are
2069 treated as sequential offsets from the tip, with -1 denoting the tip,
2072 treated as sequential offsets from the tip, with -1 denoting the tip,
2070 -2 denoting the revision prior to the tip, and so forth.
2073 -2 denoting the revision prior to the tip, and so forth.
2071 </p>
2074 </p>
2072 <p>
2075 <p>
2073 A 40-digit hexadecimal string is treated as a unique revision
2076 A 40-digit hexadecimal string is treated as a unique revision
2074 identifier.
2077 identifier.
2075 </p>
2078 </p>
2076 <p>
2079 <p>
2077 A hexadecimal string less than 40 characters long is treated as a
2080 A hexadecimal string less than 40 characters long is treated as a
2078 unique revision identifier and is referred to as a short-form
2081 unique revision identifier and is referred to as a short-form
2079 identifier. A short-form identifier is only valid if it is the prefix
2082 identifier. A short-form identifier is only valid if it is the prefix
2080 of exactly one full-length identifier.
2083 of exactly one full-length identifier.
2081 </p>
2084 </p>
2082 <p>
2085 <p>
2083 Any other string is treated as a bookmark, tag, or branch name. A
2086 Any other string is treated as a bookmark, tag, or branch name. A
2084 bookmark is a movable pointer to a revision. A tag is a permanent name
2087 bookmark is a movable pointer to a revision. A tag is a permanent name
2085 associated with a revision. A branch name denotes the tipmost open branch head
2088 associated with a revision. A branch name denotes the tipmost open branch head
2086 of that branch - or if they are all closed, the tipmost closed head of the
2089 of that branch - or if they are all closed, the tipmost closed head of the
2087 branch. Bookmark, tag, and branch names must not contain the &quot;:&quot; character.
2090 branch. Bookmark, tag, and branch names must not contain the &quot;:&quot; character.
2088 </p>
2091 </p>
2089 <p>
2092 <p>
2090 The reserved name &quot;tip&quot; always identifies the most recent revision.
2093 The reserved name &quot;tip&quot; always identifies the most recent revision.
2091 </p>
2094 </p>
2092 <p>
2095 <p>
2093 The reserved name &quot;null&quot; indicates the null revision. This is the
2096 The reserved name &quot;null&quot; indicates the null revision. This is the
2094 revision of an empty repository, and the parent of revision 0.
2097 revision of an empty repository, and the parent of revision 0.
2095 </p>
2098 </p>
2096 <p>
2099 <p>
2097 The reserved name &quot;.&quot; indicates the working directory parent. If no
2100 The reserved name &quot;.&quot; indicates the working directory parent. If no
2098 working directory is checked out, it is equivalent to null. If an
2101 working directory is checked out, it is equivalent to null. If an
2099 uncommitted merge is in progress, &quot;.&quot; is the revision of the first
2102 uncommitted merge is in progress, &quot;.&quot; is the revision of the first
2100 parent.
2103 parent.
2101 </p>
2104 </p>
2102
2105
2103 </div>
2106 </div>
2104 </div>
2107 </div>
2105 </div>
2108 </div>
2106
2109
2107 <script type="text/javascript">process_dates()</script>
2110 <script type="text/javascript">process_dates()</script>
2108
2111
2109
2112
2110 </body>
2113 </body>
2111 </html>
2114 </html>
2112
2115
2113
2116
2114 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
2117 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
2115
2118
2116 #endif
2119 #endif
@@ -1,264 +1,275 b''
1 Preparing the subrepository 'sub2'
1 Preparing the subrepository 'sub2'
2
2
3 $ hg init sub2
3 $ hg init sub2
4 $ echo sub2 > sub2/sub2
4 $ echo sub2 > sub2/sub2
5 $ hg add -R sub2
5 $ hg add -R sub2
6 adding sub2/sub2 (glob)
6 adding sub2/sub2 (glob)
7 $ hg commit -R sub2 -m "sub2 import"
7 $ hg commit -R sub2 -m "sub2 import"
8
8
9 Preparing the 'sub1' repo which depends on the subrepo 'sub2'
9 Preparing the 'sub1' repo which depends on the subrepo 'sub2'
10
10
11 $ hg init sub1
11 $ hg init sub1
12 $ echo sub1 > sub1/sub1
12 $ echo sub1 > sub1/sub1
13 $ echo "sub2 = ../sub2" > sub1/.hgsub
13 $ echo "sub2 = ../sub2" > sub1/.hgsub
14 $ hg clone sub2 sub1/sub2
14 $ hg clone sub2 sub1/sub2
15 updating to branch default
15 updating to branch default
16 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
16 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
17 $ hg add -R sub1
17 $ hg add -R sub1
18 adding sub1/.hgsub (glob)
18 adding sub1/.hgsub (glob)
19 adding sub1/sub1 (glob)
19 adding sub1/sub1 (glob)
20 $ hg commit -R sub1 -m "sub1 import"
20 $ hg commit -R sub1 -m "sub1 import"
21
21
22 Preparing the 'main' repo which depends on the subrepo 'sub1'
22 Preparing the 'main' repo which depends on the subrepo 'sub1'
23
23
24 $ hg init main
24 $ hg init main
25 $ echo main > main/main
25 $ echo main > main/main
26 $ echo "sub1 = ../sub1" > main/.hgsub
26 $ echo "sub1 = ../sub1" > main/.hgsub
27 $ hg clone sub1 main/sub1
27 $ hg clone sub1 main/sub1
28 updating to branch default
28 updating to branch default
29 cloning subrepo sub2 from $TESTTMP/sub2
29 cloning subrepo sub2 from $TESTTMP/sub2
30 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
30 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
31 $ hg add -R main
31 $ hg add -R main
32 adding main/.hgsub (glob)
32 adding main/.hgsub (glob)
33 adding main/main (glob)
33 adding main/main (glob)
34 $ hg commit -R main -m "main import"
34 $ hg commit -R main -m "main import"
35
35
36 Cleaning both repositories, just as a clone -U
36 Cleaning both repositories, just as a clone -U
37
37
38 $ hg up -C -R sub2 null
38 $ hg up -C -R sub2 null
39 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
39 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
40 $ hg up -C -R sub1 null
40 $ hg up -C -R sub1 null
41 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
41 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
42 $ hg up -C -R main null
42 $ hg up -C -R main null
43 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
43 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
44 $ rm -rf main/sub1
44 $ rm -rf main/sub1
45 $ rm -rf sub1/sub2
45 $ rm -rf sub1/sub2
46
46
47 Clone main
47 Clone main
48
48
49 $ hg clone main cloned
49 $ hg clone main cloned
50 updating to branch default
50 updating to branch default
51 cloning subrepo sub1 from $TESTTMP/sub1
51 cloning subrepo sub1 from $TESTTMP/sub1
52 cloning subrepo sub1/sub2 from $TESTTMP/sub2 (glob)
52 cloning subrepo sub1/sub2 from $TESTTMP/sub2 (glob)
53 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
53 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
54
54
55 Checking cloned repo ids
55 Checking cloned repo ids
56
56
57 $ printf "cloned " ; hg id -R cloned
57 $ printf "cloned " ; hg id -R cloned
58 cloned 7f491f53a367 tip
58 cloned 7f491f53a367 tip
59 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
59 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
60 cloned/sub1 fc3b4ce2696f tip
60 cloned/sub1 fc3b4ce2696f tip
61 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
61 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
62 cloned/sub1/sub2 c57a0840e3ba tip
62 cloned/sub1/sub2 c57a0840e3ba tip
63
63
64 debugsub output for main and sub1
64 debugsub output for main and sub1
65
65
66 $ hg debugsub -R cloned
66 $ hg debugsub -R cloned
67 path sub1
67 path sub1
68 source ../sub1
68 source ../sub1
69 revision fc3b4ce2696f7741438c79207583768f2ce6b0dd
69 revision fc3b4ce2696f7741438c79207583768f2ce6b0dd
70 $ hg debugsub -R cloned/sub1
70 $ hg debugsub -R cloned/sub1
71 path sub2
71 path sub2
72 source ../sub2
72 source ../sub2
73 revision c57a0840e3badd667ef3c3ef65471609acb2ba3c
73 revision c57a0840e3badd667ef3c3ef65471609acb2ba3c
74
74
75 Modifying deeply nested 'sub2'
75 Modifying deeply nested 'sub2'
76
76
77 $ echo modified > cloned/sub1/sub2/sub2
77 $ echo modified > cloned/sub1/sub2/sub2
78 $ hg commit --subrepos -m "deep nested modif should trigger a commit" -R cloned
78 $ hg commit --subrepos -m "deep nested modif should trigger a commit" -R cloned
79 committing subrepository sub1
79 committing subrepository sub1
80 committing subrepository sub1/sub2 (glob)
80 committing subrepository sub1/sub2 (glob)
81
81
82 Checking modified node ids
82 Checking modified node ids
83
83
84 $ printf "cloned " ; hg id -R cloned
84 $ printf "cloned " ; hg id -R cloned
85 cloned ffe6649062fe tip
85 cloned ffe6649062fe tip
86 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
86 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
87 cloned/sub1 2ecb03bf44a9 tip
87 cloned/sub1 2ecb03bf44a9 tip
88 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
88 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
89 cloned/sub1/sub2 53dd3430bcaf tip
89 cloned/sub1/sub2 53dd3430bcaf tip
90
90
91 debugsub output for main and sub1
91 debugsub output for main and sub1
92
92
93 $ hg debugsub -R cloned
93 $ hg debugsub -R cloned
94 path sub1
94 path sub1
95 source ../sub1
95 source ../sub1
96 revision 2ecb03bf44a94e749e8669481dd9069526ce7cb9
96 revision 2ecb03bf44a94e749e8669481dd9069526ce7cb9
97 $ hg debugsub -R cloned/sub1
97 $ hg debugsub -R cloned/sub1
98 path sub2
98 path sub2
99 source ../sub2
99 source ../sub2
100 revision 53dd3430bcaf5ab4a7c48262bcad6d441f510487
100 revision 53dd3430bcaf5ab4a7c48262bcad6d441f510487
101
101
102 Check that deep archiving works
102 Check that deep archiving works
103
103
104 $ cd cloned
104 $ cd cloned
105 $ echo 'test' > sub1/sub2/test.txt
105 $ echo 'test' > sub1/sub2/test.txt
106 $ hg --config extensions.largefiles=! add sub1/sub2/test.txt
106 $ hg --config extensions.largefiles=! add sub1/sub2/test.txt
107 $ mkdir sub1/sub2/folder
107 $ mkdir sub1/sub2/folder
108 $ echo 'subfolder' > sub1/sub2/folder/test.txt
108 $ echo 'subfolder' > sub1/sub2/folder/test.txt
109 $ hg --config extensions.largefiles=! add sub1/sub2/folder/test.txt
109 $ hg --config extensions.largefiles=! add sub1/sub2/folder/test.txt
110 $ hg ci -Sm "add test.txt"
110 $ hg ci -Sm "add test.txt"
111 committing subrepository sub1
111 committing subrepository sub1
112 committing subrepository sub1/sub2 (glob)
112 committing subrepository sub1/sub2 (glob)
113
114 .. but first take a detour through some deep removal testing
115
116 $ hg remove -S -I 're:.*.txt' sub1
117 removing sub1/sub2/folder/test.txt (glob)
118 removing sub1/sub2/test.txt (glob)
119 $ hg status -S
120 R sub1/sub2/folder/test.txt
121 R sub1/sub2/test.txt
122 $ hg update -Cq
123
113 $ hg --config extensions.largefiles=! archive -S ../archive_all
124 $ hg --config extensions.largefiles=! archive -S ../archive_all
114 $ find ../archive_all | sort
125 $ find ../archive_all | sort
115 ../archive_all
126 ../archive_all
116 ../archive_all/.hg_archival.txt
127 ../archive_all/.hg_archival.txt
117 ../archive_all/.hgsub
128 ../archive_all/.hgsub
118 ../archive_all/.hgsubstate
129 ../archive_all/.hgsubstate
119 ../archive_all/main
130 ../archive_all/main
120 ../archive_all/sub1
131 ../archive_all/sub1
121 ../archive_all/sub1/.hgsub
132 ../archive_all/sub1/.hgsub
122 ../archive_all/sub1/.hgsubstate
133 ../archive_all/sub1/.hgsubstate
123 ../archive_all/sub1/sub1
134 ../archive_all/sub1/sub1
124 ../archive_all/sub1/sub2
135 ../archive_all/sub1/sub2
125 ../archive_all/sub1/sub2/folder
136 ../archive_all/sub1/sub2/folder
126 ../archive_all/sub1/sub2/folder/test.txt
137 ../archive_all/sub1/sub2/folder/test.txt
127 ../archive_all/sub1/sub2/sub2
138 ../archive_all/sub1/sub2/sub2
128 ../archive_all/sub1/sub2/test.txt
139 ../archive_all/sub1/sub2/test.txt
129
140
130 Check that archive -X works in deep subrepos
141 Check that archive -X works in deep subrepos
131
142
132 $ hg --config extensions.largefiles=! archive -S -X '**test*' ../archive_exclude
143 $ hg --config extensions.largefiles=! archive -S -X '**test*' ../archive_exclude
133 $ find ../archive_exclude | sort
144 $ find ../archive_exclude | sort
134 ../archive_exclude
145 ../archive_exclude
135 ../archive_exclude/.hg_archival.txt
146 ../archive_exclude/.hg_archival.txt
136 ../archive_exclude/.hgsub
147 ../archive_exclude/.hgsub
137 ../archive_exclude/.hgsubstate
148 ../archive_exclude/.hgsubstate
138 ../archive_exclude/main
149 ../archive_exclude/main
139 ../archive_exclude/sub1
150 ../archive_exclude/sub1
140 ../archive_exclude/sub1/.hgsub
151 ../archive_exclude/sub1/.hgsub
141 ../archive_exclude/sub1/.hgsubstate
152 ../archive_exclude/sub1/.hgsubstate
142 ../archive_exclude/sub1/sub1
153 ../archive_exclude/sub1/sub1
143 ../archive_exclude/sub1/sub2
154 ../archive_exclude/sub1/sub2
144 ../archive_exclude/sub1/sub2/sub2
155 ../archive_exclude/sub1/sub2/sub2
145
156
146 $ hg --config extensions.largefiles=! archive -S -I '**test*' ../archive_include
157 $ hg --config extensions.largefiles=! archive -S -I '**test*' ../archive_include
147 $ find ../archive_include | sort
158 $ find ../archive_include | sort
148 ../archive_include
159 ../archive_include
149 ../archive_include/sub1
160 ../archive_include/sub1
150 ../archive_include/sub1/sub2
161 ../archive_include/sub1/sub2
151 ../archive_include/sub1/sub2/folder
162 ../archive_include/sub1/sub2/folder
152 ../archive_include/sub1/sub2/folder/test.txt
163 ../archive_include/sub1/sub2/folder/test.txt
153 ../archive_include/sub1/sub2/test.txt
164 ../archive_include/sub1/sub2/test.txt
154
165
155 Check that deep archive works with largefiles (which overrides hgsubrepo impl)
166 Check that deep archive works with largefiles (which overrides hgsubrepo impl)
156 This also tests the repo.ui regression in 43fb170a23bd, and that lf subrepo
167 This also tests the repo.ui regression in 43fb170a23bd, and that lf subrepo
157 subrepos are archived properly.
168 subrepos are archived properly.
158 Note that add --large through a subrepo currently adds the file as a normal file
169 Note that add --large through a subrepo currently adds the file as a normal file
159
170
160 $ echo "large" > sub1/sub2/large.bin
171 $ echo "large" > sub1/sub2/large.bin
161 $ hg --config extensions.largefiles= add --large -R sub1/sub2 sub1/sub2/large.bin
172 $ hg --config extensions.largefiles= add --large -R sub1/sub2 sub1/sub2/large.bin
162 $ echo "large" > large.bin
173 $ echo "large" > large.bin
163 $ hg --config extensions.largefiles= add --large large.bin
174 $ hg --config extensions.largefiles= add --large large.bin
164 $ hg --config extensions.largefiles= ci -S -m "add large files"
175 $ hg --config extensions.largefiles= ci -S -m "add large files"
165 committing subrepository sub1
176 committing subrepository sub1
166 committing subrepository sub1/sub2 (glob)
177 committing subrepository sub1/sub2 (glob)
167
178
168 $ hg --config extensions.largefiles= archive -S ../archive_lf
179 $ hg --config extensions.largefiles= archive -S ../archive_lf
169 $ find ../archive_lf | sort
180 $ find ../archive_lf | sort
170 ../archive_lf
181 ../archive_lf
171 ../archive_lf/.hg_archival.txt
182 ../archive_lf/.hg_archival.txt
172 ../archive_lf/.hgsub
183 ../archive_lf/.hgsub
173 ../archive_lf/.hgsubstate
184 ../archive_lf/.hgsubstate
174 ../archive_lf/large.bin
185 ../archive_lf/large.bin
175 ../archive_lf/main
186 ../archive_lf/main
176 ../archive_lf/sub1
187 ../archive_lf/sub1
177 ../archive_lf/sub1/.hgsub
188 ../archive_lf/sub1/.hgsub
178 ../archive_lf/sub1/.hgsubstate
189 ../archive_lf/sub1/.hgsubstate
179 ../archive_lf/sub1/sub1
190 ../archive_lf/sub1/sub1
180 ../archive_lf/sub1/sub2
191 ../archive_lf/sub1/sub2
181 ../archive_lf/sub1/sub2/folder
192 ../archive_lf/sub1/sub2/folder
182 ../archive_lf/sub1/sub2/folder/test.txt
193 ../archive_lf/sub1/sub2/folder/test.txt
183 ../archive_lf/sub1/sub2/large.bin
194 ../archive_lf/sub1/sub2/large.bin
184 ../archive_lf/sub1/sub2/sub2
195 ../archive_lf/sub1/sub2/sub2
185 ../archive_lf/sub1/sub2/test.txt
196 ../archive_lf/sub1/sub2/test.txt
186 $ rm -rf ../archive_lf
197 $ rm -rf ../archive_lf
187
198
188 Exclude large files from main and sub-sub repo
199 Exclude large files from main and sub-sub repo
189
200
190 $ hg --config extensions.largefiles= archive -S -X '**.bin' ../archive_lf
201 $ hg --config extensions.largefiles= archive -S -X '**.bin' ../archive_lf
191 $ find ../archive_lf | sort
202 $ find ../archive_lf | sort
192 ../archive_lf
203 ../archive_lf
193 ../archive_lf/.hg_archival.txt
204 ../archive_lf/.hg_archival.txt
194 ../archive_lf/.hgsub
205 ../archive_lf/.hgsub
195 ../archive_lf/.hgsubstate
206 ../archive_lf/.hgsubstate
196 ../archive_lf/main
207 ../archive_lf/main
197 ../archive_lf/sub1
208 ../archive_lf/sub1
198 ../archive_lf/sub1/.hgsub
209 ../archive_lf/sub1/.hgsub
199 ../archive_lf/sub1/.hgsubstate
210 ../archive_lf/sub1/.hgsubstate
200 ../archive_lf/sub1/sub1
211 ../archive_lf/sub1/sub1
201 ../archive_lf/sub1/sub2
212 ../archive_lf/sub1/sub2
202 ../archive_lf/sub1/sub2/folder
213 ../archive_lf/sub1/sub2/folder
203 ../archive_lf/sub1/sub2/folder/test.txt
214 ../archive_lf/sub1/sub2/folder/test.txt
204 ../archive_lf/sub1/sub2/sub2
215 ../archive_lf/sub1/sub2/sub2
205 ../archive_lf/sub1/sub2/test.txt
216 ../archive_lf/sub1/sub2/test.txt
206 $ rm -rf ../archive_lf
217 $ rm -rf ../archive_lf
207
218
208 Exclude normal files from main and sub-sub repo
219 Exclude normal files from main and sub-sub repo
209
220
210 $ hg --config extensions.largefiles= archive -S -X '**.txt' ../archive_lf
221 $ hg --config extensions.largefiles= archive -S -X '**.txt' ../archive_lf
211 $ find ../archive_lf | sort
222 $ find ../archive_lf | sort
212 ../archive_lf
223 ../archive_lf
213 ../archive_lf/.hgsub
224 ../archive_lf/.hgsub
214 ../archive_lf/.hgsubstate
225 ../archive_lf/.hgsubstate
215 ../archive_lf/large.bin
226 ../archive_lf/large.bin
216 ../archive_lf/main
227 ../archive_lf/main
217 ../archive_lf/sub1
228 ../archive_lf/sub1
218 ../archive_lf/sub1/.hgsub
229 ../archive_lf/sub1/.hgsub
219 ../archive_lf/sub1/.hgsubstate
230 ../archive_lf/sub1/.hgsubstate
220 ../archive_lf/sub1/sub1
231 ../archive_lf/sub1/sub1
221 ../archive_lf/sub1/sub2
232 ../archive_lf/sub1/sub2
222 ../archive_lf/sub1/sub2/large.bin
233 ../archive_lf/sub1/sub2/large.bin
223 ../archive_lf/sub1/sub2/sub2
234 ../archive_lf/sub1/sub2/sub2
224 $ rm -rf ../archive_lf
235 $ rm -rf ../archive_lf
225
236
226 Include normal files from within a largefiles subrepo
237 Include normal files from within a largefiles subrepo
227
238
228 $ hg --config extensions.largefiles= archive -S -I '**.txt' ../archive_lf
239 $ hg --config extensions.largefiles= archive -S -I '**.txt' ../archive_lf
229 $ find ../archive_lf | sort
240 $ find ../archive_lf | sort
230 ../archive_lf
241 ../archive_lf
231 ../archive_lf/.hg_archival.txt
242 ../archive_lf/.hg_archival.txt
232 ../archive_lf/sub1
243 ../archive_lf/sub1
233 ../archive_lf/sub1/sub2
244 ../archive_lf/sub1/sub2
234 ../archive_lf/sub1/sub2/folder
245 ../archive_lf/sub1/sub2/folder
235 ../archive_lf/sub1/sub2/folder/test.txt
246 ../archive_lf/sub1/sub2/folder/test.txt
236 ../archive_lf/sub1/sub2/test.txt
247 ../archive_lf/sub1/sub2/test.txt
237 $ rm -rf ../archive_lf
248 $ rm -rf ../archive_lf
238
249
239 Include large files from within a largefiles subrepo
250 Include large files from within a largefiles subrepo
240
251
241 $ hg --config extensions.largefiles= archive -S -I '**.bin' ../archive_lf
252 $ hg --config extensions.largefiles= archive -S -I '**.bin' ../archive_lf
242 $ find ../archive_lf | sort
253 $ find ../archive_lf | sort
243 ../archive_lf
254 ../archive_lf
244 ../archive_lf/large.bin
255 ../archive_lf/large.bin
245 ../archive_lf/sub1
256 ../archive_lf/sub1
246 ../archive_lf/sub1/sub2
257 ../archive_lf/sub1/sub2
247 ../archive_lf/sub1/sub2/large.bin
258 ../archive_lf/sub1/sub2/large.bin
248 $ rm -rf ../archive_lf
259 $ rm -rf ../archive_lf
249
260
250 Find an exact largefile match in a largefiles subrepo
261 Find an exact largefile match in a largefiles subrepo
251
262
252 $ hg --config extensions.largefiles= archive -S -I 'sub1/sub2/large.bin' ../archive_lf
263 $ hg --config extensions.largefiles= archive -S -I 'sub1/sub2/large.bin' ../archive_lf
253 $ find ../archive_lf | sort
264 $ find ../archive_lf | sort
254 ../archive_lf
265 ../archive_lf
255 ../archive_lf/sub1
266 ../archive_lf/sub1
256 ../archive_lf/sub1/sub2
267 ../archive_lf/sub1/sub2
257 ../archive_lf/sub1/sub2/large.bin
268 ../archive_lf/sub1/sub2/large.bin
258 $ rm -rf ../archive_lf
269 $ rm -rf ../archive_lf
259
270
260 Find an exact match to a standin (should archive nothing)
271 Find an exact match to a standin (should archive nothing)
261 $ hg --config extensions.largefiles= archive -S -I 'sub/sub2/.hglf/large.bin' ../archive_lf
272 $ hg --config extensions.largefiles= archive -S -I 'sub/sub2/.hglf/large.bin' ../archive_lf
262 $ find ../archive_lf 2> /dev/null | sort
273 $ find ../archive_lf 2> /dev/null | sort
263
274
264 $ cd ..
275 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now