##// END OF EJS Templates
files: split reusable implementation into cmdutil for subrepo support
Matt Harbison -
r24275:e1cb460a default
parent child Browse files
Show More
@@ -1,3141 +1,3159 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, cStringIO, shutil
10 import os, sys, errno, re, tempfile, cStringIO, shutil
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 dorecord(ui, repo, commitfunc, cmdsuggest, backupall, *pats, **opts):
22 def dorecord(ui, repo, commitfunc, cmdsuggest, backupall, *pats, **opts):
23 import merge as mergemod
23 import merge as mergemod
24 if not ui.interactive():
24 if not ui.interactive():
25 raise util.Abort(_('running non-interactively, use %s instead') %
25 raise util.Abort(_('running non-interactively, use %s instead') %
26 cmdsuggest)
26 cmdsuggest)
27
27
28 # make sure username is set before going interactive
28 # make sure username is set before going interactive
29 if not opts.get('user'):
29 if not opts.get('user'):
30 ui.username() # raise exception, username not provided
30 ui.username() # raise exception, username not provided
31
31
32 def recordfunc(ui, repo, message, match, opts):
32 def recordfunc(ui, repo, message, match, opts):
33 """This is generic record driver.
33 """This is generic record driver.
34
34
35 Its job is to interactively filter local changes, and
35 Its job is to interactively filter local changes, and
36 accordingly prepare working directory into a state in which the
36 accordingly prepare working directory into a state in which the
37 job can be delegated to a non-interactive commit command such as
37 job can be delegated to a non-interactive commit command such as
38 'commit' or 'qrefresh'.
38 'commit' or 'qrefresh'.
39
39
40 After the actual job is done by non-interactive command, the
40 After the actual job is done by non-interactive command, the
41 working directory is restored to its original state.
41 working directory is restored to its original state.
42
42
43 In the end we'll record interesting changes, and everything else
43 In the end we'll record interesting changes, and everything else
44 will be left in place, so the user can continue working.
44 will be left in place, so the user can continue working.
45 """
45 """
46
46
47 checkunfinished(repo, commit=True)
47 checkunfinished(repo, commit=True)
48 merge = len(repo[None].parents()) > 1
48 merge = len(repo[None].parents()) > 1
49 if merge:
49 if merge:
50 raise util.Abort(_('cannot partially commit a merge '
50 raise util.Abort(_('cannot partially commit a merge '
51 '(use "hg commit" instead)'))
51 '(use "hg commit" instead)'))
52
52
53 status = repo.status(match=match)
53 status = repo.status(match=match)
54 diffopts = patch.difffeatureopts(ui, opts=opts, whitespace=True)
54 diffopts = patch.difffeatureopts(ui, opts=opts, whitespace=True)
55 diffopts.nodates = True
55 diffopts.nodates = True
56 diffopts.git = True
56 diffopts.git = True
57 originalchunks = patch.diff(repo, changes=status, opts=diffopts)
57 originalchunks = patch.diff(repo, changes=status, opts=diffopts)
58 fp = cStringIO.StringIO()
58 fp = cStringIO.StringIO()
59 fp.write(''.join(originalchunks))
59 fp.write(''.join(originalchunks))
60 fp.seek(0)
60 fp.seek(0)
61
61
62 # 1. filter patch, so we have intending-to apply subset of it
62 # 1. filter patch, so we have intending-to apply subset of it
63 try:
63 try:
64 chunks = patch.filterpatch(ui, patch.parsepatch(fp))
64 chunks = patch.filterpatch(ui, patch.parsepatch(fp))
65 except patch.PatchError, err:
65 except patch.PatchError, err:
66 raise util.Abort(_('error parsing patch: %s') % err)
66 raise util.Abort(_('error parsing patch: %s') % err)
67
67
68 del fp
68 del fp
69
69
70 contenders = set()
70 contenders = set()
71 for h in chunks:
71 for h in chunks:
72 try:
72 try:
73 contenders.update(set(h.files()))
73 contenders.update(set(h.files()))
74 except AttributeError:
74 except AttributeError:
75 pass
75 pass
76
76
77 changed = status.modified + status.added + status.removed
77 changed = status.modified + status.added + status.removed
78 newfiles = [f for f in changed if f in contenders]
78 newfiles = [f for f in changed if f in contenders]
79 if not newfiles:
79 if not newfiles:
80 ui.status(_('no changes to record\n'))
80 ui.status(_('no changes to record\n'))
81 return 0
81 return 0
82
82
83 newandmodifiedfiles = set()
83 newandmodifiedfiles = set()
84 for h in chunks:
84 for h in chunks:
85 ishunk = isinstance(h, patch.recordhunk)
85 ishunk = isinstance(h, patch.recordhunk)
86 isnew = h.filename() in status.added
86 isnew = h.filename() in status.added
87 if ishunk and isnew and not h in originalchunks:
87 if ishunk and isnew and not h in originalchunks:
88 newandmodifiedfiles.add(h.filename())
88 newandmodifiedfiles.add(h.filename())
89
89
90 modified = set(status.modified)
90 modified = set(status.modified)
91
91
92 # 2. backup changed files, so we can restore them in the end
92 # 2. backup changed files, so we can restore them in the end
93
93
94 if backupall:
94 if backupall:
95 tobackup = changed
95 tobackup = changed
96 else:
96 else:
97 tobackup = [f for f in newfiles
97 tobackup = [f for f in newfiles
98 if f in modified or f in newandmodifiedfiles]
98 if f in modified or f in newandmodifiedfiles]
99
99
100 backups = {}
100 backups = {}
101 if tobackup:
101 if tobackup:
102 backupdir = repo.join('record-backups')
102 backupdir = repo.join('record-backups')
103 try:
103 try:
104 os.mkdir(backupdir)
104 os.mkdir(backupdir)
105 except OSError, err:
105 except OSError, err:
106 if err.errno != errno.EEXIST:
106 if err.errno != errno.EEXIST:
107 raise
107 raise
108 try:
108 try:
109 # backup continues
109 # backup continues
110 for f in tobackup:
110 for f in tobackup:
111 fd, tmpname = tempfile.mkstemp(prefix=f.replace('/', '_')+'.',
111 fd, tmpname = tempfile.mkstemp(prefix=f.replace('/', '_')+'.',
112 dir=backupdir)
112 dir=backupdir)
113 os.close(fd)
113 os.close(fd)
114 ui.debug('backup %r as %r\n' % (f, tmpname))
114 ui.debug('backup %r as %r\n' % (f, tmpname))
115 util.copyfile(repo.wjoin(f), tmpname)
115 util.copyfile(repo.wjoin(f), tmpname)
116 shutil.copystat(repo.wjoin(f), tmpname)
116 shutil.copystat(repo.wjoin(f), tmpname)
117 backups[f] = tmpname
117 backups[f] = tmpname
118
118
119 fp = cStringIO.StringIO()
119 fp = cStringIO.StringIO()
120 for c in chunks:
120 for c in chunks:
121 fname = c.filename()
121 fname = c.filename()
122 if fname in backups or fname in newandmodifiedfiles:
122 if fname in backups or fname in newandmodifiedfiles:
123 c.write(fp)
123 c.write(fp)
124 dopatch = fp.tell()
124 dopatch = fp.tell()
125 fp.seek(0)
125 fp.seek(0)
126
126
127 [os.unlink(c) for c in newandmodifiedfiles]
127 [os.unlink(c) for c in newandmodifiedfiles]
128
128
129 # 3a. apply filtered patch to clean repo (clean)
129 # 3a. apply filtered patch to clean repo (clean)
130 if backups:
130 if backups:
131 # Equivalent to hg.revert
131 # Equivalent to hg.revert
132 choices = lambda key: key in backups
132 choices = lambda key: key in backups
133 mergemod.update(repo, repo.dirstate.p1(),
133 mergemod.update(repo, repo.dirstate.p1(),
134 False, True, choices)
134 False, True, choices)
135
135
136
136
137 # 3b. (apply)
137 # 3b. (apply)
138 if dopatch:
138 if dopatch:
139 try:
139 try:
140 ui.debug('applying patch\n')
140 ui.debug('applying patch\n')
141 ui.debug(fp.getvalue())
141 ui.debug(fp.getvalue())
142 patch.internalpatch(ui, repo, fp, 1, eolmode=None)
142 patch.internalpatch(ui, repo, fp, 1, eolmode=None)
143 except patch.PatchError, err:
143 except patch.PatchError, err:
144 raise util.Abort(str(err))
144 raise util.Abort(str(err))
145 del fp
145 del fp
146
146
147 # 4. We prepared working directory according to filtered
147 # 4. We prepared working directory according to filtered
148 # patch. Now is the time to delegate the job to
148 # patch. Now is the time to delegate the job to
149 # commit/qrefresh or the like!
149 # commit/qrefresh or the like!
150
150
151 # Make all of the pathnames absolute.
151 # Make all of the pathnames absolute.
152 newfiles = [repo.wjoin(nf) for nf in newfiles]
152 newfiles = [repo.wjoin(nf) for nf in newfiles]
153 commitfunc(ui, repo, *newfiles, **opts)
153 commitfunc(ui, repo, *newfiles, **opts)
154
154
155 return 0
155 return 0
156 finally:
156 finally:
157 # 5. finally restore backed-up files
157 # 5. finally restore backed-up files
158 try:
158 try:
159 for realname, tmpname in backups.iteritems():
159 for realname, tmpname in backups.iteritems():
160 ui.debug('restoring %r to %r\n' % (tmpname, realname))
160 ui.debug('restoring %r to %r\n' % (tmpname, realname))
161 util.copyfile(tmpname, repo.wjoin(realname))
161 util.copyfile(tmpname, repo.wjoin(realname))
162 # Our calls to copystat() here and above are a
162 # Our calls to copystat() here and above are a
163 # hack to trick any editors that have f open that
163 # hack to trick any editors that have f open that
164 # we haven't modified them.
164 # we haven't modified them.
165 #
165 #
166 # Also note that this racy as an editor could
166 # Also note that this racy as an editor could
167 # notice the file's mtime before we've finished
167 # notice the file's mtime before we've finished
168 # writing it.
168 # writing it.
169 shutil.copystat(tmpname, repo.wjoin(realname))
169 shutil.copystat(tmpname, repo.wjoin(realname))
170 os.unlink(tmpname)
170 os.unlink(tmpname)
171 if tobackup:
171 if tobackup:
172 os.rmdir(backupdir)
172 os.rmdir(backupdir)
173 except OSError:
173 except OSError:
174 pass
174 pass
175
175
176 # wrap ui.write so diff output can be labeled/colorized
176 # wrap ui.write so diff output can be labeled/colorized
177 def wrapwrite(orig, *args, **kw):
177 def wrapwrite(orig, *args, **kw):
178 label = kw.pop('label', '')
178 label = kw.pop('label', '')
179 for chunk, l in patch.difflabel(lambda: args):
179 for chunk, l in patch.difflabel(lambda: args):
180 orig(chunk, label=label + l)
180 orig(chunk, label=label + l)
181
181
182 oldwrite = ui.write
182 oldwrite = ui.write
183 def wrap(*args, **kwargs):
183 def wrap(*args, **kwargs):
184 return wrapwrite(oldwrite, *args, **kwargs)
184 return wrapwrite(oldwrite, *args, **kwargs)
185 setattr(ui, 'write', wrap)
185 setattr(ui, 'write', wrap)
186
186
187 try:
187 try:
188 return commit(ui, repo, recordfunc, pats, opts)
188 return commit(ui, repo, recordfunc, pats, opts)
189 finally:
189 finally:
190 ui.write = oldwrite
190 ui.write = oldwrite
191
191
192
192
193 def findpossible(cmd, table, strict=False):
193 def findpossible(cmd, table, strict=False):
194 """
194 """
195 Return cmd -> (aliases, command table entry)
195 Return cmd -> (aliases, command table entry)
196 for each matching command.
196 for each matching command.
197 Return debug commands (or their aliases) only if no normal command matches.
197 Return debug commands (or their aliases) only if no normal command matches.
198 """
198 """
199 choice = {}
199 choice = {}
200 debugchoice = {}
200 debugchoice = {}
201
201
202 if cmd in table:
202 if cmd in table:
203 # short-circuit exact matches, "log" alias beats "^log|history"
203 # short-circuit exact matches, "log" alias beats "^log|history"
204 keys = [cmd]
204 keys = [cmd]
205 else:
205 else:
206 keys = table.keys()
206 keys = table.keys()
207
207
208 allcmds = []
208 allcmds = []
209 for e in keys:
209 for e in keys:
210 aliases = parsealiases(e)
210 aliases = parsealiases(e)
211 allcmds.extend(aliases)
211 allcmds.extend(aliases)
212 found = None
212 found = None
213 if cmd in aliases:
213 if cmd in aliases:
214 found = cmd
214 found = cmd
215 elif not strict:
215 elif not strict:
216 for a in aliases:
216 for a in aliases:
217 if a.startswith(cmd):
217 if a.startswith(cmd):
218 found = a
218 found = a
219 break
219 break
220 if found is not None:
220 if found is not None:
221 if aliases[0].startswith("debug") or found.startswith("debug"):
221 if aliases[0].startswith("debug") or found.startswith("debug"):
222 debugchoice[found] = (aliases, table[e])
222 debugchoice[found] = (aliases, table[e])
223 else:
223 else:
224 choice[found] = (aliases, table[e])
224 choice[found] = (aliases, table[e])
225
225
226 if not choice and debugchoice:
226 if not choice and debugchoice:
227 choice = debugchoice
227 choice = debugchoice
228
228
229 return choice, allcmds
229 return choice, allcmds
230
230
231 def findcmd(cmd, table, strict=True):
231 def findcmd(cmd, table, strict=True):
232 """Return (aliases, command table entry) for command string."""
232 """Return (aliases, command table entry) for command string."""
233 choice, allcmds = findpossible(cmd, table, strict)
233 choice, allcmds = findpossible(cmd, table, strict)
234
234
235 if cmd in choice:
235 if cmd in choice:
236 return choice[cmd]
236 return choice[cmd]
237
237
238 if len(choice) > 1:
238 if len(choice) > 1:
239 clist = choice.keys()
239 clist = choice.keys()
240 clist.sort()
240 clist.sort()
241 raise error.AmbiguousCommand(cmd, clist)
241 raise error.AmbiguousCommand(cmd, clist)
242
242
243 if choice:
243 if choice:
244 return choice.values()[0]
244 return choice.values()[0]
245
245
246 raise error.UnknownCommand(cmd, allcmds)
246 raise error.UnknownCommand(cmd, allcmds)
247
247
248 def findrepo(p):
248 def findrepo(p):
249 while not os.path.isdir(os.path.join(p, ".hg")):
249 while not os.path.isdir(os.path.join(p, ".hg")):
250 oldp, p = p, os.path.dirname(p)
250 oldp, p = p, os.path.dirname(p)
251 if p == oldp:
251 if p == oldp:
252 return None
252 return None
253
253
254 return p
254 return p
255
255
256 def bailifchanged(repo):
256 def bailifchanged(repo):
257 if repo.dirstate.p2() != nullid:
257 if repo.dirstate.p2() != nullid:
258 raise util.Abort(_('outstanding uncommitted merge'))
258 raise util.Abort(_('outstanding uncommitted merge'))
259 modified, added, removed, deleted = repo.status()[:4]
259 modified, added, removed, deleted = repo.status()[:4]
260 if modified or added or removed or deleted:
260 if modified or added or removed or deleted:
261 raise util.Abort(_('uncommitted changes'))
261 raise util.Abort(_('uncommitted changes'))
262 ctx = repo[None]
262 ctx = repo[None]
263 for s in sorted(ctx.substate):
263 for s in sorted(ctx.substate):
264 if ctx.sub(s).dirty():
264 if ctx.sub(s).dirty():
265 raise util.Abort(_("uncommitted changes in subrepo %s") % s)
265 raise util.Abort(_("uncommitted changes in subrepo %s") % s)
266
266
267 def logmessage(ui, opts):
267 def logmessage(ui, opts):
268 """ get the log message according to -m and -l option """
268 """ get the log message according to -m and -l option """
269 message = opts.get('message')
269 message = opts.get('message')
270 logfile = opts.get('logfile')
270 logfile = opts.get('logfile')
271
271
272 if message and logfile:
272 if message and logfile:
273 raise util.Abort(_('options --message and --logfile are mutually '
273 raise util.Abort(_('options --message and --logfile are mutually '
274 'exclusive'))
274 'exclusive'))
275 if not message and logfile:
275 if not message and logfile:
276 try:
276 try:
277 if logfile == '-':
277 if logfile == '-':
278 message = ui.fin.read()
278 message = ui.fin.read()
279 else:
279 else:
280 message = '\n'.join(util.readfile(logfile).splitlines())
280 message = '\n'.join(util.readfile(logfile).splitlines())
281 except IOError, inst:
281 except IOError, inst:
282 raise util.Abort(_("can't read commit message '%s': %s") %
282 raise util.Abort(_("can't read commit message '%s': %s") %
283 (logfile, inst.strerror))
283 (logfile, inst.strerror))
284 return message
284 return message
285
285
286 def mergeeditform(ctxorbool, baseformname):
286 def mergeeditform(ctxorbool, baseformname):
287 """return appropriate editform name (referencing a committemplate)
287 """return appropriate editform name (referencing a committemplate)
288
288
289 'ctxorbool' is either a ctx to be committed, or a bool indicating whether
289 'ctxorbool' is either a ctx to be committed, or a bool indicating whether
290 merging is committed.
290 merging is committed.
291
291
292 This returns baseformname with '.merge' appended if it is a merge,
292 This returns baseformname with '.merge' appended if it is a merge,
293 otherwise '.normal' is appended.
293 otherwise '.normal' is appended.
294 """
294 """
295 if isinstance(ctxorbool, bool):
295 if isinstance(ctxorbool, bool):
296 if ctxorbool:
296 if ctxorbool:
297 return baseformname + ".merge"
297 return baseformname + ".merge"
298 elif 1 < len(ctxorbool.parents()):
298 elif 1 < len(ctxorbool.parents()):
299 return baseformname + ".merge"
299 return baseformname + ".merge"
300
300
301 return baseformname + ".normal"
301 return baseformname + ".normal"
302
302
303 def getcommiteditor(edit=False, finishdesc=None, extramsg=None,
303 def getcommiteditor(edit=False, finishdesc=None, extramsg=None,
304 editform='', **opts):
304 editform='', **opts):
305 """get appropriate commit message editor according to '--edit' option
305 """get appropriate commit message editor according to '--edit' option
306
306
307 'finishdesc' is a function to be called with edited commit message
307 'finishdesc' is a function to be called with edited commit message
308 (= 'description' of the new changeset) just after editing, but
308 (= 'description' of the new changeset) just after editing, but
309 before checking empty-ness. It should return actual text to be
309 before checking empty-ness. It should return actual text to be
310 stored into history. This allows to change description before
310 stored into history. This allows to change description before
311 storing.
311 storing.
312
312
313 'extramsg' is a extra message to be shown in the editor instead of
313 'extramsg' is a extra message to be shown in the editor instead of
314 'Leave message empty to abort commit' line. 'HG: ' prefix and EOL
314 'Leave message empty to abort commit' line. 'HG: ' prefix and EOL
315 is automatically added.
315 is automatically added.
316
316
317 'editform' is a dot-separated list of names, to distinguish
317 'editform' is a dot-separated list of names, to distinguish
318 the purpose of commit text editing.
318 the purpose of commit text editing.
319
319
320 'getcommiteditor' returns 'commitforceeditor' regardless of
320 'getcommiteditor' returns 'commitforceeditor' regardless of
321 'edit', if one of 'finishdesc' or 'extramsg' is specified, because
321 'edit', if one of 'finishdesc' or 'extramsg' is specified, because
322 they are specific for usage in MQ.
322 they are specific for usage in MQ.
323 """
323 """
324 if edit or finishdesc or extramsg:
324 if edit or finishdesc or extramsg:
325 return lambda r, c, s: commitforceeditor(r, c, s,
325 return lambda r, c, s: commitforceeditor(r, c, s,
326 finishdesc=finishdesc,
326 finishdesc=finishdesc,
327 extramsg=extramsg,
327 extramsg=extramsg,
328 editform=editform)
328 editform=editform)
329 elif editform:
329 elif editform:
330 return lambda r, c, s: commiteditor(r, c, s, editform=editform)
330 return lambda r, c, s: commiteditor(r, c, s, editform=editform)
331 else:
331 else:
332 return commiteditor
332 return commiteditor
333
333
334 def loglimit(opts):
334 def loglimit(opts):
335 """get the log limit according to option -l/--limit"""
335 """get the log limit according to option -l/--limit"""
336 limit = opts.get('limit')
336 limit = opts.get('limit')
337 if limit:
337 if limit:
338 try:
338 try:
339 limit = int(limit)
339 limit = int(limit)
340 except ValueError:
340 except ValueError:
341 raise util.Abort(_('limit must be a positive integer'))
341 raise util.Abort(_('limit must be a positive integer'))
342 if limit <= 0:
342 if limit <= 0:
343 raise util.Abort(_('limit must be positive'))
343 raise util.Abort(_('limit must be positive'))
344 else:
344 else:
345 limit = None
345 limit = None
346 return limit
346 return limit
347
347
348 def makefilename(repo, pat, node, desc=None,
348 def makefilename(repo, pat, node, desc=None,
349 total=None, seqno=None, revwidth=None, pathname=None):
349 total=None, seqno=None, revwidth=None, pathname=None):
350 node_expander = {
350 node_expander = {
351 'H': lambda: hex(node),
351 'H': lambda: hex(node),
352 'R': lambda: str(repo.changelog.rev(node)),
352 'R': lambda: str(repo.changelog.rev(node)),
353 'h': lambda: short(node),
353 'h': lambda: short(node),
354 'm': lambda: re.sub('[^\w]', '_', str(desc))
354 'm': lambda: re.sub('[^\w]', '_', str(desc))
355 }
355 }
356 expander = {
356 expander = {
357 '%': lambda: '%',
357 '%': lambda: '%',
358 'b': lambda: os.path.basename(repo.root),
358 'b': lambda: os.path.basename(repo.root),
359 }
359 }
360
360
361 try:
361 try:
362 if node:
362 if node:
363 expander.update(node_expander)
363 expander.update(node_expander)
364 if node:
364 if node:
365 expander['r'] = (lambda:
365 expander['r'] = (lambda:
366 str(repo.changelog.rev(node)).zfill(revwidth or 0))
366 str(repo.changelog.rev(node)).zfill(revwidth or 0))
367 if total is not None:
367 if total is not None:
368 expander['N'] = lambda: str(total)
368 expander['N'] = lambda: str(total)
369 if seqno is not None:
369 if seqno is not None:
370 expander['n'] = lambda: str(seqno)
370 expander['n'] = lambda: str(seqno)
371 if total is not None and seqno is not None:
371 if total is not None and seqno is not None:
372 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
372 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
373 if pathname is not None:
373 if pathname is not None:
374 expander['s'] = lambda: os.path.basename(pathname)
374 expander['s'] = lambda: os.path.basename(pathname)
375 expander['d'] = lambda: os.path.dirname(pathname) or '.'
375 expander['d'] = lambda: os.path.dirname(pathname) or '.'
376 expander['p'] = lambda: pathname
376 expander['p'] = lambda: pathname
377
377
378 newname = []
378 newname = []
379 patlen = len(pat)
379 patlen = len(pat)
380 i = 0
380 i = 0
381 while i < patlen:
381 while i < patlen:
382 c = pat[i]
382 c = pat[i]
383 if c == '%':
383 if c == '%':
384 i += 1
384 i += 1
385 c = pat[i]
385 c = pat[i]
386 c = expander[c]()
386 c = expander[c]()
387 newname.append(c)
387 newname.append(c)
388 i += 1
388 i += 1
389 return ''.join(newname)
389 return ''.join(newname)
390 except KeyError, inst:
390 except KeyError, inst:
391 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
391 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
392 inst.args[0])
392 inst.args[0])
393
393
394 def makefileobj(repo, pat, node=None, desc=None, total=None,
394 def makefileobj(repo, pat, node=None, desc=None, total=None,
395 seqno=None, revwidth=None, mode='wb', modemap=None,
395 seqno=None, revwidth=None, mode='wb', modemap=None,
396 pathname=None):
396 pathname=None):
397
397
398 writable = mode not in ('r', 'rb')
398 writable = mode not in ('r', 'rb')
399
399
400 if not pat or pat == '-':
400 if not pat or pat == '-':
401 fp = writable and repo.ui.fout or repo.ui.fin
401 fp = writable and repo.ui.fout or repo.ui.fin
402 if util.safehasattr(fp, 'fileno'):
402 if util.safehasattr(fp, 'fileno'):
403 return os.fdopen(os.dup(fp.fileno()), mode)
403 return os.fdopen(os.dup(fp.fileno()), mode)
404 else:
404 else:
405 # if this fp can't be duped properly, return
405 # if this fp can't be duped properly, return
406 # a dummy object that can be closed
406 # a dummy object that can be closed
407 class wrappedfileobj(object):
407 class wrappedfileobj(object):
408 noop = lambda x: None
408 noop = lambda x: None
409 def __init__(self, f):
409 def __init__(self, f):
410 self.f = f
410 self.f = f
411 def __getattr__(self, attr):
411 def __getattr__(self, attr):
412 if attr == 'close':
412 if attr == 'close':
413 return self.noop
413 return self.noop
414 else:
414 else:
415 return getattr(self.f, attr)
415 return getattr(self.f, attr)
416
416
417 return wrappedfileobj(fp)
417 return wrappedfileobj(fp)
418 if util.safehasattr(pat, 'write') and writable:
418 if util.safehasattr(pat, 'write') and writable:
419 return pat
419 return pat
420 if util.safehasattr(pat, 'read') and 'r' in mode:
420 if util.safehasattr(pat, 'read') and 'r' in mode:
421 return pat
421 return pat
422 fn = makefilename(repo, pat, node, desc, total, seqno, revwidth, pathname)
422 fn = makefilename(repo, pat, node, desc, total, seqno, revwidth, pathname)
423 if modemap is not None:
423 if modemap is not None:
424 mode = modemap.get(fn, mode)
424 mode = modemap.get(fn, mode)
425 if mode == 'wb':
425 if mode == 'wb':
426 modemap[fn] = 'ab'
426 modemap[fn] = 'ab'
427 return open(fn, mode)
427 return open(fn, mode)
428
428
429 def openrevlog(repo, cmd, file_, opts):
429 def openrevlog(repo, cmd, file_, opts):
430 """opens the changelog, manifest, a filelog or a given revlog"""
430 """opens the changelog, manifest, a filelog or a given revlog"""
431 cl = opts['changelog']
431 cl = opts['changelog']
432 mf = opts['manifest']
432 mf = opts['manifest']
433 msg = None
433 msg = None
434 if cl and mf:
434 if cl and mf:
435 msg = _('cannot specify --changelog and --manifest at the same time')
435 msg = _('cannot specify --changelog and --manifest at the same time')
436 elif cl or mf:
436 elif cl or mf:
437 if file_:
437 if file_:
438 msg = _('cannot specify filename with --changelog or --manifest')
438 msg = _('cannot specify filename with --changelog or --manifest')
439 elif not repo:
439 elif not repo:
440 msg = _('cannot specify --changelog or --manifest '
440 msg = _('cannot specify --changelog or --manifest '
441 'without a repository')
441 'without a repository')
442 if msg:
442 if msg:
443 raise util.Abort(msg)
443 raise util.Abort(msg)
444
444
445 r = None
445 r = None
446 if repo:
446 if repo:
447 if cl:
447 if cl:
448 r = repo.unfiltered().changelog
448 r = repo.unfiltered().changelog
449 elif mf:
449 elif mf:
450 r = repo.manifest
450 r = repo.manifest
451 elif file_:
451 elif file_:
452 filelog = repo.file(file_)
452 filelog = repo.file(file_)
453 if len(filelog):
453 if len(filelog):
454 r = filelog
454 r = filelog
455 if not r:
455 if not r:
456 if not file_:
456 if not file_:
457 raise error.CommandError(cmd, _('invalid arguments'))
457 raise error.CommandError(cmd, _('invalid arguments'))
458 if not os.path.isfile(file_):
458 if not os.path.isfile(file_):
459 raise util.Abort(_("revlog '%s' not found") % file_)
459 raise util.Abort(_("revlog '%s' not found") % file_)
460 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
460 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
461 file_[:-2] + ".i")
461 file_[:-2] + ".i")
462 return r
462 return r
463
463
464 def copy(ui, repo, pats, opts, rename=False):
464 def copy(ui, repo, pats, opts, rename=False):
465 # called with the repo lock held
465 # called with the repo lock held
466 #
466 #
467 # hgsep => pathname that uses "/" to separate directories
467 # hgsep => pathname that uses "/" to separate directories
468 # ossep => pathname that uses os.sep to separate directories
468 # ossep => pathname that uses os.sep to separate directories
469 cwd = repo.getcwd()
469 cwd = repo.getcwd()
470 targets = {}
470 targets = {}
471 after = opts.get("after")
471 after = opts.get("after")
472 dryrun = opts.get("dry_run")
472 dryrun = opts.get("dry_run")
473 wctx = repo[None]
473 wctx = repo[None]
474
474
475 def walkpat(pat):
475 def walkpat(pat):
476 srcs = []
476 srcs = []
477 badstates = after and '?' or '?r'
477 badstates = after and '?' or '?r'
478 m = scmutil.match(repo[None], [pat], opts, globbed=True)
478 m = scmutil.match(repo[None], [pat], opts, globbed=True)
479 for abs in repo.walk(m):
479 for abs in repo.walk(m):
480 state = repo.dirstate[abs]
480 state = repo.dirstate[abs]
481 rel = m.rel(abs)
481 rel = m.rel(abs)
482 exact = m.exact(abs)
482 exact = m.exact(abs)
483 if state in badstates:
483 if state in badstates:
484 if exact and state == '?':
484 if exact and state == '?':
485 ui.warn(_('%s: not copying - file is not managed\n') % rel)
485 ui.warn(_('%s: not copying - file is not managed\n') % rel)
486 if exact and state == 'r':
486 if exact and state == 'r':
487 ui.warn(_('%s: not copying - file has been marked for'
487 ui.warn(_('%s: not copying - file has been marked for'
488 ' remove\n') % rel)
488 ' remove\n') % rel)
489 continue
489 continue
490 # abs: hgsep
490 # abs: hgsep
491 # rel: ossep
491 # rel: ossep
492 srcs.append((abs, rel, exact))
492 srcs.append((abs, rel, exact))
493 return srcs
493 return srcs
494
494
495 # abssrc: hgsep
495 # abssrc: hgsep
496 # relsrc: ossep
496 # relsrc: ossep
497 # otarget: ossep
497 # otarget: ossep
498 def copyfile(abssrc, relsrc, otarget, exact):
498 def copyfile(abssrc, relsrc, otarget, exact):
499 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
499 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
500 if '/' in abstarget:
500 if '/' in abstarget:
501 # We cannot normalize abstarget itself, this would prevent
501 # We cannot normalize abstarget itself, this would prevent
502 # case only renames, like a => A.
502 # case only renames, like a => A.
503 abspath, absname = abstarget.rsplit('/', 1)
503 abspath, absname = abstarget.rsplit('/', 1)
504 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
504 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
505 reltarget = repo.pathto(abstarget, cwd)
505 reltarget = repo.pathto(abstarget, cwd)
506 target = repo.wjoin(abstarget)
506 target = repo.wjoin(abstarget)
507 src = repo.wjoin(abssrc)
507 src = repo.wjoin(abssrc)
508 state = repo.dirstate[abstarget]
508 state = repo.dirstate[abstarget]
509
509
510 scmutil.checkportable(ui, abstarget)
510 scmutil.checkportable(ui, abstarget)
511
511
512 # check for collisions
512 # check for collisions
513 prevsrc = targets.get(abstarget)
513 prevsrc = targets.get(abstarget)
514 if prevsrc is not None:
514 if prevsrc is not None:
515 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
515 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
516 (reltarget, repo.pathto(abssrc, cwd),
516 (reltarget, repo.pathto(abssrc, cwd),
517 repo.pathto(prevsrc, cwd)))
517 repo.pathto(prevsrc, cwd)))
518 return
518 return
519
519
520 # check for overwrites
520 # check for overwrites
521 exists = os.path.lexists(target)
521 exists = os.path.lexists(target)
522 samefile = False
522 samefile = False
523 if exists and abssrc != abstarget:
523 if exists and abssrc != abstarget:
524 if (repo.dirstate.normalize(abssrc) ==
524 if (repo.dirstate.normalize(abssrc) ==
525 repo.dirstate.normalize(abstarget)):
525 repo.dirstate.normalize(abstarget)):
526 if not rename:
526 if not rename:
527 ui.warn(_("%s: can't copy - same file\n") % reltarget)
527 ui.warn(_("%s: can't copy - same file\n") % reltarget)
528 return
528 return
529 exists = False
529 exists = False
530 samefile = True
530 samefile = True
531
531
532 if not after and exists or after and state in 'mn':
532 if not after and exists or after and state in 'mn':
533 if not opts['force']:
533 if not opts['force']:
534 ui.warn(_('%s: not overwriting - file exists\n') %
534 ui.warn(_('%s: not overwriting - file exists\n') %
535 reltarget)
535 reltarget)
536 return
536 return
537
537
538 if after:
538 if after:
539 if not exists:
539 if not exists:
540 if rename:
540 if rename:
541 ui.warn(_('%s: not recording move - %s does not exist\n') %
541 ui.warn(_('%s: not recording move - %s does not exist\n') %
542 (relsrc, reltarget))
542 (relsrc, reltarget))
543 else:
543 else:
544 ui.warn(_('%s: not recording copy - %s does not exist\n') %
544 ui.warn(_('%s: not recording copy - %s does not exist\n') %
545 (relsrc, reltarget))
545 (relsrc, reltarget))
546 return
546 return
547 elif not dryrun:
547 elif not dryrun:
548 try:
548 try:
549 if exists:
549 if exists:
550 os.unlink(target)
550 os.unlink(target)
551 targetdir = os.path.dirname(target) or '.'
551 targetdir = os.path.dirname(target) or '.'
552 if not os.path.isdir(targetdir):
552 if not os.path.isdir(targetdir):
553 os.makedirs(targetdir)
553 os.makedirs(targetdir)
554 if samefile:
554 if samefile:
555 tmp = target + "~hgrename"
555 tmp = target + "~hgrename"
556 os.rename(src, tmp)
556 os.rename(src, tmp)
557 os.rename(tmp, target)
557 os.rename(tmp, target)
558 else:
558 else:
559 util.copyfile(src, target)
559 util.copyfile(src, target)
560 srcexists = True
560 srcexists = True
561 except IOError, inst:
561 except IOError, inst:
562 if inst.errno == errno.ENOENT:
562 if inst.errno == errno.ENOENT:
563 ui.warn(_('%s: deleted in working copy\n') % relsrc)
563 ui.warn(_('%s: deleted in working copy\n') % relsrc)
564 srcexists = False
564 srcexists = False
565 else:
565 else:
566 ui.warn(_('%s: cannot copy - %s\n') %
566 ui.warn(_('%s: cannot copy - %s\n') %
567 (relsrc, inst.strerror))
567 (relsrc, inst.strerror))
568 return True # report a failure
568 return True # report a failure
569
569
570 if ui.verbose or not exact:
570 if ui.verbose or not exact:
571 if rename:
571 if rename:
572 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
572 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
573 else:
573 else:
574 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
574 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
575
575
576 targets[abstarget] = abssrc
576 targets[abstarget] = abssrc
577
577
578 # fix up dirstate
578 # fix up dirstate
579 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
579 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
580 dryrun=dryrun, cwd=cwd)
580 dryrun=dryrun, cwd=cwd)
581 if rename and not dryrun:
581 if rename and not dryrun:
582 if not after and srcexists and not samefile:
582 if not after and srcexists and not samefile:
583 util.unlinkpath(repo.wjoin(abssrc))
583 util.unlinkpath(repo.wjoin(abssrc))
584 wctx.forget([abssrc])
584 wctx.forget([abssrc])
585
585
586 # pat: ossep
586 # pat: ossep
587 # dest ossep
587 # dest ossep
588 # srcs: list of (hgsep, hgsep, ossep, bool)
588 # srcs: list of (hgsep, hgsep, ossep, bool)
589 # return: function that takes hgsep and returns ossep
589 # return: function that takes hgsep and returns ossep
590 def targetpathfn(pat, dest, srcs):
590 def targetpathfn(pat, dest, srcs):
591 if os.path.isdir(pat):
591 if os.path.isdir(pat):
592 abspfx = pathutil.canonpath(repo.root, cwd, pat)
592 abspfx = pathutil.canonpath(repo.root, cwd, pat)
593 abspfx = util.localpath(abspfx)
593 abspfx = util.localpath(abspfx)
594 if destdirexists:
594 if destdirexists:
595 striplen = len(os.path.split(abspfx)[0])
595 striplen = len(os.path.split(abspfx)[0])
596 else:
596 else:
597 striplen = len(abspfx)
597 striplen = len(abspfx)
598 if striplen:
598 if striplen:
599 striplen += len(os.sep)
599 striplen += len(os.sep)
600 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
600 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
601 elif destdirexists:
601 elif destdirexists:
602 res = lambda p: os.path.join(dest,
602 res = lambda p: os.path.join(dest,
603 os.path.basename(util.localpath(p)))
603 os.path.basename(util.localpath(p)))
604 else:
604 else:
605 res = lambda p: dest
605 res = lambda p: dest
606 return res
606 return res
607
607
608 # pat: ossep
608 # pat: ossep
609 # dest ossep
609 # dest ossep
610 # srcs: list of (hgsep, hgsep, ossep, bool)
610 # srcs: list of (hgsep, hgsep, ossep, bool)
611 # return: function that takes hgsep and returns ossep
611 # return: function that takes hgsep and returns ossep
612 def targetpathafterfn(pat, dest, srcs):
612 def targetpathafterfn(pat, dest, srcs):
613 if matchmod.patkind(pat):
613 if matchmod.patkind(pat):
614 # a mercurial pattern
614 # a mercurial pattern
615 res = lambda p: os.path.join(dest,
615 res = lambda p: os.path.join(dest,
616 os.path.basename(util.localpath(p)))
616 os.path.basename(util.localpath(p)))
617 else:
617 else:
618 abspfx = pathutil.canonpath(repo.root, cwd, pat)
618 abspfx = pathutil.canonpath(repo.root, cwd, pat)
619 if len(abspfx) < len(srcs[0][0]):
619 if len(abspfx) < len(srcs[0][0]):
620 # A directory. Either the target path contains the last
620 # A directory. Either the target path contains the last
621 # component of the source path or it does not.
621 # component of the source path or it does not.
622 def evalpath(striplen):
622 def evalpath(striplen):
623 score = 0
623 score = 0
624 for s in srcs:
624 for s in srcs:
625 t = os.path.join(dest, util.localpath(s[0])[striplen:])
625 t = os.path.join(dest, util.localpath(s[0])[striplen:])
626 if os.path.lexists(t):
626 if os.path.lexists(t):
627 score += 1
627 score += 1
628 return score
628 return score
629
629
630 abspfx = util.localpath(abspfx)
630 abspfx = util.localpath(abspfx)
631 striplen = len(abspfx)
631 striplen = len(abspfx)
632 if striplen:
632 if striplen:
633 striplen += len(os.sep)
633 striplen += len(os.sep)
634 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
634 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
635 score = evalpath(striplen)
635 score = evalpath(striplen)
636 striplen1 = len(os.path.split(abspfx)[0])
636 striplen1 = len(os.path.split(abspfx)[0])
637 if striplen1:
637 if striplen1:
638 striplen1 += len(os.sep)
638 striplen1 += len(os.sep)
639 if evalpath(striplen1) > score:
639 if evalpath(striplen1) > score:
640 striplen = striplen1
640 striplen = striplen1
641 res = lambda p: os.path.join(dest,
641 res = lambda p: os.path.join(dest,
642 util.localpath(p)[striplen:])
642 util.localpath(p)[striplen:])
643 else:
643 else:
644 # a file
644 # a file
645 if destdirexists:
645 if destdirexists:
646 res = lambda p: os.path.join(dest,
646 res = lambda p: os.path.join(dest,
647 os.path.basename(util.localpath(p)))
647 os.path.basename(util.localpath(p)))
648 else:
648 else:
649 res = lambda p: dest
649 res = lambda p: dest
650 return res
650 return res
651
651
652
652
653 pats = scmutil.expandpats(pats)
653 pats = scmutil.expandpats(pats)
654 if not pats:
654 if not pats:
655 raise util.Abort(_('no source or destination specified'))
655 raise util.Abort(_('no source or destination specified'))
656 if len(pats) == 1:
656 if len(pats) == 1:
657 raise util.Abort(_('no destination specified'))
657 raise util.Abort(_('no destination specified'))
658 dest = pats.pop()
658 dest = pats.pop()
659 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
659 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
660 if not destdirexists:
660 if not destdirexists:
661 if len(pats) > 1 or matchmod.patkind(pats[0]):
661 if len(pats) > 1 or matchmod.patkind(pats[0]):
662 raise util.Abort(_('with multiple sources, destination must be an '
662 raise util.Abort(_('with multiple sources, destination must be an '
663 'existing directory'))
663 'existing directory'))
664 if util.endswithsep(dest):
664 if util.endswithsep(dest):
665 raise util.Abort(_('destination %s is not a directory') % dest)
665 raise util.Abort(_('destination %s is not a directory') % dest)
666
666
667 tfn = targetpathfn
667 tfn = targetpathfn
668 if after:
668 if after:
669 tfn = targetpathafterfn
669 tfn = targetpathafterfn
670 copylist = []
670 copylist = []
671 for pat in pats:
671 for pat in pats:
672 srcs = walkpat(pat)
672 srcs = walkpat(pat)
673 if not srcs:
673 if not srcs:
674 continue
674 continue
675 copylist.append((tfn(pat, dest, srcs), srcs))
675 copylist.append((tfn(pat, dest, srcs), srcs))
676 if not copylist:
676 if not copylist:
677 raise util.Abort(_('no files to copy'))
677 raise util.Abort(_('no files to copy'))
678
678
679 errors = 0
679 errors = 0
680 for targetpath, srcs in copylist:
680 for targetpath, srcs in copylist:
681 for abssrc, relsrc, exact in srcs:
681 for abssrc, relsrc, exact in srcs:
682 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
682 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
683 errors += 1
683 errors += 1
684
684
685 if errors:
685 if errors:
686 ui.warn(_('(consider using --after)\n'))
686 ui.warn(_('(consider using --after)\n'))
687
687
688 return errors != 0
688 return errors != 0
689
689
690 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
690 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
691 runargs=None, appendpid=False):
691 runargs=None, appendpid=False):
692 '''Run a command as a service.'''
692 '''Run a command as a service.'''
693
693
694 def writepid(pid):
694 def writepid(pid):
695 if opts['pid_file']:
695 if opts['pid_file']:
696 mode = appendpid and 'a' or 'w'
696 mode = appendpid and 'a' or 'w'
697 fp = open(opts['pid_file'], mode)
697 fp = open(opts['pid_file'], mode)
698 fp.write(str(pid) + '\n')
698 fp.write(str(pid) + '\n')
699 fp.close()
699 fp.close()
700
700
701 if opts['daemon'] and not opts['daemon_pipefds']:
701 if opts['daemon'] and not opts['daemon_pipefds']:
702 # Signal child process startup with file removal
702 # Signal child process startup with file removal
703 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
703 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
704 os.close(lockfd)
704 os.close(lockfd)
705 try:
705 try:
706 if not runargs:
706 if not runargs:
707 runargs = util.hgcmd() + sys.argv[1:]
707 runargs = util.hgcmd() + sys.argv[1:]
708 runargs.append('--daemon-pipefds=%s' % lockpath)
708 runargs.append('--daemon-pipefds=%s' % lockpath)
709 # Don't pass --cwd to the child process, because we've already
709 # Don't pass --cwd to the child process, because we've already
710 # changed directory.
710 # changed directory.
711 for i in xrange(1, len(runargs)):
711 for i in xrange(1, len(runargs)):
712 if runargs[i].startswith('--cwd='):
712 if runargs[i].startswith('--cwd='):
713 del runargs[i]
713 del runargs[i]
714 break
714 break
715 elif runargs[i].startswith('--cwd'):
715 elif runargs[i].startswith('--cwd'):
716 del runargs[i:i + 2]
716 del runargs[i:i + 2]
717 break
717 break
718 def condfn():
718 def condfn():
719 return not os.path.exists(lockpath)
719 return not os.path.exists(lockpath)
720 pid = util.rundetached(runargs, condfn)
720 pid = util.rundetached(runargs, condfn)
721 if pid < 0:
721 if pid < 0:
722 raise util.Abort(_('child process failed to start'))
722 raise util.Abort(_('child process failed to start'))
723 writepid(pid)
723 writepid(pid)
724 finally:
724 finally:
725 try:
725 try:
726 os.unlink(lockpath)
726 os.unlink(lockpath)
727 except OSError, e:
727 except OSError, e:
728 if e.errno != errno.ENOENT:
728 if e.errno != errno.ENOENT:
729 raise
729 raise
730 if parentfn:
730 if parentfn:
731 return parentfn(pid)
731 return parentfn(pid)
732 else:
732 else:
733 return
733 return
734
734
735 if initfn:
735 if initfn:
736 initfn()
736 initfn()
737
737
738 if not opts['daemon']:
738 if not opts['daemon']:
739 writepid(os.getpid())
739 writepid(os.getpid())
740
740
741 if opts['daemon_pipefds']:
741 if opts['daemon_pipefds']:
742 lockpath = opts['daemon_pipefds']
742 lockpath = opts['daemon_pipefds']
743 try:
743 try:
744 os.setsid()
744 os.setsid()
745 except AttributeError:
745 except AttributeError:
746 pass
746 pass
747 os.unlink(lockpath)
747 os.unlink(lockpath)
748 util.hidewindow()
748 util.hidewindow()
749 sys.stdout.flush()
749 sys.stdout.flush()
750 sys.stderr.flush()
750 sys.stderr.flush()
751
751
752 nullfd = os.open(os.devnull, os.O_RDWR)
752 nullfd = os.open(os.devnull, os.O_RDWR)
753 logfilefd = nullfd
753 logfilefd = nullfd
754 if logfile:
754 if logfile:
755 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
755 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
756 os.dup2(nullfd, 0)
756 os.dup2(nullfd, 0)
757 os.dup2(logfilefd, 1)
757 os.dup2(logfilefd, 1)
758 os.dup2(logfilefd, 2)
758 os.dup2(logfilefd, 2)
759 if nullfd not in (0, 1, 2):
759 if nullfd not in (0, 1, 2):
760 os.close(nullfd)
760 os.close(nullfd)
761 if logfile and logfilefd not in (0, 1, 2):
761 if logfile and logfilefd not in (0, 1, 2):
762 os.close(logfilefd)
762 os.close(logfilefd)
763
763
764 if runfn:
764 if runfn:
765 return runfn()
765 return runfn()
766
766
767 def tryimportone(ui, repo, hunk, parents, opts, msgs, updatefunc):
767 def tryimportone(ui, repo, hunk, parents, opts, msgs, updatefunc):
768 """Utility function used by commands.import to import a single patch
768 """Utility function used by commands.import to import a single patch
769
769
770 This function is explicitly defined here to help the evolve extension to
770 This function is explicitly defined here to help the evolve extension to
771 wrap this part of the import logic.
771 wrap this part of the import logic.
772
772
773 The API is currently a bit ugly because it a simple code translation from
773 The API is currently a bit ugly because it a simple code translation from
774 the import command. Feel free to make it better.
774 the import command. Feel free to make it better.
775
775
776 :hunk: a patch (as a binary string)
776 :hunk: a patch (as a binary string)
777 :parents: nodes that will be parent of the created commit
777 :parents: nodes that will be parent of the created commit
778 :opts: the full dict of option passed to the import command
778 :opts: the full dict of option passed to the import command
779 :msgs: list to save commit message to.
779 :msgs: list to save commit message to.
780 (used in case we need to save it when failing)
780 (used in case we need to save it when failing)
781 :updatefunc: a function that update a repo to a given node
781 :updatefunc: a function that update a repo to a given node
782 updatefunc(<repo>, <node>)
782 updatefunc(<repo>, <node>)
783 """
783 """
784 tmpname, message, user, date, branch, nodeid, p1, p2 = \
784 tmpname, message, user, date, branch, nodeid, p1, p2 = \
785 patch.extract(ui, hunk)
785 patch.extract(ui, hunk)
786
786
787 update = not opts.get('bypass')
787 update = not opts.get('bypass')
788 strip = opts["strip"]
788 strip = opts["strip"]
789 prefix = opts["prefix"]
789 prefix = opts["prefix"]
790 sim = float(opts.get('similarity') or 0)
790 sim = float(opts.get('similarity') or 0)
791 if not tmpname:
791 if not tmpname:
792 return (None, None, False)
792 return (None, None, False)
793 msg = _('applied to working directory')
793 msg = _('applied to working directory')
794
794
795 rejects = False
795 rejects = False
796
796
797 try:
797 try:
798 cmdline_message = logmessage(ui, opts)
798 cmdline_message = logmessage(ui, opts)
799 if cmdline_message:
799 if cmdline_message:
800 # pickup the cmdline msg
800 # pickup the cmdline msg
801 message = cmdline_message
801 message = cmdline_message
802 elif message:
802 elif message:
803 # pickup the patch msg
803 # pickup the patch msg
804 message = message.strip()
804 message = message.strip()
805 else:
805 else:
806 # launch the editor
806 # launch the editor
807 message = None
807 message = None
808 ui.debug('message:\n%s\n' % message)
808 ui.debug('message:\n%s\n' % message)
809
809
810 if len(parents) == 1:
810 if len(parents) == 1:
811 parents.append(repo[nullid])
811 parents.append(repo[nullid])
812 if opts.get('exact'):
812 if opts.get('exact'):
813 if not nodeid or not p1:
813 if not nodeid or not p1:
814 raise util.Abort(_('not a Mercurial patch'))
814 raise util.Abort(_('not a Mercurial patch'))
815 p1 = repo[p1]
815 p1 = repo[p1]
816 p2 = repo[p2 or nullid]
816 p2 = repo[p2 or nullid]
817 elif p2:
817 elif p2:
818 try:
818 try:
819 p1 = repo[p1]
819 p1 = repo[p1]
820 p2 = repo[p2]
820 p2 = repo[p2]
821 # Without any options, consider p2 only if the
821 # Without any options, consider p2 only if the
822 # patch is being applied on top of the recorded
822 # patch is being applied on top of the recorded
823 # first parent.
823 # first parent.
824 if p1 != parents[0]:
824 if p1 != parents[0]:
825 p1 = parents[0]
825 p1 = parents[0]
826 p2 = repo[nullid]
826 p2 = repo[nullid]
827 except error.RepoError:
827 except error.RepoError:
828 p1, p2 = parents
828 p1, p2 = parents
829 if p2.node() == nullid:
829 if p2.node() == nullid:
830 ui.warn(_("warning: import the patch as a normal revision\n"
830 ui.warn(_("warning: import the patch as a normal revision\n"
831 "(use --exact to import the patch as a merge)\n"))
831 "(use --exact to import the patch as a merge)\n"))
832 else:
832 else:
833 p1, p2 = parents
833 p1, p2 = parents
834
834
835 n = None
835 n = None
836 if update:
836 if update:
837 repo.dirstate.beginparentchange()
837 repo.dirstate.beginparentchange()
838 if p1 != parents[0]:
838 if p1 != parents[0]:
839 updatefunc(repo, p1.node())
839 updatefunc(repo, p1.node())
840 if p2 != parents[1]:
840 if p2 != parents[1]:
841 repo.setparents(p1.node(), p2.node())
841 repo.setparents(p1.node(), p2.node())
842
842
843 if opts.get('exact') or opts.get('import_branch'):
843 if opts.get('exact') or opts.get('import_branch'):
844 repo.dirstate.setbranch(branch or 'default')
844 repo.dirstate.setbranch(branch or 'default')
845
845
846 partial = opts.get('partial', False)
846 partial = opts.get('partial', False)
847 files = set()
847 files = set()
848 try:
848 try:
849 patch.patch(ui, repo, tmpname, strip=strip, prefix=prefix,
849 patch.patch(ui, repo, tmpname, strip=strip, prefix=prefix,
850 files=files, eolmode=None, similarity=sim / 100.0)
850 files=files, eolmode=None, similarity=sim / 100.0)
851 except patch.PatchError, e:
851 except patch.PatchError, e:
852 if not partial:
852 if not partial:
853 raise util.Abort(str(e))
853 raise util.Abort(str(e))
854 if partial:
854 if partial:
855 rejects = True
855 rejects = True
856
856
857 files = list(files)
857 files = list(files)
858 if opts.get('no_commit'):
858 if opts.get('no_commit'):
859 if message:
859 if message:
860 msgs.append(message)
860 msgs.append(message)
861 else:
861 else:
862 if opts.get('exact') or p2:
862 if opts.get('exact') or p2:
863 # If you got here, you either use --force and know what
863 # If you got here, you either use --force and know what
864 # you are doing or used --exact or a merge patch while
864 # you are doing or used --exact or a merge patch while
865 # being updated to its first parent.
865 # being updated to its first parent.
866 m = None
866 m = None
867 else:
867 else:
868 m = scmutil.matchfiles(repo, files or [])
868 m = scmutil.matchfiles(repo, files or [])
869 editform = mergeeditform(repo[None], 'import.normal')
869 editform = mergeeditform(repo[None], 'import.normal')
870 if opts.get('exact'):
870 if opts.get('exact'):
871 editor = None
871 editor = None
872 else:
872 else:
873 editor = getcommiteditor(editform=editform, **opts)
873 editor = getcommiteditor(editform=editform, **opts)
874 n = repo.commit(message, opts.get('user') or user,
874 n = repo.commit(message, opts.get('user') or user,
875 opts.get('date') or date, match=m,
875 opts.get('date') or date, match=m,
876 editor=editor, force=partial)
876 editor=editor, force=partial)
877 repo.dirstate.endparentchange()
877 repo.dirstate.endparentchange()
878 else:
878 else:
879 if opts.get('exact') or opts.get('import_branch'):
879 if opts.get('exact') or opts.get('import_branch'):
880 branch = branch or 'default'
880 branch = branch or 'default'
881 else:
881 else:
882 branch = p1.branch()
882 branch = p1.branch()
883 store = patch.filestore()
883 store = patch.filestore()
884 try:
884 try:
885 files = set()
885 files = set()
886 try:
886 try:
887 patch.patchrepo(ui, repo, p1, store, tmpname, strip, prefix,
887 patch.patchrepo(ui, repo, p1, store, tmpname, strip, prefix,
888 files, eolmode=None)
888 files, eolmode=None)
889 except patch.PatchError, e:
889 except patch.PatchError, e:
890 raise util.Abort(str(e))
890 raise util.Abort(str(e))
891 if opts.get('exact'):
891 if opts.get('exact'):
892 editor = None
892 editor = None
893 else:
893 else:
894 editor = getcommiteditor(editform='import.bypass')
894 editor = getcommiteditor(editform='import.bypass')
895 memctx = context.makememctx(repo, (p1.node(), p2.node()),
895 memctx = context.makememctx(repo, (p1.node(), p2.node()),
896 message,
896 message,
897 opts.get('user') or user,
897 opts.get('user') or user,
898 opts.get('date') or date,
898 opts.get('date') or date,
899 branch, files, store,
899 branch, files, store,
900 editor=editor)
900 editor=editor)
901 n = memctx.commit()
901 n = memctx.commit()
902 finally:
902 finally:
903 store.close()
903 store.close()
904 if opts.get('exact') and opts.get('no_commit'):
904 if opts.get('exact') and opts.get('no_commit'):
905 # --exact with --no-commit is still useful in that it does merge
905 # --exact with --no-commit is still useful in that it does merge
906 # and branch bits
906 # and branch bits
907 ui.warn(_("warning: can't check exact import with --no-commit\n"))
907 ui.warn(_("warning: can't check exact import with --no-commit\n"))
908 elif opts.get('exact') and hex(n) != nodeid:
908 elif opts.get('exact') and hex(n) != nodeid:
909 raise util.Abort(_('patch is damaged or loses information'))
909 raise util.Abort(_('patch is damaged or loses information'))
910 if n:
910 if n:
911 # i18n: refers to a short changeset id
911 # i18n: refers to a short changeset id
912 msg = _('created %s') % short(n)
912 msg = _('created %s') % short(n)
913 return (msg, n, rejects)
913 return (msg, n, rejects)
914 finally:
914 finally:
915 os.unlink(tmpname)
915 os.unlink(tmpname)
916
916
917 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
917 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
918 opts=None):
918 opts=None):
919 '''export changesets as hg patches.'''
919 '''export changesets as hg patches.'''
920
920
921 total = len(revs)
921 total = len(revs)
922 revwidth = max([len(str(rev)) for rev in revs])
922 revwidth = max([len(str(rev)) for rev in revs])
923 filemode = {}
923 filemode = {}
924
924
925 def single(rev, seqno, fp):
925 def single(rev, seqno, fp):
926 ctx = repo[rev]
926 ctx = repo[rev]
927 node = ctx.node()
927 node = ctx.node()
928 parents = [p.node() for p in ctx.parents() if p]
928 parents = [p.node() for p in ctx.parents() if p]
929 branch = ctx.branch()
929 branch = ctx.branch()
930 if switch_parent:
930 if switch_parent:
931 parents.reverse()
931 parents.reverse()
932 prev = (parents and parents[0]) or nullid
932 prev = (parents and parents[0]) or nullid
933
933
934 shouldclose = False
934 shouldclose = False
935 if not fp and len(template) > 0:
935 if not fp and len(template) > 0:
936 desc_lines = ctx.description().rstrip().split('\n')
936 desc_lines = ctx.description().rstrip().split('\n')
937 desc = desc_lines[0] #Commit always has a first line.
937 desc = desc_lines[0] #Commit always has a first line.
938 fp = makefileobj(repo, template, node, desc=desc, total=total,
938 fp = makefileobj(repo, template, node, desc=desc, total=total,
939 seqno=seqno, revwidth=revwidth, mode='wb',
939 seqno=seqno, revwidth=revwidth, mode='wb',
940 modemap=filemode)
940 modemap=filemode)
941 if fp != template:
941 if fp != template:
942 shouldclose = True
942 shouldclose = True
943 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
943 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
944 repo.ui.note("%s\n" % fp.name)
944 repo.ui.note("%s\n" % fp.name)
945
945
946 if not fp:
946 if not fp:
947 write = repo.ui.write
947 write = repo.ui.write
948 else:
948 else:
949 def write(s, **kw):
949 def write(s, **kw):
950 fp.write(s)
950 fp.write(s)
951
951
952
952
953 write("# HG changeset patch\n")
953 write("# HG changeset patch\n")
954 write("# User %s\n" % ctx.user())
954 write("# User %s\n" % ctx.user())
955 write("# Date %d %d\n" % ctx.date())
955 write("# Date %d %d\n" % ctx.date())
956 write("# %s\n" % util.datestr(ctx.date()))
956 write("# %s\n" % util.datestr(ctx.date()))
957 if branch and branch != 'default':
957 if branch and branch != 'default':
958 write("# Branch %s\n" % branch)
958 write("# Branch %s\n" % branch)
959 write("# Node ID %s\n" % hex(node))
959 write("# Node ID %s\n" % hex(node))
960 write("# Parent %s\n" % hex(prev))
960 write("# Parent %s\n" % hex(prev))
961 if len(parents) > 1:
961 if len(parents) > 1:
962 write("# Parent %s\n" % hex(parents[1]))
962 write("# Parent %s\n" % hex(parents[1]))
963 write(ctx.description().rstrip())
963 write(ctx.description().rstrip())
964 write("\n\n")
964 write("\n\n")
965
965
966 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
966 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
967 write(chunk, label=label)
967 write(chunk, label=label)
968
968
969 if shouldclose:
969 if shouldclose:
970 fp.close()
970 fp.close()
971
971
972 for seqno, rev in enumerate(revs):
972 for seqno, rev in enumerate(revs):
973 single(rev, seqno + 1, fp)
973 single(rev, seqno + 1, fp)
974
974
975 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
975 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
976 changes=None, stat=False, fp=None, prefix='',
976 changes=None, stat=False, fp=None, prefix='',
977 listsubrepos=False):
977 listsubrepos=False):
978 '''show diff or diffstat.'''
978 '''show diff or diffstat.'''
979 if fp is None:
979 if fp is None:
980 write = ui.write
980 write = ui.write
981 else:
981 else:
982 def write(s, **kw):
982 def write(s, **kw):
983 fp.write(s)
983 fp.write(s)
984
984
985 if stat:
985 if stat:
986 diffopts = diffopts.copy(context=0)
986 diffopts = diffopts.copy(context=0)
987 width = 80
987 width = 80
988 if not ui.plain():
988 if not ui.plain():
989 width = ui.termwidth()
989 width = ui.termwidth()
990 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
990 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
991 prefix=prefix)
991 prefix=prefix)
992 for chunk, label in patch.diffstatui(util.iterlines(chunks),
992 for chunk, label in patch.diffstatui(util.iterlines(chunks),
993 width=width,
993 width=width,
994 git=diffopts.git):
994 git=diffopts.git):
995 write(chunk, label=label)
995 write(chunk, label=label)
996 else:
996 else:
997 for chunk, label in patch.diffui(repo, node1, node2, match,
997 for chunk, label in patch.diffui(repo, node1, node2, match,
998 changes, diffopts, prefix=prefix):
998 changes, diffopts, prefix=prefix):
999 write(chunk, label=label)
999 write(chunk, label=label)
1000
1000
1001 if listsubrepos:
1001 if listsubrepos:
1002 ctx1 = repo[node1]
1002 ctx1 = repo[node1]
1003 ctx2 = repo[node2]
1003 ctx2 = repo[node2]
1004 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
1004 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
1005 tempnode2 = node2
1005 tempnode2 = node2
1006 try:
1006 try:
1007 if node2 is not None:
1007 if node2 is not None:
1008 tempnode2 = ctx2.substate[subpath][1]
1008 tempnode2 = ctx2.substate[subpath][1]
1009 except KeyError:
1009 except KeyError:
1010 # A subrepo that existed in node1 was deleted between node1 and
1010 # A subrepo that existed in node1 was deleted between node1 and
1011 # node2 (inclusive). Thus, ctx2's substate won't contain that
1011 # node2 (inclusive). Thus, ctx2's substate won't contain that
1012 # subpath. The best we can do is to ignore it.
1012 # subpath. The best we can do is to ignore it.
1013 tempnode2 = None
1013 tempnode2 = None
1014 submatch = matchmod.narrowmatcher(subpath, match)
1014 submatch = matchmod.narrowmatcher(subpath, match)
1015 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
1015 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
1016 stat=stat, fp=fp, prefix=prefix)
1016 stat=stat, fp=fp, prefix=prefix)
1017
1017
1018 class changeset_printer(object):
1018 class changeset_printer(object):
1019 '''show changeset information when templating not requested.'''
1019 '''show changeset information when templating not requested.'''
1020
1020
1021 def __init__(self, ui, repo, matchfn, diffopts, buffered):
1021 def __init__(self, ui, repo, matchfn, diffopts, buffered):
1022 self.ui = ui
1022 self.ui = ui
1023 self.repo = repo
1023 self.repo = repo
1024 self.buffered = buffered
1024 self.buffered = buffered
1025 self.matchfn = matchfn
1025 self.matchfn = matchfn
1026 self.diffopts = diffopts
1026 self.diffopts = diffopts
1027 self.header = {}
1027 self.header = {}
1028 self.hunk = {}
1028 self.hunk = {}
1029 self.lastheader = None
1029 self.lastheader = None
1030 self.footer = None
1030 self.footer = None
1031
1031
1032 def flush(self, rev):
1032 def flush(self, rev):
1033 if rev in self.header:
1033 if rev in self.header:
1034 h = self.header[rev]
1034 h = self.header[rev]
1035 if h != self.lastheader:
1035 if h != self.lastheader:
1036 self.lastheader = h
1036 self.lastheader = h
1037 self.ui.write(h)
1037 self.ui.write(h)
1038 del self.header[rev]
1038 del self.header[rev]
1039 if rev in self.hunk:
1039 if rev in self.hunk:
1040 self.ui.write(self.hunk[rev])
1040 self.ui.write(self.hunk[rev])
1041 del self.hunk[rev]
1041 del self.hunk[rev]
1042 return 1
1042 return 1
1043 return 0
1043 return 0
1044
1044
1045 def close(self):
1045 def close(self):
1046 if self.footer:
1046 if self.footer:
1047 self.ui.write(self.footer)
1047 self.ui.write(self.footer)
1048
1048
1049 def show(self, ctx, copies=None, matchfn=None, **props):
1049 def show(self, ctx, copies=None, matchfn=None, **props):
1050 if self.buffered:
1050 if self.buffered:
1051 self.ui.pushbuffer()
1051 self.ui.pushbuffer()
1052 self._show(ctx, copies, matchfn, props)
1052 self._show(ctx, copies, matchfn, props)
1053 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
1053 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
1054 else:
1054 else:
1055 self._show(ctx, copies, matchfn, props)
1055 self._show(ctx, copies, matchfn, props)
1056
1056
1057 def _show(self, ctx, copies, matchfn, props):
1057 def _show(self, ctx, copies, matchfn, props):
1058 '''show a single changeset or file revision'''
1058 '''show a single changeset or file revision'''
1059 changenode = ctx.node()
1059 changenode = ctx.node()
1060 rev = ctx.rev()
1060 rev = ctx.rev()
1061
1061
1062 if self.ui.quiet:
1062 if self.ui.quiet:
1063 self.ui.write("%d:%s\n" % (rev, short(changenode)),
1063 self.ui.write("%d:%s\n" % (rev, short(changenode)),
1064 label='log.node')
1064 label='log.node')
1065 return
1065 return
1066
1066
1067 log = self.repo.changelog
1067 log = self.repo.changelog
1068 date = util.datestr(ctx.date())
1068 date = util.datestr(ctx.date())
1069
1069
1070 hexfunc = self.ui.debugflag and hex or short
1070 hexfunc = self.ui.debugflag and hex or short
1071
1071
1072 parents = [(p, hexfunc(log.node(p)))
1072 parents = [(p, hexfunc(log.node(p)))
1073 for p in self._meaningful_parentrevs(log, rev)]
1073 for p in self._meaningful_parentrevs(log, rev)]
1074
1074
1075 # i18n: column positioning for "hg log"
1075 # i18n: column positioning for "hg log"
1076 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
1076 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
1077 label='log.changeset changeset.%s' % ctx.phasestr())
1077 label='log.changeset changeset.%s' % ctx.phasestr())
1078
1078
1079 # branches are shown first before any other names due to backwards
1079 # branches are shown first before any other names due to backwards
1080 # compatibility
1080 # compatibility
1081 branch = ctx.branch()
1081 branch = ctx.branch()
1082 # don't show the default branch name
1082 # don't show the default branch name
1083 if branch != 'default':
1083 if branch != 'default':
1084 # i18n: column positioning for "hg log"
1084 # i18n: column positioning for "hg log"
1085 self.ui.write(_("branch: %s\n") % branch,
1085 self.ui.write(_("branch: %s\n") % branch,
1086 label='log.branch')
1086 label='log.branch')
1087
1087
1088 for name, ns in self.repo.names.iteritems():
1088 for name, ns in self.repo.names.iteritems():
1089 # branches has special logic already handled above, so here we just
1089 # branches has special logic already handled above, so here we just
1090 # skip it
1090 # skip it
1091 if name == 'branches':
1091 if name == 'branches':
1092 continue
1092 continue
1093 # we will use the templatename as the color name since those two
1093 # we will use the templatename as the color name since those two
1094 # should be the same
1094 # should be the same
1095 for name in ns.names(self.repo, changenode):
1095 for name in ns.names(self.repo, changenode):
1096 self.ui.write(ns.logfmt % name,
1096 self.ui.write(ns.logfmt % name,
1097 label='log.%s' % ns.colorname)
1097 label='log.%s' % ns.colorname)
1098 if self.ui.debugflag:
1098 if self.ui.debugflag:
1099 # i18n: column positioning for "hg log"
1099 # i18n: column positioning for "hg log"
1100 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
1100 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
1101 label='log.phase')
1101 label='log.phase')
1102 for parent in parents:
1102 for parent in parents:
1103 label = 'log.parent changeset.%s' % self.repo[parent[0]].phasestr()
1103 label = 'log.parent changeset.%s' % self.repo[parent[0]].phasestr()
1104 # i18n: column positioning for "hg log"
1104 # i18n: column positioning for "hg log"
1105 self.ui.write(_("parent: %d:%s\n") % parent,
1105 self.ui.write(_("parent: %d:%s\n") % parent,
1106 label=label)
1106 label=label)
1107
1107
1108 if self.ui.debugflag:
1108 if self.ui.debugflag:
1109 mnode = ctx.manifestnode()
1109 mnode = ctx.manifestnode()
1110 # i18n: column positioning for "hg log"
1110 # i18n: column positioning for "hg log"
1111 self.ui.write(_("manifest: %d:%s\n") %
1111 self.ui.write(_("manifest: %d:%s\n") %
1112 (self.repo.manifest.rev(mnode), hex(mnode)),
1112 (self.repo.manifest.rev(mnode), hex(mnode)),
1113 label='ui.debug log.manifest')
1113 label='ui.debug log.manifest')
1114 # i18n: column positioning for "hg log"
1114 # i18n: column positioning for "hg log"
1115 self.ui.write(_("user: %s\n") % ctx.user(),
1115 self.ui.write(_("user: %s\n") % ctx.user(),
1116 label='log.user')
1116 label='log.user')
1117 # i18n: column positioning for "hg log"
1117 # i18n: column positioning for "hg log"
1118 self.ui.write(_("date: %s\n") % date,
1118 self.ui.write(_("date: %s\n") % date,
1119 label='log.date')
1119 label='log.date')
1120
1120
1121 if self.ui.debugflag:
1121 if self.ui.debugflag:
1122 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
1122 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
1123 for key, value in zip([# i18n: column positioning for "hg log"
1123 for key, value in zip([# i18n: column positioning for "hg log"
1124 _("files:"),
1124 _("files:"),
1125 # i18n: column positioning for "hg log"
1125 # i18n: column positioning for "hg log"
1126 _("files+:"),
1126 _("files+:"),
1127 # i18n: column positioning for "hg log"
1127 # i18n: column positioning for "hg log"
1128 _("files-:")], files):
1128 _("files-:")], files):
1129 if value:
1129 if value:
1130 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
1130 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
1131 label='ui.debug log.files')
1131 label='ui.debug log.files')
1132 elif ctx.files() and self.ui.verbose:
1132 elif ctx.files() and self.ui.verbose:
1133 # i18n: column positioning for "hg log"
1133 # i18n: column positioning for "hg log"
1134 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
1134 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
1135 label='ui.note log.files')
1135 label='ui.note log.files')
1136 if copies and self.ui.verbose:
1136 if copies and self.ui.verbose:
1137 copies = ['%s (%s)' % c for c in copies]
1137 copies = ['%s (%s)' % c for c in copies]
1138 # i18n: column positioning for "hg log"
1138 # i18n: column positioning for "hg log"
1139 self.ui.write(_("copies: %s\n") % ' '.join(copies),
1139 self.ui.write(_("copies: %s\n") % ' '.join(copies),
1140 label='ui.note log.copies')
1140 label='ui.note log.copies')
1141
1141
1142 extra = ctx.extra()
1142 extra = ctx.extra()
1143 if extra and self.ui.debugflag:
1143 if extra and self.ui.debugflag:
1144 for key, value in sorted(extra.items()):
1144 for key, value in sorted(extra.items()):
1145 # i18n: column positioning for "hg log"
1145 # i18n: column positioning for "hg log"
1146 self.ui.write(_("extra: %s=%s\n")
1146 self.ui.write(_("extra: %s=%s\n")
1147 % (key, value.encode('string_escape')),
1147 % (key, value.encode('string_escape')),
1148 label='ui.debug log.extra')
1148 label='ui.debug log.extra')
1149
1149
1150 description = ctx.description().strip()
1150 description = ctx.description().strip()
1151 if description:
1151 if description:
1152 if self.ui.verbose:
1152 if self.ui.verbose:
1153 self.ui.write(_("description:\n"),
1153 self.ui.write(_("description:\n"),
1154 label='ui.note log.description')
1154 label='ui.note log.description')
1155 self.ui.write(description,
1155 self.ui.write(description,
1156 label='ui.note log.description')
1156 label='ui.note log.description')
1157 self.ui.write("\n\n")
1157 self.ui.write("\n\n")
1158 else:
1158 else:
1159 # i18n: column positioning for "hg log"
1159 # i18n: column positioning for "hg log"
1160 self.ui.write(_("summary: %s\n") %
1160 self.ui.write(_("summary: %s\n") %
1161 description.splitlines()[0],
1161 description.splitlines()[0],
1162 label='log.summary')
1162 label='log.summary')
1163 self.ui.write("\n")
1163 self.ui.write("\n")
1164
1164
1165 self.showpatch(changenode, matchfn)
1165 self.showpatch(changenode, matchfn)
1166
1166
1167 def showpatch(self, node, matchfn):
1167 def showpatch(self, node, matchfn):
1168 if not matchfn:
1168 if not matchfn:
1169 matchfn = self.matchfn
1169 matchfn = self.matchfn
1170 if matchfn:
1170 if matchfn:
1171 stat = self.diffopts.get('stat')
1171 stat = self.diffopts.get('stat')
1172 diff = self.diffopts.get('patch')
1172 diff = self.diffopts.get('patch')
1173 diffopts = patch.diffallopts(self.ui, self.diffopts)
1173 diffopts = patch.diffallopts(self.ui, self.diffopts)
1174 prev = self.repo.changelog.parents(node)[0]
1174 prev = self.repo.changelog.parents(node)[0]
1175 if stat:
1175 if stat:
1176 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1176 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1177 match=matchfn, stat=True)
1177 match=matchfn, stat=True)
1178 if diff:
1178 if diff:
1179 if stat:
1179 if stat:
1180 self.ui.write("\n")
1180 self.ui.write("\n")
1181 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1181 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1182 match=matchfn, stat=False)
1182 match=matchfn, stat=False)
1183 self.ui.write("\n")
1183 self.ui.write("\n")
1184
1184
1185 def _meaningful_parentrevs(self, log, rev):
1185 def _meaningful_parentrevs(self, log, rev):
1186 """Return list of meaningful (or all if debug) parentrevs for rev.
1186 """Return list of meaningful (or all if debug) parentrevs for rev.
1187
1187
1188 For merges (two non-nullrev revisions) both parents are meaningful.
1188 For merges (two non-nullrev revisions) both parents are meaningful.
1189 Otherwise the first parent revision is considered meaningful if it
1189 Otherwise the first parent revision is considered meaningful if it
1190 is not the preceding revision.
1190 is not the preceding revision.
1191 """
1191 """
1192 parents = log.parentrevs(rev)
1192 parents = log.parentrevs(rev)
1193 if not self.ui.debugflag and parents[1] == nullrev:
1193 if not self.ui.debugflag and parents[1] == nullrev:
1194 if parents[0] >= rev - 1:
1194 if parents[0] >= rev - 1:
1195 parents = []
1195 parents = []
1196 else:
1196 else:
1197 parents = [parents[0]]
1197 parents = [parents[0]]
1198 return parents
1198 return parents
1199
1199
1200 class jsonchangeset(changeset_printer):
1200 class jsonchangeset(changeset_printer):
1201 '''format changeset information.'''
1201 '''format changeset information.'''
1202
1202
1203 def __init__(self, ui, repo, matchfn, diffopts, buffered):
1203 def __init__(self, ui, repo, matchfn, diffopts, buffered):
1204 changeset_printer.__init__(self, ui, repo, matchfn, diffopts, buffered)
1204 changeset_printer.__init__(self, ui, repo, matchfn, diffopts, buffered)
1205 self.cache = {}
1205 self.cache = {}
1206 self._first = True
1206 self._first = True
1207
1207
1208 def close(self):
1208 def close(self):
1209 if not self._first:
1209 if not self._first:
1210 self.ui.write("\n]\n")
1210 self.ui.write("\n]\n")
1211 else:
1211 else:
1212 self.ui.write("[]\n")
1212 self.ui.write("[]\n")
1213
1213
1214 def _show(self, ctx, copies, matchfn, props):
1214 def _show(self, ctx, copies, matchfn, props):
1215 '''show a single changeset or file revision'''
1215 '''show a single changeset or file revision'''
1216 hexnode = hex(ctx.node())
1216 hexnode = hex(ctx.node())
1217 rev = ctx.rev()
1217 rev = ctx.rev()
1218 j = encoding.jsonescape
1218 j = encoding.jsonescape
1219
1219
1220 if self._first:
1220 if self._first:
1221 self.ui.write("[\n {")
1221 self.ui.write("[\n {")
1222 self._first = False
1222 self._first = False
1223 else:
1223 else:
1224 self.ui.write(",\n {")
1224 self.ui.write(",\n {")
1225
1225
1226 if self.ui.quiet:
1226 if self.ui.quiet:
1227 self.ui.write('\n "rev": %d' % rev)
1227 self.ui.write('\n "rev": %d' % rev)
1228 self.ui.write(',\n "node": "%s"' % hexnode)
1228 self.ui.write(',\n "node": "%s"' % hexnode)
1229 self.ui.write('\n }')
1229 self.ui.write('\n }')
1230 return
1230 return
1231
1231
1232 self.ui.write('\n "rev": %d' % rev)
1232 self.ui.write('\n "rev": %d' % rev)
1233 self.ui.write(',\n "node": "%s"' % hexnode)
1233 self.ui.write(',\n "node": "%s"' % hexnode)
1234 self.ui.write(',\n "branch": "%s"' % j(ctx.branch()))
1234 self.ui.write(',\n "branch": "%s"' % j(ctx.branch()))
1235 self.ui.write(',\n "phase": "%s"' % ctx.phasestr())
1235 self.ui.write(',\n "phase": "%s"' % ctx.phasestr())
1236 self.ui.write(',\n "user": "%s"' % j(ctx.user()))
1236 self.ui.write(',\n "user": "%s"' % j(ctx.user()))
1237 self.ui.write(',\n "date": [%d, %d]' % ctx.date())
1237 self.ui.write(',\n "date": [%d, %d]' % ctx.date())
1238 self.ui.write(',\n "desc": "%s"' % j(ctx.description()))
1238 self.ui.write(',\n "desc": "%s"' % j(ctx.description()))
1239
1239
1240 self.ui.write(',\n "bookmarks": [%s]' %
1240 self.ui.write(',\n "bookmarks": [%s]' %
1241 ", ".join('"%s"' % j(b) for b in ctx.bookmarks()))
1241 ", ".join('"%s"' % j(b) for b in ctx.bookmarks()))
1242 self.ui.write(',\n "tags": [%s]' %
1242 self.ui.write(',\n "tags": [%s]' %
1243 ", ".join('"%s"' % j(t) for t in ctx.tags()))
1243 ", ".join('"%s"' % j(t) for t in ctx.tags()))
1244 self.ui.write(',\n "parents": [%s]' %
1244 self.ui.write(',\n "parents": [%s]' %
1245 ", ".join('"%s"' % c.hex() for c in ctx.parents()))
1245 ", ".join('"%s"' % c.hex() for c in ctx.parents()))
1246
1246
1247 if self.ui.debugflag:
1247 if self.ui.debugflag:
1248 self.ui.write(',\n "manifest": "%s"' % hex(ctx.manifestnode()))
1248 self.ui.write(',\n "manifest": "%s"' % hex(ctx.manifestnode()))
1249
1249
1250 self.ui.write(',\n "extra": {%s}' %
1250 self.ui.write(',\n "extra": {%s}' %
1251 ", ".join('"%s": "%s"' % (j(k), j(v))
1251 ", ".join('"%s": "%s"' % (j(k), j(v))
1252 for k, v in ctx.extra().items()))
1252 for k, v in ctx.extra().items()))
1253
1253
1254 files = ctx.p1().status(ctx)
1254 files = ctx.p1().status(ctx)
1255 self.ui.write(',\n "modified": [%s]' %
1255 self.ui.write(',\n "modified": [%s]' %
1256 ", ".join('"%s"' % j(f) for f in files[0]))
1256 ", ".join('"%s"' % j(f) for f in files[0]))
1257 self.ui.write(',\n "added": [%s]' %
1257 self.ui.write(',\n "added": [%s]' %
1258 ", ".join('"%s"' % j(f) for f in files[1]))
1258 ", ".join('"%s"' % j(f) for f in files[1]))
1259 self.ui.write(',\n "removed": [%s]' %
1259 self.ui.write(',\n "removed": [%s]' %
1260 ", ".join('"%s"' % j(f) for f in files[2]))
1260 ", ".join('"%s"' % j(f) for f in files[2]))
1261
1261
1262 elif self.ui.verbose:
1262 elif self.ui.verbose:
1263 self.ui.write(',\n "files": [%s]' %
1263 self.ui.write(',\n "files": [%s]' %
1264 ", ".join('"%s"' % j(f) for f in ctx.files()))
1264 ", ".join('"%s"' % j(f) for f in ctx.files()))
1265
1265
1266 if copies:
1266 if copies:
1267 self.ui.write(',\n "copies": {%s}' %
1267 self.ui.write(',\n "copies": {%s}' %
1268 ", ".join('"%s": "%s"' % (j(k), j(v))
1268 ", ".join('"%s": "%s"' % (j(k), j(v))
1269 for k, v in copies))
1269 for k, v in copies))
1270
1270
1271 matchfn = self.matchfn
1271 matchfn = self.matchfn
1272 if matchfn:
1272 if matchfn:
1273 stat = self.diffopts.get('stat')
1273 stat = self.diffopts.get('stat')
1274 diff = self.diffopts.get('patch')
1274 diff = self.diffopts.get('patch')
1275 diffopts = patch.difffeatureopts(self.ui, self.diffopts, git=True)
1275 diffopts = patch.difffeatureopts(self.ui, self.diffopts, git=True)
1276 node, prev = ctx.node(), ctx.p1().node()
1276 node, prev = ctx.node(), ctx.p1().node()
1277 if stat:
1277 if stat:
1278 self.ui.pushbuffer()
1278 self.ui.pushbuffer()
1279 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1279 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1280 match=matchfn, stat=True)
1280 match=matchfn, stat=True)
1281 self.ui.write(',\n "diffstat": "%s"' % j(self.ui.popbuffer()))
1281 self.ui.write(',\n "diffstat": "%s"' % j(self.ui.popbuffer()))
1282 if diff:
1282 if diff:
1283 self.ui.pushbuffer()
1283 self.ui.pushbuffer()
1284 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1284 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
1285 match=matchfn, stat=False)
1285 match=matchfn, stat=False)
1286 self.ui.write(',\n "diff": "%s"' % j(self.ui.popbuffer()))
1286 self.ui.write(',\n "diff": "%s"' % j(self.ui.popbuffer()))
1287
1287
1288 self.ui.write("\n }")
1288 self.ui.write("\n }")
1289
1289
1290 class changeset_templater(changeset_printer):
1290 class changeset_templater(changeset_printer):
1291 '''format changeset information.'''
1291 '''format changeset information.'''
1292
1292
1293 def __init__(self, ui, repo, matchfn, diffopts, tmpl, mapfile, buffered):
1293 def __init__(self, ui, repo, matchfn, diffopts, tmpl, mapfile, buffered):
1294 changeset_printer.__init__(self, ui, repo, matchfn, diffopts, buffered)
1294 changeset_printer.__init__(self, ui, repo, matchfn, diffopts, buffered)
1295 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
1295 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
1296 defaulttempl = {
1296 defaulttempl = {
1297 'parent': '{rev}:{node|formatnode} ',
1297 'parent': '{rev}:{node|formatnode} ',
1298 'manifest': '{rev}:{node|formatnode}',
1298 'manifest': '{rev}:{node|formatnode}',
1299 'file_copy': '{name} ({source})',
1299 'file_copy': '{name} ({source})',
1300 'extra': '{key}={value|stringescape}'
1300 'extra': '{key}={value|stringescape}'
1301 }
1301 }
1302 # filecopy is preserved for compatibility reasons
1302 # filecopy is preserved for compatibility reasons
1303 defaulttempl['filecopy'] = defaulttempl['file_copy']
1303 defaulttempl['filecopy'] = defaulttempl['file_copy']
1304 self.t = templater.templater(mapfile, {'formatnode': formatnode},
1304 self.t = templater.templater(mapfile, {'formatnode': formatnode},
1305 cache=defaulttempl)
1305 cache=defaulttempl)
1306 if tmpl:
1306 if tmpl:
1307 self.t.cache['changeset'] = tmpl
1307 self.t.cache['changeset'] = tmpl
1308
1308
1309 self.cache = {}
1309 self.cache = {}
1310
1310
1311 def _meaningful_parentrevs(self, ctx):
1311 def _meaningful_parentrevs(self, ctx):
1312 """Return list of meaningful (or all if debug) parentrevs for rev.
1312 """Return list of meaningful (or all if debug) parentrevs for rev.
1313 """
1313 """
1314 parents = ctx.parents()
1314 parents = ctx.parents()
1315 if len(parents) > 1:
1315 if len(parents) > 1:
1316 return parents
1316 return parents
1317 if self.ui.debugflag:
1317 if self.ui.debugflag:
1318 return [parents[0], self.repo['null']]
1318 return [parents[0], self.repo['null']]
1319 if parents[0].rev() >= ctx.rev() - 1:
1319 if parents[0].rev() >= ctx.rev() - 1:
1320 return []
1320 return []
1321 return parents
1321 return parents
1322
1322
1323 def _show(self, ctx, copies, matchfn, props):
1323 def _show(self, ctx, copies, matchfn, props):
1324 '''show a single changeset or file revision'''
1324 '''show a single changeset or file revision'''
1325
1325
1326 showlist = templatekw.showlist
1326 showlist = templatekw.showlist
1327
1327
1328 # showparents() behaviour depends on ui trace level which
1328 # showparents() behaviour depends on ui trace level which
1329 # causes unexpected behaviours at templating level and makes
1329 # causes unexpected behaviours at templating level and makes
1330 # it harder to extract it in a standalone function. Its
1330 # it harder to extract it in a standalone function. Its
1331 # behaviour cannot be changed so leave it here for now.
1331 # behaviour cannot be changed so leave it here for now.
1332 def showparents(**args):
1332 def showparents(**args):
1333 ctx = args['ctx']
1333 ctx = args['ctx']
1334 parents = [[('rev', p.rev()),
1334 parents = [[('rev', p.rev()),
1335 ('node', p.hex()),
1335 ('node', p.hex()),
1336 ('phase', p.phasestr())]
1336 ('phase', p.phasestr())]
1337 for p in self._meaningful_parentrevs(ctx)]
1337 for p in self._meaningful_parentrevs(ctx)]
1338 return showlist('parent', parents, **args)
1338 return showlist('parent', parents, **args)
1339
1339
1340 props = props.copy()
1340 props = props.copy()
1341 props.update(templatekw.keywords)
1341 props.update(templatekw.keywords)
1342 props['parents'] = showparents
1342 props['parents'] = showparents
1343 props['templ'] = self.t
1343 props['templ'] = self.t
1344 props['ctx'] = ctx
1344 props['ctx'] = ctx
1345 props['repo'] = self.repo
1345 props['repo'] = self.repo
1346 props['revcache'] = {'copies': copies}
1346 props['revcache'] = {'copies': copies}
1347 props['cache'] = self.cache
1347 props['cache'] = self.cache
1348
1348
1349 # find correct templates for current mode
1349 # find correct templates for current mode
1350
1350
1351 tmplmodes = [
1351 tmplmodes = [
1352 (True, None),
1352 (True, None),
1353 (self.ui.verbose, 'verbose'),
1353 (self.ui.verbose, 'verbose'),
1354 (self.ui.quiet, 'quiet'),
1354 (self.ui.quiet, 'quiet'),
1355 (self.ui.debugflag, 'debug'),
1355 (self.ui.debugflag, 'debug'),
1356 ]
1356 ]
1357
1357
1358 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
1358 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
1359 for mode, postfix in tmplmodes:
1359 for mode, postfix in tmplmodes:
1360 for type in types:
1360 for type in types:
1361 cur = postfix and ('%s_%s' % (type, postfix)) or type
1361 cur = postfix and ('%s_%s' % (type, postfix)) or type
1362 if mode and cur in self.t:
1362 if mode and cur in self.t:
1363 types[type] = cur
1363 types[type] = cur
1364
1364
1365 try:
1365 try:
1366
1366
1367 # write header
1367 # write header
1368 if types['header']:
1368 if types['header']:
1369 h = templater.stringify(self.t(types['header'], **props))
1369 h = templater.stringify(self.t(types['header'], **props))
1370 if self.buffered:
1370 if self.buffered:
1371 self.header[ctx.rev()] = h
1371 self.header[ctx.rev()] = h
1372 else:
1372 else:
1373 if self.lastheader != h:
1373 if self.lastheader != h:
1374 self.lastheader = h
1374 self.lastheader = h
1375 self.ui.write(h)
1375 self.ui.write(h)
1376
1376
1377 # write changeset metadata, then patch if requested
1377 # write changeset metadata, then patch if requested
1378 key = types['changeset']
1378 key = types['changeset']
1379 self.ui.write(templater.stringify(self.t(key, **props)))
1379 self.ui.write(templater.stringify(self.t(key, **props)))
1380 self.showpatch(ctx.node(), matchfn)
1380 self.showpatch(ctx.node(), matchfn)
1381
1381
1382 if types['footer']:
1382 if types['footer']:
1383 if not self.footer:
1383 if not self.footer:
1384 self.footer = templater.stringify(self.t(types['footer'],
1384 self.footer = templater.stringify(self.t(types['footer'],
1385 **props))
1385 **props))
1386
1386
1387 except KeyError, inst:
1387 except KeyError, inst:
1388 msg = _("%s: no key named '%s'")
1388 msg = _("%s: no key named '%s'")
1389 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
1389 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
1390 except SyntaxError, inst:
1390 except SyntaxError, inst:
1391 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
1391 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
1392
1392
1393 def gettemplate(ui, tmpl, style):
1393 def gettemplate(ui, tmpl, style):
1394 """
1394 """
1395 Find the template matching the given template spec or style.
1395 Find the template matching the given template spec or style.
1396 """
1396 """
1397
1397
1398 # ui settings
1398 # ui settings
1399 if not tmpl and not style: # template are stronger than style
1399 if not tmpl and not style: # template are stronger than style
1400 tmpl = ui.config('ui', 'logtemplate')
1400 tmpl = ui.config('ui', 'logtemplate')
1401 if tmpl:
1401 if tmpl:
1402 try:
1402 try:
1403 tmpl = templater.parsestring(tmpl)
1403 tmpl = templater.parsestring(tmpl)
1404 except SyntaxError:
1404 except SyntaxError:
1405 tmpl = templater.parsestring(tmpl, quoted=False)
1405 tmpl = templater.parsestring(tmpl, quoted=False)
1406 return tmpl, None
1406 return tmpl, None
1407 else:
1407 else:
1408 style = util.expandpath(ui.config('ui', 'style', ''))
1408 style = util.expandpath(ui.config('ui', 'style', ''))
1409
1409
1410 if not tmpl and style:
1410 if not tmpl and style:
1411 mapfile = style
1411 mapfile = style
1412 if not os.path.split(mapfile)[0]:
1412 if not os.path.split(mapfile)[0]:
1413 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1413 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1414 or templater.templatepath(mapfile))
1414 or templater.templatepath(mapfile))
1415 if mapname:
1415 if mapname:
1416 mapfile = mapname
1416 mapfile = mapname
1417 return None, mapfile
1417 return None, mapfile
1418
1418
1419 if not tmpl:
1419 if not tmpl:
1420 return None, None
1420 return None, None
1421
1421
1422 # looks like a literal template?
1422 # looks like a literal template?
1423 if '{' in tmpl:
1423 if '{' in tmpl:
1424 return tmpl, None
1424 return tmpl, None
1425
1425
1426 # perhaps a stock style?
1426 # perhaps a stock style?
1427 if not os.path.split(tmpl)[0]:
1427 if not os.path.split(tmpl)[0]:
1428 mapname = (templater.templatepath('map-cmdline.' + tmpl)
1428 mapname = (templater.templatepath('map-cmdline.' + tmpl)
1429 or templater.templatepath(tmpl))
1429 or templater.templatepath(tmpl))
1430 if mapname and os.path.isfile(mapname):
1430 if mapname and os.path.isfile(mapname):
1431 return None, mapname
1431 return None, mapname
1432
1432
1433 # perhaps it's a reference to [templates]
1433 # perhaps it's a reference to [templates]
1434 t = ui.config('templates', tmpl)
1434 t = ui.config('templates', tmpl)
1435 if t:
1435 if t:
1436 try:
1436 try:
1437 tmpl = templater.parsestring(t)
1437 tmpl = templater.parsestring(t)
1438 except SyntaxError:
1438 except SyntaxError:
1439 tmpl = templater.parsestring(t, quoted=False)
1439 tmpl = templater.parsestring(t, quoted=False)
1440 return tmpl, None
1440 return tmpl, None
1441
1441
1442 if tmpl == 'list':
1442 if tmpl == 'list':
1443 ui.write(_("available styles: %s\n") % templater.stylelist())
1443 ui.write(_("available styles: %s\n") % templater.stylelist())
1444 raise util.Abort(_("specify a template"))
1444 raise util.Abort(_("specify a template"))
1445
1445
1446 # perhaps it's a path to a map or a template
1446 # perhaps it's a path to a map or a template
1447 if ('/' in tmpl or '\\' in tmpl) and os.path.isfile(tmpl):
1447 if ('/' in tmpl or '\\' in tmpl) and os.path.isfile(tmpl):
1448 # is it a mapfile for a style?
1448 # is it a mapfile for a style?
1449 if os.path.basename(tmpl).startswith("map-"):
1449 if os.path.basename(tmpl).startswith("map-"):
1450 return None, os.path.realpath(tmpl)
1450 return None, os.path.realpath(tmpl)
1451 tmpl = open(tmpl).read()
1451 tmpl = open(tmpl).read()
1452 return tmpl, None
1452 return tmpl, None
1453
1453
1454 # constant string?
1454 # constant string?
1455 return tmpl, None
1455 return tmpl, None
1456
1456
1457 def show_changeset(ui, repo, opts, buffered=False):
1457 def show_changeset(ui, repo, opts, buffered=False):
1458 """show one changeset using template or regular display.
1458 """show one changeset using template or regular display.
1459
1459
1460 Display format will be the first non-empty hit of:
1460 Display format will be the first non-empty hit of:
1461 1. option 'template'
1461 1. option 'template'
1462 2. option 'style'
1462 2. option 'style'
1463 3. [ui] setting 'logtemplate'
1463 3. [ui] setting 'logtemplate'
1464 4. [ui] setting 'style'
1464 4. [ui] setting 'style'
1465 If all of these values are either the unset or the empty string,
1465 If all of these values are either the unset or the empty string,
1466 regular display via changeset_printer() is done.
1466 regular display via changeset_printer() is done.
1467 """
1467 """
1468 # options
1468 # options
1469 matchfn = None
1469 matchfn = None
1470 if opts.get('patch') or opts.get('stat'):
1470 if opts.get('patch') or opts.get('stat'):
1471 matchfn = scmutil.matchall(repo)
1471 matchfn = scmutil.matchall(repo)
1472
1472
1473 if opts.get('template') == 'json':
1473 if opts.get('template') == 'json':
1474 return jsonchangeset(ui, repo, matchfn, opts, buffered)
1474 return jsonchangeset(ui, repo, matchfn, opts, buffered)
1475
1475
1476 tmpl, mapfile = gettemplate(ui, opts.get('template'), opts.get('style'))
1476 tmpl, mapfile = gettemplate(ui, opts.get('template'), opts.get('style'))
1477
1477
1478 if not tmpl and not mapfile:
1478 if not tmpl and not mapfile:
1479 return changeset_printer(ui, repo, matchfn, opts, buffered)
1479 return changeset_printer(ui, repo, matchfn, opts, buffered)
1480
1480
1481 try:
1481 try:
1482 t = changeset_templater(ui, repo, matchfn, opts, tmpl, mapfile,
1482 t = changeset_templater(ui, repo, matchfn, opts, tmpl, mapfile,
1483 buffered)
1483 buffered)
1484 except SyntaxError, inst:
1484 except SyntaxError, inst:
1485 raise util.Abort(inst.args[0])
1485 raise util.Abort(inst.args[0])
1486 return t
1486 return t
1487
1487
1488 def showmarker(ui, marker):
1488 def showmarker(ui, marker):
1489 """utility function to display obsolescence marker in a readable way
1489 """utility function to display obsolescence marker in a readable way
1490
1490
1491 To be used by debug function."""
1491 To be used by debug function."""
1492 ui.write(hex(marker.precnode()))
1492 ui.write(hex(marker.precnode()))
1493 for repl in marker.succnodes():
1493 for repl in marker.succnodes():
1494 ui.write(' ')
1494 ui.write(' ')
1495 ui.write(hex(repl))
1495 ui.write(hex(repl))
1496 ui.write(' %X ' % marker.flags())
1496 ui.write(' %X ' % marker.flags())
1497 parents = marker.parentnodes()
1497 parents = marker.parentnodes()
1498 if parents is not None:
1498 if parents is not None:
1499 ui.write('{%s} ' % ', '.join(hex(p) for p in parents))
1499 ui.write('{%s} ' % ', '.join(hex(p) for p in parents))
1500 ui.write('(%s) ' % util.datestr(marker.date()))
1500 ui.write('(%s) ' % util.datestr(marker.date()))
1501 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
1501 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
1502 sorted(marker.metadata().items())
1502 sorted(marker.metadata().items())
1503 if t[0] != 'date')))
1503 if t[0] != 'date')))
1504 ui.write('\n')
1504 ui.write('\n')
1505
1505
1506 def finddate(ui, repo, date):
1506 def finddate(ui, repo, date):
1507 """Find the tipmost changeset that matches the given date spec"""
1507 """Find the tipmost changeset that matches the given date spec"""
1508
1508
1509 df = util.matchdate(date)
1509 df = util.matchdate(date)
1510 m = scmutil.matchall(repo)
1510 m = scmutil.matchall(repo)
1511 results = {}
1511 results = {}
1512
1512
1513 def prep(ctx, fns):
1513 def prep(ctx, fns):
1514 d = ctx.date()
1514 d = ctx.date()
1515 if df(d[0]):
1515 if df(d[0]):
1516 results[ctx.rev()] = d
1516 results[ctx.rev()] = d
1517
1517
1518 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1518 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1519 rev = ctx.rev()
1519 rev = ctx.rev()
1520 if rev in results:
1520 if rev in results:
1521 ui.status(_("found revision %s from %s\n") %
1521 ui.status(_("found revision %s from %s\n") %
1522 (rev, util.datestr(results[rev])))
1522 (rev, util.datestr(results[rev])))
1523 return str(rev)
1523 return str(rev)
1524
1524
1525 raise util.Abort(_("revision matching date not found"))
1525 raise util.Abort(_("revision matching date not found"))
1526
1526
1527 def increasingwindows(windowsize=8, sizelimit=512):
1527 def increasingwindows(windowsize=8, sizelimit=512):
1528 while True:
1528 while True:
1529 yield windowsize
1529 yield windowsize
1530 if windowsize < sizelimit:
1530 if windowsize < sizelimit:
1531 windowsize *= 2
1531 windowsize *= 2
1532
1532
1533 class FileWalkError(Exception):
1533 class FileWalkError(Exception):
1534 pass
1534 pass
1535
1535
1536 def walkfilerevs(repo, match, follow, revs, fncache):
1536 def walkfilerevs(repo, match, follow, revs, fncache):
1537 '''Walks the file history for the matched files.
1537 '''Walks the file history for the matched files.
1538
1538
1539 Returns the changeset revs that are involved in the file history.
1539 Returns the changeset revs that are involved in the file history.
1540
1540
1541 Throws FileWalkError if the file history can't be walked using
1541 Throws FileWalkError if the file history can't be walked using
1542 filelogs alone.
1542 filelogs alone.
1543 '''
1543 '''
1544 wanted = set()
1544 wanted = set()
1545 copies = []
1545 copies = []
1546 minrev, maxrev = min(revs), max(revs)
1546 minrev, maxrev = min(revs), max(revs)
1547 def filerevgen(filelog, last):
1547 def filerevgen(filelog, last):
1548 """
1548 """
1549 Only files, no patterns. Check the history of each file.
1549 Only files, no patterns. Check the history of each file.
1550
1550
1551 Examines filelog entries within minrev, maxrev linkrev range
1551 Examines filelog entries within minrev, maxrev linkrev range
1552 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1552 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1553 tuples in backwards order
1553 tuples in backwards order
1554 """
1554 """
1555 cl_count = len(repo)
1555 cl_count = len(repo)
1556 revs = []
1556 revs = []
1557 for j in xrange(0, last + 1):
1557 for j in xrange(0, last + 1):
1558 linkrev = filelog.linkrev(j)
1558 linkrev = filelog.linkrev(j)
1559 if linkrev < minrev:
1559 if linkrev < minrev:
1560 continue
1560 continue
1561 # only yield rev for which we have the changelog, it can
1561 # only yield rev for which we have the changelog, it can
1562 # happen while doing "hg log" during a pull or commit
1562 # happen while doing "hg log" during a pull or commit
1563 if linkrev >= cl_count:
1563 if linkrev >= cl_count:
1564 break
1564 break
1565
1565
1566 parentlinkrevs = []
1566 parentlinkrevs = []
1567 for p in filelog.parentrevs(j):
1567 for p in filelog.parentrevs(j):
1568 if p != nullrev:
1568 if p != nullrev:
1569 parentlinkrevs.append(filelog.linkrev(p))
1569 parentlinkrevs.append(filelog.linkrev(p))
1570 n = filelog.node(j)
1570 n = filelog.node(j)
1571 revs.append((linkrev, parentlinkrevs,
1571 revs.append((linkrev, parentlinkrevs,
1572 follow and filelog.renamed(n)))
1572 follow and filelog.renamed(n)))
1573
1573
1574 return reversed(revs)
1574 return reversed(revs)
1575 def iterfiles():
1575 def iterfiles():
1576 pctx = repo['.']
1576 pctx = repo['.']
1577 for filename in match.files():
1577 for filename in match.files():
1578 if follow:
1578 if follow:
1579 if filename not in pctx:
1579 if filename not in pctx:
1580 raise util.Abort(_('cannot follow file not in parent '
1580 raise util.Abort(_('cannot follow file not in parent '
1581 'revision: "%s"') % filename)
1581 'revision: "%s"') % filename)
1582 yield filename, pctx[filename].filenode()
1582 yield filename, pctx[filename].filenode()
1583 else:
1583 else:
1584 yield filename, None
1584 yield filename, None
1585 for filename_node in copies:
1585 for filename_node in copies:
1586 yield filename_node
1586 yield filename_node
1587
1587
1588 for file_, node in iterfiles():
1588 for file_, node in iterfiles():
1589 filelog = repo.file(file_)
1589 filelog = repo.file(file_)
1590 if not len(filelog):
1590 if not len(filelog):
1591 if node is None:
1591 if node is None:
1592 # A zero count may be a directory or deleted file, so
1592 # A zero count may be a directory or deleted file, so
1593 # try to find matching entries on the slow path.
1593 # try to find matching entries on the slow path.
1594 if follow:
1594 if follow:
1595 raise util.Abort(
1595 raise util.Abort(
1596 _('cannot follow nonexistent file: "%s"') % file_)
1596 _('cannot follow nonexistent file: "%s"') % file_)
1597 raise FileWalkError("Cannot walk via filelog")
1597 raise FileWalkError("Cannot walk via filelog")
1598 else:
1598 else:
1599 continue
1599 continue
1600
1600
1601 if node is None:
1601 if node is None:
1602 last = len(filelog) - 1
1602 last = len(filelog) - 1
1603 else:
1603 else:
1604 last = filelog.rev(node)
1604 last = filelog.rev(node)
1605
1605
1606
1606
1607 # keep track of all ancestors of the file
1607 # keep track of all ancestors of the file
1608 ancestors = set([filelog.linkrev(last)])
1608 ancestors = set([filelog.linkrev(last)])
1609
1609
1610 # iterate from latest to oldest revision
1610 # iterate from latest to oldest revision
1611 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1611 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1612 if not follow:
1612 if not follow:
1613 if rev > maxrev:
1613 if rev > maxrev:
1614 continue
1614 continue
1615 else:
1615 else:
1616 # Note that last might not be the first interesting
1616 # Note that last might not be the first interesting
1617 # rev to us:
1617 # rev to us:
1618 # if the file has been changed after maxrev, we'll
1618 # if the file has been changed after maxrev, we'll
1619 # have linkrev(last) > maxrev, and we still need
1619 # have linkrev(last) > maxrev, and we still need
1620 # to explore the file graph
1620 # to explore the file graph
1621 if rev not in ancestors:
1621 if rev not in ancestors:
1622 continue
1622 continue
1623 # XXX insert 1327 fix here
1623 # XXX insert 1327 fix here
1624 if flparentlinkrevs:
1624 if flparentlinkrevs:
1625 ancestors.update(flparentlinkrevs)
1625 ancestors.update(flparentlinkrevs)
1626
1626
1627 fncache.setdefault(rev, []).append(file_)
1627 fncache.setdefault(rev, []).append(file_)
1628 wanted.add(rev)
1628 wanted.add(rev)
1629 if copied:
1629 if copied:
1630 copies.append(copied)
1630 copies.append(copied)
1631
1631
1632 return wanted
1632 return wanted
1633
1633
1634 def walkchangerevs(repo, match, opts, prepare):
1634 def walkchangerevs(repo, match, opts, prepare):
1635 '''Iterate over files and the revs in which they changed.
1635 '''Iterate over files and the revs in which they changed.
1636
1636
1637 Callers most commonly need to iterate backwards over the history
1637 Callers most commonly need to iterate backwards over the history
1638 in which they are interested. Doing so has awful (quadratic-looking)
1638 in which they are interested. Doing so has awful (quadratic-looking)
1639 performance, so we use iterators in a "windowed" way.
1639 performance, so we use iterators in a "windowed" way.
1640
1640
1641 We walk a window of revisions in the desired order. Within the
1641 We walk a window of revisions in the desired order. Within the
1642 window, we first walk forwards to gather data, then in the desired
1642 window, we first walk forwards to gather data, then in the desired
1643 order (usually backwards) to display it.
1643 order (usually backwards) to display it.
1644
1644
1645 This function returns an iterator yielding contexts. Before
1645 This function returns an iterator yielding contexts. Before
1646 yielding each context, the iterator will first call the prepare
1646 yielding each context, the iterator will first call the prepare
1647 function on each context in the window in forward order.'''
1647 function on each context in the window in forward order.'''
1648
1648
1649 follow = opts.get('follow') or opts.get('follow_first')
1649 follow = opts.get('follow') or opts.get('follow_first')
1650 revs = _logrevs(repo, opts)
1650 revs = _logrevs(repo, opts)
1651 if not revs:
1651 if not revs:
1652 return []
1652 return []
1653 wanted = set()
1653 wanted = set()
1654 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1654 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1655 fncache = {}
1655 fncache = {}
1656 change = repo.changectx
1656 change = repo.changectx
1657
1657
1658 # First step is to fill wanted, the set of revisions that we want to yield.
1658 # First step is to fill wanted, the set of revisions that we want to yield.
1659 # When it does not induce extra cost, we also fill fncache for revisions in
1659 # When it does not induce extra cost, we also fill fncache for revisions in
1660 # wanted: a cache of filenames that were changed (ctx.files()) and that
1660 # wanted: a cache of filenames that were changed (ctx.files()) and that
1661 # match the file filtering conditions.
1661 # match the file filtering conditions.
1662
1662
1663 if not slowpath and not match.files():
1663 if not slowpath and not match.files():
1664 # No files, no patterns. Display all revs.
1664 # No files, no patterns. Display all revs.
1665 wanted = revs
1665 wanted = revs
1666
1666
1667 if not slowpath and match.files():
1667 if not slowpath and match.files():
1668 # We only have to read through the filelog to find wanted revisions
1668 # We only have to read through the filelog to find wanted revisions
1669
1669
1670 try:
1670 try:
1671 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1671 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1672 except FileWalkError:
1672 except FileWalkError:
1673 slowpath = True
1673 slowpath = True
1674
1674
1675 # We decided to fall back to the slowpath because at least one
1675 # We decided to fall back to the slowpath because at least one
1676 # of the paths was not a file. Check to see if at least one of them
1676 # of the paths was not a file. Check to see if at least one of them
1677 # existed in history, otherwise simply return
1677 # existed in history, otherwise simply return
1678 for path in match.files():
1678 for path in match.files():
1679 if path == '.' or path in repo.store:
1679 if path == '.' or path in repo.store:
1680 break
1680 break
1681 else:
1681 else:
1682 return []
1682 return []
1683
1683
1684 if slowpath:
1684 if slowpath:
1685 # We have to read the changelog to match filenames against
1685 # We have to read the changelog to match filenames against
1686 # changed files
1686 # changed files
1687
1687
1688 if follow:
1688 if follow:
1689 raise util.Abort(_('can only follow copies/renames for explicit '
1689 raise util.Abort(_('can only follow copies/renames for explicit '
1690 'filenames'))
1690 'filenames'))
1691
1691
1692 # The slow path checks files modified in every changeset.
1692 # The slow path checks files modified in every changeset.
1693 # This is really slow on large repos, so compute the set lazily.
1693 # This is really slow on large repos, so compute the set lazily.
1694 class lazywantedset(object):
1694 class lazywantedset(object):
1695 def __init__(self):
1695 def __init__(self):
1696 self.set = set()
1696 self.set = set()
1697 self.revs = set(revs)
1697 self.revs = set(revs)
1698
1698
1699 # No need to worry about locality here because it will be accessed
1699 # No need to worry about locality here because it will be accessed
1700 # in the same order as the increasing window below.
1700 # in the same order as the increasing window below.
1701 def __contains__(self, value):
1701 def __contains__(self, value):
1702 if value in self.set:
1702 if value in self.set:
1703 return True
1703 return True
1704 elif not value in self.revs:
1704 elif not value in self.revs:
1705 return False
1705 return False
1706 else:
1706 else:
1707 self.revs.discard(value)
1707 self.revs.discard(value)
1708 ctx = change(value)
1708 ctx = change(value)
1709 matches = filter(match, ctx.files())
1709 matches = filter(match, ctx.files())
1710 if matches:
1710 if matches:
1711 fncache[value] = matches
1711 fncache[value] = matches
1712 self.set.add(value)
1712 self.set.add(value)
1713 return True
1713 return True
1714 return False
1714 return False
1715
1715
1716 def discard(self, value):
1716 def discard(self, value):
1717 self.revs.discard(value)
1717 self.revs.discard(value)
1718 self.set.discard(value)
1718 self.set.discard(value)
1719
1719
1720 wanted = lazywantedset()
1720 wanted = lazywantedset()
1721
1721
1722 class followfilter(object):
1722 class followfilter(object):
1723 def __init__(self, onlyfirst=False):
1723 def __init__(self, onlyfirst=False):
1724 self.startrev = nullrev
1724 self.startrev = nullrev
1725 self.roots = set()
1725 self.roots = set()
1726 self.onlyfirst = onlyfirst
1726 self.onlyfirst = onlyfirst
1727
1727
1728 def match(self, rev):
1728 def match(self, rev):
1729 def realparents(rev):
1729 def realparents(rev):
1730 if self.onlyfirst:
1730 if self.onlyfirst:
1731 return repo.changelog.parentrevs(rev)[0:1]
1731 return repo.changelog.parentrevs(rev)[0:1]
1732 else:
1732 else:
1733 return filter(lambda x: x != nullrev,
1733 return filter(lambda x: x != nullrev,
1734 repo.changelog.parentrevs(rev))
1734 repo.changelog.parentrevs(rev))
1735
1735
1736 if self.startrev == nullrev:
1736 if self.startrev == nullrev:
1737 self.startrev = rev
1737 self.startrev = rev
1738 return True
1738 return True
1739
1739
1740 if rev > self.startrev:
1740 if rev > self.startrev:
1741 # forward: all descendants
1741 # forward: all descendants
1742 if not self.roots:
1742 if not self.roots:
1743 self.roots.add(self.startrev)
1743 self.roots.add(self.startrev)
1744 for parent in realparents(rev):
1744 for parent in realparents(rev):
1745 if parent in self.roots:
1745 if parent in self.roots:
1746 self.roots.add(rev)
1746 self.roots.add(rev)
1747 return True
1747 return True
1748 else:
1748 else:
1749 # backwards: all parents
1749 # backwards: all parents
1750 if not self.roots:
1750 if not self.roots:
1751 self.roots.update(realparents(self.startrev))
1751 self.roots.update(realparents(self.startrev))
1752 if rev in self.roots:
1752 if rev in self.roots:
1753 self.roots.remove(rev)
1753 self.roots.remove(rev)
1754 self.roots.update(realparents(rev))
1754 self.roots.update(realparents(rev))
1755 return True
1755 return True
1756
1756
1757 return False
1757 return False
1758
1758
1759 # it might be worthwhile to do this in the iterator if the rev range
1759 # it might be worthwhile to do this in the iterator if the rev range
1760 # is descending and the prune args are all within that range
1760 # is descending and the prune args are all within that range
1761 for rev in opts.get('prune', ()):
1761 for rev in opts.get('prune', ()):
1762 rev = repo[rev].rev()
1762 rev = repo[rev].rev()
1763 ff = followfilter()
1763 ff = followfilter()
1764 stop = min(revs[0], revs[-1])
1764 stop = min(revs[0], revs[-1])
1765 for x in xrange(rev, stop - 1, -1):
1765 for x in xrange(rev, stop - 1, -1):
1766 if ff.match(x):
1766 if ff.match(x):
1767 wanted = wanted - [x]
1767 wanted = wanted - [x]
1768
1768
1769 # Now that wanted is correctly initialized, we can iterate over the
1769 # Now that wanted is correctly initialized, we can iterate over the
1770 # revision range, yielding only revisions in wanted.
1770 # revision range, yielding only revisions in wanted.
1771 def iterate():
1771 def iterate():
1772 if follow and not match.files():
1772 if follow and not match.files():
1773 ff = followfilter(onlyfirst=opts.get('follow_first'))
1773 ff = followfilter(onlyfirst=opts.get('follow_first'))
1774 def want(rev):
1774 def want(rev):
1775 return ff.match(rev) and rev in wanted
1775 return ff.match(rev) and rev in wanted
1776 else:
1776 else:
1777 def want(rev):
1777 def want(rev):
1778 return rev in wanted
1778 return rev in wanted
1779
1779
1780 it = iter(revs)
1780 it = iter(revs)
1781 stopiteration = False
1781 stopiteration = False
1782 for windowsize in increasingwindows():
1782 for windowsize in increasingwindows():
1783 nrevs = []
1783 nrevs = []
1784 for i in xrange(windowsize):
1784 for i in xrange(windowsize):
1785 try:
1785 try:
1786 rev = it.next()
1786 rev = it.next()
1787 if want(rev):
1787 if want(rev):
1788 nrevs.append(rev)
1788 nrevs.append(rev)
1789 except (StopIteration):
1789 except (StopIteration):
1790 stopiteration = True
1790 stopiteration = True
1791 break
1791 break
1792 for rev in sorted(nrevs):
1792 for rev in sorted(nrevs):
1793 fns = fncache.get(rev)
1793 fns = fncache.get(rev)
1794 ctx = change(rev)
1794 ctx = change(rev)
1795 if not fns:
1795 if not fns:
1796 def fns_generator():
1796 def fns_generator():
1797 for f in ctx.files():
1797 for f in ctx.files():
1798 if match(f):
1798 if match(f):
1799 yield f
1799 yield f
1800 fns = fns_generator()
1800 fns = fns_generator()
1801 prepare(ctx, fns)
1801 prepare(ctx, fns)
1802 for rev in nrevs:
1802 for rev in nrevs:
1803 yield change(rev)
1803 yield change(rev)
1804
1804
1805 if stopiteration:
1805 if stopiteration:
1806 break
1806 break
1807
1807
1808 return iterate()
1808 return iterate()
1809
1809
1810 def _makefollowlogfilematcher(repo, files, followfirst):
1810 def _makefollowlogfilematcher(repo, files, followfirst):
1811 # When displaying a revision with --patch --follow FILE, we have
1811 # When displaying a revision with --patch --follow FILE, we have
1812 # to know which file of the revision must be diffed. With
1812 # to know which file of the revision must be diffed. With
1813 # --follow, we want the names of the ancestors of FILE in the
1813 # --follow, we want the names of the ancestors of FILE in the
1814 # revision, stored in "fcache". "fcache" is populated by
1814 # revision, stored in "fcache". "fcache" is populated by
1815 # reproducing the graph traversal already done by --follow revset
1815 # reproducing the graph traversal already done by --follow revset
1816 # and relating linkrevs to file names (which is not "correct" but
1816 # and relating linkrevs to file names (which is not "correct" but
1817 # good enough).
1817 # good enough).
1818 fcache = {}
1818 fcache = {}
1819 fcacheready = [False]
1819 fcacheready = [False]
1820 pctx = repo['.']
1820 pctx = repo['.']
1821
1821
1822 def populate():
1822 def populate():
1823 for fn in files:
1823 for fn in files:
1824 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1824 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1825 for c in i:
1825 for c in i:
1826 fcache.setdefault(c.linkrev(), set()).add(c.path())
1826 fcache.setdefault(c.linkrev(), set()).add(c.path())
1827
1827
1828 def filematcher(rev):
1828 def filematcher(rev):
1829 if not fcacheready[0]:
1829 if not fcacheready[0]:
1830 # Lazy initialization
1830 # Lazy initialization
1831 fcacheready[0] = True
1831 fcacheready[0] = True
1832 populate()
1832 populate()
1833 return scmutil.matchfiles(repo, fcache.get(rev, []))
1833 return scmutil.matchfiles(repo, fcache.get(rev, []))
1834
1834
1835 return filematcher
1835 return filematcher
1836
1836
1837 def _makenofollowlogfilematcher(repo, pats, opts):
1837 def _makenofollowlogfilematcher(repo, pats, opts):
1838 '''hook for extensions to override the filematcher for non-follow cases'''
1838 '''hook for extensions to override the filematcher for non-follow cases'''
1839 return None
1839 return None
1840
1840
1841 def _makelogrevset(repo, pats, opts, revs):
1841 def _makelogrevset(repo, pats, opts, revs):
1842 """Return (expr, filematcher) where expr is a revset string built
1842 """Return (expr, filematcher) where expr is a revset string built
1843 from log options and file patterns or None. If --stat or --patch
1843 from log options and file patterns or None. If --stat or --patch
1844 are not passed filematcher is None. Otherwise it is a callable
1844 are not passed filematcher is None. Otherwise it is a callable
1845 taking a revision number and returning a match objects filtering
1845 taking a revision number and returning a match objects filtering
1846 the files to be detailed when displaying the revision.
1846 the files to be detailed when displaying the revision.
1847 """
1847 """
1848 opt2revset = {
1848 opt2revset = {
1849 'no_merges': ('not merge()', None),
1849 'no_merges': ('not merge()', None),
1850 'only_merges': ('merge()', None),
1850 'only_merges': ('merge()', None),
1851 '_ancestors': ('ancestors(%(val)s)', None),
1851 '_ancestors': ('ancestors(%(val)s)', None),
1852 '_fancestors': ('_firstancestors(%(val)s)', None),
1852 '_fancestors': ('_firstancestors(%(val)s)', None),
1853 '_descendants': ('descendants(%(val)s)', None),
1853 '_descendants': ('descendants(%(val)s)', None),
1854 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1854 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1855 '_matchfiles': ('_matchfiles(%(val)s)', None),
1855 '_matchfiles': ('_matchfiles(%(val)s)', None),
1856 'date': ('date(%(val)r)', None),
1856 'date': ('date(%(val)r)', None),
1857 'branch': ('branch(%(val)r)', ' or '),
1857 'branch': ('branch(%(val)r)', ' or '),
1858 '_patslog': ('filelog(%(val)r)', ' or '),
1858 '_patslog': ('filelog(%(val)r)', ' or '),
1859 '_patsfollow': ('follow(%(val)r)', ' or '),
1859 '_patsfollow': ('follow(%(val)r)', ' or '),
1860 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1860 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1861 'keyword': ('keyword(%(val)r)', ' or '),
1861 'keyword': ('keyword(%(val)r)', ' or '),
1862 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1862 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1863 'user': ('user(%(val)r)', ' or '),
1863 'user': ('user(%(val)r)', ' or '),
1864 }
1864 }
1865
1865
1866 opts = dict(opts)
1866 opts = dict(opts)
1867 # follow or not follow?
1867 # follow or not follow?
1868 follow = opts.get('follow') or opts.get('follow_first')
1868 follow = opts.get('follow') or opts.get('follow_first')
1869 followfirst = opts.get('follow_first') and 1 or 0
1869 followfirst = opts.get('follow_first') and 1 or 0
1870 # --follow with FILE behaviour depends on revs...
1870 # --follow with FILE behaviour depends on revs...
1871 it = iter(revs)
1871 it = iter(revs)
1872 startrev = it.next()
1872 startrev = it.next()
1873 try:
1873 try:
1874 followdescendants = startrev < it.next()
1874 followdescendants = startrev < it.next()
1875 except (StopIteration):
1875 except (StopIteration):
1876 followdescendants = False
1876 followdescendants = False
1877
1877
1878 # branch and only_branch are really aliases and must be handled at
1878 # branch and only_branch are really aliases and must be handled at
1879 # the same time
1879 # the same time
1880 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1880 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1881 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1881 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1882 # pats/include/exclude are passed to match.match() directly in
1882 # pats/include/exclude are passed to match.match() directly in
1883 # _matchfiles() revset but walkchangerevs() builds its matcher with
1883 # _matchfiles() revset but walkchangerevs() builds its matcher with
1884 # scmutil.match(). The difference is input pats are globbed on
1884 # scmutil.match(). The difference is input pats are globbed on
1885 # platforms without shell expansion (windows).
1885 # platforms without shell expansion (windows).
1886 pctx = repo[None]
1886 pctx = repo[None]
1887 match, pats = scmutil.matchandpats(pctx, pats, opts)
1887 match, pats = scmutil.matchandpats(pctx, pats, opts)
1888 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1888 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1889 if not slowpath:
1889 if not slowpath:
1890 for f in match.files():
1890 for f in match.files():
1891 if follow and f not in pctx:
1891 if follow and f not in pctx:
1892 # If the file exists, it may be a directory, so let it
1892 # If the file exists, it may be a directory, so let it
1893 # take the slow path.
1893 # take the slow path.
1894 if os.path.exists(repo.wjoin(f)):
1894 if os.path.exists(repo.wjoin(f)):
1895 slowpath = True
1895 slowpath = True
1896 continue
1896 continue
1897 else:
1897 else:
1898 raise util.Abort(_('cannot follow file not in parent '
1898 raise util.Abort(_('cannot follow file not in parent '
1899 'revision: "%s"') % f)
1899 'revision: "%s"') % f)
1900 filelog = repo.file(f)
1900 filelog = repo.file(f)
1901 if not filelog:
1901 if not filelog:
1902 # A zero count may be a directory or deleted file, so
1902 # A zero count may be a directory or deleted file, so
1903 # try to find matching entries on the slow path.
1903 # try to find matching entries on the slow path.
1904 if follow:
1904 if follow:
1905 raise util.Abort(
1905 raise util.Abort(
1906 _('cannot follow nonexistent file: "%s"') % f)
1906 _('cannot follow nonexistent file: "%s"') % f)
1907 slowpath = True
1907 slowpath = True
1908
1908
1909 # We decided to fall back to the slowpath because at least one
1909 # We decided to fall back to the slowpath because at least one
1910 # of the paths was not a file. Check to see if at least one of them
1910 # of the paths was not a file. Check to see if at least one of them
1911 # existed in history - in that case, we'll continue down the
1911 # existed in history - in that case, we'll continue down the
1912 # slowpath; otherwise, we can turn off the slowpath
1912 # slowpath; otherwise, we can turn off the slowpath
1913 if slowpath:
1913 if slowpath:
1914 for path in match.files():
1914 for path in match.files():
1915 if path == '.' or path in repo.store:
1915 if path == '.' or path in repo.store:
1916 break
1916 break
1917 else:
1917 else:
1918 slowpath = False
1918 slowpath = False
1919
1919
1920 fpats = ('_patsfollow', '_patsfollowfirst')
1920 fpats = ('_patsfollow', '_patsfollowfirst')
1921 fnopats = (('_ancestors', '_fancestors'),
1921 fnopats = (('_ancestors', '_fancestors'),
1922 ('_descendants', '_fdescendants'))
1922 ('_descendants', '_fdescendants'))
1923 if slowpath:
1923 if slowpath:
1924 # See walkchangerevs() slow path.
1924 # See walkchangerevs() slow path.
1925 #
1925 #
1926 # pats/include/exclude cannot be represented as separate
1926 # pats/include/exclude cannot be represented as separate
1927 # revset expressions as their filtering logic applies at file
1927 # revset expressions as their filtering logic applies at file
1928 # level. For instance "-I a -X a" matches a revision touching
1928 # level. For instance "-I a -X a" matches a revision touching
1929 # "a" and "b" while "file(a) and not file(b)" does
1929 # "a" and "b" while "file(a) and not file(b)" does
1930 # not. Besides, filesets are evaluated against the working
1930 # not. Besides, filesets are evaluated against the working
1931 # directory.
1931 # directory.
1932 matchargs = ['r:', 'd:relpath']
1932 matchargs = ['r:', 'd:relpath']
1933 for p in pats:
1933 for p in pats:
1934 matchargs.append('p:' + p)
1934 matchargs.append('p:' + p)
1935 for p in opts.get('include', []):
1935 for p in opts.get('include', []):
1936 matchargs.append('i:' + p)
1936 matchargs.append('i:' + p)
1937 for p in opts.get('exclude', []):
1937 for p in opts.get('exclude', []):
1938 matchargs.append('x:' + p)
1938 matchargs.append('x:' + p)
1939 matchargs = ','.join(('%r' % p) for p in matchargs)
1939 matchargs = ','.join(('%r' % p) for p in matchargs)
1940 opts['_matchfiles'] = matchargs
1940 opts['_matchfiles'] = matchargs
1941 if follow:
1941 if follow:
1942 opts[fnopats[0][followfirst]] = '.'
1942 opts[fnopats[0][followfirst]] = '.'
1943 else:
1943 else:
1944 if follow:
1944 if follow:
1945 if pats:
1945 if pats:
1946 # follow() revset interprets its file argument as a
1946 # follow() revset interprets its file argument as a
1947 # manifest entry, so use match.files(), not pats.
1947 # manifest entry, so use match.files(), not pats.
1948 opts[fpats[followfirst]] = list(match.files())
1948 opts[fpats[followfirst]] = list(match.files())
1949 else:
1949 else:
1950 op = fnopats[followdescendants][followfirst]
1950 op = fnopats[followdescendants][followfirst]
1951 opts[op] = 'rev(%d)' % startrev
1951 opts[op] = 'rev(%d)' % startrev
1952 else:
1952 else:
1953 opts['_patslog'] = list(pats)
1953 opts['_patslog'] = list(pats)
1954
1954
1955 filematcher = None
1955 filematcher = None
1956 if opts.get('patch') or opts.get('stat'):
1956 if opts.get('patch') or opts.get('stat'):
1957 # When following files, track renames via a special matcher.
1957 # When following files, track renames via a special matcher.
1958 # If we're forced to take the slowpath it means we're following
1958 # If we're forced to take the slowpath it means we're following
1959 # at least one pattern/directory, so don't bother with rename tracking.
1959 # at least one pattern/directory, so don't bother with rename tracking.
1960 if follow and not match.always() and not slowpath:
1960 if follow and not match.always() and not slowpath:
1961 # _makefollowlogfilematcher expects its files argument to be
1961 # _makefollowlogfilematcher expects its files argument to be
1962 # relative to the repo root, so use match.files(), not pats.
1962 # relative to the repo root, so use match.files(), not pats.
1963 filematcher = _makefollowlogfilematcher(repo, match.files(),
1963 filematcher = _makefollowlogfilematcher(repo, match.files(),
1964 followfirst)
1964 followfirst)
1965 else:
1965 else:
1966 filematcher = _makenofollowlogfilematcher(repo, pats, opts)
1966 filematcher = _makenofollowlogfilematcher(repo, pats, opts)
1967 if filematcher is None:
1967 if filematcher is None:
1968 filematcher = lambda rev: match
1968 filematcher = lambda rev: match
1969
1969
1970 expr = []
1970 expr = []
1971 for op, val in sorted(opts.iteritems()):
1971 for op, val in sorted(opts.iteritems()):
1972 if not val:
1972 if not val:
1973 continue
1973 continue
1974 if op not in opt2revset:
1974 if op not in opt2revset:
1975 continue
1975 continue
1976 revop, andor = opt2revset[op]
1976 revop, andor = opt2revset[op]
1977 if '%(val)' not in revop:
1977 if '%(val)' not in revop:
1978 expr.append(revop)
1978 expr.append(revop)
1979 else:
1979 else:
1980 if not isinstance(val, list):
1980 if not isinstance(val, list):
1981 e = revop % {'val': val}
1981 e = revop % {'val': val}
1982 else:
1982 else:
1983 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1983 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1984 expr.append(e)
1984 expr.append(e)
1985
1985
1986 if expr:
1986 if expr:
1987 expr = '(' + ' and '.join(expr) + ')'
1987 expr = '(' + ' and '.join(expr) + ')'
1988 else:
1988 else:
1989 expr = None
1989 expr = None
1990 return expr, filematcher
1990 return expr, filematcher
1991
1991
1992 def _logrevs(repo, opts):
1992 def _logrevs(repo, opts):
1993 # Default --rev value depends on --follow but --follow behaviour
1993 # Default --rev value depends on --follow but --follow behaviour
1994 # depends on revisions resolved from --rev...
1994 # depends on revisions resolved from --rev...
1995 follow = opts.get('follow') or opts.get('follow_first')
1995 follow = opts.get('follow') or opts.get('follow_first')
1996 if opts.get('rev'):
1996 if opts.get('rev'):
1997 revs = scmutil.revrange(repo, opts['rev'])
1997 revs = scmutil.revrange(repo, opts['rev'])
1998 elif follow and repo.dirstate.p1() == nullid:
1998 elif follow and repo.dirstate.p1() == nullid:
1999 revs = revset.baseset()
1999 revs = revset.baseset()
2000 elif follow:
2000 elif follow:
2001 revs = repo.revs('reverse(:.)')
2001 revs = repo.revs('reverse(:.)')
2002 else:
2002 else:
2003 revs = revset.spanset(repo)
2003 revs = revset.spanset(repo)
2004 revs.reverse()
2004 revs.reverse()
2005 return revs
2005 return revs
2006
2006
2007 def getgraphlogrevs(repo, pats, opts):
2007 def getgraphlogrevs(repo, pats, opts):
2008 """Return (revs, expr, filematcher) where revs is an iterable of
2008 """Return (revs, expr, filematcher) where revs is an iterable of
2009 revision numbers, expr is a revset string built from log options
2009 revision numbers, expr is a revset string built from log options
2010 and file patterns or None, and used to filter 'revs'. If --stat or
2010 and file patterns or None, and used to filter 'revs'. If --stat or
2011 --patch are not passed filematcher is None. Otherwise it is a
2011 --patch are not passed filematcher is None. Otherwise it is a
2012 callable taking a revision number and returning a match objects
2012 callable taking a revision number and returning a match objects
2013 filtering the files to be detailed when displaying the revision.
2013 filtering the files to be detailed when displaying the revision.
2014 """
2014 """
2015 limit = loglimit(opts)
2015 limit = loglimit(opts)
2016 revs = _logrevs(repo, opts)
2016 revs = _logrevs(repo, opts)
2017 if not revs:
2017 if not revs:
2018 return revset.baseset(), None, None
2018 return revset.baseset(), None, None
2019 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
2019 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
2020 if opts.get('rev'):
2020 if opts.get('rev'):
2021 # User-specified revs might be unsorted, but don't sort before
2021 # User-specified revs might be unsorted, but don't sort before
2022 # _makelogrevset because it might depend on the order of revs
2022 # _makelogrevset because it might depend on the order of revs
2023 revs.sort(reverse=True)
2023 revs.sort(reverse=True)
2024 if expr:
2024 if expr:
2025 # Revset matchers often operate faster on revisions in changelog
2025 # Revset matchers often operate faster on revisions in changelog
2026 # order, because most filters deal with the changelog.
2026 # order, because most filters deal with the changelog.
2027 revs.reverse()
2027 revs.reverse()
2028 matcher = revset.match(repo.ui, expr)
2028 matcher = revset.match(repo.ui, expr)
2029 # Revset matches can reorder revisions. "A or B" typically returns
2029 # Revset matches can reorder revisions. "A or B" typically returns
2030 # returns the revision matching A then the revision matching B. Sort
2030 # returns the revision matching A then the revision matching B. Sort
2031 # again to fix that.
2031 # again to fix that.
2032 revs = matcher(repo, revs)
2032 revs = matcher(repo, revs)
2033 revs.sort(reverse=True)
2033 revs.sort(reverse=True)
2034 if limit is not None:
2034 if limit is not None:
2035 limitedrevs = []
2035 limitedrevs = []
2036 for idx, rev in enumerate(revs):
2036 for idx, rev in enumerate(revs):
2037 if idx >= limit:
2037 if idx >= limit:
2038 break
2038 break
2039 limitedrevs.append(rev)
2039 limitedrevs.append(rev)
2040 revs = revset.baseset(limitedrevs)
2040 revs = revset.baseset(limitedrevs)
2041
2041
2042 return revs, expr, filematcher
2042 return revs, expr, filematcher
2043
2043
2044 def getlogrevs(repo, pats, opts):
2044 def getlogrevs(repo, pats, opts):
2045 """Return (revs, expr, filematcher) where revs is an iterable of
2045 """Return (revs, expr, filematcher) where revs is an iterable of
2046 revision numbers, expr is a revset string built from log options
2046 revision numbers, expr is a revset string built from log options
2047 and file patterns or None, and used to filter 'revs'. If --stat or
2047 and file patterns or None, and used to filter 'revs'. If --stat or
2048 --patch are not passed filematcher is None. Otherwise it is a
2048 --patch are not passed filematcher is None. Otherwise it is a
2049 callable taking a revision number and returning a match objects
2049 callable taking a revision number and returning a match objects
2050 filtering the files to be detailed when displaying the revision.
2050 filtering the files to be detailed when displaying the revision.
2051 """
2051 """
2052 limit = loglimit(opts)
2052 limit = loglimit(opts)
2053 revs = _logrevs(repo, opts)
2053 revs = _logrevs(repo, opts)
2054 if not revs:
2054 if not revs:
2055 return revset.baseset([]), None, None
2055 return revset.baseset([]), None, None
2056 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
2056 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
2057 if expr:
2057 if expr:
2058 # Revset matchers often operate faster on revisions in changelog
2058 # Revset matchers often operate faster on revisions in changelog
2059 # order, because most filters deal with the changelog.
2059 # order, because most filters deal with the changelog.
2060 if not opts.get('rev'):
2060 if not opts.get('rev'):
2061 revs.reverse()
2061 revs.reverse()
2062 matcher = revset.match(repo.ui, expr)
2062 matcher = revset.match(repo.ui, expr)
2063 # Revset matches can reorder revisions. "A or B" typically returns
2063 # Revset matches can reorder revisions. "A or B" typically returns
2064 # returns the revision matching A then the revision matching B. Sort
2064 # returns the revision matching A then the revision matching B. Sort
2065 # again to fix that.
2065 # again to fix that.
2066 revs = matcher(repo, revs)
2066 revs = matcher(repo, revs)
2067 if not opts.get('rev'):
2067 if not opts.get('rev'):
2068 revs.sort(reverse=True)
2068 revs.sort(reverse=True)
2069 if limit is not None:
2069 if limit is not None:
2070 count = 0
2070 count = 0
2071 limitedrevs = []
2071 limitedrevs = []
2072 it = iter(revs)
2072 it = iter(revs)
2073 while count < limit:
2073 while count < limit:
2074 try:
2074 try:
2075 limitedrevs.append(it.next())
2075 limitedrevs.append(it.next())
2076 except (StopIteration):
2076 except (StopIteration):
2077 break
2077 break
2078 count += 1
2078 count += 1
2079 revs = revset.baseset(limitedrevs)
2079 revs = revset.baseset(limitedrevs)
2080
2080
2081 return revs, expr, filematcher
2081 return revs, expr, filematcher
2082
2082
2083 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
2083 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
2084 filematcher=None):
2084 filematcher=None):
2085 seen, state = [], graphmod.asciistate()
2085 seen, state = [], graphmod.asciistate()
2086 for rev, type, ctx, parents in dag:
2086 for rev, type, ctx, parents in dag:
2087 char = 'o'
2087 char = 'o'
2088 if ctx.node() in showparents:
2088 if ctx.node() in showparents:
2089 char = '@'
2089 char = '@'
2090 elif ctx.obsolete():
2090 elif ctx.obsolete():
2091 char = 'x'
2091 char = 'x'
2092 elif ctx.closesbranch():
2092 elif ctx.closesbranch():
2093 char = '_'
2093 char = '_'
2094 copies = None
2094 copies = None
2095 if getrenamed and ctx.rev():
2095 if getrenamed and ctx.rev():
2096 copies = []
2096 copies = []
2097 for fn in ctx.files():
2097 for fn in ctx.files():
2098 rename = getrenamed(fn, ctx.rev())
2098 rename = getrenamed(fn, ctx.rev())
2099 if rename:
2099 if rename:
2100 copies.append((fn, rename[0]))
2100 copies.append((fn, rename[0]))
2101 revmatchfn = None
2101 revmatchfn = None
2102 if filematcher is not None:
2102 if filematcher is not None:
2103 revmatchfn = filematcher(ctx.rev())
2103 revmatchfn = filematcher(ctx.rev())
2104 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2104 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2105 lines = displayer.hunk.pop(rev).split('\n')
2105 lines = displayer.hunk.pop(rev).split('\n')
2106 if not lines[-1]:
2106 if not lines[-1]:
2107 del lines[-1]
2107 del lines[-1]
2108 displayer.flush(rev)
2108 displayer.flush(rev)
2109 edges = edgefn(type, char, lines, seen, rev, parents)
2109 edges = edgefn(type, char, lines, seen, rev, parents)
2110 for type, char, lines, coldata in edges:
2110 for type, char, lines, coldata in edges:
2111 graphmod.ascii(ui, state, type, char, lines, coldata)
2111 graphmod.ascii(ui, state, type, char, lines, coldata)
2112 displayer.close()
2112 displayer.close()
2113
2113
2114 def graphlog(ui, repo, *pats, **opts):
2114 def graphlog(ui, repo, *pats, **opts):
2115 # Parameters are identical to log command ones
2115 # Parameters are identical to log command ones
2116 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
2116 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
2117 revdag = graphmod.dagwalker(repo, revs)
2117 revdag = graphmod.dagwalker(repo, revs)
2118
2118
2119 getrenamed = None
2119 getrenamed = None
2120 if opts.get('copies'):
2120 if opts.get('copies'):
2121 endrev = None
2121 endrev = None
2122 if opts.get('rev'):
2122 if opts.get('rev'):
2123 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
2123 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
2124 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2124 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2125 displayer = show_changeset(ui, repo, opts, buffered=True)
2125 displayer = show_changeset(ui, repo, opts, buffered=True)
2126 showparents = [ctx.node() for ctx in repo[None].parents()]
2126 showparents = [ctx.node() for ctx in repo[None].parents()]
2127 displaygraph(ui, revdag, displayer, showparents,
2127 displaygraph(ui, revdag, displayer, showparents,
2128 graphmod.asciiedges, getrenamed, filematcher)
2128 graphmod.asciiedges, getrenamed, filematcher)
2129
2129
2130 def checkunsupportedgraphflags(pats, opts):
2130 def checkunsupportedgraphflags(pats, opts):
2131 for op in ["newest_first"]:
2131 for op in ["newest_first"]:
2132 if op in opts and opts[op]:
2132 if op in opts and opts[op]:
2133 raise util.Abort(_("-G/--graph option is incompatible with --%s")
2133 raise util.Abort(_("-G/--graph option is incompatible with --%s")
2134 % op.replace("_", "-"))
2134 % op.replace("_", "-"))
2135
2135
2136 def graphrevs(repo, nodes, opts):
2136 def graphrevs(repo, nodes, opts):
2137 limit = loglimit(opts)
2137 limit = loglimit(opts)
2138 nodes.reverse()
2138 nodes.reverse()
2139 if limit is not None:
2139 if limit is not None:
2140 nodes = nodes[:limit]
2140 nodes = nodes[:limit]
2141 return graphmod.nodes(repo, nodes)
2141 return graphmod.nodes(repo, nodes)
2142
2142
2143 def add(ui, repo, match, prefix, explicitonly, **opts):
2143 def add(ui, repo, match, prefix, explicitonly, **opts):
2144 join = lambda f: os.path.join(prefix, f)
2144 join = lambda f: os.path.join(prefix, f)
2145 bad = []
2145 bad = []
2146 oldbad = match.bad
2146 oldbad = match.bad
2147 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
2147 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
2148 names = []
2148 names = []
2149 wctx = repo[None]
2149 wctx = repo[None]
2150 cca = None
2150 cca = None
2151 abort, warn = scmutil.checkportabilityalert(ui)
2151 abort, warn = scmutil.checkportabilityalert(ui)
2152 if abort or warn:
2152 if abort or warn:
2153 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
2153 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
2154 for f in wctx.walk(match):
2154 for f in wctx.walk(match):
2155 exact = match.exact(f)
2155 exact = match.exact(f)
2156 if exact or not explicitonly and f not in wctx and repo.wvfs.lexists(f):
2156 if exact or not explicitonly and f not in wctx and repo.wvfs.lexists(f):
2157 if cca:
2157 if cca:
2158 cca(f)
2158 cca(f)
2159 names.append(f)
2159 names.append(f)
2160 if ui.verbose or not exact:
2160 if ui.verbose or not exact:
2161 ui.status(_('adding %s\n') % match.rel(f))
2161 ui.status(_('adding %s\n') % match.rel(f))
2162
2162
2163 for subpath in sorted(wctx.substate):
2163 for subpath in sorted(wctx.substate):
2164 sub = wctx.sub(subpath)
2164 sub = wctx.sub(subpath)
2165 try:
2165 try:
2166 submatch = matchmod.narrowmatcher(subpath, match)
2166 submatch = matchmod.narrowmatcher(subpath, match)
2167 if opts.get('subrepos'):
2167 if opts.get('subrepos'):
2168 bad.extend(sub.add(ui, submatch, prefix, False, **opts))
2168 bad.extend(sub.add(ui, submatch, prefix, False, **opts))
2169 else:
2169 else:
2170 bad.extend(sub.add(ui, submatch, prefix, True, **opts))
2170 bad.extend(sub.add(ui, submatch, prefix, True, **opts))
2171 except error.LookupError:
2171 except error.LookupError:
2172 ui.status(_("skipping missing subrepository: %s\n")
2172 ui.status(_("skipping missing subrepository: %s\n")
2173 % join(subpath))
2173 % join(subpath))
2174
2174
2175 if not opts.get('dry_run'):
2175 if not opts.get('dry_run'):
2176 rejected = wctx.add(names, prefix)
2176 rejected = wctx.add(names, prefix)
2177 bad.extend(f for f in rejected if f in match.files())
2177 bad.extend(f for f in rejected if f in match.files())
2178 return bad
2178 return bad
2179
2179
2180 def forget(ui, repo, match, prefix, explicitonly):
2180 def forget(ui, repo, match, prefix, explicitonly):
2181 join = lambda f: os.path.join(prefix, f)
2181 join = lambda f: os.path.join(prefix, f)
2182 bad = []
2182 bad = []
2183 oldbad = match.bad
2183 oldbad = match.bad
2184 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
2184 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
2185 wctx = repo[None]
2185 wctx = repo[None]
2186 forgot = []
2186 forgot = []
2187 s = repo.status(match=match, clean=True)
2187 s = repo.status(match=match, clean=True)
2188 forget = sorted(s[0] + s[1] + s[3] + s[6])
2188 forget = sorted(s[0] + s[1] + s[3] + s[6])
2189 if explicitonly:
2189 if explicitonly:
2190 forget = [f for f in forget if match.exact(f)]
2190 forget = [f for f in forget if match.exact(f)]
2191
2191
2192 for subpath in sorted(wctx.substate):
2192 for subpath in sorted(wctx.substate):
2193 sub = wctx.sub(subpath)
2193 sub = wctx.sub(subpath)
2194 try:
2194 try:
2195 submatch = matchmod.narrowmatcher(subpath, match)
2195 submatch = matchmod.narrowmatcher(subpath, match)
2196 subbad, subforgot = sub.forget(submatch, prefix)
2196 subbad, subforgot = sub.forget(submatch, prefix)
2197 bad.extend([subpath + '/' + f for f in subbad])
2197 bad.extend([subpath + '/' + f for f in subbad])
2198 forgot.extend([subpath + '/' + f for f in subforgot])
2198 forgot.extend([subpath + '/' + f for f in subforgot])
2199 except error.LookupError:
2199 except error.LookupError:
2200 ui.status(_("skipping missing subrepository: %s\n")
2200 ui.status(_("skipping missing subrepository: %s\n")
2201 % join(subpath))
2201 % join(subpath))
2202
2202
2203 if not explicitonly:
2203 if not explicitonly:
2204 for f in match.files():
2204 for f in match.files():
2205 if f not in repo.dirstate and not repo.wvfs.isdir(f):
2205 if f not in repo.dirstate and not repo.wvfs.isdir(f):
2206 if f not in forgot:
2206 if f not in forgot:
2207 if repo.wvfs.exists(f):
2207 if repo.wvfs.exists(f):
2208 ui.warn(_('not removing %s: '
2208 ui.warn(_('not removing %s: '
2209 'file is already untracked\n')
2209 'file is already untracked\n')
2210 % match.rel(f))
2210 % match.rel(f))
2211 bad.append(f)
2211 bad.append(f)
2212
2212
2213 for f in forget:
2213 for f in forget:
2214 if ui.verbose or not match.exact(f):
2214 if ui.verbose or not match.exact(f):
2215 ui.status(_('removing %s\n') % match.rel(f))
2215 ui.status(_('removing %s\n') % match.rel(f))
2216
2216
2217 rejected = wctx.forget(forget, prefix)
2217 rejected = wctx.forget(forget, prefix)
2218 bad.extend(f for f in rejected if f in match.files())
2218 bad.extend(f for f in rejected if f in match.files())
2219 forgot.extend(f for f in forget if f not in rejected)
2219 forgot.extend(f for f in forget if f not in rejected)
2220 return bad, forgot
2220 return bad, forgot
2221
2221
2222 def files(ui, ctx, m, fm, fmt):
2223 rev = ctx.rev()
2224 ret = 1
2225 ds = ctx._repo.dirstate
2226
2227 for f in ctx.matches(m):
2228 if rev is None and ds[f] == 'r':
2229 continue
2230 fm.startitem()
2231 if ui.verbose:
2232 fc = ctx[f]
2233 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
2234 fm.data(abspath=f)
2235 fm.write('path', fmt, m.rel(f))
2236 ret = 0
2237
2238 return ret
2239
2222 def remove(ui, repo, m, prefix, after, force, subrepos):
2240 def remove(ui, repo, m, prefix, after, force, subrepos):
2223 join = lambda f: os.path.join(prefix, f)
2241 join = lambda f: os.path.join(prefix, f)
2224 ret = 0
2242 ret = 0
2225 s = repo.status(match=m, clean=True)
2243 s = repo.status(match=m, clean=True)
2226 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2244 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2227
2245
2228 wctx = repo[None]
2246 wctx = repo[None]
2229
2247
2230 for subpath in sorted(wctx.substate):
2248 for subpath in sorted(wctx.substate):
2231 def matchessubrepo(matcher, subpath):
2249 def matchessubrepo(matcher, subpath):
2232 if matcher.exact(subpath):
2250 if matcher.exact(subpath):
2233 return True
2251 return True
2234 for f in matcher.files():
2252 for f in matcher.files():
2235 if f.startswith(subpath):
2253 if f.startswith(subpath):
2236 return True
2254 return True
2237 return False
2255 return False
2238
2256
2239 if subrepos or matchessubrepo(m, subpath):
2257 if subrepos or matchessubrepo(m, subpath):
2240 sub = wctx.sub(subpath)
2258 sub = wctx.sub(subpath)
2241 try:
2259 try:
2242 submatch = matchmod.narrowmatcher(subpath, m)
2260 submatch = matchmod.narrowmatcher(subpath, m)
2243 if sub.removefiles(submatch, prefix, after, force, subrepos):
2261 if sub.removefiles(submatch, prefix, after, force, subrepos):
2244 ret = 1
2262 ret = 1
2245 except error.LookupError:
2263 except error.LookupError:
2246 ui.status(_("skipping missing subrepository: %s\n")
2264 ui.status(_("skipping missing subrepository: %s\n")
2247 % join(subpath))
2265 % join(subpath))
2248
2266
2249 # warn about failure to delete explicit files/dirs
2267 # warn about failure to delete explicit files/dirs
2250 deleteddirs = scmutil.dirs(deleted)
2268 deleteddirs = scmutil.dirs(deleted)
2251 for f in m.files():
2269 for f in m.files():
2252 def insubrepo():
2270 def insubrepo():
2253 for subpath in wctx.substate:
2271 for subpath in wctx.substate:
2254 if f.startswith(subpath):
2272 if f.startswith(subpath):
2255 return True
2273 return True
2256 return False
2274 return False
2257
2275
2258 isdir = f in deleteddirs or f in wctx.dirs()
2276 isdir = f in deleteddirs or f in wctx.dirs()
2259 if f in repo.dirstate or isdir or f == '.' or insubrepo():
2277 if f in repo.dirstate or isdir or f == '.' or insubrepo():
2260 continue
2278 continue
2261
2279
2262 if repo.wvfs.exists(f):
2280 if repo.wvfs.exists(f):
2263 if repo.wvfs.isdir(f):
2281 if repo.wvfs.isdir(f):
2264 ui.warn(_('not removing %s: no tracked files\n')
2282 ui.warn(_('not removing %s: no tracked files\n')
2265 % m.rel(f))
2283 % m.rel(f))
2266 else:
2284 else:
2267 ui.warn(_('not removing %s: file is untracked\n')
2285 ui.warn(_('not removing %s: file is untracked\n')
2268 % m.rel(f))
2286 % m.rel(f))
2269 # missing files will generate a warning elsewhere
2287 # missing files will generate a warning elsewhere
2270 ret = 1
2288 ret = 1
2271
2289
2272 if force:
2290 if force:
2273 list = modified + deleted + clean + added
2291 list = modified + deleted + clean + added
2274 elif after:
2292 elif after:
2275 list = deleted
2293 list = deleted
2276 for f in modified + added + clean:
2294 for f in modified + added + clean:
2277 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
2295 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
2278 ret = 1
2296 ret = 1
2279 else:
2297 else:
2280 list = deleted + clean
2298 list = deleted + clean
2281 for f in modified:
2299 for f in modified:
2282 ui.warn(_('not removing %s: file is modified (use -f'
2300 ui.warn(_('not removing %s: file is modified (use -f'
2283 ' to force removal)\n') % m.rel(f))
2301 ' to force removal)\n') % m.rel(f))
2284 ret = 1
2302 ret = 1
2285 for f in added:
2303 for f in added:
2286 ui.warn(_('not removing %s: file has been marked for add'
2304 ui.warn(_('not removing %s: file has been marked for add'
2287 ' (use forget to undo)\n') % m.rel(f))
2305 ' (use forget to undo)\n') % m.rel(f))
2288 ret = 1
2306 ret = 1
2289
2307
2290 for f in sorted(list):
2308 for f in sorted(list):
2291 if ui.verbose or not m.exact(f):
2309 if ui.verbose or not m.exact(f):
2292 ui.status(_('removing %s\n') % m.rel(f))
2310 ui.status(_('removing %s\n') % m.rel(f))
2293
2311
2294 wlock = repo.wlock()
2312 wlock = repo.wlock()
2295 try:
2313 try:
2296 if not after:
2314 if not after:
2297 for f in list:
2315 for f in list:
2298 if f in added:
2316 if f in added:
2299 continue # we never unlink added files on remove
2317 continue # we never unlink added files on remove
2300 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
2318 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
2301 repo[None].forget(list)
2319 repo[None].forget(list)
2302 finally:
2320 finally:
2303 wlock.release()
2321 wlock.release()
2304
2322
2305 return ret
2323 return ret
2306
2324
2307 def cat(ui, repo, ctx, matcher, prefix, **opts):
2325 def cat(ui, repo, ctx, matcher, prefix, **opts):
2308 err = 1
2326 err = 1
2309
2327
2310 def write(path):
2328 def write(path):
2311 fp = makefileobj(repo, opts.get('output'), ctx.node(),
2329 fp = makefileobj(repo, opts.get('output'), ctx.node(),
2312 pathname=os.path.join(prefix, path))
2330 pathname=os.path.join(prefix, path))
2313 data = ctx[path].data()
2331 data = ctx[path].data()
2314 if opts.get('decode'):
2332 if opts.get('decode'):
2315 data = repo.wwritedata(path, data)
2333 data = repo.wwritedata(path, data)
2316 fp.write(data)
2334 fp.write(data)
2317 fp.close()
2335 fp.close()
2318
2336
2319 # Automation often uses hg cat on single files, so special case it
2337 # Automation often uses hg cat on single files, so special case it
2320 # for performance to avoid the cost of parsing the manifest.
2338 # for performance to avoid the cost of parsing the manifest.
2321 if len(matcher.files()) == 1 and not matcher.anypats():
2339 if len(matcher.files()) == 1 and not matcher.anypats():
2322 file = matcher.files()[0]
2340 file = matcher.files()[0]
2323 mf = repo.manifest
2341 mf = repo.manifest
2324 mfnode = ctx._changeset[0]
2342 mfnode = ctx._changeset[0]
2325 if mf.find(mfnode, file)[0]:
2343 if mf.find(mfnode, file)[0]:
2326 write(file)
2344 write(file)
2327 return 0
2345 return 0
2328
2346
2329 # Don't warn about "missing" files that are really in subrepos
2347 # Don't warn about "missing" files that are really in subrepos
2330 bad = matcher.bad
2348 bad = matcher.bad
2331
2349
2332 def badfn(path, msg):
2350 def badfn(path, msg):
2333 for subpath in ctx.substate:
2351 for subpath in ctx.substate:
2334 if path.startswith(subpath):
2352 if path.startswith(subpath):
2335 return
2353 return
2336 bad(path, msg)
2354 bad(path, msg)
2337
2355
2338 matcher.bad = badfn
2356 matcher.bad = badfn
2339
2357
2340 for abs in ctx.walk(matcher):
2358 for abs in ctx.walk(matcher):
2341 write(abs)
2359 write(abs)
2342 err = 0
2360 err = 0
2343
2361
2344 matcher.bad = bad
2362 matcher.bad = bad
2345
2363
2346 for subpath in sorted(ctx.substate):
2364 for subpath in sorted(ctx.substate):
2347 sub = ctx.sub(subpath)
2365 sub = ctx.sub(subpath)
2348 try:
2366 try:
2349 submatch = matchmod.narrowmatcher(subpath, matcher)
2367 submatch = matchmod.narrowmatcher(subpath, matcher)
2350
2368
2351 if not sub.cat(submatch, os.path.join(prefix, sub._path),
2369 if not sub.cat(submatch, os.path.join(prefix, sub._path),
2352 **opts):
2370 **opts):
2353 err = 0
2371 err = 0
2354 except error.RepoLookupError:
2372 except error.RepoLookupError:
2355 ui.status(_("skipping missing subrepository: %s\n")
2373 ui.status(_("skipping missing subrepository: %s\n")
2356 % os.path.join(prefix, subpath))
2374 % os.path.join(prefix, subpath))
2357
2375
2358 return err
2376 return err
2359
2377
2360 def commit(ui, repo, commitfunc, pats, opts):
2378 def commit(ui, repo, commitfunc, pats, opts):
2361 '''commit the specified files or all outstanding changes'''
2379 '''commit the specified files or all outstanding changes'''
2362 date = opts.get('date')
2380 date = opts.get('date')
2363 if date:
2381 if date:
2364 opts['date'] = util.parsedate(date)
2382 opts['date'] = util.parsedate(date)
2365 message = logmessage(ui, opts)
2383 message = logmessage(ui, opts)
2366 matcher = scmutil.match(repo[None], pats, opts)
2384 matcher = scmutil.match(repo[None], pats, opts)
2367
2385
2368 # extract addremove carefully -- this function can be called from a command
2386 # extract addremove carefully -- this function can be called from a command
2369 # that doesn't support addremove
2387 # that doesn't support addremove
2370 if opts.get('addremove'):
2388 if opts.get('addremove'):
2371 if scmutil.addremove(repo, matcher, "", opts) != 0:
2389 if scmutil.addremove(repo, matcher, "", opts) != 0:
2372 raise util.Abort(
2390 raise util.Abort(
2373 _("failed to mark all new/missing files as added/removed"))
2391 _("failed to mark all new/missing files as added/removed"))
2374
2392
2375 return commitfunc(ui, repo, message, matcher, opts)
2393 return commitfunc(ui, repo, message, matcher, opts)
2376
2394
2377 def amend(ui, repo, commitfunc, old, extra, pats, opts):
2395 def amend(ui, repo, commitfunc, old, extra, pats, opts):
2378 # amend will reuse the existing user if not specified, but the obsolete
2396 # amend will reuse the existing user if not specified, but the obsolete
2379 # marker creation requires that the current user's name is specified.
2397 # marker creation requires that the current user's name is specified.
2380 if obsolete._enabled:
2398 if obsolete._enabled:
2381 ui.username() # raise exception if username not set
2399 ui.username() # raise exception if username not set
2382
2400
2383 ui.note(_('amending changeset %s\n') % old)
2401 ui.note(_('amending changeset %s\n') % old)
2384 base = old.p1()
2402 base = old.p1()
2385
2403
2386 wlock = lock = newid = None
2404 wlock = lock = newid = None
2387 try:
2405 try:
2388 wlock = repo.wlock()
2406 wlock = repo.wlock()
2389 lock = repo.lock()
2407 lock = repo.lock()
2390 tr = repo.transaction('amend')
2408 tr = repo.transaction('amend')
2391 try:
2409 try:
2392 # See if we got a message from -m or -l, if not, open the editor
2410 # See if we got a message from -m or -l, if not, open the editor
2393 # with the message of the changeset to amend
2411 # with the message of the changeset to amend
2394 message = logmessage(ui, opts)
2412 message = logmessage(ui, opts)
2395 # ensure logfile does not conflict with later enforcement of the
2413 # ensure logfile does not conflict with later enforcement of the
2396 # message. potential logfile content has been processed by
2414 # message. potential logfile content has been processed by
2397 # `logmessage` anyway.
2415 # `logmessage` anyway.
2398 opts.pop('logfile')
2416 opts.pop('logfile')
2399 # First, do a regular commit to record all changes in the working
2417 # First, do a regular commit to record all changes in the working
2400 # directory (if there are any)
2418 # directory (if there are any)
2401 ui.callhooks = False
2419 ui.callhooks = False
2402 currentbookmark = repo._bookmarkcurrent
2420 currentbookmark = repo._bookmarkcurrent
2403 try:
2421 try:
2404 repo._bookmarkcurrent = None
2422 repo._bookmarkcurrent = None
2405 opts['message'] = 'temporary amend commit for %s' % old
2423 opts['message'] = 'temporary amend commit for %s' % old
2406 node = commit(ui, repo, commitfunc, pats, opts)
2424 node = commit(ui, repo, commitfunc, pats, opts)
2407 finally:
2425 finally:
2408 repo._bookmarkcurrent = currentbookmark
2426 repo._bookmarkcurrent = currentbookmark
2409 ui.callhooks = True
2427 ui.callhooks = True
2410 ctx = repo[node]
2428 ctx = repo[node]
2411
2429
2412 # Participating changesets:
2430 # Participating changesets:
2413 #
2431 #
2414 # node/ctx o - new (intermediate) commit that contains changes
2432 # node/ctx o - new (intermediate) commit that contains changes
2415 # | from working dir to go into amending commit
2433 # | from working dir to go into amending commit
2416 # | (or a workingctx if there were no changes)
2434 # | (or a workingctx if there were no changes)
2417 # |
2435 # |
2418 # old o - changeset to amend
2436 # old o - changeset to amend
2419 # |
2437 # |
2420 # base o - parent of amending changeset
2438 # base o - parent of amending changeset
2421
2439
2422 # Update extra dict from amended commit (e.g. to preserve graft
2440 # Update extra dict from amended commit (e.g. to preserve graft
2423 # source)
2441 # source)
2424 extra.update(old.extra())
2442 extra.update(old.extra())
2425
2443
2426 # Also update it from the intermediate commit or from the wctx
2444 # Also update it from the intermediate commit or from the wctx
2427 extra.update(ctx.extra())
2445 extra.update(ctx.extra())
2428
2446
2429 if len(old.parents()) > 1:
2447 if len(old.parents()) > 1:
2430 # ctx.files() isn't reliable for merges, so fall back to the
2448 # ctx.files() isn't reliable for merges, so fall back to the
2431 # slower repo.status() method
2449 # slower repo.status() method
2432 files = set([fn for st in repo.status(base, old)[:3]
2450 files = set([fn for st in repo.status(base, old)[:3]
2433 for fn in st])
2451 for fn in st])
2434 else:
2452 else:
2435 files = set(old.files())
2453 files = set(old.files())
2436
2454
2437 # Second, we use either the commit we just did, or if there were no
2455 # Second, we use either the commit we just did, or if there were no
2438 # changes the parent of the working directory as the version of the
2456 # changes the parent of the working directory as the version of the
2439 # files in the final amend commit
2457 # files in the final amend commit
2440 if node:
2458 if node:
2441 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
2459 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
2442
2460
2443 user = ctx.user()
2461 user = ctx.user()
2444 date = ctx.date()
2462 date = ctx.date()
2445 # Recompute copies (avoid recording a -> b -> a)
2463 # Recompute copies (avoid recording a -> b -> a)
2446 copied = copies.pathcopies(base, ctx)
2464 copied = copies.pathcopies(base, ctx)
2447 if old.p2:
2465 if old.p2:
2448 copied.update(copies.pathcopies(old.p2(), ctx))
2466 copied.update(copies.pathcopies(old.p2(), ctx))
2449
2467
2450 # Prune files which were reverted by the updates: if old
2468 # Prune files which were reverted by the updates: if old
2451 # introduced file X and our intermediate commit, node,
2469 # introduced file X and our intermediate commit, node,
2452 # renamed that file, then those two files are the same and
2470 # renamed that file, then those two files are the same and
2453 # we can discard X from our list of files. Likewise if X
2471 # we can discard X from our list of files. Likewise if X
2454 # was deleted, it's no longer relevant
2472 # was deleted, it's no longer relevant
2455 files.update(ctx.files())
2473 files.update(ctx.files())
2456
2474
2457 def samefile(f):
2475 def samefile(f):
2458 if f in ctx.manifest():
2476 if f in ctx.manifest():
2459 a = ctx.filectx(f)
2477 a = ctx.filectx(f)
2460 if f in base.manifest():
2478 if f in base.manifest():
2461 b = base.filectx(f)
2479 b = base.filectx(f)
2462 return (not a.cmp(b)
2480 return (not a.cmp(b)
2463 and a.flags() == b.flags())
2481 and a.flags() == b.flags())
2464 else:
2482 else:
2465 return False
2483 return False
2466 else:
2484 else:
2467 return f not in base.manifest()
2485 return f not in base.manifest()
2468 files = [f for f in files if not samefile(f)]
2486 files = [f for f in files if not samefile(f)]
2469
2487
2470 def filectxfn(repo, ctx_, path):
2488 def filectxfn(repo, ctx_, path):
2471 try:
2489 try:
2472 fctx = ctx[path]
2490 fctx = ctx[path]
2473 flags = fctx.flags()
2491 flags = fctx.flags()
2474 mctx = context.memfilectx(repo,
2492 mctx = context.memfilectx(repo,
2475 fctx.path(), fctx.data(),
2493 fctx.path(), fctx.data(),
2476 islink='l' in flags,
2494 islink='l' in flags,
2477 isexec='x' in flags,
2495 isexec='x' in flags,
2478 copied=copied.get(path))
2496 copied=copied.get(path))
2479 return mctx
2497 return mctx
2480 except KeyError:
2498 except KeyError:
2481 return None
2499 return None
2482 else:
2500 else:
2483 ui.note(_('copying changeset %s to %s\n') % (old, base))
2501 ui.note(_('copying changeset %s to %s\n') % (old, base))
2484
2502
2485 # Use version of files as in the old cset
2503 # Use version of files as in the old cset
2486 def filectxfn(repo, ctx_, path):
2504 def filectxfn(repo, ctx_, path):
2487 try:
2505 try:
2488 return old.filectx(path)
2506 return old.filectx(path)
2489 except KeyError:
2507 except KeyError:
2490 return None
2508 return None
2491
2509
2492 user = opts.get('user') or old.user()
2510 user = opts.get('user') or old.user()
2493 date = opts.get('date') or old.date()
2511 date = opts.get('date') or old.date()
2494 editform = mergeeditform(old, 'commit.amend')
2512 editform = mergeeditform(old, 'commit.amend')
2495 editor = getcommiteditor(editform=editform, **opts)
2513 editor = getcommiteditor(editform=editform, **opts)
2496 if not message:
2514 if not message:
2497 editor = getcommiteditor(edit=True, editform=editform)
2515 editor = getcommiteditor(edit=True, editform=editform)
2498 message = old.description()
2516 message = old.description()
2499
2517
2500 pureextra = extra.copy()
2518 pureextra = extra.copy()
2501 extra['amend_source'] = old.hex()
2519 extra['amend_source'] = old.hex()
2502
2520
2503 new = context.memctx(repo,
2521 new = context.memctx(repo,
2504 parents=[base.node(), old.p2().node()],
2522 parents=[base.node(), old.p2().node()],
2505 text=message,
2523 text=message,
2506 files=files,
2524 files=files,
2507 filectxfn=filectxfn,
2525 filectxfn=filectxfn,
2508 user=user,
2526 user=user,
2509 date=date,
2527 date=date,
2510 extra=extra,
2528 extra=extra,
2511 editor=editor)
2529 editor=editor)
2512
2530
2513 newdesc = changelog.stripdesc(new.description())
2531 newdesc = changelog.stripdesc(new.description())
2514 if ((not node)
2532 if ((not node)
2515 and newdesc == old.description()
2533 and newdesc == old.description()
2516 and user == old.user()
2534 and user == old.user()
2517 and date == old.date()
2535 and date == old.date()
2518 and pureextra == old.extra()):
2536 and pureextra == old.extra()):
2519 # nothing changed. continuing here would create a new node
2537 # nothing changed. continuing here would create a new node
2520 # anyway because of the amend_source noise.
2538 # anyway because of the amend_source noise.
2521 #
2539 #
2522 # This not what we expect from amend.
2540 # This not what we expect from amend.
2523 return old.node()
2541 return old.node()
2524
2542
2525 ph = repo.ui.config('phases', 'new-commit', phases.draft)
2543 ph = repo.ui.config('phases', 'new-commit', phases.draft)
2526 try:
2544 try:
2527 if opts.get('secret'):
2545 if opts.get('secret'):
2528 commitphase = 'secret'
2546 commitphase = 'secret'
2529 else:
2547 else:
2530 commitphase = old.phase()
2548 commitphase = old.phase()
2531 repo.ui.setconfig('phases', 'new-commit', commitphase, 'amend')
2549 repo.ui.setconfig('phases', 'new-commit', commitphase, 'amend')
2532 newid = repo.commitctx(new)
2550 newid = repo.commitctx(new)
2533 finally:
2551 finally:
2534 repo.ui.setconfig('phases', 'new-commit', ph, 'amend')
2552 repo.ui.setconfig('phases', 'new-commit', ph, 'amend')
2535 if newid != old.node():
2553 if newid != old.node():
2536 # Reroute the working copy parent to the new changeset
2554 # Reroute the working copy parent to the new changeset
2537 repo.setparents(newid, nullid)
2555 repo.setparents(newid, nullid)
2538
2556
2539 # Move bookmarks from old parent to amend commit
2557 # Move bookmarks from old parent to amend commit
2540 bms = repo.nodebookmarks(old.node())
2558 bms = repo.nodebookmarks(old.node())
2541 if bms:
2559 if bms:
2542 marks = repo._bookmarks
2560 marks = repo._bookmarks
2543 for bm in bms:
2561 for bm in bms:
2544 marks[bm] = newid
2562 marks[bm] = newid
2545 marks.write()
2563 marks.write()
2546 #commit the whole amend process
2564 #commit the whole amend process
2547 createmarkers = obsolete.isenabled(repo, obsolete.createmarkersopt)
2565 createmarkers = obsolete.isenabled(repo, obsolete.createmarkersopt)
2548 if createmarkers and newid != old.node():
2566 if createmarkers and newid != old.node():
2549 # mark the new changeset as successor of the rewritten one
2567 # mark the new changeset as successor of the rewritten one
2550 new = repo[newid]
2568 new = repo[newid]
2551 obs = [(old, (new,))]
2569 obs = [(old, (new,))]
2552 if node:
2570 if node:
2553 obs.append((ctx, ()))
2571 obs.append((ctx, ()))
2554
2572
2555 obsolete.createmarkers(repo, obs)
2573 obsolete.createmarkers(repo, obs)
2556 tr.close()
2574 tr.close()
2557 finally:
2575 finally:
2558 tr.release()
2576 tr.release()
2559 if not createmarkers and newid != old.node():
2577 if not createmarkers and newid != old.node():
2560 # Strip the intermediate commit (if there was one) and the amended
2578 # Strip the intermediate commit (if there was one) and the amended
2561 # commit
2579 # commit
2562 if node:
2580 if node:
2563 ui.note(_('stripping intermediate changeset %s\n') % ctx)
2581 ui.note(_('stripping intermediate changeset %s\n') % ctx)
2564 ui.note(_('stripping amended changeset %s\n') % old)
2582 ui.note(_('stripping amended changeset %s\n') % old)
2565 repair.strip(ui, repo, old.node(), topic='amend-backup')
2583 repair.strip(ui, repo, old.node(), topic='amend-backup')
2566 finally:
2584 finally:
2567 if newid is None:
2585 if newid is None:
2568 repo.dirstate.invalidate()
2586 repo.dirstate.invalidate()
2569 lockmod.release(lock, wlock)
2587 lockmod.release(lock, wlock)
2570 return newid
2588 return newid
2571
2589
2572 def commiteditor(repo, ctx, subs, editform=''):
2590 def commiteditor(repo, ctx, subs, editform=''):
2573 if ctx.description():
2591 if ctx.description():
2574 return ctx.description()
2592 return ctx.description()
2575 return commitforceeditor(repo, ctx, subs, editform=editform)
2593 return commitforceeditor(repo, ctx, subs, editform=editform)
2576
2594
2577 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None,
2595 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None,
2578 editform=''):
2596 editform=''):
2579 if not extramsg:
2597 if not extramsg:
2580 extramsg = _("Leave message empty to abort commit.")
2598 extramsg = _("Leave message empty to abort commit.")
2581
2599
2582 forms = [e for e in editform.split('.') if e]
2600 forms = [e for e in editform.split('.') if e]
2583 forms.insert(0, 'changeset')
2601 forms.insert(0, 'changeset')
2584 while forms:
2602 while forms:
2585 tmpl = repo.ui.config('committemplate', '.'.join(forms))
2603 tmpl = repo.ui.config('committemplate', '.'.join(forms))
2586 if tmpl:
2604 if tmpl:
2587 committext = buildcommittemplate(repo, ctx, subs, extramsg, tmpl)
2605 committext = buildcommittemplate(repo, ctx, subs, extramsg, tmpl)
2588 break
2606 break
2589 forms.pop()
2607 forms.pop()
2590 else:
2608 else:
2591 committext = buildcommittext(repo, ctx, subs, extramsg)
2609 committext = buildcommittext(repo, ctx, subs, extramsg)
2592
2610
2593 # run editor in the repository root
2611 # run editor in the repository root
2594 olddir = os.getcwd()
2612 olddir = os.getcwd()
2595 os.chdir(repo.root)
2613 os.chdir(repo.root)
2596 text = repo.ui.edit(committext, ctx.user(), ctx.extra(), editform=editform)
2614 text = repo.ui.edit(committext, ctx.user(), ctx.extra(), editform=editform)
2597 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2615 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2598 os.chdir(olddir)
2616 os.chdir(olddir)
2599
2617
2600 if finishdesc:
2618 if finishdesc:
2601 text = finishdesc(text)
2619 text = finishdesc(text)
2602 if not text.strip():
2620 if not text.strip():
2603 raise util.Abort(_("empty commit message"))
2621 raise util.Abort(_("empty commit message"))
2604
2622
2605 return text
2623 return text
2606
2624
2607 def buildcommittemplate(repo, ctx, subs, extramsg, tmpl):
2625 def buildcommittemplate(repo, ctx, subs, extramsg, tmpl):
2608 ui = repo.ui
2626 ui = repo.ui
2609 tmpl, mapfile = gettemplate(ui, tmpl, None)
2627 tmpl, mapfile = gettemplate(ui, tmpl, None)
2610
2628
2611 try:
2629 try:
2612 t = changeset_templater(ui, repo, None, {}, tmpl, mapfile, False)
2630 t = changeset_templater(ui, repo, None, {}, tmpl, mapfile, False)
2613 except SyntaxError, inst:
2631 except SyntaxError, inst:
2614 raise util.Abort(inst.args[0])
2632 raise util.Abort(inst.args[0])
2615
2633
2616 for k, v in repo.ui.configitems('committemplate'):
2634 for k, v in repo.ui.configitems('committemplate'):
2617 if k != 'changeset':
2635 if k != 'changeset':
2618 t.t.cache[k] = v
2636 t.t.cache[k] = v
2619
2637
2620 if not extramsg:
2638 if not extramsg:
2621 extramsg = '' # ensure that extramsg is string
2639 extramsg = '' # ensure that extramsg is string
2622
2640
2623 ui.pushbuffer()
2641 ui.pushbuffer()
2624 t.show(ctx, extramsg=extramsg)
2642 t.show(ctx, extramsg=extramsg)
2625 return ui.popbuffer()
2643 return ui.popbuffer()
2626
2644
2627 def buildcommittext(repo, ctx, subs, extramsg):
2645 def buildcommittext(repo, ctx, subs, extramsg):
2628 edittext = []
2646 edittext = []
2629 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
2647 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
2630 if ctx.description():
2648 if ctx.description():
2631 edittext.append(ctx.description())
2649 edittext.append(ctx.description())
2632 edittext.append("")
2650 edittext.append("")
2633 edittext.append("") # Empty line between message and comments.
2651 edittext.append("") # Empty line between message and comments.
2634 edittext.append(_("HG: Enter commit message."
2652 edittext.append(_("HG: Enter commit message."
2635 " Lines beginning with 'HG:' are removed."))
2653 " Lines beginning with 'HG:' are removed."))
2636 edittext.append("HG: %s" % extramsg)
2654 edittext.append("HG: %s" % extramsg)
2637 edittext.append("HG: --")
2655 edittext.append("HG: --")
2638 edittext.append(_("HG: user: %s") % ctx.user())
2656 edittext.append(_("HG: user: %s") % ctx.user())
2639 if ctx.p2():
2657 if ctx.p2():
2640 edittext.append(_("HG: branch merge"))
2658 edittext.append(_("HG: branch merge"))
2641 if ctx.branch():
2659 if ctx.branch():
2642 edittext.append(_("HG: branch '%s'") % ctx.branch())
2660 edittext.append(_("HG: branch '%s'") % ctx.branch())
2643 if bookmarks.iscurrent(repo):
2661 if bookmarks.iscurrent(repo):
2644 edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
2662 edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
2645 edittext.extend([_("HG: subrepo %s") % s for s in subs])
2663 edittext.extend([_("HG: subrepo %s") % s for s in subs])
2646 edittext.extend([_("HG: added %s") % f for f in added])
2664 edittext.extend([_("HG: added %s") % f for f in added])
2647 edittext.extend([_("HG: changed %s") % f for f in modified])
2665 edittext.extend([_("HG: changed %s") % f for f in modified])
2648 edittext.extend([_("HG: removed %s") % f for f in removed])
2666 edittext.extend([_("HG: removed %s") % f for f in removed])
2649 if not added and not modified and not removed:
2667 if not added and not modified and not removed:
2650 edittext.append(_("HG: no files changed"))
2668 edittext.append(_("HG: no files changed"))
2651 edittext.append("")
2669 edittext.append("")
2652
2670
2653 return "\n".join(edittext)
2671 return "\n".join(edittext)
2654
2672
2655 def commitstatus(repo, node, branch, bheads=None, opts={}):
2673 def commitstatus(repo, node, branch, bheads=None, opts={}):
2656 ctx = repo[node]
2674 ctx = repo[node]
2657 parents = ctx.parents()
2675 parents = ctx.parents()
2658
2676
2659 if (not opts.get('amend') and bheads and node not in bheads and not
2677 if (not opts.get('amend') and bheads and node not in bheads and not
2660 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2678 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2661 repo.ui.status(_('created new head\n'))
2679 repo.ui.status(_('created new head\n'))
2662 # The message is not printed for initial roots. For the other
2680 # The message is not printed for initial roots. For the other
2663 # changesets, it is printed in the following situations:
2681 # changesets, it is printed in the following situations:
2664 #
2682 #
2665 # Par column: for the 2 parents with ...
2683 # Par column: for the 2 parents with ...
2666 # N: null or no parent
2684 # N: null or no parent
2667 # B: parent is on another named branch
2685 # B: parent is on another named branch
2668 # C: parent is a regular non head changeset
2686 # C: parent is a regular non head changeset
2669 # H: parent was a branch head of the current branch
2687 # H: parent was a branch head of the current branch
2670 # Msg column: whether we print "created new head" message
2688 # Msg column: whether we print "created new head" message
2671 # In the following, it is assumed that there already exists some
2689 # In the following, it is assumed that there already exists some
2672 # initial branch heads of the current branch, otherwise nothing is
2690 # initial branch heads of the current branch, otherwise nothing is
2673 # printed anyway.
2691 # printed anyway.
2674 #
2692 #
2675 # Par Msg Comment
2693 # Par Msg Comment
2676 # N N y additional topo root
2694 # N N y additional topo root
2677 #
2695 #
2678 # B N y additional branch root
2696 # B N y additional branch root
2679 # C N y additional topo head
2697 # C N y additional topo head
2680 # H N n usual case
2698 # H N n usual case
2681 #
2699 #
2682 # B B y weird additional branch root
2700 # B B y weird additional branch root
2683 # C B y branch merge
2701 # C B y branch merge
2684 # H B n merge with named branch
2702 # H B n merge with named branch
2685 #
2703 #
2686 # C C y additional head from merge
2704 # C C y additional head from merge
2687 # C H n merge with a head
2705 # C H n merge with a head
2688 #
2706 #
2689 # H H n head merge: head count decreases
2707 # H H n head merge: head count decreases
2690
2708
2691 if not opts.get('close_branch'):
2709 if not opts.get('close_branch'):
2692 for r in parents:
2710 for r in parents:
2693 if r.closesbranch() and r.branch() == branch:
2711 if r.closesbranch() and r.branch() == branch:
2694 repo.ui.status(_('reopening closed branch head %d\n') % r)
2712 repo.ui.status(_('reopening closed branch head %d\n') % r)
2695
2713
2696 if repo.ui.debugflag:
2714 if repo.ui.debugflag:
2697 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
2715 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
2698 elif repo.ui.verbose:
2716 elif repo.ui.verbose:
2699 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
2717 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
2700
2718
2701 def revert(ui, repo, ctx, parents, *pats, **opts):
2719 def revert(ui, repo, ctx, parents, *pats, **opts):
2702 parent, p2 = parents
2720 parent, p2 = parents
2703 node = ctx.node()
2721 node = ctx.node()
2704
2722
2705 mf = ctx.manifest()
2723 mf = ctx.manifest()
2706 if node == p2:
2724 if node == p2:
2707 parent = p2
2725 parent = p2
2708 if node == parent:
2726 if node == parent:
2709 pmf = mf
2727 pmf = mf
2710 else:
2728 else:
2711 pmf = None
2729 pmf = None
2712
2730
2713 # need all matching names in dirstate and manifest of target rev,
2731 # need all matching names in dirstate and manifest of target rev,
2714 # so have to walk both. do not print errors if files exist in one
2732 # so have to walk both. do not print errors if files exist in one
2715 # but not other.
2733 # but not other.
2716
2734
2717 # `names` is a mapping for all elements in working copy and target revision
2735 # `names` is a mapping for all elements in working copy and target revision
2718 # The mapping is in the form:
2736 # The mapping is in the form:
2719 # <asb path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
2737 # <asb path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
2720 names = {}
2738 names = {}
2721
2739
2722 wlock = repo.wlock()
2740 wlock = repo.wlock()
2723 try:
2741 try:
2724 ## filling of the `names` mapping
2742 ## filling of the `names` mapping
2725 # walk dirstate to fill `names`
2743 # walk dirstate to fill `names`
2726
2744
2727 m = scmutil.match(repo[None], pats, opts)
2745 m = scmutil.match(repo[None], pats, opts)
2728 if not m.always() or node != parent:
2746 if not m.always() or node != parent:
2729 m.bad = lambda x, y: False
2747 m.bad = lambda x, y: False
2730 for abs in repo.walk(m):
2748 for abs in repo.walk(m):
2731 names[abs] = m.rel(abs), m.exact(abs)
2749 names[abs] = m.rel(abs), m.exact(abs)
2732
2750
2733 # walk target manifest to fill `names`
2751 # walk target manifest to fill `names`
2734
2752
2735 def badfn(path, msg):
2753 def badfn(path, msg):
2736 if path in names:
2754 if path in names:
2737 return
2755 return
2738 if path in ctx.substate:
2756 if path in ctx.substate:
2739 return
2757 return
2740 path_ = path + '/'
2758 path_ = path + '/'
2741 for f in names:
2759 for f in names:
2742 if f.startswith(path_):
2760 if f.startswith(path_):
2743 return
2761 return
2744 ui.warn("%s: %s\n" % (m.rel(path), msg))
2762 ui.warn("%s: %s\n" % (m.rel(path), msg))
2745
2763
2746 m = scmutil.match(ctx, pats, opts)
2764 m = scmutil.match(ctx, pats, opts)
2747 m.bad = badfn
2765 m.bad = badfn
2748 for abs in ctx.walk(m):
2766 for abs in ctx.walk(m):
2749 if abs not in names:
2767 if abs not in names:
2750 names[abs] = m.rel(abs), m.exact(abs)
2768 names[abs] = m.rel(abs), m.exact(abs)
2751
2769
2752 # Find status of all file in `names`.
2770 # Find status of all file in `names`.
2753 m = scmutil.matchfiles(repo, names)
2771 m = scmutil.matchfiles(repo, names)
2754
2772
2755 changes = repo.status(node1=node, match=m,
2773 changes = repo.status(node1=node, match=m,
2756 unknown=True, ignored=True, clean=True)
2774 unknown=True, ignored=True, clean=True)
2757 else:
2775 else:
2758 changes = repo.status(match=m)
2776 changes = repo.status(match=m)
2759 for kind in changes:
2777 for kind in changes:
2760 for abs in kind:
2778 for abs in kind:
2761 names[abs] = m.rel(abs), m.exact(abs)
2779 names[abs] = m.rel(abs), m.exact(abs)
2762
2780
2763 m = scmutil.matchfiles(repo, names)
2781 m = scmutil.matchfiles(repo, names)
2764
2782
2765 modified = set(changes.modified)
2783 modified = set(changes.modified)
2766 added = set(changes.added)
2784 added = set(changes.added)
2767 removed = set(changes.removed)
2785 removed = set(changes.removed)
2768 _deleted = set(changes.deleted)
2786 _deleted = set(changes.deleted)
2769 unknown = set(changes.unknown)
2787 unknown = set(changes.unknown)
2770 unknown.update(changes.ignored)
2788 unknown.update(changes.ignored)
2771 clean = set(changes.clean)
2789 clean = set(changes.clean)
2772 modadded = set()
2790 modadded = set()
2773
2791
2774 # split between files known in target manifest and the others
2792 # split between files known in target manifest and the others
2775 smf = set(mf)
2793 smf = set(mf)
2776
2794
2777 # determine the exact nature of the deleted changesets
2795 # determine the exact nature of the deleted changesets
2778 deladded = _deleted - smf
2796 deladded = _deleted - smf
2779 deleted = _deleted - deladded
2797 deleted = _deleted - deladded
2780
2798
2781 # We need to account for the state of the file in the dirstate,
2799 # We need to account for the state of the file in the dirstate,
2782 # even when we revert against something else than parent. This will
2800 # even when we revert against something else than parent. This will
2783 # slightly alter the behavior of revert (doing back up or not, delete
2801 # slightly alter the behavior of revert (doing back up or not, delete
2784 # or just forget etc).
2802 # or just forget etc).
2785 if parent == node:
2803 if parent == node:
2786 dsmodified = modified
2804 dsmodified = modified
2787 dsadded = added
2805 dsadded = added
2788 dsremoved = removed
2806 dsremoved = removed
2789 # store all local modifications, useful later for rename detection
2807 # store all local modifications, useful later for rename detection
2790 localchanges = dsmodified | dsadded
2808 localchanges = dsmodified | dsadded
2791 modified, added, removed = set(), set(), set()
2809 modified, added, removed = set(), set(), set()
2792 else:
2810 else:
2793 changes = repo.status(node1=parent, match=m)
2811 changes = repo.status(node1=parent, match=m)
2794 dsmodified = set(changes.modified)
2812 dsmodified = set(changes.modified)
2795 dsadded = set(changes.added)
2813 dsadded = set(changes.added)
2796 dsremoved = set(changes.removed)
2814 dsremoved = set(changes.removed)
2797 # store all local modifications, useful later for rename detection
2815 # store all local modifications, useful later for rename detection
2798 localchanges = dsmodified | dsadded
2816 localchanges = dsmodified | dsadded
2799
2817
2800 # only take into account for removes between wc and target
2818 # only take into account for removes between wc and target
2801 clean |= dsremoved - removed
2819 clean |= dsremoved - removed
2802 dsremoved &= removed
2820 dsremoved &= removed
2803 # distinct between dirstate remove and other
2821 # distinct between dirstate remove and other
2804 removed -= dsremoved
2822 removed -= dsremoved
2805
2823
2806 modadded = added & dsmodified
2824 modadded = added & dsmodified
2807 added -= modadded
2825 added -= modadded
2808
2826
2809 # tell newly modified apart.
2827 # tell newly modified apart.
2810 dsmodified &= modified
2828 dsmodified &= modified
2811 dsmodified |= modified & dsadded # dirstate added may needs backup
2829 dsmodified |= modified & dsadded # dirstate added may needs backup
2812 modified -= dsmodified
2830 modified -= dsmodified
2813
2831
2814 # We need to wait for some post-processing to update this set
2832 # We need to wait for some post-processing to update this set
2815 # before making the distinction. The dirstate will be used for
2833 # before making the distinction. The dirstate will be used for
2816 # that purpose.
2834 # that purpose.
2817 dsadded = added
2835 dsadded = added
2818
2836
2819 # in case of merge, files that are actually added can be reported as
2837 # in case of merge, files that are actually added can be reported as
2820 # modified, we need to post process the result
2838 # modified, we need to post process the result
2821 if p2 != nullid:
2839 if p2 != nullid:
2822 if pmf is None:
2840 if pmf is None:
2823 # only need parent manifest in the merge case,
2841 # only need parent manifest in the merge case,
2824 # so do not read by default
2842 # so do not read by default
2825 pmf = repo[parent].manifest()
2843 pmf = repo[parent].manifest()
2826 mergeadd = dsmodified - set(pmf)
2844 mergeadd = dsmodified - set(pmf)
2827 dsadded |= mergeadd
2845 dsadded |= mergeadd
2828 dsmodified -= mergeadd
2846 dsmodified -= mergeadd
2829
2847
2830 # if f is a rename, update `names` to also revert the source
2848 # if f is a rename, update `names` to also revert the source
2831 cwd = repo.getcwd()
2849 cwd = repo.getcwd()
2832 for f in localchanges:
2850 for f in localchanges:
2833 src = repo.dirstate.copied(f)
2851 src = repo.dirstate.copied(f)
2834 # XXX should we check for rename down to target node?
2852 # XXX should we check for rename down to target node?
2835 if src and src not in names and repo.dirstate[src] == 'r':
2853 if src and src not in names and repo.dirstate[src] == 'r':
2836 dsremoved.add(src)
2854 dsremoved.add(src)
2837 names[src] = (repo.pathto(src, cwd), True)
2855 names[src] = (repo.pathto(src, cwd), True)
2838
2856
2839 # distinguish between file to forget and the other
2857 # distinguish between file to forget and the other
2840 added = set()
2858 added = set()
2841 for abs in dsadded:
2859 for abs in dsadded:
2842 if repo.dirstate[abs] != 'a':
2860 if repo.dirstate[abs] != 'a':
2843 added.add(abs)
2861 added.add(abs)
2844 dsadded -= added
2862 dsadded -= added
2845
2863
2846 for abs in deladded:
2864 for abs in deladded:
2847 if repo.dirstate[abs] == 'a':
2865 if repo.dirstate[abs] == 'a':
2848 dsadded.add(abs)
2866 dsadded.add(abs)
2849 deladded -= dsadded
2867 deladded -= dsadded
2850
2868
2851 # For files marked as removed, we check if an unknown file is present at
2869 # For files marked as removed, we check if an unknown file is present at
2852 # the same path. If a such file exists it may need to be backed up.
2870 # the same path. If a such file exists it may need to be backed up.
2853 # Making the distinction at this stage helps have simpler backup
2871 # Making the distinction at this stage helps have simpler backup
2854 # logic.
2872 # logic.
2855 removunk = set()
2873 removunk = set()
2856 for abs in removed:
2874 for abs in removed:
2857 target = repo.wjoin(abs)
2875 target = repo.wjoin(abs)
2858 if os.path.lexists(target):
2876 if os.path.lexists(target):
2859 removunk.add(abs)
2877 removunk.add(abs)
2860 removed -= removunk
2878 removed -= removunk
2861
2879
2862 dsremovunk = set()
2880 dsremovunk = set()
2863 for abs in dsremoved:
2881 for abs in dsremoved:
2864 target = repo.wjoin(abs)
2882 target = repo.wjoin(abs)
2865 if os.path.lexists(target):
2883 if os.path.lexists(target):
2866 dsremovunk.add(abs)
2884 dsremovunk.add(abs)
2867 dsremoved -= dsremovunk
2885 dsremoved -= dsremovunk
2868
2886
2869 # action to be actually performed by revert
2887 # action to be actually performed by revert
2870 # (<list of file>, message>) tuple
2888 # (<list of file>, message>) tuple
2871 actions = {'revert': ([], _('reverting %s\n')),
2889 actions = {'revert': ([], _('reverting %s\n')),
2872 'add': ([], _('adding %s\n')),
2890 'add': ([], _('adding %s\n')),
2873 'remove': ([], _('removing %s\n')),
2891 'remove': ([], _('removing %s\n')),
2874 'drop': ([], _('removing %s\n')),
2892 'drop': ([], _('removing %s\n')),
2875 'forget': ([], _('forgetting %s\n')),
2893 'forget': ([], _('forgetting %s\n')),
2876 'undelete': ([], _('undeleting %s\n')),
2894 'undelete': ([], _('undeleting %s\n')),
2877 'noop': (None, _('no changes needed to %s\n')),
2895 'noop': (None, _('no changes needed to %s\n')),
2878 'unknown': (None, _('file not managed: %s\n')),
2896 'unknown': (None, _('file not managed: %s\n')),
2879 }
2897 }
2880
2898
2881 # "constant" that convey the backup strategy.
2899 # "constant" that convey the backup strategy.
2882 # All set to `discard` if `no-backup` is set do avoid checking
2900 # All set to `discard` if `no-backup` is set do avoid checking
2883 # no_backup lower in the code.
2901 # no_backup lower in the code.
2884 # These values are ordered for comparison purposes
2902 # These values are ordered for comparison purposes
2885 backup = 2 # unconditionally do backup
2903 backup = 2 # unconditionally do backup
2886 check = 1 # check if the existing file differs from target
2904 check = 1 # check if the existing file differs from target
2887 discard = 0 # never do backup
2905 discard = 0 # never do backup
2888 if opts.get('no_backup'):
2906 if opts.get('no_backup'):
2889 backup = check = discard
2907 backup = check = discard
2890
2908
2891 backupanddel = actions['remove']
2909 backupanddel = actions['remove']
2892 if not opts.get('no_backup'):
2910 if not opts.get('no_backup'):
2893 backupanddel = actions['drop']
2911 backupanddel = actions['drop']
2894
2912
2895 disptable = (
2913 disptable = (
2896 # dispatch table:
2914 # dispatch table:
2897 # file state
2915 # file state
2898 # action
2916 # action
2899 # make backup
2917 # make backup
2900
2918
2901 ## Sets that results that will change file on disk
2919 ## Sets that results that will change file on disk
2902 # Modified compared to target, no local change
2920 # Modified compared to target, no local change
2903 (modified, actions['revert'], discard),
2921 (modified, actions['revert'], discard),
2904 # Modified compared to target, but local file is deleted
2922 # Modified compared to target, but local file is deleted
2905 (deleted, actions['revert'], discard),
2923 (deleted, actions['revert'], discard),
2906 # Modified compared to target, local change
2924 # Modified compared to target, local change
2907 (dsmodified, actions['revert'], backup),
2925 (dsmodified, actions['revert'], backup),
2908 # Added since target
2926 # Added since target
2909 (added, actions['remove'], discard),
2927 (added, actions['remove'], discard),
2910 # Added in working directory
2928 # Added in working directory
2911 (dsadded, actions['forget'], discard),
2929 (dsadded, actions['forget'], discard),
2912 # Added since target, have local modification
2930 # Added since target, have local modification
2913 (modadded, backupanddel, backup),
2931 (modadded, backupanddel, backup),
2914 # Added since target but file is missing in working directory
2932 # Added since target but file is missing in working directory
2915 (deladded, actions['drop'], discard),
2933 (deladded, actions['drop'], discard),
2916 # Removed since target, before working copy parent
2934 # Removed since target, before working copy parent
2917 (removed, actions['add'], discard),
2935 (removed, actions['add'], discard),
2918 # Same as `removed` but an unknown file exists at the same path
2936 # Same as `removed` but an unknown file exists at the same path
2919 (removunk, actions['add'], check),
2937 (removunk, actions['add'], check),
2920 # Removed since targe, marked as such in working copy parent
2938 # Removed since targe, marked as such in working copy parent
2921 (dsremoved, actions['undelete'], discard),
2939 (dsremoved, actions['undelete'], discard),
2922 # Same as `dsremoved` but an unknown file exists at the same path
2940 # Same as `dsremoved` but an unknown file exists at the same path
2923 (dsremovunk, actions['undelete'], check),
2941 (dsremovunk, actions['undelete'], check),
2924 ## the following sets does not result in any file changes
2942 ## the following sets does not result in any file changes
2925 # File with no modification
2943 # File with no modification
2926 (clean, actions['noop'], discard),
2944 (clean, actions['noop'], discard),
2927 # Existing file, not tracked anywhere
2945 # Existing file, not tracked anywhere
2928 (unknown, actions['unknown'], discard),
2946 (unknown, actions['unknown'], discard),
2929 )
2947 )
2930
2948
2931 wctx = repo[None]
2949 wctx = repo[None]
2932 for abs, (rel, exact) in sorted(names.items()):
2950 for abs, (rel, exact) in sorted(names.items()):
2933 # target file to be touch on disk (relative to cwd)
2951 # target file to be touch on disk (relative to cwd)
2934 target = repo.wjoin(abs)
2952 target = repo.wjoin(abs)
2935 # search the entry in the dispatch table.
2953 # search the entry in the dispatch table.
2936 # if the file is in any of these sets, it was touched in the working
2954 # if the file is in any of these sets, it was touched in the working
2937 # directory parent and we are sure it needs to be reverted.
2955 # directory parent and we are sure it needs to be reverted.
2938 for table, (xlist, msg), dobackup in disptable:
2956 for table, (xlist, msg), dobackup in disptable:
2939 if abs not in table:
2957 if abs not in table:
2940 continue
2958 continue
2941 if xlist is not None:
2959 if xlist is not None:
2942 xlist.append(abs)
2960 xlist.append(abs)
2943 if dobackup and (backup <= dobackup
2961 if dobackup and (backup <= dobackup
2944 or wctx[abs].cmp(ctx[abs])):
2962 or wctx[abs].cmp(ctx[abs])):
2945 bakname = "%s.orig" % rel
2963 bakname = "%s.orig" % rel
2946 ui.note(_('saving current version of %s as %s\n') %
2964 ui.note(_('saving current version of %s as %s\n') %
2947 (rel, bakname))
2965 (rel, bakname))
2948 if not opts.get('dry_run'):
2966 if not opts.get('dry_run'):
2949 util.rename(target, bakname)
2967 util.rename(target, bakname)
2950 if ui.verbose or not exact:
2968 if ui.verbose or not exact:
2951 if not isinstance(msg, basestring):
2969 if not isinstance(msg, basestring):
2952 msg = msg(abs)
2970 msg = msg(abs)
2953 ui.status(msg % rel)
2971 ui.status(msg % rel)
2954 elif exact:
2972 elif exact:
2955 ui.warn(msg % rel)
2973 ui.warn(msg % rel)
2956 break
2974 break
2957
2975
2958
2976
2959 if not opts.get('dry_run'):
2977 if not opts.get('dry_run'):
2960 needdata = ('revert', 'add', 'undelete')
2978 needdata = ('revert', 'add', 'undelete')
2961 _revertprefetch(repo, ctx, *[actions[name][0] for name in needdata])
2979 _revertprefetch(repo, ctx, *[actions[name][0] for name in needdata])
2962
2980
2963 _performrevert(repo, parents, ctx, actions)
2981 _performrevert(repo, parents, ctx, actions)
2964
2982
2965 # get the list of subrepos that must be reverted
2983 # get the list of subrepos that must be reverted
2966 subrepomatch = scmutil.match(ctx, pats, opts)
2984 subrepomatch = scmutil.match(ctx, pats, opts)
2967 targetsubs = sorted(s for s in ctx.substate if subrepomatch(s))
2985 targetsubs = sorted(s for s in ctx.substate if subrepomatch(s))
2968
2986
2969 if targetsubs:
2987 if targetsubs:
2970 # Revert the subrepos on the revert list
2988 # Revert the subrepos on the revert list
2971 for sub in targetsubs:
2989 for sub in targetsubs:
2972 ctx.sub(sub).revert(ctx.substate[sub], *pats, **opts)
2990 ctx.sub(sub).revert(ctx.substate[sub], *pats, **opts)
2973 finally:
2991 finally:
2974 wlock.release()
2992 wlock.release()
2975
2993
2976 def _revertprefetch(repo, ctx, *files):
2994 def _revertprefetch(repo, ctx, *files):
2977 """Let extension changing the storage layer prefetch content"""
2995 """Let extension changing the storage layer prefetch content"""
2978 pass
2996 pass
2979
2997
2980 def _performrevert(repo, parents, ctx, actions):
2998 def _performrevert(repo, parents, ctx, actions):
2981 """function that actually perform all the actions computed for revert
2999 """function that actually perform all the actions computed for revert
2982
3000
2983 This is an independent function to let extension to plug in and react to
3001 This is an independent function to let extension to plug in and react to
2984 the imminent revert.
3002 the imminent revert.
2985
3003
2986 Make sure you have the working directory locked when calling this function.
3004 Make sure you have the working directory locked when calling this function.
2987 """
3005 """
2988 parent, p2 = parents
3006 parent, p2 = parents
2989 node = ctx.node()
3007 node = ctx.node()
2990 def checkout(f):
3008 def checkout(f):
2991 fc = ctx[f]
3009 fc = ctx[f]
2992 repo.wwrite(f, fc.data(), fc.flags())
3010 repo.wwrite(f, fc.data(), fc.flags())
2993
3011
2994 audit_path = pathutil.pathauditor(repo.root)
3012 audit_path = pathutil.pathauditor(repo.root)
2995 for f in actions['forget'][0]:
3013 for f in actions['forget'][0]:
2996 repo.dirstate.drop(f)
3014 repo.dirstate.drop(f)
2997 for f in actions['remove'][0]:
3015 for f in actions['remove'][0]:
2998 audit_path(f)
3016 audit_path(f)
2999 util.unlinkpath(repo.wjoin(f))
3017 util.unlinkpath(repo.wjoin(f))
3000 repo.dirstate.remove(f)
3018 repo.dirstate.remove(f)
3001 for f in actions['drop'][0]:
3019 for f in actions['drop'][0]:
3002 audit_path(f)
3020 audit_path(f)
3003 repo.dirstate.remove(f)
3021 repo.dirstate.remove(f)
3004
3022
3005 normal = None
3023 normal = None
3006 if node == parent:
3024 if node == parent:
3007 # We're reverting to our parent. If possible, we'd like status
3025 # We're reverting to our parent. If possible, we'd like status
3008 # to report the file as clean. We have to use normallookup for
3026 # to report the file as clean. We have to use normallookup for
3009 # merges to avoid losing information about merged/dirty files.
3027 # merges to avoid losing information about merged/dirty files.
3010 if p2 != nullid:
3028 if p2 != nullid:
3011 normal = repo.dirstate.normallookup
3029 normal = repo.dirstate.normallookup
3012 else:
3030 else:
3013 normal = repo.dirstate.normal
3031 normal = repo.dirstate.normal
3014 for f in actions['revert'][0]:
3032 for f in actions['revert'][0]:
3015 checkout(f)
3033 checkout(f)
3016 if normal:
3034 if normal:
3017 normal(f)
3035 normal(f)
3018
3036
3019 for f in actions['add'][0]:
3037 for f in actions['add'][0]:
3020 checkout(f)
3038 checkout(f)
3021 repo.dirstate.add(f)
3039 repo.dirstate.add(f)
3022
3040
3023 normal = repo.dirstate.normallookup
3041 normal = repo.dirstate.normallookup
3024 if node == parent and p2 == nullid:
3042 if node == parent and p2 == nullid:
3025 normal = repo.dirstate.normal
3043 normal = repo.dirstate.normal
3026 for f in actions['undelete'][0]:
3044 for f in actions['undelete'][0]:
3027 checkout(f)
3045 checkout(f)
3028 normal(f)
3046 normal(f)
3029
3047
3030 copied = copies.pathcopies(repo[parent], ctx)
3048 copied = copies.pathcopies(repo[parent], ctx)
3031
3049
3032 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
3050 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
3033 if f in copied:
3051 if f in copied:
3034 repo.dirstate.copy(copied[f], f)
3052 repo.dirstate.copy(copied[f], f)
3035
3053
3036 def command(table):
3054 def command(table):
3037 """Returns a function object to be used as a decorator for making commands.
3055 """Returns a function object to be used as a decorator for making commands.
3038
3056
3039 This function receives a command table as its argument. The table should
3057 This function receives a command table as its argument. The table should
3040 be a dict.
3058 be a dict.
3041
3059
3042 The returned function can be used as a decorator for adding commands
3060 The returned function can be used as a decorator for adding commands
3043 to that command table. This function accepts multiple arguments to define
3061 to that command table. This function accepts multiple arguments to define
3044 a command.
3062 a command.
3045
3063
3046 The first argument is the command name.
3064 The first argument is the command name.
3047
3065
3048 The options argument is an iterable of tuples defining command arguments.
3066 The options argument is an iterable of tuples defining command arguments.
3049 See ``mercurial.fancyopts.fancyopts()`` for the format of each tuple.
3067 See ``mercurial.fancyopts.fancyopts()`` for the format of each tuple.
3050
3068
3051 The synopsis argument defines a short, one line summary of how to use the
3069 The synopsis argument defines a short, one line summary of how to use the
3052 command. This shows up in the help output.
3070 command. This shows up in the help output.
3053
3071
3054 The norepo argument defines whether the command does not require a
3072 The norepo argument defines whether the command does not require a
3055 local repository. Most commands operate against a repository, thus the
3073 local repository. Most commands operate against a repository, thus the
3056 default is False.
3074 default is False.
3057
3075
3058 The optionalrepo argument defines whether the command optionally requires
3076 The optionalrepo argument defines whether the command optionally requires
3059 a local repository.
3077 a local repository.
3060
3078
3061 The inferrepo argument defines whether to try to find a repository from the
3079 The inferrepo argument defines whether to try to find a repository from the
3062 command line arguments. If True, arguments will be examined for potential
3080 command line arguments. If True, arguments will be examined for potential
3063 repository locations. See ``findrepo()``. If a repository is found, it
3081 repository locations. See ``findrepo()``. If a repository is found, it
3064 will be used.
3082 will be used.
3065 """
3083 """
3066 def cmd(name, options=(), synopsis=None, norepo=False, optionalrepo=False,
3084 def cmd(name, options=(), synopsis=None, norepo=False, optionalrepo=False,
3067 inferrepo=False):
3085 inferrepo=False):
3068 def decorator(func):
3086 def decorator(func):
3069 if synopsis:
3087 if synopsis:
3070 table[name] = func, list(options), synopsis
3088 table[name] = func, list(options), synopsis
3071 else:
3089 else:
3072 table[name] = func, list(options)
3090 table[name] = func, list(options)
3073
3091
3074 if norepo:
3092 if norepo:
3075 # Avoid import cycle.
3093 # Avoid import cycle.
3076 import commands
3094 import commands
3077 commands.norepo += ' %s' % ' '.join(parsealiases(name))
3095 commands.norepo += ' %s' % ' '.join(parsealiases(name))
3078
3096
3079 if optionalrepo:
3097 if optionalrepo:
3080 import commands
3098 import commands
3081 commands.optionalrepo += ' %s' % ' '.join(parsealiases(name))
3099 commands.optionalrepo += ' %s' % ' '.join(parsealiases(name))
3082
3100
3083 if inferrepo:
3101 if inferrepo:
3084 import commands
3102 import commands
3085 commands.inferrepo += ' %s' % ' '.join(parsealiases(name))
3103 commands.inferrepo += ' %s' % ' '.join(parsealiases(name))
3086
3104
3087 return func
3105 return func
3088 return decorator
3106 return decorator
3089
3107
3090 return cmd
3108 return cmd
3091
3109
3092 # a list of (ui, repo, otherpeer, opts, missing) functions called by
3110 # a list of (ui, repo, otherpeer, opts, missing) functions called by
3093 # commands.outgoing. "missing" is "missing" of the result of
3111 # commands.outgoing. "missing" is "missing" of the result of
3094 # "findcommonoutgoing()"
3112 # "findcommonoutgoing()"
3095 outgoinghooks = util.hooks()
3113 outgoinghooks = util.hooks()
3096
3114
3097 # a list of (ui, repo) functions called by commands.summary
3115 # a list of (ui, repo) functions called by commands.summary
3098 summaryhooks = util.hooks()
3116 summaryhooks = util.hooks()
3099
3117
3100 # a list of (ui, repo, opts, changes) functions called by commands.summary.
3118 # a list of (ui, repo, opts, changes) functions called by commands.summary.
3101 #
3119 #
3102 # functions should return tuple of booleans below, if 'changes' is None:
3120 # functions should return tuple of booleans below, if 'changes' is None:
3103 # (whether-incomings-are-needed, whether-outgoings-are-needed)
3121 # (whether-incomings-are-needed, whether-outgoings-are-needed)
3104 #
3122 #
3105 # otherwise, 'changes' is a tuple of tuples below:
3123 # otherwise, 'changes' is a tuple of tuples below:
3106 # - (sourceurl, sourcebranch, sourcepeer, incoming)
3124 # - (sourceurl, sourcebranch, sourcepeer, incoming)
3107 # - (desturl, destbranch, destpeer, outgoing)
3125 # - (desturl, destbranch, destpeer, outgoing)
3108 summaryremotehooks = util.hooks()
3126 summaryremotehooks = util.hooks()
3109
3127
3110 # A list of state files kept by multistep operations like graft.
3128 # A list of state files kept by multistep operations like graft.
3111 # Since graft cannot be aborted, it is considered 'clearable' by update.
3129 # Since graft cannot be aborted, it is considered 'clearable' by update.
3112 # note: bisect is intentionally excluded
3130 # note: bisect is intentionally excluded
3113 # (state file, clearable, allowcommit, error, hint)
3131 # (state file, clearable, allowcommit, error, hint)
3114 unfinishedstates = [
3132 unfinishedstates = [
3115 ('graftstate', True, False, _('graft in progress'),
3133 ('graftstate', True, False, _('graft in progress'),
3116 _("use 'hg graft --continue' or 'hg update' to abort")),
3134 _("use 'hg graft --continue' or 'hg update' to abort")),
3117 ('updatestate', True, False, _('last update was interrupted'),
3135 ('updatestate', True, False, _('last update was interrupted'),
3118 _("use 'hg update' to get a consistent checkout"))
3136 _("use 'hg update' to get a consistent checkout"))
3119 ]
3137 ]
3120
3138
3121 def checkunfinished(repo, commit=False):
3139 def checkunfinished(repo, commit=False):
3122 '''Look for an unfinished multistep operation, like graft, and abort
3140 '''Look for an unfinished multistep operation, like graft, and abort
3123 if found. It's probably good to check this right before
3141 if found. It's probably good to check this right before
3124 bailifchanged().
3142 bailifchanged().
3125 '''
3143 '''
3126 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3144 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3127 if commit and allowcommit:
3145 if commit and allowcommit:
3128 continue
3146 continue
3129 if repo.vfs.exists(f):
3147 if repo.vfs.exists(f):
3130 raise util.Abort(msg, hint=hint)
3148 raise util.Abort(msg, hint=hint)
3131
3149
3132 def clearunfinished(repo):
3150 def clearunfinished(repo):
3133 '''Check for unfinished operations (as above), and clear the ones
3151 '''Check for unfinished operations (as above), and clear the ones
3134 that are clearable.
3152 that are clearable.
3135 '''
3153 '''
3136 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3154 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3137 if not clearable and repo.vfs.exists(f):
3155 if not clearable and repo.vfs.exists(f):
3138 raise util.Abort(msg, hint=hint)
3156 raise util.Abort(msg, hint=hint)
3139 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3157 for f, clearable, allowcommit, msg, hint in unfinishedstates:
3140 if clearable and repo.vfs.exists(f):
3158 if clearable and repo.vfs.exists(f):
3141 util.unlink(repo.join(f))
3159 util.unlink(repo.join(f))
@@ -1,6338 +1,6326 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, bundle2
24 import phases, obsolete, exchange, bundle2
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, "", False, **opts)
202 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
203 return rejected and 1 or 0
203 return rejected and 1 or 0
204
204
205 @command('addremove',
205 @command('addremove',
206 similarityopts + subrepoopts + walkopts + dryrunopts,
206 similarityopts + subrepoopts + walkopts + dryrunopts,
207 _('[OPTION]... [FILE]...'),
207 _('[OPTION]... [FILE]...'),
208 inferrepo=True)
208 inferrepo=True)
209 def addremove(ui, repo, *pats, **opts):
209 def addremove(ui, repo, *pats, **opts):
210 """add all new files, delete all missing files
210 """add all new files, delete all missing files
211
211
212 Add all new files and remove all missing files from the
212 Add all new files and remove all missing files from the
213 repository.
213 repository.
214
214
215 New files are ignored if they match any of the patterns in
215 New files are ignored if they match any of the patterns in
216 ``.hgignore``. As with add, these changes take effect at the next
216 ``.hgignore``. As with add, these changes take effect at the next
217 commit.
217 commit.
218
218
219 Use the -s/--similarity option to detect renamed files. This
219 Use the -s/--similarity option to detect renamed files. This
220 option takes a percentage between 0 (disabled) and 100 (files must
220 option takes a percentage between 0 (disabled) and 100 (files must
221 be identical) as its parameter. With a parameter greater than 0,
221 be identical) as its parameter. With a parameter greater than 0,
222 this compares every removed file with every added file and records
222 this compares every removed file with every added file and records
223 those similar enough as renames. Detecting renamed files this way
223 those similar enough as renames. Detecting renamed files this way
224 can be expensive. After using this option, :hg:`status -C` can be
224 can be expensive. After using this option, :hg:`status -C` can be
225 used to check which files were identified as moved or renamed. If
225 used to check which files were identified as moved or renamed. If
226 not specified, -s/--similarity defaults to 100 and only renames of
226 not specified, -s/--similarity defaults to 100 and only renames of
227 identical files are detected.
227 identical files are detected.
228
228
229 Returns 0 if all files are successfully added.
229 Returns 0 if all files are successfully added.
230 """
230 """
231 try:
231 try:
232 sim = float(opts.get('similarity') or 100)
232 sim = float(opts.get('similarity') or 100)
233 except ValueError:
233 except ValueError:
234 raise util.Abort(_('similarity must be a number'))
234 raise util.Abort(_('similarity must be a number'))
235 if sim < 0 or sim > 100:
235 if sim < 0 or sim > 100:
236 raise util.Abort(_('similarity must be between 0 and 100'))
236 raise util.Abort(_('similarity must be between 0 and 100'))
237 matcher = scmutil.match(repo[None], pats, opts)
237 matcher = scmutil.match(repo[None], pats, opts)
238 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
238 return scmutil.addremove(repo, matcher, "", 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.difffeatureopts(ui, opts, section='annotate',
319 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
320 whitespace=True)
320 whitespace=True)
321 for abs in ctx.walk(m):
321 for abs in ctx.walk(m):
322 fctx = ctx[abs]
322 fctx = ctx[abs]
323 if not opts.get('text') and util.binary(fctx.data()):
323 if not opts.get('text') and util.binary(fctx.data()):
324 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
324 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
325 continue
325 continue
326
326
327 lines = fctx.annotate(follow=follow, linenumber=linenumber,
327 lines = fctx.annotate(follow=follow, linenumber=linenumber,
328 diffopts=diffopts)
328 diffopts=diffopts)
329 formats = []
329 formats = []
330 pieces = []
330 pieces = []
331
331
332 for f, sep in funcmap:
332 for f, sep in funcmap:
333 l = [f(n) for n, dummy in lines]
333 l = [f(n) for n, dummy in lines]
334 if l:
334 if l:
335 if fm:
335 if fm:
336 formats.append(['%s' for x in l])
336 formats.append(['%s' for x in l])
337 else:
337 else:
338 sizes = [encoding.colwidth(x) for x in l]
338 sizes = [encoding.colwidth(x) for x in l]
339 ml = max(sizes)
339 ml = max(sizes)
340 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
340 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
341 pieces.append(l)
341 pieces.append(l)
342
342
343 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
343 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
344 fm.startitem()
344 fm.startitem()
345 fm.write(fields, "".join(f), *p)
345 fm.write(fields, "".join(f), *p)
346 fm.write('line', ": %s", l[1])
346 fm.write('line', ": %s", l[1])
347
347
348 if lines and not lines[-1][1].endswith('\n'):
348 if lines and not lines[-1][1].endswith('\n'):
349 fm.plain('\n')
349 fm.plain('\n')
350
350
351 fm.end()
351 fm.end()
352
352
353 @command('archive',
353 @command('archive',
354 [('', 'no-decode', None, _('do not pass files through decoders')),
354 [('', 'no-decode', None, _('do not pass files through decoders')),
355 ('p', 'prefix', '', _('directory prefix for files in archive'),
355 ('p', 'prefix', '', _('directory prefix for files in archive'),
356 _('PREFIX')),
356 _('PREFIX')),
357 ('r', 'rev', '', _('revision to distribute'), _('REV')),
357 ('r', 'rev', '', _('revision to distribute'), _('REV')),
358 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
358 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
359 ] + subrepoopts + walkopts,
359 ] + subrepoopts + walkopts,
360 _('[OPTION]... DEST'))
360 _('[OPTION]... DEST'))
361 def archive(ui, repo, dest, **opts):
361 def archive(ui, repo, dest, **opts):
362 '''create an unversioned archive of a repository revision
362 '''create an unversioned archive of a repository revision
363
363
364 By default, the revision used is the parent of the working
364 By default, the revision used is the parent of the working
365 directory; use -r/--rev to specify a different revision.
365 directory; use -r/--rev to specify a different revision.
366
366
367 The archive type is automatically detected based on file
367 The archive type is automatically detected based on file
368 extension (or override using -t/--type).
368 extension (or override using -t/--type).
369
369
370 .. container:: verbose
370 .. container:: verbose
371
371
372 Examples:
372 Examples:
373
373
374 - create a zip file containing the 1.0 release::
374 - create a zip file containing the 1.0 release::
375
375
376 hg archive -r 1.0 project-1.0.zip
376 hg archive -r 1.0 project-1.0.zip
377
377
378 - create a tarball excluding .hg files::
378 - create a tarball excluding .hg files::
379
379
380 hg archive project.tar.gz -X ".hg*"
380 hg archive project.tar.gz -X ".hg*"
381
381
382 Valid types are:
382 Valid types are:
383
383
384 :``files``: a directory full of files (default)
384 :``files``: a directory full of files (default)
385 :``tar``: tar archive, uncompressed
385 :``tar``: tar archive, uncompressed
386 :``tbz2``: tar archive, compressed using bzip2
386 :``tbz2``: tar archive, compressed using bzip2
387 :``tgz``: tar archive, compressed using gzip
387 :``tgz``: tar archive, compressed using gzip
388 :``uzip``: zip archive, uncompressed
388 :``uzip``: zip archive, uncompressed
389 :``zip``: zip archive, compressed using deflate
389 :``zip``: zip archive, compressed using deflate
390
390
391 The exact name of the destination archive or directory is given
391 The exact name of the destination archive or directory is given
392 using a format string; see :hg:`help export` for details.
392 using a format string; see :hg:`help export` for details.
393
393
394 Each member added to an archive file has a directory prefix
394 Each member added to an archive file has a directory prefix
395 prepended. Use -p/--prefix to specify a format string for the
395 prepended. Use -p/--prefix to specify a format string for the
396 prefix. The default is the basename of the archive, with suffixes
396 prefix. The default is the basename of the archive, with suffixes
397 removed.
397 removed.
398
398
399 Returns 0 on success.
399 Returns 0 on success.
400 '''
400 '''
401
401
402 ctx = scmutil.revsingle(repo, opts.get('rev'))
402 ctx = scmutil.revsingle(repo, opts.get('rev'))
403 if not ctx:
403 if not ctx:
404 raise util.Abort(_('no working directory: please specify a revision'))
404 raise util.Abort(_('no working directory: please specify a revision'))
405 node = ctx.node()
405 node = ctx.node()
406 dest = cmdutil.makefilename(repo, dest, node)
406 dest = cmdutil.makefilename(repo, dest, node)
407 if os.path.realpath(dest) == repo.root:
407 if os.path.realpath(dest) == repo.root:
408 raise util.Abort(_('repository root cannot be destination'))
408 raise util.Abort(_('repository root cannot be destination'))
409
409
410 kind = opts.get('type') or archival.guesskind(dest) or 'files'
410 kind = opts.get('type') or archival.guesskind(dest) or 'files'
411 prefix = opts.get('prefix')
411 prefix = opts.get('prefix')
412
412
413 if dest == '-':
413 if dest == '-':
414 if kind == 'files':
414 if kind == 'files':
415 raise util.Abort(_('cannot archive plain files to stdout'))
415 raise util.Abort(_('cannot archive plain files to stdout'))
416 dest = cmdutil.makefileobj(repo, dest)
416 dest = cmdutil.makefileobj(repo, dest)
417 if not prefix:
417 if not prefix:
418 prefix = os.path.basename(repo.root) + '-%h'
418 prefix = os.path.basename(repo.root) + '-%h'
419
419
420 prefix = cmdutil.makefilename(repo, prefix, node)
420 prefix = cmdutil.makefilename(repo, prefix, node)
421 matchfn = scmutil.match(ctx, [], opts)
421 matchfn = scmutil.match(ctx, [], opts)
422 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
422 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
423 matchfn, prefix, subrepos=opts.get('subrepos'))
423 matchfn, prefix, subrepos=opts.get('subrepos'))
424
424
425 @command('backout',
425 @command('backout',
426 [('', 'merge', None, _('merge with old dirstate parent after backout')),
426 [('', 'merge', None, _('merge with old dirstate parent after backout')),
427 ('', 'commit', None, _('commit if no conflicts were encountered')),
427 ('', 'commit', None, _('commit if no conflicts were encountered')),
428 ('', 'parent', '',
428 ('', 'parent', '',
429 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
429 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
430 ('r', 'rev', '', _('revision to backout'), _('REV')),
430 ('r', 'rev', '', _('revision to backout'), _('REV')),
431 ('e', 'edit', False, _('invoke editor on commit messages')),
431 ('e', 'edit', False, _('invoke editor on commit messages')),
432 ] + mergetoolopts + walkopts + commitopts + commitopts2,
432 ] + mergetoolopts + walkopts + commitopts + commitopts2,
433 _('[OPTION]... [-r] REV'))
433 _('[OPTION]... [-r] REV'))
434 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
434 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
435 '''reverse effect of earlier changeset
435 '''reverse effect of earlier changeset
436
436
437 Prepare a new changeset with the effect of REV undone in the
437 Prepare a new changeset with the effect of REV undone in the
438 current working directory.
438 current working directory.
439
439
440 If REV is the parent of the working directory, then this new changeset
440 If REV is the parent of the working directory, then this new changeset
441 is committed automatically. Otherwise, hg needs to merge the
441 is committed automatically. Otherwise, hg needs to merge the
442 changes and the merged result is left uncommitted.
442 changes and the merged result is left uncommitted.
443
443
444 .. note::
444 .. note::
445
445
446 backout cannot be used to fix either an unwanted or
446 backout cannot be used to fix either an unwanted or
447 incorrect merge.
447 incorrect merge.
448
448
449 .. container:: verbose
449 .. container:: verbose
450
450
451 By default, the pending changeset will have one parent,
451 By default, the pending changeset will have one parent,
452 maintaining a linear history. With --merge, the pending
452 maintaining a linear history. With --merge, the pending
453 changeset will instead have two parents: the old parent of the
453 changeset will instead have two parents: the old parent of the
454 working directory and a new child of REV that simply undoes REV.
454 working directory and a new child of REV that simply undoes REV.
455
455
456 Before version 1.7, the behavior without --merge was equivalent
456 Before version 1.7, the behavior without --merge was equivalent
457 to specifying --merge followed by :hg:`update --clean .` to
457 to specifying --merge followed by :hg:`update --clean .` to
458 cancel the merge and leave the child of REV as a head to be
458 cancel the merge and leave the child of REV as a head to be
459 merged separately.
459 merged separately.
460
460
461 See :hg:`help dates` for a list of formats valid for -d/--date.
461 See :hg:`help dates` for a list of formats valid for -d/--date.
462
462
463 Returns 0 on success, 1 if nothing to backout or there are unresolved
463 Returns 0 on success, 1 if nothing to backout or there are unresolved
464 files.
464 files.
465 '''
465 '''
466 if rev and node:
466 if rev and node:
467 raise util.Abort(_("please specify just one revision"))
467 raise util.Abort(_("please specify just one revision"))
468
468
469 if not rev:
469 if not rev:
470 rev = node
470 rev = node
471
471
472 if not rev:
472 if not rev:
473 raise util.Abort(_("please specify a revision to backout"))
473 raise util.Abort(_("please specify a revision to backout"))
474
474
475 date = opts.get('date')
475 date = opts.get('date')
476 if date:
476 if date:
477 opts['date'] = util.parsedate(date)
477 opts['date'] = util.parsedate(date)
478
478
479 cmdutil.checkunfinished(repo)
479 cmdutil.checkunfinished(repo)
480 cmdutil.bailifchanged(repo)
480 cmdutil.bailifchanged(repo)
481 node = scmutil.revsingle(repo, rev).node()
481 node = scmutil.revsingle(repo, rev).node()
482
482
483 op1, op2 = repo.dirstate.parents()
483 op1, op2 = repo.dirstate.parents()
484 if not repo.changelog.isancestor(node, op1):
484 if not repo.changelog.isancestor(node, op1):
485 raise util.Abort(_('cannot backout change that is not an ancestor'))
485 raise util.Abort(_('cannot backout change that is not an ancestor'))
486
486
487 p1, p2 = repo.changelog.parents(node)
487 p1, p2 = repo.changelog.parents(node)
488 if p1 == nullid:
488 if p1 == nullid:
489 raise util.Abort(_('cannot backout a change with no parents'))
489 raise util.Abort(_('cannot backout a change with no parents'))
490 if p2 != nullid:
490 if p2 != nullid:
491 if not opts.get('parent'):
491 if not opts.get('parent'):
492 raise util.Abort(_('cannot backout a merge changeset'))
492 raise util.Abort(_('cannot backout a merge changeset'))
493 p = repo.lookup(opts['parent'])
493 p = repo.lookup(opts['parent'])
494 if p not in (p1, p2):
494 if p not in (p1, p2):
495 raise util.Abort(_('%s is not a parent of %s') %
495 raise util.Abort(_('%s is not a parent of %s') %
496 (short(p), short(node)))
496 (short(p), short(node)))
497 parent = p
497 parent = p
498 else:
498 else:
499 if opts.get('parent'):
499 if opts.get('parent'):
500 raise util.Abort(_('cannot use --parent on non-merge changeset'))
500 raise util.Abort(_('cannot use --parent on non-merge changeset'))
501 parent = p1
501 parent = p1
502
502
503 # the backout should appear on the same branch
503 # the backout should appear on the same branch
504 wlock = repo.wlock()
504 wlock = repo.wlock()
505 try:
505 try:
506 branch = repo.dirstate.branch()
506 branch = repo.dirstate.branch()
507 bheads = repo.branchheads(branch)
507 bheads = repo.branchheads(branch)
508 rctx = scmutil.revsingle(repo, hex(parent))
508 rctx = scmutil.revsingle(repo, hex(parent))
509 if not opts.get('merge') and op1 != node:
509 if not opts.get('merge') and op1 != node:
510 try:
510 try:
511 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
511 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
512 'backout')
512 'backout')
513 repo.dirstate.beginparentchange()
513 repo.dirstate.beginparentchange()
514 stats = mergemod.update(repo, parent, True, True, False,
514 stats = mergemod.update(repo, parent, True, True, False,
515 node, False)
515 node, False)
516 repo.setparents(op1, op2)
516 repo.setparents(op1, op2)
517 repo.dirstate.endparentchange()
517 repo.dirstate.endparentchange()
518 hg._showstats(repo, stats)
518 hg._showstats(repo, stats)
519 if stats[3]:
519 if stats[3]:
520 repo.ui.status(_("use 'hg resolve' to retry unresolved "
520 repo.ui.status(_("use 'hg resolve' to retry unresolved "
521 "file merges\n"))
521 "file merges\n"))
522 return 1
522 return 1
523 elif not commit:
523 elif not commit:
524 msg = _("changeset %s backed out, "
524 msg = _("changeset %s backed out, "
525 "don't forget to commit.\n")
525 "don't forget to commit.\n")
526 ui.status(msg % short(node))
526 ui.status(msg % short(node))
527 return 0
527 return 0
528 finally:
528 finally:
529 ui.setconfig('ui', 'forcemerge', '', '')
529 ui.setconfig('ui', 'forcemerge', '', '')
530 else:
530 else:
531 hg.clean(repo, node, show_stats=False)
531 hg.clean(repo, node, show_stats=False)
532 repo.dirstate.setbranch(branch)
532 repo.dirstate.setbranch(branch)
533 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
533 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
534
534
535
535
536 def commitfunc(ui, repo, message, match, opts):
536 def commitfunc(ui, repo, message, match, opts):
537 editform = 'backout'
537 editform = 'backout'
538 e = cmdutil.getcommiteditor(editform=editform, **opts)
538 e = cmdutil.getcommiteditor(editform=editform, **opts)
539 if not message:
539 if not message:
540 # we don't translate commit messages
540 # we don't translate commit messages
541 message = "Backed out changeset %s" % short(node)
541 message = "Backed out changeset %s" % short(node)
542 e = cmdutil.getcommiteditor(edit=True, editform=editform)
542 e = cmdutil.getcommiteditor(edit=True, editform=editform)
543 return repo.commit(message, opts.get('user'), opts.get('date'),
543 return repo.commit(message, opts.get('user'), opts.get('date'),
544 match, editor=e)
544 match, editor=e)
545 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
545 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
546 if not newnode:
546 if not newnode:
547 ui.status(_("nothing changed\n"))
547 ui.status(_("nothing changed\n"))
548 return 1
548 return 1
549 cmdutil.commitstatus(repo, newnode, branch, bheads)
549 cmdutil.commitstatus(repo, newnode, branch, bheads)
550
550
551 def nice(node):
551 def nice(node):
552 return '%d:%s' % (repo.changelog.rev(node), short(node))
552 return '%d:%s' % (repo.changelog.rev(node), short(node))
553 ui.status(_('changeset %s backs out changeset %s\n') %
553 ui.status(_('changeset %s backs out changeset %s\n') %
554 (nice(repo.changelog.tip()), nice(node)))
554 (nice(repo.changelog.tip()), nice(node)))
555 if opts.get('merge') and op1 != node:
555 if opts.get('merge') and op1 != node:
556 hg.clean(repo, op1, show_stats=False)
556 hg.clean(repo, op1, show_stats=False)
557 ui.status(_('merging with changeset %s\n')
557 ui.status(_('merging with changeset %s\n')
558 % nice(repo.changelog.tip()))
558 % nice(repo.changelog.tip()))
559 try:
559 try:
560 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
560 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
561 'backout')
561 'backout')
562 return hg.merge(repo, hex(repo.changelog.tip()))
562 return hg.merge(repo, hex(repo.changelog.tip()))
563 finally:
563 finally:
564 ui.setconfig('ui', 'forcemerge', '', '')
564 ui.setconfig('ui', 'forcemerge', '', '')
565 finally:
565 finally:
566 wlock.release()
566 wlock.release()
567 return 0
567 return 0
568
568
569 @command('bisect',
569 @command('bisect',
570 [('r', 'reset', False, _('reset bisect state')),
570 [('r', 'reset', False, _('reset bisect state')),
571 ('g', 'good', False, _('mark changeset good')),
571 ('g', 'good', False, _('mark changeset good')),
572 ('b', 'bad', False, _('mark changeset bad')),
572 ('b', 'bad', False, _('mark changeset bad')),
573 ('s', 'skip', False, _('skip testing changeset')),
573 ('s', 'skip', False, _('skip testing changeset')),
574 ('e', 'extend', False, _('extend the bisect range')),
574 ('e', 'extend', False, _('extend the bisect range')),
575 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
575 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
576 ('U', 'noupdate', False, _('do not update to target'))],
576 ('U', 'noupdate', False, _('do not update to target'))],
577 _("[-gbsr] [-U] [-c CMD] [REV]"))
577 _("[-gbsr] [-U] [-c CMD] [REV]"))
578 def bisect(ui, repo, rev=None, extra=None, command=None,
578 def bisect(ui, repo, rev=None, extra=None, command=None,
579 reset=None, good=None, bad=None, skip=None, extend=None,
579 reset=None, good=None, bad=None, skip=None, extend=None,
580 noupdate=None):
580 noupdate=None):
581 """subdivision search of changesets
581 """subdivision search of changesets
582
582
583 This command helps to find changesets which introduce problems. To
583 This command helps to find changesets which introduce problems. To
584 use, mark the earliest changeset you know exhibits the problem as
584 use, mark the earliest changeset you know exhibits the problem as
585 bad, then mark the latest changeset which is free from the problem
585 bad, then mark the latest changeset which is free from the problem
586 as good. Bisect will update your working directory to a revision
586 as good. Bisect will update your working directory to a revision
587 for testing (unless the -U/--noupdate option is specified). Once
587 for testing (unless the -U/--noupdate option is specified). Once
588 you have performed tests, mark the working directory as good or
588 you have performed tests, mark the working directory as good or
589 bad, and bisect will either update to another candidate changeset
589 bad, and bisect will either update to another candidate changeset
590 or announce that it has found the bad revision.
590 or announce that it has found the bad revision.
591
591
592 As a shortcut, you can also use the revision argument to mark a
592 As a shortcut, you can also use the revision argument to mark a
593 revision as good or bad without checking it out first.
593 revision as good or bad without checking it out first.
594
594
595 If you supply a command, it will be used for automatic bisection.
595 If you supply a command, it will be used for automatic bisection.
596 The environment variable HG_NODE will contain the ID of the
596 The environment variable HG_NODE will contain the ID of the
597 changeset being tested. The exit status of the command will be
597 changeset being tested. The exit status of the command will be
598 used to mark revisions as good or bad: status 0 means good, 125
598 used to mark revisions as good or bad: status 0 means good, 125
599 means to skip the revision, 127 (command not found) will abort the
599 means to skip the revision, 127 (command not found) will abort the
600 bisection, and any other non-zero exit status means the revision
600 bisection, and any other non-zero exit status means the revision
601 is bad.
601 is bad.
602
602
603 .. container:: verbose
603 .. container:: verbose
604
604
605 Some examples:
605 Some examples:
606
606
607 - start a bisection with known bad revision 34, and good revision 12::
607 - start a bisection with known bad revision 34, and good revision 12::
608
608
609 hg bisect --bad 34
609 hg bisect --bad 34
610 hg bisect --good 12
610 hg bisect --good 12
611
611
612 - advance the current bisection by marking current revision as good or
612 - advance the current bisection by marking current revision as good or
613 bad::
613 bad::
614
614
615 hg bisect --good
615 hg bisect --good
616 hg bisect --bad
616 hg bisect --bad
617
617
618 - mark the current revision, or a known revision, to be skipped (e.g. if
618 - mark the current revision, or a known revision, to be skipped (e.g. if
619 that revision is not usable because of another issue)::
619 that revision is not usable because of another issue)::
620
620
621 hg bisect --skip
621 hg bisect --skip
622 hg bisect --skip 23
622 hg bisect --skip 23
623
623
624 - skip all revisions that do not touch directories ``foo`` or ``bar``::
624 - skip all revisions that do not touch directories ``foo`` or ``bar``::
625
625
626 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
626 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
627
627
628 - forget the current bisection::
628 - forget the current bisection::
629
629
630 hg bisect --reset
630 hg bisect --reset
631
631
632 - use 'make && make tests' to automatically find the first broken
632 - use 'make && make tests' to automatically find the first broken
633 revision::
633 revision::
634
634
635 hg bisect --reset
635 hg bisect --reset
636 hg bisect --bad 34
636 hg bisect --bad 34
637 hg bisect --good 12
637 hg bisect --good 12
638 hg bisect --command "make && make tests"
638 hg bisect --command "make && make tests"
639
639
640 - see all changesets whose states are already known in the current
640 - see all changesets whose states are already known in the current
641 bisection::
641 bisection::
642
642
643 hg log -r "bisect(pruned)"
643 hg log -r "bisect(pruned)"
644
644
645 - see the changeset currently being bisected (especially useful
645 - see the changeset currently being bisected (especially useful
646 if running with -U/--noupdate)::
646 if running with -U/--noupdate)::
647
647
648 hg log -r "bisect(current)"
648 hg log -r "bisect(current)"
649
649
650 - see all changesets that took part in the current bisection::
650 - see all changesets that took part in the current bisection::
651
651
652 hg log -r "bisect(range)"
652 hg log -r "bisect(range)"
653
653
654 - you can even get a nice graph::
654 - you can even get a nice graph::
655
655
656 hg log --graph -r "bisect(range)"
656 hg log --graph -r "bisect(range)"
657
657
658 See :hg:`help revsets` for more about the `bisect()` keyword.
658 See :hg:`help revsets` for more about the `bisect()` keyword.
659
659
660 Returns 0 on success.
660 Returns 0 on success.
661 """
661 """
662 def extendbisectrange(nodes, good):
662 def extendbisectrange(nodes, good):
663 # bisect is incomplete when it ends on a merge node and
663 # bisect is incomplete when it ends on a merge node and
664 # one of the parent was not checked.
664 # one of the parent was not checked.
665 parents = repo[nodes[0]].parents()
665 parents = repo[nodes[0]].parents()
666 if len(parents) > 1:
666 if len(parents) > 1:
667 side = good and state['bad'] or state['good']
667 side = good and state['bad'] or state['good']
668 num = len(set(i.node() for i in parents) & set(side))
668 num = len(set(i.node() for i in parents) & set(side))
669 if num == 1:
669 if num == 1:
670 return parents[0].ancestor(parents[1])
670 return parents[0].ancestor(parents[1])
671 return None
671 return None
672
672
673 def print_result(nodes, good):
673 def print_result(nodes, good):
674 displayer = cmdutil.show_changeset(ui, repo, {})
674 displayer = cmdutil.show_changeset(ui, repo, {})
675 if len(nodes) == 1:
675 if len(nodes) == 1:
676 # narrowed it down to a single revision
676 # narrowed it down to a single revision
677 if good:
677 if good:
678 ui.write(_("The first good revision is:\n"))
678 ui.write(_("The first good revision is:\n"))
679 else:
679 else:
680 ui.write(_("The first bad revision is:\n"))
680 ui.write(_("The first bad revision is:\n"))
681 displayer.show(repo[nodes[0]])
681 displayer.show(repo[nodes[0]])
682 extendnode = extendbisectrange(nodes, good)
682 extendnode = extendbisectrange(nodes, good)
683 if extendnode is not None:
683 if extendnode is not None:
684 ui.write(_('Not all ancestors of this changeset have been'
684 ui.write(_('Not all ancestors of this changeset have been'
685 ' checked.\nUse bisect --extend to continue the '
685 ' checked.\nUse bisect --extend to continue the '
686 'bisection from\nthe common ancestor, %s.\n')
686 'bisection from\nthe common ancestor, %s.\n')
687 % extendnode)
687 % extendnode)
688 else:
688 else:
689 # multiple possible revisions
689 # multiple possible revisions
690 if good:
690 if good:
691 ui.write(_("Due to skipped revisions, the first "
691 ui.write(_("Due to skipped revisions, the first "
692 "good revision could be any of:\n"))
692 "good revision could be any of:\n"))
693 else:
693 else:
694 ui.write(_("Due to skipped revisions, the first "
694 ui.write(_("Due to skipped revisions, the first "
695 "bad revision could be any of:\n"))
695 "bad revision could be any of:\n"))
696 for n in nodes:
696 for n in nodes:
697 displayer.show(repo[n])
697 displayer.show(repo[n])
698 displayer.close()
698 displayer.close()
699
699
700 def check_state(state, interactive=True):
700 def check_state(state, interactive=True):
701 if not state['good'] or not state['bad']:
701 if not state['good'] or not state['bad']:
702 if (good or bad or skip or reset) and interactive:
702 if (good or bad or skip or reset) and interactive:
703 return
703 return
704 if not state['good']:
704 if not state['good']:
705 raise util.Abort(_('cannot bisect (no known good revisions)'))
705 raise util.Abort(_('cannot bisect (no known good revisions)'))
706 else:
706 else:
707 raise util.Abort(_('cannot bisect (no known bad revisions)'))
707 raise util.Abort(_('cannot bisect (no known bad revisions)'))
708 return True
708 return True
709
709
710 # backward compatibility
710 # backward compatibility
711 if rev in "good bad reset init".split():
711 if rev in "good bad reset init".split():
712 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
712 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
713 cmd, rev, extra = rev, extra, None
713 cmd, rev, extra = rev, extra, None
714 if cmd == "good":
714 if cmd == "good":
715 good = True
715 good = True
716 elif cmd == "bad":
716 elif cmd == "bad":
717 bad = True
717 bad = True
718 else:
718 else:
719 reset = True
719 reset = True
720 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
720 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
721 raise util.Abort(_('incompatible arguments'))
721 raise util.Abort(_('incompatible arguments'))
722
722
723 cmdutil.checkunfinished(repo)
723 cmdutil.checkunfinished(repo)
724
724
725 if reset:
725 if reset:
726 p = repo.join("bisect.state")
726 p = repo.join("bisect.state")
727 if os.path.exists(p):
727 if os.path.exists(p):
728 os.unlink(p)
728 os.unlink(p)
729 return
729 return
730
730
731 state = hbisect.load_state(repo)
731 state = hbisect.load_state(repo)
732
732
733 if command:
733 if command:
734 changesets = 1
734 changesets = 1
735 if noupdate:
735 if noupdate:
736 try:
736 try:
737 node = state['current'][0]
737 node = state['current'][0]
738 except LookupError:
738 except LookupError:
739 raise util.Abort(_('current bisect revision is unknown - '
739 raise util.Abort(_('current bisect revision is unknown - '
740 'start a new bisect to fix'))
740 'start a new bisect to fix'))
741 else:
741 else:
742 node, p2 = repo.dirstate.parents()
742 node, p2 = repo.dirstate.parents()
743 if p2 != nullid:
743 if p2 != nullid:
744 raise util.Abort(_('current bisect revision is a merge'))
744 raise util.Abort(_('current bisect revision is a merge'))
745 try:
745 try:
746 while changesets:
746 while changesets:
747 # update state
747 # update state
748 state['current'] = [node]
748 state['current'] = [node]
749 hbisect.save_state(repo, state)
749 hbisect.save_state(repo, state)
750 status = ui.system(command, environ={'HG_NODE': hex(node)})
750 status = ui.system(command, environ={'HG_NODE': hex(node)})
751 if status == 125:
751 if status == 125:
752 transition = "skip"
752 transition = "skip"
753 elif status == 0:
753 elif status == 0:
754 transition = "good"
754 transition = "good"
755 # status < 0 means process was killed
755 # status < 0 means process was killed
756 elif status == 127:
756 elif status == 127:
757 raise util.Abort(_("failed to execute %s") % command)
757 raise util.Abort(_("failed to execute %s") % command)
758 elif status < 0:
758 elif status < 0:
759 raise util.Abort(_("%s killed") % command)
759 raise util.Abort(_("%s killed") % command)
760 else:
760 else:
761 transition = "bad"
761 transition = "bad"
762 ctx = scmutil.revsingle(repo, rev, node)
762 ctx = scmutil.revsingle(repo, rev, node)
763 rev = None # clear for future iterations
763 rev = None # clear for future iterations
764 state[transition].append(ctx.node())
764 state[transition].append(ctx.node())
765 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
765 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
766 check_state(state, interactive=False)
766 check_state(state, interactive=False)
767 # bisect
767 # bisect
768 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
768 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
769 # update to next check
769 # update to next check
770 node = nodes[0]
770 node = nodes[0]
771 if not noupdate:
771 if not noupdate:
772 cmdutil.bailifchanged(repo)
772 cmdutil.bailifchanged(repo)
773 hg.clean(repo, node, show_stats=False)
773 hg.clean(repo, node, show_stats=False)
774 finally:
774 finally:
775 state['current'] = [node]
775 state['current'] = [node]
776 hbisect.save_state(repo, state)
776 hbisect.save_state(repo, state)
777 print_result(nodes, bgood)
777 print_result(nodes, bgood)
778 return
778 return
779
779
780 # update state
780 # update state
781
781
782 if rev:
782 if rev:
783 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
783 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
784 else:
784 else:
785 nodes = [repo.lookup('.')]
785 nodes = [repo.lookup('.')]
786
786
787 if good or bad or skip:
787 if good or bad or skip:
788 if good:
788 if good:
789 state['good'] += nodes
789 state['good'] += nodes
790 elif bad:
790 elif bad:
791 state['bad'] += nodes
791 state['bad'] += nodes
792 elif skip:
792 elif skip:
793 state['skip'] += nodes
793 state['skip'] += nodes
794 hbisect.save_state(repo, state)
794 hbisect.save_state(repo, state)
795
795
796 if not check_state(state):
796 if not check_state(state):
797 return
797 return
798
798
799 # actually bisect
799 # actually bisect
800 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
800 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
801 if extend:
801 if extend:
802 if not changesets:
802 if not changesets:
803 extendnode = extendbisectrange(nodes, good)
803 extendnode = extendbisectrange(nodes, good)
804 if extendnode is not None:
804 if extendnode is not None:
805 ui.write(_("Extending search to changeset %d:%s\n")
805 ui.write(_("Extending search to changeset %d:%s\n")
806 % (extendnode.rev(), extendnode))
806 % (extendnode.rev(), extendnode))
807 state['current'] = [extendnode.node()]
807 state['current'] = [extendnode.node()]
808 hbisect.save_state(repo, state)
808 hbisect.save_state(repo, state)
809 if noupdate:
809 if noupdate:
810 return
810 return
811 cmdutil.bailifchanged(repo)
811 cmdutil.bailifchanged(repo)
812 return hg.clean(repo, extendnode.node())
812 return hg.clean(repo, extendnode.node())
813 raise util.Abort(_("nothing to extend"))
813 raise util.Abort(_("nothing to extend"))
814
814
815 if changesets == 0:
815 if changesets == 0:
816 print_result(nodes, good)
816 print_result(nodes, good)
817 else:
817 else:
818 assert len(nodes) == 1 # only a single node can be tested next
818 assert len(nodes) == 1 # only a single node can be tested next
819 node = nodes[0]
819 node = nodes[0]
820 # compute the approximate number of remaining tests
820 # compute the approximate number of remaining tests
821 tests, size = 0, 2
821 tests, size = 0, 2
822 while size <= changesets:
822 while size <= changesets:
823 tests, size = tests + 1, size * 2
823 tests, size = tests + 1, size * 2
824 rev = repo.changelog.rev(node)
824 rev = repo.changelog.rev(node)
825 ui.write(_("Testing changeset %d:%s "
825 ui.write(_("Testing changeset %d:%s "
826 "(%d changesets remaining, ~%d tests)\n")
826 "(%d changesets remaining, ~%d tests)\n")
827 % (rev, short(node), changesets, tests))
827 % (rev, short(node), changesets, tests))
828 state['current'] = [node]
828 state['current'] = [node]
829 hbisect.save_state(repo, state)
829 hbisect.save_state(repo, state)
830 if not noupdate:
830 if not noupdate:
831 cmdutil.bailifchanged(repo)
831 cmdutil.bailifchanged(repo)
832 return hg.clean(repo, node)
832 return hg.clean(repo, node)
833
833
834 @command('bookmarks|bookmark',
834 @command('bookmarks|bookmark',
835 [('f', 'force', False, _('force')),
835 [('f', 'force', False, _('force')),
836 ('r', 'rev', '', _('revision'), _('REV')),
836 ('r', 'rev', '', _('revision'), _('REV')),
837 ('d', 'delete', False, _('delete a given bookmark')),
837 ('d', 'delete', False, _('delete a given bookmark')),
838 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
838 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
839 ('i', 'inactive', False, _('mark a bookmark inactive')),
839 ('i', 'inactive', False, _('mark a bookmark inactive')),
840 ] + formatteropts,
840 ] + formatteropts,
841 _('hg bookmarks [OPTIONS]... [NAME]...'))
841 _('hg bookmarks [OPTIONS]... [NAME]...'))
842 def bookmark(ui, repo, *names, **opts):
842 def bookmark(ui, repo, *names, **opts):
843 '''create a new bookmark or list existing bookmarks
843 '''create a new bookmark or list existing bookmarks
844
844
845 Bookmarks are labels on changesets to help track lines of development.
845 Bookmarks are labels on changesets to help track lines of development.
846 Bookmarks are unversioned and can be moved, renamed and deleted.
846 Bookmarks are unversioned and can be moved, renamed and deleted.
847 Deleting or moving a bookmark has no effect on the associated changesets.
847 Deleting or moving a bookmark has no effect on the associated changesets.
848
848
849 Creating or updating to a bookmark causes it to be marked as 'active'.
849 Creating or updating to a bookmark causes it to be marked as 'active'.
850 The active bookmark is indicated with a '*'.
850 The active bookmark is indicated with a '*'.
851 When a commit is made, the active bookmark will advance to the new commit.
851 When a commit is made, the active bookmark will advance to the new commit.
852 A plain :hg:`update` will also advance an active bookmark, if possible.
852 A plain :hg:`update` will also advance an active bookmark, if possible.
853 Updating away from a bookmark will cause it to be deactivated.
853 Updating away from a bookmark will cause it to be deactivated.
854
854
855 Bookmarks can be pushed and pulled between repositories (see
855 Bookmarks can be pushed and pulled between repositories (see
856 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
856 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
857 diverged, a new 'divergent bookmark' of the form 'name@path' will
857 diverged, a new 'divergent bookmark' of the form 'name@path' will
858 be created. Using :hg:`merge` will resolve the divergence.
858 be created. Using :hg:`merge` will resolve the divergence.
859
859
860 A bookmark named '@' has the special property that :hg:`clone` will
860 A bookmark named '@' has the special property that :hg:`clone` will
861 check it out by default if it exists.
861 check it out by default if it exists.
862
862
863 .. container:: verbose
863 .. container:: verbose
864
864
865 Examples:
865 Examples:
866
866
867 - create an active bookmark for a new line of development::
867 - create an active bookmark for a new line of development::
868
868
869 hg book new-feature
869 hg book new-feature
870
870
871 - create an inactive bookmark as a place marker::
871 - create an inactive bookmark as a place marker::
872
872
873 hg book -i reviewed
873 hg book -i reviewed
874
874
875 - create an inactive bookmark on another changeset::
875 - create an inactive bookmark on another changeset::
876
876
877 hg book -r .^ tested
877 hg book -r .^ tested
878
878
879 - move the '@' bookmark from another branch::
879 - move the '@' bookmark from another branch::
880
880
881 hg book -f @
881 hg book -f @
882 '''
882 '''
883 force = opts.get('force')
883 force = opts.get('force')
884 rev = opts.get('rev')
884 rev = opts.get('rev')
885 delete = opts.get('delete')
885 delete = opts.get('delete')
886 rename = opts.get('rename')
886 rename = opts.get('rename')
887 inactive = opts.get('inactive')
887 inactive = opts.get('inactive')
888
888
889 def checkformat(mark):
889 def checkformat(mark):
890 mark = mark.strip()
890 mark = mark.strip()
891 if not mark:
891 if not mark:
892 raise util.Abort(_("bookmark names cannot consist entirely of "
892 raise util.Abort(_("bookmark names cannot consist entirely of "
893 "whitespace"))
893 "whitespace"))
894 scmutil.checknewlabel(repo, mark, 'bookmark')
894 scmutil.checknewlabel(repo, mark, 'bookmark')
895 return mark
895 return mark
896
896
897 def checkconflict(repo, mark, cur, force=False, target=None):
897 def checkconflict(repo, mark, cur, force=False, target=None):
898 if mark in marks and not force:
898 if mark in marks and not force:
899 if target:
899 if target:
900 if marks[mark] == target and target == cur:
900 if marks[mark] == target and target == cur:
901 # re-activating a bookmark
901 # re-activating a bookmark
902 return
902 return
903 anc = repo.changelog.ancestors([repo[target].rev()])
903 anc = repo.changelog.ancestors([repo[target].rev()])
904 bmctx = repo[marks[mark]]
904 bmctx = repo[marks[mark]]
905 divs = [repo[b].node() for b in marks
905 divs = [repo[b].node() for b in marks
906 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
906 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
907
907
908 # allow resolving a single divergent bookmark even if moving
908 # allow resolving a single divergent bookmark even if moving
909 # the bookmark across branches when a revision is specified
909 # the bookmark across branches when a revision is specified
910 # that contains a divergent bookmark
910 # that contains a divergent bookmark
911 if bmctx.rev() not in anc and target in divs:
911 if bmctx.rev() not in anc and target in divs:
912 bookmarks.deletedivergent(repo, [target], mark)
912 bookmarks.deletedivergent(repo, [target], mark)
913 return
913 return
914
914
915 deletefrom = [b for b in divs
915 deletefrom = [b for b in divs
916 if repo[b].rev() in anc or b == target]
916 if repo[b].rev() in anc or b == target]
917 bookmarks.deletedivergent(repo, deletefrom, mark)
917 bookmarks.deletedivergent(repo, deletefrom, mark)
918 if bookmarks.validdest(repo, bmctx, repo[target]):
918 if bookmarks.validdest(repo, bmctx, repo[target]):
919 ui.status(_("moving bookmark '%s' forward from %s\n") %
919 ui.status(_("moving bookmark '%s' forward from %s\n") %
920 (mark, short(bmctx.node())))
920 (mark, short(bmctx.node())))
921 return
921 return
922 raise util.Abort(_("bookmark '%s' already exists "
922 raise util.Abort(_("bookmark '%s' already exists "
923 "(use -f to force)") % mark)
923 "(use -f to force)") % mark)
924 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
924 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
925 and not force):
925 and not force):
926 raise util.Abort(
926 raise util.Abort(
927 _("a bookmark cannot have the name of an existing branch"))
927 _("a bookmark cannot have the name of an existing branch"))
928
928
929 if delete and rename:
929 if delete and rename:
930 raise util.Abort(_("--delete and --rename are incompatible"))
930 raise util.Abort(_("--delete and --rename are incompatible"))
931 if delete and rev:
931 if delete and rev:
932 raise util.Abort(_("--rev is incompatible with --delete"))
932 raise util.Abort(_("--rev is incompatible with --delete"))
933 if rename and rev:
933 if rename and rev:
934 raise util.Abort(_("--rev is incompatible with --rename"))
934 raise util.Abort(_("--rev is incompatible with --rename"))
935 if not names and (delete or rev):
935 if not names and (delete or rev):
936 raise util.Abort(_("bookmark name required"))
936 raise util.Abort(_("bookmark name required"))
937
937
938 if delete or rename or names or inactive:
938 if delete or rename or names or inactive:
939 wlock = repo.wlock()
939 wlock = repo.wlock()
940 try:
940 try:
941 cur = repo.changectx('.').node()
941 cur = repo.changectx('.').node()
942 marks = repo._bookmarks
942 marks = repo._bookmarks
943 if delete:
943 if delete:
944 for mark in names:
944 for mark in names:
945 if mark not in marks:
945 if mark not in marks:
946 raise util.Abort(_("bookmark '%s' does not exist") %
946 raise util.Abort(_("bookmark '%s' does not exist") %
947 mark)
947 mark)
948 if mark == repo._bookmarkcurrent:
948 if mark == repo._bookmarkcurrent:
949 bookmarks.unsetcurrent(repo)
949 bookmarks.unsetcurrent(repo)
950 del marks[mark]
950 del marks[mark]
951 marks.write()
951 marks.write()
952
952
953 elif rename:
953 elif rename:
954 if not names:
954 if not names:
955 raise util.Abort(_("new bookmark name required"))
955 raise util.Abort(_("new bookmark name required"))
956 elif len(names) > 1:
956 elif len(names) > 1:
957 raise util.Abort(_("only one new bookmark name allowed"))
957 raise util.Abort(_("only one new bookmark name allowed"))
958 mark = checkformat(names[0])
958 mark = checkformat(names[0])
959 if rename not in marks:
959 if rename not in marks:
960 raise util.Abort(_("bookmark '%s' does not exist") % rename)
960 raise util.Abort(_("bookmark '%s' does not exist") % rename)
961 checkconflict(repo, mark, cur, force)
961 checkconflict(repo, mark, cur, force)
962 marks[mark] = marks[rename]
962 marks[mark] = marks[rename]
963 if repo._bookmarkcurrent == rename and not inactive:
963 if repo._bookmarkcurrent == rename and not inactive:
964 bookmarks.setcurrent(repo, mark)
964 bookmarks.setcurrent(repo, mark)
965 del marks[rename]
965 del marks[rename]
966 marks.write()
966 marks.write()
967
967
968 elif names:
968 elif names:
969 newact = None
969 newact = None
970 for mark in names:
970 for mark in names:
971 mark = checkformat(mark)
971 mark = checkformat(mark)
972 if newact is None:
972 if newact is None:
973 newact = mark
973 newact = mark
974 if inactive and mark == repo._bookmarkcurrent:
974 if inactive and mark == repo._bookmarkcurrent:
975 bookmarks.unsetcurrent(repo)
975 bookmarks.unsetcurrent(repo)
976 return
976 return
977 tgt = cur
977 tgt = cur
978 if rev:
978 if rev:
979 tgt = scmutil.revsingle(repo, rev).node()
979 tgt = scmutil.revsingle(repo, rev).node()
980 checkconflict(repo, mark, cur, force, tgt)
980 checkconflict(repo, mark, cur, force, tgt)
981 marks[mark] = tgt
981 marks[mark] = tgt
982 if not inactive and cur == marks[newact] and not rev:
982 if not inactive and cur == marks[newact] and not rev:
983 bookmarks.setcurrent(repo, newact)
983 bookmarks.setcurrent(repo, newact)
984 elif cur != tgt and newact == repo._bookmarkcurrent:
984 elif cur != tgt and newact == repo._bookmarkcurrent:
985 bookmarks.unsetcurrent(repo)
985 bookmarks.unsetcurrent(repo)
986 marks.write()
986 marks.write()
987
987
988 elif inactive:
988 elif inactive:
989 if len(marks) == 0:
989 if len(marks) == 0:
990 ui.status(_("no bookmarks set\n"))
990 ui.status(_("no bookmarks set\n"))
991 elif not repo._bookmarkcurrent:
991 elif not repo._bookmarkcurrent:
992 ui.status(_("no active bookmark\n"))
992 ui.status(_("no active bookmark\n"))
993 else:
993 else:
994 bookmarks.unsetcurrent(repo)
994 bookmarks.unsetcurrent(repo)
995 finally:
995 finally:
996 wlock.release()
996 wlock.release()
997 else: # show bookmarks
997 else: # show bookmarks
998 fm = ui.formatter('bookmarks', opts)
998 fm = ui.formatter('bookmarks', opts)
999 hexfn = fm.hexfunc
999 hexfn = fm.hexfunc
1000 marks = repo._bookmarks
1000 marks = repo._bookmarks
1001 if len(marks) == 0 and not fm:
1001 if len(marks) == 0 and not fm:
1002 ui.status(_("no bookmarks set\n"))
1002 ui.status(_("no bookmarks set\n"))
1003 for bmark, n in sorted(marks.iteritems()):
1003 for bmark, n in sorted(marks.iteritems()):
1004 current = repo._bookmarkcurrent
1004 current = repo._bookmarkcurrent
1005 if bmark == current:
1005 if bmark == current:
1006 prefix, label = '*', 'bookmarks.current'
1006 prefix, label = '*', 'bookmarks.current'
1007 else:
1007 else:
1008 prefix, label = ' ', ''
1008 prefix, label = ' ', ''
1009
1009
1010 fm.startitem()
1010 fm.startitem()
1011 if not ui.quiet:
1011 if not ui.quiet:
1012 fm.plain(' %s ' % prefix, label=label)
1012 fm.plain(' %s ' % prefix, label=label)
1013 fm.write('bookmark', '%s', bmark, label=label)
1013 fm.write('bookmark', '%s', bmark, label=label)
1014 pad = " " * (25 - encoding.colwidth(bmark))
1014 pad = " " * (25 - encoding.colwidth(bmark))
1015 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1015 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1016 repo.changelog.rev(n), hexfn(n), label=label)
1016 repo.changelog.rev(n), hexfn(n), label=label)
1017 fm.data(active=(bmark == current))
1017 fm.data(active=(bmark == current))
1018 fm.plain('\n')
1018 fm.plain('\n')
1019 fm.end()
1019 fm.end()
1020
1020
1021 @command('branch',
1021 @command('branch',
1022 [('f', 'force', None,
1022 [('f', 'force', None,
1023 _('set branch name even if it shadows an existing branch')),
1023 _('set branch name even if it shadows an existing branch')),
1024 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1024 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1025 _('[-fC] [NAME]'))
1025 _('[-fC] [NAME]'))
1026 def branch(ui, repo, label=None, **opts):
1026 def branch(ui, repo, label=None, **opts):
1027 """set or show the current branch name
1027 """set or show the current branch name
1028
1028
1029 .. note::
1029 .. note::
1030
1030
1031 Branch names are permanent and global. Use :hg:`bookmark` to create a
1031 Branch names are permanent and global. Use :hg:`bookmark` to create a
1032 light-weight bookmark instead. See :hg:`help glossary` for more
1032 light-weight bookmark instead. See :hg:`help glossary` for more
1033 information about named branches and bookmarks.
1033 information about named branches and bookmarks.
1034
1034
1035 With no argument, show the current branch name. With one argument,
1035 With no argument, show the current branch name. With one argument,
1036 set the working directory branch name (the branch will not exist
1036 set the working directory branch name (the branch will not exist
1037 in the repository until the next commit). Standard practice
1037 in the repository until the next commit). Standard practice
1038 recommends that primary development take place on the 'default'
1038 recommends that primary development take place on the 'default'
1039 branch.
1039 branch.
1040
1040
1041 Unless -f/--force is specified, branch will not let you set a
1041 Unless -f/--force is specified, branch will not let you set a
1042 branch name that already exists.
1042 branch name that already exists.
1043
1043
1044 Use -C/--clean to reset the working directory branch to that of
1044 Use -C/--clean to reset the working directory branch to that of
1045 the parent of the working directory, negating a previous branch
1045 the parent of the working directory, negating a previous branch
1046 change.
1046 change.
1047
1047
1048 Use the command :hg:`update` to switch to an existing branch. Use
1048 Use the command :hg:`update` to switch to an existing branch. Use
1049 :hg:`commit --close-branch` to mark this branch as closed.
1049 :hg:`commit --close-branch` to mark this branch as closed.
1050
1050
1051 Returns 0 on success.
1051 Returns 0 on success.
1052 """
1052 """
1053 if label:
1053 if label:
1054 label = label.strip()
1054 label = label.strip()
1055
1055
1056 if not opts.get('clean') and not label:
1056 if not opts.get('clean') and not label:
1057 ui.write("%s\n" % repo.dirstate.branch())
1057 ui.write("%s\n" % repo.dirstate.branch())
1058 return
1058 return
1059
1059
1060 wlock = repo.wlock()
1060 wlock = repo.wlock()
1061 try:
1061 try:
1062 if opts.get('clean'):
1062 if opts.get('clean'):
1063 label = repo[None].p1().branch()
1063 label = repo[None].p1().branch()
1064 repo.dirstate.setbranch(label)
1064 repo.dirstate.setbranch(label)
1065 ui.status(_('reset working directory to branch %s\n') % label)
1065 ui.status(_('reset working directory to branch %s\n') % label)
1066 elif label:
1066 elif label:
1067 if not opts.get('force') and label in repo.branchmap():
1067 if not opts.get('force') and label in repo.branchmap():
1068 if label not in [p.branch() for p in repo.parents()]:
1068 if label not in [p.branch() for p in repo.parents()]:
1069 raise util.Abort(_('a branch of the same name already'
1069 raise util.Abort(_('a branch of the same name already'
1070 ' exists'),
1070 ' exists'),
1071 # i18n: "it" refers to an existing branch
1071 # i18n: "it" refers to an existing branch
1072 hint=_("use 'hg update' to switch to it"))
1072 hint=_("use 'hg update' to switch to it"))
1073 scmutil.checknewlabel(repo, label, 'branch')
1073 scmutil.checknewlabel(repo, label, 'branch')
1074 repo.dirstate.setbranch(label)
1074 repo.dirstate.setbranch(label)
1075 ui.status(_('marked working directory as branch %s\n') % label)
1075 ui.status(_('marked working directory as branch %s\n') % label)
1076 ui.status(_('(branches are permanent and global, '
1076 ui.status(_('(branches are permanent and global, '
1077 'did you want a bookmark?)\n'))
1077 'did you want a bookmark?)\n'))
1078 finally:
1078 finally:
1079 wlock.release()
1079 wlock.release()
1080
1080
1081 @command('branches',
1081 @command('branches',
1082 [('a', 'active', False,
1082 [('a', 'active', False,
1083 _('show only branches that have unmerged heads (DEPRECATED)')),
1083 _('show only branches that have unmerged heads (DEPRECATED)')),
1084 ('c', 'closed', False, _('show normal and closed branches')),
1084 ('c', 'closed', False, _('show normal and closed branches')),
1085 ] + formatteropts,
1085 ] + formatteropts,
1086 _('[-ac]'))
1086 _('[-ac]'))
1087 def branches(ui, repo, active=False, closed=False, **opts):
1087 def branches(ui, repo, active=False, closed=False, **opts):
1088 """list repository named branches
1088 """list repository named branches
1089
1089
1090 List the repository's named branches, indicating which ones are
1090 List the repository's named branches, indicating which ones are
1091 inactive. If -c/--closed is specified, also list branches which have
1091 inactive. If -c/--closed is specified, also list branches which have
1092 been marked closed (see :hg:`commit --close-branch`).
1092 been marked closed (see :hg:`commit --close-branch`).
1093
1093
1094 Use the command :hg:`update` to switch to an existing branch.
1094 Use the command :hg:`update` to switch to an existing branch.
1095
1095
1096 Returns 0.
1096 Returns 0.
1097 """
1097 """
1098
1098
1099 fm = ui.formatter('branches', opts)
1099 fm = ui.formatter('branches', opts)
1100 hexfunc = fm.hexfunc
1100 hexfunc = fm.hexfunc
1101
1101
1102 allheads = set(repo.heads())
1102 allheads = set(repo.heads())
1103 branches = []
1103 branches = []
1104 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1104 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1105 isactive = not isclosed and bool(set(heads) & allheads)
1105 isactive = not isclosed and bool(set(heads) & allheads)
1106 branches.append((tag, repo[tip], isactive, not isclosed))
1106 branches.append((tag, repo[tip], isactive, not isclosed))
1107 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1107 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1108 reverse=True)
1108 reverse=True)
1109
1109
1110 for tag, ctx, isactive, isopen in branches:
1110 for tag, ctx, isactive, isopen in branches:
1111 if active and not isactive:
1111 if active and not isactive:
1112 continue
1112 continue
1113 if isactive:
1113 if isactive:
1114 label = 'branches.active'
1114 label = 'branches.active'
1115 notice = ''
1115 notice = ''
1116 elif not isopen:
1116 elif not isopen:
1117 if not closed:
1117 if not closed:
1118 continue
1118 continue
1119 label = 'branches.closed'
1119 label = 'branches.closed'
1120 notice = _(' (closed)')
1120 notice = _(' (closed)')
1121 else:
1121 else:
1122 label = 'branches.inactive'
1122 label = 'branches.inactive'
1123 notice = _(' (inactive)')
1123 notice = _(' (inactive)')
1124 current = (tag == repo.dirstate.branch())
1124 current = (tag == repo.dirstate.branch())
1125 if current:
1125 if current:
1126 label = 'branches.current'
1126 label = 'branches.current'
1127
1127
1128 fm.startitem()
1128 fm.startitem()
1129 fm.write('branch', '%s', tag, label=label)
1129 fm.write('branch', '%s', tag, label=label)
1130 rev = ctx.rev()
1130 rev = ctx.rev()
1131 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1131 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1132 fmt = ' ' * padsize + ' %d:%s'
1132 fmt = ' ' * padsize + ' %d:%s'
1133 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1133 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1134 label='log.changeset changeset.%s' % ctx.phasestr())
1134 label='log.changeset changeset.%s' % ctx.phasestr())
1135 fm.data(active=isactive, closed=not isopen, current=current)
1135 fm.data(active=isactive, closed=not isopen, current=current)
1136 if not ui.quiet:
1136 if not ui.quiet:
1137 fm.plain(notice)
1137 fm.plain(notice)
1138 fm.plain('\n')
1138 fm.plain('\n')
1139 fm.end()
1139 fm.end()
1140
1140
1141 @command('bundle',
1141 @command('bundle',
1142 [('f', 'force', None, _('run even when the destination is unrelated')),
1142 [('f', 'force', None, _('run even when the destination is unrelated')),
1143 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1143 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1144 _('REV')),
1144 _('REV')),
1145 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1145 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1146 _('BRANCH')),
1146 _('BRANCH')),
1147 ('', 'base', [],
1147 ('', 'base', [],
1148 _('a base changeset assumed to be available at the destination'),
1148 _('a base changeset assumed to be available at the destination'),
1149 _('REV')),
1149 _('REV')),
1150 ('a', 'all', None, _('bundle all changesets in the repository')),
1150 ('a', 'all', None, _('bundle all changesets in the repository')),
1151 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1151 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1152 ] + remoteopts,
1152 ] + remoteopts,
1153 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1153 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1154 def bundle(ui, repo, fname, dest=None, **opts):
1154 def bundle(ui, repo, fname, dest=None, **opts):
1155 """create a changegroup file
1155 """create a changegroup file
1156
1156
1157 Generate a compressed changegroup file collecting changesets not
1157 Generate a compressed changegroup file collecting changesets not
1158 known to be in another repository.
1158 known to be in another repository.
1159
1159
1160 If you omit the destination repository, then hg assumes the
1160 If you omit the destination repository, then hg assumes the
1161 destination will have all the nodes you specify with --base
1161 destination will have all the nodes you specify with --base
1162 parameters. To create a bundle containing all changesets, use
1162 parameters. To create a bundle containing all changesets, use
1163 -a/--all (or --base null).
1163 -a/--all (or --base null).
1164
1164
1165 You can change compression method with the -t/--type option.
1165 You can change compression method with the -t/--type option.
1166 The available compression methods are: none, bzip2, and
1166 The available compression methods are: none, bzip2, and
1167 gzip (by default, bundles are compressed using bzip2).
1167 gzip (by default, bundles are compressed using bzip2).
1168
1168
1169 The bundle file can then be transferred using conventional means
1169 The bundle file can then be transferred using conventional means
1170 and applied to another repository with the unbundle or pull
1170 and applied to another repository with the unbundle or pull
1171 command. This is useful when direct push and pull are not
1171 command. This is useful when direct push and pull are not
1172 available or when exporting an entire repository is undesirable.
1172 available or when exporting an entire repository is undesirable.
1173
1173
1174 Applying bundles preserves all changeset contents including
1174 Applying bundles preserves all changeset contents including
1175 permissions, copy/rename information, and revision history.
1175 permissions, copy/rename information, and revision history.
1176
1176
1177 Returns 0 on success, 1 if no changes found.
1177 Returns 0 on success, 1 if no changes found.
1178 """
1178 """
1179 revs = None
1179 revs = None
1180 if 'rev' in opts:
1180 if 'rev' in opts:
1181 revs = scmutil.revrange(repo, opts['rev'])
1181 revs = scmutil.revrange(repo, opts['rev'])
1182
1182
1183 bundletype = opts.get('type', 'bzip2').lower()
1183 bundletype = opts.get('type', 'bzip2').lower()
1184 btypes = {'none': 'HG10UN',
1184 btypes = {'none': 'HG10UN',
1185 'bzip2': 'HG10BZ',
1185 'bzip2': 'HG10BZ',
1186 'gzip': 'HG10GZ',
1186 'gzip': 'HG10GZ',
1187 'bundle2': 'HG2Y'}
1187 'bundle2': 'HG2Y'}
1188 bundletype = btypes.get(bundletype)
1188 bundletype = btypes.get(bundletype)
1189 if bundletype not in changegroup.bundletypes:
1189 if bundletype not in changegroup.bundletypes:
1190 raise util.Abort(_('unknown bundle type specified with --type'))
1190 raise util.Abort(_('unknown bundle type specified with --type'))
1191
1191
1192 if opts.get('all'):
1192 if opts.get('all'):
1193 base = ['null']
1193 base = ['null']
1194 else:
1194 else:
1195 base = scmutil.revrange(repo, opts.get('base'))
1195 base = scmutil.revrange(repo, opts.get('base'))
1196 # TODO: get desired bundlecaps from command line.
1196 # TODO: get desired bundlecaps from command line.
1197 bundlecaps = None
1197 bundlecaps = None
1198 if base:
1198 if base:
1199 if dest:
1199 if dest:
1200 raise util.Abort(_("--base is incompatible with specifying "
1200 raise util.Abort(_("--base is incompatible with specifying "
1201 "a destination"))
1201 "a destination"))
1202 common = [repo.lookup(rev) for rev in base]
1202 common = [repo.lookup(rev) for rev in base]
1203 heads = revs and map(repo.lookup, revs) or revs
1203 heads = revs and map(repo.lookup, revs) or revs
1204 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1204 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1205 common=common, bundlecaps=bundlecaps)
1205 common=common, bundlecaps=bundlecaps)
1206 outgoing = None
1206 outgoing = None
1207 else:
1207 else:
1208 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1208 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1209 dest, branches = hg.parseurl(dest, opts.get('branch'))
1209 dest, branches = hg.parseurl(dest, opts.get('branch'))
1210 other = hg.peer(repo, opts, dest)
1210 other = hg.peer(repo, opts, dest)
1211 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1211 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1212 heads = revs and map(repo.lookup, revs) or revs
1212 heads = revs and map(repo.lookup, revs) or revs
1213 outgoing = discovery.findcommonoutgoing(repo, other,
1213 outgoing = discovery.findcommonoutgoing(repo, other,
1214 onlyheads=heads,
1214 onlyheads=heads,
1215 force=opts.get('force'),
1215 force=opts.get('force'),
1216 portable=True)
1216 portable=True)
1217 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1217 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1218 bundlecaps)
1218 bundlecaps)
1219 if not cg:
1219 if not cg:
1220 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1220 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1221 return 1
1221 return 1
1222
1222
1223 changegroup.writebundle(ui, cg, fname, bundletype)
1223 changegroup.writebundle(ui, cg, fname, bundletype)
1224
1224
1225 @command('cat',
1225 @command('cat',
1226 [('o', 'output', '',
1226 [('o', 'output', '',
1227 _('print output to file with formatted name'), _('FORMAT')),
1227 _('print output to file with formatted name'), _('FORMAT')),
1228 ('r', 'rev', '', _('print the given revision'), _('REV')),
1228 ('r', 'rev', '', _('print the given revision'), _('REV')),
1229 ('', 'decode', None, _('apply any matching decode filter')),
1229 ('', 'decode', None, _('apply any matching decode filter')),
1230 ] + walkopts,
1230 ] + walkopts,
1231 _('[OPTION]... FILE...'),
1231 _('[OPTION]... FILE...'),
1232 inferrepo=True)
1232 inferrepo=True)
1233 def cat(ui, repo, file1, *pats, **opts):
1233 def cat(ui, repo, file1, *pats, **opts):
1234 """output the current or given revision of files
1234 """output the current or given revision of files
1235
1235
1236 Print the specified files as they were at the given revision. If
1236 Print the specified files as they were at the given revision. If
1237 no revision is given, the parent of the working directory is used.
1237 no revision is given, the parent of the working directory is used.
1238
1238
1239 Output may be to a file, in which case the name of the file is
1239 Output may be to a file, in which case the name of the file is
1240 given using a format string. The formatting rules as follows:
1240 given using a format string. The formatting rules as follows:
1241
1241
1242 :``%%``: literal "%" character
1242 :``%%``: literal "%" character
1243 :``%s``: basename of file being printed
1243 :``%s``: basename of file being printed
1244 :``%d``: dirname of file being printed, or '.' if in repository root
1244 :``%d``: dirname of file being printed, or '.' if in repository root
1245 :``%p``: root-relative path name of file being printed
1245 :``%p``: root-relative path name of file being printed
1246 :``%H``: changeset hash (40 hexadecimal digits)
1246 :``%H``: changeset hash (40 hexadecimal digits)
1247 :``%R``: changeset revision number
1247 :``%R``: changeset revision number
1248 :``%h``: short-form changeset hash (12 hexadecimal digits)
1248 :``%h``: short-form changeset hash (12 hexadecimal digits)
1249 :``%r``: zero-padded changeset revision number
1249 :``%r``: zero-padded changeset revision number
1250 :``%b``: basename of the exporting repository
1250 :``%b``: basename of the exporting repository
1251
1251
1252 Returns 0 on success.
1252 Returns 0 on success.
1253 """
1253 """
1254 ctx = scmutil.revsingle(repo, opts.get('rev'))
1254 ctx = scmutil.revsingle(repo, opts.get('rev'))
1255 m = scmutil.match(ctx, (file1,) + pats, opts)
1255 m = scmutil.match(ctx, (file1,) + pats, opts)
1256
1256
1257 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1257 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1258
1258
1259 @command('^clone',
1259 @command('^clone',
1260 [('U', 'noupdate', None,
1260 [('U', 'noupdate', None,
1261 _('the clone will include an empty working copy (only a repository)')),
1261 _('the clone will include an empty working copy (only a repository)')),
1262 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1262 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1263 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1263 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1264 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1264 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1265 ('', 'pull', None, _('use pull protocol to copy metadata')),
1265 ('', 'pull', None, _('use pull protocol to copy metadata')),
1266 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1266 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1267 ] + remoteopts,
1267 ] + remoteopts,
1268 _('[OPTION]... SOURCE [DEST]'),
1268 _('[OPTION]... SOURCE [DEST]'),
1269 norepo=True)
1269 norepo=True)
1270 def clone(ui, source, dest=None, **opts):
1270 def clone(ui, source, dest=None, **opts):
1271 """make a copy of an existing repository
1271 """make a copy of an existing repository
1272
1272
1273 Create a copy of an existing repository in a new directory.
1273 Create a copy of an existing repository in a new directory.
1274
1274
1275 If no destination directory name is specified, it defaults to the
1275 If no destination directory name is specified, it defaults to the
1276 basename of the source.
1276 basename of the source.
1277
1277
1278 The location of the source is added to the new repository's
1278 The location of the source is added to the new repository's
1279 ``.hg/hgrc`` file, as the default to be used for future pulls.
1279 ``.hg/hgrc`` file, as the default to be used for future pulls.
1280
1280
1281 Only local paths and ``ssh://`` URLs are supported as
1281 Only local paths and ``ssh://`` URLs are supported as
1282 destinations. For ``ssh://`` destinations, no working directory or
1282 destinations. For ``ssh://`` destinations, no working directory or
1283 ``.hg/hgrc`` will be created on the remote side.
1283 ``.hg/hgrc`` will be created on the remote side.
1284
1284
1285 To pull only a subset of changesets, specify one or more revisions
1285 To pull only a subset of changesets, specify one or more revisions
1286 identifiers with -r/--rev or branches with -b/--branch. The
1286 identifiers with -r/--rev or branches with -b/--branch. The
1287 resulting clone will contain only the specified changesets and
1287 resulting clone will contain only the specified changesets and
1288 their ancestors. These options (or 'clone src#rev dest') imply
1288 their ancestors. These options (or 'clone src#rev dest') imply
1289 --pull, even for local source repositories. Note that specifying a
1289 --pull, even for local source repositories. Note that specifying a
1290 tag will include the tagged changeset but not the changeset
1290 tag will include the tagged changeset but not the changeset
1291 containing the tag.
1291 containing the tag.
1292
1292
1293 If the source repository has a bookmark called '@' set, that
1293 If the source repository has a bookmark called '@' set, that
1294 revision will be checked out in the new repository by default.
1294 revision will be checked out in the new repository by default.
1295
1295
1296 To check out a particular version, use -u/--update, or
1296 To check out a particular version, use -u/--update, or
1297 -U/--noupdate to create a clone with no working directory.
1297 -U/--noupdate to create a clone with no working directory.
1298
1298
1299 .. container:: verbose
1299 .. container:: verbose
1300
1300
1301 For efficiency, hardlinks are used for cloning whenever the
1301 For efficiency, hardlinks are used for cloning whenever the
1302 source and destination are on the same filesystem (note this
1302 source and destination are on the same filesystem (note this
1303 applies only to the repository data, not to the working
1303 applies only to the repository data, not to the working
1304 directory). Some filesystems, such as AFS, implement hardlinking
1304 directory). Some filesystems, such as AFS, implement hardlinking
1305 incorrectly, but do not report errors. In these cases, use the
1305 incorrectly, but do not report errors. In these cases, use the
1306 --pull option to avoid hardlinking.
1306 --pull option to avoid hardlinking.
1307
1307
1308 In some cases, you can clone repositories and the working
1308 In some cases, you can clone repositories and the working
1309 directory using full hardlinks with ::
1309 directory using full hardlinks with ::
1310
1310
1311 $ cp -al REPO REPOCLONE
1311 $ cp -al REPO REPOCLONE
1312
1312
1313 This is the fastest way to clone, but it is not always safe. The
1313 This is the fastest way to clone, but it is not always safe. The
1314 operation is not atomic (making sure REPO is not modified during
1314 operation is not atomic (making sure REPO is not modified during
1315 the operation is up to you) and you have to make sure your
1315 the operation is up to you) and you have to make sure your
1316 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1316 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1317 so). Also, this is not compatible with certain extensions that
1317 so). Also, this is not compatible with certain extensions that
1318 place their metadata under the .hg directory, such as mq.
1318 place their metadata under the .hg directory, such as mq.
1319
1319
1320 Mercurial will update the working directory to the first applicable
1320 Mercurial will update the working directory to the first applicable
1321 revision from this list:
1321 revision from this list:
1322
1322
1323 a) null if -U or the source repository has no changesets
1323 a) null if -U or the source repository has no changesets
1324 b) if -u . and the source repository is local, the first parent of
1324 b) if -u . and the source repository is local, the first parent of
1325 the source repository's working directory
1325 the source repository's working directory
1326 c) the changeset specified with -u (if a branch name, this means the
1326 c) the changeset specified with -u (if a branch name, this means the
1327 latest head of that branch)
1327 latest head of that branch)
1328 d) the changeset specified with -r
1328 d) the changeset specified with -r
1329 e) the tipmost head specified with -b
1329 e) the tipmost head specified with -b
1330 f) the tipmost head specified with the url#branch source syntax
1330 f) the tipmost head specified with the url#branch source syntax
1331 g) the revision marked with the '@' bookmark, if present
1331 g) the revision marked with the '@' bookmark, if present
1332 h) the tipmost head of the default branch
1332 h) the tipmost head of the default branch
1333 i) tip
1333 i) tip
1334
1334
1335 Examples:
1335 Examples:
1336
1336
1337 - clone a remote repository to a new directory named hg/::
1337 - clone a remote repository to a new directory named hg/::
1338
1338
1339 hg clone http://selenic.com/hg
1339 hg clone http://selenic.com/hg
1340
1340
1341 - create a lightweight local clone::
1341 - create a lightweight local clone::
1342
1342
1343 hg clone project/ project-feature/
1343 hg clone project/ project-feature/
1344
1344
1345 - clone from an absolute path on an ssh server (note double-slash)::
1345 - clone from an absolute path on an ssh server (note double-slash)::
1346
1346
1347 hg clone ssh://user@server//home/projects/alpha/
1347 hg clone ssh://user@server//home/projects/alpha/
1348
1348
1349 - do a high-speed clone over a LAN while checking out a
1349 - do a high-speed clone over a LAN while checking out a
1350 specified version::
1350 specified version::
1351
1351
1352 hg clone --uncompressed http://server/repo -u 1.5
1352 hg clone --uncompressed http://server/repo -u 1.5
1353
1353
1354 - create a repository without changesets after a particular revision::
1354 - create a repository without changesets after a particular revision::
1355
1355
1356 hg clone -r 04e544 experimental/ good/
1356 hg clone -r 04e544 experimental/ good/
1357
1357
1358 - clone (and track) a particular named branch::
1358 - clone (and track) a particular named branch::
1359
1359
1360 hg clone http://selenic.com/hg#stable
1360 hg clone http://selenic.com/hg#stable
1361
1361
1362 See :hg:`help urls` for details on specifying URLs.
1362 See :hg:`help urls` for details on specifying URLs.
1363
1363
1364 Returns 0 on success.
1364 Returns 0 on success.
1365 """
1365 """
1366 if opts.get('noupdate') and opts.get('updaterev'):
1366 if opts.get('noupdate') and opts.get('updaterev'):
1367 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1367 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1368
1368
1369 r = hg.clone(ui, opts, source, dest,
1369 r = hg.clone(ui, opts, source, dest,
1370 pull=opts.get('pull'),
1370 pull=opts.get('pull'),
1371 stream=opts.get('uncompressed'),
1371 stream=opts.get('uncompressed'),
1372 rev=opts.get('rev'),
1372 rev=opts.get('rev'),
1373 update=opts.get('updaterev') or not opts.get('noupdate'),
1373 update=opts.get('updaterev') or not opts.get('noupdate'),
1374 branch=opts.get('branch'))
1374 branch=opts.get('branch'))
1375
1375
1376 return r is None
1376 return r is None
1377
1377
1378 @command('^commit|ci',
1378 @command('^commit|ci',
1379 [('A', 'addremove', None,
1379 [('A', 'addremove', None,
1380 _('mark new/missing files as added/removed before committing')),
1380 _('mark new/missing files as added/removed before committing')),
1381 ('', 'close-branch', None,
1381 ('', 'close-branch', None,
1382 _('mark a branch as closed, hiding it from the branch list')),
1382 _('mark a branch as closed, hiding it from the branch list')),
1383 ('', 'amend', None, _('amend the parent of the working dir')),
1383 ('', 'amend', None, _('amend the parent of the working dir')),
1384 ('s', 'secret', None, _('use the secret phase for committing')),
1384 ('s', 'secret', None, _('use the secret phase for committing')),
1385 ('e', 'edit', None, _('invoke editor on commit messages')),
1385 ('e', 'edit', None, _('invoke editor on commit messages')),
1386 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1386 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1387 _('[OPTION]... [FILE]...'),
1387 _('[OPTION]... [FILE]...'),
1388 inferrepo=True)
1388 inferrepo=True)
1389 def commit(ui, repo, *pats, **opts):
1389 def commit(ui, repo, *pats, **opts):
1390 """commit the specified files or all outstanding changes
1390 """commit the specified files or all outstanding changes
1391
1391
1392 Commit changes to the given files into the repository. Unlike a
1392 Commit changes to the given files into the repository. Unlike a
1393 centralized SCM, this operation is a local operation. See
1393 centralized SCM, this operation is a local operation. See
1394 :hg:`push` for a way to actively distribute your changes.
1394 :hg:`push` for a way to actively distribute your changes.
1395
1395
1396 If a list of files is omitted, all changes reported by :hg:`status`
1396 If a list of files is omitted, all changes reported by :hg:`status`
1397 will be committed.
1397 will be committed.
1398
1398
1399 If you are committing the result of a merge, do not provide any
1399 If you are committing the result of a merge, do not provide any
1400 filenames or -I/-X filters.
1400 filenames or -I/-X filters.
1401
1401
1402 If no commit message is specified, Mercurial starts your
1402 If no commit message is specified, Mercurial starts your
1403 configured editor where you can enter a message. In case your
1403 configured editor where you can enter a message. In case your
1404 commit fails, you will find a backup of your message in
1404 commit fails, you will find a backup of your message in
1405 ``.hg/last-message.txt``.
1405 ``.hg/last-message.txt``.
1406
1406
1407 The --amend flag can be used to amend the parent of the
1407 The --amend flag can be used to amend the parent of the
1408 working directory with a new commit that contains the changes
1408 working directory with a new commit that contains the changes
1409 in the parent in addition to those currently reported by :hg:`status`,
1409 in the parent in addition to those currently reported by :hg:`status`,
1410 if there are any. The old commit is stored in a backup bundle in
1410 if there are any. The old commit is stored in a backup bundle in
1411 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1411 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1412 on how to restore it).
1412 on how to restore it).
1413
1413
1414 Message, user and date are taken from the amended commit unless
1414 Message, user and date are taken from the amended commit unless
1415 specified. When a message isn't specified on the command line,
1415 specified. When a message isn't specified on the command line,
1416 the editor will open with the message of the amended commit.
1416 the editor will open with the message of the amended commit.
1417
1417
1418 It is not possible to amend public changesets (see :hg:`help phases`)
1418 It is not possible to amend public changesets (see :hg:`help phases`)
1419 or changesets that have children.
1419 or changesets that have children.
1420
1420
1421 See :hg:`help dates` for a list of formats valid for -d/--date.
1421 See :hg:`help dates` for a list of formats valid for -d/--date.
1422
1422
1423 Returns 0 on success, 1 if nothing changed.
1423 Returns 0 on success, 1 if nothing changed.
1424 """
1424 """
1425 if opts.get('subrepos'):
1425 if opts.get('subrepos'):
1426 if opts.get('amend'):
1426 if opts.get('amend'):
1427 raise util.Abort(_('cannot amend with --subrepos'))
1427 raise util.Abort(_('cannot amend with --subrepos'))
1428 # Let --subrepos on the command line override config setting.
1428 # Let --subrepos on the command line override config setting.
1429 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1429 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1430
1430
1431 cmdutil.checkunfinished(repo, commit=True)
1431 cmdutil.checkunfinished(repo, commit=True)
1432
1432
1433 branch = repo[None].branch()
1433 branch = repo[None].branch()
1434 bheads = repo.branchheads(branch)
1434 bheads = repo.branchheads(branch)
1435
1435
1436 extra = {}
1436 extra = {}
1437 if opts.get('close_branch'):
1437 if opts.get('close_branch'):
1438 extra['close'] = 1
1438 extra['close'] = 1
1439
1439
1440 if not bheads:
1440 if not bheads:
1441 raise util.Abort(_('can only close branch heads'))
1441 raise util.Abort(_('can only close branch heads'))
1442 elif opts.get('amend'):
1442 elif opts.get('amend'):
1443 if repo.parents()[0].p1().branch() != branch and \
1443 if repo.parents()[0].p1().branch() != branch and \
1444 repo.parents()[0].p2().branch() != branch:
1444 repo.parents()[0].p2().branch() != branch:
1445 raise util.Abort(_('can only close branch heads'))
1445 raise util.Abort(_('can only close branch heads'))
1446
1446
1447 if opts.get('amend'):
1447 if opts.get('amend'):
1448 if ui.configbool('ui', 'commitsubrepos'):
1448 if ui.configbool('ui', 'commitsubrepos'):
1449 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1449 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1450
1450
1451 old = repo['.']
1451 old = repo['.']
1452 if not old.mutable():
1452 if not old.mutable():
1453 raise util.Abort(_('cannot amend public changesets'))
1453 raise util.Abort(_('cannot amend public changesets'))
1454 if len(repo[None].parents()) > 1:
1454 if len(repo[None].parents()) > 1:
1455 raise util.Abort(_('cannot amend while merging'))
1455 raise util.Abort(_('cannot amend while merging'))
1456 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1456 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1457 if not allowunstable and old.children():
1457 if not allowunstable and old.children():
1458 raise util.Abort(_('cannot amend changeset with children'))
1458 raise util.Abort(_('cannot amend changeset with children'))
1459
1459
1460 # commitfunc is used only for temporary amend commit by cmdutil.amend
1460 # commitfunc is used only for temporary amend commit by cmdutil.amend
1461 def commitfunc(ui, repo, message, match, opts):
1461 def commitfunc(ui, repo, message, match, opts):
1462 return repo.commit(message,
1462 return repo.commit(message,
1463 opts.get('user') or old.user(),
1463 opts.get('user') or old.user(),
1464 opts.get('date') or old.date(),
1464 opts.get('date') or old.date(),
1465 match,
1465 match,
1466 extra=extra)
1466 extra=extra)
1467
1467
1468 current = repo._bookmarkcurrent
1468 current = repo._bookmarkcurrent
1469 marks = old.bookmarks()
1469 marks = old.bookmarks()
1470 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1470 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1471 if node == old.node():
1471 if node == old.node():
1472 ui.status(_("nothing changed\n"))
1472 ui.status(_("nothing changed\n"))
1473 return 1
1473 return 1
1474 elif marks:
1474 elif marks:
1475 ui.debug('moving bookmarks %r from %s to %s\n' %
1475 ui.debug('moving bookmarks %r from %s to %s\n' %
1476 (marks, old.hex(), hex(node)))
1476 (marks, old.hex(), hex(node)))
1477 newmarks = repo._bookmarks
1477 newmarks = repo._bookmarks
1478 for bm in marks:
1478 for bm in marks:
1479 newmarks[bm] = node
1479 newmarks[bm] = node
1480 if bm == current:
1480 if bm == current:
1481 bookmarks.setcurrent(repo, bm)
1481 bookmarks.setcurrent(repo, bm)
1482 newmarks.write()
1482 newmarks.write()
1483 else:
1483 else:
1484 def commitfunc(ui, repo, message, match, opts):
1484 def commitfunc(ui, repo, message, match, opts):
1485 backup = ui.backupconfig('phases', 'new-commit')
1485 backup = ui.backupconfig('phases', 'new-commit')
1486 baseui = repo.baseui
1486 baseui = repo.baseui
1487 basebackup = baseui.backupconfig('phases', 'new-commit')
1487 basebackup = baseui.backupconfig('phases', 'new-commit')
1488 try:
1488 try:
1489 if opts.get('secret'):
1489 if opts.get('secret'):
1490 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1490 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1491 # Propagate to subrepos
1491 # Propagate to subrepos
1492 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1492 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1493
1493
1494 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1494 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1495 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1495 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1496 return repo.commit(message, opts.get('user'), opts.get('date'),
1496 return repo.commit(message, opts.get('user'), opts.get('date'),
1497 match,
1497 match,
1498 editor=editor,
1498 editor=editor,
1499 extra=extra)
1499 extra=extra)
1500 finally:
1500 finally:
1501 ui.restoreconfig(backup)
1501 ui.restoreconfig(backup)
1502 repo.baseui.restoreconfig(basebackup)
1502 repo.baseui.restoreconfig(basebackup)
1503
1503
1504
1504
1505 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1505 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1506
1506
1507 if not node:
1507 if not node:
1508 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1508 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1509 if stat[3]:
1509 if stat[3]:
1510 ui.status(_("nothing changed (%d missing files, see "
1510 ui.status(_("nothing changed (%d missing files, see "
1511 "'hg status')\n") % len(stat[3]))
1511 "'hg status')\n") % len(stat[3]))
1512 else:
1512 else:
1513 ui.status(_("nothing changed\n"))
1513 ui.status(_("nothing changed\n"))
1514 return 1
1514 return 1
1515
1515
1516 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1516 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1517
1517
1518 @command('config|showconfig|debugconfig',
1518 @command('config|showconfig|debugconfig',
1519 [('u', 'untrusted', None, _('show untrusted configuration options')),
1519 [('u', 'untrusted', None, _('show untrusted configuration options')),
1520 ('e', 'edit', None, _('edit user config')),
1520 ('e', 'edit', None, _('edit user config')),
1521 ('l', 'local', None, _('edit repository config')),
1521 ('l', 'local', None, _('edit repository config')),
1522 ('g', 'global', None, _('edit global config'))],
1522 ('g', 'global', None, _('edit global config'))],
1523 _('[-u] [NAME]...'),
1523 _('[-u] [NAME]...'),
1524 optionalrepo=True)
1524 optionalrepo=True)
1525 def config(ui, repo, *values, **opts):
1525 def config(ui, repo, *values, **opts):
1526 """show combined config settings from all hgrc files
1526 """show combined config settings from all hgrc files
1527
1527
1528 With no arguments, print names and values of all config items.
1528 With no arguments, print names and values of all config items.
1529
1529
1530 With one argument of the form section.name, print just the value
1530 With one argument of the form section.name, print just the value
1531 of that config item.
1531 of that config item.
1532
1532
1533 With multiple arguments, print names and values of all config
1533 With multiple arguments, print names and values of all config
1534 items with matching section names.
1534 items with matching section names.
1535
1535
1536 With --edit, start an editor on the user-level config file. With
1536 With --edit, start an editor on the user-level config file. With
1537 --global, edit the system-wide config file. With --local, edit the
1537 --global, edit the system-wide config file. With --local, edit the
1538 repository-level config file.
1538 repository-level config file.
1539
1539
1540 With --debug, the source (filename and line number) is printed
1540 With --debug, the source (filename and line number) is printed
1541 for each config item.
1541 for each config item.
1542
1542
1543 See :hg:`help config` for more information about config files.
1543 See :hg:`help config` for more information about config files.
1544
1544
1545 Returns 0 on success, 1 if NAME does not exist.
1545 Returns 0 on success, 1 if NAME does not exist.
1546
1546
1547 """
1547 """
1548
1548
1549 if opts.get('edit') or opts.get('local') or opts.get('global'):
1549 if opts.get('edit') or opts.get('local') or opts.get('global'):
1550 if opts.get('local') and opts.get('global'):
1550 if opts.get('local') and opts.get('global'):
1551 raise util.Abort(_("can't use --local and --global together"))
1551 raise util.Abort(_("can't use --local and --global together"))
1552
1552
1553 if opts.get('local'):
1553 if opts.get('local'):
1554 if not repo:
1554 if not repo:
1555 raise util.Abort(_("can't use --local outside a repository"))
1555 raise util.Abort(_("can't use --local outside a repository"))
1556 paths = [repo.join('hgrc')]
1556 paths = [repo.join('hgrc')]
1557 elif opts.get('global'):
1557 elif opts.get('global'):
1558 paths = scmutil.systemrcpath()
1558 paths = scmutil.systemrcpath()
1559 else:
1559 else:
1560 paths = scmutil.userrcpath()
1560 paths = scmutil.userrcpath()
1561
1561
1562 for f in paths:
1562 for f in paths:
1563 if os.path.exists(f):
1563 if os.path.exists(f):
1564 break
1564 break
1565 else:
1565 else:
1566 if opts.get('global'):
1566 if opts.get('global'):
1567 samplehgrc = uimod.samplehgrcs['global']
1567 samplehgrc = uimod.samplehgrcs['global']
1568 elif opts.get('local'):
1568 elif opts.get('local'):
1569 samplehgrc = uimod.samplehgrcs['local']
1569 samplehgrc = uimod.samplehgrcs['local']
1570 else:
1570 else:
1571 samplehgrc = uimod.samplehgrcs['user']
1571 samplehgrc = uimod.samplehgrcs['user']
1572
1572
1573 f = paths[0]
1573 f = paths[0]
1574 fp = open(f, "w")
1574 fp = open(f, "w")
1575 fp.write(samplehgrc)
1575 fp.write(samplehgrc)
1576 fp.close()
1576 fp.close()
1577
1577
1578 editor = ui.geteditor()
1578 editor = ui.geteditor()
1579 ui.system("%s \"%s\"" % (editor, f),
1579 ui.system("%s \"%s\"" % (editor, f),
1580 onerr=util.Abort, errprefix=_("edit failed"))
1580 onerr=util.Abort, errprefix=_("edit failed"))
1581 return
1581 return
1582
1582
1583 for f in scmutil.rcpath():
1583 for f in scmutil.rcpath():
1584 ui.debug('read config from: %s\n' % f)
1584 ui.debug('read config from: %s\n' % f)
1585 untrusted = bool(opts.get('untrusted'))
1585 untrusted = bool(opts.get('untrusted'))
1586 if values:
1586 if values:
1587 sections = [v for v in values if '.' not in v]
1587 sections = [v for v in values if '.' not in v]
1588 items = [v for v in values if '.' in v]
1588 items = [v for v in values if '.' in v]
1589 if len(items) > 1 or items and sections:
1589 if len(items) > 1 or items and sections:
1590 raise util.Abort(_('only one config item permitted'))
1590 raise util.Abort(_('only one config item permitted'))
1591 matched = False
1591 matched = False
1592 for section, name, value in ui.walkconfig(untrusted=untrusted):
1592 for section, name, value in ui.walkconfig(untrusted=untrusted):
1593 value = str(value).replace('\n', '\\n')
1593 value = str(value).replace('\n', '\\n')
1594 sectname = section + '.' + name
1594 sectname = section + '.' + name
1595 if values:
1595 if values:
1596 for v in values:
1596 for v in values:
1597 if v == section:
1597 if v == section:
1598 ui.debug('%s: ' %
1598 ui.debug('%s: ' %
1599 ui.configsource(section, name, untrusted))
1599 ui.configsource(section, name, untrusted))
1600 ui.write('%s=%s\n' % (sectname, value))
1600 ui.write('%s=%s\n' % (sectname, value))
1601 matched = True
1601 matched = True
1602 elif v == sectname:
1602 elif v == sectname:
1603 ui.debug('%s: ' %
1603 ui.debug('%s: ' %
1604 ui.configsource(section, name, untrusted))
1604 ui.configsource(section, name, untrusted))
1605 ui.write(value, '\n')
1605 ui.write(value, '\n')
1606 matched = True
1606 matched = True
1607 else:
1607 else:
1608 ui.debug('%s: ' %
1608 ui.debug('%s: ' %
1609 ui.configsource(section, name, untrusted))
1609 ui.configsource(section, name, untrusted))
1610 ui.write('%s=%s\n' % (sectname, value))
1610 ui.write('%s=%s\n' % (sectname, value))
1611 matched = True
1611 matched = True
1612 if matched:
1612 if matched:
1613 return 0
1613 return 0
1614 return 1
1614 return 1
1615
1615
1616 @command('copy|cp',
1616 @command('copy|cp',
1617 [('A', 'after', None, _('record a copy that has already occurred')),
1617 [('A', 'after', None, _('record a copy that has already occurred')),
1618 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1618 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1619 ] + walkopts + dryrunopts,
1619 ] + walkopts + dryrunopts,
1620 _('[OPTION]... [SOURCE]... DEST'))
1620 _('[OPTION]... [SOURCE]... DEST'))
1621 def copy(ui, repo, *pats, **opts):
1621 def copy(ui, repo, *pats, **opts):
1622 """mark files as copied for the next commit
1622 """mark files as copied for the next commit
1623
1623
1624 Mark dest as having copies of source files. If dest is a
1624 Mark dest as having copies of source files. If dest is a
1625 directory, copies are put in that directory. If dest is a file,
1625 directory, copies are put in that directory. If dest is a file,
1626 the source must be a single file.
1626 the source must be a single file.
1627
1627
1628 By default, this command copies the contents of files as they
1628 By default, this command copies the contents of files as they
1629 exist in the working directory. If invoked with -A/--after, the
1629 exist in the working directory. If invoked with -A/--after, the
1630 operation is recorded, but no copying is performed.
1630 operation is recorded, but no copying is performed.
1631
1631
1632 This command takes effect with the next commit. To undo a copy
1632 This command takes effect with the next commit. To undo a copy
1633 before that, see :hg:`revert`.
1633 before that, see :hg:`revert`.
1634
1634
1635 Returns 0 on success, 1 if errors are encountered.
1635 Returns 0 on success, 1 if errors are encountered.
1636 """
1636 """
1637 wlock = repo.wlock(False)
1637 wlock = repo.wlock(False)
1638 try:
1638 try:
1639 return cmdutil.copy(ui, repo, pats, opts)
1639 return cmdutil.copy(ui, repo, pats, opts)
1640 finally:
1640 finally:
1641 wlock.release()
1641 wlock.release()
1642
1642
1643 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1643 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1644 def debugancestor(ui, repo, *args):
1644 def debugancestor(ui, repo, *args):
1645 """find the ancestor revision of two revisions in a given index"""
1645 """find the ancestor revision of two revisions in a given index"""
1646 if len(args) == 3:
1646 if len(args) == 3:
1647 index, rev1, rev2 = args
1647 index, rev1, rev2 = args
1648 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1648 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1649 lookup = r.lookup
1649 lookup = r.lookup
1650 elif len(args) == 2:
1650 elif len(args) == 2:
1651 if not repo:
1651 if not repo:
1652 raise util.Abort(_("there is no Mercurial repository here "
1652 raise util.Abort(_("there is no Mercurial repository here "
1653 "(.hg not found)"))
1653 "(.hg not found)"))
1654 rev1, rev2 = args
1654 rev1, rev2 = args
1655 r = repo.changelog
1655 r = repo.changelog
1656 lookup = repo.lookup
1656 lookup = repo.lookup
1657 else:
1657 else:
1658 raise util.Abort(_('either two or three arguments required'))
1658 raise util.Abort(_('either two or three arguments required'))
1659 a = r.ancestor(lookup(rev1), lookup(rev2))
1659 a = r.ancestor(lookup(rev1), lookup(rev2))
1660 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1660 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1661
1661
1662 @command('debugbuilddag',
1662 @command('debugbuilddag',
1663 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1663 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1664 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1664 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1665 ('n', 'new-file', None, _('add new file at each rev'))],
1665 ('n', 'new-file', None, _('add new file at each rev'))],
1666 _('[OPTION]... [TEXT]'))
1666 _('[OPTION]... [TEXT]'))
1667 def debugbuilddag(ui, repo, text=None,
1667 def debugbuilddag(ui, repo, text=None,
1668 mergeable_file=False,
1668 mergeable_file=False,
1669 overwritten_file=False,
1669 overwritten_file=False,
1670 new_file=False):
1670 new_file=False):
1671 """builds a repo with a given DAG from scratch in the current empty repo
1671 """builds a repo with a given DAG from scratch in the current empty repo
1672
1672
1673 The description of the DAG is read from stdin if not given on the
1673 The description of the DAG is read from stdin if not given on the
1674 command line.
1674 command line.
1675
1675
1676 Elements:
1676 Elements:
1677
1677
1678 - "+n" is a linear run of n nodes based on the current default parent
1678 - "+n" is a linear run of n nodes based on the current default parent
1679 - "." is a single node based on the current default parent
1679 - "." is a single node based on the current default parent
1680 - "$" resets the default parent to null (implied at the start);
1680 - "$" resets the default parent to null (implied at the start);
1681 otherwise the default parent is always the last node created
1681 otherwise the default parent is always the last node created
1682 - "<p" sets the default parent to the backref p
1682 - "<p" sets the default parent to the backref p
1683 - "*p" is a fork at parent p, which is a backref
1683 - "*p" is a fork at parent p, which is a backref
1684 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1684 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1685 - "/p2" is a merge of the preceding node and p2
1685 - "/p2" is a merge of the preceding node and p2
1686 - ":tag" defines a local tag for the preceding node
1686 - ":tag" defines a local tag for the preceding node
1687 - "@branch" sets the named branch for subsequent nodes
1687 - "@branch" sets the named branch for subsequent nodes
1688 - "#...\\n" is a comment up to the end of the line
1688 - "#...\\n" is a comment up to the end of the line
1689
1689
1690 Whitespace between the above elements is ignored.
1690 Whitespace between the above elements is ignored.
1691
1691
1692 A backref is either
1692 A backref is either
1693
1693
1694 - a number n, which references the node curr-n, where curr is the current
1694 - a number n, which references the node curr-n, where curr is the current
1695 node, or
1695 node, or
1696 - the name of a local tag you placed earlier using ":tag", or
1696 - the name of a local tag you placed earlier using ":tag", or
1697 - empty to denote the default parent.
1697 - empty to denote the default parent.
1698
1698
1699 All string valued-elements are either strictly alphanumeric, or must
1699 All string valued-elements are either strictly alphanumeric, or must
1700 be enclosed in double quotes ("..."), with "\\" as escape character.
1700 be enclosed in double quotes ("..."), with "\\" as escape character.
1701 """
1701 """
1702
1702
1703 if text is None:
1703 if text is None:
1704 ui.status(_("reading DAG from stdin\n"))
1704 ui.status(_("reading DAG from stdin\n"))
1705 text = ui.fin.read()
1705 text = ui.fin.read()
1706
1706
1707 cl = repo.changelog
1707 cl = repo.changelog
1708 if len(cl) > 0:
1708 if len(cl) > 0:
1709 raise util.Abort(_('repository is not empty'))
1709 raise util.Abort(_('repository is not empty'))
1710
1710
1711 # determine number of revs in DAG
1711 # determine number of revs in DAG
1712 total = 0
1712 total = 0
1713 for type, data in dagparser.parsedag(text):
1713 for type, data in dagparser.parsedag(text):
1714 if type == 'n':
1714 if type == 'n':
1715 total += 1
1715 total += 1
1716
1716
1717 if mergeable_file:
1717 if mergeable_file:
1718 linesperrev = 2
1718 linesperrev = 2
1719 # make a file with k lines per rev
1719 # make a file with k lines per rev
1720 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1720 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1721 initialmergedlines.append("")
1721 initialmergedlines.append("")
1722
1722
1723 tags = []
1723 tags = []
1724
1724
1725 lock = tr = None
1725 lock = tr = None
1726 try:
1726 try:
1727 lock = repo.lock()
1727 lock = repo.lock()
1728 tr = repo.transaction("builddag")
1728 tr = repo.transaction("builddag")
1729
1729
1730 at = -1
1730 at = -1
1731 atbranch = 'default'
1731 atbranch = 'default'
1732 nodeids = []
1732 nodeids = []
1733 id = 0
1733 id = 0
1734 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1734 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1735 for type, data in dagparser.parsedag(text):
1735 for type, data in dagparser.parsedag(text):
1736 if type == 'n':
1736 if type == 'n':
1737 ui.note(('node %s\n' % str(data)))
1737 ui.note(('node %s\n' % str(data)))
1738 id, ps = data
1738 id, ps = data
1739
1739
1740 files = []
1740 files = []
1741 fctxs = {}
1741 fctxs = {}
1742
1742
1743 p2 = None
1743 p2 = None
1744 if mergeable_file:
1744 if mergeable_file:
1745 fn = "mf"
1745 fn = "mf"
1746 p1 = repo[ps[0]]
1746 p1 = repo[ps[0]]
1747 if len(ps) > 1:
1747 if len(ps) > 1:
1748 p2 = repo[ps[1]]
1748 p2 = repo[ps[1]]
1749 pa = p1.ancestor(p2)
1749 pa = p1.ancestor(p2)
1750 base, local, other = [x[fn].data() for x in (pa, p1,
1750 base, local, other = [x[fn].data() for x in (pa, p1,
1751 p2)]
1751 p2)]
1752 m3 = simplemerge.Merge3Text(base, local, other)
1752 m3 = simplemerge.Merge3Text(base, local, other)
1753 ml = [l.strip() for l in m3.merge_lines()]
1753 ml = [l.strip() for l in m3.merge_lines()]
1754 ml.append("")
1754 ml.append("")
1755 elif at > 0:
1755 elif at > 0:
1756 ml = p1[fn].data().split("\n")
1756 ml = p1[fn].data().split("\n")
1757 else:
1757 else:
1758 ml = initialmergedlines
1758 ml = initialmergedlines
1759 ml[id * linesperrev] += " r%i" % id
1759 ml[id * linesperrev] += " r%i" % id
1760 mergedtext = "\n".join(ml)
1760 mergedtext = "\n".join(ml)
1761 files.append(fn)
1761 files.append(fn)
1762 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1762 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1763
1763
1764 if overwritten_file:
1764 if overwritten_file:
1765 fn = "of"
1765 fn = "of"
1766 files.append(fn)
1766 files.append(fn)
1767 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1767 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1768
1768
1769 if new_file:
1769 if new_file:
1770 fn = "nf%i" % id
1770 fn = "nf%i" % id
1771 files.append(fn)
1771 files.append(fn)
1772 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1772 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1773 if len(ps) > 1:
1773 if len(ps) > 1:
1774 if not p2:
1774 if not p2:
1775 p2 = repo[ps[1]]
1775 p2 = repo[ps[1]]
1776 for fn in p2:
1776 for fn in p2:
1777 if fn.startswith("nf"):
1777 if fn.startswith("nf"):
1778 files.append(fn)
1778 files.append(fn)
1779 fctxs[fn] = p2[fn]
1779 fctxs[fn] = p2[fn]
1780
1780
1781 def fctxfn(repo, cx, path):
1781 def fctxfn(repo, cx, path):
1782 return fctxs.get(path)
1782 return fctxs.get(path)
1783
1783
1784 if len(ps) == 0 or ps[0] < 0:
1784 if len(ps) == 0 or ps[0] < 0:
1785 pars = [None, None]
1785 pars = [None, None]
1786 elif len(ps) == 1:
1786 elif len(ps) == 1:
1787 pars = [nodeids[ps[0]], None]
1787 pars = [nodeids[ps[0]], None]
1788 else:
1788 else:
1789 pars = [nodeids[p] for p in ps]
1789 pars = [nodeids[p] for p in ps]
1790 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1790 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1791 date=(id, 0),
1791 date=(id, 0),
1792 user="debugbuilddag",
1792 user="debugbuilddag",
1793 extra={'branch': atbranch})
1793 extra={'branch': atbranch})
1794 nodeid = repo.commitctx(cx)
1794 nodeid = repo.commitctx(cx)
1795 nodeids.append(nodeid)
1795 nodeids.append(nodeid)
1796 at = id
1796 at = id
1797 elif type == 'l':
1797 elif type == 'l':
1798 id, name = data
1798 id, name = data
1799 ui.note(('tag %s\n' % name))
1799 ui.note(('tag %s\n' % name))
1800 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1800 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1801 elif type == 'a':
1801 elif type == 'a':
1802 ui.note(('branch %s\n' % data))
1802 ui.note(('branch %s\n' % data))
1803 atbranch = data
1803 atbranch = data
1804 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1804 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1805 tr.close()
1805 tr.close()
1806
1806
1807 if tags:
1807 if tags:
1808 repo.vfs.write("localtags", "".join(tags))
1808 repo.vfs.write("localtags", "".join(tags))
1809 finally:
1809 finally:
1810 ui.progress(_('building'), None)
1810 ui.progress(_('building'), None)
1811 release(tr, lock)
1811 release(tr, lock)
1812
1812
1813 @command('debugbundle',
1813 @command('debugbundle',
1814 [('a', 'all', None, _('show all details'))],
1814 [('a', 'all', None, _('show all details'))],
1815 _('FILE'),
1815 _('FILE'),
1816 norepo=True)
1816 norepo=True)
1817 def debugbundle(ui, bundlepath, all=None, **opts):
1817 def debugbundle(ui, bundlepath, all=None, **opts):
1818 """lists the contents of a bundle"""
1818 """lists the contents of a bundle"""
1819 f = hg.openpath(ui, bundlepath)
1819 f = hg.openpath(ui, bundlepath)
1820 try:
1820 try:
1821 gen = exchange.readbundle(ui, f, bundlepath)
1821 gen = exchange.readbundle(ui, f, bundlepath)
1822 if isinstance(gen, bundle2.unbundle20):
1822 if isinstance(gen, bundle2.unbundle20):
1823 return _debugbundle2(ui, gen, all=all, **opts)
1823 return _debugbundle2(ui, gen, all=all, **opts)
1824 if all:
1824 if all:
1825 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1825 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1826
1826
1827 def showchunks(named):
1827 def showchunks(named):
1828 ui.write("\n%s\n" % named)
1828 ui.write("\n%s\n" % named)
1829 chain = None
1829 chain = None
1830 while True:
1830 while True:
1831 chunkdata = gen.deltachunk(chain)
1831 chunkdata = gen.deltachunk(chain)
1832 if not chunkdata:
1832 if not chunkdata:
1833 break
1833 break
1834 node = chunkdata['node']
1834 node = chunkdata['node']
1835 p1 = chunkdata['p1']
1835 p1 = chunkdata['p1']
1836 p2 = chunkdata['p2']
1836 p2 = chunkdata['p2']
1837 cs = chunkdata['cs']
1837 cs = chunkdata['cs']
1838 deltabase = chunkdata['deltabase']
1838 deltabase = chunkdata['deltabase']
1839 delta = chunkdata['delta']
1839 delta = chunkdata['delta']
1840 ui.write("%s %s %s %s %s %s\n" %
1840 ui.write("%s %s %s %s %s %s\n" %
1841 (hex(node), hex(p1), hex(p2),
1841 (hex(node), hex(p1), hex(p2),
1842 hex(cs), hex(deltabase), len(delta)))
1842 hex(cs), hex(deltabase), len(delta)))
1843 chain = node
1843 chain = node
1844
1844
1845 chunkdata = gen.changelogheader()
1845 chunkdata = gen.changelogheader()
1846 showchunks("changelog")
1846 showchunks("changelog")
1847 chunkdata = gen.manifestheader()
1847 chunkdata = gen.manifestheader()
1848 showchunks("manifest")
1848 showchunks("manifest")
1849 while True:
1849 while True:
1850 chunkdata = gen.filelogheader()
1850 chunkdata = gen.filelogheader()
1851 if not chunkdata:
1851 if not chunkdata:
1852 break
1852 break
1853 fname = chunkdata['filename']
1853 fname = chunkdata['filename']
1854 showchunks(fname)
1854 showchunks(fname)
1855 else:
1855 else:
1856 if isinstance(gen, bundle2.unbundle20):
1856 if isinstance(gen, bundle2.unbundle20):
1857 raise util.Abort(_('use debugbundle2 for this file'))
1857 raise util.Abort(_('use debugbundle2 for this file'))
1858 chunkdata = gen.changelogheader()
1858 chunkdata = gen.changelogheader()
1859 chain = None
1859 chain = None
1860 while True:
1860 while True:
1861 chunkdata = gen.deltachunk(chain)
1861 chunkdata = gen.deltachunk(chain)
1862 if not chunkdata:
1862 if not chunkdata:
1863 break
1863 break
1864 node = chunkdata['node']
1864 node = chunkdata['node']
1865 ui.write("%s\n" % hex(node))
1865 ui.write("%s\n" % hex(node))
1866 chain = node
1866 chain = node
1867 finally:
1867 finally:
1868 f.close()
1868 f.close()
1869
1869
1870 def _debugbundle2(ui, gen, **opts):
1870 def _debugbundle2(ui, gen, **opts):
1871 """lists the contents of a bundle2"""
1871 """lists the contents of a bundle2"""
1872 if not isinstance(gen, bundle2.unbundle20):
1872 if not isinstance(gen, bundle2.unbundle20):
1873 raise util.Abort(_('not a bundle2 file'))
1873 raise util.Abort(_('not a bundle2 file'))
1874 ui.write(('Stream params: %s\n' % repr(gen.params)))
1874 ui.write(('Stream params: %s\n' % repr(gen.params)))
1875 for part in gen.iterparts():
1875 for part in gen.iterparts():
1876 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1876 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1877 if part.type == 'b2x:changegroup':
1877 if part.type == 'b2x:changegroup':
1878 version = part.params.get('version', '01')
1878 version = part.params.get('version', '01')
1879 cg = changegroup.packermap[version][1](part, 'UN')
1879 cg = changegroup.packermap[version][1](part, 'UN')
1880 chunkdata = cg.changelogheader()
1880 chunkdata = cg.changelogheader()
1881 chain = None
1881 chain = None
1882 while True:
1882 while True:
1883 chunkdata = cg.deltachunk(chain)
1883 chunkdata = cg.deltachunk(chain)
1884 if not chunkdata:
1884 if not chunkdata:
1885 break
1885 break
1886 node = chunkdata['node']
1886 node = chunkdata['node']
1887 ui.write(" %s\n" % hex(node))
1887 ui.write(" %s\n" % hex(node))
1888 chain = node
1888 chain = node
1889
1889
1890 @command('debugcheckstate', [], '')
1890 @command('debugcheckstate', [], '')
1891 def debugcheckstate(ui, repo):
1891 def debugcheckstate(ui, repo):
1892 """validate the correctness of the current dirstate"""
1892 """validate the correctness of the current dirstate"""
1893 parent1, parent2 = repo.dirstate.parents()
1893 parent1, parent2 = repo.dirstate.parents()
1894 m1 = repo[parent1].manifest()
1894 m1 = repo[parent1].manifest()
1895 m2 = repo[parent2].manifest()
1895 m2 = repo[parent2].manifest()
1896 errors = 0
1896 errors = 0
1897 for f in repo.dirstate:
1897 for f in repo.dirstate:
1898 state = repo.dirstate[f]
1898 state = repo.dirstate[f]
1899 if state in "nr" and f not in m1:
1899 if state in "nr" and f not in m1:
1900 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1900 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1901 errors += 1
1901 errors += 1
1902 if state in "a" and f in m1:
1902 if state in "a" and f in m1:
1903 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1903 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1904 errors += 1
1904 errors += 1
1905 if state in "m" and f not in m1 and f not in m2:
1905 if state in "m" and f not in m1 and f not in m2:
1906 ui.warn(_("%s in state %s, but not in either manifest\n") %
1906 ui.warn(_("%s in state %s, but not in either manifest\n") %
1907 (f, state))
1907 (f, state))
1908 errors += 1
1908 errors += 1
1909 for f in m1:
1909 for f in m1:
1910 state = repo.dirstate[f]
1910 state = repo.dirstate[f]
1911 if state not in "nrm":
1911 if state not in "nrm":
1912 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1912 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1913 errors += 1
1913 errors += 1
1914 if errors:
1914 if errors:
1915 error = _(".hg/dirstate inconsistent with current parent's manifest")
1915 error = _(".hg/dirstate inconsistent with current parent's manifest")
1916 raise util.Abort(error)
1916 raise util.Abort(error)
1917
1917
1918 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1918 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1919 def debugcommands(ui, cmd='', *args):
1919 def debugcommands(ui, cmd='', *args):
1920 """list all available commands and options"""
1920 """list all available commands and options"""
1921 for cmd, vals in sorted(table.iteritems()):
1921 for cmd, vals in sorted(table.iteritems()):
1922 cmd = cmd.split('|')[0].strip('^')
1922 cmd = cmd.split('|')[0].strip('^')
1923 opts = ', '.join([i[1] for i in vals[1]])
1923 opts = ', '.join([i[1] for i in vals[1]])
1924 ui.write('%s: %s\n' % (cmd, opts))
1924 ui.write('%s: %s\n' % (cmd, opts))
1925
1925
1926 @command('debugcomplete',
1926 @command('debugcomplete',
1927 [('o', 'options', None, _('show the command options'))],
1927 [('o', 'options', None, _('show the command options'))],
1928 _('[-o] CMD'),
1928 _('[-o] CMD'),
1929 norepo=True)
1929 norepo=True)
1930 def debugcomplete(ui, cmd='', **opts):
1930 def debugcomplete(ui, cmd='', **opts):
1931 """returns the completion list associated with the given command"""
1931 """returns the completion list associated with the given command"""
1932
1932
1933 if opts.get('options'):
1933 if opts.get('options'):
1934 options = []
1934 options = []
1935 otables = [globalopts]
1935 otables = [globalopts]
1936 if cmd:
1936 if cmd:
1937 aliases, entry = cmdutil.findcmd(cmd, table, False)
1937 aliases, entry = cmdutil.findcmd(cmd, table, False)
1938 otables.append(entry[1])
1938 otables.append(entry[1])
1939 for t in otables:
1939 for t in otables:
1940 for o in t:
1940 for o in t:
1941 if "(DEPRECATED)" in o[3]:
1941 if "(DEPRECATED)" in o[3]:
1942 continue
1942 continue
1943 if o[0]:
1943 if o[0]:
1944 options.append('-%s' % o[0])
1944 options.append('-%s' % o[0])
1945 options.append('--%s' % o[1])
1945 options.append('--%s' % o[1])
1946 ui.write("%s\n" % "\n".join(options))
1946 ui.write("%s\n" % "\n".join(options))
1947 return
1947 return
1948
1948
1949 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1949 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1950 if ui.verbose:
1950 if ui.verbose:
1951 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1951 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1952 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1952 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1953
1953
1954 @command('debugdag',
1954 @command('debugdag',
1955 [('t', 'tags', None, _('use tags as labels')),
1955 [('t', 'tags', None, _('use tags as labels')),
1956 ('b', 'branches', None, _('annotate with branch names')),
1956 ('b', 'branches', None, _('annotate with branch names')),
1957 ('', 'dots', None, _('use dots for runs')),
1957 ('', 'dots', None, _('use dots for runs')),
1958 ('s', 'spaces', None, _('separate elements by spaces'))],
1958 ('s', 'spaces', None, _('separate elements by spaces'))],
1959 _('[OPTION]... [FILE [REV]...]'),
1959 _('[OPTION]... [FILE [REV]...]'),
1960 optionalrepo=True)
1960 optionalrepo=True)
1961 def debugdag(ui, repo, file_=None, *revs, **opts):
1961 def debugdag(ui, repo, file_=None, *revs, **opts):
1962 """format the changelog or an index DAG as a concise textual description
1962 """format the changelog or an index DAG as a concise textual description
1963
1963
1964 If you pass a revlog index, the revlog's DAG is emitted. If you list
1964 If you pass a revlog index, the revlog's DAG is emitted. If you list
1965 revision numbers, they get labeled in the output as rN.
1965 revision numbers, they get labeled in the output as rN.
1966
1966
1967 Otherwise, the changelog DAG of the current repo is emitted.
1967 Otherwise, the changelog DAG of the current repo is emitted.
1968 """
1968 """
1969 spaces = opts.get('spaces')
1969 spaces = opts.get('spaces')
1970 dots = opts.get('dots')
1970 dots = opts.get('dots')
1971 if file_:
1971 if file_:
1972 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1972 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1973 revs = set((int(r) for r in revs))
1973 revs = set((int(r) for r in revs))
1974 def events():
1974 def events():
1975 for r in rlog:
1975 for r in rlog:
1976 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1976 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1977 if p != -1))
1977 if p != -1))
1978 if r in revs:
1978 if r in revs:
1979 yield 'l', (r, "r%i" % r)
1979 yield 'l', (r, "r%i" % r)
1980 elif repo:
1980 elif repo:
1981 cl = repo.changelog
1981 cl = repo.changelog
1982 tags = opts.get('tags')
1982 tags = opts.get('tags')
1983 branches = opts.get('branches')
1983 branches = opts.get('branches')
1984 if tags:
1984 if tags:
1985 labels = {}
1985 labels = {}
1986 for l, n in repo.tags().items():
1986 for l, n in repo.tags().items():
1987 labels.setdefault(cl.rev(n), []).append(l)
1987 labels.setdefault(cl.rev(n), []).append(l)
1988 def events():
1988 def events():
1989 b = "default"
1989 b = "default"
1990 for r in cl:
1990 for r in cl:
1991 if branches:
1991 if branches:
1992 newb = cl.read(cl.node(r))[5]['branch']
1992 newb = cl.read(cl.node(r))[5]['branch']
1993 if newb != b:
1993 if newb != b:
1994 yield 'a', newb
1994 yield 'a', newb
1995 b = newb
1995 b = newb
1996 yield 'n', (r, list(p for p in cl.parentrevs(r)
1996 yield 'n', (r, list(p for p in cl.parentrevs(r)
1997 if p != -1))
1997 if p != -1))
1998 if tags:
1998 if tags:
1999 ls = labels.get(r)
1999 ls = labels.get(r)
2000 if ls:
2000 if ls:
2001 for l in ls:
2001 for l in ls:
2002 yield 'l', (r, l)
2002 yield 'l', (r, l)
2003 else:
2003 else:
2004 raise util.Abort(_('need repo for changelog dag'))
2004 raise util.Abort(_('need repo for changelog dag'))
2005
2005
2006 for line in dagparser.dagtextlines(events(),
2006 for line in dagparser.dagtextlines(events(),
2007 addspaces=spaces,
2007 addspaces=spaces,
2008 wraplabels=True,
2008 wraplabels=True,
2009 wrapannotations=True,
2009 wrapannotations=True,
2010 wrapnonlinear=dots,
2010 wrapnonlinear=dots,
2011 usedots=dots,
2011 usedots=dots,
2012 maxlinewidth=70):
2012 maxlinewidth=70):
2013 ui.write(line)
2013 ui.write(line)
2014 ui.write("\n")
2014 ui.write("\n")
2015
2015
2016 @command('debugdata',
2016 @command('debugdata',
2017 [('c', 'changelog', False, _('open changelog')),
2017 [('c', 'changelog', False, _('open changelog')),
2018 ('m', 'manifest', False, _('open manifest'))],
2018 ('m', 'manifest', False, _('open manifest'))],
2019 _('-c|-m|FILE REV'))
2019 _('-c|-m|FILE REV'))
2020 def debugdata(ui, repo, file_, rev=None, **opts):
2020 def debugdata(ui, repo, file_, rev=None, **opts):
2021 """dump the contents of a data file revision"""
2021 """dump the contents of a data file revision"""
2022 if opts.get('changelog') or opts.get('manifest'):
2022 if opts.get('changelog') or opts.get('manifest'):
2023 file_, rev = None, file_
2023 file_, rev = None, file_
2024 elif rev is None:
2024 elif rev is None:
2025 raise error.CommandError('debugdata', _('invalid arguments'))
2025 raise error.CommandError('debugdata', _('invalid arguments'))
2026 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2026 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2027 try:
2027 try:
2028 ui.write(r.revision(r.lookup(rev)))
2028 ui.write(r.revision(r.lookup(rev)))
2029 except KeyError:
2029 except KeyError:
2030 raise util.Abort(_('invalid revision identifier %s') % rev)
2030 raise util.Abort(_('invalid revision identifier %s') % rev)
2031
2031
2032 @command('debugdate',
2032 @command('debugdate',
2033 [('e', 'extended', None, _('try extended date formats'))],
2033 [('e', 'extended', None, _('try extended date formats'))],
2034 _('[-e] DATE [RANGE]'),
2034 _('[-e] DATE [RANGE]'),
2035 norepo=True, optionalrepo=True)
2035 norepo=True, optionalrepo=True)
2036 def debugdate(ui, date, range=None, **opts):
2036 def debugdate(ui, date, range=None, **opts):
2037 """parse and display a date"""
2037 """parse and display a date"""
2038 if opts["extended"]:
2038 if opts["extended"]:
2039 d = util.parsedate(date, util.extendeddateformats)
2039 d = util.parsedate(date, util.extendeddateformats)
2040 else:
2040 else:
2041 d = util.parsedate(date)
2041 d = util.parsedate(date)
2042 ui.write(("internal: %s %s\n") % d)
2042 ui.write(("internal: %s %s\n") % d)
2043 ui.write(("standard: %s\n") % util.datestr(d))
2043 ui.write(("standard: %s\n") % util.datestr(d))
2044 if range:
2044 if range:
2045 m = util.matchdate(range)
2045 m = util.matchdate(range)
2046 ui.write(("match: %s\n") % m(d[0]))
2046 ui.write(("match: %s\n") % m(d[0]))
2047
2047
2048 @command('debugdiscovery',
2048 @command('debugdiscovery',
2049 [('', 'old', None, _('use old-style discovery')),
2049 [('', 'old', None, _('use old-style discovery')),
2050 ('', 'nonheads', None,
2050 ('', 'nonheads', None,
2051 _('use old-style discovery with non-heads included')),
2051 _('use old-style discovery with non-heads included')),
2052 ] + remoteopts,
2052 ] + remoteopts,
2053 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2053 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2054 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2054 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2055 """runs the changeset discovery protocol in isolation"""
2055 """runs the changeset discovery protocol in isolation"""
2056 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2056 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2057 opts.get('branch'))
2057 opts.get('branch'))
2058 remote = hg.peer(repo, opts, remoteurl)
2058 remote = hg.peer(repo, opts, remoteurl)
2059 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2059 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2060
2060
2061 # make sure tests are repeatable
2061 # make sure tests are repeatable
2062 random.seed(12323)
2062 random.seed(12323)
2063
2063
2064 def doit(localheads, remoteheads, remote=remote):
2064 def doit(localheads, remoteheads, remote=remote):
2065 if opts.get('old'):
2065 if opts.get('old'):
2066 if localheads:
2066 if localheads:
2067 raise util.Abort('cannot use localheads with old style '
2067 raise util.Abort('cannot use localheads with old style '
2068 'discovery')
2068 'discovery')
2069 if not util.safehasattr(remote, 'branches'):
2069 if not util.safehasattr(remote, 'branches'):
2070 # enable in-client legacy support
2070 # enable in-client legacy support
2071 remote = localrepo.locallegacypeer(remote.local())
2071 remote = localrepo.locallegacypeer(remote.local())
2072 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2072 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2073 force=True)
2073 force=True)
2074 common = set(common)
2074 common = set(common)
2075 if not opts.get('nonheads'):
2075 if not opts.get('nonheads'):
2076 ui.write(("unpruned common: %s\n") %
2076 ui.write(("unpruned common: %s\n") %
2077 " ".join(sorted(short(n) for n in common)))
2077 " ".join(sorted(short(n) for n in common)))
2078 dag = dagutil.revlogdag(repo.changelog)
2078 dag = dagutil.revlogdag(repo.changelog)
2079 all = dag.ancestorset(dag.internalizeall(common))
2079 all = dag.ancestorset(dag.internalizeall(common))
2080 common = dag.externalizeall(dag.headsetofconnecteds(all))
2080 common = dag.externalizeall(dag.headsetofconnecteds(all))
2081 else:
2081 else:
2082 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2082 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2083 common = set(common)
2083 common = set(common)
2084 rheads = set(hds)
2084 rheads = set(hds)
2085 lheads = set(repo.heads())
2085 lheads = set(repo.heads())
2086 ui.write(("common heads: %s\n") %
2086 ui.write(("common heads: %s\n") %
2087 " ".join(sorted(short(n) for n in common)))
2087 " ".join(sorted(short(n) for n in common)))
2088 if lheads <= common:
2088 if lheads <= common:
2089 ui.write(("local is subset\n"))
2089 ui.write(("local is subset\n"))
2090 elif rheads <= common:
2090 elif rheads <= common:
2091 ui.write(("remote is subset\n"))
2091 ui.write(("remote is subset\n"))
2092
2092
2093 serverlogs = opts.get('serverlog')
2093 serverlogs = opts.get('serverlog')
2094 if serverlogs:
2094 if serverlogs:
2095 for filename in serverlogs:
2095 for filename in serverlogs:
2096 logfile = open(filename, 'r')
2096 logfile = open(filename, 'r')
2097 try:
2097 try:
2098 line = logfile.readline()
2098 line = logfile.readline()
2099 while line:
2099 while line:
2100 parts = line.strip().split(';')
2100 parts = line.strip().split(';')
2101 op = parts[1]
2101 op = parts[1]
2102 if op == 'cg':
2102 if op == 'cg':
2103 pass
2103 pass
2104 elif op == 'cgss':
2104 elif op == 'cgss':
2105 doit(parts[2].split(' '), parts[3].split(' '))
2105 doit(parts[2].split(' '), parts[3].split(' '))
2106 elif op == 'unb':
2106 elif op == 'unb':
2107 doit(parts[3].split(' '), parts[2].split(' '))
2107 doit(parts[3].split(' '), parts[2].split(' '))
2108 line = logfile.readline()
2108 line = logfile.readline()
2109 finally:
2109 finally:
2110 logfile.close()
2110 logfile.close()
2111
2111
2112 else:
2112 else:
2113 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2113 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2114 opts.get('remote_head'))
2114 opts.get('remote_head'))
2115 localrevs = opts.get('local_head')
2115 localrevs = opts.get('local_head')
2116 doit(localrevs, remoterevs)
2116 doit(localrevs, remoterevs)
2117
2117
2118 @command('debugfileset',
2118 @command('debugfileset',
2119 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2119 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2120 _('[-r REV] FILESPEC'))
2120 _('[-r REV] FILESPEC'))
2121 def debugfileset(ui, repo, expr, **opts):
2121 def debugfileset(ui, repo, expr, **opts):
2122 '''parse and apply a fileset specification'''
2122 '''parse and apply a fileset specification'''
2123 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2123 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2124 if ui.verbose:
2124 if ui.verbose:
2125 tree = fileset.parse(expr)[0]
2125 tree = fileset.parse(expr)[0]
2126 ui.note(tree, "\n")
2126 ui.note(tree, "\n")
2127
2127
2128 for f in ctx.getfileset(expr):
2128 for f in ctx.getfileset(expr):
2129 ui.write("%s\n" % f)
2129 ui.write("%s\n" % f)
2130
2130
2131 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2131 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2132 def debugfsinfo(ui, path="."):
2132 def debugfsinfo(ui, path="."):
2133 """show information detected about current filesystem"""
2133 """show information detected about current filesystem"""
2134 util.writefile('.debugfsinfo', '')
2134 util.writefile('.debugfsinfo', '')
2135 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2135 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2136 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2136 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2137 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2137 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2138 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2138 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2139 and 'yes' or 'no'))
2139 and 'yes' or 'no'))
2140 os.unlink('.debugfsinfo')
2140 os.unlink('.debugfsinfo')
2141
2141
2142 @command('debuggetbundle',
2142 @command('debuggetbundle',
2143 [('H', 'head', [], _('id of head node'), _('ID')),
2143 [('H', 'head', [], _('id of head node'), _('ID')),
2144 ('C', 'common', [], _('id of common node'), _('ID')),
2144 ('C', 'common', [], _('id of common node'), _('ID')),
2145 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2145 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2146 _('REPO FILE [-H|-C ID]...'),
2146 _('REPO FILE [-H|-C ID]...'),
2147 norepo=True)
2147 norepo=True)
2148 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2148 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2149 """retrieves a bundle from a repo
2149 """retrieves a bundle from a repo
2150
2150
2151 Every ID must be a full-length hex node id string. Saves the bundle to the
2151 Every ID must be a full-length hex node id string. Saves the bundle to the
2152 given file.
2152 given file.
2153 """
2153 """
2154 repo = hg.peer(ui, opts, repopath)
2154 repo = hg.peer(ui, opts, repopath)
2155 if not repo.capable('getbundle'):
2155 if not repo.capable('getbundle'):
2156 raise util.Abort("getbundle() not supported by target repository")
2156 raise util.Abort("getbundle() not supported by target repository")
2157 args = {}
2157 args = {}
2158 if common:
2158 if common:
2159 args['common'] = [bin(s) for s in common]
2159 args['common'] = [bin(s) for s in common]
2160 if head:
2160 if head:
2161 args['heads'] = [bin(s) for s in head]
2161 args['heads'] = [bin(s) for s in head]
2162 # TODO: get desired bundlecaps from command line.
2162 # TODO: get desired bundlecaps from command line.
2163 args['bundlecaps'] = None
2163 args['bundlecaps'] = None
2164 bundle = repo.getbundle('debug', **args)
2164 bundle = repo.getbundle('debug', **args)
2165
2165
2166 bundletype = opts.get('type', 'bzip2').lower()
2166 bundletype = opts.get('type', 'bzip2').lower()
2167 btypes = {'none': 'HG10UN',
2167 btypes = {'none': 'HG10UN',
2168 'bzip2': 'HG10BZ',
2168 'bzip2': 'HG10BZ',
2169 'gzip': 'HG10GZ',
2169 'gzip': 'HG10GZ',
2170 'bundle2': 'HG2Y'}
2170 'bundle2': 'HG2Y'}
2171 bundletype = btypes.get(bundletype)
2171 bundletype = btypes.get(bundletype)
2172 if bundletype not in changegroup.bundletypes:
2172 if bundletype not in changegroup.bundletypes:
2173 raise util.Abort(_('unknown bundle type specified with --type'))
2173 raise util.Abort(_('unknown bundle type specified with --type'))
2174 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2174 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2175
2175
2176 @command('debugignore', [], '')
2176 @command('debugignore', [], '')
2177 def debugignore(ui, repo, *values, **opts):
2177 def debugignore(ui, repo, *values, **opts):
2178 """display the combined ignore pattern"""
2178 """display the combined ignore pattern"""
2179 ignore = repo.dirstate._ignore
2179 ignore = repo.dirstate._ignore
2180 includepat = getattr(ignore, 'includepat', None)
2180 includepat = getattr(ignore, 'includepat', None)
2181 if includepat is not None:
2181 if includepat is not None:
2182 ui.write("%s\n" % includepat)
2182 ui.write("%s\n" % includepat)
2183 else:
2183 else:
2184 raise util.Abort(_("no ignore patterns found"))
2184 raise util.Abort(_("no ignore patterns found"))
2185
2185
2186 @command('debugindex',
2186 @command('debugindex',
2187 [('c', 'changelog', False, _('open changelog')),
2187 [('c', 'changelog', False, _('open changelog')),
2188 ('m', 'manifest', False, _('open manifest')),
2188 ('m', 'manifest', False, _('open manifest')),
2189 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2189 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2190 _('[-f FORMAT] -c|-m|FILE'),
2190 _('[-f FORMAT] -c|-m|FILE'),
2191 optionalrepo=True)
2191 optionalrepo=True)
2192 def debugindex(ui, repo, file_=None, **opts):
2192 def debugindex(ui, repo, file_=None, **opts):
2193 """dump the contents of an index file"""
2193 """dump the contents of an index file"""
2194 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2194 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2195 format = opts.get('format', 0)
2195 format = opts.get('format', 0)
2196 if format not in (0, 1):
2196 if format not in (0, 1):
2197 raise util.Abort(_("unknown format %d") % format)
2197 raise util.Abort(_("unknown format %d") % format)
2198
2198
2199 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2199 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2200 if generaldelta:
2200 if generaldelta:
2201 basehdr = ' delta'
2201 basehdr = ' delta'
2202 else:
2202 else:
2203 basehdr = ' base'
2203 basehdr = ' base'
2204
2204
2205 if ui.debugflag:
2205 if ui.debugflag:
2206 shortfn = hex
2206 shortfn = hex
2207 else:
2207 else:
2208 shortfn = short
2208 shortfn = short
2209
2209
2210 # There might not be anything in r, so have a sane default
2210 # There might not be anything in r, so have a sane default
2211 idlen = 12
2211 idlen = 12
2212 for i in r:
2212 for i in r:
2213 idlen = len(shortfn(r.node(i)))
2213 idlen = len(shortfn(r.node(i)))
2214 break
2214 break
2215
2215
2216 if format == 0:
2216 if format == 0:
2217 ui.write(" rev offset length " + basehdr + " linkrev"
2217 ui.write(" rev offset length " + basehdr + " linkrev"
2218 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2218 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2219 elif format == 1:
2219 elif format == 1:
2220 ui.write(" rev flag offset length"
2220 ui.write(" rev flag offset length"
2221 " size " + basehdr + " link p1 p2"
2221 " size " + basehdr + " link p1 p2"
2222 " %s\n" % "nodeid".rjust(idlen))
2222 " %s\n" % "nodeid".rjust(idlen))
2223
2223
2224 for i in r:
2224 for i in r:
2225 node = r.node(i)
2225 node = r.node(i)
2226 if generaldelta:
2226 if generaldelta:
2227 base = r.deltaparent(i)
2227 base = r.deltaparent(i)
2228 else:
2228 else:
2229 base = r.chainbase(i)
2229 base = r.chainbase(i)
2230 if format == 0:
2230 if format == 0:
2231 try:
2231 try:
2232 pp = r.parents(node)
2232 pp = r.parents(node)
2233 except Exception:
2233 except Exception:
2234 pp = [nullid, nullid]
2234 pp = [nullid, nullid]
2235 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2235 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2236 i, r.start(i), r.length(i), base, r.linkrev(i),
2236 i, r.start(i), r.length(i), base, r.linkrev(i),
2237 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2237 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2238 elif format == 1:
2238 elif format == 1:
2239 pr = r.parentrevs(i)
2239 pr = r.parentrevs(i)
2240 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2240 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2241 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2241 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2242 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2242 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2243
2243
2244 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2244 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2245 def debugindexdot(ui, repo, file_):
2245 def debugindexdot(ui, repo, file_):
2246 """dump an index DAG as a graphviz dot file"""
2246 """dump an index DAG as a graphviz dot file"""
2247 r = None
2247 r = None
2248 if repo:
2248 if repo:
2249 filelog = repo.file(file_)
2249 filelog = repo.file(file_)
2250 if len(filelog):
2250 if len(filelog):
2251 r = filelog
2251 r = filelog
2252 if not r:
2252 if not r:
2253 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2253 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2254 ui.write(("digraph G {\n"))
2254 ui.write(("digraph G {\n"))
2255 for i in r:
2255 for i in r:
2256 node = r.node(i)
2256 node = r.node(i)
2257 pp = r.parents(node)
2257 pp = r.parents(node)
2258 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2258 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2259 if pp[1] != nullid:
2259 if pp[1] != nullid:
2260 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2260 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2261 ui.write("}\n")
2261 ui.write("}\n")
2262
2262
2263 @command('debuginstall', [], '', norepo=True)
2263 @command('debuginstall', [], '', norepo=True)
2264 def debuginstall(ui):
2264 def debuginstall(ui):
2265 '''test Mercurial installation
2265 '''test Mercurial installation
2266
2266
2267 Returns 0 on success.
2267 Returns 0 on success.
2268 '''
2268 '''
2269
2269
2270 def writetemp(contents):
2270 def writetemp(contents):
2271 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2271 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2272 f = os.fdopen(fd, "wb")
2272 f = os.fdopen(fd, "wb")
2273 f.write(contents)
2273 f.write(contents)
2274 f.close()
2274 f.close()
2275 return name
2275 return name
2276
2276
2277 problems = 0
2277 problems = 0
2278
2278
2279 # encoding
2279 # encoding
2280 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2280 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2281 try:
2281 try:
2282 encoding.fromlocal("test")
2282 encoding.fromlocal("test")
2283 except util.Abort, inst:
2283 except util.Abort, inst:
2284 ui.write(" %s\n" % inst)
2284 ui.write(" %s\n" % inst)
2285 ui.write(_(" (check that your locale is properly set)\n"))
2285 ui.write(_(" (check that your locale is properly set)\n"))
2286 problems += 1
2286 problems += 1
2287
2287
2288 # Python
2288 # Python
2289 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2289 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2290 ui.status(_("checking Python version (%s)\n")
2290 ui.status(_("checking Python version (%s)\n")
2291 % ("%s.%s.%s" % sys.version_info[:3]))
2291 % ("%s.%s.%s" % sys.version_info[:3]))
2292 ui.status(_("checking Python lib (%s)...\n")
2292 ui.status(_("checking Python lib (%s)...\n")
2293 % os.path.dirname(os.__file__))
2293 % os.path.dirname(os.__file__))
2294
2294
2295 # compiled modules
2295 # compiled modules
2296 ui.status(_("checking installed modules (%s)...\n")
2296 ui.status(_("checking installed modules (%s)...\n")
2297 % os.path.dirname(__file__))
2297 % os.path.dirname(__file__))
2298 try:
2298 try:
2299 import bdiff, mpatch, base85, osutil
2299 import bdiff, mpatch, base85, osutil
2300 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2300 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2301 except Exception, inst:
2301 except Exception, inst:
2302 ui.write(" %s\n" % inst)
2302 ui.write(" %s\n" % inst)
2303 ui.write(_(" One or more extensions could not be found"))
2303 ui.write(_(" One or more extensions could not be found"))
2304 ui.write(_(" (check that you compiled the extensions)\n"))
2304 ui.write(_(" (check that you compiled the extensions)\n"))
2305 problems += 1
2305 problems += 1
2306
2306
2307 # templates
2307 # templates
2308 import templater
2308 import templater
2309 p = templater.templatepaths()
2309 p = templater.templatepaths()
2310 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2310 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2311 if p:
2311 if p:
2312 m = templater.templatepath("map-cmdline.default")
2312 m = templater.templatepath("map-cmdline.default")
2313 if m:
2313 if m:
2314 # template found, check if it is working
2314 # template found, check if it is working
2315 try:
2315 try:
2316 templater.templater(m)
2316 templater.templater(m)
2317 except Exception, inst:
2317 except Exception, inst:
2318 ui.write(" %s\n" % inst)
2318 ui.write(" %s\n" % inst)
2319 p = None
2319 p = None
2320 else:
2320 else:
2321 ui.write(_(" template 'default' not found\n"))
2321 ui.write(_(" template 'default' not found\n"))
2322 p = None
2322 p = None
2323 else:
2323 else:
2324 ui.write(_(" no template directories found\n"))
2324 ui.write(_(" no template directories found\n"))
2325 if not p:
2325 if not p:
2326 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2326 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2327 problems += 1
2327 problems += 1
2328
2328
2329 # editor
2329 # editor
2330 ui.status(_("checking commit editor...\n"))
2330 ui.status(_("checking commit editor...\n"))
2331 editor = ui.geteditor()
2331 editor = ui.geteditor()
2332 cmdpath = util.findexe(shlex.split(editor)[0])
2332 cmdpath = util.findexe(shlex.split(editor)[0])
2333 if not cmdpath:
2333 if not cmdpath:
2334 if editor == 'vi':
2334 if editor == 'vi':
2335 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2335 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2336 ui.write(_(" (specify a commit editor in your configuration"
2336 ui.write(_(" (specify a commit editor in your configuration"
2337 " file)\n"))
2337 " file)\n"))
2338 else:
2338 else:
2339 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2339 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2340 ui.write(_(" (specify a commit editor in your configuration"
2340 ui.write(_(" (specify a commit editor in your configuration"
2341 " file)\n"))
2341 " file)\n"))
2342 problems += 1
2342 problems += 1
2343
2343
2344 # check username
2344 # check username
2345 ui.status(_("checking username...\n"))
2345 ui.status(_("checking username...\n"))
2346 try:
2346 try:
2347 ui.username()
2347 ui.username()
2348 except util.Abort, e:
2348 except util.Abort, e:
2349 ui.write(" %s\n" % e)
2349 ui.write(" %s\n" % e)
2350 ui.write(_(" (specify a username in your configuration file)\n"))
2350 ui.write(_(" (specify a username in your configuration file)\n"))
2351 problems += 1
2351 problems += 1
2352
2352
2353 if not problems:
2353 if not problems:
2354 ui.status(_("no problems detected\n"))
2354 ui.status(_("no problems detected\n"))
2355 else:
2355 else:
2356 ui.write(_("%s problems detected,"
2356 ui.write(_("%s problems detected,"
2357 " please check your install!\n") % problems)
2357 " please check your install!\n") % problems)
2358
2358
2359 return problems
2359 return problems
2360
2360
2361 @command('debugknown', [], _('REPO ID...'), norepo=True)
2361 @command('debugknown', [], _('REPO ID...'), norepo=True)
2362 def debugknown(ui, repopath, *ids, **opts):
2362 def debugknown(ui, repopath, *ids, **opts):
2363 """test whether node ids are known to a repo
2363 """test whether node ids are known to a repo
2364
2364
2365 Every ID must be a full-length hex node id string. Returns a list of 0s
2365 Every ID must be a full-length hex node id string. Returns a list of 0s
2366 and 1s indicating unknown/known.
2366 and 1s indicating unknown/known.
2367 """
2367 """
2368 repo = hg.peer(ui, opts, repopath)
2368 repo = hg.peer(ui, opts, repopath)
2369 if not repo.capable('known'):
2369 if not repo.capable('known'):
2370 raise util.Abort("known() not supported by target repository")
2370 raise util.Abort("known() not supported by target repository")
2371 flags = repo.known([bin(s) for s in ids])
2371 flags = repo.known([bin(s) for s in ids])
2372 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2372 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2373
2373
2374 @command('debuglabelcomplete', [], _('LABEL...'))
2374 @command('debuglabelcomplete', [], _('LABEL...'))
2375 def debuglabelcomplete(ui, repo, *args):
2375 def debuglabelcomplete(ui, repo, *args):
2376 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2376 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2377 debugnamecomplete(ui, repo, *args)
2377 debugnamecomplete(ui, repo, *args)
2378
2378
2379 @command('debugnamecomplete', [], _('NAME...'))
2379 @command('debugnamecomplete', [], _('NAME...'))
2380 def debugnamecomplete(ui, repo, *args):
2380 def debugnamecomplete(ui, repo, *args):
2381 '''complete "names" - tags, open branch names, bookmark names'''
2381 '''complete "names" - tags, open branch names, bookmark names'''
2382
2382
2383 names = set()
2383 names = set()
2384 # since we previously only listed open branches, we will handle that
2384 # since we previously only listed open branches, we will handle that
2385 # specially (after this for loop)
2385 # specially (after this for loop)
2386 for name, ns in repo.names.iteritems():
2386 for name, ns in repo.names.iteritems():
2387 if name != 'branches':
2387 if name != 'branches':
2388 names.update(ns.listnames(repo))
2388 names.update(ns.listnames(repo))
2389 names.update(tag for (tag, heads, tip, closed)
2389 names.update(tag for (tag, heads, tip, closed)
2390 in repo.branchmap().iterbranches() if not closed)
2390 in repo.branchmap().iterbranches() if not closed)
2391 completions = set()
2391 completions = set()
2392 if not args:
2392 if not args:
2393 args = ['']
2393 args = ['']
2394 for a in args:
2394 for a in args:
2395 completions.update(n for n in names if n.startswith(a))
2395 completions.update(n for n in names if n.startswith(a))
2396 ui.write('\n'.join(sorted(completions)))
2396 ui.write('\n'.join(sorted(completions)))
2397 ui.write('\n')
2397 ui.write('\n')
2398
2398
2399 @command('debuglocks',
2399 @command('debuglocks',
2400 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2400 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2401 ('W', 'force-wlock', None,
2401 ('W', 'force-wlock', None,
2402 _('free the working state lock (DANGEROUS)'))],
2402 _('free the working state lock (DANGEROUS)'))],
2403 _('[OPTION]...'))
2403 _('[OPTION]...'))
2404 def debuglocks(ui, repo, **opts):
2404 def debuglocks(ui, repo, **opts):
2405 """show or modify state of locks
2405 """show or modify state of locks
2406
2406
2407 By default, this command will show which locks are held. This
2407 By default, this command will show which locks are held. This
2408 includes the user and process holding the lock, the amount of time
2408 includes the user and process holding the lock, the amount of time
2409 the lock has been held, and the machine name where the process is
2409 the lock has been held, and the machine name where the process is
2410 running if it's not local.
2410 running if it's not local.
2411
2411
2412 Locks protect the integrity of Mercurial's data, so should be
2412 Locks protect the integrity of Mercurial's data, so should be
2413 treated with care. System crashes or other interruptions may cause
2413 treated with care. System crashes or other interruptions may cause
2414 locks to not be properly released, though Mercurial will usually
2414 locks to not be properly released, though Mercurial will usually
2415 detect and remove such stale locks automatically.
2415 detect and remove such stale locks automatically.
2416
2416
2417 However, detecting stale locks may not always be possible (for
2417 However, detecting stale locks may not always be possible (for
2418 instance, on a shared filesystem). Removing locks may also be
2418 instance, on a shared filesystem). Removing locks may also be
2419 blocked by filesystem permissions.
2419 blocked by filesystem permissions.
2420
2420
2421 Returns 0 if no locks are held.
2421 Returns 0 if no locks are held.
2422
2422
2423 """
2423 """
2424
2424
2425 if opts.get('force_lock'):
2425 if opts.get('force_lock'):
2426 repo.svfs.unlink('lock')
2426 repo.svfs.unlink('lock')
2427 if opts.get('force_wlock'):
2427 if opts.get('force_wlock'):
2428 repo.vfs.unlink('wlock')
2428 repo.vfs.unlink('wlock')
2429 if opts.get('force_lock') or opts.get('force_lock'):
2429 if opts.get('force_lock') or opts.get('force_lock'):
2430 return 0
2430 return 0
2431
2431
2432 now = time.time()
2432 now = time.time()
2433 held = 0
2433 held = 0
2434
2434
2435 def report(vfs, name, method):
2435 def report(vfs, name, method):
2436 # this causes stale locks to get reaped for more accurate reporting
2436 # this causes stale locks to get reaped for more accurate reporting
2437 try:
2437 try:
2438 l = method(False)
2438 l = method(False)
2439 except error.LockHeld:
2439 except error.LockHeld:
2440 l = None
2440 l = None
2441
2441
2442 if l:
2442 if l:
2443 l.release()
2443 l.release()
2444 else:
2444 else:
2445 try:
2445 try:
2446 stat = repo.svfs.lstat(name)
2446 stat = repo.svfs.lstat(name)
2447 age = now - stat.st_mtime
2447 age = now - stat.st_mtime
2448 user = util.username(stat.st_uid)
2448 user = util.username(stat.st_uid)
2449 locker = vfs.readlock(name)
2449 locker = vfs.readlock(name)
2450 if ":" in locker:
2450 if ":" in locker:
2451 host, pid = locker.split(':')
2451 host, pid = locker.split(':')
2452 if host == socket.gethostname():
2452 if host == socket.gethostname():
2453 locker = 'user %s, process %s' % (user, pid)
2453 locker = 'user %s, process %s' % (user, pid)
2454 else:
2454 else:
2455 locker = 'user %s, process %s, host %s' \
2455 locker = 'user %s, process %s, host %s' \
2456 % (user, pid, host)
2456 % (user, pid, host)
2457 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2457 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2458 return 1
2458 return 1
2459 except OSError, e:
2459 except OSError, e:
2460 if e.errno != errno.ENOENT:
2460 if e.errno != errno.ENOENT:
2461 raise
2461 raise
2462
2462
2463 ui.write("%-6s free\n" % (name + ":"))
2463 ui.write("%-6s free\n" % (name + ":"))
2464 return 0
2464 return 0
2465
2465
2466 held += report(repo.svfs, "lock", repo.lock)
2466 held += report(repo.svfs, "lock", repo.lock)
2467 held += report(repo.vfs, "wlock", repo.wlock)
2467 held += report(repo.vfs, "wlock", repo.wlock)
2468
2468
2469 return held
2469 return held
2470
2470
2471 @command('debugobsolete',
2471 @command('debugobsolete',
2472 [('', 'flags', 0, _('markers flag')),
2472 [('', 'flags', 0, _('markers flag')),
2473 ('', 'record-parents', False,
2473 ('', 'record-parents', False,
2474 _('record parent information for the precursor')),
2474 _('record parent information for the precursor')),
2475 ('r', 'rev', [], _('display markers relevant to REV')),
2475 ('r', 'rev', [], _('display markers relevant to REV')),
2476 ] + commitopts2,
2476 ] + commitopts2,
2477 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2477 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2478 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2478 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2479 """create arbitrary obsolete marker
2479 """create arbitrary obsolete marker
2480
2480
2481 With no arguments, displays the list of obsolescence markers."""
2481 With no arguments, displays the list of obsolescence markers."""
2482
2482
2483 def parsenodeid(s):
2483 def parsenodeid(s):
2484 try:
2484 try:
2485 # We do not use revsingle/revrange functions here to accept
2485 # We do not use revsingle/revrange functions here to accept
2486 # arbitrary node identifiers, possibly not present in the
2486 # arbitrary node identifiers, possibly not present in the
2487 # local repository.
2487 # local repository.
2488 n = bin(s)
2488 n = bin(s)
2489 if len(n) != len(nullid):
2489 if len(n) != len(nullid):
2490 raise TypeError()
2490 raise TypeError()
2491 return n
2491 return n
2492 except TypeError:
2492 except TypeError:
2493 raise util.Abort('changeset references must be full hexadecimal '
2493 raise util.Abort('changeset references must be full hexadecimal '
2494 'node identifiers')
2494 'node identifiers')
2495
2495
2496 if precursor is not None:
2496 if precursor is not None:
2497 if opts['rev']:
2497 if opts['rev']:
2498 raise util.Abort('cannot select revision when creating marker')
2498 raise util.Abort('cannot select revision when creating marker')
2499 metadata = {}
2499 metadata = {}
2500 metadata['user'] = opts['user'] or ui.username()
2500 metadata['user'] = opts['user'] or ui.username()
2501 succs = tuple(parsenodeid(succ) for succ in successors)
2501 succs = tuple(parsenodeid(succ) for succ in successors)
2502 l = repo.lock()
2502 l = repo.lock()
2503 try:
2503 try:
2504 tr = repo.transaction('debugobsolete')
2504 tr = repo.transaction('debugobsolete')
2505 try:
2505 try:
2506 try:
2506 try:
2507 date = opts.get('date')
2507 date = opts.get('date')
2508 if date:
2508 if date:
2509 date = util.parsedate(date)
2509 date = util.parsedate(date)
2510 else:
2510 else:
2511 date = None
2511 date = None
2512 prec = parsenodeid(precursor)
2512 prec = parsenodeid(precursor)
2513 parents = None
2513 parents = None
2514 if opts['record_parents']:
2514 if opts['record_parents']:
2515 if prec not in repo.unfiltered():
2515 if prec not in repo.unfiltered():
2516 raise util.Abort('cannot used --record-parents on '
2516 raise util.Abort('cannot used --record-parents on '
2517 'unknown changesets')
2517 'unknown changesets')
2518 parents = repo.unfiltered()[prec].parents()
2518 parents = repo.unfiltered()[prec].parents()
2519 parents = tuple(p.node() for p in parents)
2519 parents = tuple(p.node() for p in parents)
2520 repo.obsstore.create(tr, prec, succs, opts['flags'],
2520 repo.obsstore.create(tr, prec, succs, opts['flags'],
2521 parents=parents, date=date,
2521 parents=parents, date=date,
2522 metadata=metadata)
2522 metadata=metadata)
2523 tr.close()
2523 tr.close()
2524 except ValueError, exc:
2524 except ValueError, exc:
2525 raise util.Abort(_('bad obsmarker input: %s') % exc)
2525 raise util.Abort(_('bad obsmarker input: %s') % exc)
2526 finally:
2526 finally:
2527 tr.release()
2527 tr.release()
2528 finally:
2528 finally:
2529 l.release()
2529 l.release()
2530 else:
2530 else:
2531 if opts['rev']:
2531 if opts['rev']:
2532 revs = scmutil.revrange(repo, opts['rev'])
2532 revs = scmutil.revrange(repo, opts['rev'])
2533 nodes = [repo[r].node() for r in revs]
2533 nodes = [repo[r].node() for r in revs]
2534 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2534 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2535 markers.sort(key=lambda x: x._data)
2535 markers.sort(key=lambda x: x._data)
2536 else:
2536 else:
2537 markers = obsolete.getmarkers(repo)
2537 markers = obsolete.getmarkers(repo)
2538
2538
2539 for m in markers:
2539 for m in markers:
2540 cmdutil.showmarker(ui, m)
2540 cmdutil.showmarker(ui, m)
2541
2541
2542 @command('debugpathcomplete',
2542 @command('debugpathcomplete',
2543 [('f', 'full', None, _('complete an entire path')),
2543 [('f', 'full', None, _('complete an entire path')),
2544 ('n', 'normal', None, _('show only normal files')),
2544 ('n', 'normal', None, _('show only normal files')),
2545 ('a', 'added', None, _('show only added files')),
2545 ('a', 'added', None, _('show only added files')),
2546 ('r', 'removed', None, _('show only removed files'))],
2546 ('r', 'removed', None, _('show only removed files'))],
2547 _('FILESPEC...'))
2547 _('FILESPEC...'))
2548 def debugpathcomplete(ui, repo, *specs, **opts):
2548 def debugpathcomplete(ui, repo, *specs, **opts):
2549 '''complete part or all of a tracked path
2549 '''complete part or all of a tracked path
2550
2550
2551 This command supports shells that offer path name completion. It
2551 This command supports shells that offer path name completion. It
2552 currently completes only files already known to the dirstate.
2552 currently completes only files already known to the dirstate.
2553
2553
2554 Completion extends only to the next path segment unless
2554 Completion extends only to the next path segment unless
2555 --full is specified, in which case entire paths are used.'''
2555 --full is specified, in which case entire paths are used.'''
2556
2556
2557 def complete(path, acceptable):
2557 def complete(path, acceptable):
2558 dirstate = repo.dirstate
2558 dirstate = repo.dirstate
2559 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2559 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2560 rootdir = repo.root + os.sep
2560 rootdir = repo.root + os.sep
2561 if spec != repo.root and not spec.startswith(rootdir):
2561 if spec != repo.root and not spec.startswith(rootdir):
2562 return [], []
2562 return [], []
2563 if os.path.isdir(spec):
2563 if os.path.isdir(spec):
2564 spec += '/'
2564 spec += '/'
2565 spec = spec[len(rootdir):]
2565 spec = spec[len(rootdir):]
2566 fixpaths = os.sep != '/'
2566 fixpaths = os.sep != '/'
2567 if fixpaths:
2567 if fixpaths:
2568 spec = spec.replace(os.sep, '/')
2568 spec = spec.replace(os.sep, '/')
2569 speclen = len(spec)
2569 speclen = len(spec)
2570 fullpaths = opts['full']
2570 fullpaths = opts['full']
2571 files, dirs = set(), set()
2571 files, dirs = set(), set()
2572 adddir, addfile = dirs.add, files.add
2572 adddir, addfile = dirs.add, files.add
2573 for f, st in dirstate.iteritems():
2573 for f, st in dirstate.iteritems():
2574 if f.startswith(spec) and st[0] in acceptable:
2574 if f.startswith(spec) and st[0] in acceptable:
2575 if fixpaths:
2575 if fixpaths:
2576 f = f.replace('/', os.sep)
2576 f = f.replace('/', os.sep)
2577 if fullpaths:
2577 if fullpaths:
2578 addfile(f)
2578 addfile(f)
2579 continue
2579 continue
2580 s = f.find(os.sep, speclen)
2580 s = f.find(os.sep, speclen)
2581 if s >= 0:
2581 if s >= 0:
2582 adddir(f[:s])
2582 adddir(f[:s])
2583 else:
2583 else:
2584 addfile(f)
2584 addfile(f)
2585 return files, dirs
2585 return files, dirs
2586
2586
2587 acceptable = ''
2587 acceptable = ''
2588 if opts['normal']:
2588 if opts['normal']:
2589 acceptable += 'nm'
2589 acceptable += 'nm'
2590 if opts['added']:
2590 if opts['added']:
2591 acceptable += 'a'
2591 acceptable += 'a'
2592 if opts['removed']:
2592 if opts['removed']:
2593 acceptable += 'r'
2593 acceptable += 'r'
2594 cwd = repo.getcwd()
2594 cwd = repo.getcwd()
2595 if not specs:
2595 if not specs:
2596 specs = ['.']
2596 specs = ['.']
2597
2597
2598 files, dirs = set(), set()
2598 files, dirs = set(), set()
2599 for spec in specs:
2599 for spec in specs:
2600 f, d = complete(spec, acceptable or 'nmar')
2600 f, d = complete(spec, acceptable or 'nmar')
2601 files.update(f)
2601 files.update(f)
2602 dirs.update(d)
2602 dirs.update(d)
2603 files.update(dirs)
2603 files.update(dirs)
2604 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2604 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2605 ui.write('\n')
2605 ui.write('\n')
2606
2606
2607 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2607 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2608 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2608 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2609 '''access the pushkey key/value protocol
2609 '''access the pushkey key/value protocol
2610
2610
2611 With two args, list the keys in the given namespace.
2611 With two args, list the keys in the given namespace.
2612
2612
2613 With five args, set a key to new if it currently is set to old.
2613 With five args, set a key to new if it currently is set to old.
2614 Reports success or failure.
2614 Reports success or failure.
2615 '''
2615 '''
2616
2616
2617 target = hg.peer(ui, {}, repopath)
2617 target = hg.peer(ui, {}, repopath)
2618 if keyinfo:
2618 if keyinfo:
2619 key, old, new = keyinfo
2619 key, old, new = keyinfo
2620 r = target.pushkey(namespace, key, old, new)
2620 r = target.pushkey(namespace, key, old, new)
2621 ui.status(str(r) + '\n')
2621 ui.status(str(r) + '\n')
2622 return not r
2622 return not r
2623 else:
2623 else:
2624 for k, v in sorted(target.listkeys(namespace).iteritems()):
2624 for k, v in sorted(target.listkeys(namespace).iteritems()):
2625 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2625 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2626 v.encode('string-escape')))
2626 v.encode('string-escape')))
2627
2627
2628 @command('debugpvec', [], _('A B'))
2628 @command('debugpvec', [], _('A B'))
2629 def debugpvec(ui, repo, a, b=None):
2629 def debugpvec(ui, repo, a, b=None):
2630 ca = scmutil.revsingle(repo, a)
2630 ca = scmutil.revsingle(repo, a)
2631 cb = scmutil.revsingle(repo, b)
2631 cb = scmutil.revsingle(repo, b)
2632 pa = pvec.ctxpvec(ca)
2632 pa = pvec.ctxpvec(ca)
2633 pb = pvec.ctxpvec(cb)
2633 pb = pvec.ctxpvec(cb)
2634 if pa == pb:
2634 if pa == pb:
2635 rel = "="
2635 rel = "="
2636 elif pa > pb:
2636 elif pa > pb:
2637 rel = ">"
2637 rel = ">"
2638 elif pa < pb:
2638 elif pa < pb:
2639 rel = "<"
2639 rel = "<"
2640 elif pa | pb:
2640 elif pa | pb:
2641 rel = "|"
2641 rel = "|"
2642 ui.write(_("a: %s\n") % pa)
2642 ui.write(_("a: %s\n") % pa)
2643 ui.write(_("b: %s\n") % pb)
2643 ui.write(_("b: %s\n") % pb)
2644 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2644 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2645 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2645 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2646 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2646 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2647 pa.distance(pb), rel))
2647 pa.distance(pb), rel))
2648
2648
2649 @command('debugrebuilddirstate|debugrebuildstate',
2649 @command('debugrebuilddirstate|debugrebuildstate',
2650 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2650 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2651 _('[-r REV]'))
2651 _('[-r REV]'))
2652 def debugrebuilddirstate(ui, repo, rev):
2652 def debugrebuilddirstate(ui, repo, rev):
2653 """rebuild the dirstate as it would look like for the given revision
2653 """rebuild the dirstate as it would look like for the given revision
2654
2654
2655 If no revision is specified the first current parent will be used.
2655 If no revision is specified the first current parent will be used.
2656
2656
2657 The dirstate will be set to the files of the given revision.
2657 The dirstate will be set to the files of the given revision.
2658 The actual working directory content or existing dirstate
2658 The actual working directory content or existing dirstate
2659 information such as adds or removes is not considered.
2659 information such as adds or removes is not considered.
2660
2660
2661 One use of this command is to make the next :hg:`status` invocation
2661 One use of this command is to make the next :hg:`status` invocation
2662 check the actual file content.
2662 check the actual file content.
2663 """
2663 """
2664 ctx = scmutil.revsingle(repo, rev)
2664 ctx = scmutil.revsingle(repo, rev)
2665 wlock = repo.wlock()
2665 wlock = repo.wlock()
2666 try:
2666 try:
2667 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2667 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2668 finally:
2668 finally:
2669 wlock.release()
2669 wlock.release()
2670
2670
2671 @command('debugrename',
2671 @command('debugrename',
2672 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2672 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2673 _('[-r REV] FILE'))
2673 _('[-r REV] FILE'))
2674 def debugrename(ui, repo, file1, *pats, **opts):
2674 def debugrename(ui, repo, file1, *pats, **opts):
2675 """dump rename information"""
2675 """dump rename information"""
2676
2676
2677 ctx = scmutil.revsingle(repo, opts.get('rev'))
2677 ctx = scmutil.revsingle(repo, opts.get('rev'))
2678 m = scmutil.match(ctx, (file1,) + pats, opts)
2678 m = scmutil.match(ctx, (file1,) + pats, opts)
2679 for abs in ctx.walk(m):
2679 for abs in ctx.walk(m):
2680 fctx = ctx[abs]
2680 fctx = ctx[abs]
2681 o = fctx.filelog().renamed(fctx.filenode())
2681 o = fctx.filelog().renamed(fctx.filenode())
2682 rel = m.rel(abs)
2682 rel = m.rel(abs)
2683 if o:
2683 if o:
2684 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2684 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2685 else:
2685 else:
2686 ui.write(_("%s not renamed\n") % rel)
2686 ui.write(_("%s not renamed\n") % rel)
2687
2687
2688 @command('debugrevlog',
2688 @command('debugrevlog',
2689 [('c', 'changelog', False, _('open changelog')),
2689 [('c', 'changelog', False, _('open changelog')),
2690 ('m', 'manifest', False, _('open manifest')),
2690 ('m', 'manifest', False, _('open manifest')),
2691 ('d', 'dump', False, _('dump index data'))],
2691 ('d', 'dump', False, _('dump index data'))],
2692 _('-c|-m|FILE'),
2692 _('-c|-m|FILE'),
2693 optionalrepo=True)
2693 optionalrepo=True)
2694 def debugrevlog(ui, repo, file_=None, **opts):
2694 def debugrevlog(ui, repo, file_=None, **opts):
2695 """show data and statistics about a revlog"""
2695 """show data and statistics about a revlog"""
2696 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2696 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2697
2697
2698 if opts.get("dump"):
2698 if opts.get("dump"):
2699 numrevs = len(r)
2699 numrevs = len(r)
2700 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2700 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2701 " rawsize totalsize compression heads chainlen\n")
2701 " rawsize totalsize compression heads chainlen\n")
2702 ts = 0
2702 ts = 0
2703 heads = set()
2703 heads = set()
2704
2704
2705 for rev in xrange(numrevs):
2705 for rev in xrange(numrevs):
2706 dbase = r.deltaparent(rev)
2706 dbase = r.deltaparent(rev)
2707 if dbase == -1:
2707 if dbase == -1:
2708 dbase = rev
2708 dbase = rev
2709 cbase = r.chainbase(rev)
2709 cbase = r.chainbase(rev)
2710 clen = r.chainlen(rev)
2710 clen = r.chainlen(rev)
2711 p1, p2 = r.parentrevs(rev)
2711 p1, p2 = r.parentrevs(rev)
2712 rs = r.rawsize(rev)
2712 rs = r.rawsize(rev)
2713 ts = ts + rs
2713 ts = ts + rs
2714 heads -= set(r.parentrevs(rev))
2714 heads -= set(r.parentrevs(rev))
2715 heads.add(rev)
2715 heads.add(rev)
2716 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2716 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2717 "%11d %5d %8d\n" %
2717 "%11d %5d %8d\n" %
2718 (rev, p1, p2, r.start(rev), r.end(rev),
2718 (rev, p1, p2, r.start(rev), r.end(rev),
2719 r.start(dbase), r.start(cbase),
2719 r.start(dbase), r.start(cbase),
2720 r.start(p1), r.start(p2),
2720 r.start(p1), r.start(p2),
2721 rs, ts, ts / r.end(rev), len(heads), clen))
2721 rs, ts, ts / r.end(rev), len(heads), clen))
2722 return 0
2722 return 0
2723
2723
2724 v = r.version
2724 v = r.version
2725 format = v & 0xFFFF
2725 format = v & 0xFFFF
2726 flags = []
2726 flags = []
2727 gdelta = False
2727 gdelta = False
2728 if v & revlog.REVLOGNGINLINEDATA:
2728 if v & revlog.REVLOGNGINLINEDATA:
2729 flags.append('inline')
2729 flags.append('inline')
2730 if v & revlog.REVLOGGENERALDELTA:
2730 if v & revlog.REVLOGGENERALDELTA:
2731 gdelta = True
2731 gdelta = True
2732 flags.append('generaldelta')
2732 flags.append('generaldelta')
2733 if not flags:
2733 if not flags:
2734 flags = ['(none)']
2734 flags = ['(none)']
2735
2735
2736 nummerges = 0
2736 nummerges = 0
2737 numfull = 0
2737 numfull = 0
2738 numprev = 0
2738 numprev = 0
2739 nump1 = 0
2739 nump1 = 0
2740 nump2 = 0
2740 nump2 = 0
2741 numother = 0
2741 numother = 0
2742 nump1prev = 0
2742 nump1prev = 0
2743 nump2prev = 0
2743 nump2prev = 0
2744 chainlengths = []
2744 chainlengths = []
2745
2745
2746 datasize = [None, 0, 0L]
2746 datasize = [None, 0, 0L]
2747 fullsize = [None, 0, 0L]
2747 fullsize = [None, 0, 0L]
2748 deltasize = [None, 0, 0L]
2748 deltasize = [None, 0, 0L]
2749
2749
2750 def addsize(size, l):
2750 def addsize(size, l):
2751 if l[0] is None or size < l[0]:
2751 if l[0] is None or size < l[0]:
2752 l[0] = size
2752 l[0] = size
2753 if size > l[1]:
2753 if size > l[1]:
2754 l[1] = size
2754 l[1] = size
2755 l[2] += size
2755 l[2] += size
2756
2756
2757 numrevs = len(r)
2757 numrevs = len(r)
2758 for rev in xrange(numrevs):
2758 for rev in xrange(numrevs):
2759 p1, p2 = r.parentrevs(rev)
2759 p1, p2 = r.parentrevs(rev)
2760 delta = r.deltaparent(rev)
2760 delta = r.deltaparent(rev)
2761 if format > 0:
2761 if format > 0:
2762 addsize(r.rawsize(rev), datasize)
2762 addsize(r.rawsize(rev), datasize)
2763 if p2 != nullrev:
2763 if p2 != nullrev:
2764 nummerges += 1
2764 nummerges += 1
2765 size = r.length(rev)
2765 size = r.length(rev)
2766 if delta == nullrev:
2766 if delta == nullrev:
2767 chainlengths.append(0)
2767 chainlengths.append(0)
2768 numfull += 1
2768 numfull += 1
2769 addsize(size, fullsize)
2769 addsize(size, fullsize)
2770 else:
2770 else:
2771 chainlengths.append(chainlengths[delta] + 1)
2771 chainlengths.append(chainlengths[delta] + 1)
2772 addsize(size, deltasize)
2772 addsize(size, deltasize)
2773 if delta == rev - 1:
2773 if delta == rev - 1:
2774 numprev += 1
2774 numprev += 1
2775 if delta == p1:
2775 if delta == p1:
2776 nump1prev += 1
2776 nump1prev += 1
2777 elif delta == p2:
2777 elif delta == p2:
2778 nump2prev += 1
2778 nump2prev += 1
2779 elif delta == p1:
2779 elif delta == p1:
2780 nump1 += 1
2780 nump1 += 1
2781 elif delta == p2:
2781 elif delta == p2:
2782 nump2 += 1
2782 nump2 += 1
2783 elif delta != nullrev:
2783 elif delta != nullrev:
2784 numother += 1
2784 numother += 1
2785
2785
2786 # Adjust size min value for empty cases
2786 # Adjust size min value for empty cases
2787 for size in (datasize, fullsize, deltasize):
2787 for size in (datasize, fullsize, deltasize):
2788 if size[0] is None:
2788 if size[0] is None:
2789 size[0] = 0
2789 size[0] = 0
2790
2790
2791 numdeltas = numrevs - numfull
2791 numdeltas = numrevs - numfull
2792 numoprev = numprev - nump1prev - nump2prev
2792 numoprev = numprev - nump1prev - nump2prev
2793 totalrawsize = datasize[2]
2793 totalrawsize = datasize[2]
2794 datasize[2] /= numrevs
2794 datasize[2] /= numrevs
2795 fulltotal = fullsize[2]
2795 fulltotal = fullsize[2]
2796 fullsize[2] /= numfull
2796 fullsize[2] /= numfull
2797 deltatotal = deltasize[2]
2797 deltatotal = deltasize[2]
2798 if numrevs - numfull > 0:
2798 if numrevs - numfull > 0:
2799 deltasize[2] /= numrevs - numfull
2799 deltasize[2] /= numrevs - numfull
2800 totalsize = fulltotal + deltatotal
2800 totalsize = fulltotal + deltatotal
2801 avgchainlen = sum(chainlengths) / numrevs
2801 avgchainlen = sum(chainlengths) / numrevs
2802 compratio = totalrawsize / totalsize
2802 compratio = totalrawsize / totalsize
2803
2803
2804 basedfmtstr = '%%%dd\n'
2804 basedfmtstr = '%%%dd\n'
2805 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2805 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2806
2806
2807 def dfmtstr(max):
2807 def dfmtstr(max):
2808 return basedfmtstr % len(str(max))
2808 return basedfmtstr % len(str(max))
2809 def pcfmtstr(max, padding=0):
2809 def pcfmtstr(max, padding=0):
2810 return basepcfmtstr % (len(str(max)), ' ' * padding)
2810 return basepcfmtstr % (len(str(max)), ' ' * padding)
2811
2811
2812 def pcfmt(value, total):
2812 def pcfmt(value, total):
2813 return (value, 100 * float(value) / total)
2813 return (value, 100 * float(value) / total)
2814
2814
2815 ui.write(('format : %d\n') % format)
2815 ui.write(('format : %d\n') % format)
2816 ui.write(('flags : %s\n') % ', '.join(flags))
2816 ui.write(('flags : %s\n') % ', '.join(flags))
2817
2817
2818 ui.write('\n')
2818 ui.write('\n')
2819 fmt = pcfmtstr(totalsize)
2819 fmt = pcfmtstr(totalsize)
2820 fmt2 = dfmtstr(totalsize)
2820 fmt2 = dfmtstr(totalsize)
2821 ui.write(('revisions : ') + fmt2 % numrevs)
2821 ui.write(('revisions : ') + fmt2 % numrevs)
2822 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2822 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2823 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2823 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2824 ui.write(('revisions : ') + fmt2 % numrevs)
2824 ui.write(('revisions : ') + fmt2 % numrevs)
2825 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2825 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2826 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2826 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2827 ui.write(('revision size : ') + fmt2 % totalsize)
2827 ui.write(('revision size : ') + fmt2 % totalsize)
2828 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2828 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2829 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2829 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2830
2830
2831 ui.write('\n')
2831 ui.write('\n')
2832 fmt = dfmtstr(max(avgchainlen, compratio))
2832 fmt = dfmtstr(max(avgchainlen, compratio))
2833 ui.write(('avg chain length : ') + fmt % avgchainlen)
2833 ui.write(('avg chain length : ') + fmt % avgchainlen)
2834 ui.write(('compression ratio : ') + fmt % compratio)
2834 ui.write(('compression ratio : ') + fmt % compratio)
2835
2835
2836 if format > 0:
2836 if format > 0:
2837 ui.write('\n')
2837 ui.write('\n')
2838 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2838 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2839 % tuple(datasize))
2839 % tuple(datasize))
2840 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2840 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2841 % tuple(fullsize))
2841 % tuple(fullsize))
2842 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2842 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2843 % tuple(deltasize))
2843 % tuple(deltasize))
2844
2844
2845 if numdeltas > 0:
2845 if numdeltas > 0:
2846 ui.write('\n')
2846 ui.write('\n')
2847 fmt = pcfmtstr(numdeltas)
2847 fmt = pcfmtstr(numdeltas)
2848 fmt2 = pcfmtstr(numdeltas, 4)
2848 fmt2 = pcfmtstr(numdeltas, 4)
2849 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2849 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2850 if numprev > 0:
2850 if numprev > 0:
2851 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2851 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2852 numprev))
2852 numprev))
2853 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2853 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2854 numprev))
2854 numprev))
2855 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2855 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2856 numprev))
2856 numprev))
2857 if gdelta:
2857 if gdelta:
2858 ui.write(('deltas against p1 : ')
2858 ui.write(('deltas against p1 : ')
2859 + fmt % pcfmt(nump1, numdeltas))
2859 + fmt % pcfmt(nump1, numdeltas))
2860 ui.write(('deltas against p2 : ')
2860 ui.write(('deltas against p2 : ')
2861 + fmt % pcfmt(nump2, numdeltas))
2861 + fmt % pcfmt(nump2, numdeltas))
2862 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2862 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2863 numdeltas))
2863 numdeltas))
2864
2864
2865 @command('debugrevspec',
2865 @command('debugrevspec',
2866 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2866 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2867 ('REVSPEC'))
2867 ('REVSPEC'))
2868 def debugrevspec(ui, repo, expr, **opts):
2868 def debugrevspec(ui, repo, expr, **opts):
2869 """parse and apply a revision specification
2869 """parse and apply a revision specification
2870
2870
2871 Use --verbose to print the parsed tree before and after aliases
2871 Use --verbose to print the parsed tree before and after aliases
2872 expansion.
2872 expansion.
2873 """
2873 """
2874 if ui.verbose:
2874 if ui.verbose:
2875 tree = revset.parse(expr)[0]
2875 tree = revset.parse(expr)[0]
2876 ui.note(revset.prettyformat(tree), "\n")
2876 ui.note(revset.prettyformat(tree), "\n")
2877 newtree = revset.findaliases(ui, tree)
2877 newtree = revset.findaliases(ui, tree)
2878 if newtree != tree:
2878 if newtree != tree:
2879 ui.note(revset.prettyformat(newtree), "\n")
2879 ui.note(revset.prettyformat(newtree), "\n")
2880 tree = newtree
2880 tree = newtree
2881 newtree = revset.foldconcat(tree)
2881 newtree = revset.foldconcat(tree)
2882 if newtree != tree:
2882 if newtree != tree:
2883 ui.note(revset.prettyformat(newtree), "\n")
2883 ui.note(revset.prettyformat(newtree), "\n")
2884 if opts["optimize"]:
2884 if opts["optimize"]:
2885 weight, optimizedtree = revset.optimize(newtree, True)
2885 weight, optimizedtree = revset.optimize(newtree, True)
2886 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2886 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2887 func = revset.match(ui, expr)
2887 func = revset.match(ui, expr)
2888 for c in func(repo):
2888 for c in func(repo):
2889 ui.write("%s\n" % c)
2889 ui.write("%s\n" % c)
2890
2890
2891 @command('debugsetparents', [], _('REV1 [REV2]'))
2891 @command('debugsetparents', [], _('REV1 [REV2]'))
2892 def debugsetparents(ui, repo, rev1, rev2=None):
2892 def debugsetparents(ui, repo, rev1, rev2=None):
2893 """manually set the parents of the current working directory
2893 """manually set the parents of the current working directory
2894
2894
2895 This is useful for writing repository conversion tools, but should
2895 This is useful for writing repository conversion tools, but should
2896 be used with care. For example, neither the working copy nor the dirstate
2896 be used with care. For example, neither the working copy nor the dirstate
2897 is updated, so file status may be incorrect after running this command.
2897 is updated, so file status may be incorrect after running this command.
2898
2898
2899 Returns 0 on success.
2899 Returns 0 on success.
2900 """
2900 """
2901
2901
2902 r1 = scmutil.revsingle(repo, rev1).node()
2902 r1 = scmutil.revsingle(repo, rev1).node()
2903 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2903 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2904
2904
2905 wlock = repo.wlock()
2905 wlock = repo.wlock()
2906 try:
2906 try:
2907 repo.dirstate.beginparentchange()
2907 repo.dirstate.beginparentchange()
2908 repo.setparents(r1, r2)
2908 repo.setparents(r1, r2)
2909 repo.dirstate.endparentchange()
2909 repo.dirstate.endparentchange()
2910 finally:
2910 finally:
2911 wlock.release()
2911 wlock.release()
2912
2912
2913 @command('debugdirstate|debugstate',
2913 @command('debugdirstate|debugstate',
2914 [('', 'nodates', None, _('do not display the saved mtime')),
2914 [('', 'nodates', None, _('do not display the saved mtime')),
2915 ('', 'datesort', None, _('sort by saved mtime'))],
2915 ('', 'datesort', None, _('sort by saved mtime'))],
2916 _('[OPTION]...'))
2916 _('[OPTION]...'))
2917 def debugstate(ui, repo, nodates=None, datesort=None):
2917 def debugstate(ui, repo, nodates=None, datesort=None):
2918 """show the contents of the current dirstate"""
2918 """show the contents of the current dirstate"""
2919 timestr = ""
2919 timestr = ""
2920 if datesort:
2920 if datesort:
2921 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2921 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2922 else:
2922 else:
2923 keyfunc = None # sort by filename
2923 keyfunc = None # sort by filename
2924 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2924 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2925 if ent[3] == -1:
2925 if ent[3] == -1:
2926 timestr = 'unset '
2926 timestr = 'unset '
2927 elif nodates:
2927 elif nodates:
2928 timestr = 'set '
2928 timestr = 'set '
2929 else:
2929 else:
2930 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2930 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2931 time.localtime(ent[3]))
2931 time.localtime(ent[3]))
2932 if ent[1] & 020000:
2932 if ent[1] & 020000:
2933 mode = 'lnk'
2933 mode = 'lnk'
2934 else:
2934 else:
2935 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2935 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2936 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2936 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2937 for f in repo.dirstate.copies():
2937 for f in repo.dirstate.copies():
2938 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2938 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2939
2939
2940 @command('debugsub',
2940 @command('debugsub',
2941 [('r', 'rev', '',
2941 [('r', 'rev', '',
2942 _('revision to check'), _('REV'))],
2942 _('revision to check'), _('REV'))],
2943 _('[-r REV] [REV]'))
2943 _('[-r REV] [REV]'))
2944 def debugsub(ui, repo, rev=None):
2944 def debugsub(ui, repo, rev=None):
2945 ctx = scmutil.revsingle(repo, rev, None)
2945 ctx = scmutil.revsingle(repo, rev, None)
2946 for k, v in sorted(ctx.substate.items()):
2946 for k, v in sorted(ctx.substate.items()):
2947 ui.write(('path %s\n') % k)
2947 ui.write(('path %s\n') % k)
2948 ui.write((' source %s\n') % v[0])
2948 ui.write((' source %s\n') % v[0])
2949 ui.write((' revision %s\n') % v[1])
2949 ui.write((' revision %s\n') % v[1])
2950
2950
2951 @command('debugsuccessorssets',
2951 @command('debugsuccessorssets',
2952 [],
2952 [],
2953 _('[REV]'))
2953 _('[REV]'))
2954 def debugsuccessorssets(ui, repo, *revs):
2954 def debugsuccessorssets(ui, repo, *revs):
2955 """show set of successors for revision
2955 """show set of successors for revision
2956
2956
2957 A successors set of changeset A is a consistent group of revisions that
2957 A successors set of changeset A is a consistent group of revisions that
2958 succeed A. It contains non-obsolete changesets only.
2958 succeed A. It contains non-obsolete changesets only.
2959
2959
2960 In most cases a changeset A has a single successors set containing a single
2960 In most cases a changeset A has a single successors set containing a single
2961 successor (changeset A replaced by A').
2961 successor (changeset A replaced by A').
2962
2962
2963 A changeset that is made obsolete with no successors are called "pruned".
2963 A changeset that is made obsolete with no successors are called "pruned".
2964 Such changesets have no successors sets at all.
2964 Such changesets have no successors sets at all.
2965
2965
2966 A changeset that has been "split" will have a successors set containing
2966 A changeset that has been "split" will have a successors set containing
2967 more than one successor.
2967 more than one successor.
2968
2968
2969 A changeset that has been rewritten in multiple different ways is called
2969 A changeset that has been rewritten in multiple different ways is called
2970 "divergent". Such changesets have multiple successor sets (each of which
2970 "divergent". Such changesets have multiple successor sets (each of which
2971 may also be split, i.e. have multiple successors).
2971 may also be split, i.e. have multiple successors).
2972
2972
2973 Results are displayed as follows::
2973 Results are displayed as follows::
2974
2974
2975 <rev1>
2975 <rev1>
2976 <successors-1A>
2976 <successors-1A>
2977 <rev2>
2977 <rev2>
2978 <successors-2A>
2978 <successors-2A>
2979 <successors-2B1> <successors-2B2> <successors-2B3>
2979 <successors-2B1> <successors-2B2> <successors-2B3>
2980
2980
2981 Here rev2 has two possible (i.e. divergent) successors sets. The first
2981 Here rev2 has two possible (i.e. divergent) successors sets. The first
2982 holds one element, whereas the second holds three (i.e. the changeset has
2982 holds one element, whereas the second holds three (i.e. the changeset has
2983 been split).
2983 been split).
2984 """
2984 """
2985 # passed to successorssets caching computation from one call to another
2985 # passed to successorssets caching computation from one call to another
2986 cache = {}
2986 cache = {}
2987 ctx2str = str
2987 ctx2str = str
2988 node2str = short
2988 node2str = short
2989 if ui.debug():
2989 if ui.debug():
2990 def ctx2str(ctx):
2990 def ctx2str(ctx):
2991 return ctx.hex()
2991 return ctx.hex()
2992 node2str = hex
2992 node2str = hex
2993 for rev in scmutil.revrange(repo, revs):
2993 for rev in scmutil.revrange(repo, revs):
2994 ctx = repo[rev]
2994 ctx = repo[rev]
2995 ui.write('%s\n'% ctx2str(ctx))
2995 ui.write('%s\n'% ctx2str(ctx))
2996 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2996 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2997 if succsset:
2997 if succsset:
2998 ui.write(' ')
2998 ui.write(' ')
2999 ui.write(node2str(succsset[0]))
2999 ui.write(node2str(succsset[0]))
3000 for node in succsset[1:]:
3000 for node in succsset[1:]:
3001 ui.write(' ')
3001 ui.write(' ')
3002 ui.write(node2str(node))
3002 ui.write(node2str(node))
3003 ui.write('\n')
3003 ui.write('\n')
3004
3004
3005 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3005 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3006 def debugwalk(ui, repo, *pats, **opts):
3006 def debugwalk(ui, repo, *pats, **opts):
3007 """show how files match on given patterns"""
3007 """show how files match on given patterns"""
3008 m = scmutil.match(repo[None], pats, opts)
3008 m = scmutil.match(repo[None], pats, opts)
3009 items = list(repo.walk(m))
3009 items = list(repo.walk(m))
3010 if not items:
3010 if not items:
3011 return
3011 return
3012 f = lambda fn: fn
3012 f = lambda fn: fn
3013 if ui.configbool('ui', 'slash') and os.sep != '/':
3013 if ui.configbool('ui', 'slash') and os.sep != '/':
3014 f = lambda fn: util.normpath(fn)
3014 f = lambda fn: util.normpath(fn)
3015 fmt = 'f %%-%ds %%-%ds %%s' % (
3015 fmt = 'f %%-%ds %%-%ds %%s' % (
3016 max([len(abs) for abs in items]),
3016 max([len(abs) for abs in items]),
3017 max([len(m.rel(abs)) for abs in items]))
3017 max([len(m.rel(abs)) for abs in items]))
3018 for abs in items:
3018 for abs in items:
3019 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3019 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3020 ui.write("%s\n" % line.rstrip())
3020 ui.write("%s\n" % line.rstrip())
3021
3021
3022 @command('debugwireargs',
3022 @command('debugwireargs',
3023 [('', 'three', '', 'three'),
3023 [('', 'three', '', 'three'),
3024 ('', 'four', '', 'four'),
3024 ('', 'four', '', 'four'),
3025 ('', 'five', '', 'five'),
3025 ('', 'five', '', 'five'),
3026 ] + remoteopts,
3026 ] + remoteopts,
3027 _('REPO [OPTIONS]... [ONE [TWO]]'),
3027 _('REPO [OPTIONS]... [ONE [TWO]]'),
3028 norepo=True)
3028 norepo=True)
3029 def debugwireargs(ui, repopath, *vals, **opts):
3029 def debugwireargs(ui, repopath, *vals, **opts):
3030 repo = hg.peer(ui, opts, repopath)
3030 repo = hg.peer(ui, opts, repopath)
3031 for opt in remoteopts:
3031 for opt in remoteopts:
3032 del opts[opt[1]]
3032 del opts[opt[1]]
3033 args = {}
3033 args = {}
3034 for k, v in opts.iteritems():
3034 for k, v in opts.iteritems():
3035 if v:
3035 if v:
3036 args[k] = v
3036 args[k] = v
3037 # run twice to check that we don't mess up the stream for the next command
3037 # run twice to check that we don't mess up the stream for the next command
3038 res1 = repo.debugwireargs(*vals, **args)
3038 res1 = repo.debugwireargs(*vals, **args)
3039 res2 = repo.debugwireargs(*vals, **args)
3039 res2 = repo.debugwireargs(*vals, **args)
3040 ui.write("%s\n" % res1)
3040 ui.write("%s\n" % res1)
3041 if res1 != res2:
3041 if res1 != res2:
3042 ui.warn("%s\n" % res2)
3042 ui.warn("%s\n" % res2)
3043
3043
3044 @command('^diff',
3044 @command('^diff',
3045 [('r', 'rev', [], _('revision'), _('REV')),
3045 [('r', 'rev', [], _('revision'), _('REV')),
3046 ('c', 'change', '', _('change made by revision'), _('REV'))
3046 ('c', 'change', '', _('change made by revision'), _('REV'))
3047 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3047 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3048 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3048 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3049 inferrepo=True)
3049 inferrepo=True)
3050 def diff(ui, repo, *pats, **opts):
3050 def diff(ui, repo, *pats, **opts):
3051 """diff repository (or selected files)
3051 """diff repository (or selected files)
3052
3052
3053 Show differences between revisions for the specified files.
3053 Show differences between revisions for the specified files.
3054
3054
3055 Differences between files are shown using the unified diff format.
3055 Differences between files are shown using the unified diff format.
3056
3056
3057 .. note::
3057 .. note::
3058
3058
3059 diff may generate unexpected results for merges, as it will
3059 diff may generate unexpected results for merges, as it will
3060 default to comparing against the working directory's first
3060 default to comparing against the working directory's first
3061 parent changeset if no revisions are specified.
3061 parent changeset if no revisions are specified.
3062
3062
3063 When two revision arguments are given, then changes are shown
3063 When two revision arguments are given, then changes are shown
3064 between those revisions. If only one revision is specified then
3064 between those revisions. If only one revision is specified then
3065 that revision is compared to the working directory, and, when no
3065 that revision is compared to the working directory, and, when no
3066 revisions are specified, the working directory files are compared
3066 revisions are specified, the working directory files are compared
3067 to its parent.
3067 to its parent.
3068
3068
3069 Alternatively you can specify -c/--change with a revision to see
3069 Alternatively you can specify -c/--change with a revision to see
3070 the changes in that changeset relative to its first parent.
3070 the changes in that changeset relative to its first parent.
3071
3071
3072 Without the -a/--text option, diff will avoid generating diffs of
3072 Without the -a/--text option, diff will avoid generating diffs of
3073 files it detects as binary. With -a, diff will generate a diff
3073 files it detects as binary. With -a, diff will generate a diff
3074 anyway, probably with undesirable results.
3074 anyway, probably with undesirable results.
3075
3075
3076 Use the -g/--git option to generate diffs in the git extended diff
3076 Use the -g/--git option to generate diffs in the git extended diff
3077 format. For more information, read :hg:`help diffs`.
3077 format. For more information, read :hg:`help diffs`.
3078
3078
3079 .. container:: verbose
3079 .. container:: verbose
3080
3080
3081 Examples:
3081 Examples:
3082
3082
3083 - compare a file in the current working directory to its parent::
3083 - compare a file in the current working directory to its parent::
3084
3084
3085 hg diff foo.c
3085 hg diff foo.c
3086
3086
3087 - compare two historical versions of a directory, with rename info::
3087 - compare two historical versions of a directory, with rename info::
3088
3088
3089 hg diff --git -r 1.0:1.2 lib/
3089 hg diff --git -r 1.0:1.2 lib/
3090
3090
3091 - get change stats relative to the last change on some date::
3091 - get change stats relative to the last change on some date::
3092
3092
3093 hg diff --stat -r "date('may 2')"
3093 hg diff --stat -r "date('may 2')"
3094
3094
3095 - diff all newly-added files that contain a keyword::
3095 - diff all newly-added files that contain a keyword::
3096
3096
3097 hg diff "set:added() and grep(GNU)"
3097 hg diff "set:added() and grep(GNU)"
3098
3098
3099 - compare a revision and its parents::
3099 - compare a revision and its parents::
3100
3100
3101 hg diff -c 9353 # compare against first parent
3101 hg diff -c 9353 # compare against first parent
3102 hg diff -r 9353^:9353 # same using revset syntax
3102 hg diff -r 9353^:9353 # same using revset syntax
3103 hg diff -r 9353^2:9353 # compare against the second parent
3103 hg diff -r 9353^2:9353 # compare against the second parent
3104
3104
3105 Returns 0 on success.
3105 Returns 0 on success.
3106 """
3106 """
3107
3107
3108 revs = opts.get('rev')
3108 revs = opts.get('rev')
3109 change = opts.get('change')
3109 change = opts.get('change')
3110 stat = opts.get('stat')
3110 stat = opts.get('stat')
3111 reverse = opts.get('reverse')
3111 reverse = opts.get('reverse')
3112
3112
3113 if revs and change:
3113 if revs and change:
3114 msg = _('cannot specify --rev and --change at the same time')
3114 msg = _('cannot specify --rev and --change at the same time')
3115 raise util.Abort(msg)
3115 raise util.Abort(msg)
3116 elif change:
3116 elif change:
3117 node2 = scmutil.revsingle(repo, change, None).node()
3117 node2 = scmutil.revsingle(repo, change, None).node()
3118 node1 = repo[node2].p1().node()
3118 node1 = repo[node2].p1().node()
3119 else:
3119 else:
3120 node1, node2 = scmutil.revpair(repo, revs)
3120 node1, node2 = scmutil.revpair(repo, revs)
3121
3121
3122 if reverse:
3122 if reverse:
3123 node1, node2 = node2, node1
3123 node1, node2 = node2, node1
3124
3124
3125 diffopts = patch.diffallopts(ui, opts)
3125 diffopts = patch.diffallopts(ui, opts)
3126 m = scmutil.match(repo[node2], pats, opts)
3126 m = scmutil.match(repo[node2], pats, opts)
3127 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3127 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3128 listsubrepos=opts.get('subrepos'))
3128 listsubrepos=opts.get('subrepos'))
3129
3129
3130 @command('^export',
3130 @command('^export',
3131 [('o', 'output', '',
3131 [('o', 'output', '',
3132 _('print output to file with formatted name'), _('FORMAT')),
3132 _('print output to file with formatted name'), _('FORMAT')),
3133 ('', 'switch-parent', None, _('diff against the second parent')),
3133 ('', 'switch-parent', None, _('diff against the second parent')),
3134 ('r', 'rev', [], _('revisions to export'), _('REV')),
3134 ('r', 'rev', [], _('revisions to export'), _('REV')),
3135 ] + diffopts,
3135 ] + diffopts,
3136 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3136 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3137 def export(ui, repo, *changesets, **opts):
3137 def export(ui, repo, *changesets, **opts):
3138 """dump the header and diffs for one or more changesets
3138 """dump the header and diffs for one or more changesets
3139
3139
3140 Print the changeset header and diffs for one or more revisions.
3140 Print the changeset header and diffs for one or more revisions.
3141 If no revision is given, the parent of the working directory is used.
3141 If no revision is given, the parent of the working directory is used.
3142
3142
3143 The information shown in the changeset header is: author, date,
3143 The information shown in the changeset header is: author, date,
3144 branch name (if non-default), changeset hash, parent(s) and commit
3144 branch name (if non-default), changeset hash, parent(s) and commit
3145 comment.
3145 comment.
3146
3146
3147 .. note::
3147 .. note::
3148
3148
3149 export may generate unexpected diff output for merge
3149 export may generate unexpected diff output for merge
3150 changesets, as it will compare the merge changeset against its
3150 changesets, as it will compare the merge changeset against its
3151 first parent only.
3151 first parent only.
3152
3152
3153 Output may be to a file, in which case the name of the file is
3153 Output may be to a file, in which case the name of the file is
3154 given using a format string. The formatting rules are as follows:
3154 given using a format string. The formatting rules are as follows:
3155
3155
3156 :``%%``: literal "%" character
3156 :``%%``: literal "%" character
3157 :``%H``: changeset hash (40 hexadecimal digits)
3157 :``%H``: changeset hash (40 hexadecimal digits)
3158 :``%N``: number of patches being generated
3158 :``%N``: number of patches being generated
3159 :``%R``: changeset revision number
3159 :``%R``: changeset revision number
3160 :``%b``: basename of the exporting repository
3160 :``%b``: basename of the exporting repository
3161 :``%h``: short-form changeset hash (12 hexadecimal digits)
3161 :``%h``: short-form changeset hash (12 hexadecimal digits)
3162 :``%m``: first line of the commit message (only alphanumeric characters)
3162 :``%m``: first line of the commit message (only alphanumeric characters)
3163 :``%n``: zero-padded sequence number, starting at 1
3163 :``%n``: zero-padded sequence number, starting at 1
3164 :``%r``: zero-padded changeset revision number
3164 :``%r``: zero-padded changeset revision number
3165
3165
3166 Without the -a/--text option, export will avoid generating diffs
3166 Without the -a/--text option, export will avoid generating diffs
3167 of files it detects as binary. With -a, export will generate a
3167 of files it detects as binary. With -a, export will generate a
3168 diff anyway, probably with undesirable results.
3168 diff anyway, probably with undesirable results.
3169
3169
3170 Use the -g/--git option to generate diffs in the git extended diff
3170 Use the -g/--git option to generate diffs in the git extended diff
3171 format. See :hg:`help diffs` for more information.
3171 format. See :hg:`help diffs` for more information.
3172
3172
3173 With the --switch-parent option, the diff will be against the
3173 With the --switch-parent option, the diff will be against the
3174 second parent. It can be useful to review a merge.
3174 second parent. It can be useful to review a merge.
3175
3175
3176 .. container:: verbose
3176 .. container:: verbose
3177
3177
3178 Examples:
3178 Examples:
3179
3179
3180 - use export and import to transplant a bugfix to the current
3180 - use export and import to transplant a bugfix to the current
3181 branch::
3181 branch::
3182
3182
3183 hg export -r 9353 | hg import -
3183 hg export -r 9353 | hg import -
3184
3184
3185 - export all the changesets between two revisions to a file with
3185 - export all the changesets between two revisions to a file with
3186 rename information::
3186 rename information::
3187
3187
3188 hg export --git -r 123:150 > changes.txt
3188 hg export --git -r 123:150 > changes.txt
3189
3189
3190 - split outgoing changes into a series of patches with
3190 - split outgoing changes into a series of patches with
3191 descriptive names::
3191 descriptive names::
3192
3192
3193 hg export -r "outgoing()" -o "%n-%m.patch"
3193 hg export -r "outgoing()" -o "%n-%m.patch"
3194
3194
3195 Returns 0 on success.
3195 Returns 0 on success.
3196 """
3196 """
3197 changesets += tuple(opts.get('rev', []))
3197 changesets += tuple(opts.get('rev', []))
3198 if not changesets:
3198 if not changesets:
3199 changesets = ['.']
3199 changesets = ['.']
3200 revs = scmutil.revrange(repo, changesets)
3200 revs = scmutil.revrange(repo, changesets)
3201 if not revs:
3201 if not revs:
3202 raise util.Abort(_("export requires at least one changeset"))
3202 raise util.Abort(_("export requires at least one changeset"))
3203 if len(revs) > 1:
3203 if len(revs) > 1:
3204 ui.note(_('exporting patches:\n'))
3204 ui.note(_('exporting patches:\n'))
3205 else:
3205 else:
3206 ui.note(_('exporting patch:\n'))
3206 ui.note(_('exporting patch:\n'))
3207 cmdutil.export(repo, revs, template=opts.get('output'),
3207 cmdutil.export(repo, revs, template=opts.get('output'),
3208 switch_parent=opts.get('switch_parent'),
3208 switch_parent=opts.get('switch_parent'),
3209 opts=patch.diffallopts(ui, opts))
3209 opts=patch.diffallopts(ui, opts))
3210
3210
3211 @command('files',
3211 @command('files',
3212 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3212 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3213 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3213 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3214 ] + walkopts + formatteropts,
3214 ] + walkopts + formatteropts,
3215 _('[OPTION]... [PATTERN]...'))
3215 _('[OPTION]... [PATTERN]...'))
3216 def files(ui, repo, *pats, **opts):
3216 def files(ui, repo, *pats, **opts):
3217 """list tracked files
3217 """list tracked files
3218
3218
3219 Print files under Mercurial control in the working directory or
3219 Print files under Mercurial control in the working directory or
3220 specified revision whose names match the given patterns (excluding
3220 specified revision whose names match the given patterns (excluding
3221 removed files).
3221 removed files).
3222
3222
3223 If no patterns are given to match, this command prints the names
3223 If no patterns are given to match, this command prints the names
3224 of all files under Mercurial control in the working copy.
3224 of all files under Mercurial control in the working copy.
3225
3225
3226 .. container:: verbose
3226 .. container:: verbose
3227
3227
3228 Examples:
3228 Examples:
3229
3229
3230 - list all files under the current directory::
3230 - list all files under the current directory::
3231
3231
3232 hg files .
3232 hg files .
3233
3233
3234 - shows sizes and flags for current revision::
3234 - shows sizes and flags for current revision::
3235
3235
3236 hg files -vr .
3236 hg files -vr .
3237
3237
3238 - list all files named README::
3238 - list all files named README::
3239
3239
3240 hg files -I "**/README"
3240 hg files -I "**/README"
3241
3241
3242 - list all binary files::
3242 - list all binary files::
3243
3243
3244 hg files "set:binary()"
3244 hg files "set:binary()"
3245
3245
3246 - find files containing a regular expression::
3246 - find files containing a regular expression::
3247
3247
3248 hg files "set:grep('bob')"
3248 hg files "set:grep('bob')"
3249
3249
3250 - search tracked file contents with xargs and grep::
3250 - search tracked file contents with xargs and grep::
3251
3251
3252 hg files -0 | xargs -0 grep foo
3252 hg files -0 | xargs -0 grep foo
3253
3253
3254 See :hg:`help patterns` and :hg:`help filesets` for more information
3254 See :hg:`help patterns` and :hg:`help filesets` for more information
3255 on specifying file patterns.
3255 on specifying file patterns.
3256
3256
3257 Returns 0 if a match is found, 1 otherwise.
3257 Returns 0 if a match is found, 1 otherwise.
3258
3258
3259 """
3259 """
3260 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3260 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3261 rev = ctx.rev()
3262 ret = 1
3263
3261
3264 end = '\n'
3262 end = '\n'
3265 if opts.get('print0'):
3263 if opts.get('print0'):
3266 end = '\0'
3264 end = '\0'
3267 fm = ui.formatter('files', opts)
3265 fm = ui.formatter('files', opts)
3268 fmt = '%s' + end
3266 fmt = '%s' + end
3269
3267
3270 m = scmutil.match(ctx, pats, opts)
3268 m = scmutil.match(ctx, pats, opts)
3271 ds = ctx._repo.dirstate
3269 ret = cmdutil.files(ui, ctx, m, fm, fmt)
3272 for f in ctx.matches(m):
3273 if rev is None and ds[f] == 'r':
3274 continue
3275 fm.startitem()
3276 if ui.verbose:
3277 fc = ctx[f]
3278 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
3279 fm.data(abspath=f)
3280 fm.write('path', fmt, m.rel(f))
3281 ret = 0
3282
3270
3283 fm.end()
3271 fm.end()
3284
3272
3285 return ret
3273 return ret
3286
3274
3287 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3275 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3288 def forget(ui, repo, *pats, **opts):
3276 def forget(ui, repo, *pats, **opts):
3289 """forget the specified files on the next commit
3277 """forget the specified files on the next commit
3290
3278
3291 Mark the specified files so they will no longer be tracked
3279 Mark the specified files so they will no longer be tracked
3292 after the next commit.
3280 after the next commit.
3293
3281
3294 This only removes files from the current branch, not from the
3282 This only removes files from the current branch, not from the
3295 entire project history, and it does not delete them from the
3283 entire project history, and it does not delete them from the
3296 working directory.
3284 working directory.
3297
3285
3298 To undo a forget before the next commit, see :hg:`add`.
3286 To undo a forget before the next commit, see :hg:`add`.
3299
3287
3300 .. container:: verbose
3288 .. container:: verbose
3301
3289
3302 Examples:
3290 Examples:
3303
3291
3304 - forget newly-added binary files::
3292 - forget newly-added binary files::
3305
3293
3306 hg forget "set:added() and binary()"
3294 hg forget "set:added() and binary()"
3307
3295
3308 - forget files that would be excluded by .hgignore::
3296 - forget files that would be excluded by .hgignore::
3309
3297
3310 hg forget "set:hgignore()"
3298 hg forget "set:hgignore()"
3311
3299
3312 Returns 0 on success.
3300 Returns 0 on success.
3313 """
3301 """
3314
3302
3315 if not pats:
3303 if not pats:
3316 raise util.Abort(_('no files specified'))
3304 raise util.Abort(_('no files specified'))
3317
3305
3318 m = scmutil.match(repo[None], pats, opts)
3306 m = scmutil.match(repo[None], pats, opts)
3319 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3307 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3320 return rejected and 1 or 0
3308 return rejected and 1 or 0
3321
3309
3322 @command(
3310 @command(
3323 'graft',
3311 'graft',
3324 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3312 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3325 ('c', 'continue', False, _('resume interrupted graft')),
3313 ('c', 'continue', False, _('resume interrupted graft')),
3326 ('e', 'edit', False, _('invoke editor on commit messages')),
3314 ('e', 'edit', False, _('invoke editor on commit messages')),
3327 ('', 'log', None, _('append graft info to log message')),
3315 ('', 'log', None, _('append graft info to log message')),
3328 ('f', 'force', False, _('force graft')),
3316 ('f', 'force', False, _('force graft')),
3329 ('D', 'currentdate', False,
3317 ('D', 'currentdate', False,
3330 _('record the current date as commit date')),
3318 _('record the current date as commit date')),
3331 ('U', 'currentuser', False,
3319 ('U', 'currentuser', False,
3332 _('record the current user as committer'), _('DATE'))]
3320 _('record the current user as committer'), _('DATE'))]
3333 + commitopts2 + mergetoolopts + dryrunopts,
3321 + commitopts2 + mergetoolopts + dryrunopts,
3334 _('[OPTION]... [-r] REV...'))
3322 _('[OPTION]... [-r] REV...'))
3335 def graft(ui, repo, *revs, **opts):
3323 def graft(ui, repo, *revs, **opts):
3336 '''copy changes from other branches onto the current branch
3324 '''copy changes from other branches onto the current branch
3337
3325
3338 This command uses Mercurial's merge logic to copy individual
3326 This command uses Mercurial's merge logic to copy individual
3339 changes from other branches without merging branches in the
3327 changes from other branches without merging branches in the
3340 history graph. This is sometimes known as 'backporting' or
3328 history graph. This is sometimes known as 'backporting' or
3341 'cherry-picking'. By default, graft will copy user, date, and
3329 'cherry-picking'. By default, graft will copy user, date, and
3342 description from the source changesets.
3330 description from the source changesets.
3343
3331
3344 Changesets that are ancestors of the current revision, that have
3332 Changesets that are ancestors of the current revision, that have
3345 already been grafted, or that are merges will be skipped.
3333 already been grafted, or that are merges will be skipped.
3346
3334
3347 If --log is specified, log messages will have a comment appended
3335 If --log is specified, log messages will have a comment appended
3348 of the form::
3336 of the form::
3349
3337
3350 (grafted from CHANGESETHASH)
3338 (grafted from CHANGESETHASH)
3351
3339
3352 If --force is specified, revisions will be grafted even if they
3340 If --force is specified, revisions will be grafted even if they
3353 are already ancestors of or have been grafted to the destination.
3341 are already ancestors of or have been grafted to the destination.
3354 This is useful when the revisions have since been backed out.
3342 This is useful when the revisions have since been backed out.
3355
3343
3356 If a graft merge results in conflicts, the graft process is
3344 If a graft merge results in conflicts, the graft process is
3357 interrupted so that the current merge can be manually resolved.
3345 interrupted so that the current merge can be manually resolved.
3358 Once all conflicts are addressed, the graft process can be
3346 Once all conflicts are addressed, the graft process can be
3359 continued with the -c/--continue option.
3347 continued with the -c/--continue option.
3360
3348
3361 .. note::
3349 .. note::
3362
3350
3363 The -c/--continue option does not reapply earlier options, except
3351 The -c/--continue option does not reapply earlier options, except
3364 for --force.
3352 for --force.
3365
3353
3366 .. container:: verbose
3354 .. container:: verbose
3367
3355
3368 Examples:
3356 Examples:
3369
3357
3370 - copy a single change to the stable branch and edit its description::
3358 - copy a single change to the stable branch and edit its description::
3371
3359
3372 hg update stable
3360 hg update stable
3373 hg graft --edit 9393
3361 hg graft --edit 9393
3374
3362
3375 - graft a range of changesets with one exception, updating dates::
3363 - graft a range of changesets with one exception, updating dates::
3376
3364
3377 hg graft -D "2085::2093 and not 2091"
3365 hg graft -D "2085::2093 and not 2091"
3378
3366
3379 - continue a graft after resolving conflicts::
3367 - continue a graft after resolving conflicts::
3380
3368
3381 hg graft -c
3369 hg graft -c
3382
3370
3383 - show the source of a grafted changeset::
3371 - show the source of a grafted changeset::
3384
3372
3385 hg log --debug -r .
3373 hg log --debug -r .
3386
3374
3387 See :hg:`help revisions` and :hg:`help revsets` for more about
3375 See :hg:`help revisions` and :hg:`help revsets` for more about
3388 specifying revisions.
3376 specifying revisions.
3389
3377
3390 Returns 0 on successful completion.
3378 Returns 0 on successful completion.
3391 '''
3379 '''
3392
3380
3393 revs = list(revs)
3381 revs = list(revs)
3394 revs.extend(opts['rev'])
3382 revs.extend(opts['rev'])
3395
3383
3396 if not opts.get('user') and opts.get('currentuser'):
3384 if not opts.get('user') and opts.get('currentuser'):
3397 opts['user'] = ui.username()
3385 opts['user'] = ui.username()
3398 if not opts.get('date') and opts.get('currentdate'):
3386 if not opts.get('date') and opts.get('currentdate'):
3399 opts['date'] = "%d %d" % util.makedate()
3387 opts['date'] = "%d %d" % util.makedate()
3400
3388
3401 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3389 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3402
3390
3403 cont = False
3391 cont = False
3404 if opts['continue']:
3392 if opts['continue']:
3405 cont = True
3393 cont = True
3406 if revs:
3394 if revs:
3407 raise util.Abort(_("can't specify --continue and revisions"))
3395 raise util.Abort(_("can't specify --continue and revisions"))
3408 # read in unfinished revisions
3396 # read in unfinished revisions
3409 try:
3397 try:
3410 nodes = repo.vfs.read('graftstate').splitlines()
3398 nodes = repo.vfs.read('graftstate').splitlines()
3411 revs = [repo[node].rev() for node in nodes]
3399 revs = [repo[node].rev() for node in nodes]
3412 except IOError, inst:
3400 except IOError, inst:
3413 if inst.errno != errno.ENOENT:
3401 if inst.errno != errno.ENOENT:
3414 raise
3402 raise
3415 raise util.Abort(_("no graft state found, can't continue"))
3403 raise util.Abort(_("no graft state found, can't continue"))
3416 else:
3404 else:
3417 cmdutil.checkunfinished(repo)
3405 cmdutil.checkunfinished(repo)
3418 cmdutil.bailifchanged(repo)
3406 cmdutil.bailifchanged(repo)
3419 if not revs:
3407 if not revs:
3420 raise util.Abort(_('no revisions specified'))
3408 raise util.Abort(_('no revisions specified'))
3421 revs = scmutil.revrange(repo, revs)
3409 revs = scmutil.revrange(repo, revs)
3422
3410
3423 skipped = set()
3411 skipped = set()
3424 # check for merges
3412 # check for merges
3425 for rev in repo.revs('%ld and merge()', revs):
3413 for rev in repo.revs('%ld and merge()', revs):
3426 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3414 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3427 skipped.add(rev)
3415 skipped.add(rev)
3428 revs = [r for r in revs if r not in skipped]
3416 revs = [r for r in revs if r not in skipped]
3429 if not revs:
3417 if not revs:
3430 return -1
3418 return -1
3431
3419
3432 # Don't check in the --continue case, in effect retaining --force across
3420 # Don't check in the --continue case, in effect retaining --force across
3433 # --continues. That's because without --force, any revisions we decided to
3421 # --continues. That's because without --force, any revisions we decided to
3434 # skip would have been filtered out here, so they wouldn't have made their
3422 # skip would have been filtered out here, so they wouldn't have made their
3435 # way to the graftstate. With --force, any revisions we would have otherwise
3423 # way to the graftstate. With --force, any revisions we would have otherwise
3436 # skipped would not have been filtered out, and if they hadn't been applied
3424 # skipped would not have been filtered out, and if they hadn't been applied
3437 # already, they'd have been in the graftstate.
3425 # already, they'd have been in the graftstate.
3438 if not (cont or opts.get('force')):
3426 if not (cont or opts.get('force')):
3439 # check for ancestors of dest branch
3427 # check for ancestors of dest branch
3440 crev = repo['.'].rev()
3428 crev = repo['.'].rev()
3441 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3429 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3442 # Cannot use x.remove(y) on smart set, this has to be a list.
3430 # Cannot use x.remove(y) on smart set, this has to be a list.
3443 # XXX make this lazy in the future
3431 # XXX make this lazy in the future
3444 revs = list(revs)
3432 revs = list(revs)
3445 # don't mutate while iterating, create a copy
3433 # don't mutate while iterating, create a copy
3446 for rev in list(revs):
3434 for rev in list(revs):
3447 if rev in ancestors:
3435 if rev in ancestors:
3448 ui.warn(_('skipping ancestor revision %d:%s\n') %
3436 ui.warn(_('skipping ancestor revision %d:%s\n') %
3449 (rev, repo[rev]))
3437 (rev, repo[rev]))
3450 # XXX remove on list is slow
3438 # XXX remove on list is slow
3451 revs.remove(rev)
3439 revs.remove(rev)
3452 if not revs:
3440 if not revs:
3453 return -1
3441 return -1
3454
3442
3455 # analyze revs for earlier grafts
3443 # analyze revs for earlier grafts
3456 ids = {}
3444 ids = {}
3457 for ctx in repo.set("%ld", revs):
3445 for ctx in repo.set("%ld", revs):
3458 ids[ctx.hex()] = ctx.rev()
3446 ids[ctx.hex()] = ctx.rev()
3459 n = ctx.extra().get('source')
3447 n = ctx.extra().get('source')
3460 if n:
3448 if n:
3461 ids[n] = ctx.rev()
3449 ids[n] = ctx.rev()
3462
3450
3463 # check ancestors for earlier grafts
3451 # check ancestors for earlier grafts
3464 ui.debug('scanning for duplicate grafts\n')
3452 ui.debug('scanning for duplicate grafts\n')
3465
3453
3466 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3454 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3467 ctx = repo[rev]
3455 ctx = repo[rev]
3468 n = ctx.extra().get('source')
3456 n = ctx.extra().get('source')
3469 if n in ids:
3457 if n in ids:
3470 try:
3458 try:
3471 r = repo[n].rev()
3459 r = repo[n].rev()
3472 except error.RepoLookupError:
3460 except error.RepoLookupError:
3473 r = None
3461 r = None
3474 if r in revs:
3462 if r in revs:
3475 ui.warn(_('skipping revision %d:%s '
3463 ui.warn(_('skipping revision %d:%s '
3476 '(already grafted to %d:%s)\n')
3464 '(already grafted to %d:%s)\n')
3477 % (r, repo[r], rev, ctx))
3465 % (r, repo[r], rev, ctx))
3478 revs.remove(r)
3466 revs.remove(r)
3479 elif ids[n] in revs:
3467 elif ids[n] in revs:
3480 if r is None:
3468 if r is None:
3481 ui.warn(_('skipping already grafted revision %d:%s '
3469 ui.warn(_('skipping already grafted revision %d:%s '
3482 '(%d:%s also has unknown origin %s)\n')
3470 '(%d:%s also has unknown origin %s)\n')
3483 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3471 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3484 else:
3472 else:
3485 ui.warn(_('skipping already grafted revision %d:%s '
3473 ui.warn(_('skipping already grafted revision %d:%s '
3486 '(%d:%s also has origin %d:%s)\n')
3474 '(%d:%s also has origin %d:%s)\n')
3487 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3475 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3488 revs.remove(ids[n])
3476 revs.remove(ids[n])
3489 elif ctx.hex() in ids:
3477 elif ctx.hex() in ids:
3490 r = ids[ctx.hex()]
3478 r = ids[ctx.hex()]
3491 ui.warn(_('skipping already grafted revision %d:%s '
3479 ui.warn(_('skipping already grafted revision %d:%s '
3492 '(was grafted from %d:%s)\n') %
3480 '(was grafted from %d:%s)\n') %
3493 (r, repo[r], rev, ctx))
3481 (r, repo[r], rev, ctx))
3494 revs.remove(r)
3482 revs.remove(r)
3495 if not revs:
3483 if not revs:
3496 return -1
3484 return -1
3497
3485
3498 wlock = repo.wlock()
3486 wlock = repo.wlock()
3499 try:
3487 try:
3500 for pos, ctx in enumerate(repo.set("%ld", revs)):
3488 for pos, ctx in enumerate(repo.set("%ld", revs)):
3501 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3489 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3502 ctx.description().split('\n', 1)[0])
3490 ctx.description().split('\n', 1)[0])
3503 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3491 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3504 if names:
3492 if names:
3505 desc += ' (%s)' % ' '.join(names)
3493 desc += ' (%s)' % ' '.join(names)
3506 ui.status(_('grafting %s\n') % desc)
3494 ui.status(_('grafting %s\n') % desc)
3507 if opts.get('dry_run'):
3495 if opts.get('dry_run'):
3508 continue
3496 continue
3509
3497
3510 source = ctx.extra().get('source')
3498 source = ctx.extra().get('source')
3511 if not source:
3499 if not source:
3512 source = ctx.hex()
3500 source = ctx.hex()
3513 extra = {'source': source}
3501 extra = {'source': source}
3514 user = ctx.user()
3502 user = ctx.user()
3515 if opts.get('user'):
3503 if opts.get('user'):
3516 user = opts['user']
3504 user = opts['user']
3517 date = ctx.date()
3505 date = ctx.date()
3518 if opts.get('date'):
3506 if opts.get('date'):
3519 date = opts['date']
3507 date = opts['date']
3520 message = ctx.description()
3508 message = ctx.description()
3521 if opts.get('log'):
3509 if opts.get('log'):
3522 message += '\n(grafted from %s)' % ctx.hex()
3510 message += '\n(grafted from %s)' % ctx.hex()
3523
3511
3524 # we don't merge the first commit when continuing
3512 # we don't merge the first commit when continuing
3525 if not cont:
3513 if not cont:
3526 # perform the graft merge with p1(rev) as 'ancestor'
3514 # perform the graft merge with p1(rev) as 'ancestor'
3527 try:
3515 try:
3528 # ui.forcemerge is an internal variable, do not document
3516 # ui.forcemerge is an internal variable, do not document
3529 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3517 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3530 'graft')
3518 'graft')
3531 stats = mergemod.graft(repo, ctx, ctx.p1(),
3519 stats = mergemod.graft(repo, ctx, ctx.p1(),
3532 ['local', 'graft'])
3520 ['local', 'graft'])
3533 finally:
3521 finally:
3534 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3522 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3535 # report any conflicts
3523 # report any conflicts
3536 if stats and stats[3] > 0:
3524 if stats and stats[3] > 0:
3537 # write out state for --continue
3525 # write out state for --continue
3538 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3526 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3539 repo.vfs.write('graftstate', ''.join(nodelines))
3527 repo.vfs.write('graftstate', ''.join(nodelines))
3540 raise util.Abort(
3528 raise util.Abort(
3541 _("unresolved conflicts, can't continue"),
3529 _("unresolved conflicts, can't continue"),
3542 hint=_('use hg resolve and hg graft --continue'))
3530 hint=_('use hg resolve and hg graft --continue'))
3543 else:
3531 else:
3544 cont = False
3532 cont = False
3545
3533
3546 # commit
3534 # commit
3547 node = repo.commit(text=message, user=user,
3535 node = repo.commit(text=message, user=user,
3548 date=date, extra=extra, editor=editor)
3536 date=date, extra=extra, editor=editor)
3549 if node is None:
3537 if node is None:
3550 ui.warn(
3538 ui.warn(
3551 _('note: graft of %d:%s created no changes to commit\n') %
3539 _('note: graft of %d:%s created no changes to commit\n') %
3552 (ctx.rev(), ctx))
3540 (ctx.rev(), ctx))
3553 finally:
3541 finally:
3554 wlock.release()
3542 wlock.release()
3555
3543
3556 # remove state when we complete successfully
3544 # remove state when we complete successfully
3557 if not opts.get('dry_run'):
3545 if not opts.get('dry_run'):
3558 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3546 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3559
3547
3560 return 0
3548 return 0
3561
3549
3562 @command('grep',
3550 @command('grep',
3563 [('0', 'print0', None, _('end fields with NUL')),
3551 [('0', 'print0', None, _('end fields with NUL')),
3564 ('', 'all', None, _('print all revisions that match')),
3552 ('', 'all', None, _('print all revisions that match')),
3565 ('a', 'text', None, _('treat all files as text')),
3553 ('a', 'text', None, _('treat all files as text')),
3566 ('f', 'follow', None,
3554 ('f', 'follow', None,
3567 _('follow changeset history,'
3555 _('follow changeset history,'
3568 ' or file history across copies and renames')),
3556 ' or file history across copies and renames')),
3569 ('i', 'ignore-case', None, _('ignore case when matching')),
3557 ('i', 'ignore-case', None, _('ignore case when matching')),
3570 ('l', 'files-with-matches', None,
3558 ('l', 'files-with-matches', None,
3571 _('print only filenames and revisions that match')),
3559 _('print only filenames and revisions that match')),
3572 ('n', 'line-number', None, _('print matching line numbers')),
3560 ('n', 'line-number', None, _('print matching line numbers')),
3573 ('r', 'rev', [],
3561 ('r', 'rev', [],
3574 _('only search files changed within revision range'), _('REV')),
3562 _('only search files changed within revision range'), _('REV')),
3575 ('u', 'user', None, _('list the author (long with -v)')),
3563 ('u', 'user', None, _('list the author (long with -v)')),
3576 ('d', 'date', None, _('list the date (short with -q)')),
3564 ('d', 'date', None, _('list the date (short with -q)')),
3577 ] + walkopts,
3565 ] + walkopts,
3578 _('[OPTION]... PATTERN [FILE]...'),
3566 _('[OPTION]... PATTERN [FILE]...'),
3579 inferrepo=True)
3567 inferrepo=True)
3580 def grep(ui, repo, pattern, *pats, **opts):
3568 def grep(ui, repo, pattern, *pats, **opts):
3581 """search for a pattern in specified files and revisions
3569 """search for a pattern in specified files and revisions
3582
3570
3583 Search revisions of files for a regular expression.
3571 Search revisions of files for a regular expression.
3584
3572
3585 This command behaves differently than Unix grep. It only accepts
3573 This command behaves differently than Unix grep. It only accepts
3586 Python/Perl regexps. It searches repository history, not the
3574 Python/Perl regexps. It searches repository history, not the
3587 working directory. It always prints the revision number in which a
3575 working directory. It always prints the revision number in which a
3588 match appears.
3576 match appears.
3589
3577
3590 By default, grep only prints output for the first revision of a
3578 By default, grep only prints output for the first revision of a
3591 file in which it finds a match. To get it to print every revision
3579 file in which it finds a match. To get it to print every revision
3592 that contains a change in match status ("-" for a match that
3580 that contains a change in match status ("-" for a match that
3593 becomes a non-match, or "+" for a non-match that becomes a match),
3581 becomes a non-match, or "+" for a non-match that becomes a match),
3594 use the --all flag.
3582 use the --all flag.
3595
3583
3596 Returns 0 if a match is found, 1 otherwise.
3584 Returns 0 if a match is found, 1 otherwise.
3597 """
3585 """
3598 reflags = re.M
3586 reflags = re.M
3599 if opts.get('ignore_case'):
3587 if opts.get('ignore_case'):
3600 reflags |= re.I
3588 reflags |= re.I
3601 try:
3589 try:
3602 regexp = util.re.compile(pattern, reflags)
3590 regexp = util.re.compile(pattern, reflags)
3603 except re.error, inst:
3591 except re.error, inst:
3604 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3592 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3605 return 1
3593 return 1
3606 sep, eol = ':', '\n'
3594 sep, eol = ':', '\n'
3607 if opts.get('print0'):
3595 if opts.get('print0'):
3608 sep = eol = '\0'
3596 sep = eol = '\0'
3609
3597
3610 getfile = util.lrucachefunc(repo.file)
3598 getfile = util.lrucachefunc(repo.file)
3611
3599
3612 def matchlines(body):
3600 def matchlines(body):
3613 begin = 0
3601 begin = 0
3614 linenum = 0
3602 linenum = 0
3615 while begin < len(body):
3603 while begin < len(body):
3616 match = regexp.search(body, begin)
3604 match = regexp.search(body, begin)
3617 if not match:
3605 if not match:
3618 break
3606 break
3619 mstart, mend = match.span()
3607 mstart, mend = match.span()
3620 linenum += body.count('\n', begin, mstart) + 1
3608 linenum += body.count('\n', begin, mstart) + 1
3621 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3609 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3622 begin = body.find('\n', mend) + 1 or len(body) + 1
3610 begin = body.find('\n', mend) + 1 or len(body) + 1
3623 lend = begin - 1
3611 lend = begin - 1
3624 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3612 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3625
3613
3626 class linestate(object):
3614 class linestate(object):
3627 def __init__(self, line, linenum, colstart, colend):
3615 def __init__(self, line, linenum, colstart, colend):
3628 self.line = line
3616 self.line = line
3629 self.linenum = linenum
3617 self.linenum = linenum
3630 self.colstart = colstart
3618 self.colstart = colstart
3631 self.colend = colend
3619 self.colend = colend
3632
3620
3633 def __hash__(self):
3621 def __hash__(self):
3634 return hash((self.linenum, self.line))
3622 return hash((self.linenum, self.line))
3635
3623
3636 def __eq__(self, other):
3624 def __eq__(self, other):
3637 return self.line == other.line
3625 return self.line == other.line
3638
3626
3639 def __iter__(self):
3627 def __iter__(self):
3640 yield (self.line[:self.colstart], '')
3628 yield (self.line[:self.colstart], '')
3641 yield (self.line[self.colstart:self.colend], 'grep.match')
3629 yield (self.line[self.colstart:self.colend], 'grep.match')
3642 rest = self.line[self.colend:]
3630 rest = self.line[self.colend:]
3643 while rest != '':
3631 while rest != '':
3644 match = regexp.search(rest)
3632 match = regexp.search(rest)
3645 if not match:
3633 if not match:
3646 yield (rest, '')
3634 yield (rest, '')
3647 break
3635 break
3648 mstart, mend = match.span()
3636 mstart, mend = match.span()
3649 yield (rest[:mstart], '')
3637 yield (rest[:mstart], '')
3650 yield (rest[mstart:mend], 'grep.match')
3638 yield (rest[mstart:mend], 'grep.match')
3651 rest = rest[mend:]
3639 rest = rest[mend:]
3652
3640
3653 matches = {}
3641 matches = {}
3654 copies = {}
3642 copies = {}
3655 def grepbody(fn, rev, body):
3643 def grepbody(fn, rev, body):
3656 matches[rev].setdefault(fn, [])
3644 matches[rev].setdefault(fn, [])
3657 m = matches[rev][fn]
3645 m = matches[rev][fn]
3658 for lnum, cstart, cend, line in matchlines(body):
3646 for lnum, cstart, cend, line in matchlines(body):
3659 s = linestate(line, lnum, cstart, cend)
3647 s = linestate(line, lnum, cstart, cend)
3660 m.append(s)
3648 m.append(s)
3661
3649
3662 def difflinestates(a, b):
3650 def difflinestates(a, b):
3663 sm = difflib.SequenceMatcher(None, a, b)
3651 sm = difflib.SequenceMatcher(None, a, b)
3664 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3652 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3665 if tag == 'insert':
3653 if tag == 'insert':
3666 for i in xrange(blo, bhi):
3654 for i in xrange(blo, bhi):
3667 yield ('+', b[i])
3655 yield ('+', b[i])
3668 elif tag == 'delete':
3656 elif tag == 'delete':
3669 for i in xrange(alo, ahi):
3657 for i in xrange(alo, ahi):
3670 yield ('-', a[i])
3658 yield ('-', a[i])
3671 elif tag == 'replace':
3659 elif tag == 'replace':
3672 for i in xrange(alo, ahi):
3660 for i in xrange(alo, ahi):
3673 yield ('-', a[i])
3661 yield ('-', a[i])
3674 for i in xrange(blo, bhi):
3662 for i in xrange(blo, bhi):
3675 yield ('+', b[i])
3663 yield ('+', b[i])
3676
3664
3677 def display(fn, ctx, pstates, states):
3665 def display(fn, ctx, pstates, states):
3678 rev = ctx.rev()
3666 rev = ctx.rev()
3679 datefunc = ui.quiet and util.shortdate or util.datestr
3667 datefunc = ui.quiet and util.shortdate or util.datestr
3680 found = False
3668 found = False
3681 @util.cachefunc
3669 @util.cachefunc
3682 def binary():
3670 def binary():
3683 flog = getfile(fn)
3671 flog = getfile(fn)
3684 return util.binary(flog.read(ctx.filenode(fn)))
3672 return util.binary(flog.read(ctx.filenode(fn)))
3685
3673
3686 if opts.get('all'):
3674 if opts.get('all'):
3687 iter = difflinestates(pstates, states)
3675 iter = difflinestates(pstates, states)
3688 else:
3676 else:
3689 iter = [('', l) for l in states]
3677 iter = [('', l) for l in states]
3690 for change, l in iter:
3678 for change, l in iter:
3691 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3679 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3692
3680
3693 if opts.get('line_number'):
3681 if opts.get('line_number'):
3694 cols.append((str(l.linenum), 'grep.linenumber'))
3682 cols.append((str(l.linenum), 'grep.linenumber'))
3695 if opts.get('all'):
3683 if opts.get('all'):
3696 cols.append((change, 'grep.change'))
3684 cols.append((change, 'grep.change'))
3697 if opts.get('user'):
3685 if opts.get('user'):
3698 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3686 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3699 if opts.get('date'):
3687 if opts.get('date'):
3700 cols.append((datefunc(ctx.date()), 'grep.date'))
3688 cols.append((datefunc(ctx.date()), 'grep.date'))
3701 for col, label in cols[:-1]:
3689 for col, label in cols[:-1]:
3702 ui.write(col, label=label)
3690 ui.write(col, label=label)
3703 ui.write(sep, label='grep.sep')
3691 ui.write(sep, label='grep.sep')
3704 ui.write(cols[-1][0], label=cols[-1][1])
3692 ui.write(cols[-1][0], label=cols[-1][1])
3705 if not opts.get('files_with_matches'):
3693 if not opts.get('files_with_matches'):
3706 ui.write(sep, label='grep.sep')
3694 ui.write(sep, label='grep.sep')
3707 if not opts.get('text') and binary():
3695 if not opts.get('text') and binary():
3708 ui.write(" Binary file matches")
3696 ui.write(" Binary file matches")
3709 else:
3697 else:
3710 for s, label in l:
3698 for s, label in l:
3711 ui.write(s, label=label)
3699 ui.write(s, label=label)
3712 ui.write(eol)
3700 ui.write(eol)
3713 found = True
3701 found = True
3714 if opts.get('files_with_matches'):
3702 if opts.get('files_with_matches'):
3715 break
3703 break
3716 return found
3704 return found
3717
3705
3718 skip = {}
3706 skip = {}
3719 revfiles = {}
3707 revfiles = {}
3720 matchfn = scmutil.match(repo[None], pats, opts)
3708 matchfn = scmutil.match(repo[None], pats, opts)
3721 found = False
3709 found = False
3722 follow = opts.get('follow')
3710 follow = opts.get('follow')
3723
3711
3724 def prep(ctx, fns):
3712 def prep(ctx, fns):
3725 rev = ctx.rev()
3713 rev = ctx.rev()
3726 pctx = ctx.p1()
3714 pctx = ctx.p1()
3727 parent = pctx.rev()
3715 parent = pctx.rev()
3728 matches.setdefault(rev, {})
3716 matches.setdefault(rev, {})
3729 matches.setdefault(parent, {})
3717 matches.setdefault(parent, {})
3730 files = revfiles.setdefault(rev, [])
3718 files = revfiles.setdefault(rev, [])
3731 for fn in fns:
3719 for fn in fns:
3732 flog = getfile(fn)
3720 flog = getfile(fn)
3733 try:
3721 try:
3734 fnode = ctx.filenode(fn)
3722 fnode = ctx.filenode(fn)
3735 except error.LookupError:
3723 except error.LookupError:
3736 continue
3724 continue
3737
3725
3738 copied = flog.renamed(fnode)
3726 copied = flog.renamed(fnode)
3739 copy = follow and copied and copied[0]
3727 copy = follow and copied and copied[0]
3740 if copy:
3728 if copy:
3741 copies.setdefault(rev, {})[fn] = copy
3729 copies.setdefault(rev, {})[fn] = copy
3742 if fn in skip:
3730 if fn in skip:
3743 if copy:
3731 if copy:
3744 skip[copy] = True
3732 skip[copy] = True
3745 continue
3733 continue
3746 files.append(fn)
3734 files.append(fn)
3747
3735
3748 if fn not in matches[rev]:
3736 if fn not in matches[rev]:
3749 grepbody(fn, rev, flog.read(fnode))
3737 grepbody(fn, rev, flog.read(fnode))
3750
3738
3751 pfn = copy or fn
3739 pfn = copy or fn
3752 if pfn not in matches[parent]:
3740 if pfn not in matches[parent]:
3753 try:
3741 try:
3754 fnode = pctx.filenode(pfn)
3742 fnode = pctx.filenode(pfn)
3755 grepbody(pfn, parent, flog.read(fnode))
3743 grepbody(pfn, parent, flog.read(fnode))
3756 except error.LookupError:
3744 except error.LookupError:
3757 pass
3745 pass
3758
3746
3759 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3747 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3760 rev = ctx.rev()
3748 rev = ctx.rev()
3761 parent = ctx.p1().rev()
3749 parent = ctx.p1().rev()
3762 for fn in sorted(revfiles.get(rev, [])):
3750 for fn in sorted(revfiles.get(rev, [])):
3763 states = matches[rev][fn]
3751 states = matches[rev][fn]
3764 copy = copies.get(rev, {}).get(fn)
3752 copy = copies.get(rev, {}).get(fn)
3765 if fn in skip:
3753 if fn in skip:
3766 if copy:
3754 if copy:
3767 skip[copy] = True
3755 skip[copy] = True
3768 continue
3756 continue
3769 pstates = matches.get(parent, {}).get(copy or fn, [])
3757 pstates = matches.get(parent, {}).get(copy or fn, [])
3770 if pstates or states:
3758 if pstates or states:
3771 r = display(fn, ctx, pstates, states)
3759 r = display(fn, ctx, pstates, states)
3772 found = found or r
3760 found = found or r
3773 if r and not opts.get('all'):
3761 if r and not opts.get('all'):
3774 skip[fn] = True
3762 skip[fn] = True
3775 if copy:
3763 if copy:
3776 skip[copy] = True
3764 skip[copy] = True
3777 del matches[rev]
3765 del matches[rev]
3778 del revfiles[rev]
3766 del revfiles[rev]
3779
3767
3780 return not found
3768 return not found
3781
3769
3782 @command('heads',
3770 @command('heads',
3783 [('r', 'rev', '',
3771 [('r', 'rev', '',
3784 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3772 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3785 ('t', 'topo', False, _('show topological heads only')),
3773 ('t', 'topo', False, _('show topological heads only')),
3786 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3774 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3787 ('c', 'closed', False, _('show normal and closed branch heads')),
3775 ('c', 'closed', False, _('show normal and closed branch heads')),
3788 ] + templateopts,
3776 ] + templateopts,
3789 _('[-ct] [-r STARTREV] [REV]...'))
3777 _('[-ct] [-r STARTREV] [REV]...'))
3790 def heads(ui, repo, *branchrevs, **opts):
3778 def heads(ui, repo, *branchrevs, **opts):
3791 """show branch heads
3779 """show branch heads
3792
3780
3793 With no arguments, show all open branch heads in the repository.
3781 With no arguments, show all open branch heads in the repository.
3794 Branch heads are changesets that have no descendants on the
3782 Branch heads are changesets that have no descendants on the
3795 same branch. They are where development generally takes place and
3783 same branch. They are where development generally takes place and
3796 are the usual targets for update and merge operations.
3784 are the usual targets for update and merge operations.
3797
3785
3798 If one or more REVs are given, only open branch heads on the
3786 If one or more REVs are given, only open branch heads on the
3799 branches associated with the specified changesets are shown. This
3787 branches associated with the specified changesets are shown. This
3800 means that you can use :hg:`heads .` to see the heads on the
3788 means that you can use :hg:`heads .` to see the heads on the
3801 currently checked-out branch.
3789 currently checked-out branch.
3802
3790
3803 If -c/--closed is specified, also show branch heads marked closed
3791 If -c/--closed is specified, also show branch heads marked closed
3804 (see :hg:`commit --close-branch`).
3792 (see :hg:`commit --close-branch`).
3805
3793
3806 If STARTREV is specified, only those heads that are descendants of
3794 If STARTREV is specified, only those heads that are descendants of
3807 STARTREV will be displayed.
3795 STARTREV will be displayed.
3808
3796
3809 If -t/--topo is specified, named branch mechanics will be ignored and only
3797 If -t/--topo is specified, named branch mechanics will be ignored and only
3810 topological heads (changesets with no children) will be shown.
3798 topological heads (changesets with no children) will be shown.
3811
3799
3812 Returns 0 if matching heads are found, 1 if not.
3800 Returns 0 if matching heads are found, 1 if not.
3813 """
3801 """
3814
3802
3815 start = None
3803 start = None
3816 if 'rev' in opts:
3804 if 'rev' in opts:
3817 start = scmutil.revsingle(repo, opts['rev'], None).node()
3805 start = scmutil.revsingle(repo, opts['rev'], None).node()
3818
3806
3819 if opts.get('topo'):
3807 if opts.get('topo'):
3820 heads = [repo[h] for h in repo.heads(start)]
3808 heads = [repo[h] for h in repo.heads(start)]
3821 else:
3809 else:
3822 heads = []
3810 heads = []
3823 for branch in repo.branchmap():
3811 for branch in repo.branchmap():
3824 heads += repo.branchheads(branch, start, opts.get('closed'))
3812 heads += repo.branchheads(branch, start, opts.get('closed'))
3825 heads = [repo[h] for h in heads]
3813 heads = [repo[h] for h in heads]
3826
3814
3827 if branchrevs:
3815 if branchrevs:
3828 branches = set(repo[br].branch() for br in branchrevs)
3816 branches = set(repo[br].branch() for br in branchrevs)
3829 heads = [h for h in heads if h.branch() in branches]
3817 heads = [h for h in heads if h.branch() in branches]
3830
3818
3831 if opts.get('active') and branchrevs:
3819 if opts.get('active') and branchrevs:
3832 dagheads = repo.heads(start)
3820 dagheads = repo.heads(start)
3833 heads = [h for h in heads if h.node() in dagheads]
3821 heads = [h for h in heads if h.node() in dagheads]
3834
3822
3835 if branchrevs:
3823 if branchrevs:
3836 haveheads = set(h.branch() for h in heads)
3824 haveheads = set(h.branch() for h in heads)
3837 if branches - haveheads:
3825 if branches - haveheads:
3838 headless = ', '.join(b for b in branches - haveheads)
3826 headless = ', '.join(b for b in branches - haveheads)
3839 msg = _('no open branch heads found on branches %s')
3827 msg = _('no open branch heads found on branches %s')
3840 if opts.get('rev'):
3828 if opts.get('rev'):
3841 msg += _(' (started at %s)') % opts['rev']
3829 msg += _(' (started at %s)') % opts['rev']
3842 ui.warn((msg + '\n') % headless)
3830 ui.warn((msg + '\n') % headless)
3843
3831
3844 if not heads:
3832 if not heads:
3845 return 1
3833 return 1
3846
3834
3847 heads = sorted(heads, key=lambda x: -x.rev())
3835 heads = sorted(heads, key=lambda x: -x.rev())
3848 displayer = cmdutil.show_changeset(ui, repo, opts)
3836 displayer = cmdutil.show_changeset(ui, repo, opts)
3849 for ctx in heads:
3837 for ctx in heads:
3850 displayer.show(ctx)
3838 displayer.show(ctx)
3851 displayer.close()
3839 displayer.close()
3852
3840
3853 @command('help',
3841 @command('help',
3854 [('e', 'extension', None, _('show only help for extensions')),
3842 [('e', 'extension', None, _('show only help for extensions')),
3855 ('c', 'command', None, _('show only help for commands')),
3843 ('c', 'command', None, _('show only help for commands')),
3856 ('k', 'keyword', '', _('show topics matching keyword')),
3844 ('k', 'keyword', '', _('show topics matching keyword')),
3857 ],
3845 ],
3858 _('[-ec] [TOPIC]'),
3846 _('[-ec] [TOPIC]'),
3859 norepo=True)
3847 norepo=True)
3860 def help_(ui, name=None, **opts):
3848 def help_(ui, name=None, **opts):
3861 """show help for a given topic or a help overview
3849 """show help for a given topic or a help overview
3862
3850
3863 With no arguments, print a list of commands with short help messages.
3851 With no arguments, print a list of commands with short help messages.
3864
3852
3865 Given a topic, extension, or command name, print help for that
3853 Given a topic, extension, or command name, print help for that
3866 topic.
3854 topic.
3867
3855
3868 Returns 0 if successful.
3856 Returns 0 if successful.
3869 """
3857 """
3870
3858
3871 textwidth = min(ui.termwidth(), 80) - 2
3859 textwidth = min(ui.termwidth(), 80) - 2
3872
3860
3873 keep = []
3861 keep = []
3874 if ui.verbose:
3862 if ui.verbose:
3875 keep.append('verbose')
3863 keep.append('verbose')
3876 if sys.platform.startswith('win'):
3864 if sys.platform.startswith('win'):
3877 keep.append('windows')
3865 keep.append('windows')
3878 elif sys.platform == 'OpenVMS':
3866 elif sys.platform == 'OpenVMS':
3879 keep.append('vms')
3867 keep.append('vms')
3880 elif sys.platform == 'plan9':
3868 elif sys.platform == 'plan9':
3881 keep.append('plan9')
3869 keep.append('plan9')
3882 else:
3870 else:
3883 keep.append('unix')
3871 keep.append('unix')
3884 keep.append(sys.platform.lower())
3872 keep.append(sys.platform.lower())
3885
3873
3886 section = None
3874 section = None
3887 if name and '.' in name:
3875 if name and '.' in name:
3888 name, section = name.split('.', 1)
3876 name, section = name.split('.', 1)
3889
3877
3890 text = help.help_(ui, name, **opts)
3878 text = help.help_(ui, name, **opts)
3891
3879
3892 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3880 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3893 section=section)
3881 section=section)
3894 if section and not formatted:
3882 if section and not formatted:
3895 raise util.Abort(_("help section not found"))
3883 raise util.Abort(_("help section not found"))
3896
3884
3897 if 'verbose' in pruned:
3885 if 'verbose' in pruned:
3898 keep.append('omitted')
3886 keep.append('omitted')
3899 else:
3887 else:
3900 keep.append('notomitted')
3888 keep.append('notomitted')
3901 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3889 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3902 section=section)
3890 section=section)
3903 ui.write(formatted)
3891 ui.write(formatted)
3904
3892
3905
3893
3906 @command('identify|id',
3894 @command('identify|id',
3907 [('r', 'rev', '',
3895 [('r', 'rev', '',
3908 _('identify the specified revision'), _('REV')),
3896 _('identify the specified revision'), _('REV')),
3909 ('n', 'num', None, _('show local revision number')),
3897 ('n', 'num', None, _('show local revision number')),
3910 ('i', 'id', None, _('show global revision id')),
3898 ('i', 'id', None, _('show global revision id')),
3911 ('b', 'branch', None, _('show branch')),
3899 ('b', 'branch', None, _('show branch')),
3912 ('t', 'tags', None, _('show tags')),
3900 ('t', 'tags', None, _('show tags')),
3913 ('B', 'bookmarks', None, _('show bookmarks')),
3901 ('B', 'bookmarks', None, _('show bookmarks')),
3914 ] + remoteopts,
3902 ] + remoteopts,
3915 _('[-nibtB] [-r REV] [SOURCE]'),
3903 _('[-nibtB] [-r REV] [SOURCE]'),
3916 optionalrepo=True)
3904 optionalrepo=True)
3917 def identify(ui, repo, source=None, rev=None,
3905 def identify(ui, repo, source=None, rev=None,
3918 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3906 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3919 """identify the working copy or specified revision
3907 """identify the working copy or specified revision
3920
3908
3921 Print a summary identifying the repository state at REV using one or
3909 Print a summary identifying the repository state at REV using one or
3922 two parent hash identifiers, followed by a "+" if the working
3910 two parent hash identifiers, followed by a "+" if the working
3923 directory has uncommitted changes, the branch name (if not default),
3911 directory has uncommitted changes, the branch name (if not default),
3924 a list of tags, and a list of bookmarks.
3912 a list of tags, and a list of bookmarks.
3925
3913
3926 When REV is not given, print a summary of the current state of the
3914 When REV is not given, print a summary of the current state of the
3927 repository.
3915 repository.
3928
3916
3929 Specifying a path to a repository root or Mercurial bundle will
3917 Specifying a path to a repository root or Mercurial bundle will
3930 cause lookup to operate on that repository/bundle.
3918 cause lookup to operate on that repository/bundle.
3931
3919
3932 .. container:: verbose
3920 .. container:: verbose
3933
3921
3934 Examples:
3922 Examples:
3935
3923
3936 - generate a build identifier for the working directory::
3924 - generate a build identifier for the working directory::
3937
3925
3938 hg id --id > build-id.dat
3926 hg id --id > build-id.dat
3939
3927
3940 - find the revision corresponding to a tag::
3928 - find the revision corresponding to a tag::
3941
3929
3942 hg id -n -r 1.3
3930 hg id -n -r 1.3
3943
3931
3944 - check the most recent revision of a remote repository::
3932 - check the most recent revision of a remote repository::
3945
3933
3946 hg id -r tip http://selenic.com/hg/
3934 hg id -r tip http://selenic.com/hg/
3947
3935
3948 Returns 0 if successful.
3936 Returns 0 if successful.
3949 """
3937 """
3950
3938
3951 if not repo and not source:
3939 if not repo and not source:
3952 raise util.Abort(_("there is no Mercurial repository here "
3940 raise util.Abort(_("there is no Mercurial repository here "
3953 "(.hg not found)"))
3941 "(.hg not found)"))
3954
3942
3955 hexfunc = ui.debugflag and hex or short
3943 hexfunc = ui.debugflag and hex or short
3956 default = not (num or id or branch or tags or bookmarks)
3944 default = not (num or id or branch or tags or bookmarks)
3957 output = []
3945 output = []
3958 revs = []
3946 revs = []
3959
3947
3960 if source:
3948 if source:
3961 source, branches = hg.parseurl(ui.expandpath(source))
3949 source, branches = hg.parseurl(ui.expandpath(source))
3962 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3950 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3963 repo = peer.local()
3951 repo = peer.local()
3964 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3952 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3965
3953
3966 if not repo:
3954 if not repo:
3967 if num or branch or tags:
3955 if num or branch or tags:
3968 raise util.Abort(
3956 raise util.Abort(
3969 _("can't query remote revision number, branch, or tags"))
3957 _("can't query remote revision number, branch, or tags"))
3970 if not rev and revs:
3958 if not rev and revs:
3971 rev = revs[0]
3959 rev = revs[0]
3972 if not rev:
3960 if not rev:
3973 rev = "tip"
3961 rev = "tip"
3974
3962
3975 remoterev = peer.lookup(rev)
3963 remoterev = peer.lookup(rev)
3976 if default or id:
3964 if default or id:
3977 output = [hexfunc(remoterev)]
3965 output = [hexfunc(remoterev)]
3978
3966
3979 def getbms():
3967 def getbms():
3980 bms = []
3968 bms = []
3981
3969
3982 if 'bookmarks' in peer.listkeys('namespaces'):
3970 if 'bookmarks' in peer.listkeys('namespaces'):
3983 hexremoterev = hex(remoterev)
3971 hexremoterev = hex(remoterev)
3984 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3972 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3985 if bmr == hexremoterev]
3973 if bmr == hexremoterev]
3986
3974
3987 return sorted(bms)
3975 return sorted(bms)
3988
3976
3989 if bookmarks:
3977 if bookmarks:
3990 output.extend(getbms())
3978 output.extend(getbms())
3991 elif default and not ui.quiet:
3979 elif default and not ui.quiet:
3992 # multiple bookmarks for a single parent separated by '/'
3980 # multiple bookmarks for a single parent separated by '/'
3993 bm = '/'.join(getbms())
3981 bm = '/'.join(getbms())
3994 if bm:
3982 if bm:
3995 output.append(bm)
3983 output.append(bm)
3996 else:
3984 else:
3997 if not rev:
3985 if not rev:
3998 ctx = repo[None]
3986 ctx = repo[None]
3999 parents = ctx.parents()
3987 parents = ctx.parents()
4000 changed = ""
3988 changed = ""
4001 if default or id or num:
3989 if default or id or num:
4002 if (util.any(repo.status())
3990 if (util.any(repo.status())
4003 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3991 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
4004 changed = '+'
3992 changed = '+'
4005 if default or id:
3993 if default or id:
4006 output = ["%s%s" %
3994 output = ["%s%s" %
4007 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3995 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4008 if num:
3996 if num:
4009 output.append("%s%s" %
3997 output.append("%s%s" %
4010 ('+'.join([str(p.rev()) for p in parents]), changed))
3998 ('+'.join([str(p.rev()) for p in parents]), changed))
4011 else:
3999 else:
4012 ctx = scmutil.revsingle(repo, rev)
4000 ctx = scmutil.revsingle(repo, rev)
4013 if default or id:
4001 if default or id:
4014 output = [hexfunc(ctx.node())]
4002 output = [hexfunc(ctx.node())]
4015 if num:
4003 if num:
4016 output.append(str(ctx.rev()))
4004 output.append(str(ctx.rev()))
4017
4005
4018 if default and not ui.quiet:
4006 if default and not ui.quiet:
4019 b = ctx.branch()
4007 b = ctx.branch()
4020 if b != 'default':
4008 if b != 'default':
4021 output.append("(%s)" % b)
4009 output.append("(%s)" % b)
4022
4010
4023 # multiple tags for a single parent separated by '/'
4011 # multiple tags for a single parent separated by '/'
4024 t = '/'.join(ctx.tags())
4012 t = '/'.join(ctx.tags())
4025 if t:
4013 if t:
4026 output.append(t)
4014 output.append(t)
4027
4015
4028 # multiple bookmarks for a single parent separated by '/'
4016 # multiple bookmarks for a single parent separated by '/'
4029 bm = '/'.join(ctx.bookmarks())
4017 bm = '/'.join(ctx.bookmarks())
4030 if bm:
4018 if bm:
4031 output.append(bm)
4019 output.append(bm)
4032 else:
4020 else:
4033 if branch:
4021 if branch:
4034 output.append(ctx.branch())
4022 output.append(ctx.branch())
4035
4023
4036 if tags:
4024 if tags:
4037 output.extend(ctx.tags())
4025 output.extend(ctx.tags())
4038
4026
4039 if bookmarks:
4027 if bookmarks:
4040 output.extend(ctx.bookmarks())
4028 output.extend(ctx.bookmarks())
4041
4029
4042 ui.write("%s\n" % ' '.join(output))
4030 ui.write("%s\n" % ' '.join(output))
4043
4031
4044 @command('import|patch',
4032 @command('import|patch',
4045 [('p', 'strip', 1,
4033 [('p', 'strip', 1,
4046 _('directory strip option for patch. This has the same '
4034 _('directory strip option for patch. This has the same '
4047 'meaning as the corresponding patch option'), _('NUM')),
4035 'meaning as the corresponding patch option'), _('NUM')),
4048 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4036 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4049 ('e', 'edit', False, _('invoke editor on commit messages')),
4037 ('e', 'edit', False, _('invoke editor on commit messages')),
4050 ('f', 'force', None,
4038 ('f', 'force', None,
4051 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4039 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4052 ('', 'no-commit', None,
4040 ('', 'no-commit', None,
4053 _("don't commit, just update the working directory")),
4041 _("don't commit, just update the working directory")),
4054 ('', 'bypass', None,
4042 ('', 'bypass', None,
4055 _("apply patch without touching the working directory")),
4043 _("apply patch without touching the working directory")),
4056 ('', 'partial', None,
4044 ('', 'partial', None,
4057 _('commit even if some hunks fail')),
4045 _('commit even if some hunks fail')),
4058 ('', 'exact', None,
4046 ('', 'exact', None,
4059 _('apply patch to the nodes from which it was generated')),
4047 _('apply patch to the nodes from which it was generated')),
4060 ('', 'prefix', '',
4048 ('', 'prefix', '',
4061 _('apply patch to directory relative to the root'), _('DIR')),
4049 _('apply patch to directory relative to the root'), _('DIR')),
4062 ('', 'import-branch', None,
4050 ('', 'import-branch', None,
4063 _('use any branch information in patch (implied by --exact)'))] +
4051 _('use any branch information in patch (implied by --exact)'))] +
4064 commitopts + commitopts2 + similarityopts,
4052 commitopts + commitopts2 + similarityopts,
4065 _('[OPTION]... PATCH...'))
4053 _('[OPTION]... PATCH...'))
4066 def import_(ui, repo, patch1=None, *patches, **opts):
4054 def import_(ui, repo, patch1=None, *patches, **opts):
4067 """import an ordered set of patches
4055 """import an ordered set of patches
4068
4056
4069 Import a list of patches and commit them individually (unless
4057 Import a list of patches and commit them individually (unless
4070 --no-commit is specified).
4058 --no-commit is specified).
4071
4059
4072 Because import first applies changes to the working directory,
4060 Because import first applies changes to the working directory,
4073 import will abort if there are outstanding changes.
4061 import will abort if there are outstanding changes.
4074
4062
4075 You can import a patch straight from a mail message. Even patches
4063 You can import a patch straight from a mail message. Even patches
4076 as attachments work (to use the body part, it must have type
4064 as attachments work (to use the body part, it must have type
4077 text/plain or text/x-patch). From and Subject headers of email
4065 text/plain or text/x-patch). From and Subject headers of email
4078 message are used as default committer and commit message. All
4066 message are used as default committer and commit message. All
4079 text/plain body parts before first diff are added to commit
4067 text/plain body parts before first diff are added to commit
4080 message.
4068 message.
4081
4069
4082 If the imported patch was generated by :hg:`export`, user and
4070 If the imported patch was generated by :hg:`export`, user and
4083 description from patch override values from message headers and
4071 description from patch override values from message headers and
4084 body. Values given on command line with -m/--message and -u/--user
4072 body. Values given on command line with -m/--message and -u/--user
4085 override these.
4073 override these.
4086
4074
4087 If --exact is specified, import will set the working directory to
4075 If --exact is specified, import will set the working directory to
4088 the parent of each patch before applying it, and will abort if the
4076 the parent of each patch before applying it, and will abort if the
4089 resulting changeset has a different ID than the one recorded in
4077 resulting changeset has a different ID than the one recorded in
4090 the patch. This may happen due to character set problems or other
4078 the patch. This may happen due to character set problems or other
4091 deficiencies in the text patch format.
4079 deficiencies in the text patch format.
4092
4080
4093 Use --bypass to apply and commit patches directly to the
4081 Use --bypass to apply and commit patches directly to the
4094 repository, not touching the working directory. Without --exact,
4082 repository, not touching the working directory. Without --exact,
4095 patches will be applied on top of the working directory parent
4083 patches will be applied on top of the working directory parent
4096 revision.
4084 revision.
4097
4085
4098 With -s/--similarity, hg will attempt to discover renames and
4086 With -s/--similarity, hg will attempt to discover renames and
4099 copies in the patch in the same way as :hg:`addremove`.
4087 copies in the patch in the same way as :hg:`addremove`.
4100
4088
4101 Use --partial to ensure a changeset will be created from the patch
4089 Use --partial to ensure a changeset will be created from the patch
4102 even if some hunks fail to apply. Hunks that fail to apply will be
4090 even if some hunks fail to apply. Hunks that fail to apply will be
4103 written to a <target-file>.rej file. Conflicts can then be resolved
4091 written to a <target-file>.rej file. Conflicts can then be resolved
4104 by hand before :hg:`commit --amend` is run to update the created
4092 by hand before :hg:`commit --amend` is run to update the created
4105 changeset. This flag exists to let people import patches that
4093 changeset. This flag exists to let people import patches that
4106 partially apply without losing the associated metadata (author,
4094 partially apply without losing the associated metadata (author,
4107 date, description, ...). Note that when none of the hunk applies
4095 date, description, ...). Note that when none of the hunk applies
4108 cleanly, :hg:`import --partial` will create an empty changeset,
4096 cleanly, :hg:`import --partial` will create an empty changeset,
4109 importing only the patch metadata.
4097 importing only the patch metadata.
4110
4098
4111 To read a patch from standard input, use "-" as the patch name. If
4099 To read a patch from standard input, use "-" as the patch name. If
4112 a URL is specified, the patch will be downloaded from it.
4100 a URL is specified, the patch will be downloaded from it.
4113 See :hg:`help dates` for a list of formats valid for -d/--date.
4101 See :hg:`help dates` for a list of formats valid for -d/--date.
4114
4102
4115 .. container:: verbose
4103 .. container:: verbose
4116
4104
4117 Examples:
4105 Examples:
4118
4106
4119 - import a traditional patch from a website and detect renames::
4107 - import a traditional patch from a website and detect renames::
4120
4108
4121 hg import -s 80 http://example.com/bugfix.patch
4109 hg import -s 80 http://example.com/bugfix.patch
4122
4110
4123 - import a changeset from an hgweb server::
4111 - import a changeset from an hgweb server::
4124
4112
4125 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4113 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4126
4114
4127 - import all the patches in an Unix-style mbox::
4115 - import all the patches in an Unix-style mbox::
4128
4116
4129 hg import incoming-patches.mbox
4117 hg import incoming-patches.mbox
4130
4118
4131 - attempt to exactly restore an exported changeset (not always
4119 - attempt to exactly restore an exported changeset (not always
4132 possible)::
4120 possible)::
4133
4121
4134 hg import --exact proposed-fix.patch
4122 hg import --exact proposed-fix.patch
4135
4123
4136 Returns 0 on success, 1 on partial success (see --partial).
4124 Returns 0 on success, 1 on partial success (see --partial).
4137 """
4125 """
4138
4126
4139 if not patch1:
4127 if not patch1:
4140 raise util.Abort(_('need at least one patch to import'))
4128 raise util.Abort(_('need at least one patch to import'))
4141
4129
4142 patches = (patch1,) + patches
4130 patches = (patch1,) + patches
4143
4131
4144 date = opts.get('date')
4132 date = opts.get('date')
4145 if date:
4133 if date:
4146 opts['date'] = util.parsedate(date)
4134 opts['date'] = util.parsedate(date)
4147
4135
4148 update = not opts.get('bypass')
4136 update = not opts.get('bypass')
4149 if not update and opts.get('no_commit'):
4137 if not update and opts.get('no_commit'):
4150 raise util.Abort(_('cannot use --no-commit with --bypass'))
4138 raise util.Abort(_('cannot use --no-commit with --bypass'))
4151 try:
4139 try:
4152 sim = float(opts.get('similarity') or 0)
4140 sim = float(opts.get('similarity') or 0)
4153 except ValueError:
4141 except ValueError:
4154 raise util.Abort(_('similarity must be a number'))
4142 raise util.Abort(_('similarity must be a number'))
4155 if sim < 0 or sim > 100:
4143 if sim < 0 or sim > 100:
4156 raise util.Abort(_('similarity must be between 0 and 100'))
4144 raise util.Abort(_('similarity must be between 0 and 100'))
4157 if sim and not update:
4145 if sim and not update:
4158 raise util.Abort(_('cannot use --similarity with --bypass'))
4146 raise util.Abort(_('cannot use --similarity with --bypass'))
4159 if opts.get('exact') and opts.get('edit'):
4147 if opts.get('exact') and opts.get('edit'):
4160 raise util.Abort(_('cannot use --exact with --edit'))
4148 raise util.Abort(_('cannot use --exact with --edit'))
4161 if opts.get('exact') and opts.get('prefix'):
4149 if opts.get('exact') and opts.get('prefix'):
4162 raise util.Abort(_('cannot use --exact with --prefix'))
4150 raise util.Abort(_('cannot use --exact with --prefix'))
4163
4151
4164 if update:
4152 if update:
4165 cmdutil.checkunfinished(repo)
4153 cmdutil.checkunfinished(repo)
4166 if (opts.get('exact') or not opts.get('force')) and update:
4154 if (opts.get('exact') or not opts.get('force')) and update:
4167 cmdutil.bailifchanged(repo)
4155 cmdutil.bailifchanged(repo)
4168
4156
4169 base = opts["base"]
4157 base = opts["base"]
4170 wlock = lock = tr = None
4158 wlock = lock = tr = None
4171 msgs = []
4159 msgs = []
4172 ret = 0
4160 ret = 0
4173
4161
4174
4162
4175 try:
4163 try:
4176 try:
4164 try:
4177 wlock = repo.wlock()
4165 wlock = repo.wlock()
4178 repo.dirstate.beginparentchange()
4166 repo.dirstate.beginparentchange()
4179 if not opts.get('no_commit'):
4167 if not opts.get('no_commit'):
4180 lock = repo.lock()
4168 lock = repo.lock()
4181 tr = repo.transaction('import')
4169 tr = repo.transaction('import')
4182 parents = repo.parents()
4170 parents = repo.parents()
4183 for patchurl in patches:
4171 for patchurl in patches:
4184 if patchurl == '-':
4172 if patchurl == '-':
4185 ui.status(_('applying patch from stdin\n'))
4173 ui.status(_('applying patch from stdin\n'))
4186 patchfile = ui.fin
4174 patchfile = ui.fin
4187 patchurl = 'stdin' # for error message
4175 patchurl = 'stdin' # for error message
4188 else:
4176 else:
4189 patchurl = os.path.join(base, patchurl)
4177 patchurl = os.path.join(base, patchurl)
4190 ui.status(_('applying %s\n') % patchurl)
4178 ui.status(_('applying %s\n') % patchurl)
4191 patchfile = hg.openpath(ui, patchurl)
4179 patchfile = hg.openpath(ui, patchurl)
4192
4180
4193 haspatch = False
4181 haspatch = False
4194 for hunk in patch.split(patchfile):
4182 for hunk in patch.split(patchfile):
4195 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4183 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4196 parents, opts,
4184 parents, opts,
4197 msgs, hg.clean)
4185 msgs, hg.clean)
4198 if msg:
4186 if msg:
4199 haspatch = True
4187 haspatch = True
4200 ui.note(msg + '\n')
4188 ui.note(msg + '\n')
4201 if update or opts.get('exact'):
4189 if update or opts.get('exact'):
4202 parents = repo.parents()
4190 parents = repo.parents()
4203 else:
4191 else:
4204 parents = [repo[node]]
4192 parents = [repo[node]]
4205 if rej:
4193 if rej:
4206 ui.write_err(_("patch applied partially\n"))
4194 ui.write_err(_("patch applied partially\n"))
4207 ui.write_err(_("(fix the .rej files and run "
4195 ui.write_err(_("(fix the .rej files and run "
4208 "`hg commit --amend`)\n"))
4196 "`hg commit --amend`)\n"))
4209 ret = 1
4197 ret = 1
4210 break
4198 break
4211
4199
4212 if not haspatch:
4200 if not haspatch:
4213 raise util.Abort(_('%s: no diffs found') % patchurl)
4201 raise util.Abort(_('%s: no diffs found') % patchurl)
4214
4202
4215 if tr:
4203 if tr:
4216 tr.close()
4204 tr.close()
4217 if msgs:
4205 if msgs:
4218 repo.savecommitmessage('\n* * *\n'.join(msgs))
4206 repo.savecommitmessage('\n* * *\n'.join(msgs))
4219 repo.dirstate.endparentchange()
4207 repo.dirstate.endparentchange()
4220 return ret
4208 return ret
4221 except: # re-raises
4209 except: # re-raises
4222 # wlock.release() indirectly calls dirstate.write(): since
4210 # wlock.release() indirectly calls dirstate.write(): since
4223 # we're crashing, we do not want to change the working dir
4211 # we're crashing, we do not want to change the working dir
4224 # parent after all, so make sure it writes nothing
4212 # parent after all, so make sure it writes nothing
4225 repo.dirstate.invalidate()
4213 repo.dirstate.invalidate()
4226 raise
4214 raise
4227 finally:
4215 finally:
4228 if tr:
4216 if tr:
4229 tr.release()
4217 tr.release()
4230 release(lock, wlock)
4218 release(lock, wlock)
4231
4219
4232 @command('incoming|in',
4220 @command('incoming|in',
4233 [('f', 'force', None,
4221 [('f', 'force', None,
4234 _('run even if remote repository is unrelated')),
4222 _('run even if remote repository is unrelated')),
4235 ('n', 'newest-first', None, _('show newest record first')),
4223 ('n', 'newest-first', None, _('show newest record first')),
4236 ('', 'bundle', '',
4224 ('', 'bundle', '',
4237 _('file to store the bundles into'), _('FILE')),
4225 _('file to store the bundles into'), _('FILE')),
4238 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4226 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4239 ('B', 'bookmarks', False, _("compare bookmarks")),
4227 ('B', 'bookmarks', False, _("compare bookmarks")),
4240 ('b', 'branch', [],
4228 ('b', 'branch', [],
4241 _('a specific branch you would like to pull'), _('BRANCH')),
4229 _('a specific branch you would like to pull'), _('BRANCH')),
4242 ] + logopts + remoteopts + subrepoopts,
4230 ] + logopts + remoteopts + subrepoopts,
4243 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4231 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4244 def incoming(ui, repo, source="default", **opts):
4232 def incoming(ui, repo, source="default", **opts):
4245 """show new changesets found in source
4233 """show new changesets found in source
4246
4234
4247 Show new changesets found in the specified path/URL or the default
4235 Show new changesets found in the specified path/URL or the default
4248 pull location. These are the changesets that would have been pulled
4236 pull location. These are the changesets that would have been pulled
4249 if a pull at the time you issued this command.
4237 if a pull at the time you issued this command.
4250
4238
4251 See pull for valid source format details.
4239 See pull for valid source format details.
4252
4240
4253 .. container:: verbose
4241 .. container:: verbose
4254
4242
4255 For remote repository, using --bundle avoids downloading the
4243 For remote repository, using --bundle avoids downloading the
4256 changesets twice if the incoming is followed by a pull.
4244 changesets twice if the incoming is followed by a pull.
4257
4245
4258 Examples:
4246 Examples:
4259
4247
4260 - show incoming changes with patches and full description::
4248 - show incoming changes with patches and full description::
4261
4249
4262 hg incoming -vp
4250 hg incoming -vp
4263
4251
4264 - show incoming changes excluding merges, store a bundle::
4252 - show incoming changes excluding merges, store a bundle::
4265
4253
4266 hg in -vpM --bundle incoming.hg
4254 hg in -vpM --bundle incoming.hg
4267 hg pull incoming.hg
4255 hg pull incoming.hg
4268
4256
4269 - briefly list changes inside a bundle::
4257 - briefly list changes inside a bundle::
4270
4258
4271 hg in changes.hg -T "{desc|firstline}\\n"
4259 hg in changes.hg -T "{desc|firstline}\\n"
4272
4260
4273 Returns 0 if there are incoming changes, 1 otherwise.
4261 Returns 0 if there are incoming changes, 1 otherwise.
4274 """
4262 """
4275 if opts.get('graph'):
4263 if opts.get('graph'):
4276 cmdutil.checkunsupportedgraphflags([], opts)
4264 cmdutil.checkunsupportedgraphflags([], opts)
4277 def display(other, chlist, displayer):
4265 def display(other, chlist, displayer):
4278 revdag = cmdutil.graphrevs(other, chlist, opts)
4266 revdag = cmdutil.graphrevs(other, chlist, opts)
4279 showparents = [ctx.node() for ctx in repo[None].parents()]
4267 showparents = [ctx.node() for ctx in repo[None].parents()]
4280 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4268 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4281 graphmod.asciiedges)
4269 graphmod.asciiedges)
4282
4270
4283 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4271 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4284 return 0
4272 return 0
4285
4273
4286 if opts.get('bundle') and opts.get('subrepos'):
4274 if opts.get('bundle') and opts.get('subrepos'):
4287 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4275 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4288
4276
4289 if opts.get('bookmarks'):
4277 if opts.get('bookmarks'):
4290 source, branches = hg.parseurl(ui.expandpath(source),
4278 source, branches = hg.parseurl(ui.expandpath(source),
4291 opts.get('branch'))
4279 opts.get('branch'))
4292 other = hg.peer(repo, opts, source)
4280 other = hg.peer(repo, opts, source)
4293 if 'bookmarks' not in other.listkeys('namespaces'):
4281 if 'bookmarks' not in other.listkeys('namespaces'):
4294 ui.warn(_("remote doesn't support bookmarks\n"))
4282 ui.warn(_("remote doesn't support bookmarks\n"))
4295 return 0
4283 return 0
4296 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4284 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4297 return bookmarks.diff(ui, repo, other)
4285 return bookmarks.diff(ui, repo, other)
4298
4286
4299 repo._subtoppath = ui.expandpath(source)
4287 repo._subtoppath = ui.expandpath(source)
4300 try:
4288 try:
4301 return hg.incoming(ui, repo, source, opts)
4289 return hg.incoming(ui, repo, source, opts)
4302 finally:
4290 finally:
4303 del repo._subtoppath
4291 del repo._subtoppath
4304
4292
4305
4293
4306 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4294 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4307 norepo=True)
4295 norepo=True)
4308 def init(ui, dest=".", **opts):
4296 def init(ui, dest=".", **opts):
4309 """create a new repository in the given directory
4297 """create a new repository in the given directory
4310
4298
4311 Initialize a new repository in the given directory. If the given
4299 Initialize a new repository in the given directory. If the given
4312 directory does not exist, it will be created.
4300 directory does not exist, it will be created.
4313
4301
4314 If no directory is given, the current directory is used.
4302 If no directory is given, the current directory is used.
4315
4303
4316 It is possible to specify an ``ssh://`` URL as the destination.
4304 It is possible to specify an ``ssh://`` URL as the destination.
4317 See :hg:`help urls` for more information.
4305 See :hg:`help urls` for more information.
4318
4306
4319 Returns 0 on success.
4307 Returns 0 on success.
4320 """
4308 """
4321 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4309 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4322
4310
4323 @command('locate',
4311 @command('locate',
4324 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4312 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4325 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4313 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4326 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4314 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4327 ] + walkopts,
4315 ] + walkopts,
4328 _('[OPTION]... [PATTERN]...'))
4316 _('[OPTION]... [PATTERN]...'))
4329 def locate(ui, repo, *pats, **opts):
4317 def locate(ui, repo, *pats, **opts):
4330 """locate files matching specific patterns (DEPRECATED)
4318 """locate files matching specific patterns (DEPRECATED)
4331
4319
4332 Print files under Mercurial control in the working directory whose
4320 Print files under Mercurial control in the working directory whose
4333 names match the given patterns.
4321 names match the given patterns.
4334
4322
4335 By default, this command searches all directories in the working
4323 By default, this command searches all directories in the working
4336 directory. To search just the current directory and its
4324 directory. To search just the current directory and its
4337 subdirectories, use "--include .".
4325 subdirectories, use "--include .".
4338
4326
4339 If no patterns are given to match, this command prints the names
4327 If no patterns are given to match, this command prints the names
4340 of all files under Mercurial control in the working directory.
4328 of all files under Mercurial control in the working directory.
4341
4329
4342 If you want to feed the output of this command into the "xargs"
4330 If you want to feed the output of this command into the "xargs"
4343 command, use the -0 option to both this command and "xargs". This
4331 command, use the -0 option to both this command and "xargs". This
4344 will avoid the problem of "xargs" treating single filenames that
4332 will avoid the problem of "xargs" treating single filenames that
4345 contain whitespace as multiple filenames.
4333 contain whitespace as multiple filenames.
4346
4334
4347 See :hg:`help files` for a more versatile command.
4335 See :hg:`help files` for a more versatile command.
4348
4336
4349 Returns 0 if a match is found, 1 otherwise.
4337 Returns 0 if a match is found, 1 otherwise.
4350 """
4338 """
4351 end = opts.get('print0') and '\0' or '\n'
4339 end = opts.get('print0') and '\0' or '\n'
4352 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4340 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4353
4341
4354 ret = 1
4342 ret = 1
4355 ctx = repo[rev]
4343 ctx = repo[rev]
4356 m = scmutil.match(ctx, pats, opts, default='relglob')
4344 m = scmutil.match(ctx, pats, opts, default='relglob')
4357 m.bad = lambda x, y: False
4345 m.bad = lambda x, y: False
4358
4346
4359 for abs in ctx.matches(m):
4347 for abs in ctx.matches(m):
4360 if opts.get('fullpath'):
4348 if opts.get('fullpath'):
4361 ui.write(repo.wjoin(abs), end)
4349 ui.write(repo.wjoin(abs), end)
4362 else:
4350 else:
4363 ui.write(((pats and m.rel(abs)) or abs), end)
4351 ui.write(((pats and m.rel(abs)) or abs), end)
4364 ret = 0
4352 ret = 0
4365
4353
4366 return ret
4354 return ret
4367
4355
4368 @command('^log|history',
4356 @command('^log|history',
4369 [('f', 'follow', None,
4357 [('f', 'follow', None,
4370 _('follow changeset history, or file history across copies and renames')),
4358 _('follow changeset history, or file history across copies and renames')),
4371 ('', 'follow-first', None,
4359 ('', 'follow-first', None,
4372 _('only follow the first parent of merge changesets (DEPRECATED)')),
4360 _('only follow the first parent of merge changesets (DEPRECATED)')),
4373 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4361 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4374 ('C', 'copies', None, _('show copied files')),
4362 ('C', 'copies', None, _('show copied files')),
4375 ('k', 'keyword', [],
4363 ('k', 'keyword', [],
4376 _('do case-insensitive search for a given text'), _('TEXT')),
4364 _('do case-insensitive search for a given text'), _('TEXT')),
4377 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4365 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4378 ('', 'removed', None, _('include revisions where files were removed')),
4366 ('', 'removed', None, _('include revisions where files were removed')),
4379 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4367 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4380 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4368 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4381 ('', 'only-branch', [],
4369 ('', 'only-branch', [],
4382 _('show only changesets within the given named branch (DEPRECATED)'),
4370 _('show only changesets within the given named branch (DEPRECATED)'),
4383 _('BRANCH')),
4371 _('BRANCH')),
4384 ('b', 'branch', [],
4372 ('b', 'branch', [],
4385 _('show changesets within the given named branch'), _('BRANCH')),
4373 _('show changesets within the given named branch'), _('BRANCH')),
4386 ('P', 'prune', [],
4374 ('P', 'prune', [],
4387 _('do not display revision or any of its ancestors'), _('REV')),
4375 _('do not display revision or any of its ancestors'), _('REV')),
4388 ] + logopts + walkopts,
4376 ] + logopts + walkopts,
4389 _('[OPTION]... [FILE]'),
4377 _('[OPTION]... [FILE]'),
4390 inferrepo=True)
4378 inferrepo=True)
4391 def log(ui, repo, *pats, **opts):
4379 def log(ui, repo, *pats, **opts):
4392 """show revision history of entire repository or files
4380 """show revision history of entire repository or files
4393
4381
4394 Print the revision history of the specified files or the entire
4382 Print the revision history of the specified files or the entire
4395 project.
4383 project.
4396
4384
4397 If no revision range is specified, the default is ``tip:0`` unless
4385 If no revision range is specified, the default is ``tip:0`` unless
4398 --follow is set, in which case the working directory parent is
4386 --follow is set, in which case the working directory parent is
4399 used as the starting revision.
4387 used as the starting revision.
4400
4388
4401 File history is shown without following rename or copy history of
4389 File history is shown without following rename or copy history of
4402 files. Use -f/--follow with a filename to follow history across
4390 files. Use -f/--follow with a filename to follow history across
4403 renames and copies. --follow without a filename will only show
4391 renames and copies. --follow without a filename will only show
4404 ancestors or descendants of the starting revision.
4392 ancestors or descendants of the starting revision.
4405
4393
4406 By default this command prints revision number and changeset id,
4394 By default this command prints revision number and changeset id,
4407 tags, non-trivial parents, user, date and time, and a summary for
4395 tags, non-trivial parents, user, date and time, and a summary for
4408 each commit. When the -v/--verbose switch is used, the list of
4396 each commit. When the -v/--verbose switch is used, the list of
4409 changed files and full commit message are shown.
4397 changed files and full commit message are shown.
4410
4398
4411 With --graph the revisions are shown as an ASCII art DAG with the most
4399 With --graph the revisions are shown as an ASCII art DAG with the most
4412 recent changeset at the top.
4400 recent changeset at the top.
4413 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4401 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4414 and '+' represents a fork where the changeset from the lines below is a
4402 and '+' represents a fork where the changeset from the lines below is a
4415 parent of the 'o' merge on the same line.
4403 parent of the 'o' merge on the same line.
4416
4404
4417 .. note::
4405 .. note::
4418
4406
4419 log -p/--patch may generate unexpected diff output for merge
4407 log -p/--patch may generate unexpected diff output for merge
4420 changesets, as it will only compare the merge changeset against
4408 changesets, as it will only compare the merge changeset against
4421 its first parent. Also, only files different from BOTH parents
4409 its first parent. Also, only files different from BOTH parents
4422 will appear in files:.
4410 will appear in files:.
4423
4411
4424 .. note::
4412 .. note::
4425
4413
4426 for performance reasons, log FILE may omit duplicate changes
4414 for performance reasons, log FILE may omit duplicate changes
4427 made on branches and will not show removals or mode changes. To
4415 made on branches and will not show removals or mode changes. To
4428 see all such changes, use the --removed switch.
4416 see all such changes, use the --removed switch.
4429
4417
4430 .. container:: verbose
4418 .. container:: verbose
4431
4419
4432 Some examples:
4420 Some examples:
4433
4421
4434 - changesets with full descriptions and file lists::
4422 - changesets with full descriptions and file lists::
4435
4423
4436 hg log -v
4424 hg log -v
4437
4425
4438 - changesets ancestral to the working directory::
4426 - changesets ancestral to the working directory::
4439
4427
4440 hg log -f
4428 hg log -f
4441
4429
4442 - last 10 commits on the current branch::
4430 - last 10 commits on the current branch::
4443
4431
4444 hg log -l 10 -b .
4432 hg log -l 10 -b .
4445
4433
4446 - changesets showing all modifications of a file, including removals::
4434 - changesets showing all modifications of a file, including removals::
4447
4435
4448 hg log --removed file.c
4436 hg log --removed file.c
4449
4437
4450 - all changesets that touch a directory, with diffs, excluding merges::
4438 - all changesets that touch a directory, with diffs, excluding merges::
4451
4439
4452 hg log -Mp lib/
4440 hg log -Mp lib/
4453
4441
4454 - all revision numbers that match a keyword::
4442 - all revision numbers that match a keyword::
4455
4443
4456 hg log -k bug --template "{rev}\\n"
4444 hg log -k bug --template "{rev}\\n"
4457
4445
4458 - list available log templates::
4446 - list available log templates::
4459
4447
4460 hg log -T list
4448 hg log -T list
4461
4449
4462 - check if a given changeset is included in a tagged release::
4450 - check if a given changeset is included in a tagged release::
4463
4451
4464 hg log -r "a21ccf and ancestor(1.9)"
4452 hg log -r "a21ccf and ancestor(1.9)"
4465
4453
4466 - find all changesets by some user in a date range::
4454 - find all changesets by some user in a date range::
4467
4455
4468 hg log -k alice -d "may 2008 to jul 2008"
4456 hg log -k alice -d "may 2008 to jul 2008"
4469
4457
4470 - summary of all changesets after the last tag::
4458 - summary of all changesets after the last tag::
4471
4459
4472 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4460 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4473
4461
4474 See :hg:`help dates` for a list of formats valid for -d/--date.
4462 See :hg:`help dates` for a list of formats valid for -d/--date.
4475
4463
4476 See :hg:`help revisions` and :hg:`help revsets` for more about
4464 See :hg:`help revisions` and :hg:`help revsets` for more about
4477 specifying revisions.
4465 specifying revisions.
4478
4466
4479 See :hg:`help templates` for more about pre-packaged styles and
4467 See :hg:`help templates` for more about pre-packaged styles and
4480 specifying custom templates.
4468 specifying custom templates.
4481
4469
4482 Returns 0 on success.
4470 Returns 0 on success.
4483
4471
4484 """
4472 """
4485 if opts.get('follow') and opts.get('rev'):
4473 if opts.get('follow') and opts.get('rev'):
4486 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4474 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4487 del opts['follow']
4475 del opts['follow']
4488
4476
4489 if opts.get('graph'):
4477 if opts.get('graph'):
4490 return cmdutil.graphlog(ui, repo, *pats, **opts)
4478 return cmdutil.graphlog(ui, repo, *pats, **opts)
4491
4479
4492 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4480 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4493 limit = cmdutil.loglimit(opts)
4481 limit = cmdutil.loglimit(opts)
4494 count = 0
4482 count = 0
4495
4483
4496 getrenamed = None
4484 getrenamed = None
4497 if opts.get('copies'):
4485 if opts.get('copies'):
4498 endrev = None
4486 endrev = None
4499 if opts.get('rev'):
4487 if opts.get('rev'):
4500 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4488 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4501 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4489 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4502
4490
4503 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4491 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4504 for rev in revs:
4492 for rev in revs:
4505 if count == limit:
4493 if count == limit:
4506 break
4494 break
4507 ctx = repo[rev]
4495 ctx = repo[rev]
4508 copies = None
4496 copies = None
4509 if getrenamed is not None and rev:
4497 if getrenamed is not None and rev:
4510 copies = []
4498 copies = []
4511 for fn in ctx.files():
4499 for fn in ctx.files():
4512 rename = getrenamed(fn, rev)
4500 rename = getrenamed(fn, rev)
4513 if rename:
4501 if rename:
4514 copies.append((fn, rename[0]))
4502 copies.append((fn, rename[0]))
4515 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4503 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4516 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4504 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4517 if displayer.flush(rev):
4505 if displayer.flush(rev):
4518 count += 1
4506 count += 1
4519
4507
4520 displayer.close()
4508 displayer.close()
4521
4509
4522 @command('manifest',
4510 @command('manifest',
4523 [('r', 'rev', '', _('revision to display'), _('REV')),
4511 [('r', 'rev', '', _('revision to display'), _('REV')),
4524 ('', 'all', False, _("list files from all revisions"))]
4512 ('', 'all', False, _("list files from all revisions"))]
4525 + formatteropts,
4513 + formatteropts,
4526 _('[-r REV]'))
4514 _('[-r REV]'))
4527 def manifest(ui, repo, node=None, rev=None, **opts):
4515 def manifest(ui, repo, node=None, rev=None, **opts):
4528 """output the current or given revision of the project manifest
4516 """output the current or given revision of the project manifest
4529
4517
4530 Print a list of version controlled files for the given revision.
4518 Print a list of version controlled files for the given revision.
4531 If no revision is given, the first parent of the working directory
4519 If no revision is given, the first parent of the working directory
4532 is used, or the null revision if no revision is checked out.
4520 is used, or the null revision if no revision is checked out.
4533
4521
4534 With -v, print file permissions, symlink and executable bits.
4522 With -v, print file permissions, symlink and executable bits.
4535 With --debug, print file revision hashes.
4523 With --debug, print file revision hashes.
4536
4524
4537 If option --all is specified, the list of all files from all revisions
4525 If option --all is specified, the list of all files from all revisions
4538 is printed. This includes deleted and renamed files.
4526 is printed. This includes deleted and renamed files.
4539
4527
4540 Returns 0 on success.
4528 Returns 0 on success.
4541 """
4529 """
4542
4530
4543 fm = ui.formatter('manifest', opts)
4531 fm = ui.formatter('manifest', opts)
4544
4532
4545 if opts.get('all'):
4533 if opts.get('all'):
4546 if rev or node:
4534 if rev or node:
4547 raise util.Abort(_("can't specify a revision with --all"))
4535 raise util.Abort(_("can't specify a revision with --all"))
4548
4536
4549 res = []
4537 res = []
4550 prefix = "data/"
4538 prefix = "data/"
4551 suffix = ".i"
4539 suffix = ".i"
4552 plen = len(prefix)
4540 plen = len(prefix)
4553 slen = len(suffix)
4541 slen = len(suffix)
4554 lock = repo.lock()
4542 lock = repo.lock()
4555 try:
4543 try:
4556 for fn, b, size in repo.store.datafiles():
4544 for fn, b, size in repo.store.datafiles():
4557 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4545 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4558 res.append(fn[plen:-slen])
4546 res.append(fn[plen:-slen])
4559 finally:
4547 finally:
4560 lock.release()
4548 lock.release()
4561 for f in res:
4549 for f in res:
4562 fm.startitem()
4550 fm.startitem()
4563 fm.write("path", '%s\n', f)
4551 fm.write("path", '%s\n', f)
4564 fm.end()
4552 fm.end()
4565 return
4553 return
4566
4554
4567 if rev and node:
4555 if rev and node:
4568 raise util.Abort(_("please specify just one revision"))
4556 raise util.Abort(_("please specify just one revision"))
4569
4557
4570 if not node:
4558 if not node:
4571 node = rev
4559 node = rev
4572
4560
4573 char = {'l': '@', 'x': '*', '': ''}
4561 char = {'l': '@', 'x': '*', '': ''}
4574 mode = {'l': '644', 'x': '755', '': '644'}
4562 mode = {'l': '644', 'x': '755', '': '644'}
4575 ctx = scmutil.revsingle(repo, node)
4563 ctx = scmutil.revsingle(repo, node)
4576 mf = ctx.manifest()
4564 mf = ctx.manifest()
4577 for f in ctx:
4565 for f in ctx:
4578 fm.startitem()
4566 fm.startitem()
4579 fl = ctx[f].flags()
4567 fl = ctx[f].flags()
4580 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4568 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4581 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4569 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4582 fm.write('path', '%s\n', f)
4570 fm.write('path', '%s\n', f)
4583 fm.end()
4571 fm.end()
4584
4572
4585 @command('^merge',
4573 @command('^merge',
4586 [('f', 'force', None,
4574 [('f', 'force', None,
4587 _('force a merge including outstanding changes (DEPRECATED)')),
4575 _('force a merge including outstanding changes (DEPRECATED)')),
4588 ('r', 'rev', '', _('revision to merge'), _('REV')),
4576 ('r', 'rev', '', _('revision to merge'), _('REV')),
4589 ('P', 'preview', None,
4577 ('P', 'preview', None,
4590 _('review revisions to merge (no merge is performed)'))
4578 _('review revisions to merge (no merge is performed)'))
4591 ] + mergetoolopts,
4579 ] + mergetoolopts,
4592 _('[-P] [-f] [[-r] REV]'))
4580 _('[-P] [-f] [[-r] REV]'))
4593 def merge(ui, repo, node=None, **opts):
4581 def merge(ui, repo, node=None, **opts):
4594 """merge another revision into working directory
4582 """merge another revision into working directory
4595
4583
4596 The current working directory is updated with all changes made in
4584 The current working directory is updated with all changes made in
4597 the requested revision since the last common predecessor revision.
4585 the requested revision since the last common predecessor revision.
4598
4586
4599 Files that changed between either parent are marked as changed for
4587 Files that changed between either parent are marked as changed for
4600 the next commit and a commit must be performed before any further
4588 the next commit and a commit must be performed before any further
4601 updates to the repository are allowed. The next commit will have
4589 updates to the repository are allowed. The next commit will have
4602 two parents.
4590 two parents.
4603
4591
4604 ``--tool`` can be used to specify the merge tool used for file
4592 ``--tool`` can be used to specify the merge tool used for file
4605 merges. It overrides the HGMERGE environment variable and your
4593 merges. It overrides the HGMERGE environment variable and your
4606 configuration files. See :hg:`help merge-tools` for options.
4594 configuration files. See :hg:`help merge-tools` for options.
4607
4595
4608 If no revision is specified, the working directory's parent is a
4596 If no revision is specified, the working directory's parent is a
4609 head revision, and the current branch contains exactly one other
4597 head revision, and the current branch contains exactly one other
4610 head, the other head is merged with by default. Otherwise, an
4598 head, the other head is merged with by default. Otherwise, an
4611 explicit revision with which to merge with must be provided.
4599 explicit revision with which to merge with must be provided.
4612
4600
4613 :hg:`resolve` must be used to resolve unresolved files.
4601 :hg:`resolve` must be used to resolve unresolved files.
4614
4602
4615 To undo an uncommitted merge, use :hg:`update --clean .` which
4603 To undo an uncommitted merge, use :hg:`update --clean .` which
4616 will check out a clean copy of the original merge parent, losing
4604 will check out a clean copy of the original merge parent, losing
4617 all changes.
4605 all changes.
4618
4606
4619 Returns 0 on success, 1 if there are unresolved files.
4607 Returns 0 on success, 1 if there are unresolved files.
4620 """
4608 """
4621
4609
4622 if opts.get('rev') and node:
4610 if opts.get('rev') and node:
4623 raise util.Abort(_("please specify just one revision"))
4611 raise util.Abort(_("please specify just one revision"))
4624 if not node:
4612 if not node:
4625 node = opts.get('rev')
4613 node = opts.get('rev')
4626
4614
4627 if node:
4615 if node:
4628 node = scmutil.revsingle(repo, node).node()
4616 node = scmutil.revsingle(repo, node).node()
4629
4617
4630 if not node and repo._bookmarkcurrent:
4618 if not node and repo._bookmarkcurrent:
4631 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4619 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4632 curhead = repo[repo._bookmarkcurrent].node()
4620 curhead = repo[repo._bookmarkcurrent].node()
4633 if len(bmheads) == 2:
4621 if len(bmheads) == 2:
4634 if curhead == bmheads[0]:
4622 if curhead == bmheads[0]:
4635 node = bmheads[1]
4623 node = bmheads[1]
4636 else:
4624 else:
4637 node = bmheads[0]
4625 node = bmheads[0]
4638 elif len(bmheads) > 2:
4626 elif len(bmheads) > 2:
4639 raise util.Abort(_("multiple matching bookmarks to merge - "
4627 raise util.Abort(_("multiple matching bookmarks to merge - "
4640 "please merge with an explicit rev or bookmark"),
4628 "please merge with an explicit rev or bookmark"),
4641 hint=_("run 'hg heads' to see all heads"))
4629 hint=_("run 'hg heads' to see all heads"))
4642 elif len(bmheads) <= 1:
4630 elif len(bmheads) <= 1:
4643 raise util.Abort(_("no matching bookmark to merge - "
4631 raise util.Abort(_("no matching bookmark to merge - "
4644 "please merge with an explicit rev or bookmark"),
4632 "please merge with an explicit rev or bookmark"),
4645 hint=_("run 'hg heads' to see all heads"))
4633 hint=_("run 'hg heads' to see all heads"))
4646
4634
4647 if not node and not repo._bookmarkcurrent:
4635 if not node and not repo._bookmarkcurrent:
4648 branch = repo[None].branch()
4636 branch = repo[None].branch()
4649 bheads = repo.branchheads(branch)
4637 bheads = repo.branchheads(branch)
4650 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4638 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4651
4639
4652 if len(nbhs) > 2:
4640 if len(nbhs) > 2:
4653 raise util.Abort(_("branch '%s' has %d heads - "
4641 raise util.Abort(_("branch '%s' has %d heads - "
4654 "please merge with an explicit rev")
4642 "please merge with an explicit rev")
4655 % (branch, len(bheads)),
4643 % (branch, len(bheads)),
4656 hint=_("run 'hg heads .' to see heads"))
4644 hint=_("run 'hg heads .' to see heads"))
4657
4645
4658 parent = repo.dirstate.p1()
4646 parent = repo.dirstate.p1()
4659 if len(nbhs) <= 1:
4647 if len(nbhs) <= 1:
4660 if len(bheads) > 1:
4648 if len(bheads) > 1:
4661 raise util.Abort(_("heads are bookmarked - "
4649 raise util.Abort(_("heads are bookmarked - "
4662 "please merge with an explicit rev"),
4650 "please merge with an explicit rev"),
4663 hint=_("run 'hg heads' to see all heads"))
4651 hint=_("run 'hg heads' to see all heads"))
4664 if len(repo.heads()) > 1:
4652 if len(repo.heads()) > 1:
4665 raise util.Abort(_("branch '%s' has one head - "
4653 raise util.Abort(_("branch '%s' has one head - "
4666 "please merge with an explicit rev")
4654 "please merge with an explicit rev")
4667 % branch,
4655 % branch,
4668 hint=_("run 'hg heads' to see all heads"))
4656 hint=_("run 'hg heads' to see all heads"))
4669 msg, hint = _('nothing to merge'), None
4657 msg, hint = _('nothing to merge'), None
4670 if parent != repo.lookup(branch):
4658 if parent != repo.lookup(branch):
4671 hint = _("use 'hg update' instead")
4659 hint = _("use 'hg update' instead")
4672 raise util.Abort(msg, hint=hint)
4660 raise util.Abort(msg, hint=hint)
4673
4661
4674 if parent not in bheads:
4662 if parent not in bheads:
4675 raise util.Abort(_('working directory not at a head revision'),
4663 raise util.Abort(_('working directory not at a head revision'),
4676 hint=_("use 'hg update' or merge with an "
4664 hint=_("use 'hg update' or merge with an "
4677 "explicit revision"))
4665 "explicit revision"))
4678 if parent == nbhs[0]:
4666 if parent == nbhs[0]:
4679 node = nbhs[-1]
4667 node = nbhs[-1]
4680 else:
4668 else:
4681 node = nbhs[0]
4669 node = nbhs[0]
4682
4670
4683 if opts.get('preview'):
4671 if opts.get('preview'):
4684 # find nodes that are ancestors of p2 but not of p1
4672 # find nodes that are ancestors of p2 but not of p1
4685 p1 = repo.lookup('.')
4673 p1 = repo.lookup('.')
4686 p2 = repo.lookup(node)
4674 p2 = repo.lookup(node)
4687 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4675 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4688
4676
4689 displayer = cmdutil.show_changeset(ui, repo, opts)
4677 displayer = cmdutil.show_changeset(ui, repo, opts)
4690 for node in nodes:
4678 for node in nodes:
4691 displayer.show(repo[node])
4679 displayer.show(repo[node])
4692 displayer.close()
4680 displayer.close()
4693 return 0
4681 return 0
4694
4682
4695 try:
4683 try:
4696 # ui.forcemerge is an internal variable, do not document
4684 # ui.forcemerge is an internal variable, do not document
4697 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4685 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4698 return hg.merge(repo, node, force=opts.get('force'))
4686 return hg.merge(repo, node, force=opts.get('force'))
4699 finally:
4687 finally:
4700 ui.setconfig('ui', 'forcemerge', '', 'merge')
4688 ui.setconfig('ui', 'forcemerge', '', 'merge')
4701
4689
4702 @command('outgoing|out',
4690 @command('outgoing|out',
4703 [('f', 'force', None, _('run even when the destination is unrelated')),
4691 [('f', 'force', None, _('run even when the destination is unrelated')),
4704 ('r', 'rev', [],
4692 ('r', 'rev', [],
4705 _('a changeset intended to be included in the destination'), _('REV')),
4693 _('a changeset intended to be included in the destination'), _('REV')),
4706 ('n', 'newest-first', None, _('show newest record first')),
4694 ('n', 'newest-first', None, _('show newest record first')),
4707 ('B', 'bookmarks', False, _('compare bookmarks')),
4695 ('B', 'bookmarks', False, _('compare bookmarks')),
4708 ('b', 'branch', [], _('a specific branch you would like to push'),
4696 ('b', 'branch', [], _('a specific branch you would like to push'),
4709 _('BRANCH')),
4697 _('BRANCH')),
4710 ] + logopts + remoteopts + subrepoopts,
4698 ] + logopts + remoteopts + subrepoopts,
4711 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4699 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4712 def outgoing(ui, repo, dest=None, **opts):
4700 def outgoing(ui, repo, dest=None, **opts):
4713 """show changesets not found in the destination
4701 """show changesets not found in the destination
4714
4702
4715 Show changesets not found in the specified destination repository
4703 Show changesets not found in the specified destination repository
4716 or the default push location. These are the changesets that would
4704 or the default push location. These are the changesets that would
4717 be pushed if a push was requested.
4705 be pushed if a push was requested.
4718
4706
4719 See pull for details of valid destination formats.
4707 See pull for details of valid destination formats.
4720
4708
4721 Returns 0 if there are outgoing changes, 1 otherwise.
4709 Returns 0 if there are outgoing changes, 1 otherwise.
4722 """
4710 """
4723 if opts.get('graph'):
4711 if opts.get('graph'):
4724 cmdutil.checkunsupportedgraphflags([], opts)
4712 cmdutil.checkunsupportedgraphflags([], opts)
4725 o, other = hg._outgoing(ui, repo, dest, opts)
4713 o, other = hg._outgoing(ui, repo, dest, opts)
4726 if not o:
4714 if not o:
4727 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4715 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4728 return
4716 return
4729
4717
4730 revdag = cmdutil.graphrevs(repo, o, opts)
4718 revdag = cmdutil.graphrevs(repo, o, opts)
4731 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4719 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4732 showparents = [ctx.node() for ctx in repo[None].parents()]
4720 showparents = [ctx.node() for ctx in repo[None].parents()]
4733 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4721 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4734 graphmod.asciiedges)
4722 graphmod.asciiedges)
4735 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4723 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4736 return 0
4724 return 0
4737
4725
4738 if opts.get('bookmarks'):
4726 if opts.get('bookmarks'):
4739 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4727 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4740 dest, branches = hg.parseurl(dest, opts.get('branch'))
4728 dest, branches = hg.parseurl(dest, opts.get('branch'))
4741 other = hg.peer(repo, opts, dest)
4729 other = hg.peer(repo, opts, dest)
4742 if 'bookmarks' not in other.listkeys('namespaces'):
4730 if 'bookmarks' not in other.listkeys('namespaces'):
4743 ui.warn(_("remote doesn't support bookmarks\n"))
4731 ui.warn(_("remote doesn't support bookmarks\n"))
4744 return 0
4732 return 0
4745 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4733 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4746 return bookmarks.diff(ui, other, repo)
4734 return bookmarks.diff(ui, other, repo)
4747
4735
4748 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4736 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4749 try:
4737 try:
4750 return hg.outgoing(ui, repo, dest, opts)
4738 return hg.outgoing(ui, repo, dest, opts)
4751 finally:
4739 finally:
4752 del repo._subtoppath
4740 del repo._subtoppath
4753
4741
4754 @command('parents',
4742 @command('parents',
4755 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4743 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4756 ] + templateopts,
4744 ] + templateopts,
4757 _('[-r REV] [FILE]'),
4745 _('[-r REV] [FILE]'),
4758 inferrepo=True)
4746 inferrepo=True)
4759 def parents(ui, repo, file_=None, **opts):
4747 def parents(ui, repo, file_=None, **opts):
4760 """show the parents of the working directory or revision (DEPRECATED)
4748 """show the parents of the working directory or revision (DEPRECATED)
4761
4749
4762 Print the working directory's parent revisions. If a revision is
4750 Print the working directory's parent revisions. If a revision is
4763 given via -r/--rev, the parent of that revision will be printed.
4751 given via -r/--rev, the parent of that revision will be printed.
4764 If a file argument is given, the revision in which the file was
4752 If a file argument is given, the revision in which the file was
4765 last changed (before the working directory revision or the
4753 last changed (before the working directory revision or the
4766 argument to --rev if given) is printed.
4754 argument to --rev if given) is printed.
4767
4755
4768 See :hg:`summary` and :hg:`help revsets` for related information.
4756 See :hg:`summary` and :hg:`help revsets` for related information.
4769
4757
4770 Returns 0 on success.
4758 Returns 0 on success.
4771 """
4759 """
4772
4760
4773 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4761 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4774
4762
4775 if file_:
4763 if file_:
4776 m = scmutil.match(ctx, (file_,), opts)
4764 m = scmutil.match(ctx, (file_,), opts)
4777 if m.anypats() or len(m.files()) != 1:
4765 if m.anypats() or len(m.files()) != 1:
4778 raise util.Abort(_('can only specify an explicit filename'))
4766 raise util.Abort(_('can only specify an explicit filename'))
4779 file_ = m.files()[0]
4767 file_ = m.files()[0]
4780 filenodes = []
4768 filenodes = []
4781 for cp in ctx.parents():
4769 for cp in ctx.parents():
4782 if not cp:
4770 if not cp:
4783 continue
4771 continue
4784 try:
4772 try:
4785 filenodes.append(cp.filenode(file_))
4773 filenodes.append(cp.filenode(file_))
4786 except error.LookupError:
4774 except error.LookupError:
4787 pass
4775 pass
4788 if not filenodes:
4776 if not filenodes:
4789 raise util.Abort(_("'%s' not found in manifest!") % file_)
4777 raise util.Abort(_("'%s' not found in manifest!") % file_)
4790 p = []
4778 p = []
4791 for fn in filenodes:
4779 for fn in filenodes:
4792 fctx = repo.filectx(file_, fileid=fn)
4780 fctx = repo.filectx(file_, fileid=fn)
4793 p.append(fctx.node())
4781 p.append(fctx.node())
4794 else:
4782 else:
4795 p = [cp.node() for cp in ctx.parents()]
4783 p = [cp.node() for cp in ctx.parents()]
4796
4784
4797 displayer = cmdutil.show_changeset(ui, repo, opts)
4785 displayer = cmdutil.show_changeset(ui, repo, opts)
4798 for n in p:
4786 for n in p:
4799 if n != nullid:
4787 if n != nullid:
4800 displayer.show(repo[n])
4788 displayer.show(repo[n])
4801 displayer.close()
4789 displayer.close()
4802
4790
4803 @command('paths', [], _('[NAME]'), optionalrepo=True)
4791 @command('paths', [], _('[NAME]'), optionalrepo=True)
4804 def paths(ui, repo, search=None):
4792 def paths(ui, repo, search=None):
4805 """show aliases for remote repositories
4793 """show aliases for remote repositories
4806
4794
4807 Show definition of symbolic path name NAME. If no name is given,
4795 Show definition of symbolic path name NAME. If no name is given,
4808 show definition of all available names.
4796 show definition of all available names.
4809
4797
4810 Option -q/--quiet suppresses all output when searching for NAME
4798 Option -q/--quiet suppresses all output when searching for NAME
4811 and shows only the path names when listing all definitions.
4799 and shows only the path names when listing all definitions.
4812
4800
4813 Path names are defined in the [paths] section of your
4801 Path names are defined in the [paths] section of your
4814 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4802 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4815 repository, ``.hg/hgrc`` is used, too.
4803 repository, ``.hg/hgrc`` is used, too.
4816
4804
4817 The path names ``default`` and ``default-push`` have a special
4805 The path names ``default`` and ``default-push`` have a special
4818 meaning. When performing a push or pull operation, they are used
4806 meaning. When performing a push or pull operation, they are used
4819 as fallbacks if no location is specified on the command-line.
4807 as fallbacks if no location is specified on the command-line.
4820 When ``default-push`` is set, it will be used for push and
4808 When ``default-push`` is set, it will be used for push and
4821 ``default`` will be used for pull; otherwise ``default`` is used
4809 ``default`` will be used for pull; otherwise ``default`` is used
4822 as the fallback for both. When cloning a repository, the clone
4810 as the fallback for both. When cloning a repository, the clone
4823 source is written as ``default`` in ``.hg/hgrc``. Note that
4811 source is written as ``default`` in ``.hg/hgrc``. Note that
4824 ``default`` and ``default-push`` apply to all inbound (e.g.
4812 ``default`` and ``default-push`` apply to all inbound (e.g.
4825 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4813 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4826 :hg:`bundle`) operations.
4814 :hg:`bundle`) operations.
4827
4815
4828 See :hg:`help urls` for more information.
4816 See :hg:`help urls` for more information.
4829
4817
4830 Returns 0 on success.
4818 Returns 0 on success.
4831 """
4819 """
4832 if search:
4820 if search:
4833 for name, path in sorted(ui.paths.iteritems()):
4821 for name, path in sorted(ui.paths.iteritems()):
4834 if name == search:
4822 if name == search:
4835 ui.status("%s\n" % util.hidepassword(path.loc))
4823 ui.status("%s\n" % util.hidepassword(path.loc))
4836 return
4824 return
4837 if not ui.quiet:
4825 if not ui.quiet:
4838 ui.warn(_("not found!\n"))
4826 ui.warn(_("not found!\n"))
4839 return 1
4827 return 1
4840 else:
4828 else:
4841 for name, path in sorted(ui.paths.iteritems()):
4829 for name, path in sorted(ui.paths.iteritems()):
4842 if ui.quiet:
4830 if ui.quiet:
4843 ui.write("%s\n" % name)
4831 ui.write("%s\n" % name)
4844 else:
4832 else:
4845 ui.write("%s = %s\n" % (name,
4833 ui.write("%s = %s\n" % (name,
4846 util.hidepassword(path.loc)))
4834 util.hidepassword(path.loc)))
4847
4835
4848 @command('phase',
4836 @command('phase',
4849 [('p', 'public', False, _('set changeset phase to public')),
4837 [('p', 'public', False, _('set changeset phase to public')),
4850 ('d', 'draft', False, _('set changeset phase to draft')),
4838 ('d', 'draft', False, _('set changeset phase to draft')),
4851 ('s', 'secret', False, _('set changeset phase to secret')),
4839 ('s', 'secret', False, _('set changeset phase to secret')),
4852 ('f', 'force', False, _('allow to move boundary backward')),
4840 ('f', 'force', False, _('allow to move boundary backward')),
4853 ('r', 'rev', [], _('target revision'), _('REV')),
4841 ('r', 'rev', [], _('target revision'), _('REV')),
4854 ],
4842 ],
4855 _('[-p|-d|-s] [-f] [-r] REV...'))
4843 _('[-p|-d|-s] [-f] [-r] REV...'))
4856 def phase(ui, repo, *revs, **opts):
4844 def phase(ui, repo, *revs, **opts):
4857 """set or show the current phase name
4845 """set or show the current phase name
4858
4846
4859 With no argument, show the phase name of specified revisions.
4847 With no argument, show the phase name of specified revisions.
4860
4848
4861 With one of -p/--public, -d/--draft or -s/--secret, change the
4849 With one of -p/--public, -d/--draft or -s/--secret, change the
4862 phase value of the specified revisions.
4850 phase value of the specified revisions.
4863
4851
4864 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4852 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4865 lower phase to an higher phase. Phases are ordered as follows::
4853 lower phase to an higher phase. Phases are ordered as follows::
4866
4854
4867 public < draft < secret
4855 public < draft < secret
4868
4856
4869 Returns 0 on success, 1 if no phases were changed or some could not
4857 Returns 0 on success, 1 if no phases were changed or some could not
4870 be changed.
4858 be changed.
4871 """
4859 """
4872 # search for a unique phase argument
4860 # search for a unique phase argument
4873 targetphase = None
4861 targetphase = None
4874 for idx, name in enumerate(phases.phasenames):
4862 for idx, name in enumerate(phases.phasenames):
4875 if opts[name]:
4863 if opts[name]:
4876 if targetphase is not None:
4864 if targetphase is not None:
4877 raise util.Abort(_('only one phase can be specified'))
4865 raise util.Abort(_('only one phase can be specified'))
4878 targetphase = idx
4866 targetphase = idx
4879
4867
4880 # look for specified revision
4868 # look for specified revision
4881 revs = list(revs)
4869 revs = list(revs)
4882 revs.extend(opts['rev'])
4870 revs.extend(opts['rev'])
4883 if not revs:
4871 if not revs:
4884 raise util.Abort(_('no revisions specified'))
4872 raise util.Abort(_('no revisions specified'))
4885
4873
4886 revs = scmutil.revrange(repo, revs)
4874 revs = scmutil.revrange(repo, revs)
4887
4875
4888 lock = None
4876 lock = None
4889 ret = 0
4877 ret = 0
4890 if targetphase is None:
4878 if targetphase is None:
4891 # display
4879 # display
4892 for r in revs:
4880 for r in revs:
4893 ctx = repo[r]
4881 ctx = repo[r]
4894 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4882 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4895 else:
4883 else:
4896 tr = None
4884 tr = None
4897 lock = repo.lock()
4885 lock = repo.lock()
4898 try:
4886 try:
4899 tr = repo.transaction("phase")
4887 tr = repo.transaction("phase")
4900 # set phase
4888 # set phase
4901 if not revs:
4889 if not revs:
4902 raise util.Abort(_('empty revision set'))
4890 raise util.Abort(_('empty revision set'))
4903 nodes = [repo[r].node() for r in revs]
4891 nodes = [repo[r].node() for r in revs]
4904 # moving revision from public to draft may hide them
4892 # moving revision from public to draft may hide them
4905 # We have to check result on an unfiltered repository
4893 # We have to check result on an unfiltered repository
4906 unfi = repo.unfiltered()
4894 unfi = repo.unfiltered()
4907 getphase = unfi._phasecache.phase
4895 getphase = unfi._phasecache.phase
4908 olddata = [getphase(unfi, r) for r in unfi]
4896 olddata = [getphase(unfi, r) for r in unfi]
4909 phases.advanceboundary(repo, tr, targetphase, nodes)
4897 phases.advanceboundary(repo, tr, targetphase, nodes)
4910 if opts['force']:
4898 if opts['force']:
4911 phases.retractboundary(repo, tr, targetphase, nodes)
4899 phases.retractboundary(repo, tr, targetphase, nodes)
4912 tr.close()
4900 tr.close()
4913 finally:
4901 finally:
4914 if tr is not None:
4902 if tr is not None:
4915 tr.release()
4903 tr.release()
4916 lock.release()
4904 lock.release()
4917 getphase = unfi._phasecache.phase
4905 getphase = unfi._phasecache.phase
4918 newdata = [getphase(unfi, r) for r in unfi]
4906 newdata = [getphase(unfi, r) for r in unfi]
4919 changes = sum(newdata[r] != olddata[r] for r in unfi)
4907 changes = sum(newdata[r] != olddata[r] for r in unfi)
4920 cl = unfi.changelog
4908 cl = unfi.changelog
4921 rejected = [n for n in nodes
4909 rejected = [n for n in nodes
4922 if newdata[cl.rev(n)] < targetphase]
4910 if newdata[cl.rev(n)] < targetphase]
4923 if rejected:
4911 if rejected:
4924 ui.warn(_('cannot move %i changesets to a higher '
4912 ui.warn(_('cannot move %i changesets to a higher '
4925 'phase, use --force\n') % len(rejected))
4913 'phase, use --force\n') % len(rejected))
4926 ret = 1
4914 ret = 1
4927 if changes:
4915 if changes:
4928 msg = _('phase changed for %i changesets\n') % changes
4916 msg = _('phase changed for %i changesets\n') % changes
4929 if ret:
4917 if ret:
4930 ui.status(msg)
4918 ui.status(msg)
4931 else:
4919 else:
4932 ui.note(msg)
4920 ui.note(msg)
4933 else:
4921 else:
4934 ui.warn(_('no phases changed\n'))
4922 ui.warn(_('no phases changed\n'))
4935 ret = 1
4923 ret = 1
4936 return ret
4924 return ret
4937
4925
4938 def postincoming(ui, repo, modheads, optupdate, checkout):
4926 def postincoming(ui, repo, modheads, optupdate, checkout):
4939 if modheads == 0:
4927 if modheads == 0:
4940 return
4928 return
4941 if optupdate:
4929 if optupdate:
4942 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4930 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4943 try:
4931 try:
4944 ret = hg.update(repo, checkout)
4932 ret = hg.update(repo, checkout)
4945 except util.Abort, inst:
4933 except util.Abort, inst:
4946 ui.warn(_("not updating: %s\n") % str(inst))
4934 ui.warn(_("not updating: %s\n") % str(inst))
4947 if inst.hint:
4935 if inst.hint:
4948 ui.warn(_("(%s)\n") % inst.hint)
4936 ui.warn(_("(%s)\n") % inst.hint)
4949 return 0
4937 return 0
4950 if not ret and not checkout:
4938 if not ret and not checkout:
4951 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4939 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4952 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4940 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4953 return ret
4941 return ret
4954 if modheads > 1:
4942 if modheads > 1:
4955 currentbranchheads = len(repo.branchheads())
4943 currentbranchheads = len(repo.branchheads())
4956 if currentbranchheads == modheads:
4944 if currentbranchheads == modheads:
4957 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4945 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4958 elif currentbranchheads > 1:
4946 elif currentbranchheads > 1:
4959 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4947 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4960 "merge)\n"))
4948 "merge)\n"))
4961 else:
4949 else:
4962 ui.status(_("(run 'hg heads' to see heads)\n"))
4950 ui.status(_("(run 'hg heads' to see heads)\n"))
4963 else:
4951 else:
4964 ui.status(_("(run 'hg update' to get a working copy)\n"))
4952 ui.status(_("(run 'hg update' to get a working copy)\n"))
4965
4953
4966 @command('^pull',
4954 @command('^pull',
4967 [('u', 'update', None,
4955 [('u', 'update', None,
4968 _('update to new branch head if changesets were pulled')),
4956 _('update to new branch head if changesets were pulled')),
4969 ('f', 'force', None, _('run even when remote repository is unrelated')),
4957 ('f', 'force', None, _('run even when remote repository is unrelated')),
4970 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4958 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4971 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4959 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4972 ('b', 'branch', [], _('a specific branch you would like to pull'),
4960 ('b', 'branch', [], _('a specific branch you would like to pull'),
4973 _('BRANCH')),
4961 _('BRANCH')),
4974 ] + remoteopts,
4962 ] + remoteopts,
4975 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4963 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4976 def pull(ui, repo, source="default", **opts):
4964 def pull(ui, repo, source="default", **opts):
4977 """pull changes from the specified source
4965 """pull changes from the specified source
4978
4966
4979 Pull changes from a remote repository to a local one.
4967 Pull changes from a remote repository to a local one.
4980
4968
4981 This finds all changes from the repository at the specified path
4969 This finds all changes from the repository at the specified path
4982 or URL and adds them to a local repository (the current one unless
4970 or URL and adds them to a local repository (the current one unless
4983 -R is specified). By default, this does not update the copy of the
4971 -R is specified). By default, this does not update the copy of the
4984 project in the working directory.
4972 project in the working directory.
4985
4973
4986 Use :hg:`incoming` if you want to see what would have been added
4974 Use :hg:`incoming` if you want to see what would have been added
4987 by a pull at the time you issued this command. If you then decide
4975 by a pull at the time you issued this command. If you then decide
4988 to add those changes to the repository, you should use :hg:`pull
4976 to add those changes to the repository, you should use :hg:`pull
4989 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4977 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4990
4978
4991 If SOURCE is omitted, the 'default' path will be used.
4979 If SOURCE is omitted, the 'default' path will be used.
4992 See :hg:`help urls` for more information.
4980 See :hg:`help urls` for more information.
4993
4981
4994 Returns 0 on success, 1 if an update had unresolved files.
4982 Returns 0 on success, 1 if an update had unresolved files.
4995 """
4983 """
4996 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4984 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4997 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4985 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4998 other = hg.peer(repo, opts, source)
4986 other = hg.peer(repo, opts, source)
4999 try:
4987 try:
5000 revs, checkout = hg.addbranchrevs(repo, other, branches,
4988 revs, checkout = hg.addbranchrevs(repo, other, branches,
5001 opts.get('rev'))
4989 opts.get('rev'))
5002
4990
5003 remotebookmarks = other.listkeys('bookmarks')
4991 remotebookmarks = other.listkeys('bookmarks')
5004
4992
5005 if opts.get('bookmark'):
4993 if opts.get('bookmark'):
5006 if not revs:
4994 if not revs:
5007 revs = []
4995 revs = []
5008 for b in opts['bookmark']:
4996 for b in opts['bookmark']:
5009 if b not in remotebookmarks:
4997 if b not in remotebookmarks:
5010 raise util.Abort(_('remote bookmark %s not found!') % b)
4998 raise util.Abort(_('remote bookmark %s not found!') % b)
5011 revs.append(remotebookmarks[b])
4999 revs.append(remotebookmarks[b])
5012
5000
5013 if revs:
5001 if revs:
5014 try:
5002 try:
5015 revs = [other.lookup(rev) for rev in revs]
5003 revs = [other.lookup(rev) for rev in revs]
5016 except error.CapabilityError:
5004 except error.CapabilityError:
5017 err = _("other repository doesn't support revision lookup, "
5005 err = _("other repository doesn't support revision lookup, "
5018 "so a rev cannot be specified.")
5006 "so a rev cannot be specified.")
5019 raise util.Abort(err)
5007 raise util.Abort(err)
5020
5008
5021 modheads = exchange.pull(repo, other, heads=revs,
5009 modheads = exchange.pull(repo, other, heads=revs,
5022 force=opts.get('force'),
5010 force=opts.get('force'),
5023 bookmarks=opts.get('bookmark', ())).cgresult
5011 bookmarks=opts.get('bookmark', ())).cgresult
5024 if checkout:
5012 if checkout:
5025 checkout = str(repo.changelog.rev(other.lookup(checkout)))
5013 checkout = str(repo.changelog.rev(other.lookup(checkout)))
5026 repo._subtoppath = source
5014 repo._subtoppath = source
5027 try:
5015 try:
5028 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5016 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5029
5017
5030 finally:
5018 finally:
5031 del repo._subtoppath
5019 del repo._subtoppath
5032
5020
5033 finally:
5021 finally:
5034 other.close()
5022 other.close()
5035 return ret
5023 return ret
5036
5024
5037 @command('^push',
5025 @command('^push',
5038 [('f', 'force', None, _('force push')),
5026 [('f', 'force', None, _('force push')),
5039 ('r', 'rev', [],
5027 ('r', 'rev', [],
5040 _('a changeset intended to be included in the destination'),
5028 _('a changeset intended to be included in the destination'),
5041 _('REV')),
5029 _('REV')),
5042 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5030 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5043 ('b', 'branch', [],
5031 ('b', 'branch', [],
5044 _('a specific branch you would like to push'), _('BRANCH')),
5032 _('a specific branch you would like to push'), _('BRANCH')),
5045 ('', 'new-branch', False, _('allow pushing a new branch')),
5033 ('', 'new-branch', False, _('allow pushing a new branch')),
5046 ] + remoteopts,
5034 ] + remoteopts,
5047 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5035 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5048 def push(ui, repo, dest=None, **opts):
5036 def push(ui, repo, dest=None, **opts):
5049 """push changes to the specified destination
5037 """push changes to the specified destination
5050
5038
5051 Push changesets from the local repository to the specified
5039 Push changesets from the local repository to the specified
5052 destination.
5040 destination.
5053
5041
5054 This operation is symmetrical to pull: it is identical to a pull
5042 This operation is symmetrical to pull: it is identical to a pull
5055 in the destination repository from the current one.
5043 in the destination repository from the current one.
5056
5044
5057 By default, push will not allow creation of new heads at the
5045 By default, push will not allow creation of new heads at the
5058 destination, since multiple heads would make it unclear which head
5046 destination, since multiple heads would make it unclear which head
5059 to use. In this situation, it is recommended to pull and merge
5047 to use. In this situation, it is recommended to pull and merge
5060 before pushing.
5048 before pushing.
5061
5049
5062 Use --new-branch if you want to allow push to create a new named
5050 Use --new-branch if you want to allow push to create a new named
5063 branch that is not present at the destination. This allows you to
5051 branch that is not present at the destination. This allows you to
5064 only create a new branch without forcing other changes.
5052 only create a new branch without forcing other changes.
5065
5053
5066 .. note::
5054 .. note::
5067
5055
5068 Extra care should be taken with the -f/--force option,
5056 Extra care should be taken with the -f/--force option,
5069 which will push all new heads on all branches, an action which will
5057 which will push all new heads on all branches, an action which will
5070 almost always cause confusion for collaborators.
5058 almost always cause confusion for collaborators.
5071
5059
5072 If -r/--rev is used, the specified revision and all its ancestors
5060 If -r/--rev is used, the specified revision and all its ancestors
5073 will be pushed to the remote repository.
5061 will be pushed to the remote repository.
5074
5062
5075 If -B/--bookmark is used, the specified bookmarked revision, its
5063 If -B/--bookmark is used, the specified bookmarked revision, its
5076 ancestors, and the bookmark will be pushed to the remote
5064 ancestors, and the bookmark will be pushed to the remote
5077 repository.
5065 repository.
5078
5066
5079 Please see :hg:`help urls` for important details about ``ssh://``
5067 Please see :hg:`help urls` for important details about ``ssh://``
5080 URLs. If DESTINATION is omitted, a default path will be used.
5068 URLs. If DESTINATION is omitted, a default path will be used.
5081
5069
5082 Returns 0 if push was successful, 1 if nothing to push.
5070 Returns 0 if push was successful, 1 if nothing to push.
5083 """
5071 """
5084
5072
5085 if opts.get('bookmark'):
5073 if opts.get('bookmark'):
5086 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5074 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5087 for b in opts['bookmark']:
5075 for b in opts['bookmark']:
5088 # translate -B options to -r so changesets get pushed
5076 # translate -B options to -r so changesets get pushed
5089 if b in repo._bookmarks:
5077 if b in repo._bookmarks:
5090 opts.setdefault('rev', []).append(b)
5078 opts.setdefault('rev', []).append(b)
5091 else:
5079 else:
5092 # if we try to push a deleted bookmark, translate it to null
5080 # if we try to push a deleted bookmark, translate it to null
5093 # this lets simultaneous -r, -b options continue working
5081 # this lets simultaneous -r, -b options continue working
5094 opts.setdefault('rev', []).append("null")
5082 opts.setdefault('rev', []).append("null")
5095
5083
5096 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5084 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5097 dest, branches = hg.parseurl(dest, opts.get('branch'))
5085 dest, branches = hg.parseurl(dest, opts.get('branch'))
5098 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5086 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5099 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5087 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5100 try:
5088 try:
5101 other = hg.peer(repo, opts, dest)
5089 other = hg.peer(repo, opts, dest)
5102 except error.RepoError:
5090 except error.RepoError:
5103 if dest == "default-push":
5091 if dest == "default-push":
5104 raise util.Abort(_("default repository not configured!"),
5092 raise util.Abort(_("default repository not configured!"),
5105 hint=_('see the "path" section in "hg help config"'))
5093 hint=_('see the "path" section in "hg help config"'))
5106 else:
5094 else:
5107 raise
5095 raise
5108
5096
5109 if revs:
5097 if revs:
5110 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5098 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5111
5099
5112 repo._subtoppath = dest
5100 repo._subtoppath = dest
5113 try:
5101 try:
5114 # push subrepos depth-first for coherent ordering
5102 # push subrepos depth-first for coherent ordering
5115 c = repo['']
5103 c = repo['']
5116 subs = c.substate # only repos that are committed
5104 subs = c.substate # only repos that are committed
5117 for s in sorted(subs):
5105 for s in sorted(subs):
5118 result = c.sub(s).push(opts)
5106 result = c.sub(s).push(opts)
5119 if result == 0:
5107 if result == 0:
5120 return not result
5108 return not result
5121 finally:
5109 finally:
5122 del repo._subtoppath
5110 del repo._subtoppath
5123 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5111 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5124 newbranch=opts.get('new_branch'),
5112 newbranch=opts.get('new_branch'),
5125 bookmarks=opts.get('bookmark', ()))
5113 bookmarks=opts.get('bookmark', ()))
5126
5114
5127 result = not pushop.cgresult
5115 result = not pushop.cgresult
5128
5116
5129 if pushop.bkresult is not None:
5117 if pushop.bkresult is not None:
5130 if pushop.bkresult == 2:
5118 if pushop.bkresult == 2:
5131 result = 2
5119 result = 2
5132 elif not result and pushop.bkresult:
5120 elif not result and pushop.bkresult:
5133 result = 2
5121 result = 2
5134
5122
5135 return result
5123 return result
5136
5124
5137 @command('recover', [])
5125 @command('recover', [])
5138 def recover(ui, repo):
5126 def recover(ui, repo):
5139 """roll back an interrupted transaction
5127 """roll back an interrupted transaction
5140
5128
5141 Recover from an interrupted commit or pull.
5129 Recover from an interrupted commit or pull.
5142
5130
5143 This command tries to fix the repository status after an
5131 This command tries to fix the repository status after an
5144 interrupted operation. It should only be necessary when Mercurial
5132 interrupted operation. It should only be necessary when Mercurial
5145 suggests it.
5133 suggests it.
5146
5134
5147 Returns 0 if successful, 1 if nothing to recover or verify fails.
5135 Returns 0 if successful, 1 if nothing to recover or verify fails.
5148 """
5136 """
5149 if repo.recover():
5137 if repo.recover():
5150 return hg.verify(repo)
5138 return hg.verify(repo)
5151 return 1
5139 return 1
5152
5140
5153 @command('^remove|rm',
5141 @command('^remove|rm',
5154 [('A', 'after', None, _('record delete for missing files')),
5142 [('A', 'after', None, _('record delete for missing files')),
5155 ('f', 'force', None,
5143 ('f', 'force', None,
5156 _('remove (and delete) file even if added or modified')),
5144 _('remove (and delete) file even if added or modified')),
5157 ] + subrepoopts + walkopts,
5145 ] + subrepoopts + walkopts,
5158 _('[OPTION]... FILE...'),
5146 _('[OPTION]... FILE...'),
5159 inferrepo=True)
5147 inferrepo=True)
5160 def remove(ui, repo, *pats, **opts):
5148 def remove(ui, repo, *pats, **opts):
5161 """remove the specified files on the next commit
5149 """remove the specified files on the next commit
5162
5150
5163 Schedule the indicated files for removal from the current branch.
5151 Schedule the indicated files for removal from the current branch.
5164
5152
5165 This command schedules the files to be removed at the next commit.
5153 This command schedules the files to be removed at the next commit.
5166 To undo a remove before that, see :hg:`revert`. To undo added
5154 To undo a remove before that, see :hg:`revert`. To undo added
5167 files, see :hg:`forget`.
5155 files, see :hg:`forget`.
5168
5156
5169 .. container:: verbose
5157 .. container:: verbose
5170
5158
5171 -A/--after can be used to remove only files that have already
5159 -A/--after can be used to remove only files that have already
5172 been deleted, -f/--force can be used to force deletion, and -Af
5160 been deleted, -f/--force can be used to force deletion, and -Af
5173 can be used to remove files from the next revision without
5161 can be used to remove files from the next revision without
5174 deleting them from the working directory.
5162 deleting them from the working directory.
5175
5163
5176 The following table details the behavior of remove for different
5164 The following table details the behavior of remove for different
5177 file states (columns) and option combinations (rows). The file
5165 file states (columns) and option combinations (rows). The file
5178 states are Added [A], Clean [C], Modified [M] and Missing [!]
5166 states are Added [A], Clean [C], Modified [M] and Missing [!]
5179 (as reported by :hg:`status`). The actions are Warn, Remove
5167 (as reported by :hg:`status`). The actions are Warn, Remove
5180 (from branch) and Delete (from disk):
5168 (from branch) and Delete (from disk):
5181
5169
5182 ========= == == == ==
5170 ========= == == == ==
5183 opt/state A C M !
5171 opt/state A C M !
5184 ========= == == == ==
5172 ========= == == == ==
5185 none W RD W R
5173 none W RD W R
5186 -f R RD RD R
5174 -f R RD RD R
5187 -A W W W R
5175 -A W W W R
5188 -Af R R R R
5176 -Af R R R R
5189 ========= == == == ==
5177 ========= == == == ==
5190
5178
5191 Note that remove never deletes files in Added [A] state from the
5179 Note that remove never deletes files in Added [A] state from the
5192 working directory, not even if option --force is specified.
5180 working directory, not even if option --force is specified.
5193
5181
5194 Returns 0 on success, 1 if any warnings encountered.
5182 Returns 0 on success, 1 if any warnings encountered.
5195 """
5183 """
5196
5184
5197 after, force = opts.get('after'), opts.get('force')
5185 after, force = opts.get('after'), opts.get('force')
5198 if not pats and not after:
5186 if not pats and not after:
5199 raise util.Abort(_('no files specified'))
5187 raise util.Abort(_('no files specified'))
5200
5188
5201 m = scmutil.match(repo[None], pats, opts)
5189 m = scmutil.match(repo[None], pats, opts)
5202 subrepos = opts.get('subrepos')
5190 subrepos = opts.get('subrepos')
5203 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5191 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5204
5192
5205 @command('rename|move|mv',
5193 @command('rename|move|mv',
5206 [('A', 'after', None, _('record a rename that has already occurred')),
5194 [('A', 'after', None, _('record a rename that has already occurred')),
5207 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5195 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5208 ] + walkopts + dryrunopts,
5196 ] + walkopts + dryrunopts,
5209 _('[OPTION]... SOURCE... DEST'))
5197 _('[OPTION]... SOURCE... DEST'))
5210 def rename(ui, repo, *pats, **opts):
5198 def rename(ui, repo, *pats, **opts):
5211 """rename files; equivalent of copy + remove
5199 """rename files; equivalent of copy + remove
5212
5200
5213 Mark dest as copies of sources; mark sources for deletion. If dest
5201 Mark dest as copies of sources; mark sources for deletion. If dest
5214 is a directory, copies are put in that directory. If dest is a
5202 is a directory, copies are put in that directory. If dest is a
5215 file, there can only be one source.
5203 file, there can only be one source.
5216
5204
5217 By default, this command copies the contents of files as they
5205 By default, this command copies the contents of files as they
5218 exist in the working directory. If invoked with -A/--after, the
5206 exist in the working directory. If invoked with -A/--after, the
5219 operation is recorded, but no copying is performed.
5207 operation is recorded, but no copying is performed.
5220
5208
5221 This command takes effect at the next commit. To undo a rename
5209 This command takes effect at the next commit. To undo a rename
5222 before that, see :hg:`revert`.
5210 before that, see :hg:`revert`.
5223
5211
5224 Returns 0 on success, 1 if errors are encountered.
5212 Returns 0 on success, 1 if errors are encountered.
5225 """
5213 """
5226 wlock = repo.wlock(False)
5214 wlock = repo.wlock(False)
5227 try:
5215 try:
5228 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5216 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5229 finally:
5217 finally:
5230 wlock.release()
5218 wlock.release()
5231
5219
5232 @command('resolve',
5220 @command('resolve',
5233 [('a', 'all', None, _('select all unresolved files')),
5221 [('a', 'all', None, _('select all unresolved files')),
5234 ('l', 'list', None, _('list state of files needing merge')),
5222 ('l', 'list', None, _('list state of files needing merge')),
5235 ('m', 'mark', None, _('mark files as resolved')),
5223 ('m', 'mark', None, _('mark files as resolved')),
5236 ('u', 'unmark', None, _('mark files as unresolved')),
5224 ('u', 'unmark', None, _('mark files as unresolved')),
5237 ('n', 'no-status', None, _('hide status prefix'))]
5225 ('n', 'no-status', None, _('hide status prefix'))]
5238 + mergetoolopts + walkopts + formatteropts,
5226 + mergetoolopts + walkopts + formatteropts,
5239 _('[OPTION]... [FILE]...'),
5227 _('[OPTION]... [FILE]...'),
5240 inferrepo=True)
5228 inferrepo=True)
5241 def resolve(ui, repo, *pats, **opts):
5229 def resolve(ui, repo, *pats, **opts):
5242 """redo merges or set/view the merge status of files
5230 """redo merges or set/view the merge status of files
5243
5231
5244 Merges with unresolved conflicts are often the result of
5232 Merges with unresolved conflicts are often the result of
5245 non-interactive merging using the ``internal:merge`` configuration
5233 non-interactive merging using the ``internal:merge`` configuration
5246 setting, or a command-line merge tool like ``diff3``. The resolve
5234 setting, or a command-line merge tool like ``diff3``. The resolve
5247 command is used to manage the files involved in a merge, after
5235 command is used to manage the files involved in a merge, after
5248 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5236 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5249 working directory must have two parents). See :hg:`help
5237 working directory must have two parents). See :hg:`help
5250 merge-tools` for information on configuring merge tools.
5238 merge-tools` for information on configuring merge tools.
5251
5239
5252 The resolve command can be used in the following ways:
5240 The resolve command can be used in the following ways:
5253
5241
5254 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5242 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5255 files, discarding any previous merge attempts. Re-merging is not
5243 files, discarding any previous merge attempts. Re-merging is not
5256 performed for files already marked as resolved. Use ``--all/-a``
5244 performed for files already marked as resolved. Use ``--all/-a``
5257 to select all unresolved files. ``--tool`` can be used to specify
5245 to select all unresolved files. ``--tool`` can be used to specify
5258 the merge tool used for the given files. It overrides the HGMERGE
5246 the merge tool used for the given files. It overrides the HGMERGE
5259 environment variable and your configuration files. Previous file
5247 environment variable and your configuration files. Previous file
5260 contents are saved with a ``.orig`` suffix.
5248 contents are saved with a ``.orig`` suffix.
5261
5249
5262 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5250 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5263 (e.g. after having manually fixed-up the files). The default is
5251 (e.g. after having manually fixed-up the files). The default is
5264 to mark all unresolved files.
5252 to mark all unresolved files.
5265
5253
5266 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5254 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5267 default is to mark all resolved files.
5255 default is to mark all resolved files.
5268
5256
5269 - :hg:`resolve -l`: list files which had or still have conflicts.
5257 - :hg:`resolve -l`: list files which had or still have conflicts.
5270 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5258 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5271
5259
5272 Note that Mercurial will not let you commit files with unresolved
5260 Note that Mercurial will not let you commit files with unresolved
5273 merge conflicts. You must use :hg:`resolve -m ...` before you can
5261 merge conflicts. You must use :hg:`resolve -m ...` before you can
5274 commit after a conflicting merge.
5262 commit after a conflicting merge.
5275
5263
5276 Returns 0 on success, 1 if any files fail a resolve attempt.
5264 Returns 0 on success, 1 if any files fail a resolve attempt.
5277 """
5265 """
5278
5266
5279 all, mark, unmark, show, nostatus = \
5267 all, mark, unmark, show, nostatus = \
5280 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5268 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5281
5269
5282 if (show and (mark or unmark)) or (mark and unmark):
5270 if (show and (mark or unmark)) or (mark and unmark):
5283 raise util.Abort(_("too many options specified"))
5271 raise util.Abort(_("too many options specified"))
5284 if pats and all:
5272 if pats and all:
5285 raise util.Abort(_("can't specify --all and patterns"))
5273 raise util.Abort(_("can't specify --all and patterns"))
5286 if not (all or pats or show or mark or unmark):
5274 if not (all or pats or show or mark or unmark):
5287 raise util.Abort(_('no files or directories specified'),
5275 raise util.Abort(_('no files or directories specified'),
5288 hint=('use --all to remerge all files'))
5276 hint=('use --all to remerge all files'))
5289
5277
5290 if show:
5278 if show:
5291 fm = ui.formatter('resolve', opts)
5279 fm = ui.formatter('resolve', opts)
5292 ms = mergemod.mergestate(repo)
5280 ms = mergemod.mergestate(repo)
5293 m = scmutil.match(repo[None], pats, opts)
5281 m = scmutil.match(repo[None], pats, opts)
5294 for f in ms:
5282 for f in ms:
5295 if not m(f):
5283 if not m(f):
5296 continue
5284 continue
5297 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5285 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5298 fm.startitem()
5286 fm.startitem()
5299 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5287 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5300 fm.write('path', '%s\n', f, label=l)
5288 fm.write('path', '%s\n', f, label=l)
5301 fm.end()
5289 fm.end()
5302 return 0
5290 return 0
5303
5291
5304 wlock = repo.wlock()
5292 wlock = repo.wlock()
5305 try:
5293 try:
5306 ms = mergemod.mergestate(repo)
5294 ms = mergemod.mergestate(repo)
5307
5295
5308 if not (ms.active() or repo.dirstate.p2() != nullid):
5296 if not (ms.active() or repo.dirstate.p2() != nullid):
5309 raise util.Abort(
5297 raise util.Abort(
5310 _('resolve command not applicable when not merging'))
5298 _('resolve command not applicable when not merging'))
5311
5299
5312 m = scmutil.match(repo[None], pats, opts)
5300 m = scmutil.match(repo[None], pats, opts)
5313 ret = 0
5301 ret = 0
5314 didwork = False
5302 didwork = False
5315
5303
5316 for f in ms:
5304 for f in ms:
5317 if not m(f):
5305 if not m(f):
5318 continue
5306 continue
5319
5307
5320 didwork = True
5308 didwork = True
5321
5309
5322 if mark:
5310 if mark:
5323 ms.mark(f, "r")
5311 ms.mark(f, "r")
5324 elif unmark:
5312 elif unmark:
5325 ms.mark(f, "u")
5313 ms.mark(f, "u")
5326 else:
5314 else:
5327 wctx = repo[None]
5315 wctx = repo[None]
5328
5316
5329 # backup pre-resolve (merge uses .orig for its own purposes)
5317 # backup pre-resolve (merge uses .orig for its own purposes)
5330 a = repo.wjoin(f)
5318 a = repo.wjoin(f)
5331 util.copyfile(a, a + ".resolve")
5319 util.copyfile(a, a + ".resolve")
5332
5320
5333 try:
5321 try:
5334 # resolve file
5322 # resolve file
5335 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5323 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5336 'resolve')
5324 'resolve')
5337 if ms.resolve(f, wctx):
5325 if ms.resolve(f, wctx):
5338 ret = 1
5326 ret = 1
5339 finally:
5327 finally:
5340 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5328 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5341 ms.commit()
5329 ms.commit()
5342
5330
5343 # replace filemerge's .orig file with our resolve file
5331 # replace filemerge's .orig file with our resolve file
5344 util.rename(a + ".resolve", a + ".orig")
5332 util.rename(a + ".resolve", a + ".orig")
5345
5333
5346 ms.commit()
5334 ms.commit()
5347
5335
5348 if not didwork and pats:
5336 if not didwork and pats:
5349 ui.warn(_("arguments do not match paths that need resolving\n"))
5337 ui.warn(_("arguments do not match paths that need resolving\n"))
5350
5338
5351 finally:
5339 finally:
5352 wlock.release()
5340 wlock.release()
5353
5341
5354 # Nudge users into finishing an unfinished operation
5342 # Nudge users into finishing an unfinished operation
5355 if not list(ms.unresolved()):
5343 if not list(ms.unresolved()):
5356 ui.status(_('(no more unresolved files)\n'))
5344 ui.status(_('(no more unresolved files)\n'))
5357
5345
5358 return ret
5346 return ret
5359
5347
5360 @command('revert',
5348 @command('revert',
5361 [('a', 'all', None, _('revert all changes when no arguments given')),
5349 [('a', 'all', None, _('revert all changes when no arguments given')),
5362 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5350 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5363 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5351 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5364 ('C', 'no-backup', None, _('do not save backup copies of files')),
5352 ('C', 'no-backup', None, _('do not save backup copies of files')),
5365 ] + walkopts + dryrunopts,
5353 ] + walkopts + dryrunopts,
5366 _('[OPTION]... [-r REV] [NAME]...'))
5354 _('[OPTION]... [-r REV] [NAME]...'))
5367 def revert(ui, repo, *pats, **opts):
5355 def revert(ui, repo, *pats, **opts):
5368 """restore files to their checkout state
5356 """restore files to their checkout state
5369
5357
5370 .. note::
5358 .. note::
5371
5359
5372 To check out earlier revisions, you should use :hg:`update REV`.
5360 To check out earlier revisions, you should use :hg:`update REV`.
5373 To cancel an uncommitted merge (and lose your changes),
5361 To cancel an uncommitted merge (and lose your changes),
5374 use :hg:`update --clean .`.
5362 use :hg:`update --clean .`.
5375
5363
5376 With no revision specified, revert the specified files or directories
5364 With no revision specified, revert the specified files or directories
5377 to the contents they had in the parent of the working directory.
5365 to the contents they had in the parent of the working directory.
5378 This restores the contents of files to an unmodified
5366 This restores the contents of files to an unmodified
5379 state and unschedules adds, removes, copies, and renames. If the
5367 state and unschedules adds, removes, copies, and renames. If the
5380 working directory has two parents, you must explicitly specify a
5368 working directory has two parents, you must explicitly specify a
5381 revision.
5369 revision.
5382
5370
5383 Using the -r/--rev or -d/--date options, revert the given files or
5371 Using the -r/--rev or -d/--date options, revert the given files or
5384 directories to their states as of a specific revision. Because
5372 directories to their states as of a specific revision. Because
5385 revert does not change the working directory parents, this will
5373 revert does not change the working directory parents, this will
5386 cause these files to appear modified. This can be helpful to "back
5374 cause these files to appear modified. This can be helpful to "back
5387 out" some or all of an earlier change. See :hg:`backout` for a
5375 out" some or all of an earlier change. See :hg:`backout` for a
5388 related method.
5376 related method.
5389
5377
5390 Modified files are saved with a .orig suffix before reverting.
5378 Modified files are saved with a .orig suffix before reverting.
5391 To disable these backups, use --no-backup.
5379 To disable these backups, use --no-backup.
5392
5380
5393 See :hg:`help dates` for a list of formats valid for -d/--date.
5381 See :hg:`help dates` for a list of formats valid for -d/--date.
5394
5382
5395 Returns 0 on success.
5383 Returns 0 on success.
5396 """
5384 """
5397
5385
5398 if opts.get("date"):
5386 if opts.get("date"):
5399 if opts.get("rev"):
5387 if opts.get("rev"):
5400 raise util.Abort(_("you can't specify a revision and a date"))
5388 raise util.Abort(_("you can't specify a revision and a date"))
5401 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5389 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5402
5390
5403 parent, p2 = repo.dirstate.parents()
5391 parent, p2 = repo.dirstate.parents()
5404 if not opts.get('rev') and p2 != nullid:
5392 if not opts.get('rev') and p2 != nullid:
5405 # revert after merge is a trap for new users (issue2915)
5393 # revert after merge is a trap for new users (issue2915)
5406 raise util.Abort(_('uncommitted merge with no revision specified'),
5394 raise util.Abort(_('uncommitted merge with no revision specified'),
5407 hint=_('use "hg update" or see "hg help revert"'))
5395 hint=_('use "hg update" or see "hg help revert"'))
5408
5396
5409 ctx = scmutil.revsingle(repo, opts.get('rev'))
5397 ctx = scmutil.revsingle(repo, opts.get('rev'))
5410
5398
5411 if not pats and not opts.get('all'):
5399 if not pats and not opts.get('all'):
5412 msg = _("no files or directories specified")
5400 msg = _("no files or directories specified")
5413 if p2 != nullid:
5401 if p2 != nullid:
5414 hint = _("uncommitted merge, use --all to discard all changes,"
5402 hint = _("uncommitted merge, use --all to discard all changes,"
5415 " or 'hg update -C .' to abort the merge")
5403 " or 'hg update -C .' to abort the merge")
5416 raise util.Abort(msg, hint=hint)
5404 raise util.Abort(msg, hint=hint)
5417 dirty = util.any(repo.status())
5405 dirty = util.any(repo.status())
5418 node = ctx.node()
5406 node = ctx.node()
5419 if node != parent:
5407 if node != parent:
5420 if dirty:
5408 if dirty:
5421 hint = _("uncommitted changes, use --all to discard all"
5409 hint = _("uncommitted changes, use --all to discard all"
5422 " changes, or 'hg update %s' to update") % ctx.rev()
5410 " changes, or 'hg update %s' to update") % ctx.rev()
5423 else:
5411 else:
5424 hint = _("use --all to revert all files,"
5412 hint = _("use --all to revert all files,"
5425 " or 'hg update %s' to update") % ctx.rev()
5413 " or 'hg update %s' to update") % ctx.rev()
5426 elif dirty:
5414 elif dirty:
5427 hint = _("uncommitted changes, use --all to discard all changes")
5415 hint = _("uncommitted changes, use --all to discard all changes")
5428 else:
5416 else:
5429 hint = _("use --all to revert all files")
5417 hint = _("use --all to revert all files")
5430 raise util.Abort(msg, hint=hint)
5418 raise util.Abort(msg, hint=hint)
5431
5419
5432 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5420 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5433
5421
5434 @command('rollback', dryrunopts +
5422 @command('rollback', dryrunopts +
5435 [('f', 'force', False, _('ignore safety measures'))])
5423 [('f', 'force', False, _('ignore safety measures'))])
5436 def rollback(ui, repo, **opts):
5424 def rollback(ui, repo, **opts):
5437 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5425 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5438
5426
5439 Please use :hg:`commit --amend` instead of rollback to correct
5427 Please use :hg:`commit --amend` instead of rollback to correct
5440 mistakes in the last commit.
5428 mistakes in the last commit.
5441
5429
5442 This command should be used with care. There is only one level of
5430 This command should be used with care. There is only one level of
5443 rollback, and there is no way to undo a rollback. It will also
5431 rollback, and there is no way to undo a rollback. It will also
5444 restore the dirstate at the time of the last transaction, losing
5432 restore the dirstate at the time of the last transaction, losing
5445 any dirstate changes since that time. This command does not alter
5433 any dirstate changes since that time. This command does not alter
5446 the working directory.
5434 the working directory.
5447
5435
5448 Transactions are used to encapsulate the effects of all commands
5436 Transactions are used to encapsulate the effects of all commands
5449 that create new changesets or propagate existing changesets into a
5437 that create new changesets or propagate existing changesets into a
5450 repository.
5438 repository.
5451
5439
5452 .. container:: verbose
5440 .. container:: verbose
5453
5441
5454 For example, the following commands are transactional, and their
5442 For example, the following commands are transactional, and their
5455 effects can be rolled back:
5443 effects can be rolled back:
5456
5444
5457 - commit
5445 - commit
5458 - import
5446 - import
5459 - pull
5447 - pull
5460 - push (with this repository as the destination)
5448 - push (with this repository as the destination)
5461 - unbundle
5449 - unbundle
5462
5450
5463 To avoid permanent data loss, rollback will refuse to rollback a
5451 To avoid permanent data loss, rollback will refuse to rollback a
5464 commit transaction if it isn't checked out. Use --force to
5452 commit transaction if it isn't checked out. Use --force to
5465 override this protection.
5453 override this protection.
5466
5454
5467 This command is not intended for use on public repositories. Once
5455 This command is not intended for use on public repositories. Once
5468 changes are visible for pull by other users, rolling a transaction
5456 changes are visible for pull by other users, rolling a transaction
5469 back locally is ineffective (someone else may already have pulled
5457 back locally is ineffective (someone else may already have pulled
5470 the changes). Furthermore, a race is possible with readers of the
5458 the changes). Furthermore, a race is possible with readers of the
5471 repository; for example an in-progress pull from the repository
5459 repository; for example an in-progress pull from the repository
5472 may fail if a rollback is performed.
5460 may fail if a rollback is performed.
5473
5461
5474 Returns 0 on success, 1 if no rollback data is available.
5462 Returns 0 on success, 1 if no rollback data is available.
5475 """
5463 """
5476 return repo.rollback(dryrun=opts.get('dry_run'),
5464 return repo.rollback(dryrun=opts.get('dry_run'),
5477 force=opts.get('force'))
5465 force=opts.get('force'))
5478
5466
5479 @command('root', [])
5467 @command('root', [])
5480 def root(ui, repo):
5468 def root(ui, repo):
5481 """print the root (top) of the current working directory
5469 """print the root (top) of the current working directory
5482
5470
5483 Print the root directory of the current repository.
5471 Print the root directory of the current repository.
5484
5472
5485 Returns 0 on success.
5473 Returns 0 on success.
5486 """
5474 """
5487 ui.write(repo.root + "\n")
5475 ui.write(repo.root + "\n")
5488
5476
5489 @command('^serve',
5477 @command('^serve',
5490 [('A', 'accesslog', '', _('name of access log file to write to'),
5478 [('A', 'accesslog', '', _('name of access log file to write to'),
5491 _('FILE')),
5479 _('FILE')),
5492 ('d', 'daemon', None, _('run server in background')),
5480 ('d', 'daemon', None, _('run server in background')),
5493 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5481 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5494 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5482 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5495 # use string type, then we can check if something was passed
5483 # use string type, then we can check if something was passed
5496 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5484 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5497 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5485 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5498 _('ADDR')),
5486 _('ADDR')),
5499 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5487 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5500 _('PREFIX')),
5488 _('PREFIX')),
5501 ('n', 'name', '',
5489 ('n', 'name', '',
5502 _('name to show in web pages (default: working directory)'), _('NAME')),
5490 _('name to show in web pages (default: working directory)'), _('NAME')),
5503 ('', 'web-conf', '',
5491 ('', 'web-conf', '',
5504 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5492 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5505 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5493 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5506 _('FILE')),
5494 _('FILE')),
5507 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5495 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5508 ('', 'stdio', None, _('for remote clients')),
5496 ('', 'stdio', None, _('for remote clients')),
5509 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5497 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5510 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5498 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5511 ('', 'style', '', _('template style to use'), _('STYLE')),
5499 ('', 'style', '', _('template style to use'), _('STYLE')),
5512 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5500 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5513 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5501 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5514 _('[OPTION]...'),
5502 _('[OPTION]...'),
5515 optionalrepo=True)
5503 optionalrepo=True)
5516 def serve(ui, repo, **opts):
5504 def serve(ui, repo, **opts):
5517 """start stand-alone webserver
5505 """start stand-alone webserver
5518
5506
5519 Start a local HTTP repository browser and pull server. You can use
5507 Start a local HTTP repository browser and pull server. You can use
5520 this for ad-hoc sharing and browsing of repositories. It is
5508 this for ad-hoc sharing and browsing of repositories. It is
5521 recommended to use a real web server to serve a repository for
5509 recommended to use a real web server to serve a repository for
5522 longer periods of time.
5510 longer periods of time.
5523
5511
5524 Please note that the server does not implement access control.
5512 Please note that the server does not implement access control.
5525 This means that, by default, anybody can read from the server and
5513 This means that, by default, anybody can read from the server and
5526 nobody can write to it by default. Set the ``web.allow_push``
5514 nobody can write to it by default. Set the ``web.allow_push``
5527 option to ``*`` to allow everybody to push to the server. You
5515 option to ``*`` to allow everybody to push to the server. You
5528 should use a real web server if you need to authenticate users.
5516 should use a real web server if you need to authenticate users.
5529
5517
5530 By default, the server logs accesses to stdout and errors to
5518 By default, the server logs accesses to stdout and errors to
5531 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5519 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5532 files.
5520 files.
5533
5521
5534 To have the server choose a free port number to listen on, specify
5522 To have the server choose a free port number to listen on, specify
5535 a port number of 0; in this case, the server will print the port
5523 a port number of 0; in this case, the server will print the port
5536 number it uses.
5524 number it uses.
5537
5525
5538 Returns 0 on success.
5526 Returns 0 on success.
5539 """
5527 """
5540
5528
5541 if opts["stdio"] and opts["cmdserver"]:
5529 if opts["stdio"] and opts["cmdserver"]:
5542 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5530 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5543
5531
5544 if opts["stdio"]:
5532 if opts["stdio"]:
5545 if repo is None:
5533 if repo is None:
5546 raise error.RepoError(_("there is no Mercurial repository here"
5534 raise error.RepoError(_("there is no Mercurial repository here"
5547 " (.hg not found)"))
5535 " (.hg not found)"))
5548 s = sshserver.sshserver(ui, repo)
5536 s = sshserver.sshserver(ui, repo)
5549 s.serve_forever()
5537 s.serve_forever()
5550
5538
5551 if opts["cmdserver"]:
5539 if opts["cmdserver"]:
5552 service = commandserver.createservice(ui, repo, opts)
5540 service = commandserver.createservice(ui, repo, opts)
5553 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5541 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5554
5542
5555 # this way we can check if something was given in the command-line
5543 # this way we can check if something was given in the command-line
5556 if opts.get('port'):
5544 if opts.get('port'):
5557 opts['port'] = util.getport(opts.get('port'))
5545 opts['port'] = util.getport(opts.get('port'))
5558
5546
5559 baseui = repo and repo.baseui or ui
5547 baseui = repo and repo.baseui or ui
5560 optlist = ("name templates style address port prefix ipv6"
5548 optlist = ("name templates style address port prefix ipv6"
5561 " accesslog errorlog certificate encoding")
5549 " accesslog errorlog certificate encoding")
5562 for o in optlist.split():
5550 for o in optlist.split():
5563 val = opts.get(o, '')
5551 val = opts.get(o, '')
5564 if val in (None, ''): # should check against default options instead
5552 if val in (None, ''): # should check against default options instead
5565 continue
5553 continue
5566 baseui.setconfig("web", o, val, 'serve')
5554 baseui.setconfig("web", o, val, 'serve')
5567 if repo and repo.ui != baseui:
5555 if repo and repo.ui != baseui:
5568 repo.ui.setconfig("web", o, val, 'serve')
5556 repo.ui.setconfig("web", o, val, 'serve')
5569
5557
5570 o = opts.get('web_conf') or opts.get('webdir_conf')
5558 o = opts.get('web_conf') or opts.get('webdir_conf')
5571 if not o:
5559 if not o:
5572 if not repo:
5560 if not repo:
5573 raise error.RepoError(_("there is no Mercurial repository"
5561 raise error.RepoError(_("there is no Mercurial repository"
5574 " here (.hg not found)"))
5562 " here (.hg not found)"))
5575 o = repo
5563 o = repo
5576
5564
5577 app = hgweb.hgweb(o, baseui=baseui)
5565 app = hgweb.hgweb(o, baseui=baseui)
5578 service = httpservice(ui, app, opts)
5566 service = httpservice(ui, app, opts)
5579 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5567 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5580
5568
5581 class httpservice(object):
5569 class httpservice(object):
5582 def __init__(self, ui, app, opts):
5570 def __init__(self, ui, app, opts):
5583 self.ui = ui
5571 self.ui = ui
5584 self.app = app
5572 self.app = app
5585 self.opts = opts
5573 self.opts = opts
5586
5574
5587 def init(self):
5575 def init(self):
5588 util.setsignalhandler()
5576 util.setsignalhandler()
5589 self.httpd = hgweb_server.create_server(self.ui, self.app)
5577 self.httpd = hgweb_server.create_server(self.ui, self.app)
5590
5578
5591 if self.opts['port'] and not self.ui.verbose:
5579 if self.opts['port'] and not self.ui.verbose:
5592 return
5580 return
5593
5581
5594 if self.httpd.prefix:
5582 if self.httpd.prefix:
5595 prefix = self.httpd.prefix.strip('/') + '/'
5583 prefix = self.httpd.prefix.strip('/') + '/'
5596 else:
5584 else:
5597 prefix = ''
5585 prefix = ''
5598
5586
5599 port = ':%d' % self.httpd.port
5587 port = ':%d' % self.httpd.port
5600 if port == ':80':
5588 if port == ':80':
5601 port = ''
5589 port = ''
5602
5590
5603 bindaddr = self.httpd.addr
5591 bindaddr = self.httpd.addr
5604 if bindaddr == '0.0.0.0':
5592 if bindaddr == '0.0.0.0':
5605 bindaddr = '*'
5593 bindaddr = '*'
5606 elif ':' in bindaddr: # IPv6
5594 elif ':' in bindaddr: # IPv6
5607 bindaddr = '[%s]' % bindaddr
5595 bindaddr = '[%s]' % bindaddr
5608
5596
5609 fqaddr = self.httpd.fqaddr
5597 fqaddr = self.httpd.fqaddr
5610 if ':' in fqaddr:
5598 if ':' in fqaddr:
5611 fqaddr = '[%s]' % fqaddr
5599 fqaddr = '[%s]' % fqaddr
5612 if self.opts['port']:
5600 if self.opts['port']:
5613 write = self.ui.status
5601 write = self.ui.status
5614 else:
5602 else:
5615 write = self.ui.write
5603 write = self.ui.write
5616 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5604 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5617 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5605 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5618 self.ui.flush() # avoid buffering of status message
5606 self.ui.flush() # avoid buffering of status message
5619
5607
5620 def run(self):
5608 def run(self):
5621 self.httpd.serve_forever()
5609 self.httpd.serve_forever()
5622
5610
5623
5611
5624 @command('^status|st',
5612 @command('^status|st',
5625 [('A', 'all', None, _('show status of all files')),
5613 [('A', 'all', None, _('show status of all files')),
5626 ('m', 'modified', None, _('show only modified files')),
5614 ('m', 'modified', None, _('show only modified files')),
5627 ('a', 'added', None, _('show only added files')),
5615 ('a', 'added', None, _('show only added files')),
5628 ('r', 'removed', None, _('show only removed files')),
5616 ('r', 'removed', None, _('show only removed files')),
5629 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5617 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5630 ('c', 'clean', None, _('show only files without changes')),
5618 ('c', 'clean', None, _('show only files without changes')),
5631 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5619 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5632 ('i', 'ignored', None, _('show only ignored files')),
5620 ('i', 'ignored', None, _('show only ignored files')),
5633 ('n', 'no-status', None, _('hide status prefix')),
5621 ('n', 'no-status', None, _('hide status prefix')),
5634 ('C', 'copies', None, _('show source of copied files')),
5622 ('C', 'copies', None, _('show source of copied files')),
5635 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5623 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5636 ('', 'rev', [], _('show difference from revision'), _('REV')),
5624 ('', 'rev', [], _('show difference from revision'), _('REV')),
5637 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5625 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5638 ] + walkopts + subrepoopts + formatteropts,
5626 ] + walkopts + subrepoopts + formatteropts,
5639 _('[OPTION]... [FILE]...'),
5627 _('[OPTION]... [FILE]...'),
5640 inferrepo=True)
5628 inferrepo=True)
5641 def status(ui, repo, *pats, **opts):
5629 def status(ui, repo, *pats, **opts):
5642 """show changed files in the working directory
5630 """show changed files in the working directory
5643
5631
5644 Show status of files in the repository. If names are given, only
5632 Show status of files in the repository. If names are given, only
5645 files that match are shown. Files that are clean or ignored or
5633 files that match are shown. Files that are clean or ignored or
5646 the source of a copy/move operation, are not listed unless
5634 the source of a copy/move operation, are not listed unless
5647 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5635 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5648 Unless options described with "show only ..." are given, the
5636 Unless options described with "show only ..." are given, the
5649 options -mardu are used.
5637 options -mardu are used.
5650
5638
5651 Option -q/--quiet hides untracked (unknown and ignored) files
5639 Option -q/--quiet hides untracked (unknown and ignored) files
5652 unless explicitly requested with -u/--unknown or -i/--ignored.
5640 unless explicitly requested with -u/--unknown or -i/--ignored.
5653
5641
5654 .. note::
5642 .. note::
5655
5643
5656 status may appear to disagree with diff if permissions have
5644 status may appear to disagree with diff if permissions have
5657 changed or a merge has occurred. The standard diff format does
5645 changed or a merge has occurred. The standard diff format does
5658 not report permission changes and diff only reports changes
5646 not report permission changes and diff only reports changes
5659 relative to one merge parent.
5647 relative to one merge parent.
5660
5648
5661 If one revision is given, it is used as the base revision.
5649 If one revision is given, it is used as the base revision.
5662 If two revisions are given, the differences between them are
5650 If two revisions are given, the differences between them are
5663 shown. The --change option can also be used as a shortcut to list
5651 shown. The --change option can also be used as a shortcut to list
5664 the changed files of a revision from its first parent.
5652 the changed files of a revision from its first parent.
5665
5653
5666 The codes used to show the status of files are::
5654 The codes used to show the status of files are::
5667
5655
5668 M = modified
5656 M = modified
5669 A = added
5657 A = added
5670 R = removed
5658 R = removed
5671 C = clean
5659 C = clean
5672 ! = missing (deleted by non-hg command, but still tracked)
5660 ! = missing (deleted by non-hg command, but still tracked)
5673 ? = not tracked
5661 ? = not tracked
5674 I = ignored
5662 I = ignored
5675 = origin of the previous file (with --copies)
5663 = origin of the previous file (with --copies)
5676
5664
5677 .. container:: verbose
5665 .. container:: verbose
5678
5666
5679 Examples:
5667 Examples:
5680
5668
5681 - show changes in the working directory relative to a
5669 - show changes in the working directory relative to a
5682 changeset::
5670 changeset::
5683
5671
5684 hg status --rev 9353
5672 hg status --rev 9353
5685
5673
5686 - show all changes including copies in an existing changeset::
5674 - show all changes including copies in an existing changeset::
5687
5675
5688 hg status --copies --change 9353
5676 hg status --copies --change 9353
5689
5677
5690 - get a NUL separated list of added files, suitable for xargs::
5678 - get a NUL separated list of added files, suitable for xargs::
5691
5679
5692 hg status -an0
5680 hg status -an0
5693
5681
5694 Returns 0 on success.
5682 Returns 0 on success.
5695 """
5683 """
5696
5684
5697 revs = opts.get('rev')
5685 revs = opts.get('rev')
5698 change = opts.get('change')
5686 change = opts.get('change')
5699
5687
5700 if revs and change:
5688 if revs and change:
5701 msg = _('cannot specify --rev and --change at the same time')
5689 msg = _('cannot specify --rev and --change at the same time')
5702 raise util.Abort(msg)
5690 raise util.Abort(msg)
5703 elif change:
5691 elif change:
5704 node2 = scmutil.revsingle(repo, change, None).node()
5692 node2 = scmutil.revsingle(repo, change, None).node()
5705 node1 = repo[node2].p1().node()
5693 node1 = repo[node2].p1().node()
5706 else:
5694 else:
5707 node1, node2 = scmutil.revpair(repo, revs)
5695 node1, node2 = scmutil.revpair(repo, revs)
5708
5696
5709 cwd = (pats and repo.getcwd()) or ''
5697 cwd = (pats and repo.getcwd()) or ''
5710 end = opts.get('print0') and '\0' or '\n'
5698 end = opts.get('print0') and '\0' or '\n'
5711 copy = {}
5699 copy = {}
5712 states = 'modified added removed deleted unknown ignored clean'.split()
5700 states = 'modified added removed deleted unknown ignored clean'.split()
5713 show = [k for k in states if opts.get(k)]
5701 show = [k for k in states if opts.get(k)]
5714 if opts.get('all'):
5702 if opts.get('all'):
5715 show += ui.quiet and (states[:4] + ['clean']) or states
5703 show += ui.quiet and (states[:4] + ['clean']) or states
5716 if not show:
5704 if not show:
5717 show = ui.quiet and states[:4] or states[:5]
5705 show = ui.quiet and states[:4] or states[:5]
5718
5706
5719 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5707 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5720 'ignored' in show, 'clean' in show, 'unknown' in show,
5708 'ignored' in show, 'clean' in show, 'unknown' in show,
5721 opts.get('subrepos'))
5709 opts.get('subrepos'))
5722 changestates = zip(states, 'MAR!?IC', stat)
5710 changestates = zip(states, 'MAR!?IC', stat)
5723
5711
5724 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5712 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5725 copy = copies.pathcopies(repo[node1], repo[node2])
5713 copy = copies.pathcopies(repo[node1], repo[node2])
5726
5714
5727 fm = ui.formatter('status', opts)
5715 fm = ui.formatter('status', opts)
5728 fmt = '%s' + end
5716 fmt = '%s' + end
5729 showchar = not opts.get('no_status')
5717 showchar = not opts.get('no_status')
5730
5718
5731 for state, char, files in changestates:
5719 for state, char, files in changestates:
5732 if state in show:
5720 if state in show:
5733 label = 'status.' + state
5721 label = 'status.' + state
5734 for f in files:
5722 for f in files:
5735 fm.startitem()
5723 fm.startitem()
5736 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5724 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5737 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5725 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5738 if f in copy:
5726 if f in copy:
5739 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5727 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5740 label='status.copied')
5728 label='status.copied')
5741 fm.end()
5729 fm.end()
5742
5730
5743 @command('^summary|sum',
5731 @command('^summary|sum',
5744 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5732 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5745 def summary(ui, repo, **opts):
5733 def summary(ui, repo, **opts):
5746 """summarize working directory state
5734 """summarize working directory state
5747
5735
5748 This generates a brief summary of the working directory state,
5736 This generates a brief summary of the working directory state,
5749 including parents, branch, commit status, and available updates.
5737 including parents, branch, commit status, and available updates.
5750
5738
5751 With the --remote option, this will check the default paths for
5739 With the --remote option, this will check the default paths for
5752 incoming and outgoing changes. This can be time-consuming.
5740 incoming and outgoing changes. This can be time-consuming.
5753
5741
5754 Returns 0 on success.
5742 Returns 0 on success.
5755 """
5743 """
5756
5744
5757 ctx = repo[None]
5745 ctx = repo[None]
5758 parents = ctx.parents()
5746 parents = ctx.parents()
5759 pnode = parents[0].node()
5747 pnode = parents[0].node()
5760 marks = []
5748 marks = []
5761
5749
5762 for p in parents:
5750 for p in parents:
5763 # label with log.changeset (instead of log.parent) since this
5751 # label with log.changeset (instead of log.parent) since this
5764 # shows a working directory parent *changeset*:
5752 # shows a working directory parent *changeset*:
5765 # i18n: column positioning for "hg summary"
5753 # i18n: column positioning for "hg summary"
5766 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5754 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5767 label='log.changeset changeset.%s' % p.phasestr())
5755 label='log.changeset changeset.%s' % p.phasestr())
5768 ui.write(' '.join(p.tags()), label='log.tag')
5756 ui.write(' '.join(p.tags()), label='log.tag')
5769 if p.bookmarks():
5757 if p.bookmarks():
5770 marks.extend(p.bookmarks())
5758 marks.extend(p.bookmarks())
5771 if p.rev() == -1:
5759 if p.rev() == -1:
5772 if not len(repo):
5760 if not len(repo):
5773 ui.write(_(' (empty repository)'))
5761 ui.write(_(' (empty repository)'))
5774 else:
5762 else:
5775 ui.write(_(' (no revision checked out)'))
5763 ui.write(_(' (no revision checked out)'))
5776 ui.write('\n')
5764 ui.write('\n')
5777 if p.description():
5765 if p.description():
5778 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5766 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5779 label='log.summary')
5767 label='log.summary')
5780
5768
5781 branch = ctx.branch()
5769 branch = ctx.branch()
5782 bheads = repo.branchheads(branch)
5770 bheads = repo.branchheads(branch)
5783 # i18n: column positioning for "hg summary"
5771 # i18n: column positioning for "hg summary"
5784 m = _('branch: %s\n') % branch
5772 m = _('branch: %s\n') % branch
5785 if branch != 'default':
5773 if branch != 'default':
5786 ui.write(m, label='log.branch')
5774 ui.write(m, label='log.branch')
5787 else:
5775 else:
5788 ui.status(m, label='log.branch')
5776 ui.status(m, label='log.branch')
5789
5777
5790 if marks:
5778 if marks:
5791 current = repo._bookmarkcurrent
5779 current = repo._bookmarkcurrent
5792 # i18n: column positioning for "hg summary"
5780 # i18n: column positioning for "hg summary"
5793 ui.write(_('bookmarks:'), label='log.bookmark')
5781 ui.write(_('bookmarks:'), label='log.bookmark')
5794 if current is not None:
5782 if current is not None:
5795 if current in marks:
5783 if current in marks:
5796 ui.write(' *' + current, label='bookmarks.current')
5784 ui.write(' *' + current, label='bookmarks.current')
5797 marks.remove(current)
5785 marks.remove(current)
5798 else:
5786 else:
5799 ui.write(' [%s]' % current, label='bookmarks.current')
5787 ui.write(' [%s]' % current, label='bookmarks.current')
5800 for m in marks:
5788 for m in marks:
5801 ui.write(' ' + m, label='log.bookmark')
5789 ui.write(' ' + m, label='log.bookmark')
5802 ui.write('\n', label='log.bookmark')
5790 ui.write('\n', label='log.bookmark')
5803
5791
5804 status = repo.status(unknown=True)
5792 status = repo.status(unknown=True)
5805
5793
5806 c = repo.dirstate.copies()
5794 c = repo.dirstate.copies()
5807 copied, renamed = [], []
5795 copied, renamed = [], []
5808 for d, s in c.iteritems():
5796 for d, s in c.iteritems():
5809 if s in status.removed:
5797 if s in status.removed:
5810 status.removed.remove(s)
5798 status.removed.remove(s)
5811 renamed.append(d)
5799 renamed.append(d)
5812 else:
5800 else:
5813 copied.append(d)
5801 copied.append(d)
5814 if d in status.added:
5802 if d in status.added:
5815 status.added.remove(d)
5803 status.added.remove(d)
5816
5804
5817 ms = mergemod.mergestate(repo)
5805 ms = mergemod.mergestate(repo)
5818 unresolved = [f for f in ms if ms[f] == 'u']
5806 unresolved = [f for f in ms if ms[f] == 'u']
5819
5807
5820 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5808 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5821
5809
5822 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5810 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5823 (ui.label(_('%d added'), 'status.added'), status.added),
5811 (ui.label(_('%d added'), 'status.added'), status.added),
5824 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5812 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5825 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5813 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5826 (ui.label(_('%d copied'), 'status.copied'), copied),
5814 (ui.label(_('%d copied'), 'status.copied'), copied),
5827 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5815 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5828 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5816 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5829 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5817 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5830 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5818 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5831 t = []
5819 t = []
5832 for l, s in labels:
5820 for l, s in labels:
5833 if s:
5821 if s:
5834 t.append(l % len(s))
5822 t.append(l % len(s))
5835
5823
5836 t = ', '.join(t)
5824 t = ', '.join(t)
5837 cleanworkdir = False
5825 cleanworkdir = False
5838
5826
5839 if repo.vfs.exists('updatestate'):
5827 if repo.vfs.exists('updatestate'):
5840 t += _(' (interrupted update)')
5828 t += _(' (interrupted update)')
5841 elif len(parents) > 1:
5829 elif len(parents) > 1:
5842 t += _(' (merge)')
5830 t += _(' (merge)')
5843 elif branch != parents[0].branch():
5831 elif branch != parents[0].branch():
5844 t += _(' (new branch)')
5832 t += _(' (new branch)')
5845 elif (parents[0].closesbranch() and
5833 elif (parents[0].closesbranch() and
5846 pnode in repo.branchheads(branch, closed=True)):
5834 pnode in repo.branchheads(branch, closed=True)):
5847 t += _(' (head closed)')
5835 t += _(' (head closed)')
5848 elif not (status.modified or status.added or status.removed or renamed or
5836 elif not (status.modified or status.added or status.removed or renamed or
5849 copied or subs):
5837 copied or subs):
5850 t += _(' (clean)')
5838 t += _(' (clean)')
5851 cleanworkdir = True
5839 cleanworkdir = True
5852 elif pnode not in bheads:
5840 elif pnode not in bheads:
5853 t += _(' (new branch head)')
5841 t += _(' (new branch head)')
5854
5842
5855 if cleanworkdir:
5843 if cleanworkdir:
5856 # i18n: column positioning for "hg summary"
5844 # i18n: column positioning for "hg summary"
5857 ui.status(_('commit: %s\n') % t.strip())
5845 ui.status(_('commit: %s\n') % t.strip())
5858 else:
5846 else:
5859 # i18n: column positioning for "hg summary"
5847 # i18n: column positioning for "hg summary"
5860 ui.write(_('commit: %s\n') % t.strip())
5848 ui.write(_('commit: %s\n') % t.strip())
5861
5849
5862 # all ancestors of branch heads - all ancestors of parent = new csets
5850 # all ancestors of branch heads - all ancestors of parent = new csets
5863 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5851 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5864 bheads))
5852 bheads))
5865
5853
5866 if new == 0:
5854 if new == 0:
5867 # i18n: column positioning for "hg summary"
5855 # i18n: column positioning for "hg summary"
5868 ui.status(_('update: (current)\n'))
5856 ui.status(_('update: (current)\n'))
5869 elif pnode not in bheads:
5857 elif pnode not in bheads:
5870 # i18n: column positioning for "hg summary"
5858 # i18n: column positioning for "hg summary"
5871 ui.write(_('update: %d new changesets (update)\n') % new)
5859 ui.write(_('update: %d new changesets (update)\n') % new)
5872 else:
5860 else:
5873 # i18n: column positioning for "hg summary"
5861 # i18n: column positioning for "hg summary"
5874 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5862 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5875 (new, len(bheads)))
5863 (new, len(bheads)))
5876
5864
5877 cmdutil.summaryhooks(ui, repo)
5865 cmdutil.summaryhooks(ui, repo)
5878
5866
5879 if opts.get('remote'):
5867 if opts.get('remote'):
5880 needsincoming, needsoutgoing = True, True
5868 needsincoming, needsoutgoing = True, True
5881 else:
5869 else:
5882 needsincoming, needsoutgoing = False, False
5870 needsincoming, needsoutgoing = False, False
5883 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5871 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5884 if i:
5872 if i:
5885 needsincoming = True
5873 needsincoming = True
5886 if o:
5874 if o:
5887 needsoutgoing = True
5875 needsoutgoing = True
5888 if not needsincoming and not needsoutgoing:
5876 if not needsincoming and not needsoutgoing:
5889 return
5877 return
5890
5878
5891 def getincoming():
5879 def getincoming():
5892 source, branches = hg.parseurl(ui.expandpath('default'))
5880 source, branches = hg.parseurl(ui.expandpath('default'))
5893 sbranch = branches[0]
5881 sbranch = branches[0]
5894 try:
5882 try:
5895 other = hg.peer(repo, {}, source)
5883 other = hg.peer(repo, {}, source)
5896 except error.RepoError:
5884 except error.RepoError:
5897 if opts.get('remote'):
5885 if opts.get('remote'):
5898 raise
5886 raise
5899 return source, sbranch, None, None, None
5887 return source, sbranch, None, None, None
5900 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5888 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5901 if revs:
5889 if revs:
5902 revs = [other.lookup(rev) for rev in revs]
5890 revs = [other.lookup(rev) for rev in revs]
5903 ui.debug('comparing with %s\n' % util.hidepassword(source))
5891 ui.debug('comparing with %s\n' % util.hidepassword(source))
5904 repo.ui.pushbuffer()
5892 repo.ui.pushbuffer()
5905 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5893 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5906 repo.ui.popbuffer()
5894 repo.ui.popbuffer()
5907 return source, sbranch, other, commoninc, commoninc[1]
5895 return source, sbranch, other, commoninc, commoninc[1]
5908
5896
5909 if needsincoming:
5897 if needsincoming:
5910 source, sbranch, sother, commoninc, incoming = getincoming()
5898 source, sbranch, sother, commoninc, incoming = getincoming()
5911 else:
5899 else:
5912 source = sbranch = sother = commoninc = incoming = None
5900 source = sbranch = sother = commoninc = incoming = None
5913
5901
5914 def getoutgoing():
5902 def getoutgoing():
5915 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5903 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5916 dbranch = branches[0]
5904 dbranch = branches[0]
5917 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5905 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5918 if source != dest:
5906 if source != dest:
5919 try:
5907 try:
5920 dother = hg.peer(repo, {}, dest)
5908 dother = hg.peer(repo, {}, dest)
5921 except error.RepoError:
5909 except error.RepoError:
5922 if opts.get('remote'):
5910 if opts.get('remote'):
5923 raise
5911 raise
5924 return dest, dbranch, None, None
5912 return dest, dbranch, None, None
5925 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5913 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5926 elif sother is None:
5914 elif sother is None:
5927 # there is no explicit destination peer, but source one is invalid
5915 # there is no explicit destination peer, but source one is invalid
5928 return dest, dbranch, None, None
5916 return dest, dbranch, None, None
5929 else:
5917 else:
5930 dother = sother
5918 dother = sother
5931 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5919 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5932 common = None
5920 common = None
5933 else:
5921 else:
5934 common = commoninc
5922 common = commoninc
5935 if revs:
5923 if revs:
5936 revs = [repo.lookup(rev) for rev in revs]
5924 revs = [repo.lookup(rev) for rev in revs]
5937 repo.ui.pushbuffer()
5925 repo.ui.pushbuffer()
5938 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5926 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5939 commoninc=common)
5927 commoninc=common)
5940 repo.ui.popbuffer()
5928 repo.ui.popbuffer()
5941 return dest, dbranch, dother, outgoing
5929 return dest, dbranch, dother, outgoing
5942
5930
5943 if needsoutgoing:
5931 if needsoutgoing:
5944 dest, dbranch, dother, outgoing = getoutgoing()
5932 dest, dbranch, dother, outgoing = getoutgoing()
5945 else:
5933 else:
5946 dest = dbranch = dother = outgoing = None
5934 dest = dbranch = dother = outgoing = None
5947
5935
5948 if opts.get('remote'):
5936 if opts.get('remote'):
5949 t = []
5937 t = []
5950 if incoming:
5938 if incoming:
5951 t.append(_('1 or more incoming'))
5939 t.append(_('1 or more incoming'))
5952 o = outgoing.missing
5940 o = outgoing.missing
5953 if o:
5941 if o:
5954 t.append(_('%d outgoing') % len(o))
5942 t.append(_('%d outgoing') % len(o))
5955 other = dother or sother
5943 other = dother or sother
5956 if 'bookmarks' in other.listkeys('namespaces'):
5944 if 'bookmarks' in other.listkeys('namespaces'):
5957 lmarks = repo.listkeys('bookmarks')
5945 lmarks = repo.listkeys('bookmarks')
5958 rmarks = other.listkeys('bookmarks')
5946 rmarks = other.listkeys('bookmarks')
5959 diff = set(rmarks) - set(lmarks)
5947 diff = set(rmarks) - set(lmarks)
5960 if len(diff) > 0:
5948 if len(diff) > 0:
5961 t.append(_('%d incoming bookmarks') % len(diff))
5949 t.append(_('%d incoming bookmarks') % len(diff))
5962 diff = set(lmarks) - set(rmarks)
5950 diff = set(lmarks) - set(rmarks)
5963 if len(diff) > 0:
5951 if len(diff) > 0:
5964 t.append(_('%d outgoing bookmarks') % len(diff))
5952 t.append(_('%d outgoing bookmarks') % len(diff))
5965
5953
5966 if t:
5954 if t:
5967 # i18n: column positioning for "hg summary"
5955 # i18n: column positioning for "hg summary"
5968 ui.write(_('remote: %s\n') % (', '.join(t)))
5956 ui.write(_('remote: %s\n') % (', '.join(t)))
5969 else:
5957 else:
5970 # i18n: column positioning for "hg summary"
5958 # i18n: column positioning for "hg summary"
5971 ui.status(_('remote: (synced)\n'))
5959 ui.status(_('remote: (synced)\n'))
5972
5960
5973 cmdutil.summaryremotehooks(ui, repo, opts,
5961 cmdutil.summaryremotehooks(ui, repo, opts,
5974 ((source, sbranch, sother, commoninc),
5962 ((source, sbranch, sother, commoninc),
5975 (dest, dbranch, dother, outgoing)))
5963 (dest, dbranch, dother, outgoing)))
5976
5964
5977 @command('tag',
5965 @command('tag',
5978 [('f', 'force', None, _('force tag')),
5966 [('f', 'force', None, _('force tag')),
5979 ('l', 'local', None, _('make the tag local')),
5967 ('l', 'local', None, _('make the tag local')),
5980 ('r', 'rev', '', _('revision to tag'), _('REV')),
5968 ('r', 'rev', '', _('revision to tag'), _('REV')),
5981 ('', 'remove', None, _('remove a tag')),
5969 ('', 'remove', None, _('remove a tag')),
5982 # -l/--local is already there, commitopts cannot be used
5970 # -l/--local is already there, commitopts cannot be used
5983 ('e', 'edit', None, _('invoke editor on commit messages')),
5971 ('e', 'edit', None, _('invoke editor on commit messages')),
5984 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5972 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5985 ] + commitopts2,
5973 ] + commitopts2,
5986 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5974 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5987 def tag(ui, repo, name1, *names, **opts):
5975 def tag(ui, repo, name1, *names, **opts):
5988 """add one or more tags for the current or given revision
5976 """add one or more tags for the current or given revision
5989
5977
5990 Name a particular revision using <name>.
5978 Name a particular revision using <name>.
5991
5979
5992 Tags are used to name particular revisions of the repository and are
5980 Tags are used to name particular revisions of the repository and are
5993 very useful to compare different revisions, to go back to significant
5981 very useful to compare different revisions, to go back to significant
5994 earlier versions or to mark branch points as releases, etc. Changing
5982 earlier versions or to mark branch points as releases, etc. Changing
5995 an existing tag is normally disallowed; use -f/--force to override.
5983 an existing tag is normally disallowed; use -f/--force to override.
5996
5984
5997 If no revision is given, the parent of the working directory is
5985 If no revision is given, the parent of the working directory is
5998 used.
5986 used.
5999
5987
6000 To facilitate version control, distribution, and merging of tags,
5988 To facilitate version control, distribution, and merging of tags,
6001 they are stored as a file named ".hgtags" which is managed similarly
5989 they are stored as a file named ".hgtags" which is managed similarly
6002 to other project files and can be hand-edited if necessary. This
5990 to other project files and can be hand-edited if necessary. This
6003 also means that tagging creates a new commit. The file
5991 also means that tagging creates a new commit. The file
6004 ".hg/localtags" is used for local tags (not shared among
5992 ".hg/localtags" is used for local tags (not shared among
6005 repositories).
5993 repositories).
6006
5994
6007 Tag commits are usually made at the head of a branch. If the parent
5995 Tag commits are usually made at the head of a branch. If the parent
6008 of the working directory is not a branch head, :hg:`tag` aborts; use
5996 of the working directory is not a branch head, :hg:`tag` aborts; use
6009 -f/--force to force the tag commit to be based on a non-head
5997 -f/--force to force the tag commit to be based on a non-head
6010 changeset.
5998 changeset.
6011
5999
6012 See :hg:`help dates` for a list of formats valid for -d/--date.
6000 See :hg:`help dates` for a list of formats valid for -d/--date.
6013
6001
6014 Since tag names have priority over branch names during revision
6002 Since tag names have priority over branch names during revision
6015 lookup, using an existing branch name as a tag name is discouraged.
6003 lookup, using an existing branch name as a tag name is discouraged.
6016
6004
6017 Returns 0 on success.
6005 Returns 0 on success.
6018 """
6006 """
6019 wlock = lock = None
6007 wlock = lock = None
6020 try:
6008 try:
6021 wlock = repo.wlock()
6009 wlock = repo.wlock()
6022 lock = repo.lock()
6010 lock = repo.lock()
6023 rev_ = "."
6011 rev_ = "."
6024 names = [t.strip() for t in (name1,) + names]
6012 names = [t.strip() for t in (name1,) + names]
6025 if len(names) != len(set(names)):
6013 if len(names) != len(set(names)):
6026 raise util.Abort(_('tag names must be unique'))
6014 raise util.Abort(_('tag names must be unique'))
6027 for n in names:
6015 for n in names:
6028 scmutil.checknewlabel(repo, n, 'tag')
6016 scmutil.checknewlabel(repo, n, 'tag')
6029 if not n:
6017 if not n:
6030 raise util.Abort(_('tag names cannot consist entirely of '
6018 raise util.Abort(_('tag names cannot consist entirely of '
6031 'whitespace'))
6019 'whitespace'))
6032 if opts.get('rev') and opts.get('remove'):
6020 if opts.get('rev') and opts.get('remove'):
6033 raise util.Abort(_("--rev and --remove are incompatible"))
6021 raise util.Abort(_("--rev and --remove are incompatible"))
6034 if opts.get('rev'):
6022 if opts.get('rev'):
6035 rev_ = opts['rev']
6023 rev_ = opts['rev']
6036 message = opts.get('message')
6024 message = opts.get('message')
6037 if opts.get('remove'):
6025 if opts.get('remove'):
6038 expectedtype = opts.get('local') and 'local' or 'global'
6026 expectedtype = opts.get('local') and 'local' or 'global'
6039 for n in names:
6027 for n in names:
6040 if not repo.tagtype(n):
6028 if not repo.tagtype(n):
6041 raise util.Abort(_("tag '%s' does not exist") % n)
6029 raise util.Abort(_("tag '%s' does not exist") % n)
6042 if repo.tagtype(n) != expectedtype:
6030 if repo.tagtype(n) != expectedtype:
6043 if expectedtype == 'global':
6031 if expectedtype == 'global':
6044 raise util.Abort(_("tag '%s' is not a global tag") % n)
6032 raise util.Abort(_("tag '%s' is not a global tag") % n)
6045 else:
6033 else:
6046 raise util.Abort(_("tag '%s' is not a local tag") % n)
6034 raise util.Abort(_("tag '%s' is not a local tag") % n)
6047 rev_ = nullid
6035 rev_ = nullid
6048 if not message:
6036 if not message:
6049 # we don't translate commit messages
6037 # we don't translate commit messages
6050 message = 'Removed tag %s' % ', '.join(names)
6038 message = 'Removed tag %s' % ', '.join(names)
6051 elif not opts.get('force'):
6039 elif not opts.get('force'):
6052 for n in names:
6040 for n in names:
6053 if n in repo.tags():
6041 if n in repo.tags():
6054 raise util.Abort(_("tag '%s' already exists "
6042 raise util.Abort(_("tag '%s' already exists "
6055 "(use -f to force)") % n)
6043 "(use -f to force)") % n)
6056 if not opts.get('local'):
6044 if not opts.get('local'):
6057 p1, p2 = repo.dirstate.parents()
6045 p1, p2 = repo.dirstate.parents()
6058 if p2 != nullid:
6046 if p2 != nullid:
6059 raise util.Abort(_('uncommitted merge'))
6047 raise util.Abort(_('uncommitted merge'))
6060 bheads = repo.branchheads()
6048 bheads = repo.branchheads()
6061 if not opts.get('force') and bheads and p1 not in bheads:
6049 if not opts.get('force') and bheads and p1 not in bheads:
6062 raise util.Abort(_('not at a branch head (use -f to force)'))
6050 raise util.Abort(_('not at a branch head (use -f to force)'))
6063 r = scmutil.revsingle(repo, rev_).node()
6051 r = scmutil.revsingle(repo, rev_).node()
6064
6052
6065 if not message:
6053 if not message:
6066 # we don't translate commit messages
6054 # we don't translate commit messages
6067 message = ('Added tag %s for changeset %s' %
6055 message = ('Added tag %s for changeset %s' %
6068 (', '.join(names), short(r)))
6056 (', '.join(names), short(r)))
6069
6057
6070 date = opts.get('date')
6058 date = opts.get('date')
6071 if date:
6059 if date:
6072 date = util.parsedate(date)
6060 date = util.parsedate(date)
6073
6061
6074 if opts.get('remove'):
6062 if opts.get('remove'):
6075 editform = 'tag.remove'
6063 editform = 'tag.remove'
6076 else:
6064 else:
6077 editform = 'tag.add'
6065 editform = 'tag.add'
6078 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6066 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6079
6067
6080 # don't allow tagging the null rev
6068 # don't allow tagging the null rev
6081 if (not opts.get('remove') and
6069 if (not opts.get('remove') and
6082 scmutil.revsingle(repo, rev_).rev() == nullrev):
6070 scmutil.revsingle(repo, rev_).rev() == nullrev):
6083 raise util.Abort(_("cannot tag null revision"))
6071 raise util.Abort(_("cannot tag null revision"))
6084
6072
6085 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6073 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6086 editor=editor)
6074 editor=editor)
6087 finally:
6075 finally:
6088 release(lock, wlock)
6076 release(lock, wlock)
6089
6077
6090 @command('tags', formatteropts, '')
6078 @command('tags', formatteropts, '')
6091 def tags(ui, repo, **opts):
6079 def tags(ui, repo, **opts):
6092 """list repository tags
6080 """list repository tags
6093
6081
6094 This lists both regular and local tags. When the -v/--verbose
6082 This lists both regular and local tags. When the -v/--verbose
6095 switch is used, a third column "local" is printed for local tags.
6083 switch is used, a third column "local" is printed for local tags.
6096
6084
6097 Returns 0 on success.
6085 Returns 0 on success.
6098 """
6086 """
6099
6087
6100 fm = ui.formatter('tags', opts)
6088 fm = ui.formatter('tags', opts)
6101 hexfunc = fm.hexfunc
6089 hexfunc = fm.hexfunc
6102 tagtype = ""
6090 tagtype = ""
6103
6091
6104 for t, n in reversed(repo.tagslist()):
6092 for t, n in reversed(repo.tagslist()):
6105 hn = hexfunc(n)
6093 hn = hexfunc(n)
6106 label = 'tags.normal'
6094 label = 'tags.normal'
6107 tagtype = ''
6095 tagtype = ''
6108 if repo.tagtype(t) == 'local':
6096 if repo.tagtype(t) == 'local':
6109 label = 'tags.local'
6097 label = 'tags.local'
6110 tagtype = 'local'
6098 tagtype = 'local'
6111
6099
6112 fm.startitem()
6100 fm.startitem()
6113 fm.write('tag', '%s', t, label=label)
6101 fm.write('tag', '%s', t, label=label)
6114 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6102 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6115 fm.condwrite(not ui.quiet, 'rev node', fmt,
6103 fm.condwrite(not ui.quiet, 'rev node', fmt,
6116 repo.changelog.rev(n), hn, label=label)
6104 repo.changelog.rev(n), hn, label=label)
6117 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6105 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6118 tagtype, label=label)
6106 tagtype, label=label)
6119 fm.plain('\n')
6107 fm.plain('\n')
6120 fm.end()
6108 fm.end()
6121
6109
6122 @command('tip',
6110 @command('tip',
6123 [('p', 'patch', None, _('show patch')),
6111 [('p', 'patch', None, _('show patch')),
6124 ('g', 'git', None, _('use git extended diff format')),
6112 ('g', 'git', None, _('use git extended diff format')),
6125 ] + templateopts,
6113 ] + templateopts,
6126 _('[-p] [-g]'))
6114 _('[-p] [-g]'))
6127 def tip(ui, repo, **opts):
6115 def tip(ui, repo, **opts):
6128 """show the tip revision (DEPRECATED)
6116 """show the tip revision (DEPRECATED)
6129
6117
6130 The tip revision (usually just called the tip) is the changeset
6118 The tip revision (usually just called the tip) is the changeset
6131 most recently added to the repository (and therefore the most
6119 most recently added to the repository (and therefore the most
6132 recently changed head).
6120 recently changed head).
6133
6121
6134 If you have just made a commit, that commit will be the tip. If
6122 If you have just made a commit, that commit will be the tip. If
6135 you have just pulled changes from another repository, the tip of
6123 you have just pulled changes from another repository, the tip of
6136 that repository becomes the current tip. The "tip" tag is special
6124 that repository becomes the current tip. The "tip" tag is special
6137 and cannot be renamed or assigned to a different changeset.
6125 and cannot be renamed or assigned to a different changeset.
6138
6126
6139 This command is deprecated, please use :hg:`heads` instead.
6127 This command is deprecated, please use :hg:`heads` instead.
6140
6128
6141 Returns 0 on success.
6129 Returns 0 on success.
6142 """
6130 """
6143 displayer = cmdutil.show_changeset(ui, repo, opts)
6131 displayer = cmdutil.show_changeset(ui, repo, opts)
6144 displayer.show(repo['tip'])
6132 displayer.show(repo['tip'])
6145 displayer.close()
6133 displayer.close()
6146
6134
6147 @command('unbundle',
6135 @command('unbundle',
6148 [('u', 'update', None,
6136 [('u', 'update', None,
6149 _('update to new branch head if changesets were unbundled'))],
6137 _('update to new branch head if changesets were unbundled'))],
6150 _('[-u] FILE...'))
6138 _('[-u] FILE...'))
6151 def unbundle(ui, repo, fname1, *fnames, **opts):
6139 def unbundle(ui, repo, fname1, *fnames, **opts):
6152 """apply one or more changegroup files
6140 """apply one or more changegroup files
6153
6141
6154 Apply one or more compressed changegroup files generated by the
6142 Apply one or more compressed changegroup files generated by the
6155 bundle command.
6143 bundle command.
6156
6144
6157 Returns 0 on success, 1 if an update has unresolved files.
6145 Returns 0 on success, 1 if an update has unresolved files.
6158 """
6146 """
6159 fnames = (fname1,) + fnames
6147 fnames = (fname1,) + fnames
6160
6148
6161 lock = repo.lock()
6149 lock = repo.lock()
6162 try:
6150 try:
6163 for fname in fnames:
6151 for fname in fnames:
6164 f = hg.openpath(ui, fname)
6152 f = hg.openpath(ui, fname)
6165 gen = exchange.readbundle(ui, f, fname)
6153 gen = exchange.readbundle(ui, f, fname)
6166 if isinstance(gen, bundle2.unbundle20):
6154 if isinstance(gen, bundle2.unbundle20):
6167 tr = repo.transaction('unbundle')
6155 tr = repo.transaction('unbundle')
6168 try:
6156 try:
6169 op = bundle2.processbundle(repo, gen, lambda: tr)
6157 op = bundle2.processbundle(repo, gen, lambda: tr)
6170 tr.close()
6158 tr.close()
6171 finally:
6159 finally:
6172 if tr:
6160 if tr:
6173 tr.release()
6161 tr.release()
6174 changes = [r.get('result', 0)
6162 changes = [r.get('result', 0)
6175 for r in op.records['changegroup']]
6163 for r in op.records['changegroup']]
6176 modheads = changegroup.combineresults(changes)
6164 modheads = changegroup.combineresults(changes)
6177 else:
6165 else:
6178 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6166 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6179 'bundle:' + fname)
6167 'bundle:' + fname)
6180 finally:
6168 finally:
6181 lock.release()
6169 lock.release()
6182
6170
6183 return postincoming(ui, repo, modheads, opts.get('update'), None)
6171 return postincoming(ui, repo, modheads, opts.get('update'), None)
6184
6172
6185 @command('^update|up|checkout|co',
6173 @command('^update|up|checkout|co',
6186 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6174 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6187 ('c', 'check', None,
6175 ('c', 'check', None,
6188 _('update across branches if no uncommitted changes')),
6176 _('update across branches if no uncommitted changes')),
6189 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6177 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6190 ('r', 'rev', '', _('revision'), _('REV'))
6178 ('r', 'rev', '', _('revision'), _('REV'))
6191 ] + mergetoolopts,
6179 ] + mergetoolopts,
6192 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6180 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6193 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6181 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6194 tool=None):
6182 tool=None):
6195 """update working directory (or switch revisions)
6183 """update working directory (or switch revisions)
6196
6184
6197 Update the repository's working directory to the specified
6185 Update the repository's working directory to the specified
6198 changeset. If no changeset is specified, update to the tip of the
6186 changeset. If no changeset is specified, update to the tip of the
6199 current named branch and move the current bookmark (see :hg:`help
6187 current named branch and move the current bookmark (see :hg:`help
6200 bookmarks`).
6188 bookmarks`).
6201
6189
6202 Update sets the working directory's parent revision to the specified
6190 Update sets the working directory's parent revision to the specified
6203 changeset (see :hg:`help parents`).
6191 changeset (see :hg:`help parents`).
6204
6192
6205 If the changeset is not a descendant or ancestor of the working
6193 If the changeset is not a descendant or ancestor of the working
6206 directory's parent, the update is aborted. With the -c/--check
6194 directory's parent, the update is aborted. With the -c/--check
6207 option, the working directory is checked for uncommitted changes; if
6195 option, the working directory is checked for uncommitted changes; if
6208 none are found, the working directory is updated to the specified
6196 none are found, the working directory is updated to the specified
6209 changeset.
6197 changeset.
6210
6198
6211 .. container:: verbose
6199 .. container:: verbose
6212
6200
6213 The following rules apply when the working directory contains
6201 The following rules apply when the working directory contains
6214 uncommitted changes:
6202 uncommitted changes:
6215
6203
6216 1. If neither -c/--check nor -C/--clean is specified, and if
6204 1. If neither -c/--check nor -C/--clean is specified, and if
6217 the requested changeset is an ancestor or descendant of
6205 the requested changeset is an ancestor or descendant of
6218 the working directory's parent, the uncommitted changes
6206 the working directory's parent, the uncommitted changes
6219 are merged into the requested changeset and the merged
6207 are merged into the requested changeset and the merged
6220 result is left uncommitted. If the requested changeset is
6208 result is left uncommitted. If the requested changeset is
6221 not an ancestor or descendant (that is, it is on another
6209 not an ancestor or descendant (that is, it is on another
6222 branch), the update is aborted and the uncommitted changes
6210 branch), the update is aborted and the uncommitted changes
6223 are preserved.
6211 are preserved.
6224
6212
6225 2. With the -c/--check option, the update is aborted and the
6213 2. With the -c/--check option, the update is aborted and the
6226 uncommitted changes are preserved.
6214 uncommitted changes are preserved.
6227
6215
6228 3. With the -C/--clean option, uncommitted changes are discarded and
6216 3. With the -C/--clean option, uncommitted changes are discarded and
6229 the working directory is updated to the requested changeset.
6217 the working directory is updated to the requested changeset.
6230
6218
6231 To cancel an uncommitted merge (and lose your changes), use
6219 To cancel an uncommitted merge (and lose your changes), use
6232 :hg:`update --clean .`.
6220 :hg:`update --clean .`.
6233
6221
6234 Use null as the changeset to remove the working directory (like
6222 Use null as the changeset to remove the working directory (like
6235 :hg:`clone -U`).
6223 :hg:`clone -U`).
6236
6224
6237 If you want to revert just one file to an older revision, use
6225 If you want to revert just one file to an older revision, use
6238 :hg:`revert [-r REV] NAME`.
6226 :hg:`revert [-r REV] NAME`.
6239
6227
6240 See :hg:`help dates` for a list of formats valid for -d/--date.
6228 See :hg:`help dates` for a list of formats valid for -d/--date.
6241
6229
6242 Returns 0 on success, 1 if there are unresolved files.
6230 Returns 0 on success, 1 if there are unresolved files.
6243 """
6231 """
6244 if rev and node:
6232 if rev and node:
6245 raise util.Abort(_("please specify just one revision"))
6233 raise util.Abort(_("please specify just one revision"))
6246
6234
6247 if rev is None or rev == '':
6235 if rev is None or rev == '':
6248 rev = node
6236 rev = node
6249
6237
6250 cmdutil.clearunfinished(repo)
6238 cmdutil.clearunfinished(repo)
6251
6239
6252 # with no argument, we also move the current bookmark, if any
6240 # with no argument, we also move the current bookmark, if any
6253 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6241 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6254
6242
6255 # if we defined a bookmark, we have to remember the original bookmark name
6243 # if we defined a bookmark, we have to remember the original bookmark name
6256 brev = rev
6244 brev = rev
6257 rev = scmutil.revsingle(repo, rev, rev).rev()
6245 rev = scmutil.revsingle(repo, rev, rev).rev()
6258
6246
6259 if check and clean:
6247 if check and clean:
6260 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6248 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6261
6249
6262 if date:
6250 if date:
6263 if rev is not None:
6251 if rev is not None:
6264 raise util.Abort(_("you can't specify a revision and a date"))
6252 raise util.Abort(_("you can't specify a revision and a date"))
6265 rev = cmdutil.finddate(ui, repo, date)
6253 rev = cmdutil.finddate(ui, repo, date)
6266
6254
6267 if check:
6255 if check:
6268 c = repo[None]
6256 c = repo[None]
6269 if c.dirty(merge=False, branch=False, missing=True):
6257 if c.dirty(merge=False, branch=False, missing=True):
6270 raise util.Abort(_("uncommitted changes"))
6258 raise util.Abort(_("uncommitted changes"))
6271 if rev is None:
6259 if rev is None:
6272 rev = repo[repo[None].branch()].rev()
6260 rev = repo[repo[None].branch()].rev()
6273
6261
6274 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6262 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6275
6263
6276 if clean:
6264 if clean:
6277 ret = hg.clean(repo, rev)
6265 ret = hg.clean(repo, rev)
6278 else:
6266 else:
6279 ret = hg.update(repo, rev)
6267 ret = hg.update(repo, rev)
6280
6268
6281 if not ret and movemarkfrom:
6269 if not ret and movemarkfrom:
6282 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6270 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6283 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6271 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6284 elif brev in repo._bookmarks:
6272 elif brev in repo._bookmarks:
6285 bookmarks.setcurrent(repo, brev)
6273 bookmarks.setcurrent(repo, brev)
6286 ui.status(_("(activating bookmark %s)\n") % brev)
6274 ui.status(_("(activating bookmark %s)\n") % brev)
6287 elif brev:
6275 elif brev:
6288 if repo._bookmarkcurrent:
6276 if repo._bookmarkcurrent:
6289 ui.status(_("(leaving bookmark %s)\n") %
6277 ui.status(_("(leaving bookmark %s)\n") %
6290 repo._bookmarkcurrent)
6278 repo._bookmarkcurrent)
6291 bookmarks.unsetcurrent(repo)
6279 bookmarks.unsetcurrent(repo)
6292
6280
6293 return ret
6281 return ret
6294
6282
6295 @command('verify', [])
6283 @command('verify', [])
6296 def verify(ui, repo):
6284 def verify(ui, repo):
6297 """verify the integrity of the repository
6285 """verify the integrity of the repository
6298
6286
6299 Verify the integrity of the current repository.
6287 Verify the integrity of the current repository.
6300
6288
6301 This will perform an extensive check of the repository's
6289 This will perform an extensive check of the repository's
6302 integrity, validating the hashes and checksums of each entry in
6290 integrity, validating the hashes and checksums of each entry in
6303 the changelog, manifest, and tracked files, as well as the
6291 the changelog, manifest, and tracked files, as well as the
6304 integrity of their crosslinks and indices.
6292 integrity of their crosslinks and indices.
6305
6293
6306 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6294 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6307 for more information about recovery from corruption of the
6295 for more information about recovery from corruption of the
6308 repository.
6296 repository.
6309
6297
6310 Returns 0 on success, 1 if errors are encountered.
6298 Returns 0 on success, 1 if errors are encountered.
6311 """
6299 """
6312 return hg.verify(repo)
6300 return hg.verify(repo)
6313
6301
6314 @command('version', [], norepo=True)
6302 @command('version', [], norepo=True)
6315 def version_(ui):
6303 def version_(ui):
6316 """output version and copyright information"""
6304 """output version and copyright information"""
6317 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6305 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6318 % util.version())
6306 % util.version())
6319 ui.status(_(
6307 ui.status(_(
6320 "(see http://mercurial.selenic.com for more information)\n"
6308 "(see http://mercurial.selenic.com for more information)\n"
6321 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6309 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6322 "This is free software; see the source for copying conditions. "
6310 "This is free software; see the source for copying conditions. "
6323 "There is NO\nwarranty; "
6311 "There is NO\nwarranty; "
6324 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6312 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6325 ))
6313 ))
6326
6314
6327 ui.note(_("\nEnabled extensions:\n\n"))
6315 ui.note(_("\nEnabled extensions:\n\n"))
6328 if ui.verbose:
6316 if ui.verbose:
6329 # format names and versions into columns
6317 # format names and versions into columns
6330 names = []
6318 names = []
6331 vers = []
6319 vers = []
6332 for name, module in extensions.extensions():
6320 for name, module in extensions.extensions():
6333 names.append(name)
6321 names.append(name)
6334 vers.append(extensions.moduleversion(module))
6322 vers.append(extensions.moduleversion(module))
6335 if names:
6323 if names:
6336 maxnamelen = max(len(n) for n in names)
6324 maxnamelen = max(len(n) for n in names)
6337 for i, name in enumerate(names):
6325 for i, name in enumerate(names):
6338 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
6326 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
General Comments 0
You need to be logged in to leave comments. Login now